2004.11.05

.net から Unmanaged DLL を呼び出す

(この内容はかなり特異)


.netを使用していても、まだ .netFrameworkのライブラリに不足(シリアルポート参照等)していたり
サードパーティが提供するものが対応していなかったり、して Windows API等なり
サードパーティの DLL-API を呼び出さなくてはいけなくなることがまだよくある。


.netでも Interopというものが用意されており一般的な使用には問題はないのだが、
ちょっとでも構造体やポインタが絡んでくるといきなり厄介になることがある。
取り立てて面倒な例に遭遇したので、以下に記録しておく。


問題になったのは、C(++)で上記のように定義されているAPIを使用したい場合

C++

  typedef struct {
    unsigned char* structMember;
  } structureType;
  LIBRARY_API bool CALLTYPE hogehogeApi (
    structureType* strct;
   );

  // 構造体の中に UCHAR の配列があり、値が返ってくる(構造体自体もポインタ渡し)


VB6.0 / VBA では次のように使用していた。

VB6.0 / VBA

  Public Type structureType
    structMember As Long
  End Type
  Public Declare Function hogehogeApi Lib "hogehoge.dll" (ByRef strct As structureType) As Byte

  Dim strct As structureType
  Dim strctMbr(7) As Byte ' 実際必要になるサイズ-1を指定(VBでは序数の最大値を指定する)

    strct.structMember = VarPtr(strctMbr(0))
    If (hogehogeApi(strct) <> 0) Then ...

  ' ポインタ(もどき)を、VBの非公開関数 VarPtrを使って実現している。


.netでは以下のようにしてようやく解決した。

C#.net

  [StructLayout(LayoutKind.Sequential)]
  struct structureType
  {
    public IntPtr structMember;
  };

  [DllImport("hogehoge.dll")]
  private static extern bool hogehogeApi (
    out structureType strct
   );

  structureType strct= new structureType();
  byte[] strctMbr= new byte[8]; // 必要なサイズ
  strct.structMember= GCHandle.Alloc(strctMbr, GCHandleType.Pinned).AddrOfPinnedObject();

  if ( hogehogeApi(out strct) ) { ... strctMbr[] ... }

  GCHandle.Alloc(strctMbr, GCHandleType.Pinned).Free();

  // ガベージコレクションを一時的に停止させないと正しいアドレスが取れないらしい。


他にもはまりどころ満載なのだが、ひとまず上記まで。

コメント (1)

C#でサードパーティのDLL-APIにshortの配列を渡して結果をつめてもらう方法を探していて通りすがりました。
MSDNの「OSInfo のサンプル」のところに目的の事が書いてあるんじゃないでしょうか
参考にしてみてください。
https://s.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/cpconosinfosample.asp

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
ichikawa