2010-08-10 4 views
0

моей цели

я хочу, чтобы перевести левый щелчок на правую кнопку мышиPInvokeStackImbalance - вызов неуправляемого кода из HookCallback

моего подхода

  • я зарегистрировать крюк низкого уровня через SetWindowsHookEx (user32 .dll)
  • фильтр левый-указатель мыши
  • проверить, хочу ли я перевести конкретный щелчок
  • в случае, если я действительно хочу
    • не передать сообщение
    • создать новый MouseClick через mouse_event (user32.dll тоже)

проблема

когда я делаю описанные такие вещи:

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { 
    if(nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam && doRight) { 
     doRight = false; 
     MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); 
     mouse_event(/*right down + right up*/8 | 16, hookStruct.pt.x, hookStruct.pt.y, 0, 0); 
     return new IntPtr(1); 
    } 
    return CallNextHookEx(_hookID, nCode, wParam, lParam); 
    } 

вызов mouse_event завершился неудачей с помощью PInvokeStackImbalance-Exception, который, я думаю, должен заботиться.

DllImports

, так как обычно PInvokeStackImbalance приходит из-за неправильного импорта подписей здесь мои:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool UnhookWindowsHookEx(IntPtr hhk); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr GetModuleHandle(string lpModuleName); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 
    public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo); 

появление

мой нормальный подход, чтобы локализовать проблему не удается в этом случае - поскольку mouse_event-call для себя работает, и обработка щелчков левой кнопкой тоже работает. я ненавижу, когда структура больше, чем сумма частей ...

ответ

1

mouse_event подпись должна быть, как это

public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, IntPtr dwExtraInfo); 
+0

damn am i stupid - я даже сказал, что обычно подпись неправильная ... но теперь мне интересно - я скопировал сиг из другого проекта (производственный код), и он работает там ... что происходит? – santa

+1

P/Invoke несколько прощает неправильные подписи, хотя в вашем случае неверные данные, вероятно, будут переданы функции. Чтобы предупредить, что у вас неправильная подпись, помощник по отладке PInvokeStackImbalance запускается, если он активен. –

2

mouse_event определяется как:

VOID WINAPI mouse_event(
    __in DWORD dwFlags, 
    __in DWORD dx, 
    __in DWORD dy, 
    __in DWORD dwData, 
    __in ULONG_PTR dwExtraInfo 
); 

WINAPI означает STDCALL , DWORD - uint, ULONG_PTR - UIntPtr. Так правильно, это должно быть:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo); 

Проблема состоит в том, что долго определяется в C#, как 64-бит, в то время как (и) INT является 32-битным. (U) IntPtr - 32-разрядная или 64-разрядная, в зависимости от битности операционной системы.

EDIT: Другими словами, вы передаете слишком много данных в функцию. Поскольку вызывающий очищает стек, PInvoke замечает, что не все было удалено из стека. Он делает это за вас (но вы передали неверные данные, поэтому функция, скорее всего, сделала что-то отличное от того, что вы хотели) и предупреждает вас.

+0

Я знаю о определениях типа CLR-данных, я просто был настолько глуп, чтобы ожидать, что наш производственный код будет правильным :) – santa

2

Есть лот неудачных объявлений p/invoke в Интернете. Обычно они начали жизнь в VB6. На этом языке Integer равен 16 бит, а Long - 32 бита. Возвращается к VB1, который работает в 16-разрядных операционных системах. Они не работают должным образом в VB.NET или C#.

Дисбаланс стека MDA был специально разработан для обнаружения таких плохих объявлений, но это вариант (Debug + Exceptions). Фактический вызов имеет тенденцию работать, если есть только один аргумент или при передаче большого количества нулей. Вероятность того, что код продолжает работать должным образом после вызова, к сожалению, тоже неплохая. Значение указателя стека корректируется при возврате метода. Однако вы можете столкнуться с некоторыми ужасными проблемами.

Смежные вопросы