トップ回答者
VC++で実装したDLL内のイベントハンドラを登録する関数をVC#から呼ぶ場合

質問
-
はじめまして。お世話になります。
mkmarimoと申します。
今回、プログラミングに関して自身で解決できない問題が発生してしまったので
ここで質問させていただきます。
ただ、私自身それほどプログラミング上級者ではないので、言っていることが
訳わからないかもしれませんのでご了承ください。
現在、[VC#(EXE) → VC++(DLL) → WIN32API] という関係のプログラムを作成しています。
EXEとDLLは自分で実装しています。
ここで、VC++(DLL)では、あるイベントハンドラ(Aと呼びます)と、
そのイベントハンドラを登録する関数(Bと呼びます)を実装しています。
で、C#からはBを呼んでいます。A内でWIN32APIを利用しています。
※それぞれの属性と戻り値の型は以下のとおりです。
A・・・Public static LONG CALLBACK
B・・・Public BOOL
しかし、Bを呼んだタイミングでこのB内で0x00000005(アクセス違反)で
アプリが落ちてしまいます。
これについて、何か考えられる原因はありますでしょうか。
手のつけようがなくなりご質問させていただきました。
私自身の都合によりソースは公開できませんが、わかる範囲で結構ですので、
ご回答よろしくお願いします。
回答
-
mkmarimo さんからの引用 int hModule = LoadLibrary("XXXXX.dll"); // 自作のDLLです
IntPtr ptr;
ptr = GetProcAddress(hModule, "B");
B func = (B)Marshal.GetDelegateForFunctionPointer(ptr, typeof(B));func(); // ここで落ちます。
ロードしたモジュールを リリース したいという要望がないならば、[DllImport("XXXXX.dll")]private static extern bool func();で良いと思います。とりあえず、例外が発生しているのが func() の部分なのか、XXXX.dll の中なのかも調べたほうがいいでしょう。あとは、delegate B に UnmanagedFunctionPointerAttribute を付与しない場合の呼び出し規約とかを確認されたほうがいいかもしれません。(省略した場合は stdcall だったと思います
すべての返信
-
Hongliangさん
お世話になります。mkmarimoです。
ご返信ありがとうございます。
以下、追加で補足します。
> その VC++ 製の DLL ってのはネイティブってことでいいんですかね?
はい、ネイティブです。
> いずれにせよ、C++ のヘッダの該当部分と C# の呼び出し部分(C++ がネイティブなら DllImport の宣言文も)ぐらいは書い> ていただかないとコメントしづらいですが。
すみません。C++のヘッダの該当部分というのがよくわかりませんが、C#からのDLLの呼び出しは
DllImportでKernel32.dllをインポートし、デリゲートにより実現しています。
この方法をとったのはこれしかわからなかったからです。
一部ソースを載せます。
using System.Runtime.InteropServices;
namespace XXXXXXXXXXXX
{
public delegate bool B();class Program
{
[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
public static extern int LoadLibrary(String lpFileName);[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
public static extern bool FreeLibrary(int hModule);[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr GetProcAddress(int hModule, String lpProcName);static void Main(string[] args)
{
int hModule = LoadLibrary("XXXXX.dll"); // 自作のDLLですIntPtr ptr;
ptr = GetProcAddress(hModule, "B");
B func = (B)Marshal.GetDelegateForFunctionPointer(ptr, typeof(B));func(); // ここで落ちます。
・・・・・・・・・・・・・・・・・・・
・・・・・・・・・・・・・・・・・・・
> ところで、アクセス違反って 0xC0000005 じゃないですっけ。
そのようでした。見間違えました。
以上、よろしくお願いします。
-
mkmarimo さんからの引用 int hModule = LoadLibrary("XXXXX.dll"); // 自作のDLLです
IntPtr ptr;
ptr = GetProcAddress(hModule, "B");
B func = (B)Marshal.GetDelegateForFunctionPointer(ptr, typeof(B));func(); // ここで落ちます。
ロードしたモジュールを リリース したいという要望がないならば、[DllImport("XXXXX.dll")]private static extern bool func();で良いと思います。とりあえず、例外が発生しているのが func() の部分なのか、XXXX.dll の中なのかも調べたほうがいいでしょう。あとは、delegate B に UnmanagedFunctionPointerAttribute を付与しない場合の呼び出し規約とかを確認されたほうがいいかもしれません。(省略した場合は stdcall だったと思います -
遅いレスなので投稿者は見ていないかもしれませんが・・。
これって、単純に XXXX.dll を作成したプロジェクトでデバッグ実行すればすぐに解決しますよね。
ソースも手元にあるようですし・・。
方法はいろいろありますが、
1)メニューから「プロジェクト」「プロパティー」の中の「構成プロパティー」「デバッグ」
で コマンドで 実行するアプリケーションを指定して実行する。
2)XXXX.dll をデバッグコンパイルしたときにできる .pdb ファイルを exe ファイルと同じ場所に配置する。
exeファイルを起動する。
Visual Studio から「デバッグ」「プロセスにアタッチする」で 上記の exe ファイルにアタッチする。
エラーが発生する上記の pdb ファイルを生成したときに利用した ソースファイルを Visual Studio で開いて
ブレークポイントを設定する。
試してみてください。