0

私の目標

左クリックを右クリックに変換したい

私のアプローチ

  • SetWindowsHookEx (user32.dll) を介して低レベルのフックを登録します
  • マウスの左クリックをフィルタリングする
  • その特定のクリックを翻訳するかどうかを確認します
  • 私が本当にしたい場合に備えて
    • メッセージを伝えないでください
    • mouse_event を介して新しい mouseclick を作成します (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 が機能し、左クリックの破棄も機能するためです。構造が部分の総和よりも大きいのは嫌いです...

4

3 に答える 3

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);

問題は、long が C# で 64 ビットとして定義されているのに対し、(u)int は 32 ビットであるということです。(U)IntPtr は、オペレーティング システムのビット数に応じて、32 ビットまたは 64 ビットです。

編集: つまり、関数にあまりにも多くのデータを渡しています。呼び出し先がスタックを消去するため、PInvoke は、スタックからすべてが削除されたわけではないことに気付きます。それはあなたのためにそれを行います (しかし、あなたは間違ったデータを渡したので、関数はあなたが望んでいたこととは違うことをした可能性があります) そしてあなたに警告します.

于 2010-08-10T11:22:02.710 に答える
2

インターネット上には、不適切な p/invoke 宣言がたくさんあります。彼らは通常、VB6 で生活を始めました。その言語では、Integer は 16 ビットで、Long は 32 ビットです。16 ビット オペレーティング システムで実行されていた VB1 に戻ります。VB.NET または C# では正しく動作しません。

スタックの不均衡 MDA は、このような不適切な宣言をキャッチするように特別に設計されていますが、オプション (デバッグ + 例外) です。実際の呼び出しは、引数が 1 つしかない場合、または多数のゼロを渡す場合に機能する傾向があります。残念ながら、呼び出し後にコードが適切に実行され続ける可能性も悪くありません。スタック ポインターの値は、メソッドが戻るときに自動的に修正されます。ただし、非常に厄介な問題が発生する可能性があります。

于 2010-08-10T12:23:31.123 に答える
1

mouse_eventの署名は次のようになります

public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, IntPtr dwExtraInfo);
于 2010-08-10T11:14:05.703 に答える