1

が痛い。WinApi (FindResource) を使用して、exe からリソースを読み込もうとしています。WinApi を使用して文字列リソースを正常に作成し、それらが PE エクスプローラー、Resource Hacker、および Hex Editor で存在することを確認しました。

私ができないのは、FindResource を介してそれらを見つけることです。関数は終了し、何らかのポインターを返し、LastError を 0 に設定します。ただし、ポインターbは無効なメモリを指しています。FindResource を 4 つの異なる方法でインポートしようとしましたが、すべて同じ結果になりました (b1、b2、b3、b4 は各宣言の b を意味します)。FindResource に「何か」を検索させるには、最初に LoadLibrary が必要であることを発見しました ( a1 = a2は、ロード後にメモリ内の exe の先頭を 正確に指す 2 つの同一のモジュールハンドルであり、異なる関数で取得されたばかりです)。


a (a = a1 = a2) とbは同じメモリ空間にあるに違いない と思いました (モジュールの先頭へのオフセット?)。しかし、b と a の差は常に同じ 16568 です。16 進エディタでは、文字列がオフセット 8000 付近にあり、リソースが作成されるたびに変化することがわかります。何が間違っているのか考えていますが、よくわかりません:

  • MAKELANGID(0, 0)*.mui~ 0 と 0 はニュートラルを表していることは理解しています。どこかでファイルについて何かがあるかもしれないと読みました。
  • リソースの作成により、リソースが壊れましたか? 実際、両方のリソース エディターでリソースを表示するのに問題はありませんでした
  • import 宣言が間違っているかもしれませんが、私は非常に多くの可能性を試しました。
  • リソースを開く/ロックする必要がありますか?

リソースをうまく見つけるにはどうすればよいですか? コードにバグがありますか?


public static class MyClass
{
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern bool FreeLibrary(IntPtr module);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPStr)] string filename);

    [DllImport("kernel32.dll")]
    public static extern IntPtr BeginUpdateResource([MarshalAs(UnmanagedType.LPStr)] string filename, bool deleteExistingResources);
    [DllImport("kernel32.dll")]
    public static extern bool UpdateResource(IntPtr resource, [MarshalAs(UnmanagedType.LPStr)] string type, [MarshalAs(UnmanagedType.LPStr)] string name, ushort language, IntPtr data, uint dataSize);
    [DllImport("kernel32.dll")]
    public static extern bool EndUpdateResource(IntPtr resource, bool discard);

    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "FindResource", SetLastError = true)]
    public static extern IntPtr FindResource1(IntPtr module, [MarshalAs(UnmanagedType.LPStr)]string name, [MarshalAs(UnmanagedType.LPStr)] string type);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "FindResource", SetLastError = true)]
    public static extern IntPtr FindResource2(IntPtr module, IntPtr name, IntPtr type);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "FindResource", SetLastError = true)]
    public static extern IntPtr FindResource3(IntPtr module, [In, MarshalAs(UnmanagedType.LPStr)]string name, [In, MarshalAs(UnmanagedType.LPStr)] string type);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "FindResource", SetLastError = true)]
    public static extern IntPtr FindResource4(IntPtr module, string lpName, string lpType);

    public static ushort MAKELANGID(ushort primaryLanguage, ushort subLanguage)
    {
        return Convert.ToUInt16((subLanguage << 10) | primaryLanguage);
    }

    private static void test()
    {
        string filename1 = "MyApp.exe";
        string filename2 = "MyApp2.exe";
        //if (!File.Exists(filename2))
        {
            // creating resource: name = TEST, type = SYSO, lang-id = neutral
            File.Copy(filename1, filename2, true);
            IntPtr res = BeginUpdateResource(filename2, false);
            string s = "aaahello world";
            UpdateResource(res, "SYSO", "TEST", MAKELANGID(0, 0), Marshal.StringToHGlobalAnsi(s), (uint) (s.Length));
            EndUpdateResource(res, false);
        }
        // find resource
        IntPtr a1 = LoadLibrary(filename2);
        IntPtr a2 = GetModuleHandle(filename2);
        IntPtr hInstance = Marshal.GetHINSTANCE(typeof(MyClass).Module);
        if (a1 == a2)
            Console.WriteLine("a1 = a2 = " + a2 + ", hInstance: " + hInstance);
        else
            Console.WriteLine(a1 + " != " + a2);

        for (int i = 0; i < 10; i++)
            Console.WriteLine("." + Marshal.ReadByte(a2 + i));

        IntPtr b1 = FindResource1(a2, "TEST", "SYSO");
        IntPtr b2 = FindResource2(a2, Marshal.StringToHGlobalAnsi("TEST"), Marshal.StringToHGlobalAnsi("SYSO"));
        IntPtr b3 = FindResource3(a2, "TEST", "SYSO");
        IntPtr b4 = FindResource4(a2, "TEST", "SYSO");

        Console.WriteLine(" -> res: " + b1 + ", " + (b1.ToInt32() - a2.ToInt32()) + ", " + Marshal.PtrToStringAnsi(b1));
        Console.WriteLine(" -> res: " + b2 + ", " + (b2.ToInt32() - a2.ToInt32()) + ", " + Marshal.PtrToStringAnsi(b2));
        Console.WriteLine(" -> res: " + b3 + ", " + (b3.ToInt32() - a2.ToInt32()) + ", " + Marshal.PtrToStringAnsi(b3));
        Console.WriteLine(" -> res: " + b4 + ", " + (b4.ToInt32() - a2.ToInt32()) + ", " + Marshal.PtrToStringAnsi(b4));

        for (int i = 0; i < 10; i++)
            Console.WriteLine("." + Marshal.ReadByte(b1 + i));
    }

    [STAThread]
    public static void Main()
    {
        test();
        Console.ReadKey();
    }
}


インターネット上に FindResource に関する非常に多くの投稿があることを知っており、それらの多くを読みましたが、この問題が修正されたものはありませんでした。

4

1 に答える 1

3

FindResource()リソースへのポインターではなく、ハンドルを返します。データを取得するには、さらにいくつかの手順が必要です。LoadResource()次にLockResource()、実際のリソース バイトへのポインタを取得する必要があります。

私が知る限り、これは古い 16 ビット時代からの名残です。

于 2013-02-21T18:58:49.243 に答える