0

我们有一个具有以下接口和类声明的 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# 方法是否直接在传入的内存(可能被固定)上操作?

4

2 回答 2

2

不,这里肯定需要一份副本,因为您要求进行结构更改。CLR必须创建一个托管数组对象以满足 byte[] 参数类型要求。并且源数组不能按原样使用,因为它只是一块原始内存。另一种方式 (byte[] to unsigned char*) 可以工作,但这里不是这种情况。

数组的普通 COM 自动化类型是 SAFEARRAY 顺便说一句,没有速度优势,但有更多的 COM 客户端可以使用您的服务器。

于 2012-07-10T17:07:01.723 回答
1

在这种情况下,将在非托管代码和托管代码之间传递引用。即使未指定 in/out 参数,“固定优化”也会在某些情况下为您执行此操作(但用作 tlib 始终必须指定 in/out 修饰符)。

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

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

有关“固定优化”的更多信息:http: //msdn.microsoft.com/en-us/library/23acw07k.aspx

于 2012-07-10T14:58:04.807 回答