第4章 程序 I

2021-06-27 20:10:51 字數 3178 閱讀 1719

4.1.1 程序例項控制代碼

載入到程序位址空間的每乙個可執行檔案或者dll檔案都被賦予了乙個獨一無二的例項控制代碼。可執行檔案的例項被昂做(w)winmain函式的第乙個引數hinstanceexe傳入。在需要載入資源的函式呼叫中,一般都要提供此控制代碼的值。例如,為了從可執行檔案的映像中能夠載入乙個圖示資源,就需要呼叫下面的函式:

hicon loadicon(hinstance hinstance, pctstr pszicon);

此函式的第乙個引數指出哪個檔案包含了需要載入的資源。許多應用程式都會將(w)winmain的hinstance引數儲存在乙個全域性變數中,是其很容易被可執行檔案的所有**訪問。

platfrom sdk文件指出,有的函式需要乙個hmodule型別的引數。下面的getmodulefilename函式就是乙個例子:

dword getmodulefilename(

hmoudle hinstance,

ptstr pszpath,

dword cchpath)

說明,事實上,hmoudle和hinstance完全是一回事。

可執行檔案的映像具體載入到哪乙個基位址,是由聯結器決定的。不同的聯結器使用不同的預設基位址。由於歷史原因,visual studio鏈結器使用的預設基位址是0x004000000,這是在執行windows 98時,可執行檔案的映像能載入到的最低的乙個位址。使用microsoft鏈結器的/base:address鏈結器開關,可以更改在將應用程式載入到哪個基位址。

hmodule getmoudlehandle(pctstr pszmodule);

呼叫這個函式時,要傳遞乙個以0為終止符的字串,他指定了已在主調程序的位址空間中載入的乙個可執行檔案或者dll檔案的名稱。如果系統找到了指定的可執行檔案或者dll檔案名字,getmoudlehandle就會返回可執行檔案/dll檔案映像載入到的基位址。如果沒找到,系統將會返回null.另乙個用法是pszmoudle引數傳入null,這樣可以返回主調程序的可執行檔案的基位址。如果我們的**在乙個dll中,那麼可以利用兩種方法來了解**證在什麼模組中執行。第乙個方法就是利用鏈結器提供的偽變數_imagebase, 他指向當前正在執行的模組的基位址。如前所述,這個c執行庫啟動**在動用我們的(w)winmain函式時所做的事情。第二個方法就是嗲用getmoudlehandleex,將get_moudle_handle_ex_flag_from_address作為他的第乙個引數,將當前函式的位址作為第二個引數。最後乙個引數是乙個指向hmoudle的指標,getmoudlehnadleex會用傳入函式所在dll的基位址來填寫該指標。

記住getmoudlehandle函式的兩大重要特徵。首先,它只檢查主調程序的位址空間。如果主調程序沒有任何通用對話方塊函式,那麼一旦呼叫getmoudlehandle,並iang其傳遞comdlg32,就會導致返回null--即使它也許已經被載入到其他程序的位址空間。其次,呼叫getmodulehandle並向其傳遞null值,會返回程序位址空間中的可執行檔案的基位址。所以,即使呼叫getmoudlehandle(null)的**是乙個在dll檔案中,返回值仍是可執行檔案的基位址,而非dll檔案的基位址。

4.1.2 程序前乙個例項的控制代碼

如前所述,c/c++執行庫啟動**總是向(w)winmain的hprevinstane引數傳遞null,該引數用於16位windows系統,因而仍然將其保留為(w)winmain的乙個引數,目的只是方便我們移植16位的windows應用程式。絕對不要在自己的**中引用這個引數。

4.1.3 程序的命令列

系統在建立乙個新程序時,會傳乙個命令列給他。這個命令列幾乎中總是非空的: 至少,用於建立新程序的可執行檔案的名稱是命令列上的第乙個標記token。不過,在後面討論createprocess函式時候,我們會知道程序能接收只由乙個字元構成的命令列,即用於終止字串的0.c執行庫的啟動**開始執行乙個gui應用程式是,會呼叫windows函式getcommandline來獲取程序的完整命令列,忽略可執行檔案的名稱,然後將指向命令列甚於部分的乙個指標傳給winmain的pszcmdline引數。

應用程式可以通過自己選擇的任何一種方式來解析和解釋命令列字串。我們實際上可以寫資料到pszcmdline引數所指向的記憶體快取區,但在任何情況下,寫入快取區的時候都不應該越界。就我個人而言,我始終把他當作乙個唯讀的快取區。如果想對命令列程序改動,我首先會想命令列快取區複製到我的應用程式的乙個本地快取區,在對在即的本地快取區進行修改。

我們可以效仿c執行庫的例子,通過呼叫getcommandline函式來獲取乙個指向程序完整命令列的指標,如,ptstr getcommandline();

該函式放回乙個快取區指標,快取區中包含完整的命令列。注意,它返回的總是乙個快取區的位址。這個不應該向pszcmdline寫入資料的另乙個理由;它指向同乙個快取區,修改它之後,就沒辦法知道原來的命令列是什麼。雖然microsoft反對繼續使用全域性變數_argc和_argv,但是,應用程式仍然可以使用他們來訪問物件命令列的每個標記。利用shellapi.h檔案中宣告並由shell32.dll匯出的函式commandlinetoargvw,即可將任何unicode字串分解成單獨的標記

pwstr* commanlinetoargvw( pwstr pszcmdline, int* pnumargs)

此函式在內部分配記憶體,許多應用程式不會釋放這塊記憶體-它們依靠作業系統在程序終止時釋放。這個完全可以接受。如果要自己釋放記憶體,需要呼叫heapfree。

int nnumargs;

pwstr* ppargv = commandlinetoargvw(getcommandlinew(), &nnumargs);

// free the memory block

heapfree(getprocessheap(), 0, ppargv);

4.1.4 程序的環境變數

每個程序都有乙個與它關聯的環境塊(environment block), 這是在程序位址空間內分配的一塊記憶體。

訪問環境塊的方式。第一種呼叫getenviromentstrings函式來獲取完整的環境塊。如果不需要了,應該呼叫freeenviromentstrings函式來釋放它。第二種方式是cui專業。他用過應用程式main入口點函式所接收的tchar* env引數來實現。不同於getenviromentstrings返回的值,env是乙個字串指標陣列,每個指標都指向乙個不同的環境變數。

擴充套件環境變數字串用expandenviromentstrings函式

新增,刪除或者修改乙個變數的值,使用setenviromentvariable函式。

第4章 程序管理

第四章 程序管理 入門學習 什麼是程序?程序的生命週期?程序的狀態?程序 乙個程式執行起來就是程式 生命週期 這個程式從啟動到結束的時間 程序的狀態 程序狀態有,正在執行,暫停執行,殭屍 卡機了 這個圖大家都很熟悉吧 沒錯就是我們電腦上的 任務管理器 可以在這裡面 看到我們所開啟的程式 和系統程式 ...

第4章 程序和程式

程序是由正文段 text 資料段 data segment 和系統段 system segment 共同組成的乙個執行環境。程式是乙個儲存在硬碟上的普通檔案,裡面包含 指令和資料的集合,這寫 指令和資料儲存在磁碟上的乙個可執行映像 executale image 中。linux中每個程序都是由乙個t...

第4章程序排程(六)

4.7 實時排程策略 linux提供兩種實時排程策略 sched fifo和sched rr。普通的 非實時的排程策略是sched normal。借助排程類的框架,這些實時策略被乙個特殊的實時排程器管理。具體實現定義在kernel sched rt.c中。sched fifo是一種簡單的 先入先出的...