2015-11-05 39 views
2

我已經成立了一個WH_MOUSE掛鉤,一切都只是工作正常,我不能讓lparam(指針MOUSEHOOKSTRUCT結構)傳遞給我的HOOKPROC功能在C#中正確轉換。如何正確翻譯WH_MOUSE LPARAM託管代碼

我的項目由兩部分組成,一部分是C++中的非託管部分,它執行掛鉤和過濾並通知託管代碼。

問題是我得到不正確的數據,例如翻譯後的怪異X和Y座標lparam。大多數時候X是0,而大多數時候Y是正確的,然後每隔一次點擊我得到一個值,例如X爲198437245,Y爲-1等。

請注意,我已經確認以下內容:

  • lparam的值正確傳遞給我的C#代碼(通過託管和非託管部分上的斷點驗證),例如鼠標事件發生時,它們都是2420528
  • 非託管代碼與託管代碼處於相同的上下文中,即相同的地址空間。
  • lparam的價值是正確的,因爲我可以成功使用非託管的部分將其轉換爲有效的座標:

    POINT pt = reinterpret_cast<MOUSEHOOKSTRUCT*>(lparam)->pt; 
    int x = pt.x; // correct, e.g. 250 
    int y = pt.y; // correct, e.g. 400 
    

    但是,使用下面的翻譯後,X和Y變成亂碼。

這裏是我的C++ HOOKPROC功能:

static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam) 
{ 
    // filter messages 
    // ... 

    // send lparam to C# code 
} 

這裏是我如何在C#轉換lparam

IntPtr lparam = ...; // passed from unmanaged code and confirmed to be the same value 
MouseHookStruct mouseData = 
    (MouseHookStruct)Marshal.PtrToStructure(lparam, typeof(MouseHookStruct)); 

這裏是我是如何映射POINTMOUSEHOOKSTRUCT結構,以C#:

[StructLayout(LayoutKind.Sequential)] 
public class POINT 
{ 
    public int x; 
    public int y; 
} 

[StructLayout(LayoutKind.Sequential)] 
public class MouseHookStruct 
{ 
    public POINT pt; 
    public IntPtr hwnd; 
    public uint wHitTestCode; 
    public IntPtr dwExtraInfo; 
} 

我在做什麼明顯錯誤?

UPDATE

sizeof(MOUSEHOOKSTRUCT)在C++和C#兩個打印20Marshal.SizeOf(typeof(MouseHookStruct))

我在Windows 7 64位,但C#和C++代碼都編譯並運行爲32位。

+0

你正在處理的案例中* nCode *在你的* InternalMouseHookCallback *中小於零? – IInspectable

+0

@IInspectable,是的,在這種情況下,我只是'返回CallNextHookEx(...)', –

+0

這應該真的進入問題。你是否比較了非託管MOUSEHOOKSTRUCT和你的MouseHookStruct的大小?他們應該是一樣的。同樣,所有成員的抵消應該是相同的。 – IInspectable

回答

0

我發現到Marshal.ReadInt32(lparam)Marshal.ReadInt32(lparam, 4)多次調用讀取XY值,而執行流程已經達到了我的C#代碼沒有返回相同的值。如果我正在閱讀它只是足夠快,我會得到正確的結果,但不會在下一次迭代。

這使我相信,到時候lparam達到我的C#代碼,我想要處理它,底層結構被釋放,lparam指向垃圾。

我不知道爲什麼我大部分時間都不知道爲什麼會得到正確的Y值,這真的讓我失望,並且讓我懷疑結構映射是不正確的,也許是因爲它的內存在稍後被填充,而X的記憶瞬間被其他東西填滿。

我已經解決了我的問題,讀取C++中的實際MOUSEHOOKSTRUCT字節並將它們發送到我的C#代碼,而不是發送lparam指針。

2
public class POINT 

POINT是本地winapi中的結構。您傾向於將它聲明爲C#中的類。但不是當:

public class MouseHookStruct 
{ 
    public POINT pt; 
    // etc... 
} 

pt場現在是一個參考,而不是一個值。編組人員會嘗試將MOUSEHOOKSTRUCT.pt解引用,就像它是一個指針一樣。非常值得注意的是,這不會產生一個更大的bang響亮的聲音,所以預計會出現AccessViolationException異常。也許你只有在輔助顯示器上進行測試纔會感到不幸。

您必須將其聲明爲struct