C# 使用 Windows API 操作控件: SendMessage

在C#中,程序采用了的驅動采用了事件驅動而不是原來的消息驅動,雖然.net框架提供的事件已經十分豐富,但是在以前的系統中定義了豐富的消息對系統的編程提供了方便的實現方法,因此在C#中使用消息有時候還是大大提高編程的效率的。

定義消息
在c#中消息需要定義成windows系統中的原始的6進制數字,比如
const int WM_Lbutton = 0x0; //定義了鼠標的左鍵點擊消息
public const int USER = 0x000 // 是windows系統定義的用戶消息

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

[DllImport("User.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(
int hWnd,   // handle to destination window
int Msg,   ? // message
int wParam, ? ?// first message parameter
int lParam? ? ? ? ?// second message parameter
);


消息的接受
在C#中,任何一個窗口都有也消息的接收處理函數,就是defproc函數
你可以在form中重載該函數來處理消息

protected override void DefWndProc ( ref System.WinForms.Message m )
{switch(m.msg){case WM_Lbutton :///string與MFC中的CString的Format函數的使用方法有所不同string message = string.Format("收到消息!參數為:{0},{}",m.wParam,m.lParam);MessageBox.Show(message);///顯示一個消息框break;default:base.DefWndProc(ref m);///調用基類函數處理非自定義消息。break;}
}


其實,C#中的事件也是通過封裝系統消息來實現的,如果你在DefWndProc函數中不處理該
那么,他會交給系統來處理該消息,系統便會通過代理來實現鼠標單擊的處理函數,因此你可以通過
defproc函數來攔截消息,比如你想攔截某個按鈕的單擊消息


C#中其他的消息處理方法
在C#中有的時候需要對控件的消息進行預處理,比如你用owc的spreedsheet控件來處理Excel文件,你不想讓用戶可以隨便選中
數據進行編輯,你就可以屏蔽掉鼠標事件,這個時候就必須攔截系統預先定義好的事件(這在MFC中稱為子類化),你可以通過C#提供的一個接口

IMessageFilter來實現消息的過濾

public class Form: System.Windows.Forms.Form,IMessageFilter{const int WM_MOUSEMOVE = 0x00public bool PreFilterMessage(ref Message m) {  Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode; if(m.Msg == m.Msg==WM_MOUSEMOVE) //||m.Msg == WM_LBUTTONDOWN{//MessageBox.Show("Ignoring Escape...");  return true; } return false; }
}


備注:主要描述在調用API函數SendMessage時數據類型的轉換。


SendMessage是一個在user32.dll中聲明的API函數,在C#中導入如下:

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

?

本文描述其參數 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();
}
SendMessage-------PostMessage
1、首先是返回值意義的區別,我們先看一下 MSDN 里的聲明:
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
1.其中 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必須等到消息被處理后才會返回。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252109.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252109.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252109.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

對類的理解:

在public class First 表示如果一個類的聲明為public,要求該類的類名必須和文件保持一致。在編譯 源文件時,讓雨果源文件中定義了多個類,那么每個類會形成*.class 文件,執行是,通過Java類名,運行的的是該類…

概率論

概率論轉載于:https://www.cnblogs.com/zengkefu/p/7357249.html

Hive安裝中遇到過的坑

實現說明每一個用戶的環境都有細微的不一致,所以這里只是個人經過這些坑的處理,但是不意味著所有處理都是這樣的操作,僅作為參考。 第一個坑 數據庫安裝,數據庫最好裝在Linux上,一直出了很多錯,這里有一個博…

Halcon:模版匹配

一:函數介紹 1.創建模板 create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID) Template :模板圖像 NumLevels:圖像金字塔級數,該值越小…

java基礎英語---第二十六天

Terminate [ t?:mineit ] 結束 Instantiation [in,stn?iei??n] 實例化 Instance declared [diklε?d] 公然的 Access [ ?kses ] 進入,接近,入口,通道 Accessible [?kses?bl] 可進入的 invoke [inv?uk] 調用 board [b?:d] 木板,甲板 MainBoard card [kɑ:d] …

ASP.NET Core部署到Linux服務器(CentOS7 x64)

前言 本文主要講解如何一步步將ASP.NET Core網站發布到Linux服務器,文中會講解具體步驟及需要避免的各種問題。 目錄 一、環境介紹 二、創建及發布ASP.NET Core網站項目 三、服務器軟件安裝(.NET Core SDK) 四、在服務器上部署ASP.NET Core網…

redux進一步優化

1. 將原來的 mapStateToDispatch 中的函數提取出來,放在組件中, 如原來的: function mapStateToProps(state, ownProps) {return {hasMore:state.getIn([tabs,hasMore]),} } function mapDispatchToProps(dispatch) {return {addTabList:(i…

C# : 調用C++動態庫(dll)

在實際軟件開發過程中,由于公司使用了多種語言開發,在C#中可能需要實現某個功能,而該功能可能用其他語言已經實現了,那么我們可以調用其他語言寫好的模塊嗎?還有就是,由于C#開發好的項目,我們可…

Python3.5以上版本lxml導入etree報錯Unresolved reference

Web抓取Web站點使用HTML描述,這意味著每個web頁面是一個結構化的文檔。有時從中 獲取數據同時保持它的結構是有用的。web站點不總是以容易處理的格式, 如 csv 或者 json 提供它們的數據。 這正是web抓取出場的時機。Web抓取是使用計算機程序將web頁面數據…

linux設置history歷史記錄

#說明export HISTSIZE1000 #設置歷史記錄顯示1000行export HISTTIMEFORMAT%F %T #設置歷史記錄格式 999 2017-08-15 10:58:32 #修改vim /etc/profilesed -i "s/\(HISTSIZE\).*/\11000/" /etc/profilesed -i "/HISTSIZE/aexport HISTTIMEFORMAT%F %T " /et…

STL-容器庫101--array【C11】

1. 原型 C11提供 template < class T, size_t N > class array;T&#xff1a; 元素類型&#xff0c;以 array::value_type 作為別名使用&#xff1b;N&#xff1a; array中元素大小&#xff1b; 固定size的序列容器&#xff1b;初始化時&#xff0c; array對象不保存任何…

C#:向C++封送結構體數組

在使用第三方的非托管API時&#xff0c;我們經常會遇到參數為指針或指針的指針這種情況&#xff0c; 一般我們會用IntPtr指向我們需要傳遞的參數地址&#xff1b; 但是當遇到這種一個導出函數時,我們如何正確的使用IntPtr呢&#xff0c; extern "C" __declspec(dll…

其它綜合-CentOS7 忘記root密碼

CentOS7 忘記root密碼 長時間不用的 CentOS 機器再次開機的時候忽然忘記了密碼&#xff0c;總不能就重裝一臺吧&#xff0c;還有好多服務在機器上&#xff0c;于是決定重置root的密碼。   如果是已經開啟的機器&#xff0c;需要進行關閉&#xff0c;重新啟動。在啟動選擇內核…

left join on and 與 left join on where的區別

數據庫在通過連接兩張或多張表來返回記錄時&#xff0c;都會生成一張中間的臨時表&#xff0c;然后再將這張臨時表返回給用戶。 在使用left jion時&#xff0c;on和where條件的區別如下&#xff1a; 1、 on條件是在生成臨時表時使用的條件&#xff0c;它不管on中的條件是否為真…

spring boot高性能實現二維碼掃碼登錄(中)——Redis版

前言 本打算用CountDownLatch來實現&#xff0c;但有個問題我沒有考慮&#xff0c;就是當用戶APP沒有掃二維碼的時候&#xff0c;線程會阻塞5分鐘&#xff0c;這反而造成性能的下降。好吧&#xff0c;現在回歸傳統方式&#xff1a;前端ajax每隔1秒或2秒發一次請求&#xff0c;去…

C# :socket 通訊基礎使用實例

們在講解Socket編程前&#xff0c;先看幾個和Socket編程緊密相關的概念&#xff1a; TCP/IP層次模型當然這里我們只討論重要的四層 01&#xff0c;應用層(Application)&#xff1a;應用層是個很廣泛的概念&#xff0c;有一些基本相同的系統級TCP/IP應用以及應用協議&#xff0…

IBM發表論文:可能已找到處理量子計算退相干的方法

在《自然》雜志最近發表的一篇論文中&#xff0c;IBM和其他機構的研究人員設計了兩種量子算法&#xff0c;利用變分量子電路和量子核估計器來訓練一種支持向量機分類器。這兩種算法背后的關鍵思想是使用量子狀態空間作為特征空間表示&#xff0c;有效地構建映射&#xff0c;從原…

PHP + NGINX 控制視頻文件播放,并防止文件下載

最簡單的方法是使用NGINX的 internal 功能 server { listen 80; server_name www.xxx.com;  location / { index index.php index.html index.htm; root /xxx; if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s$…

可視化調試工具

rosrun rqt_console rqt_console # 查看日志消息&#xff0c;可filter、highlight指定級別。 rosrun rqt_logger_level rqt_logger_level # 可設在日志記錄器的嚴重級別 rosrun rqt_topic rqt_topic # 顯示topic調試信息 rosrun rqt_publisher rqt_publisher # 在界面中管理ro…

C#:委托基礎與事件

通過以下思維導圖&#xff0c;學習委托的基本概念&#xff0c;后面著重講解委托的運用&#xff0c;希望通過最簡單的方式收獲更多的知識。 1.委托的各種寫法 1、委托 委托名new 委托&#xff08;會調用的方法名); 委托名&#xff08;參數&#xff09;; 2、委托 委托名 會調用…