1. 程式人生 > >windows核心程式設計之程序

windows核心程式設計之程序

什麼是程序?

程序是一個正在執行程式的例項。由兩部分組成:一個核心物件,用於管理程序以及一個地址空間,包含所有可執行檔案或DLL模組的程式碼和資料,此外還包含動態記憶體分配。


在分析程序之前,先看下windows程式是如何建立的?

Windows應用程式分為CUI和GUI程式,即控制檯使用者介面和圖形使用者介面。

不同的應用程式連結器開關不同,/SUBSYSTEM:CONSOLE和/SUBSYSTEM:WINDOWS分別代表不同應用程式的連結器開關。

不同的應用程式必須有一個入口點函式,開始執行的時候,該函式被呼叫。為此,VC的“系統-子系統”值刪除掉,即不指定控制檯或

GUI,則編譯器會根據程式碼中存在main或者WinMain來自動選擇子系統(這裡不談Unicode了),很方便!

啟動程式:

根據子系統執行mainCRTStartup/WinMainCRTStartup,在該函式中幹幾件事(1)準備命令列和環境變數(用於char *argv[]char *env[])(2)初始化CRT的全域性變數(包括_osver_winmajor_winver__argc_environ等)(3)初始化CRT執行庫的記憶體分配(mallocfree)、IO函式等(4)初始化全域性物件呼叫C++建構函式。


退出程式:

main返回後mainCRTStartup

會呼叫exitexit幹以下幾件事:(1)執行通過_onexit註冊的函式(2)執行全域性物件的C++解構函式(通過atexit註冊的)(3)判斷_CrtDumpMemoryLeaks設定的記憶體洩漏檢測標誌,嘗試檢測記憶體洩漏(4)呼叫ExitProcess


Windows應用程式如何使用例項控制代碼呢?

可執行檔案的例項被當做(w)WinMain函式的一個引數hInstanceExe傳入。有時需要HINSTANCE,有時候需要HMODULE型別。通過GetModuleFileName獲取該型別控制代碼。HINSTANCE是指可執行檔案的映像檔案載入到記憶體後的基址(連結器中可以配置)。可以通過GetModuleHandle函式返回一個控制代碼或者基地址。傳入

NULL可以得到執行檔案的HINSTANCE(即使呼叫者位於某個模組中同樣返回應用程式基址)。


程序的環境變數

 訪問環境變數:char *env[]引數、GetEnvironmentStringsGetEnvironmentVariableExpandEnvironmentStrings(將一個使用了類似”%USERPROFILE%”環境變數的字串中的變數替換成值)。系統環境變數:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Enviroment。使用者環境變數:HKEY_CURRENT_USER\Enviroment修改環境變數後可以通知相關的系統視窗(如控制面板等):SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) “Enviroment”)

程序的驅動器和目錄

如果不提供完整路徑,windows函式會在當前驅動器的當前目錄查詢檔案和目錄。

更改和獲取當前目錄的方式為如下函式GetCurrentDirectory和SetCurrentDirectory。程序的當前目錄的設定,如一個程序的環境變數如下

=C:=C:\Uility\Bin

=D:=D:\Program Files

為此C驅動器的當前目錄為\Uility\Bin ,D盤驅動器的當前目錄為\Program Files 可以用C函式_chdir函式可以設定環境變數。

GetVersionEx獲取系統版本資訊。

VerifyVersionInfo檢測當前系統是否滿足版本需要

如何建立一個程序呢?CreateProcess函式

當一個執行緒呼叫該函式時,就會建立一個核心物件並初始使用計數為1,用於管理程序,然後系統為程序建立一個虛擬地址空間。主執行緒核心物件和程序的核心物件一樣。主執行緒會執行windows程式的啟動函式,並呼叫入口函式。該函式的引數介紹如下:

CreateProcess的引數:關於lpApplicationNamelpCommandLine,有兩種用法:(1前者指定應用程式路徑,後者指定引數(第一個引數前面要有一個空格,似乎底層會直接連線兩個串)(2)前者為NULL,後者指定路徑和引數,空格隔開。常用第二種方法。注意,lpCommandLine中由於是用空格分隔引數的,所以對其中含有空格的路徑一定要用內層引號括起來。另外CreateProcessW有一個奇怪的行為,它會修改引數lpCommandLine(似乎只在lpApplicationName為空的時候會修改),所以使用Unicode版本的時候傳入的該引數不能是常字串(如L”Nodepad 1.txt”),而應該另外準備緩衝傳給該API供其修改,因為ANSI版本是呼叫Unicode版本的且在編碼轉換的時候內建了緩衝,所以CreateProcessAlpCommandLine引數可以是常串(最終API會修改轉換編碼的臨時緩衝)。預設情況下,CUICUI型子程序會和父程序共享控制檯,在引數dwCreationFlags中新增DETACHED_PROCESSCREATE_NEW_CONSOLE標誌可以阻止這種行為。在dwCreationFlags中新增CREATE_NEW_PROCESS_GROUP標誌,可以控制程序組的組織,使用者按下Ctrl+C的時候同一程序組的所有程序得到通知。lpEnvironment指定為NULL的時候,底層為用GetEnvironmentStrings來填充。lpCurrentDirectoryNULL的時候,子程序繼承父程序的當前目錄。lpStartupInfo不能為空,至少要初始化結構為0並將cb賦為sizeof。使用STARTUPINFOEX結構作為lpStartupInfo引數,還可以具體指定子程序要繼承哪些父程序的可繼承核心物件(即使bInheritHandles引數為FALSE)。

Windows建立子程序的目的?

1.與父程序地址隔離;2.可以同時處理不同的程式碼;

程序之間如何共享資料呢?

動態資料交換DDE,OLE,管道,郵件槽,其中匿名管道使用過,用來執行.bat指令碼去抓取手機產品的資料。共享資料最方便的方式是記憶體對映檔案。

記憶體對映檔案解析:

與虛擬記憶體相比,記憶體對映檔案允許開發人員預定一塊地址空間區域並給球調撥物理儲存器。記憶體對映檔案的物理儲存器來自於磁碟上已有的檔案。記憶體對映主要用於以下三種情況:

• 系統使用記憶體對映檔案,以便載入和執行. exe和DLL檔案。這可以大大節省頁檔案空間和應用程式啟動執行所需的時間。

• 可以使用記憶體對映檔案來訪問磁碟上的資料檔案。這使你可以不必對檔案執行I/O操作,並且可以不必對檔案內容進行快取。

• 可以使用記憶體對映檔案,使同一臺計算機上執行的多個程序能夠相互之間共享資料。Windows確實提供了其他一些方法,以便在程序之間進行資料通訊,但是這些方法都是使用記憶體對映檔案來實現的,這使得記憶體對映檔案成為單個計算機上的多個程序互相進行通訊的最有效的方法。

首先分析一下作業系統記憶體原理:這篇文章講述非常好:http://blog.csdn.net/do2jiang/article/details/4690967

分析程序的資料共享方法1,即在同一個可執行檔案或DLL的多個例項間共享靜態資料。

每個.exe檔案或DLL檔案對映由許多段組成。每個標準的段名都以點號開始。

編譯程式的時候,編譯器會將程式碼放在一個名叫.text的段中。比外,未經過初始化的資料放在.bss段中,將已經初始化的資料放在.data段中。

除了標準段以外,編譯的時候使用編譯器指示符來建立自己的段。舉例:

#pragma data_seg("Shared")

LONG g_lInstanceCount = 0;

#pragma data_seg()

/SECTION:Shared, RWS


存對映檔案在程序中共享資料的例子:

http://www.cnblogs.com/fangyukuan/archive/2010/09/09/1822310.html