最近使用CreateProcess创建rundll32.exe进程,发现并没有正常加载DLL,后来才发现是命令行参数传错了,CreateProcess并不是我想象的那样,网上找了一下,发现还有许多东西不是想的那么简单。下面的文字翻译自《INFO: Understanding CreateProcess and Command-line Arguments》
创建32位进程时CreateProcess的行为
案例1
如果传递了ApplicationName参数,且CommandLine参数是NULL,那么ApplicationName参数同时也会被当做CommandLine参数。但这并不意味着你可以在ApplicationName参数中添加额外的命令行参数。比如下面的代码就无法成功创建进程:
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/createprocess-command-line.html
CreateProcess("c:\\MyApp.exe Param1 Param2", NULL, ... );
案例3当ApplicationName和CommandLine两个参数同时都使用的时候,就会体现出CreateProcess的灵活性了(也是容易混淆的地方)。这时候允许你指明要执行的程序以及要传给程序的完整的命令行参数。你也许会认为传递给创建的程序的命令行参数是ApplicationName和CommandLine的组合,但实际上不是这样的。实际情况是,由CreateProcess创建的进程可以接收一个指定的参数填充到argv[0],下面的例子就会产生这种不正常现象:
Copyed From 程序人生 Home Page:http://www.programlife.net Source URL:http://www.programlife.net/createprocess-command-line.html
CreateProcess( "c:\\MyApp.exe", "Param1 Param2 Param3", ...);
MyApp的命令参数将会是这样的:
argv[0] == "Param1"
argv[1] == "Param2"
argv[2] == "Param3"
此外,在《Windows核心编程》中提到,CreateProcess函数的lpCommandLine参数类型为LPTSTR,这意味着CreateProcess期望你将传递一个非常量字符串的地址,从内部来讲,CreateProcess实际上要修改你传递给它的命令行字符串,不过,在CreateProcess返回之前,它将该字符串恢复为它的原始形式。所以如果传递的是常量字符串,那么可能会引发违规访问的异常。
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/createprocess-command-line.html
所以,CreateProcess正确的写法应该这样:
TCHAR szPath[MAX_PATH] = {L"C:\\Windows\\System32\\rundll32.exe"};
TCHAR szCmdLine[MAX_PATH] = {
L"C:\\Windows\\System32\\rundll32.exe"
L" D:\\Test.dll,TestFunc" // 注意前面的空格
};
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
BOOL bRet = FALSE;
bRet = CreateProcess(
szPath,
szCmdLine,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/createprocess-command-line.html
以上内容为转载。
在工程实施工程中,采用的案例2的方式,开辟新的进程。发现有极个别的程序无法调用,查了半天没有发现问题所在。当不传递命令参数的时候,采用案例1的方式可以调用;传递命令参数的时候,采用案例3的方式可以调用。
下面附上代码:
<span style="font-size:14px;">CString strPhoto;
GetDlgItem(IDC_EDIT1)->GetWindowText(strPhoto);
STARTUPINFO startInfo={sizeof(startInfo)}; //定义一个STARTUPINFO结构对象
memset(&startInfo, 0, sizeof(STARTUPINFO)); //对startInfo进行初始化
startInfo.dwFlags=STARTF_USESHOWWINDOW;
startInfo.wShowWindow=TRUE;
startInfo.cb = sizeof(STARTUPINFO); //cb成员为STARTUPINFO结构的大小
PROCESS_INFORMATION procInfo; //PROCESS_INFORMATION结构对象
memset(&procInfo, 0, sizeof(PROCESS_INFORMATION));
TCHAR cmdline[] =TEXT("c://program files//internet explorer//iexplore.exe http://community.csdn.net/");
CString str=strPhoto;
str+=" dfadsfasdf";
BOOL bRet =CreateProcess(
strPhoto.GetBuffer(0),
str.GetBuffer(0),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&startInfo,
&procInfo
); //创建子进程
int error = GetLastError();
if(bRet)
{
::CloseHandle (procInfo.hThread);
::CloseHandle (procInfo.hProcess);
CString strshow;
strshow.Format("%d",procInfo.dwProcessId);
AfxMessageBox("新进程的进程ID号:"+strshow);
strshow.Format("%d",procInfo.dwThreadId);
AfxMessageBox("新进程的主线程ID号: "+strshow);
}
else
{
CString strshow;
strshow.Format("%d",error);
AfxMessageBox("error code:"+strshow );
}</span>