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