當你需要建立、開啟和操作各種核心對象的時候,系統要建立和操作若干類型的核心對象,強如存取符號對象、事件對象、檔案對象、檔案對應物件、I/O完成連接埠對象、工作物件、信箱對象、互斥對象、管道對象、進程對象、信標對象、線程對象和等待計時器對象等等。這些對象都是通過調用函數來建立的。例如:CreateFileMapping函數可使系統能夠建立一個檔案對應物件。
每個核心對象只是核心分配的一個記憶體塊。 並且只能由該核心訪問。該記憶體塊是一種資料結構,它的尵負責維護該對象的各種資訊。有些資料成員(如安全性描述元、使用計數器等)在所有的物件類型中都是相同的,但大多數資料成員屬於特定的物件類型。例如,進程對象有一個進程ID、一本基本優先順序和一個結束代碼,而檔案對象則擁有一個位元組位移、一個共用模式和一個開啟模式。
MS規定,核心對象只能被核心訪問,因此應該程式無法在記憶體中找到這些資料結構並直接改變他們的內容。其目的是為了確保核心對象結構保持狀態的一致。這個限制也使得使用者可以在不破壞任何應用程式的情況下在這些結構中添、刪除和修改資料成員。
我們不能直接修改,但我們又要修改。於是物件控點便出現了。 當建立一個核心對象的時候,會返回一個它的控制代碼。這是一個不透明的值,你只需要知道它能標誌你建立的這個對象就行了。 而當需要修改核心對象時,只需將這個控制代碼傳入MS為你提供的API,這個API自然知道你需要修改哪個對象。值得注意的是,這些控制代碼值是與進程密切相關的。也就是說,A進程自己建立的控制代碼只能在他自己的進程中,以及它所有的線程中使用。如果其它進程試圖訪問這個控制代碼,就會調用失敗。當然MS也提供了幾種進程間共用核心對象的方法。
核心對象有一個引用計數,標誌著你的核心對象被引用了多少次。 因為核心對象是核心所有,所以核心必須知道什麼時候外部不需要使用對象了。 引用計數就是這個目的。 核心對象在第一次建立的時候,計數為1,當另一個進程訪問它的時候,便會加1。當有進程調用CloseHandle並傳入它的控制代碼時,它的引用計數就減1。當核心檢測到此引用計數為0的時候,便會找個合適的時機釋放掉這個對象。值得說明的是,就算沒有調用CloseHandle,當所有使用這個核心對象的進程退出時,核心也會釋放掉這個對象。因此,可以確保在沒有進程引用該對象的時候,系統中不保留任何核心對象。當然,如果不釋放,則會在程式運行過程中造成記憶體佔用量大的可能。
對於核心對象,我們除了關注其控制代碼外,還應該關注它的安全性描述元,雖然這個安全性描述元在普通的應用程式(如普通的小軟體,用戶端應用程式等)中不使用。但對於某些場合,如伺服器。或者是對使用者身份有要求的應用程式中卻要使用。 它標誌著訪問此應用程式的許可權。
在建立核心對象時,會傳入一個 PSECURITY_ATTRIBUTES 參數 如:
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
大多數應用程式傳遞給psa的是NULL,這樣對象管理組中的任何成員和對象建立者有著同樣的全部存取權限。
PSECURITY_ATTRIBUTES定義大概如下:
typedef struct _PSECURITY_ATTRIBUTES{
DWORD nLength
LPVOID lpSecurityDescriptor;//安全性描述元。
BOOL bInheritHandle;
} PSECURITY_ATTRIBUTES;
而對於對象的安全描述,則只有第二個成員lpSecurityDescriptor有用。 比如我們想要開啟一個檔案對應,則可以像如下操作。
HANDLE hMapping = OpenFileMapping(FILE_MAP_READ,FASE,"MyFileMapping");
傳入FILE_MAP_READ則表示著你需要開啟此檔案,並在開啟後讀取這個檔案。 此時核心就會進行安全檢查,看是否你有讀取該對應檔的許可權。而這個檢查則是由你先前建立此檔案對應時傳入的安全性描述元而決定。