xi52qian |
|
|||
xi52qian |
日歷
統(tǒng)計
導(dǎo)航常用鏈接留言簿隨筆檔案搜索最新評論
閱讀排行榜評論排行榜 |
進程由兩部分組成:
進程是不活潑的,進程當(dāng)中至少要有一個線程,每個線程要有自己的堆棧和自己的CPU寄存器。CPU通過算法給每個線程分配時間片的辦法來造成假象是在同時工作(多核通過自己的算法實現(xiàn)同時運行)。 4.1 編寫第一個Windiws應(yīng)用程序 Windows兩種類型的程序:
注意:倆者的概念其實是很模糊的,CUI可以創(chuàng)建GUI圖形界面,反之GUI程序可能用CUI程序。 Windows進入點函數(shù)(區(qū)分在于CUI和GUI程序,ANSI碼和UNICODE碼) int WINAPI WinMain( HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, int nCmdShow); int WINAPI wWinMain( HINSTANCE hinstExe, HINSTANCE, PWSTR pszCmdLine, int nCmdShow); int __cdecl main( int argc, char *argv[], char *envp[]); int __cdecl wmain( int argc, wchar_t *argv[], wchar_t *envp[]); 其實Windows程序啟動時最開始并不調(diào)用自己寫的入口函數(shù),而是調(diào)用系統(tǒng)的幾個入口函數(shù),以便可以調(diào)用malloc和free之類的函數(shù),初始化全局和靜態(tài)C++對象等。
應(yīng)用程序類型 進入點 嵌入可執(zhí)行文件的啟動函數(shù) ANSI碼GUI應(yīng)用程序 WinMain WinMainCRTStattup UNICODE碼GUI應(yīng)用程序 wWinMain wWinMainCRTStattup ANSI碼CUI應(yīng)用程序 main mainCRTStattup UNICODE碼CUI應(yīng)用程序 wmain wmainCRTStattup 注意:應(yīng)用程序會根據(jù)SUBSYSTEM開關(guān)來查找嵌入可執(zhí)行啟動函數(shù),如果進入點函數(shù)和啟動函數(shù)不匹配則顯示鏈接錯誤。可以刪除SUBSYSTEM(VS Project Settings)開關(guān),這樣應(yīng)用程序會自動需找匹配的函數(shù)。 進入點函數(shù)返回時調(diào)用系統(tǒng)的exit函數(shù),將返回值傳遞給它。exit函數(shù)負(fù)責(zé)下面操作:
4.1.1 進程的實例句柄 WinMain/wWinMain函數(shù)的第一個參數(shù)表示進程加載的可執(zhí)行文件的基地址/句柄。對于加載資源的調(diào)用都要使用此句柄,比如HICON LoadIcon(HINSTANCE, PCTSTR)。有的函數(shù)需要使用HMODULE,和HINSTANCE是一個意思(區(qū)分主要在于16位的操作系統(tǒng)中)。 HMODULE GetModuleHandle(PCTSTR pszModele); 函數(shù)作用,返回加載調(diào)用進程中的可執(zhí)行文件或者DLL的基地址/句柄,參數(shù)是可執(zhí)行文件或者DLL的名稱。給pszModule賦值NULL,則返回的是進程中可執(zhí)行文件的句柄。 注意:如果找不到則返回NULL。如果在DLL中傳遞NULL,返回的仍然是進程加載的可執(zhí)行文件的句柄。 4.1.2 進程的前一個實例句柄 第二個參數(shù)都傳遞NULL,是為16位系統(tǒng)所保留的。 4.1.3 進程的命令行 注意:不要試圖修改命令行內(nèi)部內(nèi)存的值,要使用修改先拷貝出來。 PTSTR GetCommandLine(); // 返回命令行字符串 PTSTR CommandLineToArgv(PTSTR pszCmdLine, int *pNumArgs); // 拆分命令行字符串函數(shù) Demo: int nNumargs; PTSTR *ppArgv = CommandLineToArgv(GetCommandLine(), &nNumargs); if ('x' == *ppArgv[1]) { // TODO: } // 手動釋放內(nèi)存,一般不需要釋放,系統(tǒng)會進程關(guān)閉時候自動釋放 HeapFree(GetProcessHeap, 0, ppArgv);
環(huán)境塊是進程地址空間中分配的內(nèi)存塊每個環(huán)境塊都包含一組字符串,格式如下: VarName1=VarVarlue1\0 VarName2=VarVarlue2\0 VarName3=VarVarlue3\0 ….. VarNameX=VarVarlueX\0 \0 注意:
DWORD GetEnvironmentVariable(PCTSTR pszName, PTSTR pszValue, DWORD cchValue);
ExpandEnvironmentStrings(PCSTR pszSrc, PSTR pszDst, DWORD nSize); 用來用現(xiàn)實出可替換的環(huán)境變量的字符串。 BOOL SetEnvironmentVariable(PCTSTR pszName, PCTSTR pszValue); 設(shè)置環(huán)境變量的值,如果不存在則創(chuàng)建,如果存在則替換他的值。 4.1.5 進程的親緣性 子進程繼承父進程的親緣性。(具體什么意思沒明白) 4.1.6 進程的錯誤模式 進程可以設(shè)置如何處理一些錯誤。 UINT SetErrorMode(UINT fuErrorMode);
標(biāo)志 說明 SEM_FAILCRITICALERRORS 系統(tǒng)不顯示關(guān)鍵錯誤句柄消息框,并將錯誤返回給調(diào)用進程 SEM_NOGOFAULTERRORBOX 系統(tǒng)不顯示一般保護故障消息框。本標(biāo)志只應(yīng)該由采用異常情況處理程序來處理一般保護(GP)故障的調(diào)式應(yīng)用程式來設(shè)定 SEM_NOOPENFILEERRORBOX 當(dāng)系統(tǒng)找不到文件時,它不顯示消息框。 SEM_NOALIGNMENTFAULTEXCEPT 系統(tǒng)自動排除內(nèi)存沒有對其的故障,并使應(yīng)用程序看不到這些故障。本標(biāo)志對X86處理器不起作用。 子進程繼承父進程的錯誤模式,如果不想讓子進程繼承父進程的錯誤模式的話,可以再調(diào)用CreateProcess時設(shè)定CREATE_DEFAULT_ERROR_MODE標(biāo)志。 4.1.7 進程的當(dāng)前驅(qū)動器和目錄 默認(rèn)情況下不提供全路徑的話,系統(tǒng)就會在當(dāng)前驅(qū)動器和目錄中查找文件,比如CreateFile,因為驅(qū)動器和目錄是每個進程來維護的,所以某個線程改變了目錄和驅(qū)動器會改變整個進程的目錄和驅(qū)動器。 下面兩個函數(shù)讀取和設(shè)置: DWORD GetCurrentDirectory(DWORD cchCurDir, PTSTR pszCurDir); BOOL SetCurrentDirectory(PCTSTR pszCurDir); 4.1.8 進程的當(dāng)前目錄 驅(qū)動器環(huán)境塊的格式: =C:=C:\Utility\Bin 程序查找驅(qū)動器環(huán)境塊,如果沒有則按驅(qū)動器名查找。 子進程不能繼承父進程的驅(qū)動器塊,如果想繼承必須寫到環(huán)境變量中去。(好像是這樣,如果有不對請高人指點)。 DWORD GetFullPathName(PCTSTR pszFile, DWORD cchPath, PTSTR pszPath, PTSTR *ppszFilePart); 獲取驅(qū)動器的當(dāng)前目錄,比如: TCHAR szCurDir[MAX_PATH];
DWORD GetFullPathName(TEXT("C:"), MAX_PATH, szCurDir, NULL);
DWORD GetVersion();此函數(shù)存在高地位的混論BUG,所以盡量不要使用。 BOOL GetVersion(POSVERSIONINFOEX pVersionInfomation); typedef struct _OSVERSIONINFOEXA { DWORD dwOSVersionInfoSize; // 在調(diào)用GetVersionEx函數(shù)之前,必必須置為sizeof(OSVERSIONINFOEX) DWORD dwMajorVersion; // 主系統(tǒng)的主要版本號 DWORD dwMinorVersion; // 主系統(tǒng)的次要版本號 DWORD dwBuildNumber; // 當(dāng)前系統(tǒng)的構(gòu)建號 DWORD dwPlatformId; // 識別當(dāng)前系統(tǒng)的平臺。可以使VER_PLATFORM_WIN32(WIN32),VER_PLATFORM_WIN32_WINDOWS(WINDOWS 95/WINDOWS 98),VER_PLATFORM_WIN32_NT(WINDOWS NT/WINDOWS 2000)或VER_PLATFORM_WIN32_CEHH(WINDOWS CE) CHAR szCSDVersion[ 128 ]; // Maintenance string for PSS usage 本域包含了附加文本,用于提供關(guān)于已經(jīng)安裝的操作系統(tǒng)的詳細(xì)信息 WORD wServicePackMajor; // 最新安裝的服務(wù)程序包的主要版本號 WORD wServicePackMinor; // 最新安裝的服務(wù)程序包的次要版本號 WORD wSuiteMask; // 用于標(biāo)識系統(tǒng)上存在那個程序組(VER_SUITE_SMALLBUSINESS,VER_SUITE_ENTERPRISE,VER_SUITE_BACKOFFICE,VER_SUITE_COMMUNICATIONS,VER_SUITE_TERMINAL,VER_SUITE_SMALLBUSINESS_RESTRICTED,VER_SUITE_EMBEDDEDNT和VER_SUITE_DATACENTER) BYTE wProductType; // 用于標(biāo)識安裝了下面的哪個操作系統(tǒng):VER_NT_WORKSTATION,VER_NT_SERVER或VER_NT_DOMAIN_CONTROLLER BYTE wReserved; // 留作將來使用 } OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA; 這個是擴展版本。 4.2 CreateProcess函數(shù)
終于看到正題了~
![]() BOOL CreateProcess( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
4.2.1 pszApplicationName和pszCommandLine pszCommandLine參數(shù):用來創(chuàng)建進程的命令行參數(shù)。查看第一個標(biāo)記,如果沒有”.exe”會自動添加”.exe”上去。(如果pszApplicationName參數(shù)NULL)
如果pszApplicationName參數(shù)不為NULL,系統(tǒng)將在當(dāng)前目錄中查找.exe文件(不會自動添加“.exe”),如果找不到將失敗,此時pszCommandLine作為參數(shù)傳遞給可執(zhí)行程序的進程。 4.2.2 psaProcess,psaThread和binHeritHandles psaProcess,psaThread是進程和進程主線程內(nèi)核對象的安全屬性。默認(rèn)值為NULL。 binHeritHandles設(shè)置為TRUE表示父進程在創(chuàng)建子進程可以繼承安全屬性標(biāo)志里設(shè)置為TRUE的任何可繼承的內(nèi)核對象。如果設(shè)置為FALSE子進程將不繼承任何內(nèi)核對象。 4.2.3 fdwCreate 用于標(biāo)識標(biāo)志,定義規(guī)則如何創(chuàng)建新進程。我一般寫默認(rèn)值NULL。具體的太多了,請查看MSDN吧,不想寫了。 4.2.4 pvEnvironment 設(shè)置子進程使用的環(huán)境內(nèi)存塊,一般默認(rèn)值為NULL,表示子進程繼承父進程的環(huán)境塊。 PVOID GetEnvironmentString(); // 獲取當(dāng)前內(nèi)存塊的地址 BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock); // 不用的時候調(diào)用此函數(shù)釋放內(nèi)存塊
設(shè)定工作目錄和驅(qū)動器號,如果為NULL則和應(yīng)用程序的目錄相同,如果設(shè)置比如以’\0’結(jié)尾的包含驅(qū)動器名的路徑。 4.2.6 psiStartInfo typedef struct _STARTUPINFO { DWORD cb; //(兩者兼有,控制臺和窗口程序) LPSTR lpReserved; // (兩者兼有)保留,必須初始化為NULL LPSTR lpDesktop; // (兩者兼有)用于標(biāo)識啟動應(yīng)用程序所在的桌面的名字。如果該桌面存在,新進程便與指定的桌面相關(guān)聯(lián)。如果桌面不存在,便創(chuàng)建一個帶有默認(rèn)屬性的桌面,并使用為新進程指定的名字。如果lpDesktop是NULL(這是最常見的情況),那么該進程將與當(dāng)前桌面相關(guān)聯(lián)。 LPSTR lpTitle; // (控制臺)用于設(shè)定控制臺窗口名稱。如果lpTitle是NULL,則可執(zhí)行文件的名字將用作窗口名 DWORD dwX; // x,y坐標(biāo),只有當(dāng)子進程用CW_USEDEFAULT作為CreateWindows的x參數(shù)來創(chuàng)建它的第一個重疊窗口時,才使用這兩個坐標(biāo)。若是創(chuàng)建控制臺窗口的應(yīng)用程序,這些成員用于指明控制臺窗口的左上角。 DWORD dwY; DWORD dwXSize; //(兩者兼有)設(shè)定窗口寬度和長度,只有子進程用WM_USEDEFAULT作為CreateWIndows的nWidth參數(shù)來創(chuàng)建它的第一個重疊窗口時才是用這個值。控制臺就是控制臺的寬和長 DWORD dwYSize; DWORD dwXCountChars; //(控制臺)用于設(shè)定子應(yīng)用程序控制臺的長度和寬度(字符表示) DWORD dwYCountChars; DWORD dwFillAttribute;// (控制臺)用于設(shè)定子應(yīng)用程序的控制臺背影顏色和文本。 DWORD dwFlags; // (兩者兼有)參見下一段 WORD wShowWindow; // (窗口)用于設(shè)定子應(yīng)用程序初次調(diào)用ShowWindow將SW_SHOWDEFAULT作為nCmdShow參數(shù)傳遞時,該應(yīng)用程序的第一個重疊窗口應(yīng)該如何出現(xiàn)。本成員可以是通常用于ShowWindow函數(shù)的任何一個SW_*標(biāo)識符 WORD cbReserved2; // 保留,必須初始化為0 LPBYTE lpReserved2; // 保留,必須初始化為NULL HANDLE hStdInput; // (控制臺)用于設(shè)定控制臺輸入和輸出用的緩存的句柄。默認(rèn)設(shè)置hStdInput是鍵盤緩存,hStdOutput和hStdError窗口的緩存。 HANDLE hStdOutput; // HANDLE hStdError; } STARTUPINFO, *LPSTARTUPINFO;
STARTUPINFO si = {sizeof(si)}; dwFlags標(biāo)志,用于修改如何來創(chuàng)建子進程。 標(biāo)志 STARTF_USESIZE 使用dwXSize和dwYSize成員 STARTF_USESHOWWINDOW 使用wShowWIndow成員 STARTF_USEPOSITION 使用dwX和dwY成員 STARTF_USECOUNTCHARS 使用dwXCountChars和dwYCountChars成員 STARTF_USEFILLATTRIBUTE 使用dwFillAttribute成員 STARTF_USESTDHANDLES 使用hStdInput,hStdOutput和hStdError成員 STARTF_RUN_FULLSCREEN 強制再x86計算機上運行的控制臺應(yīng)用程序以全屏幕方式啟動運行 STARTF_FORCEONFEEDBACK 光標(biāo)設(shè)置為沙漏,過了2秒如果進程沒啟動GUI,CreateProcess程序?qū)⒐鈽?biāo)設(shè)置為箭頭,5秒內(nèi)顯示一個窗口,成功調(diào)用GetMessage則反復(fù)箭頭,如果沒有成功,等待5秒 變?yōu)榧^ STARTF_FORCEOFFFEEDBACK 4.2.7 ppiProcInfo typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; 返回的分別是,子進程進程句柄,子進程中主線程的線程句柄,子進程ID,子進程中主線程的ID。 注意:
4.3 終止進程的運行 4.3.1 主線程的進入點函數(shù)返回 最好強力推薦使用這種方式。
4.3.2 ExitProcess函數(shù) 避免使用這個方法。 VOID ExitProcess(UINT fuExitCode); 終止進程運行,并將退出碼設(shè)置為fuExitCode。 注意:
4.3.3 TerminiateProcess函數(shù) 能不用就別用。 BOOL TerminiateProcess(HANDLE hProcess, UINT fuExitCode;) 關(guān)閉指定為hProcess句柄的進程,推出代碼為fuExitCode。 注意:
4.3.4 進程終止運行時出現(xiàn)的情況
注意: 進程內(nèi)核對象的壽命可能遠(yuǎn)遠(yuǎn)大于進程本身,父進程保留子進程內(nèi)核對象可以查看它的推出代碼調(diào)用下面函數(shù): BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);
4.4 子進程 沒什么好說的,前面的都說了,用CloseHandle關(guān)閉子進程和子進程中主線程的句柄值來切斷父進程和子進程的所有聯(lián)系。
4.5 每局系統(tǒng)中運行的進程 利用ToolHelp函數(shù)族來開發(fā)管理操作系統(tǒng)上的進程。打算自己也寫個試試。
本文章的內(nèi)容是本人學(xué)習(xí)Windows核心編程第四章后的總結(jié),有錯誤請大家糾正,轉(zhuǎn)載注明出處:
|
![]() |
|
Copyright © xi52qian | Powered by: 博客園 模板提供:滬江博客 |