然后,看一下我們可能需要的一些API第一個(gè)CreateProcess
這個(gè)函數(shù)很惡心啊,先看看他的聲明(M$的東西一貫惡心,習(xí)慣就好)
- BOOL WINAPI CreateProcess(
- __in_opt LPCTSTR lpApplicationName,
- __inout_opt LPTSTR lpCommandLine,
- __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
- __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
- __in BOOL bInheritHandles,
- __in DWORD dwCreationFlags,
- __in_opt LPVOID lpEnvironment,
- __in_opt LPCTSTR lpCurrentDirectory,
- __in LPSTARTUPINFO lpStartupInfo,
- __out LPPROCESS_INFORMATION lpProcessInformation
- );
復(fù)制代碼 對參數(shù),不做太詳細(xì)的解釋,這里只對這個(gè)函數(shù)做一點(diǎn)簡單說明lpApplicationName 進(jìn)程名
lpCommandLine 進(jìn)程路徑+進(jìn)程名
lpProcessAttributes 進(jìn)程安全描述結(jié)構(gòu)
lpThreadAttributes 線程安全描述結(jié)構(gòu)
bInheritHandles 是否從父進(jìn)程繼承句柄
dwCreateFlags 進(jìn)程優(yōu)先級等等,看文檔比較靠譜,參數(shù)比較復(fù)雜
lpEnvironment 進(jìn)程的環(huán)境變量(不指定的話,默認(rèn)繼承父進(jìn)程的所有環(huán)境變量)
lpStartupInfo 進(jìn)程創(chuàng)建以后的狀態(tài)(掛起,就緒...),這里能設(shè)置的和dwCreateFlags其實(shí)有類似的地方,具體不做太多討論,看文檔比較靠譜
lpCurrentDirectory 進(jìn)程創(chuàng)建以后的路徑,默認(rèn)是可執(zhí)行文件exe的路徑
lpProcessInformation 返回的進(jìn)程信息,包含進(jìn)程句柄和線程句柄
接下來,就是用這玩意創(chuàng)建一個(gè)進(jìn)程了。(想想linux和unix下的fork函數(shù)吧,多么簡單,或者是exec函數(shù)...)
再下來,需要簡單介紹下CreateThread,因?yàn)樯衔睦镎f了,需要一個(gè)不影響當(dāng)前進(jìn)程執(zhí)行的模塊來負(fù)責(zé)做守護(hù)
那么,CreateThread又有啥呢?當(dāng)然,CreateThread函數(shù)就相對簡單的多了
- HANDLE WINAPI CreateThread(
- __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
- __in SIZE_T dwStackSize,
- __in LPTHREAD_START_ROUTINE lpStartAddress,
- __in_opt LPVOID lpParameter,
- __in DWORD dwCreationFlags,
- __out_opt LPDWORD lpThreadId
- );
復(fù)制代碼 lpThreadAttributes 線程安全結(jié)構(gòu)dwStackSize 線程棧大小
lpStartAddress 線程執(zhí)行體函數(shù)
lpParameter 線程執(zhí)行體函數(shù)的參數(shù)
dwCreateFlags 線程的優(yōu)先級,線程狀態(tài)等標(biāo)志
lpThreadId 線程ID
參數(shù)確實(shí)相比進(jìn)程簡單了很多,但是還是復(fù)雜
如此復(fù)雜的API,如何調(diào)用?這確實(shí)是問題,不過好處是,對于絕大部分的情況,我們都可以傳NULL(對于非指針和句柄傳0代替)
API內(nèi)部看到NULL(0)以后會(huì)用默認(rèn)的參數(shù)來代替他們
那么,我們可以如何調(diào)用呢?
下面寫2個(gè)簡單的調(diào)用例子
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
復(fù)制代碼 以上就是創(chuàng)建一個(gè)進(jìn)程的代碼了,如果不出特殊需求
創(chuàng)建進(jìn)程都可以用這種形式,對我們不關(guān)注的參數(shù),直接傳NULL 或者是 0
那么,線程呢?
線程可能有點(diǎn)麻煩的
現(xiàn)在的線程創(chuàng)建,一般是把一個(gè)函數(shù)當(dāng)作一個(gè)線程來執(zhí)行
所以,我們首先需要定義一個(gè)函數(shù),作為線程的執(zhí)行體。
和進(jìn)程的入口函數(shù)main(其實(shí)main不是真正的入口,以后講到PE文件的時(shí)候會(huì)講到),線程的入口函數(shù)也是一個(gè)固定的格式
DWORD WINAPI ThreadProc(void *arg);
只有滿足這個(gè)格式的函數(shù)才能當(dāng)作線程函數(shù)
這里的函數(shù)聲明又多了一個(gè)東西,叫做WINAPI
其實(shí)WINAPI是個(gè)宏,在windows.h里面是這樣定義的
#define WINAPI __stdcall
他規(guī)定了函數(shù)的調(diào)用約定方式(這個(gè)涉及到一點(diǎn)點(diǎn)的匯編知識,所以就暫時(shí)不展開講了),平時(shí)用的最多的C庫,調(diào)用約定都是__cdecl的形式
好了,廢話說完了,那么,如何創(chuàng)建一個(gè)線程呢?
- DWORD WINAPI ThreadProc(void *arg)
- {
- return 0;
- }
- HANDLE hThread;
- DWORD dwThreadID;
- hThread = CreateThread(
- NULL,
- 0,
- MyThreadFunction,
- pDataArray[i],
- 0,
- &dwThreadID
- );
復(fù)制代碼 如此,就能創(chuàng)建一個(gè)線程了