西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁編程開發(fā)Delphi → CreateProcess函數(shù) 詳細(xì)使用說明

CreateProcess函數(shù) 詳細(xì)使用說明

相關(guān)軟件相關(guān)文章發(fā)表評論 來源:西西整理時間:2011/4/20 9:07:47字體大小:A-A+

作者:佚名點擊:4199次評論:0次標(biāo)簽: CreateProcess

  • 類型:角色扮演大。18.1M語言:中文 評分:.0
  • 標(biāo)簽:
立即下載

函數(shù)原型  BOOL CreateProcess

  (

  LPCTSTR lpApplicationName,

  LPTSTR lpCommandLine,

  LPSECURITY_ATTRIBUTES lpProcessAttributes。

  LPSECURITY_ATTRIBUTES lpThreadAttributes,

  BOOL bInheritHandles,

  DWORD dwCreationFlags,

  LPVOID lpEnvironment,

  LPCTSTR lpCurrentDirectory,

  LPSTARTUPINFO lpStartupInfo,

  LPPROCESS_INFORMATION lpProcessInformation

  );

CreateProcess函數(shù)

  CreateProcess函數(shù)用于創(chuàng)建進(jìn)程:

  1. BOOL CreateProcess(  
  2.    PCTSTR pszApplicationName,  
  3.    PTSTR pszCommandLine,  
  4.    PSECURITY_ATTRIBUTES psaProcess,  
  5.    PSECURITY_ATTRIBUTES psaThread,  
  6.    BOOL bInheritHandles,  
  7.    DWORD fdwCreate,  
  8.    PVOID pvEnvironment,  
  9.    PCTSTR pszCurDir,  
  10.    PSTARTUPINFO psiStartInfo,  
  11.    PPROCESS_INFORMATION ppiProcInfo);  

線程調(diào)用CreateProcess時,系統(tǒng)會創(chuàng)建一個進(jìn)程內(nèi)核對象,將其引用計數(shù)初始化為1(進(jìn)程內(nèi)核對象并不是進(jìn)程本身,它只是操作系統(tǒng)用來管理進(jìn)程的數(shù)據(jù)結(jié)構(gòu),其中包含了進(jìn)程的一些統(tǒng)計信息)。然后系統(tǒng)為新進(jìn)程開辟虛擬地址空間,并將可執(zhí)行文件的代碼和數(shù)據(jù)以及所需的DLL裝載到該地址空間中。接著系統(tǒng)為進(jìn)程主線程創(chuàng)建線程內(nèi)核對象,并將其引用計數(shù)初始為1(同進(jìn)程一樣,線程內(nèi)核對象也不是線程本身,而且操作系統(tǒng)用來管理線程的數(shù)據(jù)結(jié)構(gòu))。主線程將鏈接器設(shè)置的入口點函數(shù)作為C/C++運行時啟動函數(shù)調(diào)用,這些啟動函數(shù)最終又調(diào)用代碼中的入口點函數(shù)如WinMain、wWinMain、main和 wmain。當(dāng)操作系統(tǒng)成功創(chuàng)建了新的進(jìn)程和主線程后,CreateProcess返回TRUE。以上是CreateProcess的簡要介紹,下面我們來詳細(xì)討論它的參數(shù)。

pszApplicationName和pszCommandLine
  pszApplicationName和pszCommandLine分別表示進(jìn)程使用的可執(zhí)行文件名和向其傳遞的命令行字符串,我們先來看看 pszCommandLine參數(shù)。注意pszCommandLine是PTSTR,這意味著你必須為其傳遞指向非常量字符串的地址。 CreateProcess內(nèi)部會更改向其傳遞的命令行字符串,但在CreateProcess返回之前,它會將該字符串恢復(fù)原樣。這一點是非常重要的,因為如果你向CreateProcess傳遞的命令行字符串位于進(jìn)程的只讀存儲區(qū),就會發(fā)生Access Violation錯誤。比如,下面的代碼執(zhí)行時會觸發(fā)Access Violation,因為微軟的C/C++編譯器會把常量字符串放入只讀存儲區(qū)(注意早期的微軟C/C++編譯器會將常量字符串放在可讀寫存儲區(qū),因此下面的代碼在舊的編譯環(huán)境下不會出錯):

  1. STARTUPINFO si = { sizeof(si) };  
  2. PROCESS_INFORMATION pi;  
  3. CreateProcess(NULL, TEXT("NOTEPAD"), NULL, NULL,  
  4.    FALSE, 0, NULL, NULL, &si, &pi);  

解決這個問題的方法很簡單,將命令行字符串復(fù)制到臨時緩沖區(qū)既可,如下所示:

  1. STARTUPINFO si = { sizeof(si) };  
  2. PROCESS_INFORMATION pi;  
  3. TCHAR szCommandLine[] = TEXT("NOTEPAD");  
  4. CreateProcess(NULL, szCommandLine, NULL, NULL,  
  5.    FALSE, 0, NULL, NULL, &si, &pi);  

微軟在其C++編譯器選項中提供了/GF開關(guān),/GF打開時,程序中所有用到的常量字符串將只維護(hù)單一副本,且位于只讀存儲部分。在調(diào)用 CreateProcess時,開發(fā)人員應(yīng)該打開/GF開關(guān)并使用緩沖區(qū)。我們希望微軟在未來版本的Windows中會改進(jìn)CreateProcess,使其接受常量字符串作為命令行參數(shù),并在其內(nèi)部分配/釋放臨時緩沖區(qū)而不是讓API調(diào)用者來做。另外,假如你使用常量ANSI字符串作為 CreateProcess參數(shù),并不會發(fā)生Access Violation錯誤,我們在前面的章節(jié)已經(jīng)提到過,許多WinAPI函數(shù)的ANSI版本會將ANSI參數(shù)轉(zhuǎn)換為UNIDOE編碼后調(diào)用其 Unicode版本,CreateProcess會把ANSI字符串轉(zhuǎn)換為Unicode編碼后放在臨時緩沖區(qū),并調(diào)用Unicode版的 CreateProcess,因此不會觸發(fā)Access Violation。
  pszCommandLine參數(shù)指定了 CreateProcess創(chuàng)建新進(jìn)程所需的完整命令行。當(dāng)CreateProcess解析該參數(shù)時,它會檢查命令行參數(shù)中的第一個標(biāo)記,并將其作為進(jìn)程要執(zhí)行的可執(zhí)行文件名,如果該文件名沒有指定后綴,函數(shù)將把它當(dāng)作exe文件。CreateProcess會按下面的順序查找該文件:
1. 包含當(dāng)前進(jìn)程可執(zhí)行文件的目錄
2. 當(dāng)前進(jìn)程的當(dāng)前目錄
3. Windows系統(tǒng)目錄,既GetSystemDirectory返回的目錄
4. Windows目錄
5. PATH環(huán)境變量列出的目錄
當(dāng)然,如果文件名包含了完整路徑,系統(tǒng)將會在該路徑中查找文件而不會再做上面的搜索。如果系統(tǒng)找到了可執(zhí)行文件,它會創(chuàng)建一個新的進(jìn)程并把可執(zhí)行文件的代碼和數(shù)據(jù)映射到進(jìn)程的地址空間,然后調(diào)用CRT啟動函數(shù)(linker選項卡中的入口點函數(shù)),接著CRT啟動函數(shù)檢查命令行參數(shù),過濾掉其中的可執(zhí)行文件部分,并把剩下字符串的地址作為pszCmdLine傳給wWinMain/WinMain。

以上情形都是在pszApplicationName為NULL時發(fā)生的。 pszApplicationName指定了進(jìn)程要執(zhí)行的可執(zhí)行文件的名稱,假如沒有指定文件后綴,系統(tǒng)并不會做任何處理。 pszApplicationName不包含完整路徑時,CreateProcess只從當(dāng)前目錄中查找可執(zhí)行文件,查找失敗時函數(shù)失敗并返回 FALSE。即使指定了pszApplicationName,CreateProcess仍然會將pszCommandLine參數(shù)作為新進(jìn)程的命令行。比如下面的代碼:

  1. // Make sure that the path is in a read/write section of memory.  
  2. TCHAR szPath[] = TEXT("WORDPAD README.TXT");  
  3.   
  4. // Spawn the new process.  
  5. CreateProcess(TEXT("C:\\WINDOWS\\SYSTEM32\\NOTEPAD.EXE"),szPath,...);  

執(zhí)行上面代碼時,系統(tǒng)會打開notepad.exe(記事本),但它的命令行卻是WORDPAD README.TXT(WORDPAD是寫字板),這看上去非常奇怪,但CreateProcess就是這樣工作的。這種 pszApplicationName提供的特性被用來支持Windows的POSIX子系統(tǒng)。

psaProcess, psaThread和bInheritHandles
  創(chuàng)建新進(jìn)程時,系統(tǒng)會創(chuàng)建一個進(jìn)程內(nèi)核對象和一個線程內(nèi)核對象(用于進(jìn)程的主線程),和其它內(nèi)核對象一樣,創(chuàng)建者(在這兒是父進(jìn)程)必須指定其安全屬性。psaProcess和psaThread分別指定了新進(jìn)程的進(jìn)程內(nèi)核對象和線程內(nèi)核對象的安全屬性。將其設(shè)為NULL時,系統(tǒng)為對應(yīng)的內(nèi)核對象指定默認(rèn)的安全屬性。你可以創(chuàng)建SECURITY_ATTRIBUTES類型的變量,設(shè)置其中各個域的值然后將變量地址傳遞給psaProcess或 psaThread,以應(yīng)用指定的安全屬性。正如在第3章討論內(nèi)核對象時談到的,當(dāng)你想要控制新的進(jìn)內(nèi)核對象的句柄能否被父進(jìn)程以后創(chuàng)建的子進(jìn)程繼承時,你應(yīng)該設(shè)置SECURITY_ATTRIBUTES變量的bInheritHandle域的值。
  下面的Inherit.cpp展示了內(nèi)核對象句柄繼承。假設(shè)執(zhí)行該代碼的進(jìn)程為A,它調(diào)用CreateProcess創(chuàng)建了進(jìn)程B,接著又創(chuàng)建了子進(jìn)程C。注意調(diào)用CreateProcess時A使用的psaProcess、psaThread和bInheritHandles參數(shù),代碼注釋很詳細(xì)的描述了這些參數(shù)的作用:

  1. /************************************************************ 
  2. Module name: Inherit.cpp 
  3. Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre 
  4. ************************************************************/  
  5.   
  6.   
  7. #include <Windows.h>  
  8.   
  9.   
  10. int WINAPI _tWinMain (HINSTANCE hInstanceExe, HINSTANCE,  
  11.    PTSTR pszCmdLine, int nCmdShow) {  
  12.   
  13.    // Prepare a STARTUPINFO structure for spawning processes.  
  14.    STARTUPINFO si = { sizeof(si) };  
  15.    SECURITY_ATTRIBUTES saProcess, saThread;  
  16.    PROCESS_INFORMATION piProcessB, piProcessC;  
  17.    TCHAR szPath[MAX_PATH];  
  18.   
  19.    // Prepare to spawn Process B from Process A.  
  20.    // The handle identifying the new process  
  21.    // object should be inheritable.  
  22.    saProcess.nLength = sizeof(saProcess);  
  23.    saProcess.lpSecurityDescriptor = NULL;  
  24.    saProcess.bInheritHandle = TRUE;  
  25.   
  26.    // The handle identifying the new thread  
  27.    // object should NOT be inheritable.  
  28.    saThread.nLength = sizeof(saThread);  
  29.    saThread.lpSecurityDescriptor = NULL;  
  30.    saThread.bInheritHandle = FALSE;  
  31.   
  32.    // Spawn Process B.  
  33.    _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessB"));  
  34.    CreateProcess(NULL, szPath, &saProcess, &saThread,  
  35.       FALSE, 0, NULL, NULL, &si, &piProcessB);  
  36.   
  37.    // The pi structure contains two handles  
  38.    // relative to Process A:  
  39.    // hProcess, which identifies Process B's process  
  40.    // object and is inheritable; and hThread, which identifies  
  41.    // Process B's primary thread object and is NOT inheritable.  
  42.   
  43.    // Prepare to spawn Process C from Process A.  
  44.    // Since NULL is passed for the psaProcess and psaThread  
  45.    // parameters, the handles to Process C's process and  
  46.    // primary thread objects default to "noninheritable."  
  47.   
  48.    // If Process A were to spawn another process, this new  
  49.    // process would NOT inherit handles to Process C's process  
  50.    // and thread objects.  
  51.   
  52.    // Because TRUE is passed for the bInheritHandles parameter,  
  53.    // Process C will inherit the handle that identifies Process  
  54.    // B's process object but will not inherit a handle to  
  55.    // Process B's primary thread object.  
  56.    _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessC"));  
  57.    CreateProcess(NULL, szPath, NULL, NULL,  
  58.       TRUE, 0, NULL, NULL, &si, &piProcessC);  
  59.   
  60.    return(0);  
  61. }  

fdwCreate
  fdwCreate參數(shù)用來控制進(jìn)程被創(chuàng)建時的行為,下面列出了它可能的取值:
·DEBUG_PROCESS:父進(jìn)程將調(diào)試子進(jìn)程及子進(jìn)程創(chuàng)建的所有進(jìn)程,指定該參數(shù)后,在子進(jìn)程或子進(jìn)程創(chuàng)建的任意進(jìn)程中發(fā)生特定事件時系統(tǒng)將通知父進(jìn)程
·DEBUG_ONLY_THIS_PROCESS:父進(jìn)程將調(diào)試子進(jìn)程,指定該參數(shù)后,在子進(jìn)程中發(fā)生特定事件時系統(tǒng)將通知父進(jìn)程
·CREATE_SUSPENDED:進(jìn)程創(chuàng)建后其主線程暫不執(zhí)行。此時父進(jìn)程可以在子進(jìn)程運行之前更改子進(jìn)程地址空間中的數(shù)據(jù)、更改子進(jìn)程主線程優(yōu)先級、將子進(jìn)程添加到作業(yè)中等。父進(jìn)程完成其更改后,可以調(diào)用ResumeThread函數(shù)恢復(fù)子進(jìn)程主線程運行
·DETACHED_PROCESS:系統(tǒng)將阻止CUI程序向其父進(jìn)程的CUI窗口寫入其輸出。當(dāng)父進(jìn)程為CUI進(jìn)程時,創(chuàng)建的CUI子進(jìn)程默認(rèn)使用父進(jìn)程的CUI窗口(如cmd.exe程序)。指定該參數(shù)后,新進(jìn)程在需要輸出到窗口時必須調(diào)用AllocConsole創(chuàng)建CUI窗口
·CREATE_NEW_CONSOLE:系統(tǒng)自動為新進(jìn)程創(chuàng)建一個CUI窗口,該標(biāo)志不能與DETACHED_PROCESS同時使用
·CREATE_NO_WINDOW:系統(tǒng)不為新進(jìn)程創(chuàng)建CUI窗口,使用該標(biāo)志可以創(chuàng)建不含窗口的CUI程序
·CREATE_NEW_PROCESS_GROUP:新進(jìn)程將作為一個新的進(jìn)程組的根進(jìn)程,新的進(jìn)程組將包含以根進(jìn)程為祖先的所有進(jìn)程。用戶在進(jìn)程組中的某個進(jìn)程CUI窗口中按下Ctrl+C或Ctrl+B時,系統(tǒng)將通知進(jìn)程組中的所有進(jìn)程這一事件
·CREATE_DEFAULT_ERROR_MODE:子進(jìn)程不繼承父進(jìn)程的任何錯誤標(biāo)志
·CREATE_SEPARATE_WOW_VDM:僅用于16位Windows程序,不譯
·CREATE_SHARED_WOW_VDM:僅用于16位Windows程序,不譯
·CREATE_UNICODE_ENVIRONMENT:子進(jìn)程的環(huán)境塊為Unicode字符串。進(jìn)程的環(huán)境塊默認(rèn)只包含ANSI字符串
·CREATE_FORCEDOS:強(qiáng)制系統(tǒng)運行內(nèi)嵌在16位OS/2系統(tǒng)中的MS-DOS程序
·CREATE_BREAKAWAY_FROM_JOB:當(dāng)父進(jìn)程屬于某個作業(yè)時,新建的子進(jìn)程將不再與該作業(yè)關(guān)聯(lián)
·EXTENDED_STARTUPINFO_PRESENT:傳遞給CreateProcess函數(shù)的psiStartInfo參數(shù)是STARTUPINFOEX類型的變量
  fdwCreate參數(shù)也可以用于設(shè)置新進(jìn)程的優(yōu)先級。但你不必這樣做,對大多數(shù)應(yīng)用你也不應(yīng)該這樣做——系統(tǒng)會為新進(jìn)程分配默認(rèn)優(yōu)先級。表4-5列出了可能的優(yōu)先級常量:
進(jìn)程優(yōu)先級描述
這些常量決定了進(jìn)程中的線程在CPU中調(diào)度的優(yōu)先級,我們在188頁的“優(yōu)先級概述”中會討論該問題。

pvEnvironment
  參數(shù)pvEnvironment指向一塊內(nèi)存區(qū)域,其中包含新進(jìn)程用到的環(huán)境字符串。大多數(shù)情況下,你可以為其傳遞NULL,此時新進(jìn)程將繼承父進(jìn)程的環(huán)境字符串。

pszCurDir
  參數(shù)pszCurDir允許父進(jìn)程設(shè)置子進(jìn)程的當(dāng)前驅(qū)動器和目錄。如果該參數(shù)為NULL,子進(jìn)程將使用父進(jìn)程的當(dāng)前驅(qū)動器和目錄作為其當(dāng)前驅(qū)動器和目錄。如果pszCurDir非空,則其必須指向一個包含驅(qū)動器標(biāo)識的以0結(jié)尾的路徑字符串。

psiStartInfo
  psiStartInfo是指向STARTUPINFO或STARTUPINFOEX變量的提針:

  1. typedef struct _STARTUPINFO {  
  2.    DWORD cb;  
  3.    PSTR lpReserved;  
  4.    PSTR lpDesktop;  
  5.    PSTR lpTitle;  
  6.    DWORD dwX;  
  7.    DWORD dwY;  
  8.    DWORD dwXSize;  
  9.    DWORD dwYSize;  
  10.    DWORD dwXCountChars;  
  11.    DWORD dwYCountChars;  
  12.    DWORD dwFillAttribute;  
  13.    DWORD dwFlags;  
  14.    WORD wShowWindow;  
  15.    WORD cbReserved2;  
  16.    PBYTE lpReserved2;  
  17.    HANDLE hStdInput;  
  18.    HANDLE hStdOutput;  
  19.    HANDLE hStdError;  
  20. } STARTUPINFO, *LPSTARTUPINFO;  
  21.   
  22. typedef struct _STARTUPINFOEX {  
  23.     STARTUPINFO StartupInfo;  
  24.     struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList;  
  25. } STARTUPINFOEX, *LPSTARTUPINFOEX;  

  Windows創(chuàng)建新進(jìn)程時會使用STARTUPINFO(EX)的成員變量,大多數(shù)情況下可以使用這些變量的默認(rèn)值,此時你應(yīng)該該將其cb域設(shè)置為結(jié)構(gòu)的大小,并將其余域清0,如下:

  1. STARTUPINFO si = { sizeof(si) };  
  2. CreateProcess(..., &si, ...);  

  許多開發(fā)人員常常會忘記執(zhí)行上述操作,如果你沒有清空其內(nèi)容,STARTUPINFO(EX)的內(nèi)容會是調(diào)用線程堆棧上的一些數(shù)據(jù)。將這些垃圾數(shù)據(jù)傳遞給CreateProcess可能導(dǎo)致無法預(yù)料的結(jié)果,為了讓CreateProcess正常工作,你必須將STARTUPINFO(EX)中沒有用到的域清0。
  表4-6列出了STARTUPINFO(EX)結(jié)構(gòu)的成員,注意有些成員只在GUI應(yīng)用中生效,而有些則只在CUI應(yīng)用中生效:
STARTUPINFO(EX)結(jié)構(gòu)成員列表
  現(xiàn)在我們來討論dwFlags成員。dwFlags包含一組標(biāo)志用來指示如何創(chuàng)建子進(jìn)程,其中大多數(shù)標(biāo)志只是告訴CreateProcess是否使用STARTUPINFO結(jié)構(gòu)中的某個成員,表4-7列出了dwFlags的可取值:
dwFlags可取值
  另外兩個標(biāo)志 STARTF_FORCEONFEEDBACK和STARTF_FORCEOFFFEEDBACK可以控制在創(chuàng)建子進(jìn)程時如何顯示鼠標(biāo)指針。由于 Windows支持搶先式多任務(wù)調(diào)度,因此你可以在創(chuàng)建子程并等待子進(jìn)程初始化時,執(zhí)行另外的程序。如果你指定了 STARTF_FORCEONFEEDBACK,Windows會在新進(jìn)程初始化時將鼠標(biāo)光標(biāo)指針更改為“后臺運行”,如下圖:

這個標(biāo)志意味著系統(tǒng)后臺正在處理某些任務(wù)(在這里是創(chuàng)建并初始化子進(jìn)程),但你依然可以繼續(xù)使用系統(tǒng)。當(dāng)你指定了STARTF_FORCEOFFFEEDBACK標(biāo)志時,CreateProcess不會更改鼠標(biāo)指針樣式。
  如果指定了STARTF_FORCEONFEEDBACK,且子進(jìn)程在CreateProcess調(diào)用后2秒內(nèi)執(zhí)行了GUI調(diào)用,CreateProcess會等待子進(jìn)程顯示窗口。如果該GUI調(diào)用后5秒之內(nèi)還沒有窗口顯示,CreateProcess會將鼠標(biāo)指針恢復(fù)原狀,否則繼續(xù)等待5秒,如果在這5秒之內(nèi)子進(jìn)程調(diào)用了GetMessage函數(shù),CreateProcess會認(rèn)為子進(jìn)程已經(jīng)完成初始化并將鼠標(biāo)指針復(fù)位。
  STARTUPINFO的wShowWindow變量將傳遞給wWinMain/WinMain的最后一個參數(shù)nCmdShow,它的取值是 ShowWindow函數(shù)接受的參數(shù)值之一,通常被指定為SW_SHOWNORMAL、SW_SHOWMINNOACTIVE或 SW_SHOWDEFAULT。

  在結(jié)束本節(jié)之前,我們來看看STARTUPINFOEX結(jié)構(gòu)。通過使用同時兼容STARTUPINFOEX和STARTUPINFO結(jié)構(gòu)的參數(shù)psiStartInfo,微軟在保持CreateProcess簽名的同時提高了其擴(kuò)展性。下面是STARTUPINFOEX結(jié)構(gòu)的定義:

  1. typedef struct _STARTUPINFOEXA {  
  2.     STARTUPINFOA StartupInfo;  
  3.     struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList;  
  4. } STARTUPINFOEXA, *LPSTARTUPINFOEXA;  
  5. typedef struct _STARTUPINFOEXW {  
  6.     STARTUPINFOW StartupInfo;  
  7.     struct _PROC_THREAD_ATTRIBUTE_LIST *lpAttributeList;  
  8. } STARTUPINFOEXW, *LPSTARTUPINFOEXW;  

lpAttributeList(屬性鏈表)是_PROC_THREAD_ATTRIBUTE_LIST結(jié)構(gòu)的鏈表,其中每個結(jié)構(gòu)包含一個key/value對,目前,_PROC_THREAD_ATTRIBUTE_LIST中key的取值只能是下面兩種:

  • PROC_THREAD_ATTRIBUTE_HANDLE_LIST:告訴 CreateProcess指定的句柄可被子進(jìn)程繼承,當(dāng)然該句柄必須是可繼承的(其繼承標(biāo)志位為1),且無需將CreateProcess的 bInheritHandles參數(shù)設(shè)置為TRUE。使用該標(biāo)志可以指定子進(jìn)程繼承可繼承句柄的子集而不是全部。這對于需要在不同的安全環(huán)境中創(chuàng)建子進(jìn)程的進(jìn)程而言非常重要,在這種情況下,由于安全原因,某些子進(jìn)程可能不應(yīng)該繼承全部的可繼承句柄。
  • PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:指定一個進(jìn)程句柄,指定的進(jìn)程(包括其可繼承句柄、親緣性、優(yōu)先級等等)會替代調(diào)用CreateProcess的當(dāng)前進(jìn)程,成為子進(jìn)程的父進(jìn)程。如果當(dāng)前進(jìn)程在調(diào)用CreateProcess時指定了DEBUG_PROCESS或DEBUG_ONLY_THIS_PROCESS,重新指定父進(jìn)程并不影響原父進(jìn)程調(diào)試過程,在子進(jìn)程中發(fā)生的特定事件仍然會報告給原父進(jìn)程。

  屬性鏈表的內(nèi)容是不透明的,因此我們需要一些函數(shù)來創(chuàng)建空的屬性鏈表。創(chuàng)建屬性鏈表需要以下幾個步驟,首先,為其分配存儲空間,然后向其中添加鍵值對。函數(shù)InitializeProcThreadAttributeList用來創(chuàng)建新的屬性鏈表并為其分配存儲空間:

  1. BOOL InitializeProcThreadAttributeList(  
  2.    PPROC_THREAD_ATTRIBUTE_LIST pAttributeList,  
  3.    DWORD dwAttributeCount,  
  4.    DWORD dwFlags,  
  5.    PSIZE_T pSize);  

參數(shù)dwFlags必須指定為0,你可以先用如下方式獲得屬性鏈表所需的空間大。

  1. SIZE_T cbAttributeListSize = 0;  
  2. BOOL bReturn = InitializeProcThreadAttributeList(  
  3.    NULL, 1, 0, &cbAttributeListSize);  
  4. // bReturn is FALSE but GetLastError() returns ERROR_INSUFFICIENT_BUFFER  

cbAttributeListSize 返回創(chuàng)建屬性鏈表所需的內(nèi)存大小,該大小與dwAttributeCount參數(shù)相關(guān),dwAttributeCount指定了屬性鏈表中的 key/value對的數(shù)目。接下來你可以用cbAttributeListSize為屬性鏈表分配空間:

  1. pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)  
  2.    HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize);  

然后再次調(diào)用InitializeProcThreadAttributeList初始化屬性鏈表的內(nèi)容:

  1. bReturn = InitializeProcThreadAttributeList(  
  2.    pAttributeList, 1, 0, &cbAttributeListSize);  

當(dāng)屬性鏈表初始化完成后,就可以調(diào)用UpdateProcThreadAttribute向其添加鍵/值對了:

  1. BOOL UpdateProcThreadAttribute(  
  2.    PPROC_THREAD_ATTRIBUTE_LIST pAttributeList,  
  3.    DWORD dwFlags,  
  4.    DWORD_PTR Attribute,  
  5.    PVOID pValue,  
  6.    SIZE_T cbSize,  
  7.    PVOID pPreviousValue,  
  8.    PSIZE_T pReturnSize);  

pAttributeList是要添加鍵/值對的屬性列表,Attribute可取 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS或PROC_THREAD_ATTRIBUTE_HANDLE_LIST,取前者時,pValue參數(shù)應(yīng)指向另外一個進(jìn)程的句柄,cbSize取值應(yīng)為sizeof(HANDLE),否則,pValue指向子進(jìn)程要繼承的所有內(nèi)核對象的句柄數(shù)組,cbSize取值應(yīng)是sizeof(HANDLE)乘以該數(shù)組的大小。參數(shù)dwFlags、pPreviousValue和 pReturnSize是保留參數(shù),應(yīng)分別賦0、NULL和NULL。

  注意,如果在創(chuàng)建子進(jìn)程時為其指定新的父進(jìn)程,既使用了 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,那么在使用 PROC_THREAD_ATTRIBUTE_HANDLE_LIST時,pValue指向的句柄數(shù)組中的句柄應(yīng)該是新父進(jìn)程句柄表中對象的句柄,而不是調(diào)用CreateProcess的進(jìn)程所有。

當(dāng)你在CreateProcess的dwCreateFlags參數(shù)中指定了EXTENDED_STARTUPINFO_PRESENT時,你應(yīng)該向CreateProcess的pStartupInfo參數(shù)傳遞一個STARTUPINFOEX結(jié)構(gòu)的指針,如下面所示:

  1. STARTUPINFOEX esi = { sizeof(STARTUPINFOEX) };  
  2. esi.lpAttributeList = pAttributeList;  
  3. bReturn = CreateProcess(  
  4.    ..., EXTENDED_STARTUPINFO_PRESENT, ...  
  5.    &esi.StartupInfo, ...);  

其中pAttributeList是按前面的方法創(chuàng)建的屬性列表。當(dāng)你不再需要該屬性列表時,應(yīng)該調(diào)用下面的方法回收為其分配的內(nèi)存:

  1. VOID DeleteProcThreadAttributeList(  
  2.    PPROC_THREAD_ATTRIBUTE_LIST pAttributeList);  

  最后,應(yīng)用程序可以調(diào)用GetStartupInfo獲得由其父進(jìn)程在CreateProcess中指定的STARTUPINFO結(jié)構(gòu)的拷貝:

  1. VOID GetStartupInfo(LPSTARTUPINFO pStartupInfo);  

注意,無論父進(jìn)程在調(diào)用CreateProcess時參數(shù)pStartupInfo指向STARTUPINFO還是STARTUPINFOEX結(jié)構(gòu),GetStartupInfo總是返回STARTUPINFO結(jié)構(gòu)的拷貝。

ppiProcInfo
  ppiProcInfo 參數(shù)是PROCESS_INFORMATION結(jié)構(gòu)的指針,調(diào)用CreateProcess時該結(jié)構(gòu)必須由開發(fā)人員手動分配。CreateProcess 在返回前會填充ppiProcInfo指向的結(jié)構(gòu)的內(nèi)容。PROCESS_INFORMATION定義如下:

  1. typedef struct _PROCESS_INFORMATION {  
  2.    HANDLE hProcess;  
  3.    HANDLE hThread;  
  4.    DWORD dwProcessId;  
  5.    DWORD dwThreadId;  
  6. } PROCESS_INFORMATION;  

  CreateProcess會創(chuàng)建一個進(jìn)程內(nèi)核對象和一個線程內(nèi)核對象,創(chuàng)建初期,系統(tǒng)將其引用計數(shù)分別置為1。CreateProcess返回之前會獲得這兩個對象的訪問權(quán)限,這樣每個對象的引用計數(shù)會分別增加1,CreateProcess返回之后,兩個對象的引用計數(shù)變成2。這意味著如果系統(tǒng)要釋放CreateProcess進(jìn)程/線程內(nèi)核對象,相應(yīng)的進(jìn)程/線程必須終止,并且調(diào)用CreateProcess的線程必須調(diào)用 CloseHandle關(guān)閉相應(yīng)的對象句柄,這樣才能使得其引用計數(shù)變?yōu)?,系統(tǒng)方能釋放。

 

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    第 1 樓 四川成都鐵通ADSL 網(wǎng)友 客人 發(fā)表于: 2012/8/13 23:46:40
    非常詳細(xì),謝謝版主

    支持( 0 ) 蓋樓(回復(fù))

    發(fā)表評論 查看所有評論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)