سؤال

I'm currently trying to start a process using CreateProcess() API : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

The main issue I'm getting is that the child process seems to be launched with the working directory of the parent process, regardless of what is indicated into the lpCurrentDirectory parameter.

To give a bit more details : lpCurrentDirectory seems to work for simple command-line programs, but for more complex ones (think GUI), it seems not taken into consideration, since all ressource dependencies are searched from the calling directory process.

I could try to switch the calling process working directory back & forth, but a second issue is that the called process is not located into the target directory. For the time being, it is located into the same directory as the calling process, although it could change in the future. When I'm trying to call a child process located into a different directory than the parent one, for some reason, it fails. I've checked the directory structure multiple times, to no avail up to now.

I've been looking around (including into S.O.) and although some people seem to complain about the same issue, I have not found a usable work around for now. Note, for example, that I can't use ShellExec instead, it has to be CreateProcess().

In case it does matter, my current test system is Windows Seven 64 bits. The software is supposed to work on a wider range of OS, from XP to Seven, 32 & 64 bits (I guess W8 is out of scope for now).

[Edit] I've been able to find a solution to call a child process outside of the calling process working directory. I was using lpApplicationName for that, which is fine, but apparently does not need to be quoted, even with complex names involving space characters.

This allowed me to test the idea of modifying the working directory of the calling process (using SetCurrentDirectory()) before invoking CreateProcess(). To my surprise, it did not work : the working directory is in fact the directory specified into the full path of lpApplicationName, regardless of whatever has been set to the parent's working directory thanks to SetCurrentDirectory() (and verified using GetCurrentDirectory())

This is a problem in my case, since I want the process to run into another selected directory (both specified into lpCurrentDirectory parameter, and with a call to SetCurrentDirectory() before CreateProcess()).

هل كانت مفيدة؟

المحلول

I believe your problem is that you are assuming that the child process should try to load its resources from the current directory (as suggested in your third paragraph) when in fact it is much more usual for a process to load its resources from the directory it is launched from. In other words, the behaviour you are describing is as-expected in most cases.

When an application is launched by double-clicking on a document or by using drag-and-drop, the current directory is set to the directory containing the document, so if the application loads its resources from the current directory, it won't work.

This simple test application demonstrates that lpCurrentDirectory works, in that the current directory of the child process is set to the directory specified:

#include <Windows.h>

void showcd(wchar_t * caption)
{
    wchar_t buffer[512];

    if (GetCurrentDirectory(512, buffer) == 0)
    {
        DWORD err = GetLastError();
        MessageBox(NULL, L"GetCurrentDirectory failed", caption, MB_OK);
        ExitProcess(err);
    }

    buffer[511] = L'\0';
    MessageBox(NULL, buffer, caption, MB_OK);
}

void parent(wchar_t * cd)
{
    wchar_t cmd[512];
    STARTUPINFO sinfo;
    PROCESS_INFORMATION pinfo;

    GetStartupInfo(&sinfo);

    showcd(L"Parent Process");

    if (GetModuleFileName(NULL, cmd, 512) == 0)
    {
        MessageBox(NULL, L"GetModuleFileName failed", L"Parent Process", MB_OK);
        ExitProcess(GetLastError());
    }

    cmd[511] = L'\0';

    if (!CreateProcess(
        cmd, NULL, NULL, NULL, FALSE, 0, NULL, cd, &sinfo, &pinfo
        ))
    {
        DWORD err = GetLastError();
        MessageBox(NULL, L"CreateProcess failed", L"Oops", MB_OK);
        ExitProcess(err);
    }
}

int CALLBACK WinMain( 
  _In_  HINSTANCE hInstance,
  _In_  HINSTANCE hPrevInstance,
  _In_  LPSTR lpCmdLine,
  _In_  int nCmdShow
) 
{
    wchar_t * cmdline;
    for (cmdline = GetCommandLine(); *cmdline; cmdline++)
    {
        if (*cmdline == L'*') 
        {
            parent(cmdline + 1);
            return 0;
        }
    }

    showcd(L"Child Process");
    return 0;
}

To test the application, run it with a command line like this:

currentdirectorytest *c:\Users\Public

The first dialog box, from the parent process, shows the parent process current directory. The second dialog box, from the child process, shows the child process current directory and should be the directory given on the command line. (Note that the directory specified must exist, or creation of the child process will fail.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top