1. 程式人生 > >關於C#中使用訊息獲取Message.LParam所包含的資料

關於C#中使用訊息獲取Message.LParam所包含的資料

在C#中也可以使用Windows 訊息,包括系統訊息和自定義訊息。
對於自定義訊息中,對於LParam可以在發中或者接收過程中使用自定義結構來傳遞資料
如:
public struct MyStruct
{
    public int i;
    public string str;
}

傳送訊息可以呼叫WindowsAPI,SendMessage:

MyStruct myst = new MyStruct();
SendMessage(hWnd, WM_USER, 0,ref myst);

接收訊息可通過重寫DefWndProc來實現:

protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
    switch(m.Msg)
    {
        case WM_USER:  // 任何訊息
            int iWPara = (int)m.WParam;
            MyStruct myStr = new MyStruct();
            Type myType=myType.GetType();
            myType = (MyStruct)m.GetLParam(myType);
            break;
        default:
            base.DefWndProc(ref m);//呼叫基類函式處理非自定義訊息。
            break;
    }
}

但是對於一些非自定義的訊息, 如WM_SETTEXT,或者一些第三方應用所發出的訊息,其中的LParam中可能包含的是一個指向字串的指標,如char *,那麼這時候如何取得LParam中的實際資料呢?
以一自定義訊息為例,通過該訊息的m.LParam.ToString()得知儲存的資料型別為"String",
但是使用GetLParam(str.GetType())獲取會出現錯誤,因為GetLParam只接受結構型別。那怎麼辦呢?

在網上查找了很久這方面的資料,發現問問題的很多,但是卻沒有找到直接的答案,能找到的都是通過自定義結構進行傳遞的例子,但這卻並不能解決很多我們無法決定訊息如何傳送的情況,包括在MSDN中,也沒有找到有關於此的直接介紹,後來無意想器,既然LParam是IntPtr的指標型別,那麼,不呼叫GetLParam,而直接獲取該指標指向的記憶體不就可以麼?經過實踐,一次成功:

那就是使用Marshal.Copy,將資料從非託管記憶體指標複製到託管 8 位無符號整數陣列.
如下:

byte[] ch = new byte[256];
System.Runtime.InteropServices.Marshal.Copy(m.LParam,ch,0,255);
string str = System.Text.Encoding.Default.GetString(ch);//轉換為字串

這樣,就成功獲得了m.LParam所包含的字元資料。
利用Marshal.Copy,可以解決很多類似的情況,這樣,無論LParam傳遞過來的是什麼型別,也不能擔心了,所有的訊息,你可以盡情的來使用了~~哈哈
另外,對於指標使用上,我曾嘗試使用unsafe程式碼,編譯執行都正常,卻無法獲得真實資料,不過有了Marshal.Copy,就沒必要再去考慮unsafe了,不是嗎?畢竟unsafe並不是推薦使用的GOOD方式。