抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

CreateProcess

创建一个新进程及主线程。新进程在调用进程的安全上下文中运行;

函数声明

1
2
3
4
5
6
7
8
9
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
WINBASEAPI
BOOL
WINAPI
CreateProcessA(
_In_opt_ LPCSTR lpApplicationName,
_Inout_opt_ LPSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOA lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);

WINBASEAPI
BOOL
WINAPI
CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);

#ifdef UNICODE
#define CreateProcess CreateProcessW
#else
#define CreateProcess CreateProcessA
#endif // !UNICODE

参数

lpApplicationName

要执行的模块的名称。lpApplicationName参数可以是NULL, 要运行批处理文件, 必须启动命令解释程序, 并将lpApplicationName设置成cmd.exe;

lpCommandLine

要执行的命令行。lpCommandLine的参数可以是NULL, 在这种情况下, 该函数使用由lpApplicationName指向的字符串作为命令行。如果lpApplicationNamelpCommandLine都不为NULL, 则由lpApplicationName指向的以空字符串结尾的字符串会指定要执行的模块, 并且由lpCommandLine指向的以空字符串结尾的字符串会指定命令行;

lpProcessAttributes

指向SECURITY_ATTRIBUTES结构的指针, 用于确定是否可以由子进程继承返回新进程对象的句柄。如果lpProcessAttributesNULL, 则不能继承句柄;

lpThreadAttributes

指向SECURITY_ATTRIBUTES结构的指针, 用于确定是否可以由子进程继承返回的新线程对象的句柄。如果lpThreadAttributesNULL, 则不能继承句柄;

bInheritHandles

如果此参数为TRUE, 则调用进程中的每个可继承句柄都将由新进程来继承。如果该参数为FALSE, 则不会继承句柄;

dwCreationFlags

控制优先级和创建进程的标志。例如, CREATE_NEW_CONSOLE表示新进程将使用一个新控制台, 而不是继承父进程的控制台。CREATE_SUSPENDED表示新进程的主线程会以暂停的状态来创建, 直到调用ResumeThread函数时才运行;

lpEnvironment

指向新进程的环境块的指针。如果此参数为NULL, 则新进程将使用调用进程的环境;

lpCurrentDirectory

指向进程当前目录的完整路径。该字符串还可以指定UNC路径, 如果此参数为NULL, 则新进程将具有与调用进程相同的当前驱动器和目录;

lpStartupInfo

指向STARTUPINFOSTARTUPINFOEX结构的指针。STARTUPINFOSTARTUPINFOEX中的句柄在不需要时必须由CloseHandle关闭;

lpProcessInformation

指向PROCESS_INFOMATION结构的指针。用于接收有关新进程的标识信息。PROCESS_INFOMATION中的句柄必须在不需要时由CloseHandle关闭;

返回值

如果函数成功, 则返回值非零;
如果函数失败, 则返回值为零;

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
STARTUPINFO si = { 0 };
PROCESS_INFOMATION pi = { 0 };
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW; // 指定wShowWindow成员有效
si.wShowWindow = uiCmdShow;
BOOL bRet = CreateProcess(NULL, "cmd.exe", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (bRet == FALSE)
{
CloseHandle(pi.hThread);
CloseHanle(pi.hProcess);
return;
}

使用事项-1

CreateProcess着重注意5个参数: 执行模块名称的参数lpApplicationName、执行命令行的参数lpCommandLine、控制进程优先级和创建进程标志的参数dwCreationFlags、指向STARTUPINFO信息结构的参数lpStartupInfo、以及指向PROCESS_INFOMATION信息结构的参数lpProcessInformation;

使用事项-2

CreateProcess函数在指定窗口显示方式时, 需要在STARTUPINFO结构体中将启用标志设置成STARTF_USESHOWWINDOW, 表示wShowWindow成员显示方式有效。然后将wShowWindow设置为SW_HIDE隐藏窗口, 创建方式为CREATE_NEW_CONSOLE创建一个新控制台;

创建进程时共享句柄表

在创建进程中创建一个进程(比如WeChat进程), 并设定该子进程的进程内核句柄与主线程内核句柄为可继承;
在A进程中再创建一个进程B, 在进程B中对WeChat进程控制;

代码示例

1
2
3
4
5
6
7
8
9
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
42
43
44
45
46
47
// 进程A代码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>

int main()
{
WCHAR wcBuffer[256]{};
WCHAR wcHandle[10]{};

SECURITY_ATTRIBUTES sa_p{};
sa_p.nLength = sizeof(SECURITY_ATTRIBUTES);
sa_p.lpSecurityDescriptor = NULL;
sa_p.bInheritHandle = TRUE;

SECURITY_ATTRIBUTES sa_t{};
sa_t.nLength = sizeof(SECURITY_ATTRIBUTES);
sa_t.lpSecurityDescriptor = NULL;
sa_t.bInheritHandle = TRUE;

STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi{};

const char* szCmdLine = "D:\\Tencent\\WeChat\\WeChat.exe";
WCHAR wcCmdLine[256]{};
wsprintf(wcCmdLine, L"%S", szCmdLine);
if (FALSE == CreateProcess(NULL, wcCmdLine, &sa_p, &sa_t, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
printf("WeChat CreateProcess Failed\n");
return 0;
}

wsprintf(wcHandle, L"%x %x", pi.hProcess, pi.hThread);
wsprintf(wcBuffer, L"D:\\Visual Studio Projects\\DiShui Projects\\05_20_Test_Demo\\ConsoleApplication1\\x64\\Debug\\ConsoleApplication2.exe %s", wcHandle);

STARTUPINFO si_B = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi_B{};

if (FALSE == CreateProcess(NULL, wcBuffer, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si_B, &pi_B))
{
printf("CreateProcess Failed\n");
return 0;
}
return 0;
}
1
2
3
4
5
6
7
8
9
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
42
43
44
45
// 进程B代码
// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>

int main(int argc, char* argv[])
{
DWORD dwProcessHandle = -1;
DWORD dwThreadHandle = 0;
WCHAR wcBuffer[256]{};

printf("%s %s\n", argv[1], argv[2]);
// 转换进程句柄
MultiByteToWideChar(CP_ACP, 0, argv[1], -1, wcBuffer, sizeof(wcBuffer) / sizeof(WCHAR));
swscanf(wcBuffer, L"%x", &dwProcessHandle);
printf("%x\n", dwProcessHandle);
// 转换线程句柄
memset(wcBuffer, 0, 256);
MultiByteToWideChar(CP_ACP, 0, argv[2], -1, wcBuffer, sizeof(wcBuffer) / sizeof(WCHAR));
swscanf(wcBuffer, L"%x", &dwThreadHandle);
printf("%x\n", dwThreadHandle);

printf("获取父进程句柄、主线程句柄\n");
Sleep(5000);
//挂起主线程
printf("挂起主线程\n");
SuspendThread((HANDLE)dwThreadHandle);

Sleep(5000);

// 恢复主线程
printf("恢复主线程\n");
ResumeThread((HANDLE)dwThreadHandle);

Sleep(5000);

// 关闭ID进程
TerminateProcess((HANDLE)dwProcessHandle, 1);
WaitForSingleObject((HANDLE)dwProcessHandle, INFINITE);
printf("ID进程已经关闭\n");

system("pause");
}

评论