【问题标题】:why does ::CreateProcess(path,cmd,...) fail with error "File not found"?为什么 ::CreateProcess(path,cmd,...) 失败并出现错误“找不到文件”?
【发布时间】:2011-06-22 22:58:24
【问题描述】:

我试图让一个 C++ 程序调用一个已经制作好的 C# 程序在后台运行。

STARTUPINFO info = {sizeof(info)};
PROCESS_INFORMATION processinfo;
DWORD error1 = GetLastError();
bool x = ::CreateProcess((LPCWSTR)"C:\Convert_Shrink.exe", GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
DWORD error = GetLastError();

在 CreateProcess 之前error1 为 0 CreateProcess 后错误为 2

错误 2:

ERROR_FILE_NOT_FOUND 2 (0x2) The system cannot find the file specified.

我已将其更改为 C:\ \ 以防他们检查转义序列,但我仍然收到错误 2,我不知道为什么。

【问题讨论】:

  • 这种转换只会阻止编译器告诉你你做错了。它并没有阻止你做错事。在字符串前面放一个 L 使其成为 Unicode 文字。
  • 应用程序路径是否也只能这么长?我把程序放在C:\进行测试,但它需要与目录较深的程序在同一目录中。

标签: c++ winapi


【解决方案1】:

你可以:

  • 使用CreateProcessA 匹配您的ANSI 文件路径:

    bool x = ::CreateProcessA("C:\\Convert_Shrink.exe", GetCommandLineA(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

* 提供与您的 Unicode 设置所需的字符串格式相匹配的文件路径:

    bool x = ::CreateProcess(_T("C:\\Convert_Shrink.exe"), GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);

  • 使用CreateProcessW,这样你就可以传递一个Unicode文件路径(支持扩展字符):

    bool x = ::CreateProcessW(L"C\\\Convert_Shrink.exe", GetCommandLineW(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

(正如@dolphy 所说,参数必须是可写字符串)

  • 提供与您的 Unicode 设置所需的字符串格式相匹配的文件路径:

    #if UNICODE
    std::wstring exename =
    #else
    const char* exename =
    #endif
        _T("C:\\Convert_Shrink.exe");
    bool x = ::CreateProcess(&exename[0], GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

  • 使用CreateProcessW,这样你就可以传递一个Unicode文件路径(支持扩展字符):

    wchar_t exename[] = L"C:\\Convert_Shrink.exe";
    bool x = ::CreateProcessW(exename, GetCommandLineW(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

【讨论】:

  • 你做了一顿这顿饭。只需将(LPCWSTR) 替换为L 就可以了! ;-)
  • @David:不,CreateProcessW 要求它的参数是可写的。 MSDN 明确禁止传递字符串文字。
  • 非常好。我猜这是因为实现使用输入缓冲区进行解析。
【解决方案2】:

仅作记录。 CreateProcessAsUser 在内部调用 SearchPath。 SearchPath 使用文件系统重定向器https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187%28v=vs.85%29.aspx

因此,如果您在 WOW64 下运行 32 位应用程序,并且您在 system32 目录中请求使用 exe 的进程,例如“c:\windows\system32\myapp.exe”,CreateProcessAsUser 将在 syswow64 中查找,例如“c:\windows\syswow64\myapp.exe”。如果您的 exe 不存在,您将收到“找不到文件错误”。

【讨论】:

  • 感谢此文件系统重定向说明。我在 Win 7 x64 位系统上浪费了半天时间来解决这个问题! :)
【解决方案3】:

我刚刚查找了 GetCommandLine(),MSDN 声明它获取当前进程的命令行。 CreateProcess() 的 MSDN 条目指出第二个参数是您想要执行的命令行命令,如果我没看错的话。因此,您实际上是在告诉 CreateProcess() 运行 C++ 程序的另一个实例,而不是 C# 程序。

(编辑) 实际上,经过仔细检查, CreateProcess() 文档似乎并没有清楚地解释如果您同时提供第一个和第二个参数会发生什么。它说第一个指定模块,第二个指定命令行。有什么区别?

很抱歉这个不确定的答案,如果可以的话,我会把这个答案转换成几个关于你的问题的 cmets。

【讨论】:

  • 也许他想转发所有的论点。很难说。但演员阵容绝对是错误的。
【解决方案4】:

您是否尝试将字符串转换为 LPCTSTR

bool x = ::CreateProcess((LPCTSTR)"C:\Convert_Shrink.exe", GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo); 

From Microsoft:

The Unicode version of this function, CreateProcessW, can modify the contents 
of this string. Therefore, this parameter cannot be a pointer to read-only 
memory (such as a const variable or a literal string). If this parameter is a 
constant string, the function may cause an access violation.

【讨论】:

  • 很好地抓住了糟糕的演员阵容。不幸的是,这个“修复”很糟糕(-1)。在@Grant 显然拥有的 Unicode 版本中,这与问题中的代码完全相同。
  • 很公平。我想除了我质疑的演员表本身之外,我认为它不是一个 unicode 版本,这对我来说并不明显。但是,这可能意味着我不应该回答。
  • 投到(LPCTSTR) 是个坏主意。因为字面意思是一样的。正确的方法是使用 _T() 宏。
  • 您引用的文档也非常重要,并且发现了我最初犯的一个错误。但同样,演员表不是解决方案。
  • 同意。我没有删除答案的唯一原因是让其他人可以了解确切的区别(就像我刚才所做的那样)。
猜你喜欢
  • 2020-11-23
  • 1970-01-01
  • 2014-02-05
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多