1. 程式人生 > >【轉】VC++的視窗控制代碼和視窗ID

【轉】VC++的視窗控制代碼和視窗ID

控制代碼是視窗資源的標識,它標識資源在系統中所佔用的記憶體塊,應用程式通過視窗控制代碼對視窗進行操作。除了視窗控制代碼之外,任何一種資源都有它自己的控制代碼,比如游標控制代碼、點陣圖控制代碼等。視窗ID是視窗在應用程式中的唯一標識,通過視窗ID可以獲取視窗控制代碼。

-------------------------------------------------------------------------------------------------

VC++中控制元件的ID是什麼概念?控制代碼又是什麼?

   這兩個概念都是控制元件的標識,這兩個概念可以從"內外兩方面考慮",
"外"指的是使用者(程式設計師)識別的,在vc編輯系統中,ID就是被程式設計師利用的,對各種控制元件進行操作的標識;"內"部的ID是指控制代碼,即控制代碼是內部作業系統識別這個ID的標識。
另外,在程式執行期,整個程序不會有ID這個東西,只會有控制代碼,而在編輯器內(即在程式的非執行期內),存在的是ID,而不會存在控制代碼,但對同一個控制元件而言,它們指的是同一個東西。關鍵是看用在什麼期間

------------------------------------------------------------------------------------------------

ID--HANDLE--HWND三者之間的互相轉換

id->控制代碼、、、、、hWnd = ::GetDlgItem(hParentWnd,id);

id->指標、、、、、CWnd::GetDlgItem();

控制代碼->id、、、、、id = GetWindowLong(hWnd,GWL_ID);

控制代碼->指標、、、、CWnd *pWnd=CWnd::FromHandle(hWnd);

指標->ID、、、、、id = GetWindowLong(pWnd->GetSafeHwnd,GWL_ID);

                                           GetDlgCtrlID();

指標->控制代碼、、、、hWnd=cWnd.GetSafeHandle() or mywnd->m_hWnd;

////////////////////////////////////////////////////////////////////////////////////////////////

先通過::FindWindow()函式取得主對話方塊的控制代碼  
  函式原形如下:  
  HWND   FindWindow(  
      LPCTSTR   lpClassName,     //   主視窗的類名  
      LPCTSTR   lpWindowName     //   視窗標題  
  );  
  這個函式的返回值是主視窗的控制代碼  
  然後在通過::FindWindowEx()函式取得子視窗的控制代碼  
  函式原形如下:  
  HWND   FindWindowEx(  
      HWND   hwndParent,             //   父視窗的控制代碼  
      HWND   hwndChildAfter,     //   得到的子視窗的控制代碼  
      LPCTSTR   lpszClass,         //   子視窗類名  
      LPCTSTR   lpszWindow         //   子視窗標題  
  );  
  上面這個函式是通過父視窗的控制代碼取得子視窗的控制代碼,後面的兩個引數可以選用其中之一  
  另一個設定成NULL即可!

////////////////////////////////////////////////////////////////////////////////////////////////

在VC的視窗類中有一成員變數:m_hWnd ,它代表這個視窗的控制代碼。因此在VC中通過一些得到視窗指標的函式,然後再訪問它的成員變數,應該可以得到所要的控制代碼。
比如用這個函式得到視窗指標,然後訪問它的m_hWnd 。
AfxGetMainWnd( );

//////////////////////////////////////////////////////////////////////////////////////////////

VC:如何根據檔名來獲取程式程序和視窗控制代碼的程式碼:

根據系統程序中的模組名和執行檔名稱的匹配來查詢程式程序的程式碼如下(因為視窗類和視窗名都在變化,所以只能如此了)。

//做系統程序快照

Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

//找第一個程序

f = Process32First(Snapshot, &processListStr);

while(f)

{

 char *t1="3SMeeting.exe"; //這是執行檔名

 if (*processListStr.szExeFile ==*t1){

 sprintf( szHello, "ProcessID:%X  EXE:%s",processListStr.th32ProcessID,processListStr.szExeFile);

 TextOut(hdc, rt.left, rt.top, szHello,strlen(szHello));

break;

 }

 f = Process32Next(Snapshot, &processListStr); //繼續查詢

}

CloseHandle(Snapshot);

在VC中獲取其它視窗控制代碼的方法很多,但用FindWindow等要根據視窗類和視窗標題來查詢得到視窗控制代碼,正好碰到視窗類和視窗標題都是不斷變化的,下面的程式碼是我經過實踐得到的。

根據視窗名的一部分來獲取視窗的控制代碼,程式碼如下:

int i;

//以桌面為父視窗來查詢第一個主視窗

hWndPrevious   =   GetWindow(GetDesktopWindow(),GW_CHILD);

 LPTSTR m_pszExeName;

  while   (IsWindow(hWndPrevious))    

  {

  int i=GetWindowTextLength(hWndPrevious);

  GetWindowText(hWndPrevious,szHello,i);//獲取視窗標題

//這裡我的視窗中只有下面幾個字是不變的

  if (strstr(szHello,"當前使用者數:")){

   sprintf( szHello1, "Hwnd:%X  Title:%s",hWndPrevious,szHello);

 TextOut(hdc, rt.left, rt.top, szHello1,strlen(szHello1));

 break;

//匹配,這時hWndPrevious就是所要找的視窗的控制代碼

  }

  hWndPrevious   =  GetWindow(hWndPrevious,GW_HWNDNEXT);

  }    

歡迎指正。

------------------------------------------------------------------------------------------------

windows使用兩種字符集ansi和unicode,前者就是通常使用的單位元組方式,但這種方式處理象中文這樣的雙位元組字元不方便,容易出現半個漢字的情況。而後者是雙位元組方式,方便處理雙位元組字元。windows nt的所有與字元有關的函式都提供兩種方式的版本,而windows 9x只支援ansi方式。_t一般同字常數相關,如_t("hello")。如果你編譯一個程式為ansi方式,_t實際不起任何作用。而如果編譯一個程式為unicode方式,則編譯器會把"hello"字串以unicode方式儲存。_t和_l的區別在於,_l不管你是以什麼方式編譯,一律以以unicode方式儲存。

------------------------------------------------------------------------------------------------ 

派生和繼承


1.派生類的概念

    以面向物件的程式設計的觀點來看,繼承表達的是物件類之間的相互關係。這種關係使得某類物件可以繼承另外一類物件的特徵和能力。如果一類物件繼承了另一類物件的特徵和能力,這個類就叫做所繼承類的派生類。

1.1宣告一個派生類的一般格式是:

   class 派生類名:派生方式( public or private)基類名{

//派生類新增加或修改的資料和成員函式};

1.2派生類建構函式和解構函式的執行順序

當派生類中不含物件成員時

●在建立派生類物件時,建構函式的執行順序是:基類的建構函式→派生類的建構函式;

●在撤消派生類物件時,解構函式的執行順序是:派生類的建構函式→基類的建構函式。

當派生類中含有物件成員時

●在定義派生類物件時,建構函式的執行順序:基類的建構函式→物件成員的建構函式→派生類的建構函式;

●在撤消派生類物件時,解構函式的執行順序:派生類的建構函式→物件成員的建構函式→基類的建構函式。
.
1.3派生類建構函式和解構函式的構造規則

當基類中無顯式定義建構函式或有函式但無引數時派生類可以不向基類傳遞引數,甚至可以不定義建構函式;
當基類中有建構函式且含有引數時,派生類必須定義建構函式以提供把引數傳遞給基類建構函式的途徑。

⑴派生類建構函式的一般格式為:

派生類::派生類建構函式名(引數表):基類建構函式名(引數表){
// 派生類新增成員
}

⑵當派生類中含有物件成員時,其建構函式的一般形式為:
派生類::派生類建構函式名(引數表):基類建構函式名(引數表),物件成員名(引數表),……物件成員名n(引數表)

{//新增資料初始化(不包括物件成員)
}

2.多重繼承

前面我們介紹的派生類只有一個基類,稱為單基派生或單一繼承。在實際運用中,我們經常需要派生類同時具有多個基類,這種方法稱為多基派生或多重繼承。

2.1多重繼承的宣告:

在C++中,宣告具有兩個以上基類的派生類與宣告單基派生類的形式類似,只需將要繼承的多個基類用逗號分開即可。

在多重繼承中,公有派生和私有派生對於基類成員在派生類的可訪問性與單繼承的規則相同。
另外,對基類成員的訪問必須是無二義的,若兩個基類中具有同名的資料成員或成員函式,使用成員名限定來消除二義性,若派生類中新增成員或成員函式與基類成員或成員函式同名,則派生類會覆蓋外層同名成員,也須使用作用域分辨符。

2.2多重繼承的建構函式和解構函式:

    多重繼承的建構函式的定義形式與單繼承建構函式的定義形式類似,只有n個基類的建構函式之間用“,”分隔。

    多重繼承的建構函式的執行順序與單繼承建構函式的執行順序相同,也是遵循先執行基類的建構函式,再執行物件成員的建構函式,最後執行派生類建構函式的原則。在多個基類之間,則嚴格按照派生類宣告是從左到右的順序來排列先後。而解構函式的執行順序與建構函式的執行順序相反。

2.3虛基類:

    如果某個派生類的部分或全部直接基類是從另一個共同的基類派生而來,在這些基類中,從上一級基類繼承來的成員就有相同的名稱,則在這個派生類中訪問這個共同的基類中的成員時,可能會產生二義性,此時,可定義虛基類。這就要求在其直接基類的定義中,使用關鍵字virtual將那個共同的基類定義為虛基類,其語法形式如下:

class 派生類名: virtual 派生方式 基類

    虛基類的初始化與一般的多重繼承的初始化在語法上是一樣的 ,但建構函式的呼叫順序不同,虛基類建構函式的呼叫順序是這樣規定的:

1)在同一層次中,先呼叫虛基類的建構函式,接下來依次是非虛基類的建構函式,物件成員的建構函式,派生類的建構函式。

2)若同一層次中包含多個虛基類,這些虛基類的建構函式按對他們說明的先後次序呼叫

3)若虛基類由非虛基類派生而來,則仍然先呼叫基類建構函式,再呼叫派生類建構函式。

3.注意

1.基類向派生類提供它的行為和結構,派生類負責正確初始化基類物件

2.要用正確的引數呼叫直接基類的建構函式,以作為每個派生類建構函式的一部分(討論)

3.普通成員函式不能用這種語法呼叫基類方法

4.類只負責其直接基類的構造。但存在虛基類時有所不同

5.派生類建構函式的引數要包括自己使用的和基類需要使用的所用引數

6.派生類繼承基類的行為和結構,但不繼承建構函式和解構函式

7.要在派生類拷貝建構函式中呼叫基類的拷貝建構函式

8.要在派生類賦值運算子中呼叫基類的賦值運算子

9. 派生類解構函式並不明確呼叫基類的解構函式

10. 所用虛基類都由最後的派生類的建構函式所初始化。當建立物件時,將忽略子物件建構函式內部對虛基類建構函式的呼叫。

11.公有繼承是繼承的主要模式,私有繼承只在特殊情況下用(如實現堆疊類可從列表類中繼承,但它不是某種列表,重新匯出私有基類的成員。)私有繼承沒有多型性。

12.在單一繼承能實現目的時,不要用多重繼承

13.繼承的優點:程式碼重用,在正在執行的程式中加入新類和新功能(如衛星、病人監護),動態聯編,多型性。


------------------------------------------------------------------------------------------------

事件是由應用程式觸發的,而訊息是作業系統感知到的應用程式的事件,該事件將被轉換成訊息傳送到應用程式的訊息佇列中。訊息可以由作業系統產生,也可以由另一個訊息產生,訊息的處理函式就是視窗過程函式。

    訊息是通過MSG結構來實現的,該結構的定義如下:

    typedef struct {

        HWND hwnd;              //接收訊息的視窗控制代碼,如果是執行緒訊息,則為NULL

        UINT message;          //訊息的標識

        WPARAM wParam;     //附件函式,其精確含義取決於訊息成員的值

        LPARAM lParam;        //附件函式,其精確含義取決於訊息成員的值

        DWORD time;            //訊息被投遞的時間

        POINT pt;                   //訊息被投遞時游標在螢幕中的位置

    } MSG, *PMSG;


-------------------------------------------------------------------------------------------------

1、要認識到在任何情況下都不能使用指向空值的引用。但指標可以給他賦空值。

2、在C++裡,引用應被初始化。但指標可以是未初始化的指標(不過空指標合法但危險)。

3、不存在指向空值的引用這個事實意味著使用引用的程式碼效率比使用指標的要高。因為在使用引用之前不需要測試它的合法性。相反,指標則應該總是被測試,防止其為空

4、指標與引用的另一個重要的不同是指標可以被重新賦值以指向另一個不同的物件。但是引用則總是指向在初始化時被指定的物件,以後不能改變。

    總的來說,在以下情況下你應該使用指標,一是你考慮到存在不指向任何物件的可能(在這種情況下,你能夠設定指標為空),二是你需要能夠在不同的時刻指向不同的物件(在這種情況下,你能改變指標的指向)。如果總是指向一個物件並且一旦指向一個物件後就不會改變指向,那麼你應該使用引用。

還有一種情況,就是當你過載某個操作符時,你應該使用引用。最普通的例子是操作符[]。這個操作符典型的用法是返回一個目標物件,其能被賦值。

------------------------------------------------------------------------------------------------