CreateProcess 失败 - 错误 183

CreateProcess Fails - Error 183

因此,我无法更改的代码调用可执行文件,我需要为其提供与黑盒代码调用不同的命令行参数。我想我可以制作一个可执行文件作为代理。 proc.exe 位于黑盒部分预期的位置,获取命令行参数,修改它们,然后调用 procReal.exe 原始文件。

不幸的是,CreateProcess 似乎无法启动,返回状态 183。我已经尽我所能查找了一切,但找不到太多相关信息。尝试翻转事物,将句柄继承设置为 true,手动指定工作目录,但不执行任何这些操作。没运气。我假设这里发生了一些事情,继承了调用应用程序的正确安全上下文,因此包装器可以作为正确的直通,但我不知道该怎么做...

下面的代码,不相关的部分被删减了。

编辑 请求后将完整代码放在这里。这已经没有任何意义了。它现在将部分工作,但前提是 traceFilefopen 部分不存在。连fprintfs都删不掉,特别是整段都要删掉

我已经尝试回复每个人的评论,我想我已经排除了其中大部分问题,但目前的异常行为仍然存在。我能读到的更多内容说,某些形式的复制字符串可能会导致内存溢出,这有可能吗?

#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <tchar.h>
#include <algorithm>
#include <string>

using namespace std;

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 );

int main(int argc, char* argv[]) {

    const string path = "E:\util\bin\";
    const string procName = "procReal.exe";
    const string argToFilter = "-t";


    string origValue;
    string passedValue;

    for(int i = 1; i < argc; i++)
    {
        origValue.append(" ").append(argv[i]);
    }

    for(int i = 1; i < argc; i++)
    {
        if (!caseInsensitiveStringCompare(argv[i],argToFilter))
        {
            passedValue.append(" ").append(argv[i]);
        }
        else
        {
            i++; // skip over argument and it's value
        }

    }

    const LPCTSTR exeModule = (path+procName).c_str();

    std::vector<char> chars(passedValue.c_str(), passedValue.c_str() + passedValue.size() + 1u);
    LPTSTR exeArgs = &chars[0];


    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    GetStartupInfo(&si);

    FILE* traceFile;
  traceFile = fopen ((path+"lastRun.txt").c_str(), "w");  // This causes exeModule to change value for unknown reasons???
  fprintf(traceFile, "orig: %s%s\n", exeModule, origValue.c_str());
  fprintf(traceFile, "%s%s\n", exeModule, exeArgs);

  SetLastError(0);

    // Start the child process.
    if( !CreateProcess( exeModule,   // use module name with args for exeArgs
        exeArgs,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        TRUE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL, // use parent's starting directory
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    )
    {
        FILE* myfile;
        myfile = fopen ((path+"error.txt").c_str(), "w");
        fprintf(myfile, "CreateProcess failed (%d).\n", int(GetLastError()));
        fclose(myfile);
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    DWORD exit_code;
    GetExitCodeProcess(pi.hProcess, &exit_code);

    fprintf(traceFile, "Exit Code: %d\n", int(exit_code));
    fclose(traceFile);

    // Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

    return exit_code;
}

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
    std::string str1Cpy( str1 );
    std::string str2Cpy( str2 );
    std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
    std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
    return ( str1Cpy == str2Cpy );
}

最明显的问题是你不能说(path+procName).c_str(),因为它构建的临时字符串对象会立即被丢弃,使返回的指针无效。 我也很怀疑假设 vector 的元素一定是连续的。

更正后的字符串处理代码应如下所示:

    string passedValue(procName);  // First element of command line MUST be module name

    ...

    const string exeModuleString(path + procName);
    const LPCTSTR exeModule = exeModuleString.c_str();

    LPTSTR exeArgs = new char[passedValue.size() + 1];
    passedValue.copy(exeArgs, passedValue.size());
    exeArgs[passedValue.size()] = '[=10=]';

(这可能不是 最好的方法;我不经常使用 C++。但它应该可以正常工作。)

已更正的错误处理代码,确保立即读取最后一个错误代码,应该如下所示:

    {
        DWORD err = GetLastError();
        FILE* myfile;
        myfile = fopen ((path+"error.txt").c_str(), "w");
        fprintf(myfile, "CreateProcess failed (%d).\n", int(err));
        fclose(myfile);
    }

您的代码报告了错误的错误代码,因为调用 fopen() 会更改它。 (当创建覆盖现有文件的新文件时,最后的错误代码设置为 ERROR_ALREADY_EXISTS。)

有两个更广泛的问题,在您的上下文中可能重要也可能不重要。首先,您正在使用 argv[] 为新进程构建命令行;这意味着命令行解析(如 Parsing C Command-Line Arguments 中所述)将应用两次(一次由您的进程,一次由子进程)如果命令行包含任何特殊字符(如引号或反斜杠),这可能会导致问题.理想情况下,在一般情况下,您应该改为调用 GetCommandLine()。 (当然,这使得解析字符串以删除额外参数变得更加困难。)

其次,您显然是在 ANSI 模式下构建代码。如果命令行包含任何宽字符 ("Unicode"),这可能会导致问题。人们普遍认为,最佳实践是始终以 Unicode 模式构建。您需要对代码进行的唯一主要更改是将 string 替换为 wstring,因此它应该足够简单。

我也遇到了同样的问题。 当我调用没有 window 的可执行文件时,问题似乎就在那里。 我找到了 2 个解决方案:

1。 使用 exe 的名称创建一个 bat 文件,后跟参数, 然后执行bat文件: CreateProcess( "temp.bat" , NULL , ....等

2。 使用 _spawnl