C#::X64
従来型DLLをC#から使うときの話はid:lord_hollow:20090606:p1に書いてあるんだけども、32bit環境でずーーっと開発してきたDLLとC#アプリを64Bitマシンで動かしてみたらLoadLibraryで失敗した。
そのときのエラーメッセージは"有効なWin32アプリケーションではありません"。x64環境なのにエラーメッセージはWin32のままですね。怠慢ではないのか!(笑
で、だ。いろいろ調べてみると・・・作ったままの状態のプロジェクトはターゲットプラットフォームが"AnyCPU"になっていて、x86だろうがx64だろうが動く中間コードを吐く。それをx64で動かすとx64モードで動くわけだけど、C++で作ったDLLは当然x86のままなのでまー普通に動かない、というのが原因のようです。
x64環境はどちらかというとイレギュラーな環境なので、DLLをx64でビルドしなおすという解決方法は使わないとすると、対策としては、C#プロジェクトの[プラットフォーム ターゲット] プロパティを「X86」に設定するだけ、らしい。これでx64環境でもx86として実行されるようになる(遅くなったりするのかも)。
ところがどっこいこのプロパティはExpressEditionでは表示されないので、その場合はcsprojファイルを直接編集する必要があるようです。
http://www.microsoft.com/japan/msdn/vstudio/express/support/knownIssues/
最初の
セクションを探し、次の行を追加します。
x86
ところで、Win32APIを呼んで失敗したときのGetLastError/FormatMessageまでの一連の流れはC#では以下のように簡単に書けるようです。
class Library : IDisposable{ [DllImport("kernel32.dll", SetLastError=true)] private static extern IntPtr LoadLibrary(String lpFileName); [DllImport("kernel32.dll")] private static extern Boolean FreeLibrary(IntPtr hLibModule); public Library(string dllName){ hModule = LoadLibrary(dllName); if (hModule == IntPtr.Zero){ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } public void Dispose(){ FreeLibrary(hModule); } }
インポートするときの属性に"SetLastError=true"を追加して、コール後に戻り値が異常だったらWin32Exception(Marshal.GetLastWin32Error())をスローするだけ。便利だね。マーシャラ賢すぎる。きっとこの部分の開発チームは超苦労したことでしょう。
FormatMessageの可変長部分は処理されないので、必要に応じて別途置換する必要があるようですが。