核心對象主要要用來供系統和應用程式管理系統資源,像進程、線程、檔案等。存取符號對象、事件對象、檔案對象、工作物件、互斥對象、管道對象、等待計時器對象等都是核心對象。我們在編程時經常要建立、開啟和操作它們。核心對象通過調用函數來建立,如要建立檔案對應物件,就調用CreateFileMapping函數。每個核心對象都會分配一個記憶體塊,只能由其核心訪問。該記憶體塊是一種資料結構,用於管理對象的各種資訊。
我們的應用程式不能直接存取核心對象的資料結構。需要通過Windows提供的函數來訪問。
核心對象由核心擁有,並不是進程所擁有。每個核心對象都有一個計數器來儲存有多少個進程在使用它的資訊。
核心對象有安全性描述元的保護,安全性描述元描述了誰建立了該對象以及誰能夠使用該對象。用於建立核心對象的函數幾乎都有一個指向SEC URITY_ATTRIBUTES 結構的指標作為其參數。CreateFileMapping函數的指標的代碼如下所示:1 HANDLE CreateFileMapping(
2 HANDLE hFile.
3 PSECURITY_ATTRIBUTES psa,
4 DWORD flProtect,
5 DWORD dwMaximumSizeHigh,
6 DWORD dwMaximuniSizeLow,
7 PCTSTR pszNarne);
大多數應用程式通過傳NULL值建立具有預設安全性的對象(對象管理小組的任何成員及建立者擁有全部訪問權,而其他任何人均無權訪問)
。如果你想限制別人對對象的訪問,你就需要單獨建立一個SECURITY_ATTRIBUTES對象並對其初始化。代碼如下:
1 SECURITY_ATTRIBUTES sa;
2 sa.nLength = sizeof(sa); //Used for versioning
3 sa.lpSecuntyDescriptor = pSD, //Address of an initialized SD
4 sa.bInheritHandle = FALSE; //Discussed later
5 HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,
6 &sa, PAGE_REAOWRITE, 0, 1024, "MyFileMapping");
當一個進程被初始化時,系統會為其分配一個控制代碼表。控制代碼表用於核心對象,而不用於使用者物件和GDI對象。
表3-1 進程的控制代碼結構
索引 |
核心對象記憶體塊的指標 |
訪問屏蔽(標誌位的D W O R D ) |
標誌(標誌位的D W O R D ) |
1 |
0 x ? ? ? ? ? ? ? ? |
0 x ? ? ? ? ? ? ? ? |
0 x ? ? ? ? ? ? ? ? |
2 |
0 x ? ? ? ? ? ? ? ? |
0 x ? ? ? ? ? ? ? ? |
0 x ? ? ? ? ? ? ? ? |
... |
... |
... |
... |
建立核心對象
進程初次初始化時,控制代碼表是空的。進程中的線程調用建立核心對象的函數時,核心就為相應的核心對象分配一個記憶體塊,並初始化。核心
對進程的控制代碼表進行掃描,找到一個空項,用對象的資料結構的記憶體位址進行初始化。下面是一些建立核心對象的函數:
1 HANDLE CreateThread(
2 PSECURITY_ATTRIBUTES psa,
3 DWORD dwStackSize,
4 PTHREAD_START_ROUTINE pfnStartAddr,
5 PVOID pvParam,
6 DWORD dwCreationFlags,
7 PDWORD pdwfhreadId);
8
9 HANDEE CreateFile(
10 PCTSTR pszFileName,
11 DWORD dwDesiredAccebS,
12 DWORD dwShareMode,
13 PSECURITY_ATTRIBUTES psa,
14 DWORD dwCreationDistribution,
15 DWORD dwFlagsAndAttnbutes,
16 HANDEE hTemplateFile);
關閉核心對象
不論通過何種方式建立核心對象,都通過調用CloseHandle方法來結束對核心對象的操作。
BOOL CloseHandle(HANDLE hobj);
為什麼結束進程能釋放所有佔用的資源?進程在運行時有可能出現記憶體流失。在進程終止運行時,系統會自動掃描進程的控制代碼表。若表中擁有任何無效項目(進程終止前沒關閉的對象),系統將關閉這些對象的控制代碼。對象的計數器被置0,核心便會撤銷這些對象。
跨進程邊界共用核心對象
很多時候,不同進程的線程需要共用核心對象。如郵箱和指定的管道使應用程式能在連網的電腦上不同的進程之間發送資料區塊。
物件控點的相容性:只有當進程之間是父子關係時,才能使用物件控點的繼承性。在這種情況下,父進程可以使用一個或多個核心物件控點,並且該父進程可以決定產生一個子進程,為子進程賦予對父進程的核心對象的訪問權。
實現過程:1.父進程建立核心對象,並指明對象的控制代碼是可繼承的控制代碼,注意核心對象本身不具備繼承性。
2.使用物件控點繼承性時要執行的下一個步驟是讓父進程產生子進程。這要使用CreateProcess函數來完成:
1 BOOL CreateProcess(
2 PCTSTR pszApplicationName,
3 PTSTR pszCommandLine,
4 PSECURITY_ATTRIBUTES psaProcess,
5 PSECURITY_ATTRIBUTES psaThread,
6 BOOL bInheritHandles, //TRUE表可繼承,FALSE表不可繼承
7 DWORD fdwCreale,
8 PVOIO pvEnvironment,
9 PCTSTR pszCurDir,
10 PSTARTUPINFO psiStartInfo,
11 PPROCESS_INFORMATION ppiProcInfo);
在這個過程中,系統將拷貝可繼承的控制代碼的每個項目到子繼承的控制代碼表中。並遞增核心對象相應的計數器。CreateProcess函數返回後,父進程會立即關閉對象的控制代碼,而不影響子進程對該對象進行相關操作。
命名物件:共用跨越進程邊界的核心對象的另一種方法。大部分核心對象可以被命名。若要按名字共用對象,則必須為對象賦予同一個名字。如下面的建立命名核心對象的代碼:
1HANDLE CreateMutex(
2 PSLCURITY_ATTRIBUTES psa,
3 BOOL bInitialOwner,
4 PCTSTR pszName);
5
6HANDLE CreateEvent(
7 PSECURITY_ATTRIBUTES psa,
8 BOOL bManualReset,
9 BOOL bInitialState,
10 PCTSTR pszName);