views:

2279

answers:

8

Hello I have the following code but it isn't working as expected, can't figure out what the problem is.

Basically, I'm executing a process (a .NET process) and passing it command line arguments, it is executed successfully by CreateProcess() but CreateProcess() isn't passing the command line arguments

What am I doing wrong here??

int main(int argc, char* argv[])
{
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field

    LPTSTR cmdArgs = "[email protected]";

    if(CreateProcess("D:\\email\\smtp.exe", cmdArgs, 
        NULL,NULL,FALSE,0,NULL,
        NULL,&StartupInfo,&ProcessInfo))
    { 
        WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);

        printf("Yohoo!");
    }  
    else
    {
        printf("The process could not be started...");
    }

    return 0;
}

EDIT: Hey one more thing, if I pass my cmdArgs like this:

// a space as the first character
LPTSTR cmdArgs = " [email protected]";

Then I get the error, then CreateProcess returns TRUE but my target process isn't executed.

Object reference not set to an instance of an object
+1  A: 

Try this:

LPTSTR cmdArgs = "[email protected]";
CString szcmdline("D:\\email\\smtp.exe");
szcmdline += _T(" ") + cmdArgs ;

//Leave first param empty and pass path + argms in 
    if(CreateProcess(NULL, szcmdline, second
aJ
Error in that code, you're putting the value into szcmdline_in but using szcmdline. Any reason why to bring MFC strings into the example?
Ray Hayes
No specific reason.It was just for symbolic. I will change the szcmdline_in to szcmdline. Thanks.
aJ
+4  A: 

You should specify also the module name in parameters: LPTSTR cmdArgs = "App [email protected]"; It should be the whole command line (including argv[0]).

EFraim
I get the errorObject reference not set to an instance of an object
hab
This helps. It would never know if I didn't come across this answer.
david.healed
+1  A: 

It doesn't look like you are using CreateProcess correctly, see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx.

  • The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.

  • The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

  • If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.

So in your case, you need this as the command argument and should probably pass a NULL for the first parameter to get the behaviour your want.

// NOTE THE Null-Terminated string too!
LPTSTR cmdArgs = "D:\\email\\smtp.exe [email protected]\0";
Ray Hayes
Your code snippet at the end defines a string with TWO null terminators - no need to explicitly put in a second one.
Daniel Earwicker
I get the errorObject reference not set to an instance of an object
hab
@Earwicker, been a long time since I've done C++, still the result is the same...
Ray Hayes
A: 

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

Therefore you can try using LPTSTR cmdArgs = _tcsdup("[email protected]").

Another problem is: how does the target process reads the arguments? using argv[0] as application name? Then you shoud append the application name as the first parameter too.

Vlagged
Or drop the memory management responsibility back where it belongs, the compiler: TCHAR[] cmdArgs = _T("[email protected]");
MSalters
A: 

You are not allocating memory for your string.

Instead of:

LPTSTR cmdArgs = "[email protected]";

try:

TCHAR cmdArgs[] = "[email protected]";

Edit: then call:

 CreateProcess("D:\\email\\smtp.exe", &cmdArgs[0], ...

This will create a local array on the stack and then pass a pointer to that array.

morechilli
error C2440: 'initializing' : cannot convert from 'char (*)[20]' to 'char *'
hab
morechilli
A: 

If the first parameter to CreateProcess() is non-NULL, it will use that to locate the image to launch.

If it is NULL, it will parser the 2nd argument to try to get the executable to launch from the 1st token.

In either case, the C runtime will use the second argument to populate the argv array. So the first token from that parameter shows up in argv[0].

You probably want something like the following (I've change the smtp.exe program to echoargs.exe - a simple utility I have to help figure out just this kind of issue):

int main(int argc, char* argv[])
{
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter
    LPSTR cmdArgs = "echoargs.exe [email protected]";

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field


    if(CreateProcess("C:\\util\\echoargs.exe", cmdArgs, 
        NULL,NULL,FALSE,0,NULL,
        NULL,&StartupInfo,&ProcessInfo))
    { 
        WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);

        printf("Yohoo!");
    }  
    else
    {
        printf("The process could not be started...");
    }

    return 0;
}

Here's the output I get from that program:

echoargs.exe [email protected]
[0]: echoargs.exe
[1]: [email protected]

Yohoo!
Michael Burr
A: 

Below is a cut down version of the code used by the Zeus IDE to run external processes:

bool createProcess(const char *pszTitle, const char *pszCommand)
{
  STARTUPINFO StartInfo;

  memset(&StartInfo, 0, sizeof(StartInfo));

  StartInfo.cb      = sizeof(StartInfo);
  StartInfo.lpTitle = (pszTitle) ? (char *)pszTitle : (char *)pszCommand;

  StartInfo.wShowWindow = SW_NORMAL;
  StartInfo.dwFlags    |= STARTF_USESHOWWINDOW;

  if (CreateProcess(0, (char *)pszCommand, 
                    0, 0, TRUE,
                    CREATE_NEW_PROCESS_GROUP, 0, 0, 
                    &StartInfo, &ProcessInfo))
  {
    lErrorCode = 0;
  }
  else
  {
    lErrorCode = GetLastError();
  }

  return (lErrorCode == 0);
}

The pszCommand would be the full executable path and file name and arguments so for example:

pszCommand = "D:\\email\\smtp.exe [email protected]";

From what I can tell, the only real difference between the two is that in the Zeus example, the dwCreationFlags argument is set to the CREATE_NEW_PROCESS_GROUP value.

jussij
A: 

i find this thread useful to the problem i am currently having with delphi 7. can somebody kindly translate this to delphi please? thanks in advance...

abby