无法访问从托管代码传递到非托管代码的数组值

时间:2016-02-19 08:49:53

标签: c# com marshalling com-interop unmanaged

我想做什么

我试图从ac#client.i调用ATL COM服务器(基本上是一个dll)编写的方法我试图通过引用该方法传递一个c风格的一维数组并返回第一个索引数组的值。方法如下:

calc class(C ++)中的函数定义:

    STDMETHODIMP CCalc::ConformantCArray(int ArrSize, int** ptr,int* res)
      {
        (*ptr)++;//***REFERENCE 2*** 
        *res = *(*ptr);//***REFERENCE 1*** 
        return S_OK;
      }

对应的idl声明

    HRESULT ConformantCArray([in] int ArrSize, [in] int** CArray,[out,retval] int* res) ;

在msdn文章的帮助下,我发现可以生成和修改互操作,以便在托管代码和非托管代码之间适当地编组参数。我使用TLBIMP生成了一个Interop,并解组生成的互操作dll以找到签名如下:

修改前签名(IL代码):

    instance int32  ConformantCArray([in] int32 ArrSize,[in] native int CArray)

我修改了IL代码,因为我通过引用传递了1-d数组,生成的interop中缺少引用部分并相应地修改它(从一本关于互操作性的书中提到)。

修改后的签名(IL代码):

    instance int32  ConformantCArray([in] int32 ArrSize,[in] native int & CArray)    

现在我通过使用 GCHANDLE 类固定数组来调用此方法来固定数组,并通过 INTPTR 并在int变量 VAL 中读取返回值。我选择固定对象,因为我担心如果托管数组指针被复制到无人堆栈并且如果复制它将仅复制数组指针引用的第一个值,因为它只是第一个值的地址,这将导致只获取数组的零索引值(如果我想从托管堆栈复制值,堆到非托管堆栈,请纠正我,堆是错的。听起来不错吧?

C#客户端代码:

            int val = 0;
            int[] CArray = {1,2,3};
            GCHandle handle = GCHandle.Alloc(CArray, GCHandleType.Pinned);
            IntPtr ptr = handle.AddrOfPinnedObject();
            int ArrSize = 2;

            try
            {

                val = obj.ConformantCArray(ArrSize, ref ptr);
            }
            finally
            {

                if (handle.IsAllocated)
                    handle.Free();
            }

现在结束我对场景的长期解释,因为我即将提出问题。

我面临的问题:

如果您在第一个代码块中看到代码本身的代码,我将返回第一个索引值,该值应返回 2 (参见参考资料) 1代码块),但它返回一个垃圾值 -14758585

可是: 如果我返回没有代码 *( ptr)++; 的数组的零索引值(查看代码块的参考2)。返回值是 1 正如预期的那样。所以我推断出只有零索引值可用于非托管代码。 如果是这样,为什么?我怎样才能解决这个问题? 我希望能够在服务器端获取数组的所有值。

0 个答案:

没有答案