0

マネージドC#コードとアンマネージドC++コードの間で配列をマーシャリングするプロジェクトを実装しようとしています。私は問題に直面していて、ウェブ上で私が見つけた解決策はどれもうまくいかないようです。この点についてのコメントをいただければ幸いです。

私は完全なコードを提示していませんが、問題を示す非常に単純化された部分です。大きな作品のように見えますが、非常にシンプルですが、概念的なものです。できるだけ多くの全体像を伝えたかっただけです。

C ++部分:

Object.h

class cObject
{
public:
    //...constructor, destructor...
    int Method_Known_Size(double* array, int size);
    int Method_Unknown_Size(double* array);
    ...
    void FreeArray(double* p);
}

Object.cpp

int Method_Known_Size(double* array, int size)
{
    //modify array somehow..
    for(int i=0; i<size; i++) array[i] = i;

}

int method_Unknown_Size(double* array)
{
    int size = 9;
    array = new double[size];
    for(int i=0; i<size; i++) array[i] = i;
}

(Caller.hをスキップ) Caller.cpp

//...callers for constructor, destructor, for releasing unmanaged memory...
extern "C" int __stdcall Run_Known_Size(cObject* pObject, double* array, int size)
{
     return cObject->Method_Known_Size(array, size);
}

extern "C" int __stdcall Run_Unknown_Size(cObject* pObject, double* array)
{
     return cObject->Method_Unknown_Size(array);
}

extern "C" void __stdcall Release(cObject* cObject, double* array)
{
     if(cObject != NULL) cObject->FreeArray(array);
}

したがって、基本的にRun_Known_Sizeメソッドは、C#メモリによってすでに割り当てられているものRun_Unknown_Sizeを変更し、配列を作成して変更します。

C#パート

public class DllWrapper: IDisposable
{       
    /* Creating an object, disposing,...
    [DllImport("cObject.dll")]
    CreateObject();...DisposeObject(IntPtr pObject);
    ...CallFreeArray(IntPtr pArray);*/

    [DllImport("cObject.dll")]
    private static extern int CallRun_Known_Size(IntPtr pObject, 
           [Out] double [] arr_allocated, int size);

    [DllImport("cObject.dll")]
    private static extern int CallRun_Unknown_Size(IntPtr pObject, 
           [Out] IntPtr arr_not_allocated);                         

    private IntPtr m_pNativeObject;

    public DllWrapper()
    {
        this.m_pNativeObject = CreateObject();
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool bDisposing)
    {
        if (this.m_pNativeObject != IntPtr.Zero)
        {
            DisposeObject(this.m_pNativeObject);
            this.m_pNativeObject = IntPtr.Zero;
        }

        if (bDisposing)
        {
            GC.SuppressFinalize(this);
        }
    }

    ~DllWrapper()
    {
        Dispose(false);
    }

    public void ReleaseUnmanAraray(IntPtr pArr)
    {
        CallFreeArray(pArr);
    }

    public int Run_Known_Size(double[] arr_allocated, int size)
    {
        return CallRun_Known_Size(this.m_pNativeObject, arr_allocated, size);
    }

    public int Run_Unknown_Size(IntPtr arr_not_allocated)
    {
        return CallRun_Known_Size(this.m_pNativeObject, arr_not_allocated);
    }
}

static void Main(string[] args)
{
    double[] alloc_arr = new double[] { 1, 5, 3, 3, 5, 5, 8, 9,1 };
    int size = 9;            


    double[] Arr_for_Copy = new double[size];

    IntPtr pArr = new IntPtr();

    DllWrapper wrapper = new DllWrapper();

    int res1 = Run_Known_Size(alloc_arr, size);
    int res2 = Run_Unknown_size(pArr);

    if (pArr != IntPtr.Zero) // pArr IS ZERO ALWAYS!!!!!!
    {
        Marshal.Copy(pArr, Arr_for_Copy, 0, size);
    }
    else
    {
        Console.WriteLine("Pointer was zero again");
    }

    wrapper.ReleaseUnmanAraray(pScores);
    wrapper.Dispose();

    Console.ReadLine();
}

C#で割り当てられた配列では、すべてが正常に機能します。これらの配列は、エラーなしでC++から変更されています。しかし、配列のサイズがわからないために配列を事前に割り当てることができなかった場合、私が見つけた唯一の解決策は、[Out] IntPtrを渡し、C ++にメモリを管理させ、配列を割り当てて変更することです。次に、返されたIntPtrをC#のdouble []配列にマーシャリングできます。これは、サイズがすでにわかっているためです(簡単にするために、サイズとして4を入力しますが、サイズを決定するためにint *サイズを渡します)。

IntPtrを渡し、このポインターに基づいてC ++で配列を作成した後、すべての試行はゼロポインター(エラーなし)で終了します。

COMオブジェクトを含むソリューションを見てきましたが、移植性の問題があるため、それを使用することは避けなければなりません。

前もって感謝します。

4

1 に答える 1

5

のパラメータはMethod_Unknown_Sizeであり、パラメータ自体double*を変更しています。呼び出し元から送信された元の値を変更する場合は、パラメーターを配列へのポインターとして定義する必要があります。これは、doubleのポインターへのポインターまたはdoubleのポインターへの参照を意味します。

また、何らかの方法で、呼び出し元に配列のサイズを伝える必要があります(すでに管理していると思います)。

C ++:

int method_Unknown_Size(double *&array)
{
    int size = 9;
    array = new double[size];
    for(int i=0; i<size; i++) array[i] = i;
    return size;
}

void FreeArray(double *&p)
{
    delete[] p;
    p = NULL;
}

extern "C" int __stdcall Run_Unknown_Size(cObject *pObject, double *&array)
{
     return cObject->Method_Unknown_Size(array);
}

extern "C" void __stdcall Release(cObject *cObject, double *&array)
{
     if(cObject != NULL) cObject->FreeArray(array);
}

C#:

[DllImport("cObject.dll")]
private static extern int Run_Unknown_Size(IntPtr pObject, 
       out IntPtr arr_not_allocated);

[DllImport("cObject.dll")]
private static extern int Release(IntPtr pObject,
       ref IntPtr arr_not_allocated);


// to allocate the array:
IntPtr pArr;
int res2 = Run_Unknown_size(m_pNativeObject, out pArr);

// to free the array:
Release(m_pNativeObject, ref pArr);

これは絶対に機能します!そうでない場合は教えてください!

于 2013-03-05T07:42:10.137 に答える