首先在开始正文之前先介绍最简单的获取进程/线程句柄方法。那就是可以在创建进程/线程时获取句柄。
创建进程/线程是获取句柄。
//进程创建函数
BOOL CreateProcess(
PCTSTR pszApplicationName,
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY_ATTRIBUTES psaThread,
BOOL bInheritHandles,
DWORD fdwCreate,
PVOID pvEnvironment,
PCTSTR pszCurDir,
PSTARTUPINFO psiStartInfo,
PPROCESS_INFORMATION ppiProcInfo);
参数好多啊,如果想了解参数的具体含义可以去查看MSDN,本文不对这些参数进行详解,但是最后一个参数除外,通过它可以获得进程和主线程的内核句柄和ID。先来看一下PPROCESS_INFORMATION结构:
typedef struct _PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessID;
DWORD dwThreadID;
}PROCESS_INFORMATION;
在创建进程之前,我们首先要自己定义一个PROCESS_INFORMATION变量,然后使用它的地址调用CreateProcess()函数,CreateProcess函数在返回之前会出事化结构成员。这样我们就可以的到进程与主线程的句柄和ID了。
PROCESS_INFORMATION pi;
CreateProcess(……,&pi);
接下来就可以通过pi来获取进程与主线程的句柄和ID。
//创建线程函数
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD cbStackSize,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreateFlags,
PDWORD pdwThreadID
);
该函数的返回值就是创建的新线程的句柄,最后一个参数即为线程ID。
接下来介绍一下在Windows系统中如何获取进程/线程的伪句柄。
Windows提供了两个函数来获取进程/线程的伪句柄。
HANDLE GetCurrentProcess(); //获取进程伪句柄
HANDLE GetCurrentThread(); //获取线程伪句柄
调用这两个函数会返回进程/线程内核对象的一个伪句柄,不会在进程句柄表中新建句柄,同时也不会增加进程/线程内核对象计数。
当然如果使用伪句柄进行CloseHandle()函数调用,CloseHandle会忽略此次调用。
接下来介绍将伪句柄转换为真实句柄。
//复制内核对象句柄函数
BOOL DuplicateHandle(
HANDLE hSourceProcess,
HANDLE hSource,
HANDLE hTargetProcess,
HANDLE phTarget,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
这个函数获得一个进程句柄表中的一个记录项,然后在另一个句柄表中创建这个记录项的副本。
第一个参数hSourceProcess和第三个参数hTargetProcess是内核对象句柄,而且必须是进程内核对象。
第二个参数hSource可以是任何类型内核对象的句柄,但是必须和第一个参数所代表的进程相关。
第四个参数用来接收复制的句柄值。
最后三个参数用来指定内核对象在目标进程中的句柄表项,使用何种访问权限和继承标志。
若最后一个参数指定为DUPLICATE_SAME_ACCESS,表明复制后的句柄与原句柄具有相同的访问权限。
//获取线程句柄
HANDLE hThread;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&hThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
//获取进程句柄
HANDLE hProcess;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentProcess(),
GetCurrentProcess(),
&hProcess,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
可以看到,获取进程和线程句柄只是传入DuplicateHandle()的第二个参数不同。但是这个函数会增加内核对象计数,所以在使用完句柄后需要调用CloseHandle()使句柄计数减一。