Upload
bartholomew-foster
View
248
Download
0
Embed Size (px)
Citation preview
ProcessesProcesses
井民全製作
IntroductionIntroduction
Process is an instance of running Process is an instance of running programprogram Kernel object:Kernel object:
OS uses to OS uses to managemanage the process and the process and keeps keeps informationinformation about the process about the process
Address space:Address space:
contains all the executable or DLL contains all the executable or DLL module’s module’s code and datacode and data
包含 Heap 配置的空間Thread 使用的 Stack
包含 Heap 配置的空間Thread 使用的 Stack
例如 : ExitCode, STILL ACTIVE 等資訊
例如 : ExitCode, STILL ACTIVE 等資訊
IntroductionIntroduction
Processes are inert, it must have a Processes are inert, it must have a threadthread that runs in its context that runs in its context
Single process Single process several threads several threads ThreadThread
Own set of CPU registersOwn set of CPU registers Own StackOwn Stack All thread run concurrently by offering All thread run concurrently by offering
time slicestime slices
Create ProcessCreate Process Create Primary thread
Create Primary thread
Thread 1Thread 1
Thread 2Thread 2
靜止不動的靜止不動的
CPU
Thread1
Thread2
Thread3
Thread5
Thread7
Thread4Thread6
Thread8
Writing Your First Windows Writing Your First Windows ApplicationApplication
Two types of applicationTwo types of application GUI:GUI: based on based on graphicalgraphical user interface user interface
Create window, menuCreate window, menu Could output text string to consoleCould output text string to console the Linker switch: the Linker switch:
/SUBSYSTEM:WINDOWS/SUBSYSTEM:WINDOWS
CUICUI: based on : based on consoleconsole user interface user interface CMD.exe (2k) or COMMAND.COM(98)CMD.exe (2k) or COMMAND.COM(98) could display a graphical dialog box could display a graphical dialog box the Linker switch: the Linker switch: /SUBSYSTEM:CONSOLE/SUBSYSTEM:CONSOLECreate a
consoleWindow
Create a consoleWindow Load the applicationLoad the application
OS’s loader
Load the applicationLoad the applicationOS’s loader
The entry point function for The entry point function for C/C++C/C++
Application TypeApplication Type Startup FunctionStartup Function Entry PointEntry Point
GUI applicationGUI application
((ANSIANSI characters) characters)WinMainWinMainCRTStartupCRTStartup WinMain(HINSTANCWinMain(HINSTANC
E …)E …)
GUI applicationGUI application
((UNICODEUNICODE characters) characters)wwWinMainWinMainCRTCRTStartupStartup wwWinMain(HINSTANWinMain(HINSTAN
CE …)CE …)
CUI applicationCUI application
((ANSIANSI characters) characters)mainmainCRTCRTStartupStartup main(int argc,char main(int argc,char
*argv[], …)*argv[], …)
CUI applicationCUI application
((UNICODEUNICODE characters) characters)wwmainmainCRTCRTStartupStartup wwmain(int argc, main(int argc,
wchar_t *argv[])wchar_t *argv[])
Operating SystemOperating System Startup FunctionStartup Function int __cdecl main(…){
}
int __cdecl main(…){
}
Entry Point function
Initializes the C/C++run-time library ( 之後你才可以呼叫 malloc, free)
GUI
CUI
C/C++ Run-Time CRT 呼叫的是 WinMain
呼叫的是 main
功用在於
1 2
新增解釋
C/C++ 的起始執行位置執行檔的起始執行位置
位於 crt.0.c 位於你的 project
Choose the proper C/C++ Choose the proper C/C++ startup functionstartup function
WinMainCRTStartupWinMainCRTStartup
LinkerLinker
mainCRTStartupmainCRTStartup
/SUBSYSTEM:WINDOWS
/SUBSYSTEM:CONSOLE
You can You can removeremove the /SUBSYSTEM the /SUBSYSTEM linker switch linker switch system checksystem check
範例 : RemoveLinkerSwitchDemo
系統會看看你的 source 檔中 , 包含哪一種 entry point function以決定你是哪一個 subsystem
調整不同的選項看看 ( 選錯 => 出現 link 錯誤 )
注意 : .Net 2003 IDE 會向你詢問 entry point function: 請加入 WinMainCRTStartup
選擇 選擇 SubSystemSubSystem
What the startup What the startup functions do?functions do?
PointerPointer
Full command lineFull command line
Step 1
PointerPointerEnvironment variables
Environment variables
Initial C/C++ run time’sGlobal variables
Initial C/C++ run time’sGlobal variables
Initial heap malloc / calloc
Initial heap malloc / calloc
Global and static C++ object 呼叫他們的建構子
Global and static C++ object 呼叫他們的建構子
C/C++ Entry functionC/C++ Entry functionthen
int retValue= main(__argc,__argv,_environ);
If you wrote a main function
建立 Heap 結構建立 Heap 結構
main(), wmain(), WinMain(), wWinMain
Step 2
Step 3
Step 4
Step 5
作業系統版本等資訊
GetStartupInfo(&StartupInfo);int nMainRetVal = wWinMain(GetModuleHandle(NULL), NULL, pszCommandLineUnicode, (StartupInfo.dwFlags & STARTF_USESHOWWINDOW)? StartupInfo.wShowWindow : SW_SHOWDEFAULT);
目前 instance 的 Handle
目前 instance 的 Handle
永遠設為 null永遠設為 null
命令列字串命令列字串
指定視窗該如何秀出來
指定視窗該如何秀出來
int nMainRetVal = WinMain(GetModuleHandle(NULL), NULL, pszCommandLineAnsi , (StartupInfo.dwFlags & STARTF_USESHOWWINDOW)? StartupInfo.wShowWindow : SW_SHOWDEFAULT);
ANSI 版本
ANSI 版本
int nMainRetVal = wmain(__argc, __wargv, __wenviron);
如果你寫了 wmain如果你寫了 wmain
int nMainRetVal = main(__argc, __argv, __environ);
Startup function 如何呼叫你的 entry function ?
ANSI 版本
ANSI 版本
The C/C++ run-time The C/C++ run-time global global variablevariable
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);
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);
see: 讀取環境變數範例
請 #include <stdlib.h>
在 Startup function 片段中 ,設定初值
在 Startup function 片段中 ,設定初值
Crt0.c line 155
When your entry-point function When your entry-point function returnreturn
Call any functions Call any functions registeredregistered by calls by calls to the to the _onexit_onexit function function
Call Call destructordestructor global & static C+ global & static C++ objects+ objects
Call OS’s Call OS’s ExitProcessExitProcess() to kill your () to kill your processprocess
Startup FunctionStartup Function
C/C++ run-time library
exit( main 傳回值 )
Crt0dat.c line 374Crt0dat.c line 374
Registers a routine to Registers a routine to be be called at exit timecalled 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;}
#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;}
註冊當 main 結束時 , 要呼叫的 function(LIFO 後進先出 Last In First Out)
註冊當 main 結束時 , 要呼叫的 function(LIFO 後進先出 Last In First Out)
See: 註冊 on_exit 範例參考資料 : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt__onexit.asp
int fn1(void);int fn2(void);
int fn1(void);int fn2(void);
GDI 程式也可以使用
A Process’s Instance A Process’s Instance HandleHandle
Needed for load resourcesNeeded for load resources
You can save this handle in You can save this handle in a global a global variablevariable, so that easily accessible to , so that easily accessible to all the code.all the code.
Some functions requires a Some functions requires a parameter of the type parameter of the type HMODULEHMODULE
HICON LoadIcon( HINSTANCE hinst, PCTR pszIcon);HICON LoadIcon( HINSTANCE hinst, PCTR pszIcon);
ex 指定你 resource 的位置指定你 resource 的位置
HINSTANCE = HMODULE
用途 :用途 :
MFC 程式 : 你可以用下面指令 theApp.m_hInstance
A Process’s Instance A Process’s Instance HandleHandle
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){}
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){}is the base memory address where the executable file’s image into the space
hInstancecodecode
0x00400000(default)
virtual space
In Win98, In Win98, 0x00400000 is the 0x00400000 is the lowest addresslowest address where where the executable file the executable file image can be loaded.image can be loaded.
You can change the You can change the base address!base address!Linker option: /BASE: address
Base address
請看範例程式
注意 : 5 個 0
Win2000 沒有這個限制Win2000 沒有這個限制
更改你的 Module 基底位址更改你的 Module 基底位址
Get the module handle/base Get the module handle/base addressaddress
HMODULE GetModuleHandle(PCTSTR pszModule);HMODULE GetModuleHandle(PCTSTR pszModule);
要取得位址的 module(.dll or .exe) 名稱 ( 字串 )要取得位址的 module(.dll or .exe) 名稱 ( 字串 )傳回的 handle (base address)傳回的 handle (base address)
傳回 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"));
也可以察看 Common Control library 被 載入的位址 : HMODULE h=GetModuleHandle(_T("Comctl32.dll"));
取得 取得 console application console application 的載入的載入位址位址
因為 因為 main/ wmain main/ wmain 沒有參數給你 沒有參數給你 Process Process 的 的 Handle, Handle, 所以你可以使用所以你可以使用
GetModuleHandle(NULL)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
GetModuleHandle 傳回來的 Handle 不會增加該 process 的 usage counter, 故不必 close
使用 void* 位址顯示格式 %p使用 void* 位址顯示格式 %p
A Process’s Command A Process’s Command LineLine
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
C:\Cmd.exe 1 2 3 4 5 6
PTSTR GetCommandLine(); // 取得全部的參數列PTSTR GetCommandLine(); // 取得全部的參數列
int nNumArgs; PWSTR *ppArgv=CommandLineToArgvW( GetCommandLineW(), &nNumArgs); // 處理 if( *pArgv[1] == L’x’) … HeapFree( GetProcessHeap(), 0, ppArgv);
Parsing ArgumentsParsing Arguments
MessageBox(NULL,ppArgv[1],L"test",MB_OK);MessageBox(NULL,ppArgv[1],L"test",MB_OK);
字串
範例程式 : 剖析你的 commandline範例程式 : 剖析你的 commandline
always NULL
新增圖片說明
IDE 設定 command 參數
自動將 參數解析出來
環境變數 環境變數 A Process’s Environment A Process’s Environment
VariableVariable Every Process has an environment Every Process has an environment
block associated with itblock associated with it
codecode
JAVA_HOME=C:\j2sdk1.4.1_01\0Name1=Value2\0Name2=Value3\0\0
JAVA_HOME=C:\j2sdk1.4.1_01\0Name1=Value2\0Name2=Value3\0\0
virtual space
Note: 1. ‘=‘ cannot be part of the name 2. XYZ= Windows
ABC =Home空白也算數空白也算數
以 \0 結尾以 \0 結尾
變數名稱變數名稱 值值
最後結束最後結束
設定環境變數初值設定環境變數初值Create an initial set of Create an initial set of environment variableenvironment variable
Windows 98Windows 98 Autoexec.batAutoexec.bat
SET VarName=VarValueSET VarName=VarValue
Windows 2000Windows 2000
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
HKEY_CURRENT_USER\EnvironmentHKEY_CURRENT_USER\Environment
System 的設定System 的設定
目前 User 的設定目前 User 的設定
JAVA_HOME=C:\j2sdk1.4.1_01\0Name1=Value2\0Name2=Value3\0\0
JAVA_HOME=C:\j2sdk1.4.1_01\0Name1=Value2\0Name2=Value3\0\0
Environment blockEnvironment block
使用 Registry使用 Registry
Regedit.exeRegedit.exe
讀取環境變數的值讀取環境變數的值Determine the value of an Determine the value of an
environment valueenvironment valueDWORD GetEnvironmentVariable (PCTSTR pszName, PTSTR pszValue, DWORD cchValue);
NameName
ValueValue
Ex:
#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;
}
#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, _Tfor TCHAR, _T
配置 TCHAR 字元陣列當字串傳回儲存空間配置 TCHAR 字元陣列當字串傳回儲存空間
查詢 環境變數 Java_Home 的內容查詢 環境變數 Java_Home 的內容
注意 : 要夠大 , 否則不會放進來注意 : 要夠大 , 否則不會放進來
範例 : 讀取環境變數的值
空間大小空間大小
You can modify, delete, add You can modify, delete, add the variable from the the variable from the environment blockenvironment block
BOOL SetEnvironmentVariable (PCTSTR pszName, PTSTR pszValue);
#include <windows.h> #include <tchar.h>
int APIENTRY WinMain(…){ TCHAR pszValue[100]; SetEnvironmentVariable(_T("MyProjectDir"), _T("c:\\test")); MessageBox(NULL, pszValue, _T(“Set Environment Value), MB_OK);return 0;
}
#include <windows.h> #include <tchar.h>
int APIENTRY WinMain(…){ TCHAR pszValue[100]; SetEnvironmentVariable(_T("MyProjectDir"), _T("c:\\test")); MessageBox(NULL, pszValue, _T(“Set Environment Value), MB_OK);return 0;
}
SetEnvironmentVariable(_T(“MyProjectDir“ ), _T(“c:\\test”));設定環境變數 MyProjectDir=c:\test設定環境變數 MyProjectDir=c:\test
SetEnvironmentVariable(_T(“MyProjectDir“ ), NULL);刪除環境變數 MyProjectDir刪除環境變數 MyProjectDir
程式 Demo: 環境變數刪除新增範例注意 : SetEnvironmentVariable 只為反映在目前的 process 的設定上 , 不會影響其他的 process注意 : SetEnvironmentVariable 只為反映在目前的 process 的設定上 , 不會影響其他的 process
更改 更改 Registry Registry 上的變數值上的變數值 Step 1: Step 1: Open the Key Open the Key
KEY_CURRENT_USER Environment (Sub Key)
Step 2: Set the value
HKEY hKey; LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_ALL_ACCESS, &hKey );
HKEY hKey; LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_ALL_ACCESS, &hKey );
Opened keyOpened key 要修改的 Sub key要修改的 Sub key
must be 0must be 0Access maskAccess mask Handle to the opened
key
Handle to the openedkey
Succeeds
ERROR_SUCCESS
Succeeds
ERROR_SUCCESS
LPCTSTR pszValue=_T("d:\\test"); lRet=RegSetValueEx(hKey,_T("TestDir"), 0,REG_SZ, (const BYTE*)pszValue, lstrlen(pszValue)*sizeof(TCHAR));
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 ModeA Process’s Error Mode -- -- 自己接手處理嚴重錯誤自己接手處理嚴重錯誤 Tell the system Tell the system how the process how the process
should respondshould respond to serious errors to serious errors Disk media failures, unhandled Disk media failures, unhandled
exception, file-find failures, and data exception, file-find failures, and data misalignmentmisalignment
FlagFlag DescriptionDescription
SEM_FAILSEM_FAILCRITICALCRITICALERRORERRORS S
要求不要產生 要求不要產生 critical-critical-error-handlererror-handler message message boxbox
SEM_NOSEM_NOGPFAULTGPFAULTERRORBERRORBOX OX
不要產生不要產生 general-general-protection-faultprotection-fault message boxmessage box
SEM_NOSEM_NOOPENFILEOPENFILEERRORERRORBOX BOX
當系統找不到檔案時當系統找不到檔案時 ,, 不要秀不要秀出錯誤訊息出錯誤訊息
SEM_NOSEM_NOALIGNMENTALIGNMENTFAULFAULTEXCEPT TEXCEPT
要求系統自動修正 要求系統自動修正 memory memory alignment falutsalignment faluts
不要秀出 不要秀出 general-protection-general-protection-faultfault
補充
請直接執行 exe 檔 ( 不要在 IDE 中執行 )
自己處理 錯誤自己處理 錯誤
判斷 判斷 A 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;}
#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
設定發生問題時 , 系統不要秀出 message box
嘗試的讀取 A 槽的資料嘗試的讀取 A 槽的資料
若沒有 error 發生時 , GetLastError 會傳回 -1 我們藉此判斷是否正常
若沒有 error 發生時 , GetLastError 會傳回 -1 我們藉此判斷是否正常
設定回原來的設定設定回原來的設定
程式 Demo:: 判斷 a 槽是否 ready 範例
設定與取得預設路徑設定與取得預設路徑 ::Obtain and set the current drive Obtain and set the current drive
and directoryand directoryDWORD GetCurrentDirectory( DWORD nBufferLength, // size, in characters, of directory buffer LPTSTR lpBuffer // pointer to buffer for current directory);
DWORD GetCurrentDirectory( DWORD nBufferLength, // size, in characters, of directory buffer LPTSTR lpBuffer // pointer to buffer for current directory);
#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;
}
#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: 讀取預設路徑範例
BOOL SetCurrentDirectory( LPCTSTR lpPathName); 會反映到目前 Process 中所有的 threads
BOOL SetCurrentDirectory( LPCTSTR lpPathName); 會反映到目前 Process 中所有的 threads
有多少個字元被讀取有多少個字元被讀取 取得目前目錄的字串 取得目前目錄的字串
Handling current directories Handling current directories for multiple drives -- for multiple drives -- 更改其他槽更改其他槽的預設路徑的預設路徑
1. 1. 先看 先看 Current DirectoryCurrent Directory 2. If your current directory = C:\, then the 2. If your current directory = C:\, then the
system looks up system looks up 環境 變數 環境 變數 ““ =D:”=D:” 3. If “D:” did not exist 3. If “D:” did not exist open from the root of D open from the root of D
drivedrive
hFile = CreateFile(_T("D:myfile.txt"), …) hFile = CreateFile(_T("D:myfile.txt"), …) D:myfile.txtD:myfile.txt
Where to open the myfile.txt
file ?
Problem
磁碟機 D 的目前目錄 例如 : =D:=D:\Program Files 磁碟機 D 的目前目錄 例如 : =D:=D:\Program Files
You can use _chdir instead the SetCurrentDirect
ory()!
隨著 _chdir 的設定 , 會新增修改每個磁碟機的 Default Directory 的環境變數
_chdir 的好處是
_chdir _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");}
列出目前目錄下 , 的所有 exe 檔列出目前目錄下 , 的所有 exe 檔
如果 _chdir(“c:\\”); 則會設定目前目錄為 c:\\並且列出 c:\\ 下所有的 exe 檔
如果 _chdir(“c:\\”); 則會設定目前目錄為 c:\\並且列出 c:\\ 下所有的 exe 檔
Example: Example: 設定 設定 D D 槽的 槽的 Default Default
DirectoryDirectory#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;
}
#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;
}
目前更改了 D 槽的預設路徑目前更改了 D 槽的預設路徑程式 Demo: 更改其他槽的預設路徑範例
The child process The child process does not inherit does not inherit the parent process’s current the parent process’s current directoriesdirectories Root of every drive (default)Root of every drive (default)
You must create the You must create the drive-letter drive-letter environment variableenvironment variable
=C:=C:\Utility\Bin=D:=D:\Program Files
=C:=C:\Utility\Bin=D:=D:\Program Files
Environment block
=C:=C:\Utility\Bin=D:=D:\Program Files
=C:=C:\Utility\Bin=D:=D:\Program Files
Child A’s environment block
=C:=C:\Utility\Bin=D:=D:\Program Files
=C:=C:\Utility\Bin=D:=D:\Program Files
TCHAR szCurDir[MAX_PATH];DWORD GetFullPathName(_T(“C:”), MAX_PATH, szCurDir, NULL);
TCHAR szCurDir[MAX_PATH];DWORD GetFullPathName(_T(“C:”), MAX_PATH, szCurDir, NULL);
放進指定的檔名 ,傳回 完整的路徑名稱
先建立 Driver-Letter 環境變數先建立 Driver-Letter 環境變數
Child 會繼承 parent的環境變數 , 使得各個Device Default Directory會被複製
Child 會繼承 parent的環境變數 , 使得各個Device Default Directory會被複製
傳回目前 C 槽的Current Directory
傳回目前 C 槽的Current Directory
檔案名稱檔案名稱 Buffer 大小Buffer 大小 Buffer 位置Buffer 位置 Filename 所在位置Filename 所在位置
C 的預設目錄為 c:\Utility\Bin C 的預設目錄為 c:\Utility\Bin
* Current Directory 每個 process 只有一個* Current Directory 每個 process 只有一個
Child B’s environment block
D 的預設目錄為 D:\Program Files D 的預設目錄為 D:\Program Files
How to determine the Windows How to determine the Windows versionsversions
BOOL GetVersionEx( LPOSVERSIONINFO lpVersionInformation); BOOL GetVersionEx( LPOSVERSIONINFO lpVersionInformation);
MemberMember DescriptionDescription
dwOSVersionInfoSizdwOSVersionInfoSizee
LPOSVERSIONINFO 的大小 .必須使用 sizeof(LPOSVERSIONINFOEX)EX)
dwMajorVersion, dwMajorVersion, dwMinorVersion, dwMinorVersion, dwBuildNumberdwBuildNumber
主要主要 ,, 次要版本號碼與建構號碼次要版本號碼與建構號碼4 4 95, 98 , ME, NT4.0; (Major) 5 95, 98 , ME, NT4.0; (Major) 5 2000, XP, Server 2003 2000, XP, Server 2003
0 10 90 0 (Minor) 0 1 20 10 90 0 (Minor) 0 1 2
dwPlatformId dwPlatformId VER_PLATFORM_WIN32s VER_PLATFORM_WIN32s Win32s on Windows 3.1 Win32s on Windows 3.1
VER_PLATFORM_WIN32_WINDOWS VER_PLATFORM_WIN32_WINDOWS Windows 95 /98 Windows 95 /98
VER_PLATFORM_WIN32_NT VER_PLATFORM_WIN32_NT Windows NT/ Windows NT/Windows2000Windows2000
VER_PLATFORM_WIN32_CEHH VER_PLATFORM_WIN32_CEHH Windows CE Windows CE
… … (( 其他其他 ))
wProductTypewProductType VER_NT_WORKSTATION VER_NT_WORKSTATION W2k XP Professional, XP Home W2k XP Professional, XP Home EditionEdition
VER_NT_DOMAIN_CONTROLLERVER_NT_DOMAIN_CONTROLLER
VER_NT_SERVER VER_NT_SERVER Server Server
Example: Example: 判斷是否為判斷是否為Win2000Win2000
#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;
}
#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 作業系統判斷是否為 Win2000 作業系統
程式 Demo: 判斷是否為 Win2000 範例
Create the Process:Create the Process: Process Process 建立流程建立流程
Create a Process kernel object
Create a Process kernel objectA thread call CreateProcess 1
管理 Process 的資料結構管理 Process 的資料結構
Create a Virtual address space
Create a Virtual address space
Load the Code ,Data and DLL
Load the Code ,Data and DLL
main{}
Create a Thread kernel object
Create a Thread kernel object1
管理 Thread 的資料結構管理 Thread 的資料結構
建立 primary thread建立 primary thread
main{}
執行 C/C++ run-timeStartup code
執行 C/C++ run-timeStartup code
Create the Process:Create the Process: The CreateProcess The CreateProcess function 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);
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 / thread 是否可以被其他 child 繼承
TRUE: 則每個可以被繼承的 Kernel Object 都會被新建立的 process 繼承
TRUE: 則每個可以被繼承的 Kernel Object 都會被新建立的 process 繼承
設定 process 的建立方式 : 1. 是否擁有 console 2. 優先權類別設定
設定 process 的建立方式 : 1. 是否擁有 console 2. 優先權類別設定
指向環境變數區塊的位址 , NULL 使用 parent 的environment.
指向環境變數區塊的位址 , NULL 使用 parent 的environment.
字串 , 指定新建立 process 的目前目錄 .
字串 , 指定新建立 process 的目前目錄 .
一個 STARTUPINFO 結構 : 紀錄 window 位置 , 大小 console 寬度字元數 , 高度字元數 標準輸入輸出與標準錯誤的 handle
一個 STARTUPINFO 結構 : 紀錄 window 位置 , 大小 console 寬度字元數 , 高度字元數 標準輸入輸出與標準錯誤的 handle
一個 PROCESS_INFORMATION 結構 : 紀錄新建立的 Process Handle 與 PID primary thread Handle 與 hID
一個 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 );}
範例程式範例程式
等待新建出來的 process terminated( 試著把這行拿掉看看 )
等待新建出來的 process terminated( 試著把這行拿掉看看 )
將 reference 到 process 與 thread 的 Handle close 起來
將 reference 到 process 與 thread 的 Handle close 起來
配置 STARTUPINFO 與PROCESS_INFOMATION 給新建的 process 使用
配置 STARTUPINFO 與PROCESS_INFOMATION 給新建的 process 使用
設定初值設定初值
建立新的 process 主要程式碼建立新的 process 主要程式碼
Terminating a ProcessTerminating a Process Primary thread’s Primary thread’s entry-point function returnsentry-point function returns
WinMain, main, wWinMain and wmainWinMain, main, wWinMain and wmain The thread’s The thread’s resourcesresources will be cleaned up will be cleaned up
properlyproperly C++C++ object will be destroyed properly object will be destroyed properly The The memorymemory used in the thread’s stack will free used in the thread’s stack will free Process’s Process’s exit codeexit code will return will return Process kernel object Process kernel object usage counterusage counter - 1 - 1
ExitProcess()ExitProcess() TerminateProcess()TerminateProcess()
All the threads in the process dieAll the threads in the process die
強烈建議使用強烈建議使用
下列四種情況下 , 會 Terminating 一個 proces下列四種情況下 , 會 Terminating 一個 proces
可以強迫其他 process終止 ( 不會通知 DLL 對應的 detaching function) Process 可能沒有機會 update 狀態資料到 disk 中
可以強迫其他 process終止 ( 不會通知 DLL 對應的 detaching function) Process 可能沒有機會 update 狀態資料到 disk 中
強迫自己終止 ( 會通知 DLL ) C++ 解構子不會被呼叫強迫自己終止 ( 會通知 DLL ) C++ 解構子不會被呼叫
由 main 或 WinMain離開 , 系統幫你做的事情由 main 或 WinMain離開 , 系統幫你做的事情
ExitProcess() functionExitProcess() function
Any thread that call Any thread that call ExitProcess()ExitProcess() will terminates the processwill terminates the process
All All system resourcesystem resource will be cleaned will be cleaned up perfectlyup perfectly
C/C++ run time policyC/C++ run time policy
VOID ExitProcess(UINT fuExitCode);VOID ExitProcess(UINT fuExitCode);
int APIENTRY WinMain(…){ … return 0;}
int APIENTRY WinMain(…){ … return 0;}
進入 C/C++ run-timeStartup code
進入 C/C++ run-timeStartup code
call ExitProcess(0)call ExitProcess(0)
Any threads running in the process terminate
這裡指的是那些 Handle (Event,File,Process…)這裡指的是那些 Handle (Event,File,Process…)
0 表示正常結束0 表示正常結束
C/C++ C/C++ 程式應該避免呼叫 程式應該避免呼叫 ExitProcess()ExitProcess()
System resource will be cleaned but System resource will be cleaned but the C++ objects are not.the C++ objects are not.
#include <windows.h>
#include <iostream>using namespace std;
CSomeObj g_GlobalObj; // 宣告全區域變數void main(){
CSomeObj LocalObj;ExitProcess(0);
}
#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;}};
class CSomeObj{ public: CSomeObj(){ cout<<" 建構子 " << endl;} ~CSomeObj(){ cout<<" 解構子 "<< endl;}};
執行結果執行結果
建構子建構子
建構子建構子直接呼叫的結果直接呼叫的結果
C++ 物件沒有被解構C++ 物件沒有被解構
程式範例 : 避免呼叫 ExitProcess
導致系統狀態無法更新 有可能的情況是在物件的解構子中 , 針對目標資料庫做結束的動作 , 因為你呼叫了 ExitProcess() 而導致資料庫資訊不正確
TerminateProcess TerminateProcess function()function()
You can terminate You can terminate another processanother process
BOOL TerminateProcess(HANDLE hProcess,UINT fuExitCode);BOOL TerminateProcess(HANDLE hProcess,UINT fuExitCode);
TerminateProcess(…)TerminateProcess(…)
Process A Process B
根本沒有通知 ,來不及存檔
terminate
OS 會接手把會接手把
ProcessB 的所有資源全部釋
放
列出所有目前正在執行列出所有目前正在執行 Processes NameProcesses 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;
}
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)1. 取得目前系統中正在執行 Processes 的快照 (snapshot)
2. 取出第一個正在執行的 Process2. 取出第一個正在執行的 Process
3. 印出相關 Process 的名稱3. 印出相關 Process 的名稱
#include <windows.h>#include <stdio.h>#include <tlhelp32.h>void main(){ GetProcessList();}
#include <windows.h>#include <stdio.h>#include <tlhelp32.h>void main(){ GetProcessList();}
C/C++ startup
ignoredignored
程式範例 : 列出目前系統正在執行的 Process參考資料 : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/taking_a_snapshot_and_viewing_processes.asp
列出的是 process列出的是 process
Terminate Terminate 所有目前正在執行的 所有目前正在執行的 NotepadNotepad
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;
}
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);}
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取得 notepad.exe process 的 Handle
Terminate notepad processesTerminate notepad processes
程式範例 :TerminateProcess
這個傳回來的 Handle 不需要繼承屬性
這個傳回來的 Handle 不需要繼承屬性
When a Process TerminatesWhen a Process Terminates當當 ProcessProcess 被終結時被終結時 ,, 系統的動作系統的動作
流程流程Terminate any
remaining thread
Terminate any remaining thread
All User & GDI objectsare freed
All User & GDI objectsare freed
All Kernel objectsare closed
All Kernel objectsare closed
若沒有任何 Process 擁有它 ,則這個 Kernel object 將會被destory
若沒有任何 Process 擁有它 ,則這個 Kernel object 將會被destory
Exit codeSTILL_ACTIVE
Exit codeSTILL_ACTIVE VOID ExitProcess(UINT fuExitCode);VOID ExitProcess(UINT fuExitCode);
釋放如 menu, icon 等資源釋放如 menu, icon 等資源
Signaled the Process kernel object
Signaled the Process kernel object
-1
系統狀態會由 STILL_ACTIVE 改成 fuExitCode
系統狀態會由 STILL_ACTIVE 改成 fuExitCode
Obtain the process’s exit Obtain the process’s exit codecode
BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);
Get the process’s handleGet the process’s handle
WaitForSingleObjectWaitForSingleObject
GetExitCodeProcessGetExitCodeProcess
等待該 process terminate等待該 process terminate
You can call this function at any time
若目標 process 沒有 exit 則 1. pdwExitcode
STILL_ACTIVE
(0x103)
回傳的資料
會傳回目標 process 的 kernel objectExitCode
Appendix (Appendix ( 補充補充 ))
__cdecl V.S. __stdcall__cdecl V.S. __stdcall __cdecl: __cdecl: defaultdefault calling converting for C/C++ calling converting for C/C++
The stack is cleaned up by the The stack is cleaned up by the callercaller. . (( 可處理不定變數可處理不定變數 ))
__stdcall: is used to call __stdcall: is used to call Win32 APIWin32 API The The calleecallee clean the stack. clean the stack. (( 故不定變數 故不定變數 function function 由 由 __cdecl __cdecl
處理處理 ))
ElementElement Startup FunctionStartup Function
Argument-passing Argument-passing orderorder
Right to LeftRight to Left
Stack-maintenance Stack-maintenance responsibilityresponsibility
Calling functionCalling function pop the pop the arguments from the arguments from the stackstack
ElementElement Startup FunctionStartup Function
Argument-passing Argument-passing orderorder
Right to LeftRight to Left
Stack-maintenance Stack-maintenance responsibilityresponsibility
Called functionCalled function pop its pop its own argument from the own argument from the stackstack
Microsoft Specific Microsoft Specific
參考資料 : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_6.asp
被呼叫的 function被呼叫的 function
因為只有 caller 才知道 push 了多少參數給 callee function
因為只有 caller 才知道 push 了多少參數給 callee function
__fastcall__fastcall
__fastcall:__fastcall: arguments to functions are to be arguments to functions are to be
passed in passed in registersregisters, when , when possiblepossible..
ElementElement Startup FunctionStartup Function
Argument-passing Argument-passing orderorder ECX & EDXECX & EDX 前兩個 前兩個 DWORD DWORD 或較小的或較小的 argumentargument
剩下的剩下的 are passed right to leftare passed right to left
Stack-maintenance Stack-maintenance responsibilityresponsibility
Called functionCalled function pop the pop the arguments from the stackarguments from the stack
參考資料 : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_core___fastcall.asp
EndEnd