GIDForums

Go Back   GIDForums > Computer Programming Forums > CPP / C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read


 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 06-May-2005, 19:32
ubergeek ubergeek is offline
Regular Member
 
Join Date: Jan 2005
Posts: 775
ubergeek is a jewel in the roughubergeek is a jewel in the roughubergeek is a jewel in the rough

Dynamic memory, loops, and segmentation faults


(I apologize if you haven't seen The Wizard of Oz and therefore didn't understand my title.)

Anyways, I'm having some trouble with this program and can't seem to find the problem. The program takes other programs and/or shortcuts to run as command-line arguments. It can also send command-line arguments to the .exe files that it runs. The format is like this:

"c:\multishort\multishort.exe" c:\windows\system32\mspaint.exe AAc:\test.bmp c:\windows\system32\notepad.exe AAc:\test.txt

This SHOULD run Paint with c:\test.bmp open and Notepad with c:\test.txt open. Actually it does neither. Currently, the program simply decides to exit after executing line 33. This is most puzzling. Here is the code:

CPP / C++ / C Code:
/*
   MultiShort v1.0
   
   by ubergeek
   
   runs multiple programs from one shortcut (see readme.txt for more details)
   
   MultiShort is free software. There is no warranty, implied or otherwise. If
   you like it, great. Use it. If you don't like it, don't use it. If it causes
   any harm to you or your computer, such as not working, deleteing files, or
   kidnapping your relatives, I am not responsible.
   
   ms.h
*/


#ifndef _MULTISHORT_PROGRAM_H_FILE_  //inclusion guard
#define _MULTISHORT_PROGRAM_H_FILE_


#include <windows.h> //windows API functions
#include <shlobj.h>  //IShellLink and IPersistFile interfaces
#include <wtypes.h>  //CLSCTX enumeration
#include <objbase.h> //interface-related functions
#include <objidl.h>  //interface-related functions
#include <strsafe.h> //StringCchCopy -- replacement for strcpy that causes segmentation faults much less often
#include <string>    //string class
//must link libole32.a and libuuid.a (in VC++ it would be ole32.lib and uuid.lib)
using namespace std;

enum PROGTYPE { EXE, LNK };

inline int dbgmsg(const char *msg) { return MessageBox(NULL, msg, "MultiShort: Debugging Message", MB_OK | MB_ICONINFORMATION); }
inline int errmsg(const char *msg) { return MessageBox(NULL, msg, "MultiShort: Error", MB_OK | MB_ICONERROR); }
inline int dbgmsg(const string &strmsg) { return dbgmsg(strmsg.c_str()); }
inline int errmsg(const string &strmsg) { return errmsg(strmsg.c_str()); }


struct LNKINFO         //holds information about a shortcut (.lnk) file
{
    string filename;    //actual filename of the .lnk
    string pointedprog; //file the shortcut points to
    string pointedargs; //any arguments to be passed on to pointedprog
    int pointedshowcmd; //window state to give to pointedprog
};

struct PROG
{
    PROGTYPE type;
    union /*anonymous*/
    {
        string *pexename;
        LNKINFO *plnkinf;
    };
};

bool isExecutable(string); //takes command-line argument (path and filename) as an std::string, and returns true if the file has a .exe extension, and false if it doesn't.
void getShortcutInfo(LNKINFO*); //takes path\filename of a shortcut (.lnk) and fills a LNKINFO structure
void toLower(string*); //takes a string and converts any uppercase letters in it to lowercase
int getNumProgs(int, char**); //takes the argc and argv from main, parses it, and determines how many actual programs/shortcuts there are to run
bool parseCommandLine(int, char**, PROG*, int*);


#endif //inclusion guard

CPP / C++ / C Code:
/*
   MultiShort v1.0
   
   by ubergeek
   
   runs multiple programs from one shortcut (see readme.txt for more details)
   
   MultiShort is free software. There is no warranty, implied or otherwise. If
   you like it, great. Use it. If you don't like it, don't use it. If it causes
   any harm to you or your computer, such as not working, deleteing files, or
   kidnapping your relatives, I am not responsible.
   
   multishort.cpp
*/

#include "ms.h"

int main(int argc, char *argv[]) //argc tells me how many command-line arguments there are, and argv is an array of the command-line arguments passed to MultiShort, split at spaces (but not split inside quoted arguments)
{
    if (argc < 2)
    {
        errmsg("You didn't give me anything to run! Read readme.txt if you're confused.");
        return 1;
    }
    if ( (argv[1][0] == 'A') && (argv[1][1] == 'A') )
    {
        errmsg("First argument must be a program or shortcut, not an argument. Read readme.txt if you're confused.");
        return 1;
    }
    PROG *progs_to_run = NULL;
    int numprogs = 0;
    bool success = parseCommandLine(argc, argv, progs_to_run, &numprogs); //will allocate progs_to_run for me. this means that i should definitely check that and not forget to delete[] it!
    dbgmsg("back from parsecommandline"); //line 33. Nothing after this is run. ???
    for (int i = 0; i < numprogs; ++i)
    {
        if (progs_to_run[i].type == EXE) dbgmsg(progs_to_run[i].pexename->c_str());
        else
        {
            dbgmsg(progs_to_run[i].plnkinf->pointedprog.c_str());
            dbgmsg(progs_to_run[i].plnkinf->pointedargs.c_str());
        }
    }
    dbgmsg("done outputting parsecmdln's work");
    if (!success)
    {
        errmsg("Fatal error. Exiting.");
        return 1;
    }
    if (numprogs < 2) //if you didn't provide two or more programs to run...
    {
        errmsg("You must provide two or more programs to run as command-line arguments. If you didn't provide any programs to run, why run this program? It doesn't as yet do anything else. If you only provided one program to run, then why use MultiShort? Just make a regular shortcut. Read readme.txt if you're confused."); //...then tell the user what went wrong and how to fix it.
        return 1;
    }
    STARTUPINFO startinfo;          //these structures are required by CreateProcess, but at this time MultiShort don't use them for anything. They provide a higher level of control over how the program is run, for example it can be run minimized.
    ZeroMemory(&startinfo, sizeof(STARTUPINFO));
    startinfo.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION procinfo;
    dbgmsg("starting real work");
    for (int i = 0; i < numprogs; i++) //this loop will run until all the command-line arguments have been considered
    {
        if (progs_to_run[i].type == EXE)
        {
            ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
            CreateProcess(NULL, const_cast<char*>(progs_to_run[i].pexename->c_str()), NULL, NULL, false, 0, NULL, NULL, &startinfo, &procinfo); //this is the most important line in the program. it runs the program specified in the command-line argument
            CloseHandle(procinfo.hProcess); //and, clean up after Windows
            CloseHandle(procinfo.hThread);
        }
        else //the file is not in the form path\filename.exe||bat||com
        {
            getShortcutInfo(progs_to_run[i].plnkinf); //fill our structure
            
            if (isExecutable(progs_to_run[i].plnkinf->pointedprog))
            {
                string exec = "\"";         //start with a space
                exec += progs_to_run[i].plnkinf->pointedprog; //add the filename
                exec += "\" ";              //closing quote and a space
                exec += progs_to_run[i].plnkinf->pointedargs; //and any arguments
                
                startinfo.wShowWindow = progs_to_run[i].plnkinf->pointedshowcmd;
                startinfo.dwFlags |= STARTF_USESHOWWINDOW;
                
                ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
                CreateProcess(NULL, const_cast<char*>(exec.c_str()), NULL, NULL, false, 0, NULL, NULL, &startinfo, &procinfo); //this is the most important line in the program. it runs the program specified in the command-line argument (lnkinf.pointedprog + lnkinf.pointedargs as lnkinf.pointedshowcmd)
                CloseHandle(procinfo.hProcess); //and, clean up after Windows
                CloseHandle(procinfo.hThread);
            }
            else
            {
                SHELLEXECUTEINFO shlexecinf;
                ZeroMemory(&shlexecinf, sizeof(SHELLEXECUTEINFO));
                shlexecinf.cbSize = sizeof(SHELLEXECUTEINFO); //initialize our structure...
                shlexecinf.hwnd = GetDesktopWindow(); //display messages with the desktop window as parent
                shlexecinf.lpVerb = "open"; //open the pointedprog
                shlexecinf.lpFile = new char[progs_to_run[i].plnkinf->pointedprog.length()+2];      //allocate our strings
                shlexecinf.lpParameters = new char[progs_to_run[i].plnkinf->pointedprog.length()+2];
                StringCchCopy(const_cast<char*>(shlexecinf.lpFile), progs_to_run[i].plnkinf->pointedprog.length()+1, progs_to_run[i].plnkinf->pointedprog.c_str());       //copy them
                StringCchCopy(const_cast<char*>(shlexecinf.lpParameters), progs_to_run[i].plnkinf->pointedargs.length()+1, progs_to_run[i].plnkinf->pointedargs.c_str());
                shlexecinf.nShow = progs_to_run[i].plnkinf->pointedshowcmd;

                if (!ShellExecuteEx(&shlexecinf)) //attempt to run the pointedprog...
                {
                    char errstr[300];
                    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errstr, 299, NULL); //...but if it doesn't work, check what the error was and retrieve it
                    string err = "Failed to execute \""; //assemble error description string
                    err += progs_to_run[i].plnkinf->pointedprog.c_str();
                    err += "\" because ";
                    err += errstr;
                    err += ". Make sure that the file exists and is not currently running or opened by another program.";
                    errmsg(err.c_str()); //display the error
                }
                
                delete[] shlexecinf.lpFile;       //memory leaks are bad
                delete[] shlexecinf.lpParameters;
            }
        }
    }
    
    delete[] progs_to_run; //memory leaks are still bad, although this one wouldn't be as serious because the program is going to exit in about a millisecond anyways and release all its memory back to the operating system
    
    return 0; //all done! goodbye!
}

bool isExecutable(string filename)
{
    int ilastdot = filename.rfind(".", filename.length()); //find the dot that designates the beginning of the extension
    string extension = filename.substr(ilastdot, filename.length() - ilastdot); //using that dot, slice off the extension
    toLower(&extension); //convert the extension to lowercase for comparison purposes
    return ( (extension == ".exe") || (extension == ".bat") || (extension == ".com") ); //check if the extension denotes an executable file
}

void toLower(string *str)
{
    for (string::iterator iter = str->begin(); iter != str->end(); ++iter)
    { //iterate through the string
        if ( ((int)*iter >= 65) && ((int)*iter <= 90) ) //if it's an uppercase letter
        {
            *iter += 32; //convert it to lowercase
        }
    }
}

void getShortcutInfo(LNKINFO *shortcut)
{
    CoInitializeEx(NULL, 0); //make CoCreateInstance work
    
    IShellLink *shell_link;    //declare interface pointers
    IPersistFile *persist_file;
    
    char path[MAX_PATH+1], args[INFOTIPSIZE+1];
    
    LRESULT ret = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&shell_link); //get a pointer to the IShellLink interface
    
    shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); //get a pointer to the IPersistFile interface

    WCHAR file[shortcut->filename.length()+1];
    MultiByteToWideChar(CP_ACP, 0, shortcut->filename.c_str(), -1, file, MAX_PATH);
    persist_file->Load(file, STGM_READ); //open the link

    shell_link->Resolve(GetDesktopWindow(), SLR_UPDATE); //resolve the link and update it if it has changed

    shell_link->GetPath(path, MAX_PATH, NULL, 0);      //gather information
    shell_link->GetArguments(args, INFOTIPSIZE);
    shell_link->GetShowCmd(&shortcut->pointedshowcmd);

    shortcut->pointedprog = path; //transfer information
    shortcut->pointedargs = args;

    shell_link->Release();   //release the interfaces
    persist_file->Release();
    
    CoUninitialize(); //undo whatever CoInitializeEx did
}

bool parseCommandLine(int argc, char **argv, PROG *output, int *num)
{
    *num = 0;
    output = new PROG[*num]; //allocate output
    if (!output) return false;
    dbgmsg("set up num, allocated output");
    int index = 0;
    bool making_exe = false;
    for (int i = 1; i < argc; ++i, ++(*num)) //iterate through the arguments
    {
        dbgmsg("in loop");
        if ( !( (argv[i][0] == 'A') && (argv[i][1] == 'A') ) )
        { //it's a program, not an argument
            dbgmsg("program");
            if (isExecutable(string(argv[i])))
            {
                making_exe = true;
                ++index;
                output[index].type = EXE;
                output[index].pexename = new string;
                *output[index].pexename = "\"";
                *output[index].pexename += argv[i];
                *output[index].pexename += "\"";
            }
            else
            {
                making_exe = false;
                ++index;
                output[index].type = LNK;
                output[index].plnkinf = new LNKINFO;
                output[index].plnkinf->filename = argv[i];
            }
        }
        else
        { //it's an argument
            dbgmsg("argument");
            int len = strlen(argv[i]);
            for (int j = 2; j < len; ++j) //this loop trims off the leading AA
            {
                argv[i][j-2] = argv[i][j];
            }
            argv[i][len-2] = '\0';
        
            if (making_exe) //no arguments for .lnks
            {
                if (!output[index].pexename) output[index].pexename = new string;
                *output[index].pexename += " ";
                *output[index].pexename += argv[i];
            }
            else
            {
                if (!output[index].plnkinf) output[index].plnkinf = new LNKINFO;
                output[index].plnkinf->pointedargs += argv[i];
            }
        }
    }
    return true;
}

There are no compiling or linking errors with Dev-C++ 4.9.9.2 (set to compile a console program but in Linker Settings it is set to not create a console window.)

Does anyone see the problem? (If you can't make sense of the code, tell me and I'll put even more comments in.)
  #2  
Old 07-May-2005, 04:04
Dr. Evil Dr. Evil is offline
Member
 
Join Date: Oct 2004
Location: Netherlands
Posts: 120
Dr. Evil will become famous soon enough
You're problem is your memory allocation for output in parseCommandLine(). You first allocate the memory (which will always allocate to zero thanks to two such assignments), then find how big it has to be. Thus, later on when the function returns, main() tries to cycle through the array's non-existant elements, causing a crash.
  #3  
Old 07-May-2005, 16:53
ubergeek ubergeek is offline
Regular Member
 
Join Date: Jan 2005
Posts: 775
ubergeek is a jewel in the roughubergeek is a jewel in the roughubergeek is a jewel in the rough
all right, made some progress but weird things are still happening.
here's the updated code:
CPP / C++ / C Code:
/*
   MultiShort v1.0
   
   by ubergeek
   
   runs multiple programs from one shortcut (see readme.txt for more details)
   
   MultiShort is free software. There is no warranty, implied or otherwise. If
   you like it, great. Use it. If you don't like it, don't use it. If it causes
   any harm to you or your computer, such as not working, deleteing files, or
   kidnapping your relatives, I am not responsible.
   
   ms.h
*/


#ifndef _MULTISHORT_PROGRAM_H_FILE_  //inclusion guard
#define _MULTISHORT_PROGRAM_H_FILE_


#include <windows.h> //windows API functions
#include <shlobj.h>  //IShellLink and IPersistFile interfaces
#include <wtypes.h>  //CLSCTX enumeration
#include <objbase.h> //interface-related functions
#include <objidl.h>  //interface-related functions
#include <strsafe.h> //StringCchCopy -- replacement for strcpy that causes segmentation faults much less often
#include <string>    //string class
//must link libole32.a and libuuid.a (in VC++ it would be ole32.lib and uuid.lib)
using namespace std;

enum PROGTYPE { EXE, LNK };

inline int dbgmsg(const char *msg) { return MessageBox(NULL, msg, "MultiShort: Debugging Message", MB_OK | MB_ICONINFORMATION); }
inline int errmsg(const char *msg) { return MessageBox(NULL, msg, "MultiShort: Error", MB_OK | MB_ICONERROR); }
inline int dbgmsg(const string &strmsg) { return dbgmsg(strmsg.c_str()); }
inline int errmsg(const string &strmsg) { return errmsg(strmsg.c_str()); }


struct LNKINFO         //holds information about a shortcut (.lnk) file
{
    string filename;    //actual filename of the .lnk
    string pointedprog; //file the shortcut points to
    string pointedargs; //any arguments to be passed on to pointedprog
    int pointedshowcmd; //window state to give to pointedprog
};

struct PROG
{
    PROGTYPE type;
    union /*anonymous*/
    {
        string *pexename;
        LNKINFO *plnkinf;
    };
};

bool isExecutable(string); //takes command-line argument (path and filename) as an std::string, and returns true if the file has a .exe extension, and false if it doesn't.
void getShortcutInfo(LNKINFO*); //takes path\filename of a shortcut (.lnk) and fills a LNKINFO structure
void toLower(string*); //takes a string and converts any uppercase letters in it to lowercase
int getNumProgs(int, char**); //takes the argc and argv from main, parses it, and determines how many actual programs/shortcuts there are to run
bool parseCommandLine(int, char**, PROG*);


#endif //inclusion guard
CPP / C++ / C Code:
/*
   MultiShort v1.0
   
   by ubergeek
   
   runs multiple programs from one shortcut (see readme.txt for more details)
   
   MultiShort is free software. There is no warranty, implied or otherwise. If
   you like it, great. Use it. If you don't like it, don't use it. If it causes
   any harm to you or your computer, such as not working, deleteing files, or
   kidnapping your relatives, I am not responsible.
   
   multishort.cpp
*/

#include "ms.h"

int main(int argc, char *argv[]) //argc tells me how many command-line arguments there are, and argv is an array of the command-line arguments passed to MultiShort, split at spaces (but not split inside quoted arguments)
{
    if (argc < 2)
    {
        errmsg("You didn't give me anything to run! Read readme.txt if you're confused.");
        return 1;
    }
    if ( (argv[1][0] == 'A') && (argv[1][1] == 'A') )
    {
        errmsg("First argument must be a program or shortcut, not an argument. Read readme.txt if you're confused.");
        return 1;
    }
    PROG *progs_to_run = NULL;
    int numprogs = getNumProgs(argc, argv);
    progs_to_run = new PROG[numprogs];
    if (progs_to_run == NULL)
    {
        dbgmsg("progs_to_run is NULL");
        return 0;
    }
    bool success = parseCommandLine(argc, argv, progs_to_run);
    dbgmsg("back from parsecommandline");
    if (progs_to_run == NULL)
    {
        dbgmsg("progs_to_run is NULL");
        return 0;
    }
    for (int i = 0; i < numprogs; ++i)
    {
        dbgmsg("in for loop");
        if (progs_to_run[i].type == EXE)
        {
            dbgmsg("exe:");
            dbgmsg(progs_to_run[i].pexename->c_str());
        }
        else
        {
            dbgmsg("lnk:");
            dbgmsg(progs_to_run[i].plnkinf->filename.c_str());
        }
    }
    dbgmsg("done outputting parsecmdln's work");
    if (!success)
    {
        errmsg("Fatal error. Exiting.");
        return 1;
    }
    if (numprogs < 2) //if you didn't provide two or more programs to run...
    {
        errmsg("You must provide two or more programs to run as command-line arguments. If you didn't provide any programs to run, why run this program? It doesn't as yet do anything else. If you only provided one program to run, then why use MultiShort? Just make a regular shortcut. Read readme.txt if you're confused."); //...then tell the user what went wrong and how to fix it.
        return 1;
    }
    STARTUPINFO startinfo;          //these structures are required by CreateProcess, but at this time MultiShort don't use them for anything. They provide a higher level of control over how the program is run, for example it can be run minimized.
    ZeroMemory(&startinfo, sizeof(STARTUPINFO));
    startinfo.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION procinfo;
    dbgmsg("starting real work");
    for (int i = 0; i < numprogs; i++) //this loop will run until all the command-line arguments have been considered
    {
        if (progs_to_run[i].type == EXE)
        {
            ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
            CreateProcess(NULL, const_cast<char*>(progs_to_run[i].pexename->c_str()), NULL, NULL, false, 0, NULL, NULL, &startinfo, &procinfo); //this is the most important line in the program. it runs the program specified in the command-line argument (argv[i])
            CloseHandle(procinfo.hProcess); //and, clean up after Windows
            CloseHandle(procinfo.hThread);
        }
        else //the file is not in the form path\filename.exe||bat||com
        {
            getShortcutInfo(progs_to_run[i].plnkinf); //fill our structure
            
            if (isExecutable(progs_to_run[i].plnkinf->pointedprog))
            {
                string exec = "\"";         //start with a space
                exec += progs_to_run[i].plnkinf->pointedprog; //add the filename
                exec += "\" ";              //closing quote and a space
                exec += progs_to_run[i].plnkinf->pointedargs; //and any arguments
                
                startinfo.wShowWindow = progs_to_run[i].plnkinf->pointedshowcmd;
                startinfo.dwFlags |= STARTF_USESHOWWINDOW;
                
                ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
                CreateProcess(NULL, const_cast<char*>(exec.c_str()), NULL, NULL, false, 0, NULL, NULL, &startinfo, &procinfo); //this is the most important line in the program. it runs the program specified in the command-line argument (lnkinf.pointedprog + lnkinf.pointedargs as lnkinf.pointedshowcmd)
                CloseHandle(procinfo.hProcess); //and, clean up after Windows
                CloseHandle(procinfo.hThread);
            }
            else
            {
                SHELLEXECUTEINFO shlexecinf;
                ZeroMemory(&shlexecinf, sizeof(SHELLEXECUTEINFO));
                shlexecinf.cbSize = sizeof(SHELLEXECUTEINFO); //initialize our structure...
                shlexecinf.hwnd = GetDesktopWindow(); //display messages with the desktop window as parent
                shlexecinf.lpVerb = "open"; //open the pointedprog
                shlexecinf.lpFile = new char[progs_to_run[i].plnkinf->pointedprog.length()+2];      //allocate our strings
                shlexecinf.lpParameters = new char[progs_to_run[i].plnkinf->pointedprog.length()+2];
                StringCchCopy(const_cast<char*>(shlexecinf.lpFile), progs_to_run[i].plnkinf->pointedprog.length()+1, progs_to_run[i].plnkinf->pointedprog.c_str());       //copy them
                StringCchCopy(const_cast<char*>(shlexecinf.lpParameters), progs_to_run[i].plnkinf->pointedargs.length()+1, progs_to_run[i].plnkinf->pointedargs.c_str());
                shlexecinf.nShow = progs_to_run[i].plnkinf->pointedshowcmd;

                if (!ShellExecuteEx(&shlexecinf)) //attempt to run the pointedprog...
                {
                    char errstr[300];
                    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errstr, 299, NULL); //...but if it doesn't work, check what the error was and retrieve it
                    string err = "Failed to execute \""; //assemble error description string
                    err += progs_to_run[i].plnkinf->pointedprog.c_str();
                    err += "\" because ";
                    err += errstr;
                    err += ". Make sure that the file exists and is not currently running or opened by another program.";
                    errmsg(err.c_str()); //display the error
                }
                
                delete[] shlexecinf.lpFile;       //memory leaks are bad
                delete[] shlexecinf.lpParameters;
            }
        }
    }
    
    delete[] progs_to_run; //memory leaks are still bad, although this one wouldn't be as serious because the program is going to exit in about a millisecond anyways and release all its memory back to the operating system
    
    return 0; //all done! goodbye!
}

bool isExecutable(string filename)
{
    int ilastdot = filename.rfind(".", filename.length()); //find the dot that designates the beginning of the extension
    string extension = filename.substr(ilastdot, filename.length() - ilastdot); //using that dot, slice off the extension
    toLower(&extension); //convert the extension to lowercase for comparison purposes
    return ( (extension == ".exe") || (extension == ".bat") || (extension == ".com") ); //check if the extension denotes an executable file
}

void toLower(string *str)
{
    for (string::iterator iter = str->begin(); iter != str->end(); ++iter)
    { //iterate through the string
        if ( ((int)*iter >= 65) && ((int)*iter <= 90) ) //if it's an uppercase letter
        {
            *iter += 32; //convert it to lowercase
        }
    }
}

void getShortcutInfo(LNKINFO *shortcut)
{
    CoInitializeEx(NULL, 0); //make CoCreateInstance work
    
    IShellLink *shell_link;    //declare interface pointers
    IPersistFile *persist_file;
    
    char path[MAX_PATH+1], args[INFOTIPSIZE+1];
    
    LRESULT ret = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&shell_link); //get a pointer to the IShellLink interface
    
    shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); //get a pointer to the IPersistFile interface

    WCHAR file[shortcut->filename.length()+1];
    MultiByteToWideChar(CP_ACP, 0, shortcut->filename.c_str(), -1, file, MAX_PATH);
    persist_file->Load(file, STGM_READ); //open the link

    shell_link->Resolve(GetDesktopWindow(), SLR_UPDATE); //resolve the link and update it if it has changed

    shell_link->GetPath(path, MAX_PATH, NULL, 0);      //gather information
    shell_link->GetArguments(args, INFOTIPSIZE);
    shell_link->GetShowCmd(&shortcut->pointedshowcmd);

    shortcut->pointedprog = path; //transfer information
    shortcut->pointedargs = args;

    shell_link->Release();   //release the interfaces
    persist_file->Release();
    
    CoUninitialize(); //undo whatever CoInitializeEx did
}

int getNumProgs(int argc, char **argv)
{
    int nprogs = 0;
    for (--argc; argc > 0; --argc)
    {
        if ( (argv[argc][0] == 'A') && (argv[argc][1] == 'A') ) continue;
        ++nprogs;
    }
    return nprogs;
}

bool parseCommandLine(int argc, char **argv, PROG *output)
{
    dbgmsg("in parsecommandline");
    if (output == NULL)
    {
        dbgmsg("output is null!");
        return false;
    }
    int index = 0;
    bool making_exe = false;
    for (int i = 1; i < argc; ++i) //iterate through the arguments
    {
        if ( !( (argv[i][0] == 'A') && (argv[i][1] == 'A') ) )
        { //it's a program, not an argument
            if (isExecutable(string(argv[i])))
            {
                making_exe = true;
                ++index;
                output[index].type = EXE;
                output[index].pexename = new string("\"");
                *output[index].pexename += argv[i];
                *output[index].pexename += "\"";
            }
            else
            {
                making_exe = false;
                ++index;
                output[index].type = LNK;
                output[index].plnkinf = new LNKINFO;
                output[index].plnkinf->filename = argv[i];
            }
        }
        else
        { //it's an argument
            int len = strlen(argv[i]);
            for (int j = 2; j < len; ++j) //this loop trims off the leading AA
            {
                argv[i][j-2] = argv[i][j];
            }
            argv[i][len-2] = '\0';
        
            if (making_exe) //no arguments for .lnks
            {
                if (!output[index].pexename) output[index].pexename = new string;
                *output[index].pexename += " ";
                *output[index].pexename += argv[i];
            }
            else
            {
                if (!output[index].plnkinf) output[index].plnkinf = new LNKINFO;
                output[index].plnkinf->pointedargs += argv[i];
            }
        }
    }
    return true;
}

Running with parameters:
Code:
c:\windows\system32\mspaint.exe AAc:\test.bmp c:\windows\system32\notepad.exe AAc:\test.txt

The parseCommandLine function appears to succeed but then my for loop to display the contents of progs_to_run behaves weirdly. First it tells me there is a shortcut and gives some weird gibberish characters for its filename (but the same ones each time). Then it outputs the paint exe correctly, and proceeds to crash.
 

Recent GIDBlogGoing to Iraq by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 18:57.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.