繁体   English   中英

如何在C#中使用char *参数调用ActiveX函数

[英]How to call an ActiveX function with char * parameter in C#

我有这个c ++函数:

unsigned int ReadUserMemory( unsigned char *lpBuffer, unsigned int iAddress, unsigned int nNumberOfByte );

它从内存的iAddress读取nNumberOfByte字节并将其放入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);

但是显然,此代码是错误的。 如何调用此方法? 提前致谢。

我认为Peter R有一个非常有效的观点,因为使用COM很复杂,因为您需要学习COM以及C ++和C#。 C ++互操作是另一种选择,但是它还需要学习第三种技术,称为C ++ / CLI,它可能比COM更合适,但仍然会出现问题。 COM和C ++ / CLI都是很大的,复杂的野兽,因此您最好在dll中声明所需的C函数并使用P / Invoke,这可能会更好,请参见例如http://msdn.microsoft.com/zh-cn /magazine/cc164123.aspx 如果是这样,可以在如何使用C#中的p / invoke将指针传递给数组的方法中找到所需的魔术

假设您想继续沿着COM路线前进,我一直在玩弄它,对我来说,您似乎需要通过嵌入在COM dll中的类型库来获得一些可以正常工作的东西。 简而言之,我无法使COM interop与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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM