ここで利用可能な SDK の一部である tccdvc.dll という DLL があります。
DLL は C++ で作成されており、DLL を調べると、リンカー バージョン 6.0 でリンクされていることがわかります。したがって、VC++ 6.0 で作成されたものと推測されます。DLL にはソース コードが付属しておらず、.lib ファイルと .h ファイルのみが付属しています。エクスポートされたすべての関数は、extern "C" (C++ 名マングリングなし) として宣言され、APIENTRY (__stdcall) を使用して宣言されます。
この tccdvc.dll にアクセスするために、Windows XP SP3 (32 ビット) 上の Visual Studio 2010 で C++ (.NET ではない) プログラムを作成しました。これは、提供された .lib ファイルを使用する場合と、LoadLibrary/GetProcAddress を使用する場合の両方で正常に機能します。また、tccdvc.dll を使用する C++ DLL (mywrapper.dll と呼びましょう) も作成しました。これも 2 つのバージョンで、1 つは .lib ファイルを使用し、もう 1 つは LoadLibrary/GetProcAddress を使用します。繰り返しますが、これはうまくいきます。この mywrapper.dll は、__cdecl 呼び出し規約を使用します。これには、tccdvc.dll をロードする InitMyWrapperDLL() という関数が含まれています。LoadLibrary/GetProcAddress を使用する mywrapper.dll のバージョンには、次のようなコードがあります。
typedef int (APIENTRY *TCCPROCTYPE01)();
HMODULE TCCmodule;
TCCPROCTYPE01 Proc_TCC_DVCOpen;
extern "C" __declspec(dllexport) void InitMyWrapperDLL ()
{ TCCmodule = LoadLibrary("tccdvc.dll");
Proc_TCC_DVCOpen = (TCCPROCTYPE01)GetProcAddress(TCCmodule, "TCC_DVCOpen");
...
}
繰り返しますが、C++ フロントエンドを使用すると、これは正常に機能します。ただし、C# (同じマシン上) から呼び出すと、LoadLibrary("tccdvc.dll") 呼び出しは NULL を返します。C# では、次を使用しています。
[DllImport("mywrapper.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi, ExactSpelling=true, EntryPoint="InitMyWrapperDLL")]
private static extern void InitMyWrapperDLL ();
...
InitMyWrapperDLL();
代わりに提供された tccdvc.lib ファイルを使用して mywrapper.dll をコンパイルすると、DLL の初期化が失敗したことを意味するエラー コード 0x8007045a (1114 とも呼ばれます) で失敗し、DLL の名前として mywrapper.dll が与えられます。この失敗は、mywrapper.dll を介してロードされる tccdvc.dll が原因であることが判明しました。
C# で以下を使用しても失敗します。
[DllImport("tcc.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi, ExactSpelling=true, EntryPoint="TCC_DVCOpen")]
private static extern Int32 TCC_DVCOpen ();
...
TCC_DVCOpen();
宣言で「安全でない」も使用しましたが、違いはありませんでした。LoadLibrary() が失敗し、TCC_DVCOpen() にさえ到達しないため、予測可能です。
問題を特定するために、mywrapper.dll の LoadLibrary/GetProcAddress バージョンを再度使用し、C# プログラムに次のコードを追加しました。
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary (string lpLibFileName);
[DllImport("kernel32.dll")]
private static extern Int32 GetLastError ();
...
IntPtr hdll1 = LoadLibrary("mywrapper.dll");
IntPtr hdll2 = LoadLibrary("tccdvc.dll");
Int32 errcode = GetLastError();
この後、hdll1 には有効な値がありますが、hdll2 は 0 です。.NET 3.5 Framework を使用している場合、GetLastError() は再び 0x8007045a を返しますが、.NET 4.0 を使用している場合、GetLastError() は 0 (ERROR_SUCCESS) を返します。
Sysinternals の Process Monitor を使用して詳細情報を取得したところ、tccdvc.dll が正常に読み取られ、マップされていることがわかりました。Process Monitor が表示するものは、C# を使用している場合に失敗する理由についてのヒントを与えてくれませんが、C++ を使用している場合にはそうではありません。
何か案は?ありがとう!