首先在開始正文之前先介紹最簡單的獲取進程/線程句柄方法。那就是可以在創建進程/線程時獲取句柄。
//進程創建函數
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);
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提供了兩個函數來獲取進程/線程的偽句柄。
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()使句柄計數減一。