3

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

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

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

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

我一直在环顾四周(包括 SO),尽管有些人似乎抱怨同样的问题,但我目前还没有找到可用的解决方法。请注意,例如,我不能使用 ShellExec,它必须是 CreateProcess()。

万一这很重要,我当前的测试系统是 Windows 7 64 位。该软件应该可以在更广泛的操作系统上运行,从 XP 到 7、32 和 64 位(我猜 W8 暂时超出了范围)。

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

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

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

4

1 回答 1

2

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

当应用程序通过双击文档或拖放启动时,当前目录设置为包含该文档的目录,因此如果应用程序从当前目录加载其资源,它将无法工作.

这个简单的测试应用程序演示了它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

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

于 2013-10-11T02:02:35.230 回答