近日與同事聊天提及到進程通信,還沒搞過,於是就谷歌一下。發現實現進程通信的方法也不只一種,調用Windows API的,用IPC通道的,共享內存,利用Socket、配置文件、注冊表等等。我后來嘗試的只有IPC通道和Windows API。而用API的還有分同步的SendMessage和異步的PostMessage。目前來看用API的大部分都是用SendMessage。我也分別介紹一下吧。
IPC通道
用IPC通道其實是Remoting里的其中一種,這種方式用起來感覺有點像Web Service。
首先定義一個類,這個類供通訊的目標進程調用。
1 public class IPCMessageModel:MarshalByRefObject 2 { 3 public string GetMessage() 4 { 5 return "Server work normally " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 6 } 7 8 public string GetSleepMessage() 9 { 10 System.Threading.Thread.Sleep(30*1000); 11 return "Server work slowly " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 12 } 13 }
這個類必須繼承 MarshalByRefObject。通訊的兩個進程都必須能訪問到這個類。
接下來則是通訊的服務端,只需要建一個控制台程序就行了。
1 IpcChannel serverchannel = new IpcChannel("testchannel"); 2 ChannelServices.RegisterChannel(serverchannel, false); 3 RemotingConfiguration.RegisterWellKnownServiceType(typeof(IPCMessageModel), "test", WellKnownObjectMode.Singleton);
這段話是我個人理解,首先要建立一個信道(或者說是一條管道吧),這個信道是要命名的,接着就要注冊這個信道,讓這個信道正式投入使用,這里的信道可以注冊,也可以注銷。此外還要注冊服務的類型,這個稱為服務器激活類型,就是用上面定義的那個IPCMessageModel。也要給它命名。這樣服務端就完成了。但是這里的類型只能被注冊成一個服務器激活類型,又不能注銷。
最后到客戶端,最簡單的也是建一個控制台程序就行了。
1 IpcChannel tcc = new IpcChannel(); 2 ChannelServices.RegisterChannel(tcc, false); 3 WellKnownClientTypeEntry remotEntry = new WellKnownClientTypeEntry(typeof(IPCMessageModel), "ipc://testchannel/test"); 4 RemotingConfiguration.RegisterWellKnownClientType(remotEntry); 5 6 IPCMessageModel st = new IPCMessageModel();
又來一段個人見解,同樣要建立一個信道,但這里由於是客戶端,就不需要命名了,但同樣要注冊這個信道才能使用,在注冊服務類型時就與服務端有出入了,又要建立一個服務器激活類型的實例,構造要用最上面的定義的IPCMessageModel類型,服務端的信道的名稱還有注冊服務類型的名稱在這里用的上了,URL就是以 "ipc://注冊的信道名稱/注冊的類型名稱"。在構造了一個IPCMessageModel的實例之后,就可以調用該類里面的方法了,也就是說可以通訊了。
使用SendMessage方法
調用Windows API的SendMessage方法,它的特點是,只要消息發出,等到接收端響應了,發送端才會往下執行,否則發送端就會一直卡着直到接收端響應。
首先來個發送端的定義,發送端最簡單的可以用建一個控制台程序
由於調用了API,免不了要聲明一下外部方法
1 [DllImport("User32.dll", EntryPoint = "SendMessage")] 2 private static extern int SendMessage(int hWnd, int Msg,int wParam,ref COPYDATASTRUCT lParam); 3 4 [DllImport("User32.dll", EntryPoint = "FindWindow")] 5 private static extern int FindWindow(string lpClassName,string lpWindowName); 6 7 8 public struct COPYDATASTRUCT 9 { 10 public IntPtr dwData; 11 public int cbData; 12 [MarshalAs(UnmanagedType.LPStr)] 13 public string lpData; 14 }
由於第一次使用系統API,可能見解會有些欠缺。方法的參數是可以隨需要而定的,我發現網上其他人寫的SendMessage方法的第一個參數是IntPtr類型的,而最后那個參數有些是直接用int類型。
SendMessage方法的各個參數如下,第一個是接受窗口的句柄,第二個是發送的消息,第三個和第四個是要傳遞的相關參數。至於第二個參數發送消息的代碼,在本文最后附帶了Windows已定義的各個消息代碼,是從別的博客里摘抄過來的。
FindWidows方法的第一參數沒搞懂,第二個是接受端窗體的名字。
由於發送方法還用到了一個結構體,於是定義了COPYDATASTRUCT結構體
發送端的代碼如下
1 int WINDOW_HANDLER = FindWindow(null, @"Form1"); 2 if (WINDOW_HANDLER != 0) 3 { 4 byte[] sarr = System.Text.Encoding.Default.GetBytes(msg); 5 int len = sarr.Length; 6 COPYDATASTRUCT cds; 7 cds.dwData = (IntPtr)100; 8 cds.lpData = msg; 9 cds.cbData = len + 1; 10 SendMessage(WINDOW_HANDLER, 0x004A, 0, ref cds); 11 }
首先要查找接收端,用FindWindow方法,按窗體標題欄的名稱來查找,為了確保消息發送的有效性,同時也避免一直等待接收消息的響應而造成的程序卡死,在發送前要對窗體查找結果進行判斷,如果查找不了窗體,那個WINDOW_HANDLER的值是0的。發送消息前那串代碼就就填寫發送的結構體各個字段的信息。
接着到接收端了,由於上面也提及到要查找窗體,因此接收端需要建一個窗體的程序
窗體主要重寫DefWndProc方法,要對消息作一個判斷,如果是發送端發來的消息,就執行相應操作,如果是其他消息,則調用原本DefWndProc方法
1 protected override void DefWndProc(ref System.Windows.Forms.Message m) 2 { 3 switch (m.Msg) 4 { 5 case 0x004A: 6 COPYDATASTRUCT mystr = new COPYDATASTRUCT(); 7 Type mytype = mystr.GetType(); 8 mystr = (COPYDATASTRUCT)m.GetLParam(mytype); 9 MessageBox.Show(mystr.lpData); 10 break; 11 default: 12 base.DefWndProc(ref m); 13 break; 14 } 15 }
同樣接收端要定義COPYDATASTRUCT結構體,或者把結構體放在一個dll里面,接收端和發送端共同引用。上面代碼7~8行是把發送來的結構體提取出來。
由發送端調用了SendMessage方法之后,一直卡着,等到接收端DefWnProc方法執行了收到信息之后,發送端才往下執行SendMessage方法后面的代碼。
使用PostMessage方法
發送端也是建一個簡單的控制台程序就行了,同樣要聲明一下外部方法。
1 [return: MarshalAs(UnmanagedType.Bool)] 2 [DllImport("user32.dll", SetLastError = true)] 3 private static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam); 4 5 [DllImport("User32.dll", EntryPoint = "FindWindow")] 6 private static extern int FindWindow( string lpClassName, string lpWindowName );
這里沒有定義發送消息用的結構體了,因為結構體附帶的數據在接收端查看不了,是null的。但是int類型就可以。發送的代碼跟SendMessage的大同小異
1 int WINDOW_HANDLER = FindWindow(null, @"Form1"); 2 3 if (WINDOW_HANDLER != 0) 4 { 5 PostMessage(WINDOW_HANDLER, 0x65, 65, 1); 6 }
也是要FindWindow,這里的消息代碼用了自定義的0x65,原本是跟SendMessage的一樣用0x004A的,但是在接收端老是收不了消息,嘗試一下自定義的,卻行了。
接收端也是一個窗體程序,同樣要重寫DefWnProc方法
1 protected override void DefWndProc(ref System.Windows.Forms.Message m) 2 { 3 switch (m.Msg) 4 { 5 case 0x65: 6 { 7 MessageBox.Show(m.WParam.ToInt32().ToString() + " " + m.LParam.ToString()+" "+mystr.lpData ); 8 } 9 break; 10 11 default: 12 base.DefWndProc(ref m); 13 break; 14 } 15 }
其實跟SendMessage的接收端代碼一樣的,只是消息代碼換了,case的標簽也要換一下,否則就不會處理了。
最后附帶一下系統定義好的消息代碼

WM_NULL = 0x0000; WM_CREATE = 0x0001; 應用程序創建一個窗口 WM_DESTROY = 0x0002; 一個窗口被銷毀 WM_MOVE = 0x0003; 移動一個窗口 WM_SIZE = 0x0005; 改變一個窗口的大小 WM_ACTIVATE = 0x0006; 一個窗口被激活或失去激活狀態; WM_SETFOCUS = 0x0007; 獲得焦點后 WM_KILLFOCUS = 0x0008; 失去焦點 WM_ENABLE = 0x000A; 改變enable狀態 WM_SETREDRAW = 0x000B; 設置窗口是否能重畫 WM_SETTEXT = 0x000C; 應用程序發送此消息來設置一個窗口的文本 WM_GETTEXT = 0x000D; 應用程序發送此消息來復制對應窗口的文本到緩沖區 WM_GETTEXTLENGTH = 0x000E; 得到與一個窗口有關的文本的長度(不包含空字符) WM_PAINT = 0x000F; 要求一個窗口重畫自己 WM_CLOSE = 0x0010; 當一個窗口或應用程序要關閉時發送一個信號 WM_QUERYENDSESSION = 0x0011; 當用戶選擇結束對話框或程序自己調用ExitWindows函數 WM_QUIT = 0x0012; 用來結束程序運行或當程序調用postquitmessage函數 WM_QUERYOPEN = 0x0013; 當用戶窗口恢復以前的大小位置時,把此消息發送給某個圖標 WM_ERASEBKGND = 0x0014; 當窗口背景必須被擦除時(例在窗口改變大小時) WM_SYSCOLORCHANGE = 0x0015; 當系統顏色改變時,發送此消息給所有頂級窗口 WM_ENDSESSION = 0x0016; 當系統進程發出WM_QUERYENDSESSION消息后,此消息發送給應用程序, 通知它對話是否結束 WM_SYSTEMERROR = 0x0017; WM_SHOWWINDOW = 0x0018; 當隱藏或顯示窗口是發送此消息給這個窗口 WM_ACTIVATEAPP = 0x001C; 發此消息給應用程序哪個窗口是激活的,哪個是非激活的; WM_FONTCHANGE = 0x001D; 當系統的字體資源庫變化時發送此消息給所有頂級窗口 WM_TIMECHANGE = 0x001E; 當系統的時間變化時發送此消息給所有頂級窗口 WM_CANCELMODE = 0x001F; 發送此消息來取消某種正在進行的摸態(操作) WM_SETCURSOR = 0x0020; 如果鼠標引起光標在某個窗口中移動且鼠標輸入沒有被捕獲時,就發消息給某個窗口 WM_MOUSEACTIVATE = 0x0021; 當光標在某個非激活的窗口中而用戶正按着鼠標的某個鍵發送此消息給當前窗口 WM_CHILDACTIVATE = 0x0022; 發送此消息給MDI子窗口當用戶點擊此窗口的標題欄,或當窗口被激活,移動,改變大小 WM_QUEUESYNC = 0x0023; 此消息由基於計算機的訓練程序發送,通過WH_JOURNALPALYBACK的hook程序 分離出用戶輸入消息 WM_GETMINMAXINFO = 0x0024; 此消息發送給窗口當它將要改變大小或位置; WM_PAINTICON = 0x0026; 發送給最小化窗口當它圖標將要被重畫 WM_ICONERASEBKGND = 0x0027; 此消息發送給某個最小化窗口,僅當它在畫圖標前它的背景必須被重畫 WM_NEXTDLGCTL = 0x0028; 發送此消息給一個對話框程序去更改焦點位置 WM_SPOOLERSTATUS = 0x002A; 每當打印管理列隊增加或減少一條作業時發出此消息 WM_DRAWITEM = 0x002B; 當button,combobox,listbox,menu的可視外觀改變時發送 此消息給這些空件的所有者 WM_MEASUREITEM = 0x002C; 當button, combo box, list box, list view control, or menu item 被創建時 發送此消息給控件的所有者 WM_DELETEITEM = 0x002D; 當the list box 或 combo box 被銷毀 或 當 某些項被刪除通過LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息 WM_VKEYTOITEM = 0x002E; 此消息有一個LBS_WANTKEYBOARDINPUT風格的發出給它的所有者來響應WM_KEYDOWN消息 WM_CHARTOITEM = 0x002F; 此消息由一個LBS_WANTKEYBOARDINPUT風格的列表框發送給他的所有者來響應WM_CHAR消息 WM_SETFONT = 0x0030; 當繪制文本時程序發送此消息得到控件要用的顏色 WM_GETFONT = 0x0031; 應用程序發送此消息得到當前控件繪制文本的字體 WM_SETHOTKEY = 0x0032; 應用程序發送此消息讓一個窗口與一個熱鍵相關連 WM_GETHOTKEY = 0x0033; 應用程序發送此消息來判斷熱鍵與某個窗口是否有關聯 WM_QUERYDRAGICON = 0x0037; 此消息發送給最小化窗口,當此窗口將要被拖放而它的類中沒有定義圖標,應用程序能返回一個圖標或光標的句柄,當用戶拖放圖標時系統顯示這個圖標或光標 WM_COMPAREITEM = 0x0039; 發送此消息來判定combobox或listbox新增加的項的相對位置 WM_GETOBJECT = 0x003D; WM_COMPACTING = 0x0041; 顯示內存已經很少了 WM_WINDOWPOSCHANGING = 0x0046; 發送此消息給那個窗口的大小和位置將要被改變時,來調用setwindowpos函數或其它窗口管理函數 WM_WINDOWPOSCHANGED = 0x0047; 發送此消息給那個窗口的大小和位置已經被改變時,來調用setwindowpos函數或其它窗口管理函數 WM_POWER = 0x0048;(適用於16位的windows) 當系統將要進入暫停狀態時發送此消息 WM_COPYDATA = 0x004A; 當一個應用程序傳遞數據給另一個應用程序時發送此消息 WM_CANCELJOURNAL = 0x004B; 當某個用戶取消程序日志激活狀態,提交此消息給程序 WM_NOTIFY = 0x004E; 當某個控件的某個事件已經發生或這個控件需要得到一些信息時,發送此消息給它的父窗口 WM_INPUTLANGCHANGEREQUEST = 0x0050; 當用戶選擇某種輸入語言,或輸入語言的熱鍵改變 WM_INPUTLANGCHANGE = 0x0051; 當平台現場已經被改變后發送此消息給受影響的最頂級窗口 WM_TCARD = 0x0052; 當程序已經初始化windows幫助例程時發送此消息給應用程序 WM_HELP = 0x0053; 此消息顯示用戶按下了F1,如果某個菜單是激活的,就發送此消息個此窗口關聯的菜單,否則就 發送給有焦點的窗口,如果當前都沒有焦點,就把此消息發送給當前激活的窗口 WM_USERCHANGED = 0x0054; 當用戶已經登入或退出后發送此消息給所有的窗口,當用戶登入或退出時系統更新用戶的具體 設置信息,在用戶更新設置時系統馬上發送此消息; WM_NOTIFYFORMAT = 0x0055; 公用控件,自定義控件和他們的父窗口通過此消息來判斷控件是使用ANSI還是UNICODE結構 在WM_NOTIFY消息,使用此控件能使某個控件與它的父控件之間進行相互通信 WM_CONTEXTMENU = 0x007B; 當用戶某個窗口中點擊了一下右鍵就發送此消息給這個窗口 WM_STYLECHANGING = 0x007C; 當調用SETWINDOWLONG函數將要改變一個或多個 窗口的風格時發送此消息給那個窗口 WM_STYLECHANGED = 0x007D; 當調用SETWINDOWLONG函數一個或多個 窗口的風格后發送此消息給那個窗口 WM_DISPLAYCHANGE = 0x007E; 當顯示器的分辨率改變后發送此消息給所有的窗口 WM_GETICON = 0x007F; 此消息發送給某個窗口來返回與某個窗口有關連的大圖標或小圖標的句柄; WM_SETICON = 0x0080; 程序發送此消息讓一個新的大圖標或小圖標與某個窗口關聯; WM_NCCREATE = 0x0081; 當某個窗口第一次被創建時,此消息在WM_CREATE消息發送前發送; WM_NCDESTROY = 0x0082; 此消息通知某個窗口,非客戶區正在銷毀 WM_NCCALCSIZE = 0x0083; 當某個窗口的客戶區域必須被核算時發送此消息 WM_NCHITTEST = 0x0084;//移動鼠標,按住或釋放鼠標時發生 WM_NCPAINT = 0x0085; 程序發送此消息給某個窗口當它(窗口)的框架必須被繪制時; WM_NCACTIVATE = 0x0086; 此消息發送給某個窗口 僅當它的非客戶區需要被改變來顯示是激活還是非激活狀態; WM_GETDLGCODE = 0x0087; 發送此消息給某個與對話框程序關聯的控件,widdows控制方位鍵和TAB鍵使輸入進入此控件 通過響應WM_GETDLGCODE消息,應用程序可以把他當成一個特殊的輸入控件並能處理它 WM_NCMOUSEMOVE = 0x00A0; 當光標在一個窗口的非客戶區內移動時發送此消息給這個窗口 //非客戶區為:窗體的標題欄及窗 的邊框體 WM_NCLBUTTONDOWN = 0x00A1; 當光標在一個窗口的非客戶區同時按下鼠標左鍵時提交此消息 WM_NCLBUTTONUP = 0x00A2; 當用戶釋放鼠標左鍵同時光標某個窗口在非客戶區十發送此消息; WM_NCLBUTTONDBLCLK = 0x00A3; 當用戶雙擊鼠標左鍵同時光標某個窗口在非客戶區十發送此消息 WM_NCRBUTTONDOWN = 0x00A4; 當用戶按下鼠標右鍵同時光標又在窗口的非客戶區時發送此消息 WM_NCRBUTTONUP = 0x00A5; 當用戶釋放鼠標右鍵同時光標又在窗口的非客戶區時發送此消息 WM_NCRBUTTONDBLCLK = 0x00A6; 當用戶雙擊鼠標右鍵同時光標某個窗口在非客戶區十發送此消息 WM_NCMBUTTONDOWN = 0x00A7; 當用戶按下鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 WM_NCMBUTTONUP = 0x00A8; 當用戶釋放鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 WM_NCMBUTTONDBLCLK = 0x00A9; 當用戶雙擊鼠標中鍵同時光標又在窗口的非客戶區時發送此消息 WM_KEYFIRST = 0x0100; WM_KEYDOWN = 0x0100; //按下一個鍵 WM_KEYUP = 0x0101; //釋放一個鍵 WM_CHAR = 0x0102; //按下某鍵,並已發出WM_KEYDOWN, WM_KEYUP消息 WM_DEADCHAR = 0x0103; 當用translatemessage函數翻譯WM_KEYUP消息時發送此消息給擁有焦點的窗口 WM_SYSKEYDOWN = 0x0104; 當用戶按住ALT鍵同時按下其它鍵時提交此消息給擁有焦點的窗口; WM_SYSKEYUP = 0x0105; 當用戶釋放一個鍵同時ALT 鍵還按着時提交此消息給擁有焦點的窗口 WM_SYSCHAR = 0x0106; 當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后提交此消息給擁有焦點的窗口 WM_SYSDEADCHAR = 0x0107; 當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后發送此消息給擁有焦點的窗口 WM_KEYLAST = 0x0108; WM_INITDIALOG = 0x0110; 在一個對話框程序被顯示前發送此消息給它,通常用此消息初始化控件和執行其它任務 WM_COMMAND = 0x0111; 當用戶選擇一條菜單命令項或當某個控件發送一條消息給它的父窗口,一個快捷鍵被翻譯 WM_SYSCOMMAND = 0x0112; 當用戶選擇窗口菜單的一條命令或當用戶選擇最大化或最小化時那個窗口會收到此消息 WM_TIMER = 0x0113; //發生了定時器事件 WM_HSCROLL = 0x0114; 當一個窗口標准水平滾動條產生一個滾動事件時發送此消息給那個窗口,也發送給擁有它的控件 WM_VSCROLL = 0x0115; 當一個窗口標准垂直滾動條產生一個滾動事件時發送此消息給那個窗口也,發送給擁有它的控件 WM_INITMENU = 0x0116; 當一個菜單將要被激活時發送此消息,它發生在用戶菜單條中的某項或按下某個菜單鍵,它允許程序在顯示前更改菜單 WM_INITMENUPOPUP = 0x0117; 當一個下拉菜單或子菜單將要被激活時發送此消息,它允許程序在它顯示前更改菜單,而不要改變全部 WM_MENUSELECT = 0x011F; 當用戶選擇一條菜單項時發送此消息給菜單的所有者(一般是窗口) WM_MENUCHAR = 0x0120; 當菜單已被激活用戶按下了某個鍵(不同於加速鍵),發送此消息給菜單的所有者; WM_ENTERIDLE = 0x0121; 當一個模態對話框或菜單進入空載狀態時發送此消息給它的所有者,一個模態對話框或菜單進入空載狀態就是在處理完一條或幾條先前的消息后沒有消息它的列隊中等待 WM_MENURBUTTONUP = 0x0122; WM_MENUDRAG = 0x0123; WM_MENUGETOBJECT = 0x0124; WM_UNINITMENUPOPUP = 0x0125; WM_MENUCOMMAND = 0x0126; WM_CHANGEUISTATE = 0x0127; WM_UPDATEUISTATE = 0x0128; WM_QUERYUISTATE = 0x0129; WM_CTLCOLORMSGBOX = 0x0132; 在windows繪制消息框前發送此消息給消息框的所有者窗口,通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置消息框的文本和背景顏色 WM_CTLCOLOREDIT = 0x0133; 當一個編輯型控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置編輯框的文本和背景顏色 WM_CTLCOLORLISTBOX = 0x0134; 當一個列表框控件將要被繪制前發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置列表框的文本和背景顏色 WM_CTLCOLORBTN = 0x0135; 當一個按鈕控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置按紐的文本和背景顏色 WM_CTLCOLORDLG = 0x0136; 當一個對話框控件將要被繪制前發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置對話框的文本背景顏色 WM_CTLCOLORSCROLLBAR= 0x0137; 當一個滾動條控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置滾動條的背景顏色 WM_CTLCOLORSTATIC = 0x0138; 當一個靜態控件將要被繪制時發送此消息給它的父窗口;通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置靜態控件的文本和背景顏色 WM_MOUSEFIRST = 0x0200; WM_MOUSEMOVE = 0x0200; // 移動鼠標 WM_LBUTTONDOWN = 0x0201; //按下鼠標左鍵 WM_LBUTTONUP = 0x0202; //釋放鼠標左鍵 WM_LBUTTONDBLCLK = 0x0203; //雙擊鼠標左鍵 WM_RBUTTONDOWN = 0x0204; //按下鼠標右鍵 WM_RBUTTONUP = 0x0205; //釋放鼠標右鍵 WM_RBUTTONDBLCLK = 0x0206; //雙擊鼠標右鍵 WM_MBUTTONDOWN = 0x0207; //按下鼠標中鍵 WM_MBUTTONUP = 0x0208; //釋放鼠標中鍵 WM_MBUTTONDBLCLK = 0x0209; //雙擊鼠標中鍵 WM_MOUSEWHEEL = 0x020A; 當鼠標輪子轉動時發送此消息個當前有焦點的控件 WM_MOUSELAST = 0x020A; WM_PARENTNOTIFY = 0x0210; 當MDI子窗口被創建或被銷毀,或用戶按了一下鼠標鍵而光標在子窗口上時發送此消息給它的父窗口 WM_ENTERMENULOOP = 0x0211; 發送此消息通知應用程序的主窗口that已經進入了菜單循環模式 WM_EXITMENULOOP = 0x0212; 發送此消息通知應用程序的主窗口that已退出了菜單循環模式 WM_NEXTMENU = 0x0213; WM_SIZING = 532; 當用戶正在調整窗口大小時發送此消息給窗口;通過此消息應用程序可以監視窗口大小和位置也可以修改他們 WM_CAPTURECHANGED = 533; 發送此消息 給窗口當它失去捕獲的鼠標時; WM_MOVING = 534; 當用戶在移動窗口時發送此消息,通過此消息應用程序可以監視窗口大小和位置也可以修改他們; WM_POWERBROADCAST = 536; 此消息發送給應用程序來通知它有關電源管理事件; WM_DEVICECHANGE = 537; 當設備的硬件配置改變時發送此消息給應用程序或設備驅動程序 WM_IME_STARTCOMPOSITION = 0x010D; WM_IME_ENDCOMPOSITION = 0x010E; WM_IME_COMPOSITION = 0x010F; WM_IME_KEYLAST = 0x010F; WM_IME_SETCONTEXT = 0x0281; WM_IME_NOTIFY = 0x0282; WM_IME_CONTROL = 0x0283; WM_IME_COMPOSITIONFULL = 0x0284; WM_IME_SELECT = 0x0285; WM_IME_CHAR = 0x0286; WM_IME_REQUEST = 0x0288; WM_IME_KEYDOWN = 0x0290; WM_IME_KEYUP = 0x0291; WM_MDICREATE = 0x0220; 應用程序發送此消息給多文檔的客戶窗口來創建一個MDI 子窗口 WM_MDIDESTROY = 0x0221; 應用程序發送此消息給多文檔的客戶窗口來關閉一個MDI 子窗口 WM_MDIACTIVATE = 0x0222; 應用程序發送此消息給多文檔的客戶窗口通知客戶窗口激活另一個MDI子窗口,當客戶窗口收到此消息后,它發出WM_MDIACTIVE消息給MDI子窗口(未激活)激活它; WM_MDIRESTORE = 0x0223; 程序 發送此消息給MDI客戶窗口讓子窗口從最大最小化恢復到原來大小 WM_MDINEXT = 0x0224; 程序 發送此消息給MDI客戶窗口激活下一個或前一個窗口 WM_MDIMAXIMIZE = 0x0225; 程序發送此消息給MDI客戶窗口來最大化一個MDI子窗口; WM_MDITILE = 0x0226; 程序 發送此消息給MDI客戶窗口以平鋪方式重新排列所有MDI子窗口 WM_MDICASCADE = 0x0227; 程序 發送此消息給MDI客戶窗口以層疊方式重新排列所有MDI子窗口 WM_MDIICONARRANGE = 0x0228; 程序 發送此消息給MDI客戶窗口重新排列所有最小化的MDI子窗口 WM_MDIGETACTIVE = 0x0229; 程序 發送此消息給MDI客戶窗口來找到激活的子窗口的句柄 WM_MDISETMENU = 0x0230; 程序 發送此消息給MDI客戶窗口用MDI菜單代替子窗口的菜單 WM_ENTERSIZEMOVE = 0x0231; WM_EXITSIZEMOVE = 0x0232; WM_DROPFILES = 0x0233; WM_MDIREFRESHMENU = 0x0234; WM_MOUSEHOVER = 0x02A1; WM_MOUSELEAVE = 0x02A3; WM_CUT = 0x0300; 程序發送此消息給一個編輯框或combobox來刪除當前選擇的文本 WM_COPY = 0x0301; 程序發送此消息給一個編輯框或combobox來復制當前選擇的文本到剪貼板 WM_PASTE = 0x0302; 程序發送此消息給editcontrol或combobox從剪貼板中得到數據 WM_CLEAR = 0x0303; 程序發送此消息給editcontrol或combobox清除當前選擇的內容; WM_UNDO = 0x0304; 程序發送此消息給editcontrol或combobox撤消最后一次操作 WM_RENDERFORMAT = 0x0305; WM_RENDERALLFORMATS = 0x0306; WM_DESTROYCLIPBOARD = 0x0307; 當調用ENPTYCLIPBOARD函數時 發送此消息給剪貼板的所有者 WM_DRAWCLIPBOARD = 0x0308; 當剪貼板的內容變化時發送此消息給剪貼板觀察鏈的第一個窗口;它允許用剪貼板觀察窗口來 顯示剪貼板的新內容; WM_PAINTCLIPBOARD = 0x0309; 當剪貼板包含CF_OWNERDIPLAY格式的數據並且剪貼板觀察窗口的客戶區需要重畫; WM_VSCROLLCLIPBOARD = 0x030A; WM_SIZECLIPBOARD = 0x030B; 當剪貼板包含CF_OWNERDIPLAY格式的數據並且剪貼板觀察窗口的客戶區域的大小已經改變是此消息通過剪貼板觀察窗口發送給剪貼板的所有者; WM_ASKCBFORMATNAME = 0x030C; 通過剪貼板觀察窗口發送此消息給剪貼板的所有者來請求一個CF_OWNERDISPLAY格式的剪貼板的名字 WM_CHANGECBCHAIN = 0x030D; 當一個窗口從剪貼板觀察鏈中移去時發送此消息給剪貼板觀察鏈的第一個窗口; WM_HSCROLLCLIPBOARD = 0x030E; 此消息通過一個剪貼板觀察窗口發送給剪貼板的所有者 ;它發生在當剪貼板包含CFOWNERDISPALY格式的數據並且有個事件在剪貼板觀察窗的水平滾動條上;所有者應滾動剪貼板圖象並更新滾動條的值; WM_QUERYNEWPALETTE = 0x030F; 此消息發送給將要收到焦點的窗口,此消息能使窗口在收到焦點時同時有機會實現他的邏輯調色板 WM_PALETTEISCHANGING= 0x0310; 當一個應用程序正要實現它的邏輯調色板時發此消息通知所有的應用程序 WM_PALETTECHANGED = 0x0311; 此消息在一個擁有焦點的窗口實現它的邏輯調色板后發送此消息給所有頂級並重疊的窗口,以此來改變系統調色板 WM_HOTKEY = 0x0312; 當用戶按下由REGISTERHOTKEY函數注冊的熱鍵時提交此消息 WM_PRINT = 791; 應用程序發送此消息僅當WINDOWS或其它應用程序發出一個請求要求繪制一個應用程序的一部分; WM_PRINTCLIENT = 792; WM_HANDHELDFIRST = 856; WM_HANDHELDLAST = 863; WM_PENWINFIRST = 0x0380; WM_PENWINLAST = 0x038F; WM_COALESCE_FIRST = 0x0390; WM_COALESCE_LAST = 0x039F; WM_DDE_FIRST = 0x03E0; 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 = 0x8000; WM_USER = 0x0400; 按扭 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列表框獲得輸入焦點