windows下想要创建一个子进程不如linux的fork函数来得方便,通过CreateProcess函数创建一个新的进程,函数的定义如下
- BOOL CreateProcess(
- LPCTSTR lpApplicationName, // 应用程序名称
- LPTSTR lpCommandLine, // 命令行字符串
- LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程的安全属性
- LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程的安全属性
- BOOL bInheritHandles, // 是否继承父进程的属性
- DWORD dwCreationFlags, // 创建标志
- LPVOID lpEnvironment, // 指向新的环境块的指针
- LPCTSTR lpCurrentDirectory, // 指向当前目录名的指针
- LPSTARTUPINFO lpStartupInfo, // 传递给新进程的信息
- LPPROCESS_INFORMATION lpProcessInformation // 新进程返回的信息
- );
下面写一个创建进程和简单的控制示例,首先创建一个小程序,作为子进程的实体
- #include<iostream>
- #include<Windows.h>
- using namespace std;
- int main(int argc, char *argv[])
- {
- cout << "args_num: " << argc << endl;
- for(int i = 0;i < argc;i ++){
- cout << "arg " << i << " = " << argv[i] << endl;
- }
- return 0;
- }
- #include<iostream>
- #include<Windows.h>
- using namespace std;
- int main()
- {
- char cWindowsDirectory[MAX_PATH];
- //LPTSTR 与 wchar_t* 等价(Unicode环境下)
- LPTSTR cWinDir = new TCHAR[MAX_PATH];
- GetCurrentDirectory(MAX_PATH, cWinDir);
- LPTSTR sConLin = wcscat(cWinDir , L"\\..\\Debug\\another.exe a b c d");
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- ZeroMemory(&si, sizeof(si));
- ZeroMemory(&pi, sizeof(pi));
- //创建一个新进程
- if(CreateProcess(
- NULL, // 指向一个NULL结尾的、用来指定可执行模块的宽字节字符串
- sConLin, // 命令行字符串
- NULL, // 指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。
- NULL, // 如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。<同上>
- false,// 指示新进程是否从调用进程处继承了句柄。
- 0, // 指定附加的、用来控制优先类和进程的创建的标
- // CREATE_NEW_CONSOLE 新控制台打开子进程
- // CREATE_SUSPENDED 子进程创建后挂起,直到调用ResumeThread函数
- NULL, // 指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境
- NULL, // 指定子进程的工作路径
- &si, // 决定新进程的主窗体如何显示的STARTUPINFO结构体
- &pi // 接收新进程的识别信息的PROCESS_INFORMATION结构体
- ))
- {
- cout << "create process success" << endl;
- //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能不小心调用TerminateProcess函数关掉子进程
- // CloseHandle(pi.hProcess);
- // CloseHandle(pi.hThread);
- }
- else{
- cerr << "failed to create process" << endl;
- }
- Sleep(100);
- //终止子进程
- TerminateProcess(pi.hProcess, 300);
- //终止本进程,状态码
- ExitProcess(1001);
- return 0;
- }
CreateProcess的参数虽然多而且麻烦,其实大部分设置为NULL即可,右边这个链接里面有多进程编程相关的函数介绍:http://blog.csdn.net/bxhj3014/article/details/2082255
=======================CreateProcess()详解及用法=======================
CreateProcess() 函数原型如下:
[C++]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
|
BOOL
WINAPI CreateProcess(
__in_opt
LPCTSTR
lpApplicationName,
__inout_opt
LPTSTR
lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in
BOOL
bInheritHandles,
__in
DWORD
dwCreationFlags,
__in_opt
LPVOID
lpEnvironment,
__in_opt
LPCTSTR
lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
|
该函数用来创建一个新的进程。
第 1 个参数 lpApplicationName 是输入参数,指向启动进程的 exe 文件。
第 2 个参数 lpCommandLine 是输入参数,是启动进程的命令行中的参数。
当这两个参数都不为 NULL 时,第 1 个参数指定要启动的进程 exe 文件(不带参数),第 2 个参数指定启动进程所需参数。第 1 个参数也可以为 NULL,此时第 2 个参数就不能为 NULL,在 lpCommandLine 需要指定出要启动的程序名以及所接参数,彼此间以空格隔开,其中第 1 个参数即是程序名。
第 3 个参数 lpProcessAttributes 是输入参数,指向 SECURITY_ATTRIBUTES 结构变量,是进程的安全属性,可以为 NULL 则使用默认的安全属性。
第 4 个参数 lpThreadAttributes 是输入参数,同第 3 个参数一样,指向 SECURITY_ATTRIBUTES 结构变量。
第 5个参数 bInheritHandles 是输入参数,表示新进程是否从调用进程处继承了句柄。如果参数的值为 TRUE,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限;如果设为 FALSE,那么不继承。
第 6 个参数 dwCreationFlags 是输入参数,表示进程的创建标志以及优先级控制。如 : CREATE_NEW_CONSOLE 会使新建的控制台程序拥有一个新的控制台; DEBUG_PROCESS 调用进程将被当作一个调试程序,并且新进程会被当作被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
第 7 个参数 lpEnvironment 是输入参数,指向新进程的环境变量块,如果设置为 NULL,那么使用父进程的环境变量。
第 8 个参数 lpCurrentDirectory 是输入参数,指定创建后新进程的当前目录,如果设置为 NULL,那么就在父进程所在的当前目录。
第 9 个参数 lpStartupInfo 是输入参数,指向一个 STARTUPINFO 结构,该结构里可以设定启动信息,可以设置为 NULL 。
第 10 个参数 lpProcessInformation 是输出参数,指向一个 PROCESS_INFORMATION 结构,返回被创建进程的信息。
测试代码:
[C++]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#include "stdafx.h"
#include <locale.h>
#include <Windows.h>
int
_tmain(
int
argc, _TCHAR* argv[])
{
PROCESS_INFORMATION ProInfo;
//进程信息结构
STARTUPINFO StartInfo;
ZeroMemory ( &StartInfo,
sizeof
(StartInfo));
LPTSTR
szPrameter = TEXT(
"C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe [url]www.groad.net[/url]"
);
TCHAR
szCmdLine[2048] = {0};
CopyMemory(szCmdLine, szPrameter, 2*_tcslen(szPrameter));
ZeroMemory (&ProInfo,
sizeof
(ProInfo));
if
(!CreateProcess ( NULL,
// 执行的程序名
szCmdLine,
// 命令行指定
NULL,
// 进程安全属性,NULL 时使用默认安全属性
NULL,
// 线程安全属性,NULL 时使用默认安全属性
FALSE,
// 不继承句柄
0,
// 进程创建标志
NULL,
// 环境变量块,为 NULL 时使用父进程环境变量
NULL,
// 新进程目录
&StartInfo,
// 启动信息结构
&ProInfo)
// 进程信息结构
) {
_tprintf (TEXT(
"CreateProcess failed : %d\n"
), GetLastError());
return
(-1);
}
// 等待子进程结束
WaitForSingleObject(ProInfo.hProcess, INFINITE);
CloseHandle ( ProInfo.hProcess );
CloseHandle ( ProInfo.hThread );
return
0;
}
|
上面程序启动谷歌 Chrome 浏览器并打开 www.groad.net 这个主页。在程序中,当第 1 个参数为 NULL 时,要启动的程序以及网址参数均指定在第 2 个参数中。注意,不能直接将参数 szPrameter 直接填写到第 2 个参数中,因为指定的命令行参数中含有空格,这样往往会造成参数解析错误,比如它会被解析成: 也就是会认为 chrome.exe www.groad.net.exe 这就是一个程序,这是无法执行的。
而将命令行参数拷贝到数组中却是可行的,但如此一来却要多定义一个数组。如果是英文 Windows 环境,并无需构建多字符程序,那么可以将引号把路径括起来,这也不会出错,比如: 注意上面的路径使用反斜杠转义了括起路径的双引号。
但是,如果在第 1 个参数和第 2 个参数里分别指定程序名和参数,那么也无需添加一个数组来存储命令行参数,但第 2 个参数中指定的命令行参数注意前面要添加一个空格,否则可能无法正确解析参数,比如: 这里只是针对浏览器打开网址这种情况,并非所有的情形都会没问题,比如我测试时,IE 和 MaxThon 是需要在网址面前添加空格的,否则打开的是一个空白页。但对于 Chrome ,不管网址前加不加空格都只能打开空白页,得用上面添加的数组情况方能正常。这也许和浏览器程序本身有关。如果用的是记事打开一些文本,如果后面的文本路径参数不添加空格,那么打开空白,反之正常;而对于 UE ,那么即使后面不添加空格也照样打开,所以从这两个例子看来,仍然是和程序本身有关。但是,添加一个空格会保持较好的兼容性,如若还不行,可以考虑用一个数组来接纳所有的命令行参数。
另外,程序中使用了 WaitForSingleObject() 函数以等待子进程的退出,如当我们关闭了浏览器,那么上面的程序也随之结束,否则一直在那等待。
转:http://www.groad.net/bbs/thread-6367-1-1.html