2

最近、セカンダリ ライブラリ/バイナリ モジュールのリソースを操作していて、奇妙なエラーが発生しました。

2 つのネイティブ WinAPI 参照があります。

[DllImport("kernel32.dll", SetLastError = true)]
public extern static bool EnumResourceNames(IntPtr hModule, int lpszType, EnumResNameProc lpEnumFunc, IntPtr lParam);

[DllImport("kernel32.dll", SetLastError=true)]
public extern static IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags);

LoadLibraryEx を呼び出すと、必要なだけの IntPtr インスタンスが取得されます。

IntPtr x = WinApi.LoadLibraryEx(@"D:\Software\Reflector\Reflector.exe",IntPtr.Zero,2);
Debug.WriteLine(x.ToInt32());

ただし、アイコン リソースを列挙しようとすると (ID = 3 で定義):

Debug.WriteLine(WinApi.EnumResourceNames(x, 3, new EnumResNameProc(ListCallback), IntPtr.Zero));
Debug.WriteLine(Marshal.GetLastWin32Error());

次のエラー コードが表示されます (GetLastError によって返されます)。

-532462766

これは通常、私の知る限り、不明なエラーがあることを意味しますが、ちょっと興味があります - 実行可能ファイルからリソースを一覧表示する際の問題は何でしょうか?

4

2 に答える 2

4

-532462766 == 0xe0434352. 最後の 3 つの 16 進数のペアは "CCR" を綴ります。これは、Microsoft のプログラマーが簡単に認識できる例外コードを考え出すために使用する一般的なトリックです。正確な意味は、マネージ コードに一般的に関連付けられており、通常は意味のあるマネージ例外を生成することに失敗しないサブシステムでは非常に低レベルであるように見えることを超えて、非常に神秘的です。

その不思議な例外には優れた理由の候補があります.EnumResourcesのpinvoke宣言が間違っています. 2 番目の引数は int ではなく IntPtr です。これは、64 ビット オペレーティング システムでカブームになる可能性があります。

CCR の意味がわかったら、返信してください。


using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics;

class Program {
    static void Main(string[] args) {
        try {
            IntPtr module = LoadLibraryEx(@"C:\windows\system32\user32.dll", IntPtr.Zero, 2);
            if (module == IntPtr.Zero) throw new Win32Exception();
            if (!EnumResourceNames(module, (IntPtr)3, new EnumResNameProc(ListCallback), IntPtr.Zero))
                throw new Win32Exception();
        }
        catch (Win32Exception ex) {
            Console.WriteLine(ex.Message);
        }
        Console.ReadLine();
    }

    static bool ListCallback(IntPtr hModule, IntPtr type, IntPtr name, IntPtr lp) {
        long idorname = (long)name;
        if (idorname >> 16 == 0) Console.WriteLine("#{0}", idorname);
        else Console.WriteLine(Marshal.PtrToStringAnsi(name));
        return true;
    }

    public delegate bool EnumResNameProc(IntPtr hModule, IntPtr type, IntPtr name, IntPtr lp);
    [DllImport("kernel32.dll", SetLastError = true)]
    public extern static bool EnumResourceNames(IntPtr hModule, IntPtr type, EnumResNameProc lpEnumFunc, IntPtr lParam);
    [DllImport("kernel32.dll", SetLastError = true)]
    public extern static IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags);
}
于 2011-01-22T01:32:35.983 に答える
0

Hans Passant は正しいとしていますが、エラー メッセージを詳しく説明すると、0xe0434352 は .NET 例外の一般的なエラー コードです。これを Visual Studio デバッガーから実行するSystem.ArgumentExceptionと、EnumResourceNames がコールバックを呼び出そうとしたときに a が発生していることがわかります。エラーメッセージは次のとおりです。

String として渡されるポインターは、プロセスのアドレス空間の下位 64K にある必要はありません。

この例外は EnumResourceNames によってキャッチされ、失敗に変わります。Hans が示したように、解決策は、コールバック関数が 2 番目と 3 番目のパラメーターを文字列ではなく IntPtr として受け取る必要があることです。

于 2013-11-12T00:58:37.013 に答える