我有这个c ++函数:
unsigned int ReadUserMemory( unsigned char *lpBuffer, unsigned int iAddress, unsigned int nNumberOfByte );
从内存的nNumberOfByte
读取iAddress
字节并将其放入lpBuffer
。
我用它创建了一个ATL对象(将在C#中使用):
[id(6), helpstring("method ReadUserMemory")] HRESULT ReadUserMemory(BYTE* lpBuffer, [in] ULONG iAddress, [in] ULONG nNumberOfByte, [out,retval] ULONG* result);
我既不是C#程序员,也不是经验丰富的ATL程序员!现在我将使用以下代码在C#中测试此函数:
byte [] b = new byte[100];
axObj.ReadUserMemory(b, 0, 100);
但显然这段代码错了。如何调用此方法?提前谢谢。
答案 0 :(得分:1)
我认为Peter R有一个非常有效的观点,因为使用COM很复杂,因为它需要学习COM以及C ++和C#,正如您所发现的那样。 C ++互操作是另一种选择,但这也需要学习第三种技术,称为C ++ / CLI,它可能比COM更合适,但仍然可能存在问题。 COM和C ++ / CLI都是非常庞大,复杂的野兽,所以你可能最好只在dll中声明你需要的C函数并使用P / Invoke,参见例如http://msdn.microsoft.com/en-us/magazine/cc164123.aspx。如果是这样,您可以在How can I pass a pointer to an array using p/invoke in C#?中找到您想要的魔力。
假设你想继续沿着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。