none
dwExitCode returns exit code 87 (ERROR_INVALID_PARAMETER) from ::GetExitCodeProcess after creating the process (launching the .exe) using ::CreateProcessW in C++ RRS feed

  • Question

  • Hello all,

     

    I am using the below code to create the process and to wait the process to exit.

    First I am calling _CreateProcessAndWaitEx function and this function internally calling ::CreateProcessW to create the process (launching the .exe).
    Here the paths are valid. So it is creating the process.

    After that calling MsgWaitForObject and this function internally calling ::GetExitCodeProcess. But here dwExitCode returns exit code 87 (i.e, ERROR_INVALID_PARAMETER)

    Could anyone please help me why here I am getting exit code 87 (ERROR_INVALID_PARAMETER)?

    Below is the code snippet:

    _CreateProcessAndWaitEx(LPCWSTR pszExePath, LPWSTR pszCmdLine, LPCWSTR pszCurrentDirectory, HANDLE hUserToken, BOOL bWait)
    {

    Below is the values of the above parameters:

    pszExePath = C:\Program Files\Common Files\Installer\emrinst.exe
    pszCmdLine=  C:\Test\Emrinst\src\pkg\2000.inf /install
    pszCurrentDirectory = C:\Test\src\TestPath
    hUserToken is NULL
    AND bWait IS TRUE


    LPWSTR      pszTemp;
    WCHAR       szWorkingDir[MAX_PATH + 1];
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    WCHAR szExe[MAX_PATH * 4];

    DWORD dwExitCode = 0;

    wcscpy_s(szWorkingDir, MAX_PATH + 1, pszExePath);
    pszTemp = wcsrchr(szWorkingDir, L'\\');
    if (pszTemp)
    *pszTemp = L'\0';
    else
    szWorkingDir[0] = L'\0';

    wsprintf(szExe, L"\"%s\" %s", pszExePath, pszCmdLine);

    ::ZeroMemory(&si, sizeof(si));
    ::ZeroMemory(&pi, sizeof(pi));

    si.cb = sizeof(si);
    si.lpDesktop = L"winsta0\\default";


    if (NULL != hUserToken)
    {
    dwExitCode = ::CreateProcessAsUser(hUserToken, 0, szExe,
    0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0,
    pszCurrentDirectory, &si, &pi);
    }
    else
    {

    // control is comming to this loop and creating the process

    dwExitCode = ::CreateProcessW(pszExePath, pszCmdLine,
    0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0,
    pszCurrentDirectory, &si, &pi);
    }
    if (0 == dwExitCode)
    {
    dwExitCode = ::GetLastError();
    return dwExitCode;
    }
    dwExitCode = 0;

    if (pi.hThread)
    ::CloseHandle(pi.hThread);

    if (pi.hProcess)
    {

    // Then it is comming to this loop and calling _MsgWaitForObject function


    if (bWait)
    dwExitCode = _MsgWaitForObject(&(pi.hProcess));
    ::CloseHandle(pi.hProcess);
    }

    return dwExitCode;
    }

    _MsgWaitForObject(HANDLE *phObjects)
    {

    MSG Msg;
    BOOL bResult = TRUE;

    DWORD       dwExitCode = ERROR_SUCCESS;

    while (bResult)
    {
    DWORD dwResult = ::MsgWaitForMultipleObjects(1, phObjects, FALSE, INFINITE, QS_ALLINPUT);

    if (WAIT_OBJECT_0 == dwResult)
    {
    // Here dwExitCode returns exit code 87 (i.e, ERROR_INVALID_PARAMETER)

    ::GetExitCodeProcess(phObjects[0], &dwExitCode);
    bResult = FALSE;
    break;
    }
    else
    {
    if ((WAIT_OBJECT_0 + 1) == dwResult)
    {
    while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
    {
    ::TranslateMessage(&Msg);
    ::DispatchMessage(&Msg);
    }
    }
    else
    {
    dwExitCode = GetLastError();
    break;
    }
    }
    }

    return dwExitCode;
    }

    Thanks in advance

    Wednesday, October 9, 2019 5:10 PM

Answers

  • If you cannot fix the installer to accept “-”, then maybe consider the next workaround:

    • For the first parameter of CreateProcessW, specify the full path of installer without additional quotation marks, even if the path contains space.
    • For the second parameter, specify name and option: “2000.inf /install” (or maybe “2000.inf  ‑install”. If the name is different and includes spaces, then use quotation marks.
    • For lpCurrentDirectory, specify the location of 2000.inf, i.e. “C:\Test\Emrinst\src\en-US\pkg”, without additional quotation marks.


    Sunday, October 13, 2019 6:36 PM

All replies

  • Maybe you should check the BOOL result of GetExitCodeProcess. If it is not FALSE, then probably 87 is one of return codes of installer, having some meaning. If it is FALSE, then call immediately GetLastError to get details.

    • Edited by Viorel_MVP Wednesday, October 9, 2019 6:33 PM
    Wednesday, October 9, 2019 6:30 PM
  • Perhaps the program you are executing doesn't like your command line, terminated and set its exit code as 87
    Wednesday, October 9, 2019 6:50 PM
  • You do not show the declaration of phObjects nor how it is filled.

    Also, I cannot find the following in the MSDN.

    • _MsgWaitForObject
    • _CreateProcessAndWaitEx



    Sam Hobbs
    SimpleSamples.Info

    Wednesday, October 9, 2019 8:11 PM
  • Hi @RLWA32,

    You are correct, it is due to the command line path. We are setting the command line path using the below code:

           std::wstring strCommandLine = L"";
    strCommandLine += L"\"";
    strCommandLine += strInfFile;
    strCommandLine += L"\"";
    strCommandLine += L" /install";

    Once I set double quotes to the command line path, passing it to the CreateProcess function like as shown below:

          pszCmdLine="C:\Test\Emrinst\src\pkg\2000.inf" /install

    But the system is interpreting pszCmdLine as /install

    It is truncating the double quoted path "C:\Test\Emrinst\src\pkg\2000.inf"and showing
    Installer Command line: /install

    (Error) No valid inf file set. There was something wrong with the installer parameters.

    Is the way I am setting the command line parameter (using quotes) is wrong?

    Could anyone please help me to resolve this?


    Friday, October 11, 2019 6:33 PM
  • Try including the fully qualified path to the program as the first parameter passed on the command line.

    int main(int argc, char *argv[])
    or
    int wmain(int argc, wchar_t *argv[])

    A C/C++ console application that retrieves command line parameters from main/wmain will expect that argv[0] is the program name.

    Perhaps your installer is making the same assumption and so it is disregarding the content of argv[0] which, in your example, is a parameter other than the program name.

    https://docs.microsoft.com/en-us/cpp/c-language/arguments-to-main?view=vs-2019


    • Edited by RLWA32 Friday, October 11, 2019 7:03 PM added link
    Friday, October 11, 2019 7:01 PM
  • I found the root cause of the issue. It is because the space in the first parameter i.e., lpApplicationName of the CreateProcessW function

    In the below path (pszExePath) there are spaces because of this process is not creating.

    pszExePath = "C:\\Program Files\\Common Files\\Installer\\emrinst.exe";

    I tried to trim the space by adding quotes to the path using the below lines but still i am facing the issue.

    pszExePath = L"\"";
    pszExePath += "C:\\Program Files\\Common Files\\Installer\\emrinst.exe";
    pszExePath += L"\"";

    could anyone please help me how to trim the space from the path?





    Saturday, October 12, 2019 5:10 PM
  • Any path that contains embedded spaces should be enclosed in double quotes (").
    Saturday, October 12, 2019 6:10 PM
  • It seems you are changing the problem.

    Initially you said that the process was created but returned exit code 87.

    Now you are saying the process is not created.

    So exactly what did you change and how did you change it.

    Assuming that pszExePath is a std::wstring object  then this code snippet -

    pszExePath = L"\"";
    pszExePath += "C:\\Program Files\\Common Files\\Installer\\emrinst.exe";
    pszExePath += L"\"";

    will not compile.

    So when you post code, make sure to post the actual code being used, and from now on, use the "Insert Code Block" button for the code you post.  It makes it a lot easier to read it.


    • Edited by RLWA32 Saturday, October 12, 2019 7:11 PM
    Saturday, October 12, 2019 7:10 PM
  • Hi @RLWA32

    Sorry for the confusion. I am trying to fix the issue by changing the code placing paths with double quotes(").

    First parameter is not accepting the quotes. To resolve that set the first parameter of the CreateProcessW function as NULL and to the second parameter passing the complete path. with this it is working.

    But if the path has special characters like in the second parameter path is embedded with hyphen (en-US) in that case again getting exit code 87.
    Here also it is creating the process and then getting exit code 87.

    Below is the code that i have changed:

    In to the CreateProcessW function, I am passing the lpApplicationName (pszExePath) and then passing lpCommandLine (pszCmdLine)

    To resolve the embedded spaces enclosing the paths with double quotes(").
    With command line path is working properly. But the lpApplicationName is not accepting the double quotes(").

    std::wstring pszExePath; std::wstring pszCmdLine;

    pszExePath = L"\""; pszExePath += L"C:\\Program Files\\Common Files\\Installer\\emrinst.exe"; pszExePath += L"\"";

    pszCmdLine = L" ";  pszCmdLine += L"\""; pszCmdLine += "C:\\Test\\Emrinst\\src\\en-US\\pkg\\2000.inf";    pszCmdLine += L"\""; pszCmdLine += L" /install";


    So changed the CreateProcessW function by setting the first parameter as NULL.
    And then adding lpApplicationName and lpCommandLine into a string and pass it to the second parameter.

    std::wstring strFullPath = L""; strFullPath += pszExePath; strFullPath += pszCmdLine;

    std::wstring pszCurrentDirectory; pszCurrentDirectory = "C:\\Test\\src\\TestPath"; DWORD dwExitCode = 0;

    dwExitCode = ::CreateProcessW(NULL, (LPWSTR)strFullPath.c_str(),0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0,

    pszCurrentDirectory, &si, &pi);


    Could anyone please explain if is there anyway to resolve the special character issue in the path?

    Sunday, October 13, 2019 4:12 PM
  • Does it work when you start the program manually? Does it accept “-” correctly?

    Sunday, October 13, 2019 4:54 PM
  • Hi @Viorel_,

    It is not accepting the "-" when i tested manually.

    I tried the program by debugging. Even in that case also it is not accepting "-".

    Regards,

    Sunday, October 13, 2019 5:20 PM
  • Again, the posted code will not compile.

    pszCmdLine += "C:\\Test\\Emrinst\\src\\en-US\\pkg\\2000.inf";   	

    pszCmdLine is a std::wstring.  Boom, compilation error.

    dwExitCode = ::CreateProcessW(NULL, (LPWSTR)strFullPath.c_str(),0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, pszCurrentDirectory, &si, &pi);

    The above also caused a compilation error. pszCurrentDirectory is a std::wstring.

    My test had no problem accepting the "-" character in the passed parameter.  And it is not among those characters that are illegal for use in a name.
    • Edited by RLWA32 Sunday, October 13, 2019 6:14 PM
    Sunday, October 13, 2019 5:51 PM
  • If you cannot fix the installer to accept “-”, then maybe consider the next workaround:

    • For the first parameter of CreateProcessW, specify the full path of installer without additional quotation marks, even if the path contains space.
    • For the second parameter, specify name and option: “2000.inf /install” (or maybe “2000.inf  ‑install”. If the name is different and includes spaces, then use quotation marks.
    • For lpCurrentDirectory, specify the location of 2000.inf, i.e. “C:\Test\Emrinst\src\en-US\pkg”, without additional quotation marks.


    Sunday, October 13, 2019 6:36 PM
  • Now I'm confused.

    Is the problem with CreateProcessW or with the program being executed?


    • Edited by RLWA32 Sunday, October 13, 2019 6:43 PM
    Sunday, October 13, 2019 6:43 PM
  • Thankyou @Viorel_ and @RLWA32 for your valuable inputs

    I followed your instructions and passed the first two parameters and formed the path like as shown below:

    C:\Program Files\Common Files\Installer\emrinst.exe "2000\2000.inf" /install /WorkingDir=C:\Test\Emrinst\src\en-US\pkg

    Now it is accepting "-" and working fine. Finally I resolved the issue.

    Once again thank you...
    Monday, October 14, 2019 2:49 PM
  • @RLWA32,

    I am also confused whether the issue is with CreateProcessW  or the program that is executing (emrinst.exe). Finally I understood that it is with the program that is executing.

    Monday, October 14, 2019 2:52 PM