續上......
核心對象如何在進程邊界共用?
1.物件控點的繼承
當進程具有父子關係,就能使用物件控點的繼承性。父進程有一個或多個物件控點,並且父進程可以決定產生一個子進程,為子進程賦於父進程的核心對象的訪問權。
具體實現:
在安全性描述元中指定,如:
SECURITY_ATTRIGBUTES sa
sa.nLength=sizeof(sa);
sa.lpSecuntyDescriptor=null;
sa.bInherithandle=TRUE; //指定子進程可以繼承該父進程的核心對象。
HANDLE hMutex = CreateMutex(@sa,FALSE,NULL);
然後,在進程中使用CreateProcess函數: BOOL CreateProcess(
PCTSTR pszApplicationName,
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY_ATTRIBUTES psaThread,
BOOL bInheritHandles,
DWORD fdwCreale,
PVOIO pvEnvironment,
PCTSTR pszCurDir,
PSTARTUPINFO psiStartInfo,
PPROCESS_INFORMATION ppiProcInfo);
為bInheritHandles指定TRUE,則告訴系統,子進程繼承父進程的控制代碼表中的可繼承控制代碼。
2.改變控制代碼標誌:
因為每個進程都會有個核心物件控點表,指明該進程所擁有的控制代碼資訊。那麼,我們可以直接設定進程的控制代碼表,以擷取某個核心對象的訪問權。
控制代碼表的樣式:
索引 |
核心對象記憶體塊的指標 |
訪問屏蔽(標誌位的D W O R D ) |
標誌(標誌位的D W O R D ) |
1 |
0 x 0 0 0 0 0 0 0 0 |
(無) |
(無) |
2 |
0 x 0 0 0 0 0 0 0 0 |
(無) |
(無) |
3 |
0 x F 0 0 0 0 0 1 0 |
0 x ? ? ? ? ? ? ? ? |
0 x 0 0 0 0 0 0 0 1 |
設定控制代碼標誌的函數: BOOL SetHandleInformation(
HANDLE hObject,
DWORD dwMask,
DWORD dwFlags);
可以看到,該函數擁有3 個參數。第一個參數h O b j e c t 用於標識一個有效控制代碼。第二個參數d w M a s k 告訴該函數想要改變哪個或那幾個標誌。目前有兩個標誌與每個控制代碼相關聯: #define HANDLE FLAG_INHERIT 0x00000001
#define HANDLE FLAG PROTECT FROM CLOSE 0x00000002
比如,開啟一個核心對象的繼承標誌,則可以這樣:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
關閉該標誌,則可以:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT, 0);
3.給核心對象命名
建立許多核心對象可以進行命名,如:
HANDLE CreateMutex(
PSLCURITY_ATTRIBUTES psa,
BOOL bInitialOwner,
PCTSTR pszName);
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszNarne);
HANDLE CreateWaitableTimer(
PSLCURITY_ATTRIBUTES psa,
BOOL bManualReset,
PCTSTR pszName);
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
如果建立時最後的參數設定NULL,則建立一個末名命的核心對象當建立一個未命名的對象時,可以通過使用繼承性(如上一節介紹的那樣)或D u p l i c a t e H a n d l e (下一節將要介紹)共用跨越進程的對象。若要按名字共用對象,必須為對象賦予一個名字
實現:我們在ProcessA中建立一個核心對象:
HANDLE hMutexPronessA = CreateMutex(NULL, FALSE, "JeffMutex");
然後,在ProcessB中建立一個與ProcessA中同名的核心對象:
HANDLE hMutexProcessB = CreateMutex(NULL, FALSE, "JeffMutex");
下面,會發生什麼情況?以下是書中所揭示的:
當Process B 調用C r e a t e M u t e x 時,系統首先要查看是否已經存在一個名字為“J e ff M u t e x ”的核心對象。由於確實存在一個帶有該名字的對象,因此核心要檢查對象的類型。由於試圖建立一個互斥對象,而名字為“J e ff M u t e x ”的對象也是個互斥對象,因此系統會執行一次安全檢查,以確定調用者是否擁有對該對象的完整的訪問權。如果擁有這種訪問權,系統就在Process B 的控制代碼表中找出一個空項目,並對該項目進行初始化,使該項目指向現有的核心對象。如果該物件類型不匹配,或者調用者被拒絕訪問,那麼C r e a t e M u t e x 將運行失敗(返回N U L L )。當Process B 對C r e a t e M u t e x 的調用取得成功時,它並不實際建立一個互斥對象。相反,Process B 只是被賦予一個與進程相關的控制代碼值,用於標識核心中現有的互斥對象。當然,由於Process B 的控制代碼表中的一個新項目要引用該對象,互斥對象的使用計數就會遞增。在Process A和Process B 同時關閉它們的物件控點之前,該對象是不會被撤消的。請注意,這兩個進程中的控制代碼值很可能是不同的值。這是可以的。Process A 將使用它的控制代碼值,而Process B 則使用它自己的控制代碼值來操作一個互斥核心對象。
按名字共用對象的另一種方法是,進程不調用C r e a t e *函數,而是調用下面顯示的O p e n *函數中的某一個,如: HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
HANDLE OpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
HANDLE OpenSemaphore(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
HANDLE OpenWaitableTimer(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
HANDLE OpenFileMapping(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
調用Create*與調用Open*來建立開啟核心對象有什麼區別呢?
調用C r e a t e *函數與調用O p e n *函數之間的主要差別是,如果對象並不存在,那麼C r e a t e *函數將建立該對象,而O p e n *函數則運行失敗。
4.複製核心物件控點:
共用跨越進程邊界的核心對象的最後一個方法是使用D u p l i c a t e H a n d l e 函數: BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);
簡單說來,該函數取出一個進程的控制代碼表中的項目,並將該項目拷貝到另一個進程的控制代碼表中。
二,進程
1.何為進程,進程有何特性?
所謂進程,就是一個正在運行程式的執行個體。它由兩部分組成:
• 一個是作業系統用來管理進程的核心對象。
• 另一個是地址空間,它包含所有可執行模組或D L L 模組的代碼和資料。它還包含動態記憶體分配的空間。如線程堆棧和堆分配空間。
注意,進程是不活潑的,即進程完成的操作,是需要靠進程中的線程來完成。每個進程都必須有一個線程,也可以有多個線程。線程負責執行包含在進程地址空間內的代碼。所謂多線程,就是多個線程同時執行包含在地址空間內的代碼。
若要使線程執行進程內的代碼,作業系統必須為線程分配CPU時間片。它是以一種迴圈的方式來提供時間片的,即給每個線程多少時間,時間完成之後,收回CPU,轉交給另外的線程。
建立一個進程,系統會自動為其進程建立一個主線程。然後,可利用該線程可以建立其它的線程,其正是多線程。