SDK的WIN32 API用句柄HANDLE操作Windows窗口,而VC将HANDLE封裝為CWnd類的一個成員變量m_hWnd,可以取此對象的m_hWnd屬性來得到句柄。同時,VC中每一個窗口類都可以聲明為一個窗口指針來調用窗口類的成員屬性和成員變量。
1 窗口窗口是Windows應用程序中一個非常重要的元素,一個Windows應用程序至少要有一個窗口,稱為主窗口,窗口是指現在是屏幕上面的一快矩形區域,是Windows應用程序與用戶進行交互的接口。利用窗口,可以接收用戶的輸入及顯示輸出。
一個應用程序窗口通常包含标題欄、菜單欄、系統菜單、最小化框、最大化框、可調邊框、滾動條等
窗口可以分為客戶區和非客戶區,客戶區是窗口的一部分,應用程序通常在客戶區中顯示文字或繪制圖形。而标題欄、菜單欄、系統菜單、最小化和最大化,可調系統邊框為窗口的非客戶區,他們由windows來管理,而應用程序則主要管理客戶區的外觀及操作。
窗口可以有一個父窗口,有父窗口的窗口稱為子窗口,另外,對話框和消息框也是一種窗口,在對話框上面還包含許多子窗口,這些子窗口的形式有按鈕、單選按鈕、複選框、組框、文本編輯框等。
此外,在我們啟動Windows系統後,我們的桌面也是一個窗口,稱為桌面窗口,是位于最上層的窗口,由Windows系統創建和管理。
2 窗口句柄當用你CreateWindow創建了一個窗口,這個窗口其實并不是你創建的,而是系統替你的創建的,系統為創建這個窗口,它必須要保留很多的和這個窗口相關的數據,這些數據并不是給你用的,而是系統用來維護窗口用的,而句柄就是系統用來找到這個窗口相關數據的一人索引。你向一個API提供一個句柄,比如ShowWindow(HWND);要顯示這個窗口,這個工作還是系統替你做的,它根據你提供的索引,也就是句柄,找到窗口,然後進行相關的處理。所以說,句柄是相關對象的唯一索引。從這一點上看,有點像指針,但是指針的内容是對象的地址,而句柄并不是地址,句柄隻是一個索引,一個整數。
句柄的實質就是一個結構體的實例。
Windows系統中有許多内核對象(這裡的對象不完全等價于"面向對象程序設計"一詞中的"對象",雖然實質上還真差不多),比如打開的文件,創建的線程,程序的窗口,等等。這些重要的對象肯定不是4個字節或者8個字節足以完全描述的,他們擁有大量的屬性。為了保存這樣一個"對象"的狀态,往往需要上百甚至上千字節的内存空間,那麼怎麼在程序間或程序内部的子過程(函數)之間傳遞這些數據呢?拖着這成百上千的字節拷貝來拷貝去嗎?顯然會浪費效率。那麼怎麼辦?當然傳遞這些對象的首地址是一個辦法,但這至少有兩個缺點:
I 暴露了内核對象本身,使得程序(而不是操作系統内核)也可以任意地修改對象地内部狀态(首地址都知道了,還有什麼不能改的?),這顯然是操作系統内核所不允許的;
II 操作系統有定期整理内存的責任,如果一些内存整理過一次後,對象被搬走了怎麼辦?
所以,Windows操作系統就采用進一步的間接:在進程的地址空間中設一張表,表裡頭專門保存一些編号和由這個編号對應一個地址,而由那個地址去引用實際的對象,這個編号跟那個地址在數值上沒有任何規律性的聯系,純粹是個映射而已。
在Windows系統中,這個編号就叫做"句柄"。
在Windows應用程序中,窗口是通過句柄HWND來标識的,我們要對某個窗口進行操作,首先就要獲取到這個窗口的句柄。
每個窗口在被創建出來之後就會被賦予一個句柄,該句柄指向一個數據結構體,結構體裡明确表示着該窗口的各種信息,窗口大小,窗口名等,當我們得到這個句柄時就可以請求操作系統對它做一系列操作,列如:移動窗口,關閉窗口,最小化最大化等,這些都是通過窗口句柄來告訴操作系統的,我們要對哪個窗口進行操作,而消息則是告訴操作系統要做什麼樣的操作,消息的附加參數就是操作值,列如移動窗口,會有附加的xy坐标參數!
3 Windows對象和MFC對象的區别句柄有Windows句柄,文件句柄,分配内存句柄,圖形句柄等,系統在創建這次資源的時候回為其分配内存,并返回标識這些資源的标識号,這個标識号就是句柄,實際上,我們可以将句柄看做是指針。
在使用句柄之前,必須先創建他們,當不在使用時,應當及時銷毀,如果不銷毀他們,最終将到時資源洩露,資源洩露有可能導緻系統崩潰,所以,務必确保在适當的時候銷毀不在使用的句柄。
另外,程序運行時也是以進程存在,進程也是用ID或句柄去标識。
進程創建時,windows系統為進程構造了一個句柄表。當該進程希望獲得一個内核對象句柄或者創建一個内核對象從而獲得該對象句柄時。系統會将在句柄表中增加一個表項,表項的内容中存儲了指向目标内核對象的指針。同時,系統返回這個表項在句柄表中的索引作為句柄。這樣,進程就通過句柄查詢句柄表得到對象指針,從而可以訪問該對象。同時又由于有了句柄表的保護,可以防止對内核對象的非法操作。
windows對象并不是我們平時所說的“面向對象”程序設計中的“類的對象”,而是一種windows資源實體,如畫筆、字體等。
如果想要去使用這些windows對象我們需要用句柄來标識它們。
而MFC對象則是真正的“面向對象”思想中的“類的對象”(必須用構造函數去創建)。
在windows編程中,除了普通的“類的對象”外,用得最多的“C 類的對象”應該是MFC對象了(如果你是用MFC編程的話),
MFC對象是指“封裝了windows對象的C 對象”(也就是MFC對象中有一個控制window對象的控制器,那麼控制器想工作就得和一個window對象鍊接起來,這樣就能控制器就能控制這個對象了)。
所謂Windows對象是Win32下用句柄表示的Windows操作系統對象;
所謂MFC對象就是C 對象,是一個C 類的實例.
一個MFC窗口對象是一個C CWnd類(或派生類)的實例,是程序直接創建的。
在程序執行中它随着窗口類構造函數的調用而生成,随着析構函數的調用而消失。
而Windows窗口則是Windows系統的一個内部數據結構的實例,由一個“窗口句柄”标識,Windows系統創建它并給它分配系統資源。
Windows窗口在MFC窗口對象創建之後,由CWnd類的Create成員函數創建,“窗口句柄”保存在MFC窗口對象的m_hWnd成員變量中。
Windows窗口可以被一個程序銷毀,也可以被用戶的動作銷毀。
MFC中的窗口類,就是C 類與Windows窗口的句柄的結合。在基于CWnd繼承而來的所有類中,都有一個公有的成員變量m_hWnd,這個成員變量就是窗口對象關聯的windows窗口句柄。我們在類中可以直接使用這個窗口句柄成員變量。這個窗口對象就是标準的C 對象。其實MFC窗口類并不神奇,就是包裝了一下API而已。m_hWnd的類型就是HWND。 MFC給CWnd提供了兩個成員函數Attach(HWND hWndNew )和Detach()。前者傳入一個窗口句柄,将該窗口關聯到C 對象,後者則是将當前關聯的窗口解關聯。而關聯就是給m_hWnd賦值,解關聯就是将m_hWnd設置為NULL。解關聯後,窗口對象就不關聯任何窗口了,此時就不能執行窗口相關的任何操作,都會失敗。如果要關聯新的窗口,隻要執行Attach函數即可。
4 對話框控件消息響應函數中可以直接調用的函數4.1 MFC全局函數,如:
AfxMessageBox 顯示一個消息框
AfxGetApp 返回應用程序對象CWinApp的一個指針
AfxGetAppName 返回應用程序的名稱
AfxInitRichEdit 為應用程序初始化RichEdit控件
4.2 API函數,如:
SendMessage(),調用一個窗口的窗口函數,将一條消息發給那個窗口;
OpenFile() 這個函數能執行大量不同的文件操作;
RegCreateKey() 在指定的項下創建或打開一個項;
GetCaretPos() 判斷插入符的當前位置;
ShellExecute() 用指定程序打開指定路徑下的文件;
4.3 其父類定義的成員函數,如CWnd類:
PreSubclassWindow()
在調用SubclassWindow之前,允許其它必要的子類化工作
FromHandle()
當給定一個窗口的句柄時,返回CWnd對象的指針。如果沒有CWnd對象與這個句柄相連接,則創建一個臨時的CWnd對象并與之相連接
GetSafeHwnd
返回m_hWnd,如果該指針為NULL,則返回NULL
etFocus()
要求輸入焦點
SetWindowPos()
改變子窗口、彈出窗口和頂層窗口的大小、位置以及順序
GetClientRect
獲得CWnd客戶區域的大小
GetDlgItem(),
獲得指定的對話框中具有指定ID的控件
UpdateData()
初始化對話框或獲得對話框中的數據
SetWindowText()
将窗口的文本或标題文字(如果有)設為指定的文本
SetWindowText
将窗口的文本或标題文字(如果有)設為指定的文本
SetTimer()
安裝一個系統定時器,當它被激活時,發送一個WM_TIMER消息
MessageBox()
創建并顯示一個窗口,其中包含了應用程序提供的消息和标題
SendMessage()
向CWnd對象發送一個消息,直到這條消息被處理之後才返回
OnPaint()
調用這個函數以重畫窗口的一部分
OnLButtonDown()
當用戶按下鼠标左鍵時調用這個函數
OnTimer()
當達到SetTimer指定的時間間隔時調用這個函數
4.4 繼承關系不同的GetDlgItem()
1) CWindow::GetDlgItem HWND GetDlgItem(int nID)const; 2) CWnd::GetDlgItem CWnd* GetDlgItem(int nID) const; void CWnd::GetDlgItem( int nID, HWND *phWnd) const; 3)Windows SDK HWND GetDlgItem(HWND hDlg,int nIDDlgItem);
5 窗口句柄和指針使用的場合先看下面的兩行代碼,簡單了解一下窗口句柄和指針的一個使用場合:
5.1 API函數以句柄為參數
CString str = "在編輯框上顯示給定文本。"; SendMessage(GetActiveWindow()->GetDlgItem(IDC_textbox)->m_hWnd, WM_SETTEXT , 0 , (LPARAM)str.GetBuffer(0));
此代碼可以在當前活動窗口的IDC_textbox文本框控件中顯示一個字符串str。
① API函數SendMessage()功能: 将指定的消息發送到一個或多個窗口。
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam)
hWnd:其窗口程序将接收消息的窗口的句柄。如果此參數為HWND_BROADCAST,則消息将被發送到系統中所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口,但消息不被發送到子窗口。
Msg:指定被發送的消息。
wParam:指定附加的消息特定信息。
IParam:指定附加的消息特定信息。
返回值:指定消息處理的結果,依賴于所發送的消息。
② CWnd類方法GetDlgItem(IDC_textbox),能夠返回一個MFC指針*CWnd;
③ CWnd類方法GetActiveWindow(),可以返回當前窗口的一個HWND句柄;
④ “->m_hWnd”是将一個指針轉換為句柄。一般窗口對象都會有一個其對應的句柄變量,所以我們可以取此對象的m_hWnd屬性來得到句柄。
5.2 MFC對象指針調用成員函數
下面的的代碼也是在編輯框上顯示給定文件:
CString str = "在編輯框上顯示給定文本。"; CEdit *edit1=(CEdit*)GetDlgItem(IDC_EDIT2); edit1->SetWindowText(str);
GetDlgItem()可以返回一個MFC指針*CWnd,并用(CEdit*)做了下類型轉換,然後就可以使用CEdit類的成員函數,例如SetWindowText()。
5.3 API函數使用句柄作為參數
CString str = "F:\\help\\list.html"; API函數ShellExecute(this->m_hWnd, "open", str,"", NULL, SW_SHOW);
this->m_hWnd; //返回的就是窗口類自己的句柄呢,也可以用MFC全局函數:
AfxGetMainWnd()->m_hWnd;
6 窗口ID和指針對MFC編程來說,對話框和控件都可以理解為一個子窗口,都有對應的一個ID和類。可以返回對應的對象指針。
7 獲得窗口句柄的方法HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)
HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)
HWND WindowFromPoint(POINT& Point)//獲得當前鼠标光标位置的窗口HWND
在任何類中獲得應用程序類
HWND AfxGetInstanceHandle()
獲取當前活動窗口句柄
HWND GetActiveWindow(VOID)
獲取前台窗口句柄
HWND GetForegroundWindow( void );
獲得對話框中某控件的句柄
HWND GetDlgItem(m_hDLG,m_nID_DlgItem);
獲得GDI對象的句柄
HWND m_hGDIObj = m_pGDIObj->GetSafeHanle();
8 獲取窗口指針的辦法① 獲取當前應用進程的指針
AfxGetApp();
② 獲得主框架窗口指針(任何時候都可以用,隻要是MFC程序中)
CWnd* pWnd = AfxGetMainWnd();
③ 獲得對話框中控件指針
CWnd* pWnd = GetDlgItem(IDC_xxx);
可以強制轉換為具體類型,如CEdit *edit1 = (*CEdit)GetDlgItem(IDC_xxx);
④ 獲得工具欄指針
CToolBar * pToolBar=(CtoolBar*)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);
9 窗口、控件的指針和句柄的相互轉化① 指針轉化為句柄
在MFC應用程序中首先要獲得窗口的指針,然後将其轉化為句柄
CWnd *pwnd = FindWindow(“ExploreWClass”,NULL); //希望找到資源管理器 HWND hwnd = pwnd->m_hwnd; //得到它的HWND
這樣的代碼當開始得到的pwnd為空的時候就會出現一個“General protection error”,并關閉應用程序,因為一般不能對一個NULL指針訪問其成員,如果用下面的代碼:
CWnd *pwnd = FindWindow(“ExploreWClass”,NULL); //希望找到資源管理器 HWND hwnd = pwnd->GetSafeHwnd(); //得到它的HWND
就不會出現問題,因為盡管當pwnd是NULL時,GetSafeHwnd仍然可以用,隻是返回NULL
② 句柄轉化為指針
在MFC應用程序中首先用GetDlgItem()獲得對話框控件的句柄,然後獲得其指針:
HANDLE hWnd; GetDlgItem(IDC_xxx,&hWnd); CWnd *pWnd=CWnd::FromHandle(hWnd); pWnd->Attach(hWnd); //Attaches a Windows to a CWnd object
// 用FindWindow()得到一個窗口句柄,然後轉換為容器指針
HWND hWnd=::FindWindow(NULL,_T("IDD_Assistants")); //得到對話框的句柄 CAssistantsDialog* pWnd= (CAssistantsDialog*)CAssistantsDialog::FromHandle(hWnd); //由句柄得到對話框的對象指針 pWnd- >xxx( ); //調用C***Dialog中的函數xxx();
10 窗口、控件的指針和句柄與其ID的相互轉化ID->句柄,hWnd = ::GetDlgItem(hParentWnd,id);
ID->指針,CWnd::GetDlgItem();
句柄->ID,id = GetWindowLong(hWnd,GWL_ID);
指針->ID,id = GetWindowLong(pWnd->GetSafeHwnd,GWL_ID);
HICON->ID,HICON hIcon = AfxGetApp()->LoadIcon(nIconID);
ID->HICON,HICON hIcon = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(nIconID));
-End-
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!