1. 程式人生 > >Linux中控制代碼是什麼?

Linux中控制代碼是什麼?

控制代碼:控制代碼是一個32位的整數,實際上是windows在記憶體中維護的一個物件(視窗等)記憶體實體地址列表的整數索引

指標:指標對應著一個數據在記憶體中的地址,得到了指標就可以自由地修改該資料


(在Linux
有相應機制,但沒有統一的控制代碼型別,各種型別的系統資源由各自的型別來標識,由各自的介面操作。)

當把硬碟上的資源調入記憶體以後,將有一個控制代碼指向它,但是控制代碼只能指向一個資源。而且控制代碼知道所指的記憶體有多大。還有指標,指標指向地址,它不知道分配的記憶體有多大。 

但是如果你定義一個控制代碼,然後在VC裡面右擊滑鼠,選擇"go to definition of handle”,你會發現它的本質就是一個指標,但是它的作用不同於指標。它和通常意義上的指標是有區別的。控制代碼借用了指標的思想,有它的邏輯特點,但沒 有它的物理功能。控制代碼是WINDOWS分配給視窗等資源的唯一標識,是一個整數。


一、書上定義:

<<Microsoft Windows 3 Developer''s Workshop>>(Microsoft Press,by Richard Wilton)

在Windows環境中,控制代碼是用來標識專案的,這些專案包括:模組(module)、任務(task)、例項 (instance)、檔案(file)、記憶體塊(block of memory)、選單(menu)、控制(control)、字型(font)、資源(resource),包括圖示(icon),游標 (cursor),字串(string)等、GDI物件(GDI object),包括點陣圖(bitmap),畫刷(brush),元檔案(metafile),調色盤(palette),畫筆(pen),區域

(region),以及裝置描述表(device context)。 

<<WINDOWS程式設計短平快>>(南京大學出版社):

控制代碼是WONDOWS用來標識被應用程式所建立或使用的物件的唯一整數,WINDOWS使用各種各樣的控制代碼標識諸如應用程式例項,視窗,控制,點陣圖,GDI物件等等。WINDOWS控制代碼有點象C語言中的檔案控制代碼。

二、MFC原始碼:

#ifdef STRICT

typedef void *HANDLE;

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name


#else

typedef PVOID HANDLE;

#define DECLARE_HANDLE(name) typedef HANDLE name

#endif

DECLARE_HANDLE(HMODULE); 

DECLARE_HANDLE(HINSTANCE); 

DECLARE_HANDLE(HLOCAL); 

DECLARE_HANDLE(HGLOBAL); 

DECLARE_HANDLE(HDC); 

DECLARE_HANDLE(HRGN); 

DECLARE_HANDLE(HWND); 

DECLARE_HANDLE(HMENU); 

DECLARE_HANDLE(HACCEL); 

DECLARE_HANDLE(HTASK); 

三、理解:

控制代碼是一個32位的整數,實際上是windows在記憶體中維護的一個物件(視窗等)記憶體實體地址列表的整數索引。因為windows的記憶體管理經常 會將當前空閒物件的記憶體釋放掉,當需要時訪問再重新提交到物理儲存,所以物件的實體地址是變化的,不允許程式直接通過實體地址來訪問物件。程式將想訪問的 物件的控制代碼傳遞給系統,系統根據控制代碼檢索自己維護的物件列表就能知道程式想訪問的物件及其實體地址了。控制代碼是一種指向指標的指標。我們知道,所謂指標是一 種記憶體地址。應用程式啟動後,組成這個程式的各個物件是駐留在記憶體的。如果簡單地理解,似乎我們只要獲知這個記憶體的首地址,那麼就可以隨時用這個地址訪問
物件了。但是,如果真這麼認為,那麼就大錯特錯了。我們知道windows是一個虛擬記憶體為基礎的作業系統。在這種情況下,windows記憶體管理器經常 在記憶體中來回移動物件,以此來滿足各種應用程式的記憶體需要,物件被移動意味著它的地址變化了。如果地址總是如此的變化,我們應該去那裡找物件呢?為了解決 這個問題,windows作業系統為各個應用程式騰出一些記憶體地址,用來專門登記各個應用物件在記憶體中的地址變化,而這個地址(儲存單元的位置)本身是不變的。windows 記憶體管理器移動物件在記憶體中的位置後,把物件新的地址告知這個控制代碼地址來儲存。這樣我們只需要記住這個控制代碼地址就可以間接地知道物件具體在記憶體中哪個位置
了。這個地址是在物件裝載(load)時由系統分配的,當系統解除安裝時又釋放給系統。句並地址(穩定)----->記載著物件在記憶體中的地址 -------->物件在記憶體中的地址(不穩定)----->實際物件。但是必須注意,程式每次重新啟動,系統不保證分配跟這個程式的控制代碼還 是原來哪個控制代碼,而絕大多數情況下的確不一樣。假如我們把進入電影院看電影看成是一個應用程式的啟動執行,那麼系統給應用程式分配的控制代碼總是不一樣,這和 每次電影院給我們的門票總是不同的座位是一個道理。

因此,控制代碼和指標其實是兩個截然不同的概念。windows系統用句並標記系統資源,用句並隱藏系統資訊。你只需要知道有這個東西,然後去呼叫它就行了,它是32bit的uint。指標則標記某個實體記憶體的地址,是不同的概念。

指標對應著一個數據在記憶體中的地址,得到了指標就可以自由地修改該資料。Windows並不希望一般程式修改其內部資料結構,因為這樣太不 安全。所以Windows給每個使用GlobalAlloc等函式宣告的記憶體區域指定一個控制代碼(本質上仍是一個指標,但不要直接操作它),平時你只是在調 用API函式時利用這個控制代碼來說明要操作哪段記憶體。當你需要對某個記憶體進行直接操作時,可以使用GlobalLock鎖住這段記憶體並獲得指標來直接進行操 作。

控制代碼是指標的“指標”,使用控制代碼主要是為了利於windows在程序記憶體地址空間移動分配的記憶體塊,以防止程序的記憶體空間被撕的四分五裂而存在過多的碎片。 

控制代碼是一些表的索引也就是指向指標的指標。間接的引用物件,windows可以修改物件的"物理"地址和 描述器的值,但是控制代碼的值是不變的。

控制代碼可以在獲得視窗的時候使用,指標可以進行呼叫視窗,兩個使用的地方不一樣.一個括號外,一個括號內.

從視窗指標獲取視窗控制代碼:GetSafeHwnd();

從視窗控制代碼獲取臨時視窗指標:FromHandle(); 

從視窗控制代碼獲取永久視窗指標: FromHandlePermanent();

其實兩者被沒有關係,實際上是MFC在建立視窗的時候用鉤子函式溝住HCBT_CREATEWND訊息,

然後通過CWnd::Attach()函式把二者捆綁在一起。

以後就可以用GetSafeHwnd(),FromHandle(),FromHandlePermanent()這三個函式可以互相得到了。

MFC之所以要這樣做,主要是為了使原來的SDK面向過程的程式設計遍成面向物件的程式設計,所有的MFC的視窗都共用一視窗過程函式,在視窗過程函式裡, 通過視窗控制代碼(HWND)找到視窗物件指標(CWnd *)從而把訊息分發到視窗物件中,這樣以後就可以在視窗類中實行訊息響應程式設計處理了。

附註:獲得視窗控制代碼三種方法

1.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName) 

HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)

2.HWND WindowFromPoint(POINT& Point)//獲得當前滑鼠游標位置的視窗HWND

3.BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)

BOOL CALLBACK EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc,LPARAM lParam)

BOOL CALLBACK EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)

在Linux中:

1.控制代碼就是一個識別符號,只要獲得物件的控制代碼,我們就可以對物件進行任意的操作。

2.控制代碼不是指標,作業系統用控制代碼可以找到一塊記憶體,這個控制代碼可能是識別符號,map的key,也可能是指標,看作業系統怎麼處理的了。
fd算是在某種程度上替代控制代碼吧;
Linux
有相應機制,但沒有統一的控制代碼型別,各種型別的系統資源由各自的型別來標識,由各自的介面操作。

3.http://tech.ddvip.com/2009-06/1244006580122204_11.html
在作業系統層面上,檔案操作也有類似於FILE的一個概念,在Linux裡,這叫做檔案描述符(File
Descriptor),而在Windows裡,叫做控制代碼(Handle)(以下在沒有歧義的時候統稱為控制代碼)。使用者通過某個函式開啟檔案以獲得控制代碼,此
後用戶操縱檔案皆通過該控制代碼進行。
設計這麼一個控制代碼的原因在於控制代碼可以防止使用者隨意讀寫作業系統核心的檔案物件。無論是Linux還是Windows,檔案控制代碼總是和核心的檔案物件相關聯的,但如何關聯細節使用者並不可見。核心可以通過控制代碼來計算出核心裡檔案物件的地址,但此能力並不對使用者開放。
下面舉一個實際的例子,在Linux中,值為0、1、2的fd分別代表標準輸入、標準輸出和標準錯誤輸出。在程式中開啟檔案得到的fd從3開始增長。
fd具體是什麼呢?在核心中,每一個程序都有一個私有的“開啟檔案表”,這個表是一個指標陣列,每一個元素都指向一個核心的開啟檔案物件。而fd,就是這
個表的下標。當用戶開啟一個檔案時,核心會在內部生成一個開啟檔案物件,並在這個表裡找到一個空項,讓這一項指向生成的開啟檔案物件,並返回這一項的下標
作為fd。由於這個表處於核心,並且使用者無法訪問到,因此使用者即使擁有fd,也無法得到開啟檔案物件的地址,只能夠通過系統提供的函式來操作。
在C語言裡,操縱檔案的渠道則是FILE結構,不難想象,C語言中的FILE結構必定和fd有一對一的關係,每個FILE結構都會記錄自己唯一對應的fd。

控制代碼http://zh.wikipedia.org/wiki/%E5%8F%A5%E6%9F%84

程式設計 中,控制代碼是一種特殊的智慧指標 。當一個應用程式 要引用其他系統(如資料庫作業系統 )所管理的記憶體 塊或物件 時,就要使用控制代碼。
控制代碼與普通指標 的區別在於,指標包含的是引用物件 的記憶體地址 ,而控制代碼則是由系統所管理的引用標識,該標識可以被系統重新定位到一個記憶體地址 上。這種間接訪問物件 的模式增強了系統對引用物件 的控制。(參見封裝 )。
在上世紀80年代的作業系統(如Mac
OS 和Windows )的記憶體管理 中,控制代碼被廣泛應用。Unix 系統的檔案描述符 基本上也屬於控制代碼。和其它桌面環境 一樣,Windows
API 大量使用控制代碼來標識系統中的物件 ,並建立作業系統與使用者空間 之間的通訊渠道。例如,桌面上的一個窗體由一個HWND 型別的控制代碼來標識。
如今,記憶體 容量的增大和虛擬記憶體 演算法使得更簡單的指標 愈加受到青睞,而指向另一指標的那類控制代碼受到冷淡。儘管如此,許多作業系統 仍然把指向私有物件 的指標以及程序傳遞給客戶端 的內部陣列 下標稱為控制代碼。