CreateProcess 失败 - 错误 183
CreateProcess Fails - Error 183
因此,我无法更改的代码调用可执行文件,我需要为其提供与黑盒代码调用不同的命令行参数。我想我可以制作一个可执行文件作为代理。 proc.exe
位于黑盒部分预期的位置,获取命令行参数,修改它们,然后调用 procReal.exe
原始文件。
不幸的是,CreateProcess 似乎无法启动,返回状态 183。我已经尽我所能查找了一切,但找不到太多相关信息。尝试翻转事物,将句柄继承设置为 true,手动指定工作目录,但不执行任何这些操作。没运气。我假设这里发生了一些事情,继承了调用应用程序的正确安全上下文,因此包装器可以作为正确的直通,但我不知道该怎么做...
下面的代码,不相关的部分被删减了。
编辑 请求后将完整代码放在这里。这已经没有任何意义了。它现在将部分工作,但前提是 traceFile
的 fopen
部分不存在。连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
因此,我无法更改的代码调用可执行文件,我需要为其提供与黑盒代码调用不同的命令行参数。我想我可以制作一个可执行文件作为代理。 proc.exe
位于黑盒部分预期的位置,获取命令行参数,修改它们,然后调用 procReal.exe
原始文件。
不幸的是,CreateProcess 似乎无法启动,返回状态 183。我已经尽我所能查找了一切,但找不到太多相关信息。尝试翻转事物,将句柄继承设置为 true,手动指定工作目录,但不执行任何这些操作。没运气。我假设这里发生了一些事情,继承了调用应用程序的正确安全上下文,因此包装器可以作为正确的直通,但我不知道该怎么做...
下面的代码,不相关的部分被删减了。
编辑 请求后将完整代码放在这里。这已经没有任何意义了。它现在将部分工作,但前提是 traceFile
的 fopen
部分不存在。连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