c#委托與事件、消息、WndProc用法(轉)


 

c#委托與事件 心得 
c#用委托來實現事件通知機制。委托相當與c++函數指針。整個過程涉及一個呼叫者,一個被呼叫者,還有就是這個委托。

 


- 實現步驟
有以下幾步: 1. 申明委托, 2.定義呼叫者和調用的函數, 3.定義被呼叫者和具體實現的函數(被調用的函數)

 

1.申明委托 ,在包里或者類里,public
 public delegate void PlayGame(Object sender, EventArgs e); 
2.定義呼叫者(類LetsGame)和調用委托的函數,在呼叫者里要有委托的實例(呼叫者扔出一個委托,被呼叫者給這個委托賦值)
class LetsGame{ 
    public event PlayGame theGame; 
    public void startPlay(EventArgs e){ 
        if(theGame != null){ 
        theGame(this,e); 
    } 
}

 

3. 定義被呼叫者(類MS)和具體實現的函數(被調用的函數),也就是concrete class的實現或者叫函數指針實例。打個比方,在一個叫MS的類中實現.MS中對呼叫者中委托的實例進行賦值.
class MS {
    public MS(LetsGame lg) {
        lg.theGame += new PlayGame(MSPlayGame);
    }
    public void MSPlayGame(Object sender, EventArgs e){ 
        Console.WriteLine("Who laughs the last who wins"); 
    } 
}

 

這樣當調用LetsGame.startPlay的時候就會調用MS.MSPlayGame.

 

 

 

- 實際應用
對照一下c#的GUI事件處理或者asp.net的web控件事件處理,能幫我們更好的理解委托和事件.大家一定很熟悉asp.net里下面的代碼
private void InitializeComponent()
{    
    
    this.Button1.Click += new System.EventHandler(this.Button1_Click);
    
}

 

 

 

private void Button1_Click(object sender, System.EventArgs e)
{
    //do sth
}

 

這就是用委托來實現事件.你可能發現我們並沒有給它聲明委托對象並通過event關鍵字來引用該委托對象,那是因為asp.net早就幫我們做好了該項工作,其委托對象是System.EventHandler. Button1相當於上面的LetsGame的實例,是呼叫者,Button1_Click是被呼叫方法.當你click Button1后,Button1就會調用Button1_Click.

 


-雜項
我覺得這種機制和design pattern里的observer很類似,我們完全可以用observer來達到同樣的效果,但是用委托更靈活,不需要定義一個interface然后所有的concrete class都實現某個方法,函數指針(委托)更靈活.

 

還有,委托不一定非要和事件一起用,單獨用的時候就是函數指針.

 

 

 

 

 

 

 

-------------------------------------------------------------------------------
WndProc(ref Message m)
protected override void WndProc(ref Message m) 

    const int WM_SYSCOMMAND = 0x0112; 
    const int SC_CLOSE = 0xF060; 
    if (m.Msg == WM_SYSCOMMAND && (int) m.WParam == SC_CLOSE) 
    { 
        // 屏蔽傳入的消息事件 
        this.WindowState = FormWindowState.Minimized; 
        return; 
     } 
    base.WndProc(ref m); 
}

 

protected override void WndProc(ref    Message m)
{
     const int WM_SYSCOMMAND = 0x0112;
     const int SC_CLOSE = 0xF060;
     const int SC_MINIMIZE = 0xF020;
     if (m.Msg == WM_SYSCOMMAND && ((int)m.WParam == SC_MINIMIZE || (int)m.WParam == SC_CLOSE))
     {
         //最小化到系統欄 
         this.Hide();
         return;
     }
     base.WndProc(ref    m);
}

 

----------------------------------------------
不規則窗體拖動

 

using System.Runtime.InteropServices;

 

[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
[DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_MOVE = 0xF010;
public const int HTCAPTION = 0x0002;

 

public void ShapedForm_MouseDown(object sender, MouseEventArgs e) 

ReleaseCapture();
SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}

 

-------------------------------------------------------------------
protected override void WndProc(ref Message m)
  {
  //攔截窗體最小化按鈕消息,調用隱藏動畫並隱藏窗體
  if (m.Msg == (int)hyFrameWork.win32Api.Enum.WinMsg.WM_SYSCOMMAND)
  {
  if (m.WParam.ToInt32() == (int)hyFrameWork.win32Api.Enum.ECNCSysCommandConstants.SC_MINIMIZE)
  {
  formShowControl(false);
  return;
  }
  }
  base.WndProc(ref m);
  }
  -------------------------------------------
  大體的消息說明,你自己看吧 
WM_NULL = $0000; 
WM_CREATE = $0001; 
應用程序創建一個窗口 
WM_DESTROY = $0002; 
一個窗口被銷毀 
WM_MOVE = $0003; 
移動一個窗口 
WM_SIZE = $0005; 
改變一個窗口的大小 
WM_ACTIVATE = $0006; 
一個窗口被激活或失去激活狀態; 
WM_SETFOCUS = $0007; 
獲得焦點后 
WM_KILLFOCUS = $0008; 
失去焦點 
WM_ENABLE = $000A; 
改變enable狀態 
WM_SETREDRAW = $000B; 
設置窗口是否能重畫 
WM_SETTEXT = $000C; 
應用程序發送此消息來設置一個窗口的文本 
WM_GETTEXT = $000D; 
應用程序發送此消息來復制對應窗口的文本到緩沖區 
WM_GETTEXTLENGTH = $000E; 
得到與一個窗口有關的文本的長度(不包含空字符) 
WM_PAINT = $000F; 
要求一個窗口重畫自己 
WM_CLOSE = $0010; 
當一個窗口或應用程序要關閉時發送一個信號 
WM_QUERYENDSESSION = $0011; 
當用戶選擇結束對話框或程序自己調用ExitWindows函數 
WM_QUIT = $0012; 
用來結束程序運行或當程序調用postquitmessage函數 
WM_QUERYOPEN = $0013; 
當用戶窗口恢復以前的大小位置時,把此消息發送給某個圖標 
WM_ERASEBKGND = $0014; 
當窗口背景必須被擦除時(例在窗口改變大小時) 
WM_SYSCOLORCHANGE = $0015; 
當系統顏色改變時,發送此消息給所有頂級窗口 
WM_ENDSESSION = $0016; 
當系統進程發出WM_QUERYENDSESSION消息后,此消息發送給應用程序, 
通知它對話是否結束 
WM_SYSTEMERROR = $0017; 
WM_SHOWWINDOW = $0018; 
當隱藏或顯示窗口是發送此消息給這個窗口 
WM_ACTIVATEAPP = $001C; 
發此消息給應用程序哪個窗口是激活的,哪個是非激活的; 
WM_FONTCHANGE = $001D; 
當系統的字體資源庫變化時發送此消息給所有頂級窗口 
WM_TIMECHANGE = $001E; 
當系統的時間變化時發送此消息給所有頂級窗口 
WM_CANCELMODE = $001F; 
發送此消息來取消某種正在進行的摸態(操作) 
WM_SETCURSOR = $0020; 
如果鼠標引起光標在某個窗口中移動且鼠標輸入沒有被捕獲時,就發消息給某個窗口 
WM_MOUSEACTIVATE = $0021; 
當光標在某個非激活的窗口中而用戶正按着鼠標的某個鍵發送此消息給當前窗口 
WM_CHILDACTIVATE = $0022; 
發送此消息給MDI子窗口當用戶點擊此窗口的標題欄,或當窗口被激活,移動,改變大小 
WM_QUEUESYNC = $0023; 
此消息由基於計算機的訓練程序發送,通過WH_JOURNALPALYBACK的hook程序 
分離出用戶輸入消息 
WM_GETMINMAXINFO = $0024; 
此消息發送給窗口當它將要改變大小或位置; 
WM_PAINTICON = $0026; 
發送給最小化窗口當它圖標將要被重畫 
WM_ICONERASEBKGND = $0027; 
此消息發送給某個最小化窗口,僅當它在畫圖標前它的背景必須被重畫 
WM_NEXTDLGCTL = $0028; 
發送此消息給一個對話框程序去更改焦點位置 
WM_SPOOLERSTATUS = $002A; 
每當打印管理列隊增加或減少一條作業時發出此消息 
WM_DRAWITEM = $002B; 
當button,combobox,listbox,menu的可視外觀改變時發送 
此消息給這些空件的所有者 
WM_MEASUREITEM = $002C; 
當button, combo box, list box, list view control, or menu item 被創建時 
發送此消息給控件的所有者 
WM_DELETEITEM = $002D; 
當the list box 或 combo box 被銷毀 或 當 某些項被刪除通過LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息 
WM_VKEYTOITEM = $002E; 
此消息有一個LBS_WANTKEYBOARDINPUT風格的發出給它的所有者來響應WM_KEYDOWN消息 
WM_CHARTOITEM = $002F; 
此消息由一個LBS_WANTKEYBOARDINPUT風格的列表框發送給他的所有者來響應WM_CHAR消息 
WM_SETFONT = $0030; 
當繪制文本時程序發送此消息得到控件要用的顏色 
WM_GETFONT = $0031; 
應用程序發送此消息得到當前控件繪制文本的字體 
WM_SETHOTKEY = $0032; 
應用程序發送此消息讓一個窗口與一個熱鍵相關連 
WM_GETHOTKEY = $0033; 
應用程序發送此消息來判斷熱鍵與某個窗口是否有關聯 
WM_QUERYDRAGICON = $0037; 
此消息發送給最小化窗口,當此窗口將要被拖放而它的類中沒有定義圖標,應用程序能 
返回一個圖標或光標的句柄,當用戶拖放圖標時系統顯示這個圖標或光標 
WM_COMPAREITEM = $0039; 
發送此消息來判定combobox或listbox新增加的項的相對位置 
WM_GETOBJECT = $003D; 
WM_COMPACTING = $0041; 
顯示內存已經很少了 
WM_WINDOWPOSCHANGING = $0046; 
發送此消息給那個窗口的大小和位置將要被改變時,來調用setwindowpos函數或其它窗口管理函數 
WM_WINDOWPOSCHANGED = $0047; 
發送此消息給那個窗口的大小和位置已經被改變時,來調用setwindowpos函數或其它窗口管理函數 
WM_POWER = $0048;(適用於16位的windows) 
當系統將要進入暫停狀態時發送此消息 
WM_COPYDATA = $004A; 
當一個應用程序傳遞數據給另一個應用程序時發送此消息 
WM_CANCELJOURNAL = $004B; 
當某個用戶取消程序日志激活狀態,提交此消息給程序 
WM_NOTIFY = $004E; 
當某個控件的某個事件已經發生或這個控件需要得到一些信息時,發送此消息給它的父窗口 
WM_INPUTLANGCHANGEREQUEST = $0050; 
當用戶選擇某種輸入語言,或輸入語言的熱鍵改變 
WM_INPUTLANGCHANGE = $0051; 
當平台現場已經被改變后發送此消息給受影響的最頂級窗口 
WM_TCARD = $0052; 
當程序已經初始化windows幫助例程時發送此消息給應用程序 
WM_HELP = $0053; 
此消息顯示用戶按下了F1,如果某個菜單是激活的,就發送此消息個此窗口關聯的菜單,否則就 
發送給有焦點的窗口,如果當前都沒有焦點,就把此消息發送給當前激活的窗口 
WM_USERCHANGED = $0054; 
當用戶已經登入或退出后發送此消息給所有的窗口,當用戶登入或退出時系統更新用戶的具體 
設置信息,在用戶更新設置時系統馬上發送此消息; 
WM_NOTIFYFORMAT = $0055; 
公用控件,自定義控件和他們的父窗口通過此消息來判斷控件是使用ANSI還是UNICODE結構 
在WM_NOTIFY消息,使用此控件能使某個控件與它的父控件之間進行相互通信 
WM_CONTEXTMENU = $007B; 
當用戶某個窗口中點擊了一下右鍵就發送此消息給這個窗口 
WM_STYLECHANGING = $007C; 
當調用SETWINDOWLONG函數將要改變一個或多個 窗口的風格時發送此消息給那個窗口 
WM_STYLECHANGED = $007D; 
當調用SETWINDOWLONG函數一個或多個 窗口的風格后發送此消息給那個窗口 
WM_DISPLAYCHANGE = $007E; 
當顯示器的分辨率改變后發送此消息給所有的窗口 
WM_GETICON = $007F; 
此消息發送給某個窗口來返回與某個窗口有關連的大圖標或小圖標的句柄; 
WM_SETICON = $0080; 
程序發送此消息讓一個新的大圖標或小圖標與某個窗口關聯; 
WM_NCCREATE = $0081; 
當某個窗口第一次被創建時,此消息在WM_CREATE消息發送前發送; 
WM_NCDESTROY = $0082; 
此消息通知某個窗口,非客戶區正在銷毀 
WM_NCCALCSIZE = $0083; 
當某個窗口的客戶區域必須被核算時發送此消息 
WM_NCHITTEST = $0084;//移動鼠標,按住或釋放鼠標時發生 
WM_NCPAINT = $0085; 
程序發送此消息給某個窗口當它(窗口)的框架必須被繪制時; 
WM_NCACTIVATE = $0086; 
此消息發送給某個窗口 僅當它的非客戶區需要被改變來顯示是激活還是非激活狀態; 
WM_GETDLGCODE = $0087; 
發送此消息給某個與對話框程序關聯的控件,widdows控制方位鍵和TAB鍵使輸入進入此控件 
通過響應WM_GETDLGCODE消息,應用程序可以把他當成一個特殊的輸入控件並能處理它 
WM_NCMOUSEMOVE = $00A0; 
當光標在一個窗口的非客戶區內移動時發送此消息給這個窗口 //非客戶區為:窗體的標題欄及窗 
的邊框體 
WM_NCLBUTTONDOWN = $00A1; 
當光標在一個窗口的非客戶區同時按下鼠標左鍵時提交此消息 
WM_NCLBUTTONUP = $00A2; 
當用戶釋放鼠標左鍵同時光標某個窗口在非客戶區十發送此消息; 
WM_NCLBUTTONDBLCLK = $00A3; 
當用戶雙擊鼠標左鍵同時光標某個窗口在非客戶區十發送此消息 
WM_NCRBUTTONDOWN = $00A4; 
當用戶按下鼠標右鍵同時光標又在窗口的非客戶區時發送此消息 
WM_NCRBUTTONUP = $00A5; 
當用戶釋放鼠標右鍵同時光標又在窗口的非客戶區時發送此消息 
WM_NCRBUTTONDBLCLK = $00A6; 
當用戶雙擊鼠標右鍵同時光標某個窗口在非客戶區十發送此消息 
WM_NCMBUTTONDOWN = $00A7; 
當用戶按下鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 
WM_NCMBUTTONUP = $00A8; 
當用戶釋放鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 
WM_NCMBUTTONDBLCLK = $00A9; 
當用戶雙擊鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 
WM_KEYFIRST = $0100; 
WM_KEYDOWN = $0100; 
//按下一個鍵 
WM_KEYUP = $0101; 
//釋放一個鍵 
WM_CHAR = $0102; 
//按下某鍵,並已發出WM_KEYDOWN, WM_KEYUP消息 
WM_DEADCHAR = $0103; 
當用translatemessage函數翻譯WM_KEYUP消息時發送此消息給擁有焦點的窗口 
WM_SYSKEYDOWN = $0104; 
當用戶按住ALT鍵同時按下其它鍵時提交此消息給擁有焦點的窗口; 
WM_SYSKEYUP = $0105; 
當用戶釋放一個鍵同時ALT 鍵還按着時提交此消息給擁有焦點的窗口 
WM_SYSCHAR = $0106; 
當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后提交此消息給擁有焦點的窗口 
WM_SYSDEADCHAR = $0107; 
當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后發送此消息給擁有焦點的窗口 
WM_KEYLAST = $0108; 
WM_INITDIALOG = $0110; 
在一個對話框程序被顯示前發送此消息給它,通常用此消息初始化控件和執行其它任務 
WM_COMMAND = $0111; 
當用戶選擇一條菜單命令項或當某個控件發送一條消息給它的父窗口,一個快捷鍵被翻譯 
WM_SYSCOMMAND = $0112; 
當用戶選擇窗口菜單的一條命令或當用戶選擇最大化或最小化時那個窗口會收到此消息 
WM_TIMER = $0113; //發生了定時器事件 
WM_HSCROLL = $0114; 
當一個窗口標准水平滾動條產生一個滾動事件時發送此消息給那個窗口,也發送給擁有它的控件 
WM_VSCROLL = $0115; 
當一個窗口標准垂直滾動條產生一個滾動事件時發送此消息給那個窗口也,發送給擁有它的控件 WM_INITMENU = $0116; 
當一個菜單將要被激活時發送此消息,它發生在用戶菜單條中的某項或按下某個菜單鍵,它允許 
程序在顯示前更改菜單 
WM_INITMENUPOPUP = $0117; 
當一個下拉菜單或子菜單將要被激活時發送此消息,它允許程序在它顯示前更改菜單,而不要 
改變全部 
WM_MENUSELECT = $011F; 
當用戶選擇一條菜單項時發送此消息給菜單的所有者(一般是窗口) 
WM_MENUCHAR = $0120; 
當菜單已被激活用戶按下了某個鍵(不同於加速鍵),發送此消息給菜單的所有者; 
WM_ENTERIDLE = $0121; 
當一個模態對話框或菜單進入空載狀態時發送此消息給它的所有者,一個模態對話框或菜單進入空載狀態就是在處理完一條或幾條先前的消息后沒有消息它的列隊中等待 
WM_MENURBUTTONUP = $0122; 
WM_MENUDRAG = $0123; 
WM_MENUGETOBJECT = $0124; 
WM_UNINITMENUPOPUP = $0125; 
WM_MENUCOMMAND = $0126; 
WM_CHANGEUISTATE = $0127; 
WM_UPDATEUISTATE = $0128; 
WM_QUERYUISTATE = $0129; 
WM_CTLCOLORMSGBOX = $0132; 
在windows繪制消息框前發送此消息給消息框的所有者窗口,通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置消息框的文本和背景顏色 
WM_CTLCOLOREDIT = $0133; 
當一個編輯型控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置編輯框的文本和背景顏色 
WM_CTLCOLORLISTBOX = $0134; 
當一個列表框控件將要被繪制前發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置列表框的文本和背景顏色 
WM_CTLCOLORBTN = $0135; 
當一個按鈕控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置按紐的文本和背景顏色 
WM_CTLCOLORDLG = $0136; 
當一個對話框控件將要被繪制前發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置對話框的文本背景顏色 
WM_CTLCOLORSCROLLBAR= $0137; 
當一個滾動條控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置滾動條的背景顏色 
WM_CTLCOLORSTATIC = $0138; 
當一個靜態控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以 
通過使用給定的相關顯示設備的句柄來設置靜態控件的文本和背景顏色 
WM_MOUSEFIRST = $0200; 
WM_MOUSEMOVE = $0200; 
// 移動鼠標 
WM_LBUTTONDOWN = $0201; 
//按下鼠標左鍵 
WM_LBUTTONUP = $0202; 
//釋放鼠標左鍵 
WM_LBUTTONDBLCLK = $0203; 
//雙擊鼠標左鍵 
WM_RBUTTONDOWN = $0204; 
//按下鼠標右鍵 
WM_RBUTTONUP = $0205; 
//釋放鼠標右鍵 
WM_RBUTTONDBLCLK = $0206; 
//雙擊鼠標右鍵 
WM_MBUTTONDOWN = $0207; 
//按下鼠標中鍵 
WM_MBUTTONUP = $0208; 
//釋放鼠標中鍵 
WM_MBUTTONDBLCLK = $0209; 
//雙擊鼠標中鍵 
WM_MOUSEWHEEL = $020A; 
當鼠標輪子轉動時發送此消息個當前有焦點的控件 
WM_MOUSELAST = $020A; 
WM_PARENTNOTIFY = $0210; 
當MDI子窗口被創建或被銷毀,或用戶按了一下鼠標鍵而光標在子窗口上時發送此消息給它的父窗口 
WM_ENTERMENULOOP = $0211; 
發送此消息通知應用程序的主窗口that已經進入了菜單循環模式 
WM_EXITMENULOOP = $0212; 
發送此消息通知應用程序的主窗口that已退出了菜單循環模式 
WM_NEXTMENU = $0213; 
WM_SIZING = 532; 
當用戶正在調整窗口大小時發送此消息給窗口;通過此消息應用程序可以監視窗口大小和位置 
也可以修改他們 
WM_CAPTURECHANGED = 533; 
發送此消息 給窗口當它失去捕獲的鼠標時; 
WM_MOVING = 534; 
當用戶在移動窗口時發送此消息,通過此消息應用程序可以監視窗口大小和位置 
也可以修改他們; 
WM_POWERBROADCAST = 536; 
此消息發送給應用程序來通知它有關電源管理事件; 
WM_DEVICECHANGE = 537; 
當設備的硬件配置改變時發送此消息給應用程序或設備驅動程序 
WM_IME_STARTCOMPOSITION = $010D; 
WM_IME_ENDCOMPOSITION = $010E; 
WM_IME_COMPOSITION = $010F; 
WM_IME_KEYLAST = $010F; 
WM_IME_SETCONTEXT = $0281; 
WM_IME_NOTIFY = $0282; 
WM_IME_CONTROL = $0283; 
WM_IME_COMPOSITIONFULL = $0284; 
WM_IME_SELECT = $0285; 
WM_IME_CHAR = $0286; 
WM_IME_REQUEST = $0288; 
WM_IME_KEYDOWN = $0290; 
WM_IME_KEYUP = $0291; 
WM_MDICREATE = $0220; 
應用程序發送此消息給多文檔的客戶窗口來創建一個MDI 子窗口 
WM_MDIDESTROY = $0221; 
應用程序發送此消息給多文檔的客戶窗口來關閉一個MDI 子窗口 
WM_MDIACTIVATE = $0222; 
應用程序發送此消息給多文檔的客戶窗口通知客戶窗口激活另一個MDI子窗口,當客戶窗口收到 
此消息后,它發出WM_MDIACTIVE消息給MDI子窗口(未激活)激活它; 
WM_MDIRESTORE = $0223; 
程序 發送此消息給MDI客戶窗口讓子窗口從最大最小化恢復到原來大小 
WM_MDINEXT = $0224; 
程序 發送此消息給MDI客戶窗口激活下一個或前一個窗口 
WM_MDIMAXIMIZE = $0225; 
程序發送此消息給MDI客戶窗口來最大化一個MDI子窗口; 
WM_MDITILE = $0226; 
程序 發送此消息給MDI客戶窗口以平鋪方式重新排列所有MDI子窗口 
WM_MDICASCADE = $0227; 
程序 發送此消息給MDI客戶窗口以層疊方式重新排列所有MDI子窗口 
WM_MDIICONARRANGE = $0228; 
程序 發送此消息給MDI客戶窗口重新排列所有最小化的MDI子窗口 
WM_MDIGETACTIVE = $0229; 
程序 發送此消息給MDI客戶窗口來找到激活的子窗口的句柄 
WM_MDISETMENU = $0230; 
程序 發送此消息給MDI客戶窗口用MDI菜單代替子窗口的菜單 
WM_ENTERSIZEMOVE = $0231; 
WM_EXITSIZEMOVE = $0232; 
WM_DROPFILES = $0233; 
WM_MDIREFRESHMENU = $0234; 
WM_MOUSEHOVER = $02A1; 
WM_MOUSELEAVE = $02A3; 
WM_CUT = $0300; 
程序發送此消息給一個編輯框或combobox來刪除當前選擇的文本 
WM_COPY = $0301; 
程序發送此消息給一個編輯框或combobox來復制當前選擇的文本到剪貼板 
WM_PASTE = $0302; 
程序發送此消息給editcontrol或combobox從剪貼板中得到數據 
WM_CLEAR = $0303; 
程序發送此消息給editcontrol或combobox清除當前選擇的內容; 
WM_UNDO = $0304; 
程序發送此消息給editcontrol或combobox撤消最后一次操作 
WM_RENDERFORMAT = $0305;

 

WM_RENDERALLFORMATS = $0306; 
WM_DESTROYCLIPBOARD = $0307; 
當調用ENPTYCLIPBOARD函數時 發送此消息給剪貼板的所有者 
WM_DRAWCLIPBOARD = $0308; 
當剪貼板的內容變化時發送此消息給剪貼板觀察鏈的第一個窗口;它允許用剪貼板觀察窗口來 
顯示剪貼板的新內容; 
WM_PAINTCLIPBOARD = $0309; 
當剪貼板包含CF_OWNERDIPLAY格式的數據並且剪貼板觀察窗口的客戶區需要重畫; 
WM_VSCROLLCLIPBOARD = $030A; 
WM_SIZECLIPBOARD = $030B; 
當剪貼板包含CF_OWNERDIPLAY格式的數據並且剪貼板觀察窗口的客戶區域的大小已經改變是此消息通過剪貼板觀察窗口發送給剪貼板的所有者; 
WM_ASKCBFORMATNAME = $030C; 
通過剪貼板觀察窗口發送此消息給剪貼板的所有者來請求一個CF_OWNERDISPLAY格式的剪貼板的名字 
WM_CHANGECBCHAIN = $030D; 
當一個窗口從剪貼板觀察鏈中移去時發送此消息給剪貼板觀察鏈的第一個窗口; 
WM_HSCROLLCLIPBOARD = $030E; 
此消息通過一個剪貼板觀察窗口發送給剪貼板的所有者 ;它發生在當剪貼板包含CFOWNERDISPALY格式的數據並且有個事件在剪貼板觀察窗的水平滾動條上;所有者應滾動剪貼板圖象並更新滾動條的值; 
WM_QUERYNEWPALETTE = $030F; 
此消息發送給將要收到焦點的窗口,此消息能使窗口在收到焦點時同時有機會實現他的邏輯調色板 
WM_PALETTEISCHANGING= $0310; 
當一個應用程序正要實現它的邏輯調色板時發此消息通知所有的應用程序 
WM_PALETTECHANGED = $0311; 
此消息在一個擁有焦點的窗口實現它的邏輯調色板后發送此消息給所有頂級並重疊的窗口,以此 
來改變系統調色板 
WM_HOTKEY = $0312; 
當用戶按下由REGISTERHOTKEY函數注冊的熱鍵時提交此消息 
WM_PRINT = 791; 
應用程序發送此消息僅當WINDOWS或其它應用程序發出一個請求要求繪制一個應用程序的一部分; 
WM_PRINTCLIENT = 792; 
WM_HANDHELDFIRST = 856; 
WM_HANDHELDLAST = 863; 
WM_PENWINFIRST = $0380; 
WM_PENWINLAST = $038F; 
WM_COALESCE_FIRST = $0390; 
WM_COALESCE_LAST = $039F; 
WM_DDE_FIRST = $03E0; 
WM_DDE_INITIATE = WM_DDE_FIRST + 0; 
一個DDE客戶程序提交此消息開始一個與服務器程序的會話來響應那個指定的程序和主題名; 
WM_DDE_TERMINATE = WM_DDE_FIRST + 1; 
一個DDE應用程序(無論是客戶還是服務器)提交此消息來終止一個會話; 
WM_DDE_ADVISE = WM_DDE_FIRST + 2; 
一個DDE客戶程序提交此消息給一個DDE服務程序來請求服務器每當數據項改變時更新它 
WM_DDE_UNADVISE = WM_DDE_FIRST + 3; 
一個DDE客戶程序通過此消息通知一個DDE服務程序不更新指定的項或一個特殊的剪貼板格式的項 
WM_DDE_ACK = WM_DDE_FIRST + 4; 
此消息通知一個DDE(動態數據交換)程序已收到並正在處理WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIAT消息 
WM_DDE_DATA = WM_DDE_FIRST + 5; 
一個DDE服務程序提交此消息給DDE客戶程序來傳遞個一數據項給客戶或通知客戶的一條可用數據項 
WM_DDE_REQUEST = WM_DDE_FIRST + 6; 
一個DDE客戶程序提交此消息給一個DDE服務程序來請求一個數據項的值; 
WM_DDE_POKE = WM_DDE_FIRST + 7; 
一個DDE客戶程序提交此消息給一個DDE服務程序,客戶使用此消息來請求服務器接收一個未經同意的數據項;服務器通過答復WM_DDE_ACK消息提示是否它接收這個數據項; 
WM_DDE_EXECUTE = WM_DDE_FIRST + 8; 
一個DDE客戶程序提交此消息給一個DDE服務程序來發送一個字符串給服務器讓它象串行命令一樣被處理,服務器通過提交WM_DDE_ACK消息來作回應; 
WM_DDE_LAST = WM_DDE_FIRST + 8; 
WM_APP = $8000; 
WM_USER = $0400; 
此消息能幫助應用程序自定義私有消息; 
///////////////////////////////////////////////////////////////////// 
通知消息(Notification message)是指這樣一種消息,一個窗口內的子控件發生了一些事情,需要通 
知父窗口。通知消息只適用於標准的窗口控件如按鈕、列表框、組合框、編輯框,以及Windows 95公 
共控件如樹狀視圖、列表視圖等。例如,單擊或雙擊一個控件、在控件中選擇部分文本、操作控件的 
滾動條都會產生通知消息。 
按扭 
B N _ C L I C K E D //用戶單擊了按鈕 
B N _ D I S A B L E //按鈕被禁止 
B N _ D O U B L E C L I C K E D //用戶雙擊了按鈕 
B N _ H I L I T E //用戶加亮了按鈕 
B N _ PA I N T按鈕應當重畫 
B N _ U N H I L I T E加亮應當去掉 
組合框 
C B N _ C L O S E U P組合框的列表框被關閉 
C B N _ D B L C L K用戶雙擊了一個字符串 
C B N _ D R O P D O W N組合框的列表框被拉出 
C B N _ E D I T C H A N G E用戶修改了編輯框中的文本 
C B N _ E D I T U P D AT E編輯框內的文本即將更新 
C B N _ E R R S PA C E組合框內存不足 
C B N _ K I L L F O C U S組合框失去輸入焦點 
C B N _ S E L C H A N G E在組合框中選擇了一項 
C B N _ S E L E N D C A N C E L用戶的選擇應當被取消 
C B N _ S E L E N D O K用戶的選擇是合法的 
C B N _ S E T F O C U S組合框獲得輸入焦點 
編輯框 
E N _ C H A N G E編輯框中的文本己更新 
E N _ E R R S PA C E編輯框內存不足 
E N _ H S C R O L L用戶點擊了水平滾動條 
E N _ K I L L F O C U S編輯框正在失去輸入焦點 
E N _ M A X T E X T插入的內容被截斷 
E N _ S E T F O C U S編輯框獲得輸入焦點 
E N _ U P D AT E編輯框中的文本將要更新 
E N _ V S C R O L L用戶點擊了垂直滾動條消息含義 
列表框 
L B N _ D B L C L K用戶雙擊了一項 
L B N _ E R R S PA C E列表框內存不夠 
L B N _ K I L L F O C U S列表框正在失去輸入焦點 
L B N _ S E L C A N C E L選擇被取消 
L B N _ S E L C H A N G E選擇了另一項 
L B N _ S E T F O C U S列表框獲得輸入焦點 
------------------------------------------------------------------
static bool flag = false;
        protected override void WndProc(ref Message m)//C# 重寫 WndProc 移動窗口
        {
           switch (m.Msg) {
                 case 0x0200: //WM_MOUSEMOVE
                         if (flag)
                         {
                             PostMessage(this.Handle, 0x00A1,new IntPtr(2),m.LParam);//這里需要導入 user32.dll 
                         }
                         break;
                     case 0x201://WM_LBUTTONDOWN
                         flag = true;
                         break;
                     case 0x202://WM_LBUTTONUP
                        flag = false;

 

                               break;

 

                default:
                    base.WndProc(ref m);
                    break;
            }

 

      [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
------------------------------------------------------------
 [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wparam, int lparam);
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e); if (e.Button == MouseButtons.Left)//按下的是鼠標左鍵  
            {
                Capture = false;//釋放鼠標,使能夠手動操作         
                SendMessage(Handle, 0x00A1, 2, 0);//拖動窗體     
            }
        }
 --------------------------------------------------------
  protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case 0x0201://鼠標左鍵按下的消息
                    m.Msg = 0x00A1;//更改消息為非客戶區按下鼠標
                    m.LParam = IntPtr.Zero;//默認值
                    m.WParam = new IntPtr(2);//鼠標放在標題欄內
                    break;
            }
            base.WndProc(ref m);
        }
 ----------------------------------------------------

 

 重寫 WndProc函數來同時實現無標題欄的窗體移動和禁止雙擊窗體最大化

 

protected override void WndProc(ref Message m)
        {
            const int WM_NCHITTEST = 0x84;
            const int HTCLIENT = 0x01;
            const int HTCAPTION = 0x02;
            const int WM_SYSCOMMAND = 0x112;
            const int SC_MAXMIZE = 0xF030;
            const int WM_NCLBUTTONDBLCLK = 0xA3;
            switch (m.Msg)
            {
                case 0x4e:
                case 0xd:
                case 0xe:
                case 0x14:
                    base.WndProc(ref m);
                    break;
                case WM_NCHITTEST://鼠標點任意位置后可以拖動窗體
                    
                    this.DefWndProc(ref m);
                    if (m.Result.ToInt32() == HTCLIENT)
                    {
                        m.Result = new IntPtr(HTCAPTION);
                        return;
                    }
                    break;
                case WM_NCLBUTTONDBLCLK://禁止雙擊最大化
                    Console.WriteLine(this.WindowState);
                    
                        return;

 

                   
                    break;

 

                default:
                    
                    base.WndProc(ref m);
                    break;
            }
        }
----------------------------------------------------------
第一步,先在類的級別中申明兩個API函數,

 

  ///注冊熱鍵 
  [DllImport("user32.dll")] 
  private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, Keys vk); 
  ///卸載熱鍵 
  [DllImport("user32.dll")] 
  private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

 

  注意引入名字空間 System.Runtime.InteropServices;

 

  上面兩個函數參數的解釋:

 

  RegisterHotKey 函數中,

 

  hWnd為本程序窗口的句柄,在C#的窗口中直接用Handle屬性就可以引用窗口句柄

 

  id為熱鍵的標示符,是我們自己定義的,因為一個程序中可以定義多個熱鍵,所以要用這個字段來區別,具體用法見下

 

  fsModifiers為激活熱鍵時,是否和系統鍵組合使用,none:0 Alt:1 Ctrl:2 Shift:4,並且還可以用或運算來組合使用

 

  vk就是要定義的熱鍵,C#中按鍵都被包含在Keys枚舉中

 

  UnregisterHotKey 函數中,

 

  hWnd和RegisterHotKey 函數中是一樣的,id為要卸載的熱鍵標示

 

  第二步,在窗口的初始化中注冊熱鍵,例如 RegisterHotKey(Handle, 100, 0, Keys.F9);

 

  將些熱鍵識別為100,0表示不使用系統鍵,Keys.F9表示此熱鍵為F9,若要同時按Shift+Ctrl+F9,則第三個參數應該為 2|4 其實對二進制運算熟悉的朋友,               可以立刻算出 2|4=6

 

  第三步,可以響應熱鍵了:

 

  重寫窗體的WndProc函數,具體代碼為

 

  protected override void WndProc(ref Message m) { 
  //這個if的條件中固定的 
  if (m.Msg == 0x312) { 
  //這個if就在於判斷是哪個熱鍵,100對應上面RegisterHotKey函數中的第二個參數 
  if (m.WParam.ToInt32() == 100) { 
  //這里就是響應的函數 
  DoSomething(); 
  } 
  } 
  base.WndProc(ref m); 
  }

 

  WndProc()函數的功能就是處理Windows消息,在其它地方還將看到這個函數的妙用!

 

  第四步,在程序結束的時候調用UnregisterHotKey(Handle,100)卸載此熱鍵!

 

  WIN32

 

  第一步,在int WINAPI WinMain()函數中,

 

  while(GetMessage(&msg,NULL,0,0)){……}

 

  之前,注冊熱鍵

 

  RegisterHotKey(hWnd,100,0,VK_F9)

 

  VK_F9為WinUser.h中定義的宏,其他鍵也是用類似的形式進行定義,不過數字鍵和字母鍵,直接用'0','A'這樣的形式

 

  第二步,在while(GetMessage(&msg,NULL,0,0)) {……}

 

  循環體內,添加代碼

 

  //這是響應熱鍵條件,從WM_HOTKEY宏的定義中,可以看出來它代表的值為 0x312 ,和C#中的if條件是一致的 
  if(msg.message ==WM_HOTKEY) 
  { 
  //這里的條件用來判斷熱鍵的標示符 
  if(msg.wParam==100) 
  { 
  //這里調用想要執行的函數 
  DoSomething(); 
  } 
  }

 

  第三步,在while()循環結束后,調用 UnregisterHotKey(hWnd,100) 卸載熱鍵。

 

  MFC

 

  第一步,在MFC的窗體中添加其WM_HOTKEY消息的響應,

 

  void C熱鍵Dlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2) 
  { 
  //這里用來判斷熱鍵的標識符 
  if(nHotKeyId == 100) 
  { 
  //響應函數 
  DoSomething(); 
  } 
  CDialog::OnHotKey(nHotKeyId, nKey1, nKey2); 
  }

 

  第二步,在MFC窗體的初始化地方,添加注冊熱鍵的代碼:

 

  RegisterHotKey(m_hWnd,100,0,VK_F9);

 

  注意上面的字段m_hWnd,是CWnd類中字段,完成由MFC控制,我們只需要在適合地方引用就可以了。

 

  第三步,在窗體銷毀的地方調用 UnregisterHotKey(hWnd,100) 卸載熱鍵就可以了。

 

  到這里,大家可以已經掌握了在三種環境中設置系統級熱鍵的方法。筆者的體會是,在WIN32和C#中方法大概相同,筆者就是在C#的基礎上,嘗試着在WIN32中實現該功能,結果一次成功,但是在MFC中就走了一些彎路。
------------------------------------------------------------------------

 

  protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case 0x0005://change size: WM_SIZE
                    {
                        FormWindowState newState = FormWindowState.Normal;
                        switch (m.WParam.ToInt32())
                        {
                            case 0://SIZE_RESTORED
                                newState = FormWindowState.Normal;
                                break;
                            case 1://SIZE_MINIMIZED
                                newState = FormWindowState.Minimized;
                                break;
                            case 2://SIZE_MAXIMIZED
                                newState = FormWindowState.Maximized;
                                break;
                            default:
                                break;
                        }

 

                        if (newState != this.preWindowState)
                        {
                            this.OnWindowStateChanged(new WindowStateChangedEventArgs(this.preWindowState, newState));
                            this.preWindowState = newState;
                        }
                    }
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }
        #endregion
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM