閱讀33 返回首頁    go 阿裏雲 go 技術社區[雲棲]


核心編程隨筆2

Note 1:
以前版本的Windows設計的一些應用程序之所以在Windows Vista上不能正常工作,就是因為在實現這些程序時,沒有充分考慮安全性.假定一個應用程序在啟動時要從一個注冊表子項中讀取一些數據.正確的做法是調用RegOpenKeyEx,向其傳入KEY_QUERY_VALUE,從而指定查詢子項數據的權限.然而許多應用程序對安全性沒有任何考慮.有的軟件開發人員還是按照老習慣,在調用RegOpenKeyEx函數的時候,傳入KEY_ALL_ACCESS作為期望的訪問權限.這樣做的問題在於,對於一個不是管理員的標準用戶,注冊表項(比如HKLM)也許是隻讀的.所以,當這樣的應用程序在Windows Vista上麵運行時,調用RegOpenKeyEx函數並傳遞KEY_ALL_ACCESS就會失敗.

Note 2:
不同進程中運行的線程需要共享內核對象.下麵羅列了一些理由.

利用文件映射對象,可以在同一台機器上運行的兩個不同進程之間共享數據塊.
借助mailslots和named pipes,在網絡中的不同計算機上運行的進程可以相互發送數據塊.
mutexes、semaphores和事件允許不同進程中的線程同步執行.例如,一個應用程序可能需要在完成某個任務之後,向另一個應用程序發出通知.
用三種不同的機製來允許進程共享內核對象:使用對象句柄繼承,為對象命名,以及複製對象句柄;

Note 3:
如果你寫的一個服務要同這些應用程序通信,就不能假定它和用戶應用程序在同一個會話中運行.要想更多地了解Session0隔離問題,及其對服務開發人員的影響,請閱讀"Impact of Session 0 Isolation on Services and Drivers in Windows Vista"一文,網址是https://www.microsoft.com/whdc/system/vista/services.mspx.

Note 4:

複製對象句柄的函數:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);
(hyp:這個一個可以用來做很多邪惡事情的函數,比如你可以打開一個文件然後把句柄複製到係統進程裏麵,這樣子文件就刪不掉了)

Note 5;
一般將進程定義成一個正在運行的程序的一個實例,它由以下兩個組件構成:
             一個內核對象,操作係統用它來管理進程.內核對象也是係統保存進程統計信息的地方.
             一個地址空間,其中包含所有執行體(executable)或DLL模塊的代碼和數據.此外,它還包含動態內存分配,比如線程堆棧和堆的分配.

Note 6:
進程要做任何事情,都必須讓一個線程在它的上下文中運行.該線程要執行進程地址空間包含的代碼.一個進程可以有多個線程,所有線程都在進程的地址空間中"同時"執行代碼.因此每個線程都有它自己的一組CPU寄存器和它自己的堆棧.每個進程至少要有一個線程執行進程地址空間包含的代碼.一個進程創建的時候,係統會自動創建它的第一個線程,這稱為主線程(primary thread).然後這個線程再創建更多的線程,如果沒有線程要執行進程地址空間包含的代碼,進程就失去了繼續存在的理由.所以,係統會自動銷毀進程及其地址空間.(hyp:所以結束一個進程的所有線程將會導致進程被結束)

Note 7:
如果你的代碼在一個DLL中,那麼可利用兩個辦法來了解代碼正在什麼模塊中運行:
第一個辦法是利用鏈接器提供的偽變量__ImageBase,它指向當前正在運行的模塊的基地址.
第二個辦法是調用GetModuleHandleEx,將GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS作為它的第一個參數,將當前方法的地址作為第二個參數.最後一個參數是指向一個HMODULE的指針,該指針將由GetModuleHandleEx來填充,它就是包含了傳入函數的那個DLL的基地址.
以下代碼對這兩個辦法都進行了演示:
extern "C" const IMAGE_DOS_HEADER __ImageBase;
void DumpModule() {
// Get the base address of the running application.
// Can be different from the running module if this code is in a DLL.
HMODULE hModule = GetModuleHandle(NULL);
_tprintf(TEXT("with GetModuleHandle(NULL) = 0x%x\r\n"), hModule);
// Use the pseudo-variable __ImageBase to get
// the address of the current module hModule/hInstance.
_tprintf(TEXT("with __ImageBase = 0x%x\r\n"), (HINSTANCE)&__ImageBase);
// Pass the address of the current method DumpModule
// as parameter to GetModuleHandleEx to get the address
// of the current module hModule/hInstance.
hModule = NULL;
GetModuleHandleEx(
   GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
   (PCTSTR)DumpModule,
   &hModule);
_tprintf(TEXT("with GetModuleHandleEx = 0x%x\r\n"), hModule);
}
int _tmain(int argc, TCHAR* argv[]) {
DumpModule();
return(0);
}
Note 8:
調用GetCommandLine函數可以獲得一個指向進程完整命令行的指針.
應用程序可以使用全局變量__argc和__argv(或__wargv)來訪問對命令行的各個單獨的組件,不過這些變量現在已經不提倡使用了.
利用在ShellAPI.h文件中聲明並由Shell32.dll導出的函數CommandLineToArgvW可以將任何Unicode字符串分解成單獨的標記:
PWSTR* CommandLineToArgvW(
PWSTR pszCmdLine,
int* pNumArgs);
CommandLineToArgvW在內部分配內存.許多應用程序不會釋放這個內存——它們指望操作係統在進程終止時釋放內存.這是完全可以接受的.不過,如果你想自己釋放內存,正確的做法就是像下麵這樣調用HeapFree:
int nNumArgs;
PWSTR *ppArgv = CommandLineToArgvW(GetCommandLineW(), &nNumArgs);
// Use the arguments…
if (*ppArgv[1] == L'x') {
...
}
// Free the memory block
HeapFree(GetProcessHeap(), 0, ppArgv);
Note 9:
每個進程都有一個與它關聯的環境塊(environment block).這是在進程地址空間內分配的一個內存塊.其中包含和下麵相似的一組字符串:
=::=::\ ...
VarName1=VarValue1\0
VarName2=VarValue2\0
VarName3=VarValue3\0 ...
VarNameX=VarValueX\0
\0
每個字符串的第一部分是一個環境變量的名稱,後跟一個等號,等號之後是希望賦給此變量的值.
注意,除了第一個=::=::\字符串,塊中可能還有其他字符串是以等號(=)開頭的.

最後更新:2017-04-03 15:22:09

  上一篇:go qsort
  下一篇:go 網絡子係統9_ip校驗和計算