Windows程序设计——进程创建
这一部分的学习还是要通过大量的代码阅读吧。在这里可以截取有用的代码并添加注释。
进程定义
正在运行的程序,拥有自己的虚拟地址空间拥有自己的代码、数据和其他资源。
组成:进程内核对象,操作系统使用内核对象来管理该进程。私有的虚拟地址空间。
应用程序启动过程
操作系统通过CreateProcess
函数来创建新的进程,分配虚拟地址空间,加载代码和数据;然后创建一个主线程,调用main函数。
CreateProcess(
LPCSTR lpApplicationName, // 可执行文件的名称
LPSTR lpCommandLine, // 指定了要传递给执行模块的参数。
LPSECURITY_ATTRIBUTES lpProcessAttributes,// 进程安全性,值为 NULL
的话表示使用默认的安全属性
LPSECURITY_ATTRIBUTES lpThreadAttributes,// 线程安全性,值为 NULL
的话表示使用默认的安全属性
BOOL bInheritHandles, // 指定了当前进程中的可继承句柄是否可被新进程继承。
DWORD dwCreationFlags, // 指定了新进程的优先级以及其他创建标志
LPVOID lpEnvironment, // 指定新进程使用的环境变量
LPCSTR lpCurrentDirectory, // 新进程使用的当前目录
LPSTARTUPINFO lpStartupInfo, // 指定新进程中主窗口的位置、大小和标准句柄等
LPPROCESS_INFORMATION lpProcessInformation
//【out】返回新建进程的标志信息,如 ID 号、句柄等
);
对创建进程中用到的结构体进行简单说明。通过STARTUPINFO类型的变量,指定新的进程的相关信息。通过GetStartupInfo函数来获取父进程创建自己时使用的变量:
typedef struct {
DWORD cb; // 本结构的长度,总是应该被设为 sizeof(STARTUPINFO)
LPSTR lpReserved; // 保留(Reserve)字段,即程序不使用这个参数
LPSTR lpDesktop; // 指定桌面名称
LPSTR lpTitle; // 控制台应用程序使用,指定控制台窗口标题
DWORD dwX; // 指定新创建窗口的位置坐标(dwX,dwY)和大小信息
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars; // 控制台程序使用,指定控制台窗口的行数
DWORD dwYCountChars;
DWORD dwFillAttribute; // 控制台程序使用,指定控制台窗口的背景色
DWORD dwFlags; // 标志。它的值决定了 STARTUPINFO
结构中哪些成员的值是有效的。
WORD wShowWindow; // 窗口的显示方式
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput; // 控制台程序使用, 几个标准句柄
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
通过pROCESS_INFORMATION结构体来获取进程创建后的信息
typedef struct{
HANDLE hProcess; // 新建进程的内核句柄
HANDLE hThread; // 新建进程中主线程的内核句柄
DWORD dwProcessId; // 新建进程的 ID
DWORD dwThreadId; // 新建进程的主线程 ID
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
解决了字符集的问题
发现内核对象的方法中W表示的宽字符,一般对应的是utf8,工程如果是用unicode进行编码的时候,就会使用W结尾的内核方法。(非Unicode编码的时候链接A结尾的方法)。所以在工程中可以配置为多字符编码,这样可以调用程序设计中的大部分代码,不存在编码问题。
进程控制
获取进程快照的方法
#include <windows.h>
#include <tlhelp32.h> // 声明快照函数的头文件
int main(int argc, char* argv[])
{
//这是一个进程的记录变量
PROCESSENTRY32 pe32;
// 在使用这个结构之前,先设置它的大小
pe32.dwSize = sizeof(pe32);
//
给系统内的所有进程拍一个快照,这个对象是一个列表,需要用专门的函数进行遍历
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
{
printf(“ CreateToolhelp32Snapshot 调用失败! \n”);
return -1;
}
// 遍历进程快照,轮流显示每个进程的信息
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
while(bMore)
{
printf(“ 进程名称: %s \n”, pe32.szExeFile);
printf(“ 进程 ID 号: %u \n\n”, pe32.th32ProcessID);
bMore = ::Process32Next(hProcessSnap, &pe32);
}
// 不要忘记清除掉 snapshot 对象
::CloseHandle(hProcessSnap);
return 0;
}
CreateToolhelp32Snapshot()也可以获取其他类型的快照。TH32CS_SNAPPROCESS、TH32CS_SNAPHEAPLIST、TH32CS_SNAPMOUDULE、TH32CS_SNAPMOUDULE。
储存进程信息的结构体PROCESSENTRY32
typedef struct
{ DWORD dwSize; // 结构的长度,必须预先设置
DWORD cntUsage; // 进程的引用记数
DWORD th32ProcessID; // 进程 ID
DWORD th32DefaultHeapID; // 进程默认堆的 ID
DWORD th32ModuleID; // 进程模块的 ID
DWORD cntThreads; // 进程创建的线程数
DWORD th32ParentProcessID; // 进程的父线程 ID
LONG pcPriClassBase; // 进程创建的线程的基本优先级
DWORD dwFlags; // 内部使用
CHAR szExeFile[MAX_PATH]; // 进程对应的可执行文件名
} PROCESSENTRY32;
终止当前进程
主线程的入口函数返回。
进程中一个线程调用了ExitProcess函数。
此进程中的所有线程都结束了。
其他进程中的一个线程调用了TerminateProcess函数
说明:
退出当前进程
void ExitProcess(UINT uExitCode); // 参数 uExitCode
为此程序的退出代码,当期那进程力科技术。
终止其他进程
BOOL TerminateProcess(
HANDLE hProcess, // 要结束的进程(目标进程)的句柄
UINT uExitCode // 指定目标进程的退出代码,你可以使用 GetExitCodeProcess
取得一个进程的退出代码
);//用来结束其他进程。
获取某个进程的句柄,方便对一个进程进行操作
HANDLE OpenProcess(
DWORD dwDesiredAccess, // 想得到的访问权限,可以是
PROCESS_ALL_ACCESS,所有可以进行的权限,PROCESS_QUERY_INFORMATION
查看该进程信息的权限……
BOOL bInheritHandle, // 指定返回的句柄是否可以被继承
DWORD dwProcessId // 指定要打开的进程的 ID 号
);
终止其他进程的代码示例
BOOL TerminateProcessFromId(DWORD dwId)
{ BOOL bRet = FALSE;
// 打开目标进程,取得进程句柄
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwId);
if(hProcess != NULL)
{ // 终止进程
bRet = ::TerminateProcess(hProcess, 0);
}
CloseHandle(hProcess);//注意句柄类型需要使用这个函数进行关闭
return bRet;
}
进程终止后会发生的事情
1. 相关对象句柄都被关闭
2. 进程内的线程终止执行
3. 集成内核对象变为受信状态,所有等待在此对象上的线程开始运行。
4. 系统将进程对象中退出代码的值由STILL_ACTIVE改为退出码。
保护进程
以下函数用来实现进程内存的读写。
BOOL ReadProcessMemory(
HANDLE hProcess, // 待读进程的句柄
LPCVOID lpBaseAddress, // 目标进程中待读内存的起始地址
LPVOID lpBuffer, // 用来接受读取数据的缓冲区
DWORD nSize, // 要读取的字节数
LPDWORD lpNumberOfBytesRead // 用来供函数返回实际读取的字节数
);
WriteProcessMemory( hProcess, lpBaseAddress, lpBuffer, nSize,
lpNumberOfBytesRead); // 参数含义同上
以下函数用来获取当前系统的版本信息
BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);
系统会将操作系统的版本信息返回到参数 lpVersionInfo 指向的 OSVERSIONINFO
结构中。
typedef struct OSVERSIONINFO {
DWORD dwOSVersionInfoSize; // 本结构的大小,必须在调用之前设置
DWORD dwMajorVersion; // 操作系统的主版本号
DWORD dwMinorVersion; // 操作系统的次版本号
DWORD dwBuildNumber; // 操作系统的编译版本号
DWORD dwPlatformId; // 操作系统平台。可以是 VER_PLATFORM_WIN32_NT(2000
系列)等
TCHAR szCSDVersion[128]; // 指定安装在系统上的最新服务包,例如“Service Pack
3”等
} OSVERSIONINFO;
Windows程序设计中常见的类型。
| BOOL/BOOLEAN | 8bit,TRUE/FALSE | 布尔型 | |
|---|---|---|---|
| BYTE | unsigned 8 bit | ||
| BSTR CComBSTR _bstr_t | 32 bit | BSTR是指向字符串的32位指针 是对BSTR的封装 是对BSTR的封装 | |
| CHAR | 8 bit | (ANSI)字符类型 | |
| COLORREF | 32 bit | RGB颜色值 整型 | |
| DWORD | unsigned 32 bit | 整型 | |
| FLOAT | float型 | float型 | |
| HANDLE | Object句柄 | ||
| HBITMAP | bitmap句柄 | ||
| HBRUSH | brush句柄 | ||
| HCURSOR | cursor句柄 | ||
| HDC | 设备上下文句柄 | ||
| HFILE | OpenFile打开的File句柄 | ||
| HFONT | font句柄 | ||
| HHOOK | hook句柄 | ||
| HKEY | 注册表键句柄 | ||
| HPEN | pen句柄 | ||
| HWND | window句柄 | ||
| INT | 不同系统长度不同 | 一般为32位 | |
| LONG | 不同系统长度不同 | 一般为32位 | |
| LONGLONG | 64位带符号整型 | ||
| LPARAM | 32 bit | 消息参数 | |
| LPBOOL | BOOL型指针 | ||
| LPBYTE | BYTE型指针 | ||
| LPCOLOREF | COLORREF型指针 | ||
| LPCSTR/LPSTR/PCSTR | 指向8位(ANSI)字符串类型指针 | ||
| LPCWSTR/LPWSTR/PCWSTR | 指向16位Unicode字符串类型 | ||
| LPCTSTR/LPTSTR/PCTSTR | 指向一8位或16位字符串类型指针 | ||
| LPVOID | 指向一个未指定类型的32位指针 | ||
| LPDWORD | 指向一个DWORD型指针 | ||
| 其他相似类型: LPHANDLE、LPINT、LPLONG、LPWORD、LPRESULT PBOOL、PBOOLEAN、PBYTE、PCHAR、PDWORD、PFLOAT、PHANDLE、PINT、PLONG、PSHORT…… 说明:(1)在16位系统中 LP为16bit,P为8bit,在32位系统中都是32bit(此时等价) (2)LPCSTR等 中的C指Const,T表示TCHAR模式即可以工作在ANSI下也可UNICODE | |||
| SHORT | usigned | 整型 | |
| 其他UCHAR、UINT、ULONG、ULONGLONG、USHORT为无符号相应类型 | |||
| TBYTE | WCHAR型或者CHAR型 | ||
| TCHAR | ANSI与unicode均可 | ||
| VARIANT _variant_t COleVariant | 一个结构体参考OAIDL.H _variant_t是VARIANT的封装类 COleVariant也是VARIANT的封装类 | ||
| WNDPROC | 指向一个窗口过程的32位指针 | ||
| WCHAR | 16位Unicode字符型 | ||
| WORD | 16位无符号整型 | ||
| WPARAM | 消息参数 | ||
| MFC 独有 数据 类型 | 下面两个数据类型是微软基础类库中独有的数据类型 | ||
| POSITION | 标记集合中一个元素的位置的值 被MFC中的集合类所使用 | ||
| LPCRECT | 指向一个RECT结构体常量(不能修改) 的32位指针 | ||
| CString | 其实是MFC中的一个类 | ||
Windows数据类型命名规律
基本数据类型包括:BYTE、CHAR、WORD、SHORT、INT等。
指针类型的命令方式一般是在其指向的数据类型前加“LP”或“P”,比如指向DWORD的指针类型为“LPDWORD”和“PDWORD”
各种句柄类型的命名方式一般都是在对象名前加“H”,比如位图(BITMAP)对应的句柄类型为“HBITMAP”。
无符号类型一般是以“U”开头,比如“INT”是符号类型,“UINT”是无符号类型
DWORD实质上就是 unsigned long 数据类型,32位无符号整型。
而经常要用到的HANDLE类型实质上是无类型指针void,HANDLE定义为:
typedof PVOID HANDLE;
HANDLE实际上就是一个PVOID,那PVOID又是什么呢?
Typeof void *PVOID;
PVOID就是指向void的指针。




