创建进程
BOOL CreateProcess(
LPCTSTR lpAppName, //可执行的映像文件名。如果没有指定lpAppName参数,那么lpCommandLine参数(也就是第二个参数)的第一个空白定界标记前面的字符串。
LPTSTR lpCommandLine, //用于执行应用程序的命令行,整个命令行可以用于GetCommandLine函数的新进程。
LPSECURITY_ATTRIBUTES lpProcessAttributes, //可选参数,新进程的属性。如果不指定,那么函数创建的进程没有安全描述符,且产生的句柄在进程创建时不被继承。
LPSECURITY_ATTRIBUTES lpThreadAttributes, //可选参数,用来指定新线程的属性。其他同上
BOOL bInheritHandles, //指定此新进程是否将继承调用进程可见对象的句柄。
DWORD dwCreationFlags, //控制进程创建时候的一些标志
LPVOID lpEnvironment, //可选参数。指向环境数据区的指针,如果没有指定该参数,那么当前执行进程的环境数据区。对使用EnvironmentStrings的函数来说可以使用此环境数据区。
LPCTCTR lpCurrentDirectory, //可选参数。(这个参数主要是为需要启动一个应用程序并指定其初始驱动好工作目录的外壳(shell)提供的)如果指定该参数,那么可以为新进程提供表示当前驱动器和目录的字符串(该字符串必须包括驱动器字母在内的全限定路径名)。如果没有指定,那么新进程就被建立在当前所在的同一驱动器和目录里。
LPSTARTUPINFO lpStartupInfo, //指定如何显示应用程序窗口的数据结构
LPPROCESS_INFORMATION lpProcessInformation //接收有关新进程的标识信息
);
这个函数创建一个进程和一个主线程对象,并打开每个对象的句柄。
注意:
-
对于lpAppName参数(或者是lpCommandLine参数的文件名部分)来说,如果文件名不包含扩展名,那么默认采用.EXE作为扩展名;如果文件名不包含目录路径,那么Windows将会在以下目录中寻找:
- 当前目录
- Windows目录
- Windows系统目录
- 路径变量中所列出来的目录
-
dwCreationFlags,提供控制进程创建时的一些标识:
- DEBUG_PROCESS, 如果它被置位,就说明正在创建进程的进程被当做调试进程,被创建的进程当做被调试程序,所有出现在被调试程序中的调试事件都要报告给调试程序
- DEBUG_ONLY_THIS_PROCESS, 如果它没有被置位,并且调试进程处于被调试状态,则这个进程成为调用进程的调试程序的另一个被调试进程;如果调用进程不是一个正在被调试的进程,则不出现与调试程序有关的活动。
- CREATE_SUSPENDED, 此进程被创建,但该进程的初始线程仍被挂起。创建此进程的程序可以调用ResumeThread函数来重新使用该线程。直到完成这些操作后,才执行此进程。
- CREATE_NEW_CONSOLE, 所创建的程序将有一个新的控制台,而不是继承父控制台。
- DETACHED_PROCESS, 所创建的进程没有控制台。从一个没有控制台的函数中调用一个控制台函数会导致出错。如果次进程以后想拥有一个控制台的话,可以调用AllocateConsole函数得到。如果设置了CREATE_NEW_CONSOLE和DETACHED_PROOCESS两个值,则将返回一个出错信息。
- CREATE_UNICODE_ENVIRONMENT, 如果设置了该标志位,那么lpEnvironment指针指向的环境变量块使用Unicode字符;如果没有,那么使用ANSI字符。
- CREATE_SHARED_WOW_VDM,
- CREATE_NEW_PROCESS_GROUP, 新创建的进程是一个进程组的根进程,该进程组包括所有该进程的后代进程。该进程组的ID和该进程的ID相同。
- CREATE_DEFAULT_ERROR_MODE, 新创建的进程将不继承调用者的出错模式,而是为新创建的进程创建缺省出错模式。
STARTUPINFO 结构:
typedef struct _STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;
typedef struct _STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved;
LPWSTR lpDesktop;
LPWSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOW, *LPSTARTUPINFOW;
#ifdef UNICODE
typedef STARTUPINFOW STARTUPINFO;
typedef LPSTARTUPINFOW LPSTARTUPINFO;
#else
typedef STARTUPINFOA STARTUPINFO;
typedef LPSTARTUPINFOA LPSTARTUPINFO;
#endif // UNICODE
- PROCESS_INFORMATION结构:
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
创建进程(指定用户运行)
BOOL CreateProcessAsUser(
HANDLE hToken, //指定一个代表用户的句柄,该句柄必须有TOKEN_QUERY、TOKEN_DUPLICATE和TOKEN_ASSIGN_PRIARY属性。
LPCTSTR lpAppName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTCTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
这个函数与CreateProcess类似,具体参数也可以参照CreateProcess的参数,只是该函数创建的进程只能在hToken参数所指定用户的安全上下文中运行。缺省情况下,新创建的进程是非交互式的,也就是说,它不接受用户的输入,同样的,新进程将继承调用者进程的环境变量,而不继承与指定用户相联系的环境变量。
- 函数成功返回非零值,否则返回零值
- 关于Token的内容还没有学习,有时间补
结束进程
VOID ExitProcess(
UNIT uExitCode
);
当前进程可以使用ExitProcess函数退出,并附带退出其所有的线程。。这个API函数提供了应用程序彻底终止的方法,这包括在所有附加的DLL的实例终止入口调用他们。
在将进程终止情况通知给所有的DLL以后,此API会终止这个当前进程。
终止子进程
BOOL TerminateProcess(
HANDLE hProcess, //要终止的进程的句柄
UINT uExitCode
);
这个函数用于终止特定进程以及它的所有线程
- 它不通知DLL进程被附着在要终止的进程上。
- 使用TerminateProcess而不使用ExitProcess会影响由DLL得到的全局数据的状态。
- 进程的终止态会从STILL_ACTIVE改为进程中最后一个终止线程的终止态(通常和函数的退出值相同)。
= 终止一个进程不会从系统中删掉该进程。它只是终止其所有线程的执行,并关闭所有由该进程打开的对象句柄。一个进程只有在其最后一个句柄被关闭时才会从系统中删除。
一个小实验:
// testProcess.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include<Windows.h>
#include <atlstr.h>
#include <strsafe.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char cWindowsDirectory[MAX_PATH];
//LPTSTR 与 wchar_t* 等价(Unicode环境下)
LPTSTR cWinDir = new TCHAR[MAX_PATH];
GetCurrentDirectory(MAX_PATH, cWinDir);
CString str(cWinDir);
wcscat_s(cWinDir, str.GetLength()*sizeof(WCHAR) / sizeof(char), _T("\\Debug\\test2.exe"));
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
//创建一个新进程
if (CreateProcess(
NULL, // 指向一个NULL结尾的、用来指定可执行模块的宽字节字符串
cWinDir, // 命令行字符串
NULL, // 指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。
NULL, // 如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。<同上>
false,// 指示新进程是否从调用进程处继承了句柄。
CREATE_NEW_CONSOLE, // 指定附加的、用来控制优先类和进程的创建的标
// 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);
//终止子进程
BOOL bRet = TerminateProcess(pi.hProcess, 300);
//终止本进程,状态码
ExitProcess(1001);
return 0;
}