我认为 Peter R 有一个非常有效的观点,因为使用 COM 很复杂,因为它需要学习 COM 以及 C++ 和 C#,正如您所发现的。C++ 互操作是另一种选择,但这也需要学习第三种技术,称为 C++/CLI,它可能比 COM 更适合,但仍然存在问题。COM 和 C++/CLI 都是相当大而复杂的野兽,所以你最好只在 dll 中声明你需要的 C 函数并使用 P/Invoke,参见例如http://msdn.microsoft.com/en-us /杂志/cc164123.aspx。如果是这样,您可以在如何使用 C# 中的 p/invoke 传递指向数组的指针中找到您想要的魔法?.
假设您想继续沿 COM 路线走下去,我尝试了一下,对我来说,您似乎需要通过嵌入在 COM dll 中的类型库来获得可以工作的东西。简而言之,我无法使 COM 互操作与 . 一起工作unsigned char *lpBuffer
,尽管也许其他人可以!使用的类型库友好类型是 SAFEARRAY,它本质上是 VB 喜欢查看数组的方式。
在这种情况下,您的 idl 变为
[id(1)] HRESULT ReadUserMemory([out] SAFEARRAY(byte)* buffer, [in] ULONG iAddress, [in] ULONG nNumberOfByte, [out,retval] ULONG* result);
您的 C++ 实现看起来像这样
STDMETHODIMP CObj::ReadUserMemory(SAFEARRAY ** pBuffer, ULONG iAddress, ULONG nNumberOfByte, ULONG* result)
{
if (pBuffer== nullptr)
return E_POINTER;
SAFEARRAY*& psa = *pBuffer;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = nNumberOfByte;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
if(psa == NULL)
return E_OUTOFMEMORY;
void* data = nullptr;
SafeArrayAccessData(psa, &data);
for(int i=0; i<nNumberOfByte; ++i) {
((char*)data)[i] = (char)i;
}
SafeArrayUnaccessData(psa);
return S_OK;
}
SafeArrayUnaccessData
即使SafeArrayAccessData
失败后的代码也应该调用。
C# 客户端现在看起来像这样,特别是我们已经从 更改byte[]
为System.Array
static void Main(string[] args)
{
RUMLib.IObj axObj = new RUMLib.Obj();
Array a = null;
axObj.ReadUserMemory(out a, 2, 6);
for (int i = 0; i < a.Length; ++i)
{
Console.Write("{0},", a.GetValue(i));
}
Console.WriteLine();
}
程序的输出是
0,1,2,3,4,5,
请注意,当数据从 SAFEARRAY 返回到 C# 数组时,可能会进行编组,即复制数据。这对您来说可能会非常昂贵,在这种情况下建议您使用 C++/CLI 或 P/Invoke。