C# 進程(應用程序)間通信


SendMessage用法:

函數功能:該函數將指定的消息發送到一個或多個窗口。此函數為指定的窗口調用窗口程序,直到窗口程序處理完消息再返回。該函數是應用程序和應用程序之間進行消息傳遞的主要手段之一。
    函數原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);

    參數:

    hWnd:其窗口程序將接收消息的窗口的句柄。如果此參數為HWND_BROADCAST,則消息將被發送到系統中所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口,但消息不被發送到子窗口。

    Msg:指定被發送的消息。

    wParam:指定附加的消息指定信息。

    IParam:指定附加的消息指定信息。

    返回值:返回值指定消息處理的結果,依賴於所發送的消息。

    備注:需要用HWND_BROADCAST通信的應用程序應當使用函數RegisterWindowMessage來為應用程序間的通信取得一個唯一的消息。

    如果指定的窗口是由調用線程創建的,則窗口程序立即作為子程序調用。如果指定的窗口是由不同線程創建的,則系統切換到該線程並調用恰當的窗口程序。線程間的消息只有在線程執行消息檢索代碼時才被處理。發送線程被阻塞直到接收線程處理完消息為止。

C#中使用該函數首先導入命名空間:
using System.Runtime.InteropServices;

然后寫API引用部分的代碼,放入 class 內部
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

這個函數有四個參數,第一個是窗口句柄,窗口可以是任何類型的屏幕對象;第二個是用於區別其他消息的常量值;第三個通常是一個與消息有關的常量值,也可能是窗口或控件的句柄,第三個參數是可選參數,有的消息要,有的不需要,比如單擊就不需要這個參數,
別的消息,比如鼠標移動的可能需要在這里加上一些鼠標的參數;第四個通常是一個指向內存中數據的指針。在C#中消息需要定義成windows系統中的原始的16進制數字,比如 const int WM_Lbutton = 0x201; //定義了鼠標的左鍵點擊消息。詳細值在最后。

const int BM_CLICK = 0xF5;
IntPtr maindHwnd = FindWindow(null, "窗體標題名"); //獲得已知窗體標題名的句柄
if (maindHwnd != IntPtr.Zero)
{
    IntPtr childHwnd = FindWindowEx(maindHwnd, IntPtr.Zero, null, "子窗體");   //獲得子窗體的句柄
    if (childHwnd != IntPtr.Zero)
    {
        SendMessage(childHwnd, BM_CLICK, 0, 0);     //發送點擊按鈕的消息
    }
    else
    {
        MessageBox.Show("沒有找到子窗口");
    }
}
else
{
    MessageBox.Show("沒有找到窗口");
}
//wMsg參數常量值:

 //創建一個窗口   
const int WM_CREATE = 0x01;   
//當一個窗口被破壞時發送   
const int WM_DESTROY = 0x02;   
//移動一個窗口   
const int WM_MOVE = 0x03;   
//改變一個窗口的大小   
const int WM_SIZE = 0x05;   
//一個窗口被激活或失去激活狀態   
const int WM_ACTIVATE = 0x06;   
//一個窗口獲得焦點   
const int WM_SETFOCUS = 0x07;   
//一個窗口失去焦點   
const int WM_KILLFOCUS = 0x08;   
//一個窗口改變成Enable狀態   
const int WM_ENABLE = 0x0A;   
//設置窗口是否能重畫   
const int WM_SETREDRAW = 0x0B;   
//應用程序發送此消息來設置一個窗口的文本   
const int WM_SETTEXT = 0x0C;   
//應用程序發送此消息來復制對應窗口的文本到緩沖區   
const int WM_GETTEXT = 0x0D;   
//得到與一個窗口有關的文本的長度(不包含空字符)   
const int WM_GETTEXTLENGTH = 0x0E;   
//要求一個窗口重畫自己   
const int WM_PAINT = 0x0F;   
//當一個窗口或應用程序要關閉時發送一個信號   
const int WM_CLOSE = 0x10;   
//當用戶選擇結束對話框或程序自己調用ExitWindows函數   
const int WM_QUERYENDSESSION = 0x11;   
//用來結束程序運行   
const int WM_QUIT = 0x12;   
//當用戶窗口恢復以前的大小位置時,把此消息發送給某個圖標   
const int WM_QUERYOPEN = 0x13;   
//當窗口背景必須被擦除時(例在窗口改變大小時)   
const int WM_ERASEBKGND = 0x14;   
//當系統顏色改變時,發送此消息給所有頂級窗口   
const int WM_SYSCOLORCHANGE = 0x15;   
//當系統進程發出WM_QUERYENDSESSION消息后,此消息發送給應用程序,通知它對話是否結束   
const int WM_ENDSESSION = 0x16;   
//當隱藏或顯示窗口是發送此消息給這個窗口   
const int WM_SHOWWINDOW = 0x18;   
//發此消息給應用程序哪個窗口是激活的,哪個是非激活的   
const int WM_ACTIVATEAPP = 0x1C;   
//當系統的字體資源庫變化時發送此消息給所有頂級窗口   
const int WM_FONTCHANGE = 0x1D;   
//當系統的時間變化時發送此消息給所有頂級窗口   
const int WM_TIMECHANGE = 0x1E;   
//發送此消息來取消某種正在進行的摸態(操作)   
const int WM_CANCELMODE = 0x1F;   
//如果鼠標引起光標在某個窗口中移動且鼠標輸入沒有被捕獲時,就發消息給某個窗口   
const int WM_SETCURSOR = 0x20;   
//當光標在某個非激活的窗口中而用戶正按着鼠標的某個鍵發送此消息給//當前窗口   
const int WM_MOUSEACTIVATE = 0x21;   
//發送此消息給MDI子窗口//當用戶點擊此窗口的標題欄,或//當窗口被激活,移動,改變大小   
const int WM_CHILDACTIVATE = 0x22;   
//此消息由基於計算機的訓練程序發送,通過WH_JOURNALPALYBACK的hook程序分離出用戶輸入消息   
const int WM_QUEUESYNC = 0x23;   
//此消息發送給窗口當它將要改變大小或位置   
const int WM_GETMINMAXINFO = 0x24;   
//發送給最小化窗口當它圖標將要被重畫   
const int WM_PAINTICON = 0x26;   
//此消息發送給某個最小化窗口,僅//當它在畫圖標前它的背景必須被重畫   
const int WM_ICONERASEBKGND = 0x27;   
//發送此消息給一個對話框程序去更改焦點位置   
const int WM_NEXTDLGCTL = 0x28;   
//每當打印管理列隊增加或減少一條作業時發出此消息    
const int WM_SPOOLERSTATUS = 0x2A;   
//當button,combobox,listbox,menu的可視外觀改變時發送   
const int WM_DRAWITEM = 0x2B;   
//當button, combo box, list box, list view control, or menu item 被創建時   
const int WM_MEASUREITEM = 0x2C;   
//此消息有一個LBS_WANTKEYBOARDINPUT風格的發出給它的所有者來響應WM_KEYDOWN消息    
const int WM_VKEYTOITEM = 0x2E;   
//此消息由一個LBS_WANTKEYBOARDINPUT風格的列表框發送給他的所有者來響應WM_CHAR消息    
const int WM_CHARTOITEM = 0x2F;   
//當繪制文本時程序發送此消息得到控件要用的顏色   
const int WM_SETFONT = 0x30;   
//應用程序發送此消息得到當前控件繪制文本的字體   
const int WM_GETFONT = 0x31;   
//應用程序發送此消息讓一個窗口與一個熱鍵相關連    
const int WM_SETHOTKEY = 0x32;   
//應用程序發送此消息來判斷熱鍵與某個窗口是否有關聯   
const int WM_GETHOTKEY = 0x33;   
//此消息發送給最小化窗口,當此窗口將要被拖放而它的類中沒有定義圖標,應用程序能返回一個圖標或光標的句柄,當用戶拖放圖標時系統顯示這個圖標或光標   
const int WM_QUERYDRAGICON = 0x37;   
//發送此消息來判定combobox或listbox新增加的項的相對位置   
const int WM_COMPAREITEM = 0x39;   
//顯示內存已經很少了   
const int WM_COMPACTING = 0x41;   
//發送此消息給那個窗口的大小和位置將要被改變時,來調用setwindowpos函數或其它窗口管理函數   
const int WM_WINDOWPOSCHANGING = 0x46;   
//發送此消息給那個窗口的大小和位置已經被改變時,來調用setwindowpos函數或其它窗口管理函數   
const int WM_WINDOWPOSCHANGED = 0x47;   
//當系統將要進入暫停狀態時發送此消息   
const int WM_POWER = 0x48;   
//當一個應用程序傳遞數據給另一個應用程序時發送此消息   
const int WM_COPYDATA = 0x4A;   
//當某個用戶取消程序日志激活狀態,提交此消息給程序   
const int WM_CANCELJOURNA = 0x4B;   
//當某個控件的某個事件已經發生或這個控件需要得到一些信息時,發送此消息給它的父窗口    
const int WM_NOTIFY = 0x4E;   
//當用戶選擇某種輸入語言,或輸入語言的熱鍵改變   
const int WM_INPUTLANGCHANGEREQUEST = 0x50;   
//當平台現場已經被改變后發送此消息給受影響的最頂級窗口   
const int WM_INPUTLANGCHANGE = 0x51;   
//當程序已經初始化windows幫助例程時發送此消息給應用程序   
const int WM_TCARD = 0x52;   
//此消息顯示用戶按下了F1,如果某個菜單是激活的,就發送此消息個此窗口關聯的菜單,否則就發送給有焦點的窗口,如果//當前都沒有焦點,就把此消息發送給//當前激活的窗口   
const int WM_HELP = 0x53;   
//當用戶已經登入或退出后發送此消息給所有的窗口,//當用戶登入或退出時系統更新用戶的具體設置信息,在用戶更新設置時系統馬上發送此消息   
const int WM_USERCHANGED = 0x54;   
//公用控件,自定義控件和他們的父窗口通過此消息來判斷控件是使用ANSI還是UNICODE結構   
const int WM_NOTIFYFORMAT = 0x55;   
//當用戶某個窗口中點擊了一下右鍵就發送此消息給這個窗口   
//const int WM_CONTEXTMENU = ??;   
//當調用SETWINDOWLONG函數將要改變一個或多個 窗口的風格時發送此消息給那個窗口   
const int WM_STYLECHANGING = 0x7C;   
//當調用SETWINDOWLONG函數一個或多個 窗口的風格后發送此消息給那個窗口   
const int WM_STYLECHANGED = 0x7D;   
//當顯示器的分辨率改變后發送此消息給所有的窗口   
const int WM_DISPLAYCHANGE = 0x7E;   
//此消息發送給某個窗口來返回與某個窗口有關連的大圖標或小圖標的句柄   
const int WM_GETICON = 0x7F;   
//程序發送此消息讓一個新的大圖標或小圖標與某個窗口關聯   
const int WM_SETICON = 0x80;   
//當某個窗口第一次被創建時,此消息在WM_CREATE消息發送前發送   
const int WM_NCCREATE = 0x81;   
//此消息通知某個窗口,非客戶區正在銷毀    
const int WM_NCDESTROY = 0x82;   
//當某個窗口的客戶區域必須被核算時發送此消息   
const int WM_NCCALCSIZE = 0x83;   
//移動鼠標,按住或釋放鼠標時發生   
const int WM_NCHITTEST = 0x84;   
//程序發送此消息給某個窗口當它(窗口)的框架必須被繪制時   
const int WM_NCPAINT = 0x85;   
//此消息發送給某個窗口僅當它的非客戶區需要被改變來顯示是激活還是非激活狀態   
const int WM_NCACTIVATE = 0x86;   
//發送此消息給某個與對話框程序關聯的控件,widdows控制方位鍵和TAB鍵使輸入進入此控件通過應   
const int WM_GETDLGCODE = 0x87;   
//當光標在一個窗口的非客戶區內移動時發送此消息給這個窗口 非客戶區為:窗體的標題欄及窗 的邊框體   
const int WM_NCMOUSEMOVE = 0xA0;   
//當光標在一個窗口的非客戶區同時按下鼠標左鍵時提交此消息   
const int WM_NCLBUTTONDOWN = 0xA1;   
//當用戶釋放鼠標左鍵同時光標某個窗口在非客戶區十發送此消息    
const int WM_NCLBUTTONUP = 0xA2;   
//當用戶雙擊鼠標左鍵同時光標某個窗口在非客戶區十發送此消息   
const int WM_NCLBUTTONDBLCLK = 0xA3;   
//當用戶按下鼠標右鍵同時光標又在窗口的非客戶區時發送此消息   
const int WM_NCRBUTTONDOWN = 0xA4;   
//當用戶釋放鼠標右鍵同時光標又在窗口的非客戶區時發送此消息   
const int WM_NCRBUTTONUP = 0xA5;   
//當用戶雙擊鼠標右鍵同時光標某個窗口在非客戶區十發送此消息   
const int WM_NCRBUTTONDBLCLK = 0xA6;   
//當用戶按下鼠標中鍵同時光標又在窗口的非客戶區時發送此消息   
const int WM_NCMBUTTONDOWN = 0xA7;   
//當用戶釋放鼠標中鍵同時光標又在窗口的非客戶區時發送此消息   
const int WM_NCMBUTTONUP = 0xA8;   
//當用戶雙擊鼠標中鍵同時光標又在窗口的非客戶區時發送此消息   
const int WM_NCMBUTTONDBLCLK = 0xA9;   
//WM_KEYDOWN 按下一個鍵   
const int WM_KEYDOWN = 0x0100;   
//釋放一個鍵   
const int WM_KEYUP = 0x0101;   
//按下某鍵,並已發出WM_KEYDOWN, WM_KEYUP消息   
const int WM_CHAR = 0x102;   
//當用translatemessage函數翻譯WM_KEYUP消息時發送此消息給擁有焦點的窗口   
const int WM_DEADCHAR = 0x103;   
//當用戶按住ALT鍵同時按下其它鍵時提交此消息給擁有焦點的窗口   
const int WM_SYSKEYDOWN = 0x104;   
//當用戶釋放一個鍵同時ALT 鍵還按着時提交此消息給擁有焦點的窗口   
const int WM_SYSKEYUP = 0x105;   
//當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后提交此消息給擁有焦點的窗口   
const int WM_SYSCHAR = 0x106;   
//當WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函數翻譯后發送此消息給擁有焦點的窗口   
const int WM_SYSDEADCHAR = 0x107;   
//在一個對話框程序被顯示前發送此消息給它,通常用此消息初始化控件和執行其它任務   
const int WM_INITDIALOG = 0x110;   
//當用戶選擇一條菜單命令項或當某個控件發送一條消息給它的父窗口,一個快捷鍵被翻譯   
const int WM_COMMAND = 0x111;   
//當用戶選擇窗口菜單的一條命令或//當用戶選擇最大化或最小化時那個窗口會收到此消息   
const int WM_SYSCOMMAND = 0x112;   
//發生了定時器事件   
const int WM_TIMER = 0x113;   
//當一個窗口標准水平滾動條產生一個滾動事件時發送此消息給那個窗口,也發送給擁有它的控件   
const int WM_HSCROLL = 0x114;   
//當一個窗口標准垂直滾動條產生一個滾動事件時發送此消息給那個窗口也,發送給擁有它的控件   
const int WM_VSCROLL = 0x115;   
//當一個菜單將要被激活時發送此消息,它發生在用戶菜單條中的某項或按下某個菜單鍵,它允許程序在顯示前更改菜單   
const int WM_INITMENU = 0x116;   
//當一個下拉菜單或子菜單將要被激活時發送此消息,它允許程序在它顯示前更改菜單,而不要改變全部   
const int WM_INITMENUPOPUP = 0x117;   
//當用戶選擇一條菜單項時發送此消息給菜單的所有者(一般是窗口)   
const int WM_MENUSELECT = 0x11F;   
//當菜單已被激活用戶按下了某個鍵(不同於加速鍵),發送此消息給菜單的所有者   
const int WM_MENUCHAR = 0x120;   
//當一個模態對話框或菜單進入空載狀態時發送此消息給它的所有者,一個模態對話框或菜單進入空載狀態就是在處理完一條或幾條先前的消息后沒有消息它的列隊中等待   
const int WM_ENTERIDLE = 0x121;   
//在windows繪制消息框前發送此消息給消息框的所有者窗口,通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置消息框的文本和背景顏色   
const int WM_CTLCOLORMSGBOX = 0x132;   
//當一個編輯型控件將要被繪制時發送此消息給它的父窗口通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置編輯框的文本和背景顏色   
const int WM_CTLCOLOREDIT = 0x133;   
  
//當一個列表框控件將要被繪制前發送此消息給它的父窗口通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置列表框的文本和背景顏色   
const int WM_CTLCOLORLISTBOX = 0x134;   
//當一個按鈕控件將要被繪制時發送此消息給它的父窗口通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置按紐的文本和背景顏色   
const int WM_CTLCOLORBTN = 0x135;   
//當一個對話框控件將要被繪制前發送此消息給它的父窗口通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置對話框的文本背景顏色   
const int WM_CTLCOLORDLG = 0x136;   
//當一個滾動條控件將要被繪制時發送此消息給它的父窗口通過響應這條消息,所有者窗口可以通過使用給定的相關顯示設備的句柄來設置滾動條的背景顏色   
const int WM_CTLCOLORSCROLLBAR = 0x137;   
//當一個靜態控件將要被繪制時發送此消息給它的父窗口通過響應這條消息,所有者窗口可以 通過使用給定的相關顯示設備的句柄來設置靜態控件的文本和背景顏色   
const int WM_CTLCOLORSTATIC = 0x138;   
//當鼠標輪子轉動時發送此消息個當前有焦點的控件   
const int WM_MOUSEWHEEL = 0x20A;   
//雙擊鼠標中鍵   
const int WM_MBUTTONDBLCLK = 0x209;   
//釋放鼠標中鍵   
const int WM_MBUTTONUP = 0x208;   
//移動鼠標時發生,同WM_MOUSEFIRST   
const int WM_MOUSEMOVE = 0x200;   
//按下鼠標左鍵   
const int WM_LBUTTONDOWN = 0x201;   
//釋放鼠標左鍵   
const int WM_LBUTTONUP = 0x202;   
//雙擊鼠標左鍵   
const int WM_LBUTTONDBLCLK = 0x203;   
//按下鼠標右鍵   
const int WM_RBUTTONDOWN = 0x204;   
//釋放鼠標右鍵   
const int WM_RBUTTONUP = 0x205;   
//雙擊鼠標右鍵   
const int WM_RBUTTONDBLCLK = 0x206;   
//按下鼠標中鍵   
const int WM_MBUTTONDOWN = 0x207;   
  
const int WM_USER = 0x0400;   
const int MK_LBUTTON = 0x0001;   
const int MK_RBUTTON = 0x0002;   
const int MK_SHIFT = 0x0004;   
const int MK_CONTROL = 0x0008;   
const int MK_MBUTTON = 0x0010;   
const int MK_XBUTTON1 = 0x0020;   
const int MK_XBUTTON2 = 0x0040;

消息統一采用4位16進制的數。

系統消息使用的是0x0100(WM_KEYDOWN);0x0000--0x0400是系統自定義的消息,其中0x0000為WM_NULL,0x0400為WM_USER。0x0400以后的數值我們可以作為自定義的消息值。

自定義消息,需要下面幾個步驟:

1、  定義消息

public const int USER = 0x0400;

在C#中就可以做對應的聲明:

public const int WM_TEST = USER+101;

2、  發送消息

消息發送是通過windows提供的API函數SendMessage來實現的,它的原型定義:       

[DllImport("User32.dll",EntryPoint="SendMessage")]

 private static extern int SendMessage(

     IntPtr hWnd,      // handle to destination window

     uint Msg,         // message

     uint wParam,      // first message parameter

     uint lParam       // second message parameter

);

3、  消息接收

消息發出之后,在Form中如何接收呢?我們可以重載DefWinproc函數來接收消息。

protected override void DefWndProc ( ref System.Windows.Forms.Message m )
{
      switch(m.Msg)
      {
          case Message.WM_TEST: //處理消息
               break;
          default:
                base.DefWndProc(ref m);//調用基類函數處理非自定義消息。
              break;
        }
}

示例應用

1、  定義消息

我們在工程中添加一個Message類用來定義消息。然后添加了三個成員變量,其中USER為自定義消息的初始值,相當與MFC中的WM_USER。WM_TEST為自定義的用來響應應用程序的消息,WM_MSG為自定義的用來響應DLL傳遞過來的消息。如何在DLL定義消息請參考文章:VC.Net從DLL傳遞消息到DLL

public class Message
 {
     public const int USER = 0x0400;

     public const int WM_TEST = USER+101;

     public const int WM_MSG = USER+102;

}

2、  聲明引用函數

在使用消息的地方,申明引用的函數,我們這里在MsgForm.cs文件中申明:

//申明發送消息函數

[DllImport("User32.dll",EntryPoint="SendMessage")]

private static extern int SendMessage(

     IntPtr hWnd,      // handle to destination window

     uint Msg,         // message

     uint wParam,      // first message parameter

     uint lParam       // second message parameter

     );

 //申明DLL中啟動消息函數

[DllImport("MessageDLL.dll",EntryPoint="StartSendMessage")]

private extern static void StartSendMessage(IntPtr hWnd);

3、  處理系統消息

protected override void OnPaint (  System.Windows.Forms.PaintEventArgs e )

{

///定義字體:黑體,大小:28

Font font = new Font("黑體",28);

///創建藍色畫筆

SolidBrush bluepen = new SolidBrush(Color.Blue);

///創建黑色畫筆            

SolidBrush blackpen = new SolidBrush(Color.FromArgb(0xa0,0xa0,0xb0));

///寫字符串

e.Graphics.DrawString("VC知識庫",font,blackpen,65,25);

///偏移4個象素用不同的顏色再寫一次,達到立體效果

e.Graphics.DrawString("VC知識庫",font,bluepen,61,21);       

}

4、   觸發自定義消息

//測試應用程序消息

 private void TestAppbutton_Click(object sender, System.EventArgs e)

{

    SendMessage(this.Handle,Message.WM_TEST,100,200);

}

//測試DLL消息

private void TestDLLbutton_Click(object sender, System.EventArgs e)

{

    StartSendMessage(this.Handle);

}

5、  響應和處理自定義消息

protected override void DefWndProc ( ref System.Windows.Forms.Message m )

{

      string message;

      switch(m.Msg)

      {

            case Message.WM_TEST://處理消息

                    message = string.Format("收到從應用程序發出的消息!參數為:{0},{1}",m.WParam,m.LParam);

                    MessageBox.Show(message);///顯示一個消息框

                    break;

             case Message.WM_MSG:

                    message = string.Format("收到從DLL發出的消息!參數為:{0},{1}",m.WParam,m.LParam);

                    MessageBox.Show(message);///顯示一個消息框

                    break;

             default:

                    base.DefWndProc(ref m);//調用基類函數處理非自定義消息。

                    break;

       }

 }

下面是一個簡單的小例子:

自定義消息Message:

class Message
    {
        public const int USER = 0x0400;
        public const int WM_TEST = USER + 101;
        public const int WM_MSG = USER + 102;
    }

接收端和發送端

接收端Form1:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, int msg, uint wParam, uint lParam);
        //[DllImport("MessageDLL.dll", EntryPoint = "StartSendMessage")]//MessageDLL找不到

        //private static extern int StartSendMessage(IntPtr hWnd);


        //自己觸發自定義消息

        private void button1_Click(object sender, EventArgs e)
        {
            SendMessage(this.Handle, Message.WM_TEST, 100, 200);
        }
        private void button2_Click(object sender, EventArgs e)
        {
            //StartSendMessage(this.Handle);

        }


        //響應和處理自定義消息

        protected override void DefWndProc(ref System.Windows.Forms.Message m)
        {
            string message;
            switch (m.Msg)
            {
                case Message.WM_TEST://處理消息

                    message = string.Format("收到從應用程序發出的消息!參數為:{0}, {1}", m.WParam, m.LParam);
                    MessageBox.Show(message);
                    break;
                //case Message.WM_MSG:

                // message = string.Format("收到從DLL發出的消息!參數為:{0}, {1}", m.WParam, m.LParam);

                // MessageBox.Show(message);

                // break;

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

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            this.label1.Text = e.KeyValue.ToString();
        }

    }

發送端Form2:button1啟動接收端,button2關閉接收端,button3傳遞系統消息和自定義的消息。

 

public partial class Form1 : Form
    {
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
        //[DllImport("MessageDLL.dll", EntryPoint = "StartSendMessage")]//MessageDLL找不到

        //private static extern int StartSendMessage(IntPtr hWnd);


        //internal string local = "this is a local internal";

        public Form1()
        {
            InitializeComponent();
        }
        //ClassLibrary1.Class1 cla = new ClassLibrary1.Class1();


        ProcessStartInfo startInfo = new ProcessStartInfo();
        Process pro = new Process();

        private void Form1_Load(object sender, EventArgs e)
        {
            startInfo.FileName = @"F:\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe";
            pro.StartInfo = startInfo;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            pro.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            pro.Kill();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            IntPtr hWnd = pro.MainWindowHandle;
            int data = Convert.ToInt32(this.textBox1.Text);
            SendMessage(hWnd, 0x0100, data, 0);

            SendMessage(hWnd, Message.WM_TEST, 300, 300);
}
 
SendMessage與PostMessage

1、首先是返回值意義的區別,我們先看一下 MSDN 里的聲明:



LRESULT SendMessage(

HWND hWnd,

UINT Msg,

WPARAM wParam,

LPARAM lParam

);

BOOL PostMessage(

HWND hWnd,

UINT Msg,

WPARAM wParam,

LPARAM lParam

);



其中 4 個參數的意義是一樣的,返回值類型不同(其實從數據上看他們一樣是一個 32 位的數,只是意義不一樣),LRESULT 表示的是消息被處理后的返回值,BOOL 表示的是消息是不是 Post 成功。



2、PostMessage 是異步的,SendMessage 是同步的。

PostMessage 只把消息放入隊列,不管消息是否被處理就返回,消息可能不被處理;而 SendMessage 等待消息被處理完了之后才返回,如果消息不被處理,發送消息的線程將一直被阻塞。



3、如果在同一個線程內,SendMessage 發送消息時,由 USER32.DLL
模塊調用目標窗口的消息處理程序,並將結果返回。SendMessage 在同一線程中發送消息並不入線程消息隊列。PostMessage
發送消息時,消息要先放入線程的消息隊列,然后通過消息循環分派到目標窗口(DispatchMessage)。



如果在不同線程內,SendMessage 發送消息到目標窗口所屬線程的消息隊列,然后發送消息的線程在 USER32.DLL
模塊內監視和等待消息處理,直到目標窗口處理完返回。SendMessage 在返回前還做了很多工作,比如,響應別的線程向它
SendMessage。Post 到別的線程時,最好用 PostThreadMessage 代替
PostMessage,PostMessage 的 hWnd 參數可以是 NULL,等效於 PostThreadMessage +
GetCurrentThreadId。Post WM_QUIT 時,應使用 PostQuitMessage 代替。



4、系統只整編(marshal)系統消息(0 到 WM_USER 之間的消息),發送用戶消息(WM_USER 以上)到別的進程時,需要自己做整編。



用 PostMessage、SendNotifyMessage、SendMessageCallback 等異步函數發送系統消息時,參數里不可以使用指針,因為發送者並不等待消息的處理就返回,接受者還沒處理指針就已經被釋放了。



5、在 Windows 2000/XP 里,每個消息隊列最多只能存放 10,000 個 Post
的消息,超過的還沒被處理的將不會被處理,直接丟掉。這個值可以改得更大:[HKEY_LOCAL_MACHINE/SOFTWARE/
Microsoft/Windows NT/CurrentVersion/Windows] USERPostMessageLimit,最小可以是
4000。

PostMessage只負責將消息放到消息隊列中,不確定何時及是否處理

SendMessage要等到受到消息處理的返回碼(DWord類型)后才繼續

PostMessage執行后馬上返回

SendMessage必須等到消息被處理后才會返回。


免責聲明!

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



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