CreateProcess()似乎不受lpCurrentDirectory的影响

时间:2013-06-30 22:20:01

标签: c windows visual-c++ directory createprocess

我目前正在尝试使用CreateProcess()API启动一个进程: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

我遇到的主要问题是,无论 lpCurrentDirectory 参数中指示了什么,子进程似乎都是使用父进程的工作目录启动的>

提供更多细节:lpCurrentDirectory似乎适用于简单的命令行程序,但对于更复杂的命令行程序(想想GUI),似乎没有考虑到,因为从调用目录进程中搜索所有的ressource依赖项。

我可以尝试将调用进程工作目录切换回来&第四个问题,但第二个问题是被调用进程不在目标目录中。目前,它与调用进程位于同一目录中,尽管将来可能会发生变化。当我试图将子进程调用到与父进程不同的目录时,由于某种原因,它会失败。我已多次检查目录结构,到目前为止无济于事。

我一直在寻找(包括进入S.O.)虽然有些人似乎抱怨同样的问题,但我现在还没有找到可用的工作。请注意,例如,我不能使用ShellExec,它必须是CreateProcess()。

如果它确实重要,我目前的测试系统是Windows 7 64位。该软件应该适用于更广泛的操作系统,从XP到Seven,32& 64位(我猜W8现在不在范围内)。

[编辑] 我已经找到了在调用流程工作目录之外调用子进程的解决方案。我正在使用lpApplicationName,这很好,但显然不需要引用,即使复杂的名称涉及空格字符。

这使我能够在调用CreateProcess()之前测试修改调用进程的工作目录(使用SetCurrentDirectory()的想法。令我惊讶的是,它不起作用:工作目录实际上是指定到lpApplicationName的完整路径中的目录,无论由于SetCurrentDirectory()(并使用GetCurrentDirectory()验证)已经设置到父工作目录的任何内容/ p>

这是我的问题,因为我希望进程运行到另一个选定的目录(都指定为lpCurrentDirectory参数,并在CreateProcess()之前调用SetCurrentDirectory())。

1 个答案:

答案 0 :(得分:3)

我认为您的问题是您假设子进程应该尝试从当前目录加载其资源(如第三段中所示),而事实上,进程加载其资源的情况更为常见它从中启动的目录。换句话说,在大多数情况下,您所描述的行为都是预期的。

通过双击文档或使用拖放操作启动应用程序时,当前目录将设置为包含该文档的目录,因此如果应用程序从当前目录加载其资源,则会赢不行。

这个简单的测试应用程序演示了lpCurrentDirectory的工作原理,因为子进程的当前目录设置为指定的目录:

#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;
}

要测试应用程序,请使用如下命令行运行它:

currentdirectorytest *c:\Users\Public

父进程的第一个对话框显示父进程当前目录。子进程的第二个对话框显示子进程当前目录,并且应该是命令行上给出的目录。 (请注意,指定的目录必须存在,否则子进程的创建将失败。)