1. 程式人生 > >Windows API 之SendMessage[user32]

Windows API 之SendMessage[user32]

 函式功能:該函式將指定的訊息傳送到一個或多個視窗。此函式為指定的視窗呼叫視窗程式,直到視窗程式處理完訊息再返回。而函式PostMessage不同,將一個訊息寄送到一個執行緒的訊息佇列後立即返回。     函式原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);     引數:     hWnd:其視窗程式將接收訊息的視窗的控制代碼。如果此引數為HWND_BROADCAST,則訊息將被髮送到系統中所有頂層視窗,包括無效或不可見的非自身擁有的視窗、被覆蓋的視窗和彈出式視窗,但訊息不被髮送到子視窗。     Msg:指定被髮送的訊息。     wParam:指定附加的訊息指定資訊。     IParam:指定附加的訊息指定資訊。     返回值:

返回值指定訊息處理的結果,依賴於所傳送的訊息。     備註:需要用HWND_BROADCAST通訊的應用程式應當使用函式RegisterWindowMessage來為應用程式間的通訊取得一個唯一的訊息。     如果指定的視窗是由呼叫執行緒建立的,則視窗程式立即作為子程式呼叫。如果指定的視窗是由不同執行緒建立的,則系統切換到該執行緒並呼叫恰當的視窗程式。執行緒間的訊息只有在執行緒執行訊息檢索程式碼時才被處理。傳送執行緒被阻塞直到接收執行緒處理完訊息為止。

以上是對SendMessage的基本介紹,其用法很多,主要是在於其引數的使用和資料轉換:

using System.Runtime.InteropServices;
[DllImport("user32.dll", EntryPoint="SendMessageA")]
public static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

 SendMessage是一個在user32.dll中宣告的API函式,在C#中匯入如下:

本文描述其引數 lParam 的用法,主要是資料型別之間的轉化

● 一種最簡單的處理方式是宣告多個SendMessage函式(overload),用所需的資料型別直接替換IntPtr。例如:

//宣告:
[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam,  string lParam);
[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam,  ref Rectangle lParam);
//呼叫:
string s = "hello, floodzhu";
SendMessage(this.textBox1.Handle, WM_SETTEXT, IntPtr.Zero, s);

Rectangle rect = new Rectangle();
SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, ref rect);

● 對要求返回字串的型別(out string)可以用 StringBuilder 代替,此時不需要 out/ref。例如:

[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, int wParam, StringBuilder lParam);
private void button1_Click(object sender, System.EventArgs e)
{
    const int buffer_size = 1024;
    StringBuilder buffer = new StringBuilder(buffer_size);
    SendMessage(this.textBox1.Handle, WM_GETTEXT, buffer_size, buffer);
    //MessageBox.Show(buffer.ToString());
}

● 如果想用 InPtr 型別統一處理的話,可以藉助於 Marshal 或者 GCHandle 的相關方法。例如:

[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

private void button2_Click(object sender, System.EventArgs e)
{
    Rectangle rect = new Rectangle();
    IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Rectangle)));
    Marshal.StructureToPtr(rect, buffer ,true);

    SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, buffer);

    rect = (Rectangle)Marshal.PtrToStructure(buffer, typeof(Rectangle));

    Marshal.FreeHGlobal(buffer);
}

或者

private void button2_Click(object sender, System.EventArgs e)
{
    Rectangle rect = new Rectangle();
    GCHandle gch = GCHandle.Alloc(rect);

    SendMessage(this.richTextBox1.Handle, EM_GETRECT, (IntPtr)0, (IntPtr)gch);
    rect = (Rectangle)Marshal.PtrToStructure((IntPtr)gch, typeof(Rectangle));

    gch.Free();
}

● 模擬按鈕點選。第三個引數是可選引數,有時需要有時不需要,比如該例中就不需要。

const int BM_CLICK = 0xF5;
IntPtr maindHwnd = FindWindow(null, "QQ使用者登入"); //獲得QQ登陸框的控制代碼
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;

轉自原文連結