互操作:带有C#COM服务器字节数组参数的C++COM客户端-是直接复制入/出或访问的数组



我们有一个C#/.Net COM服务器(COM可见程序集),具有以下接口&类声明:

[ComVisible(true)]
[Guid( "..." )]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITest
{
    void TestMethod( [In] int nNumElements, 
                     [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte [] bArray );
}
[ComVisible(true)]
[Guid( "..." )]
[ClassInterface( ClassInterfaceType.None )]
[ProgId( "CSCOMServer.CSTest" )]
public class CSTest : ITest
{
    public void TestMethod( int nNumElements, byte [] bArray )
    {
        for (int i = 0; i < bArray.Length; i++)
        {
            bArray [i] = (byte)i;
        }
    }
}

生成的IDL/typelib是:

...
interface ITest : IUnknown {
    HRESULT _stdcall TestMethod(
                    [in] long nNumElements, 
                    [in, out] unsigned char* bArray);
};
...
coclass CSTest {
    interface _Object;
    [default] interface ITest;
};

目标是能够从C++COM客户端利用这一点,使用以下方法可以很好地工作:

int iSize = 10;
ITest *test;
byte *buf  = (byte*)CoTaskMemAlloc( iSize * sizeof(byte) );
CoCreateInstance( CLSID_CSTest, NULL, CLSCTX_INPROC_SERVER, IID_ITest, (void **) &test );
test->TestMethod( iSize, buf );

缓冲区由C++分配,并传递给C#进行填充。所有操作都很好,在完成TestMethod()后,C++数组(buf)包含由C#方法设置的正确值。

问题在于效率:
Interop包装器是否在封送处理("In"阶段)然后返回("Out"阶段)期间执行数组复制,或者C#方法是否直接对传入的内存(可能被固定)进行操作?

不,这里肯定需要一个副本,因为您要求进行结构更改。CLR必须创建一个托管数组对象,以满足byte[]参数类型的要求。源数组在任何方面都不能按原样使用,因为它只是一块原始内存。另一种方法(byte[]到unsignedchar*)也可以,但这里的情况并非如此。

阵列的普通COM自动化类型是SAFEARRAY btw,没有速度优势,但有更多的COM客户端可以使用您的服务器。

在这种情况下,将在非托管代码和托管代码之间传递引用。在某些情况下,即使没有指定输入/输出参数,"固定优化"也会为您做到这一点(但要用作tlib,必须始终指定输入/流出修饰符)。

可以假设基元类型的一维数组将始终固定(通过引用传递)在同一单元上运行的非托管代码和托管代码之间。

您可以在此处阅读更多信息:http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.80).aspx

有关"钉扎优化"的详细信息:http://msdn.microsoft.com/en-us/library/23acw07k.aspx

最新更新