480 likes | 613 Views
Processes. 井民全製作. Introduction. Process is an instance of running program Kernel object: OS uses to manage the process and keeps information about the process Address space: contains all the executable or DLL module ’ s code and data. 例如 : ExitCode, STILL ACTIVE 等資訊.
E N D
Processes 井民全製作
Introduction • Process is an instance of running program • Kernel object: OS uses to manage the process and keeps information about the process • Address space: contains all the executable or DLL module’s code and data 例如: ExitCode, STILL ACTIVE等資訊 包含 Heap 配置的空間 Thread 使用的 Stack
Thread1 Thread2 Thread8 CPU Thread7 Thread3 Thread6 Thread4 Thread5 Introduction 靜止不動的 • Processes are inert, it must have a thread that runs in its context • Single process several threads • Thread • Own set of CPU registers • Own Stack • All thread run concurrently by offering time slices Thread 1 Create Process Create Primary thread Thread 2
Writing Your First Windows Application • Two types of application • GUI: based on graphical user interface • Create window, menu • Could output text string to console • the Linker switch: /SUBSYSTEM:WINDOWS • CUI: based on console user interface • CMD.exe (2k) or COMMAND.COM(98) • could display a graphical dialog box • the Linker switch: /SUBSYSTEM:CONSOLE Load the application OS’s loader Create a consoleWindow Load the application OS’s loader
新增解釋 The entry point function for C/C++ 1 2 執行檔的起始執行位置 C/C++ 的起始執行位置 int __cdecl main(…){ } Operating System Startup Function Entry Point function 功用在於 Initializes the C/C++ run-time library (之後你才可以呼叫 malloc, free) 位於你的project 位於 crt.0.c C/C++ Run-Time CRT 呼叫的是 WinMain GUI 呼叫的是 main CUI
注意: .Net 2003 IDE 會向你詢問 entry point function: 請加入 WinMainCRTStartup Choose the proper C/C++ startup function • You can remove the /SUBSYSTEM linker switch system check WinMainCRTStartup /SUBSYSTEM:WINDOWS Linker mainCRTStartup /SUBSYSTEM:CONSOLE 系統會看看你的source檔中, 包含哪一種 entry point function 以決定你是哪一個 subsystem 範例: RemoveLinkerSwitchDemo 調整不同的選項看看 (選錯=> 出現 link 錯誤)
What the startup functions do? Full command line Pointer Step 1 Pointer main(), wmain(), WinMain(), wWinMain Step 2 Environment variables Step 5 C/C++ Entry function Initial C/C++ run time’s Global variables then Step 3 作業系統版本等資訊 int retValue= main(__argc,__argv,_environ); 建立 Heap 結構 Initial heap malloc / calloc Step 4 If you wrote a main function Global and static C++ object 呼叫他們的建構子
目前 instance 的 Handle 永遠設為 null 命令列字串 指定視窗該如何秀出來 Startup function 如何呼叫你的 entry function ? GetStartupInfo(&StartupInfo); int nMainRetVal = wWinMain(GetModuleHandle(NULL), NULL, pszCommandLineUnicode, (StartupInfo.dwFlags & STARTF_USESHOWWINDOW)? StartupInfo.wShowWindow : SW_SHOWDEFAULT); int nMainRetVal = WinMain(GetModuleHandle(NULL), NULL, pszCommandLineAnsi , (StartupInfo.dwFlags & STARTF_USESHOWWINDOW)? StartupInfo.wShowWindow : SW_SHOWDEFAULT); ANSI 版本 如果你寫了wmain int nMainRetVal = wmain(__argc, __wargv, __wenviron); ANSI 版本 int nMainRetVal = main(__argc, __argv, __environ);
Crt0.c line 155 The C/C++ run-time global variable 請 #include <stdlib.h> printf(“作業系統 build version %d\n",_osver); printf(“作業系統 major version %d\n",_winmajor); printf(“作業系統 minor version %d\n",_winminor); printf("作業系統 win version %d\n",_winver); printf("command line 共有 %d 個參數\n",__argc); for(int i=0;i<__argc;i++){ if(__argv!=NULL) printf("\tANSI 字串參數 %s\n",__argv[i]); if(__wargv!=NULL) printf("\tUNICODE 字串參數 %s\n",__wargv[i]); } printf("ANSI 字串envoronent指標 %p\n",_environ); printf("UNICODE 字串envoronent指標 %p\n",_wenviron); printf("ANSI 目前程式的full path %s\n",_pgmptr); printf("UNICODE 目前程式的full path %s\n",_wpgmptr); 在 Startup function 片段中,設定初值 see: 讀取環境變數範例
Crt0dat.c line 374 When your entry-point function return C/C++ run-time library • Call any functions registered by calls to the _onexit function • Call destructor global & static C++ objects • Call OS’s ExitProcess() to kill your process Startup Function exit( main 傳回值 )
Registers a routine to be called at exit time #include <stdlib.h> #include <stdio.h> int fn1(void), fn2(void); // 定義 prototypes void main(void){ _onexit( fn1 ); _onexit( fn2 ); printf( "This is executed first.\n" ); } int fn1(){ printf("第三號執行.\n" ); return 0; } int fn2(){ printf("第二號執行"); return 0;} int fn1(void); int fn2(void); 註冊當 main 結束時,要呼叫的 function (LIFO 後進先出 Last In First Out) GDI 程式也可以使用 See:註冊on_exit 範例 參考資料: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt__onexit.asp
A Process’s Instance Handle 用途: • Needed for load resources • You can save this handle in a global variable, so that easily accessible to all the code. • Some functions requires a parameter of the type HMODULE 指定你 resource 的位置 ex HICON LoadIcon( HINSTANCE hinst, PCTR pszIcon); HINSTANCE = HMODULE MFC 程式: 你可以用下面指令 theApp.m_hInstance
A Process’s Instance Handle int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ } • In Win98, 0x00400000 is the lowest address where the executable file image can be loaded. • You can change the base address! is the base memory address where the executable file’s image into the space 注意: 5 個 0 code Win2000 沒有這個限制 hInstance 0x00400000(default) Base address Linker option: /BASE: address virtual space 請看範例程式
Get the module handle/base address HMODULE GetModuleHandle(PCTSTR pszModule); 傳回的handle (base address) 要取得位址的 module(.dll or .exe) 名稱 (字串) 傳回 NULL: 表示系統找不到相關的 module (可能是目前的Process 沒有載入) int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ HMODULE MyHandle=GetModuleHandle(NULL); MessageBoxEx(NULL,"查看 hInstance 的值","查看 hInstance 的值",MB_OK); return 0; } 取得目前 process的載入位址 也可以察看 Common Control library 被 載入的位址: HMODULE h=GetModuleHandle(_T("Comctl32.dll"));
取得 console application 的載入位址 • 因為 main/ wmain 沒有參數給你 Process 的 Handle, 所以你可以使用 GetModuleHandle(NULL) #include <stdlib.h> // for C/C++ global varible definition #include <stdio.h> // for printf #include <windows.h> int main(){ char buffer[100]; sprintf(buffer,"The module base address= %p", GetModuleHandle(NULL) ); MessageBox(NULL,buffer,"讀取 module base address",MB_OK); } GetModuleHandle 傳回來的 Handle 不會增加 該 process 的 usage counter, 故不必 close 使用 void* 位址顯示格式 %p
新增圖片說明 IDE 設定 command 參數 A Process’s Command Line always NULL int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); C:\Cmd.exe 1 2 3 4 5 6 Parsing Arguments PTSTRGetCommandLine(); // 取得全部的參數列 int nNumArgs; PWSTR *ppArgv=CommandLineToArgvW( GetCommandLineW(), &nNumArgs); // 處理 if( *pArgv[1] == L’x’) … HeapFree( GetProcessHeap(), 0, ppArgv); 自動將 參數解析出來 MessageBox(NULL,ppArgv[1],L"test",MB_OK); 字串 範例程式: 剖析你的 commandline
環境變數 A Process’s Environment Variable • Every Process has an environment block associated with it 以 \0 結尾 變數名稱 值 JAVA_HOME=C:\j2sdk1.4.1_01\0 Name1=Value2\0 Name2=Value3\0 \0 最後結束 code Note: 1. ‘=‘ cannot be part of the name 2. XYZ= Windows ABC =Home 空白也算數 virtual space
設定環境變數初值Create an initial set of environment variable • Windows 98 • Autoexec.bat • SET VarName=VarValue • Windows 2000 Regedit.exe 使用 Registry System 的設定 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\Session Manager\Environment JAVA_HOME=C:\j2sdk1.4.1_01\0 Name1=Value2\0 Name2=Value3\0 \0 HKEY_CURRENT_USER\Environment 目前User的設定 Environment block
注意: 要夠大,否則不會放進來 讀取環境變數的值Determine the value of an environment value DWORD GetEnvironmentVariable (PCTSTR pszName, PTSTR pszValue, DWORD cchValue); Name Value 空間大小 Ex: 查詢 環境變數 Java_Home的內容 #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ TCHAR pszValue[100]; DWORD ReadedChar=GetEnvironmentVariable(_T("JAVA_HOME"),pszValue,100); MessageBox(NULL,pszValue,_T("Read Environment Value"),MB_OK); return 0; } for TCHAR, _T 配置 TCHAR 字元陣列當字串傳回儲存空間 範例: 讀取環境變數的值
You can modify, delete, add the variable from the environment block BOOL SetEnvironmentVariable (PCTSTR pszName, PTSTR pszValue); SetEnvironmentVariable(_T(“MyProjectDir“), _T(“c:\\test”)); 設定環境變數 MyProjectDir=c:\test SetEnvironmentVariable(_T(“MyProjectDir“), NULL); 刪除環境變數 MyProjectDir #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ TCHAR pszValue[100]; SetEnvironmentVariable(_T("MyProjectDir"), _T("c:\\test")); MessageBox(NULL, pszValue, _T(“SetEnvironment Value), MB_OK); return 0; } 注意: SetEnvironmentVariable 只為反映在目前的 process 的設定上, 不會影響其他的 process 程式Demo:環境變數刪除新增範例
Succeeds ERROR_SUCCESS Handle to the opened key 更改 Registry 上的變數值 • Step 1: Open the Key • KEY_CURRENT_USER • Environment (Sub Key) • Step 2: Set the value Opened key 要修改的 Sub key HKEY hKey; LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_ALL_ACCESS, &hKey ); must be 0 Access mask 新的值 要改的變數 LPCTSTR pszValue=_T("d:\\test"); lRet=RegSetValueEx(hKey,_T("TestDir"), 0,REG_SZ, (const BYTE*)pszValue, lstrlen(pszValue)*sizeof(TCHAR)); 值為字串 新字串的位址 新字串的長度 程式Demo: Registry 修改範例
A Process’s Error Mode --自己接手處理嚴重錯誤 • Tell the system how the process should respond to serious errors • Disk media failures, unhandled exception, file-find failures, and data misalignment
自己處理 錯誤 補充 不要秀出 general-protection-fault 請直接執行 exe 檔 (不要在 IDE中執行)
判斷 A 槽是否有磁片 #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ int OldMode = SetErrorMode (SEM_FAILCRITICALERRORS); SetLastError(-1); WIN32_FIND_DATA fd; FindFirstFile("A:\\*.*", &fd); int error = GetLastError(); switch(error){ case ERROR_FILE_NOT_FOUND: case -1: MessageBox(NULL,”磁片OK”,MB_OK); break; default: ShowErrorMessage(error); } SetErrorMode(OldMode); return 0; } 設定發生問題時,系統 不要秀出message box 嘗試的讀取A槽的資料 若沒有error 發生時, GetLastError會傳回 -1 我們藉此判斷是否正常 設定回原來的設定 程式Demo::判斷a槽是否ready範例
設定與取得預設路徑:Obtain and set the current drive and directory DWORD GetCurrentDirectory( DWORD nBufferLength, // size, in characters, of directory buffer LPTSTR lpBuffer // pointer to buffer for current directory ); BOOL SetCurrentDirectory( LPCTSTR lpPathName); 會反映到目前 Process 中所有的 threads #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ const DWORD nBufferLength=100; TCHAR lpBuffer[nBufferLength]; DWORD Num=GetCurrentDirectory (nBufferLength , lpBuffer); if(Num==0){ ShowErrorMessage(Num); return -1; } MessageBox(NULL, lpBuffer, _T("目前的預設路徑"), MB_OK); return 0; } 取得目前目錄的字串 有多少個字元被讀取 程式Demo:讀取預設路徑範例
You can use _chdir instead the SetCurrentDirectory()! _chdir 的好處是 隨著 _chdir 的設定, 會新增修改每個磁碟機的 Default Directory 的環境變數 Handling current directories for multiple drives -- 更改其他槽的預設路徑 Problem hFile = CreateFile(_T("D:myfile.txt"), …) • 1. 先看 Current Directory • 2. If your current directory = C:\, then the system looks up 環境 變數 “=D:” • 3. If “D:” did not exist open from the root of D drive D:myfile.txt Where to open the myfile.txt file ? 磁碟機 D 的目前目錄 例如: =D:=D:\Program Files
_chdir 範例 #include <direct.h> #include <stdio.h> #include <stdlib.h> int main( int argc, char *argv[] ) { if( _chdir( argv[1] ) ) printf( "Unable to locate the directory: %s\n", argv[1] ); else system( "dir *.exe"); } 如果 _chdir(“c:\\”); 則會設定目前目錄為 c:\\ 並且列出 c:\\ 下所有的 exe 檔 列出目前目錄下,的所有 exe 檔
Example: 設定 D 槽的 Default Directory #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ SetEnvironmentVariable(_T("=D:"),_T("D:\\TEST")); HANDLE hFile; hFile = CreateFile(_T("D:myfile.txt"), // file to create GENERIC_WRITE, // open for writing 0, // do not share NULL, // default security CREATE_ALWAYS, // overwrite existing FILE_ATTRIBUTE_NORMAL | // normal file FILE_FLAG_OVERLAPPED, // asynchronous I/O NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { MessageBox(NULL,_T("Could not open file "),_T("Error"),MB_OK); return 0; } CloseHandle(hFile); // 系統離開時,也會自動的close 所有的handle return 0; } 程式Demo:更改其他槽的預設路徑範例 目前更改了D槽的預設路徑
* Current Directory 每個 process 只有一個 • The child process does not inherit the parent process’s current directories • Root of every drive (default) • You must create the drive-letter environment variable 先建立 Driver-Letter 環境變數 Child 會繼承 parent 的環境變數,使得各個 Device Default Directory 會被複製 =C:=C:\Utility\Bin =D:=D:\Program Files C 的預設目錄為 c:\Utility\Bin =C:=C:\Utility\Bin =D:=D:\Program Files Child A’s environment block D 的預設目錄為 D:\Program Files =C:=C:\Utility\Bin =D:=D:\Program Files Environment block 放進指定的檔名, 傳回 完整的路徑名稱 Child B’s environment block 傳回目前C 槽的 Current Directory TCHAR szCurDir[MAX_PATH]; DWORD GetFullPathName(_T(“C:”), MAX_PATH, szCurDir, NULL); 檔案名稱 Buffer大小 Buffer位置 Filename所在位置
How to determine the Windows versions BOOL GetVersionEx( LPOSVERSIONINFO lpVersionInformation);
Example: 判斷是否為Win2000 #include <windows.h> #include <tchar.h> int APIENTRY WinMain(…){ OSVERSIONINFOEX osver={0}; osver.dwOSVersionInfoSize=sizeof(OSVERSIONINFOEX); BOOL bFlag=GetVersionEx((OSVERSIONINFO *) &osver); if(bFlag==FALSE){ MessageBox(NULL,_T("Error"),_T("系統資訊"),MB_OK); ExitProcess(-1); } if(osver.dwMajorVersion==5 && osver.dwMinorVersion==0) MessageBox(NULL,_T("Windows2000"),_T("系統資訊"),MB_OK); return 0; } 指定大小 取得版本資訊 判斷是否為Win2000作業系統 程式Demo:判斷是否為Win2000範例
Create the Process: Process 建立流程 管理 Process 的資料結構 Create a Process kernel object 1 A thread call CreateProcess Create a Virtual address space Load the Code ,Data and DLL main{ } 管理 Thread 的資料結構 1 Create a Thread kernel object 建立primary thread main{ } 執行 C/C++ run-time Startup code
Create the Process: The CreateProcess function 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); 新建出來的 process / thread 是否可以被其他 child 繼承 執行檔名稱 命令列 設定 process 的建立方式: 1. 是否擁有 console 2. 優先權類別設定 TRUE: 則每個可以被繼承的Kernel Object都會被新建立的 process 繼承 字串, 指定新建立 process 的目前目錄 . 指向環境變數區塊的 位址, NULL 使用 parent 的environment. 一個 STARTUPINFO結構: 紀錄 window 位置,大小 console 寬度字元數,高度字元數 標準輸入輸出與標準錯誤的 handle 一個 PROCESS_INFORMATION結構: 紀錄新建立的 Process Handle 與 PID primary thread Handle 與 hID
void main( VOID ){ STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); // Start the child process. if( !CreateProcess( NULL, // No module name (use command line). "MyChildProcess", // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. FALSE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parent's environment block. NULL, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi ) // Pointer to PROCESS_INFORMATION structure. ) { ErrorExit( "CreateProcess failed." ); } // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } 配置 STARTUPINFO 與 PROCESS_INFOMATION 給新建的 process 使用 範例程式 設定初值 建立新的 process 主要程式碼 等待新建出來的 process terminated (試著把這行拿掉看看) 將reference 到 process 與 thread 的 Handle close 起來
Terminating a Process 下列四種情況下, 會 Terminating 一個 proces • Primary thread’s entry-point function returns • WinMain, main, wWinMain and wmain • The thread’s resources will be cleaned up properly • C++ object will be destroyed properly • The memory used in the thread’s stack will free • Process’s exit code will return • Process kernel object usage counter - 1 • ExitProcess() • TerminateProcess() • All the threads in the process die 強烈建議使用 由 main 或 WinMain 離開,系統幫你做的事情 強迫自己終止 (會通知 DLL ) C++ 解構子不會被呼叫 可以強迫其他 process 終止 (不會通知 DLL 對應的 detaching function) Process 可能沒有機會 update 狀態資料到 disk 中
這裡指的是那些 Handle (Event,File,Process…) int APIENTRY WinMain(…){ … return 0; } 進入 C/C++ run-time Startup code Any threads running in the process terminate call ExitProcess(0) ExitProcess() function • Any thread that call ExitProcess() will terminates the process • All system resource will be cleaned up perfectly • C/C++ run time policy 0 表示正常結束 VOID ExitProcess(UINT fuExitCode);
#include <windows.h> #include <iostream> using namespace std; CSomeObj g_GlobalObj; // 宣告全區域變數 void main(){ CSomeObj LocalObj; ExitProcess(0); } class CSomeObj{ public: CSomeObj(){ cout<<"建構子" << endl;} ~CSomeObj(){ cout<<"解構子"<< endl;} }; C/C++ 程式應該避免呼叫 ExitProcess() 程式範例 :避免呼叫ExitProcess • System resource will be cleaned but the C++ objects are not. 導致系統狀態無法更新 有可能的情況是在物件的解構子中, 針對目標資料庫做結束的動作, 因為你呼叫了 ExitProcess() 而導致資料庫資訊不正確 執行結果 建構子 建構子 直接呼叫的結果 C++物件沒有被解構
TerminateProcess function() • You can terminate another process BOOL TerminateProcess(HANDLE hProcess,UINT fuExitCode); 根本沒有通知, 來不及存檔 TerminateProcess(…) terminate Process A Process B OS 會接手把會接手把ProcessB的所有資源全部釋放
C/C++ startup #include <windows.h> #include <stdio.h> #include <tlhelp32.h> void main(){ GetProcessList(); } 列出所有目前正在執行Processes Name範例 BOOL GetProcessList( ){ HANDLE hProcessSnap; hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hProcessSnap == INVALID_HANDLE_VALUE ) { printError( "CreateToolhelp32Snapshot (of processes)" ); return( FALSE ); } PROCESSENTRY32 pe32; pe32.dwSize = sizeof( PROCESSENTRY32 ); if( !Process32First( hProcessSnap, &pe32 ) ) { printError( "Process32First" ); CloseHandle( hProcessSnap ); // Must clean up the snapshot object! return( FALSE ); } do{ printf( "\nPROCESS NAME: %s", pe32.szExeFile ); }while( Process32Next( hProcessSnap, &pe32 ) ); // 4. Don't forget to clean up the snapshot object! CloseHandle( hProcessSnap ); return TRUE; } 1. 取得目前系統中正在執行Processes 的快照(snapshot) 列出的是 process ignored 2. 取出第一個正在執行的Process 3. 印出相關Process的名稱 程式範例:列出目前系統正在執行的Process 參考資料: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/taking_a_snapshot_and_viewing_processes.asp
Terminate 所有目前正在執行的 Notepad BOOL GetProcessList( ){ HANDLE hProcessSnap; hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); <中間省略> do{ printf( "\nPROCESS NAME: %s", pe32.szExeFile ); }while( Process32Next( hProcessSnap, &pe32 ) ); // 4. Don't forget to clean up the snapshot object! CloseHandle( hProcessSnap ); return TRUE; } if(strcmpi("NotePad.exe",pe32.szExeFile)==0){ printf("發現NotePad.exe程式 刪除"); HANDLE hProcess; hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID ); if( hProcess == NULL ) printError( "OpenProcess" ); TerminateProcess(hProcess,0); CloseHandle( hProcess ); WaitForSingleObject(hProcess,INFINITE); } 取得 notepad.exe process 的 Handle 這個傳回來的 Handle 不需要繼承屬性 Terminate notepad processes 程式範例:TerminateProcess
When a Process Terminates當Process被終結時,系統的動作流程 Terminate any remaining thread All User & GDI objects are freed 釋放如 menu, icon 等資源 All Kernel objects are closed 若沒有任何Process 擁有它, 則這個 Kernel object 將會被 destory Exit code STILL_ACTIVE VOID ExitProcess(UINT fuExitCode); 系統狀態會由 STILL_ACTIVE 改成 fuExitCode Signaled the Process kernel object -1
Obtain the process’s exit code 會傳回目標 process 的 kernel object ExitCode BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode); 回傳的資料 Get the process’s handle WaitForSingleObject 等待該 process terminate • You can call this function atany time • 若目標 process 沒有 exit 則 • pdwExitcode STILL_ACTIVE • (0x103) GetExitCodeProcess
參考資料:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_6.asp參考資料:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_6.asp __cdecl V.S. __stdcall Microsoft Specific • __cdecl: default calling converting for C/C++ • The stack is cleaned up by the caller. (可處理不定變數) • __stdcall: is used to call Win32 API • The callee clean the stack. (故不定變數 function 由 __cdecl 處理) 因為只有 caller 才知道 push 了 多少參數給 callee function 被呼叫的 function
__fastcall • __fastcall: • arguments to functions are to be passed in registers, when possible. 參考資料: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_core___fastcall.asp