DOBON.NET DOBON.NETプログラミング掲示板過去ログ

VC++で作成されたDLLの使用

環境/言語:[Windows2000 SP4、C#+VC++、.NET Framework1.1]
分類:[.NET]

以下のようなVC++で作成されたDLLのメソッドを使用したいのですが、
C#では引数をどのように設定してやればいいのかわかりません。

[VC++]
extern "C" int VCTEST_DECLSPEC TestSetDataBuffer(SAFEARAY* pData) {
  return VcTest.SetDataBuffer(pData);
}

int CTest::SetDataBuffer(SAFEARAY* pData) {
  LONG lLBound, lUBound;

  SafeArrayGetLBound(pData, 1, &lLBound);
  SafeArrayGetUBound(pData, 1, &lUBound);
  :
  :// pDataの各配列にDoubleのデータを設定します。
}

これに対して、C#側で以下のように記述しました。
[C#]
[DllImport("VCTest.dll", EntryPoint="TestSetDataBuffer")]
private static extern int TestSetDataBuffer(ref double[] pBuffer);

private void Test() {
  double[] dvData = new double[256];
  int lSts = TestSetDataBuffer(ref dvData);
  :
  :
}

 VC側で各SafeArrayGetLBound()の結果を表示できるようにしたのですが
lLBound、lUBoundともに不定値が入ってしまいます。
自分で色々調べたつもりではありますが、どうしてもわからないので
何とぞご教授お願いします。
C#との連携はしたことないのですが

> int CTest::SetDataBuffer(SAFEARAY* pData) {
ここって
LPSAFEARRAY*型でなくてもいけるのかなぁ?
(VB6以前との連携ではLPSAFEARRAY*型で受け取る)

それと、SafeArrayLock〜SafeArrayUnlockをはなくてもいいのかなぁ?
2006/03/07(Tue) 11:19:19 編集(投稿者)

http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpguide/html/cpcondefaultmarshalingforarrays.asp
を参考に確かめてみました。

[VC](VC++6.0)
int WINAPI Sample( LPSAFEARRAY* arg )
{
    SAFEARRAY* psa = *arg;
    
    if ( psa->cDims != 1 ) return 0;

    ::SafeArrayLock( psa );

    long int i, lb, ub;
    ::SafeArrayGetLBound( psa, 1, &lb );
    ::SafeArrayGetUBound( psa, 1, &ub );

    int result = 0;
    for ( i = lb; i <= ub; ++i )
    {
        int n;
        ::SafeArrayGetElement( psa, &i, &n );
        result += n;
    }

    ::SafeArrayUnlock( psa );

    return result;
}

[C#] (.NET Framework 1.1)
using System.Runtime.InteropServices;

public class test
{
    [ DllImport( "csdll.dll", EntryPoint = "Sample" ) ]
    private static extern int Sample
        ( [ MarshalAs( UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4 ) ] ref int[] arg );
    public static void Main()
    {
        int[] arg = new int[] { 1, 2, 3, 4 };
        int result = Sample( ref arg );
        System.Console.WriteLine( "結果は {0} です。", result );
    }
}
>>int CTest::SetDataBuffer(SAFEARAY* pData) {
> ここって
> LPSAFEARRAY*型でなくてもいけるのかなぁ?
> (VB6以前との連携ではLPSAFEARRAY*型で受け取る)
すみません、
ここは別に SAFEARAY*型 でもいけました。

ということで、C#側だけを直せばうまくいくのかな。
>Blueさん
色々と調査の上のご教授に感謝します。

Blueさんからのアドバイスを元に色々試した所、
VC++のDLL側をLPSAFEARRAY*で受ける事で正しく動作しました。
[VC++]
extern "C" int VCTEST_DECLSPEC TestSetDataBuffer(LPSAFEARAY* pData) {
  SAFEARRAY* pWkData = *pData;
  return VcTest.SetDataBuffer(pWkData);
}

[C#]
private static extern int TestSetDataBuffer
        ([MarshalAs(UnmanagedType.SafeArray)] ref double[] pBuffer);

体調を壊していたため確認が遅くなりましたが、
どうもありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板