GetDelegateForFunctionPointer

気づいてなかったのですが、.NET2.0からは、関数ポインタをDelegateへ変換して呼び出せるようになったんですね。.NET1.1のころはManaged C++を使ったり、ヘルパDLLを用意したりする必要があったのが、C#だけで解決できるようになったのは良いですね。試しにSusieプラグインを呼び出すサンプルを書いてみました。
画像表示までやると日記で書くようなコード量じゃなくなるので、アーカイブ内のファイル名を列挙するだけです。(^^;

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace Sample
{
    #region Win32 API
    static class Win32Api
    {
        const string KERNEL32 = "kernel32";
        [DllImport(KERNEL32)]
        public extern static IntPtr LoadLibrary(string lpFileName);

        [DllImport(KERNEL32)]
        public extern static bool FreeLibrary(IntPtr hModule);

        [DllImport(KERNEL32, CharSet = CharSet.Ansi)]
        public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

        [DllImport(KERNEL32)]
        public extern static IntPtr LocalLock(IntPtr hMem);

        [DllImport(KERNEL32)]
        public extern static bool LocalUnlock(IntPtr hMem);

        [DllImport(KERNEL32)]
        public extern static IntPtr LocalFree(IntPtr hMem);
    }
    #endregion

    delegate int GetPluginInfo(int infono, byte buf, int len);
    delegate bool IsSupported(string filename, IntPtr dw);
    // GetArchiveInfo関数は使い方によってdelegateを分けてみた
    delegate int GetArchiveInfoFromFile(string filename, int offset, uint flag, out IntPtr hInfo);
    delegate int GetArchiveInfoFromMemory(IntPtr ptr, int len, uint flag, out IntPtr hInfo);

    // Susieのアライメントは1らしい
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    unsafe public struct FileInfo
    {
        public fixed byte method[8];        /* 圧縮法の種類 */
        public uint position;               /* ファイル上での位置 */
        public uint compsize;               /* 圧縮されたサイズ */
        public uint filesize;               /* 元のファイルサイズ */
        public uint timestamp;              /* ファイルの更新日時 */
        public fixed byte path[200];        /* 相対パス */
        public fixed byte filename[200];    /* ファイルネーム */
        public uint crc;                    /* CRC */
    }

    class Program
    {
        static void ShowVersionInfo(GetPluginInfo gpi)
        {
            byte buf = new byte[256];
            int n = 0;
            while (true)
            {
                int ret = gpi(n, buf, buf.Length);
                if (ret <= 0)
                    break;
                string s = Encoding.Default.GetString(buf).Trim(Char.MinValue);
                Console.WriteLine(s);
                ++n;
            }
        }

        static void ShowInfo(IntPtr hInfo)
        {
            unsafe
            {
                IntPtr ptr = Win32Api.LocalLock(hInfo);
                FileInfo* pfi = (FileInfo*)ptr.ToPointer();
                while (true)
                {
                    string method = Marshal.PtrToStringAnsi*1
                        break;
                    // アーカイブ内にあるファイル名を表示
                    string name = Marshal.PtrToStringAnsi*2;
            // バージョン情報を表示してみる
            ShowVersionInfo(gpi);

            pFunc = Win32Api.GetProcAddress(hModule, "IsSupported");
            IsSupported isSupported = (IsSupported)
                Marshal.GetDelegateForFunctionPointer(pFunc, typeof(IsSupported));
            using (FileStream fs = new FileStream(archive, FileMode.Open))
            {
                bool flag = isSupported(archive, fs.SafeFileHandle.DangerousGetHandle());
                if (flag)
                    Console.WriteLine("Plugin support {0}.", archive);
            }

            // このサンプルは、pluginを
            // Archive extractor,Multi-pictureを前提にしている
            pFunc = Win32Api.GetProcAddress(hModule, "GetArchiveInfo");
            GetArchiveInfoFromFile gai = (GetArchiveInfoFromFile)
                Marshal.GetDelegateForFunctionPointer(pFunc, typeof(GetArchiveInfoFromFile));

            IntPtr hInfo;
            int ret = gai(archive, 0, 0, out hInfo);
            if (ret == 0)
            {
                ShowInfo(hInfo);
                Win32Api.LocalFree(hInfo);
            }

            Win32Api.FreeLibrary(hModule);
        }
    }
}

*1:IntPtr)pfi->method).Trim(Char.MinValue); // methodが空になったら打ち切り if (String.IsNullOrEmpty(method

*2:IntPtr)pfi->filename); Console.WriteLine(name); ++pfi; } Win32Api.LocalUnlock(hInfo); } } static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("xxx.exe plugin archive"); return; } string plugin = args[0]; string archive = args[1]; IntPtr hModule = Win32Api.LoadLibrary(plugin); IntPtr pFunc = IntPtr.Zero; pFunc = Win32Api.GetProcAddress(hModule, "GetPluginInfo"); GetPluginInfo gpi = (GetPluginInfo) Marshal.GetDelegateForFunctionPointer(pFunc, typeof(GetPluginInfo