Windows API - CreateProcess() path with space

2020-03-10 05:22发布

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?

标签: winapi
5条回答
▲ chillily
2楼-- · 2020-03-10 05:57

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.

查看更多
兄弟一词,经得起流年.
3楼-- · 2020-03-10 05:58

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.

查看更多
女痞
4楼-- · 2020-03-10 06:03

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.

查看更多
We Are One
5楼-- · 2020-03-10 06:14

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
                    ) 
查看更多
该账号已被封号
6楼-- · 2020-03-10 06:15

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();
查看更多
登录 后发表回答