19

プロジェクトでGma.UserActivityMonitorライブラリを使用しようとしていますが、自分では解決できないエラーに直面しました。

ファイルには、次のコードでHookManager.Callbacks.cs呼び出される静的メソッドがありEnsureSubscribedToGlobalMouseEventsます (多かれ少なかれ):

var asm = Assembly.GetExecutingAssembly().GetModules()[0];
var mar = Marshal.GetHINSTANCE(asm);
s_MouseHookHandle = SetWindowsHookEx(
    WH_MOUSE_LL,
    s_MouseDelegate,
    mar,
    0);
//If SetWindowsHookEx fails.
if (s_MouseHookHandle == 0)
{
    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
    int errorCode = Marshal.GetLastWin32Error();
    //do cleanup

    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
    throw new Win32Exception(errorCode);
}

SetWindowsHookEx常に戻り、上記のコードは message とreturn codeの呼び出しで0例外をスローし続けます。Gma.UserActivityMonitor の元のプロジェクトで提供されているデモを正常に実行できますが、私のプロジェクトは少し複雑すぎてここで説明できないため、私のプロジェクトとの違いを詳しく説明することはできません。誰かが問題を盲目的に推測できることを願っています。The specified module could not be foundMarshal.GetLastWin32Error126

ところで、プロジェクトのFAQでは、プロジェクトがデバッグされているときにのみチェックされると、他の人が私のものに近い問題を抱えている(SetWindowsHookExエラーを返す)と言われています。Enable Visual Studio hosting processそのため、私のボックスのチェックを外しましたが、デバッグモードだけでなく、Windowsエクスプローラーでリリースファイルをダブルクリックしたときも同じ問題が発生します(Visual Studioは関係ありません)。

詳細については、デモ プロジェクト (正常に動作します) でasm変数が指している点{Gma.UserActivityMonitor.dll}と、例外がスローされた私のプロジェクトでも同じです!

4

1 に答える 1

34

この種のコードは、.NET 4 以降では機能しなくなりました。表示されるエラー コードは、126 = "指定されたモジュールが見つかりませんでした" という説明的なものです。これは、「mar」変数にがらくたが含まれていることを示しています。

.NET 4 では、CLR がかなり大幅に変更されました。これにより、jit されたコードがアンマネージ モジュール内に存在するふりをしなくなりました。そのため、Marshal.GetHINSTANCE() は機能しなくなりました。その後、コードはずさんになり、戻り値をチェックするのを忘れます。障害を検出して災害を宣言するには、(IntPtr)-1 をテストする必要があります。Codeproject で見つけたコードにはよくあることですが、寄稿者が修正できない多くのバグやずさんさがあります。SOモデルではありません:)

SetWindowsHookEx() は、低レベルのフックには少し厄介です。有効なモジュール ハンドルが必要であり、それをチェックしますが、実際には使用しません。これは、Win7 SP1 前後の Windows で修正されました。確かに有用な修正を意図していましたが、実際には問題を悪化させました。これは、開発マシンでは機能するが、ユーザーのマシンでは機能しない可能性があるためです。

とにかく、修正は簡単です。有効なモジュールハンドルを吐き出すだけです。マネージド アプリに常に存在するモジュールから取得できます。それを取得するには、LoadLibrary を pinvokeする必要があります。

var mar = LoadLibrary("user32.dll");
s_MouseHookHandle = SetWindowsHookEx(
    WH_MOUSE_LL,
    s_MouseDelegate,
    mar,
    0);

FreeLibrary() を呼び出す必要はありません。そのモジュールは、プログラムが終了するまでロードされたままになります。

于 2013-07-27T13:07:54.627 に答える