12

How do I pass path with space to the CreateProcess() function?

The following works

STARTUPINFO si;
            PROCESS_INFORMATION pi;

            ZeroMemory( &si, sizeof(si) );
            si.cb = sizeof(si);
            ZeroMemory( &pi, sizeof(pi) );

            if( !CreateProcess(_T("c:\\installer\\ew3d.exe"),    // No module name (use command line)
                _T("c:\\installer\\ew3d.exe /qr"),//argv[1],        // Command line
                NULL,           // Process handle not inheritable
                NULL,           // Thread handle not inheritable
                FALSE,          // Set handle inheritance to FALSE
                0,              // No creation flags
                NULL,           // Use parent's environment block
                NULL,           // Use parent's starting directory 
                &si,            // Pointer to STARTUPINFO structure
                &pi )           // Pointer to PROCESS_INFORMATION structure
                ) 
            {
                printf( "CreateProcess failed (%d).\n", GetLastError() );
                return false;
            }

            //Wait until child process exits.
            WaitForSingleObject( pi.hProcess, INFINITE );

            // Close process and thread handles. 
            CloseHandle( pi.hProcess );
            CloseHandle( pi.hThread );

But if I use a path with space as as the code below, it didn't work.

CreateProcess(_T("c:\\master installer\\ew3d.exe"),    // No module name (use command line)
                    _T("c:\\master installer\\ew3d.exe /qr"),//argv[1],        // Command line
                    NULL,           // Process handle not inheritable
                    NULL,           // Thread handle not inheritable
                    FALSE,          // Set handle inheritance to FALSE
                    0,              // No creation flags
                    NULL,           // Use parent's environment block
                    NULL,           // Use parent's starting directory 
                    &si,            // Pointer to STARTUPINFO structure
                    &pi )           // Pointer to PROCESS_INFORMATION structure
                    ) 

And quoting the command such as below didn't help too

CreateProcess(_T("\"c:\\master installer\\ew3d.exe\""),    // No module name (use command line)
                    _T("\"c:\\master installer\\ew3d.exe\" /qr"),//argv[1],        // Command line
                    NULL,           // Process handle not inheritable
                    NULL,           // Thread handle not inheritable
                    FALSE,          // Set handle inheritance to FALSE
                    0,              // No creation flags
                    NULL,           // Use parent's environment block
                    NULL,           // Use parent's starting directory 
                    &si,            // Pointer to STARTUPINFO structure
                    &pi )           // Pointer to PROCESS_INFORMATION structure
                    ) 

What is the right way to pass in the path with space?

david.healed
  • 1,289
  • 7
  • 16
  • 31

5 Answers5

23

In response to another answer, example #3 is NOT the correct one.

The issue is that the quotes should NOT encapsulate the module pathname passed as the first parameter of CreateProcess. However, quotes SHOULD encapsulate arg0 (again module path) as passed for the command line (second parameter of CreateProcess).

So, the correct rendition would be:

CreateProcess(_T("c:\\master installer\\ew3d.exe"),    
                    _T("\"c:\\master installer\\ew3d.exe\" /qr"),
                    NULL,           // Process handle not inheritable
                    NULL,           // Thread handle not inheritable
                    FALSE,          // Set handle inheritance to FALSE
                    0,              // No creation flags
                    NULL,           // Use parent's environment block
                    NULL,           // Use parent's starting directory 
                    &si,            // Pointer to STARTUPINFO structure
                    &pi )           // Pointer to PROCESS_INFORMATION structure
                    ) 
dyasta
  • 2,056
  • 17
  • 23
3

Your 3rd snippet is the correct one, not sure why you have trouble. Having the GetLastError() return value would be valuable here. Do note however that the 2nd argument of CreateProcess is an LPTSTR, not an LPCTSTR. In other words, Windows can write back to the string. Pretty creepy, isn't it? Enough reason perhaps to use ShellExecuteEx() instead.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • For the third snippet, GetLastError() return 123 which means "The filename, directory name, or volume label syntax is incorrect." – david.healed Oct 29 '10 at 16:29
  • Unusual. Is the path you use *exactly* as posted or did you doctor it? – Hans Passant Oct 29 '10 at 17:14
  • Copy exactly from my test application. – david.healed Oct 30 '10 at 03:52
  • Yes, I gave up CreateProcess() and use ShellExcuteEx() which doesn't have this problem anymore. But I have a very weird problem perhaps you can have a look at it - http://stackoverflow.com/questions/4058073/windows-api-shellexecuteex-didnt-wait-on-usb-drive-and-cd-drive – david.healed Oct 30 '10 at 09:44
  • 3
    The issue is that the quotes should not encapsulate the module pathname (first parameter of CreateProcess). That's why the error is path does not exist. However, you *should* continue to quote encapsulate arg0 (again module path) as passed for the command line (second parameter of CreateProcess). I posted new answer below. – dyasta Nov 26 '13 at 20:11
2

You don't need to specify the application path in both the first and second arguments. According to the MSDN documentation the second argument should be only command line arguments if you list the application name in the first argument. Otherwise, set the first argument to NULL and then in the second argument enclose the application name in quotes if it contains a space. Not sure why your last listing doesn't work.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • I got the idea (putting full path on both arguments) from http://stackoverflow.com/questions/1135784/createprocess-doesnt-pass-command-line-arguments. And in fact I tested it - it fail if I don't put full path in both arguments. – david.healed Oct 29 '10 at 15:46
2

Docs are unclear, but it seems possible that if you include a space you must allow param 2 to define the full path.

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous.

Have you tried this variation?

CreateProcess(NULL,    // No module name (use command line)
              _T("\"c:\\master installer\\ew3d.exe\" /qr"),//argv[1],        // Command line
              NULL,           // Process handle not inheritable
              NULL,           // Thread handle not inheritable
              FALSE,          // Set handle inheritance to FALSE
              0,              // No creation flags
              NULL,           // Use parent's environment block
              NULL,           // Use parent's starting directory 
              &si,            // Pointer to STARTUPINFO structure
              &pi )           // Pointer to PROCESS_INFORMATION structure
             ) 

EDIT: The following worked for me (dwError is 0). My project is built with multibyte charset.

LPTSTR szCmdLine = _tcsdup(TEXT(
    "\"C:\\Program Files\\adobe\\Reader 8.0\\reader\\acrord32.exe\" /qr"));
CreateProcess(NULL,
              szCmdLine,
              NULL,           // Process handle not inheritable
              NULL,           // Thread handle not inheritable
              FALSE,          // Set handle inheritance to FALSE
              0,              // No creation flags
              NULL,           // Use parent's environment block
              NULL,           // Use parent's starting directory 
              &si,            // Pointer to STARTUPINFO structure
              &pi            // Pointer to PROCESS_INFORMATION structure
             );     // This works. Downcasting of pointer to members in general is fine.

DWORD error = GetLastError();
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
1

A bit late to the party. For some reason, I cannot up-vote Praetorian, but he's right. I was suffering from the same problem, and NULLing the Application Name did the trick. I also tried path in App Name & just the command line params in the second argument, to no avail.

I am on Win7 x64.

CreateProcess (NULL, "\"Path to exe\" -x -y -z", ...);

works for me.

sachinjm
  • 95
  • 1
  • 8
  • 1
    That works, but isn't 100% pedantically correct. My answer (the one most upvoted) explains the full context. The accepted answer above it is wrong. – dyasta Jun 16 '15 at 16:24