将SAFEARRAY从c返回到c#

将SAFEARRAY从c返回到c#,第1张

概述我有一个创建,填充和返回SAFEARRAY的c方法: SAFEARRAY* TestClass::GetResult(long& size) { return GetSafeArrayList(size);}How should I export that function in a DLL so that c# could take itHow should I write c 我有一个创建,填充和返回SAFEARRAY的c方法:

SAFEARRAY* TestClass::GetResult(long& size) {    return GetSafeArrayList(size);}How should I export that function in a DLL so that c# Could take itHow should I write c# method signature?

我有以下几点:

extern "C" __declspec(dllexport) voID GetResult(SAFEARRAY*& data,long& size){    size = 0;    data = handle->GetResult(size);}

这是对的,不是吗?

感谢帮助!

编辑:

c#来电:

public static extern voID GetResult(IntPtr handle,[MarshalAs(UnmanagedType.SafeArray,SafeArraySubType = VarEnum.VT_USERdefineD)] TestStruct[] data,ref int size);
解决方法 使用SAFEARRAY(int)的完整示例C# – > C – > C#(因此数组在C#中用一些数据初始化,传递给C,在那里修改并返回到C#).

C :

// For the varIoUs _t classes for handling BSTR and IUnkNown#include <comdef.h>struct ManagedUDT{    BSTR m_str01;    int m_int01;    ~ManagedUDT()    {        ::SysFreeString(m_str01);        m_str01 = NulL;    }};extern "C" __declspec(dllexport) voID GetResult(SAFEARRAY*& data){    if (data != NulL)    {        // Begin print content of SAFEARRAY        VARTYPE vt;        HRESulT hr = SafeArrayGetvartype(data,&vt);        if (SUCCEEDED(hr))        {            // To make this code simple,we print only            // SAFEARRAY(VT_I4)            if (vt == VT_I4)            {                int *pVals;                hr = SafeArrayAccessData(data,(voID**)&pVals); // direct access to SA memory                if (SUCCEEDED(hr))                {                    long lowerBound,upperBound;  // get array bounds                    SafeArrayGetLBound(data,1,&lowerBound);                    SafeArrayGetUBound(data,&upperBound);                    long cnt_elements = upperBound - lowerBound + 1;                    for (int i = 0; i < cnt_elements; i++)  // iterate through returned values                    {                        int val = pVals[i];                        printf("C++: %d\n",val);                    }                    SafeArrayUnaccessData(data);                }                else                {                    // Error                }            }        }        else        {            // Error        }        // End print content of SAFEARRAY        // Delete the SAFEARRAY if already present        SafeArrayDestroy(data);        data = NulL;    }    {        // Creation of a new SAFEARRAY        SAFEARRAYBOUND bounds;        bounds.lLbound = 0;        bounds.cElements = 10;        data = SafeArrayCreate(VT_I4,&bounds);        int *pVals;        HRESulT hr = SafeArrayAccessData(data,(voID**)&pVals); // direct access to SA memory        if (SUCCEEDED(hr))        {            for (ulONG i = 0; i < bounds.cElements; i++)            {                pVals[i] = i + 100;            }        }        else        {            // Error        }    }}

C#

[Dllimport("Nativelibrary.dll",CallingConvention = CallingConvention.Cdecl)]private static extern voID GetResult([MarshalAs(UnmanagedType.SafeArray,SafeArraySubType = VarEnum.VT_I4)] ref int[] ar);

var data = new int[] { 1,2,3,4,5 };GetResult(ref data);if (data != null){    for (int i = 0; i < data.Length; i++)    {        Console.Writeline("C#: {0}",data[i]);    }}else{    Console.Writeline("C#: data is null");}

代码部分取自https://stackoverflow.com/a/12484259/613130和https://stackoverflow.com/a/3735438/613130

SAFEARRAY(VT_RECORD)

这是可行的……很难……但可行.请不要这样做.你不能讨厌这个世界.我希望你不要!

C :

// For the _com_util#include <comdef.h>extern "C"{    __declspec(dllexport) voID GetResultSafeArray(SAFEARRAY *&psa)    {        // All the varIoUs hr results should be checked!        HRESulT hr;        // Begin sanity checks        if (psa == NulL)        {            // Error        }        VARTYPE pvt;        hr = ::SafeArrayGetvartype(psa,&pvt);        if (pvt != VT_RECORD)        {            // Error        }        UINT size;        size = ::SafeArrayGetElemsize(psa);        if (size != sizeof(ManagedUDT))        {            // Error        }        // From tests done,it seems SafeArrayGetRecordInfo does a AddRef        _com_ptr_t<_com_IIID<IRecordInfo,NulL> > prinfo;        // The_com_ptr_t<>::operator& is overloaded        hr = ::SafeArrayGetRecordInfo(psa,&prinfo);        // From tests done,it seems Getname returns a new instance of the        // BSTR        // It is ok to use _bstr_t.GetAddress() here,see its description        _bstr_t name1;        hr = prinfo->Getname(name1.GetAddress());        const _bstr_t name2 = _bstr_t(L"ManagedUDT");        if (name1 != name2)        {            // Error        }        // End sanity checks        long lowerBound,upperBound;  // get array bounds        hr = ::SafeArrayGetLBound(psa,&lowerBound);        hr = ::SafeArrayGetUBound(psa,&upperBound);        long cnt_elements = upperBound - lowerBound + 1;        // Begin print        ManagedUDT *pVals;        hr = ::SafeArrayAccessData(psa,(voID**)&pVals);        printf("C++:\n");        for (int i = 0; i < cnt_elements; ++i)        {            ManagedUDT *pVal = pVals + i;            // If you are using a recent VisualC++,you can            // #include <memory>,and then            //std::unique_ptr<char[]> pstr(_com_util::ConvertBSTRToString(pVal->m_str01));            // and you don't need the char *pstr line and the delete[]            // line            char *pstr = _com_util::ConvertBSTRToString(pVal->m_str01);            printf("%s,%d\n",pstr,pVal->m_int01);            delete[] pstr;        }        hr = ::SafeArrayUnaccessData(psa);        // End print        // Begin free        SAFEARRAYBOUND sab;        sab.lLbound = 0;        sab.cElements = 0;        // SafeArrayRedim will call IRecordInfo::RecordClear        hr = ::SafeArrayRedim(psa,&sab);        // End Free        // Begin create        int numElements = 10;        sab.cElements = numElements;        hr = ::SafeArrayRedim(psa,&sab);        hr = ::SafeArrayAccessData(psa,(voID**)&pVals);        for (int i = 0; i < numElements; i++)        {            ManagedUDT *pVal = pVals + i;            char pstr[100];            sprintf(pstr,"Element #%d",i);            pVal->m_str01 = _com_util::ConvertStringToBSTR(pstr);            pVal->m_int01 = 100 + i;        }        hr = ::SafeArrayUnaccessData(psa);        // End create    }    __declspec(dllexport) voID GetResultSafeArrayOut(SAFEARRAY *&psa,ITypeInfo *itypeinfo)    {        // All the varIoUs hr results should be checked!        HRESulT hr;        // Begin sanity checks        if (psa != NulL)        {            // Begin free            // SafeArrayDestroy will call IRecordInfo::RecordClear            // if necessary            hr = ::SafeArrayDestroy(psa);            // End Free        }        // Begin create        int numElements = 10;        SAFEARRAYBOUND sab;        sab.lLbound = 0;        sab.cElements = numElements;        // The_com_ptr_t<>::operator& is overloaded        _com_ptr_t<_com_IIID<IRecordInfo,NulL> > prinfo;        hr = ::GetRecordInfoFromTypeInfo(itypeinfo,&prinfo);        psa = ::SafeArrayCreateVectorEx(VT_RECORD,numElements,prinfo);        ManagedUDT *pVals;        hr = ::SafeArrayAccessData(psa,i);            pVal->m_str01 = _com_util::ConvertStringToBSTR(pstr);            pVal->m_int01 = 100 + i;        }        hr = ::SafeArrayUnaccessData(psa);        // End create    }}

C#:

[ComVisible(true)][GuID("BBFE1092-A90C-4b6d-B279-CBA28B9EDDFA")][StructLayout(LayoutKind.Sequential)]public struct ManagedUDT{    [MarshalAs(UnmanagedType.BStr)]    public string m_str01;    public Int32 m_int01;}[Dllimport("Nativelibrary.dll",CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Ansi)]static extern voID GetResultSafeArray([MarshalAs(UnmanagedType.SafeArray)] ref ManagedUDT[] array);[Dllimport("Nativelibrary.dll",CharSet = CharSet.Ansi)]static extern voID GetResultSafeArrayOut([MarshalAs(UnmanagedType.SafeArray)] out ManagedUDT[] array,IntPtr itypeinfo);[Dllimport("Nativelibrary.dll",CharSet = CharSet.Ansi,EntryPoint = "GetResultSafeArrayOut")]static extern voID GetResultSafeArrayRef([MarshalAs(UnmanagedType.SafeArray)] ref ManagedUDT[] array,IntPtr itypeinfo);

var arr = new[]{    new ManagedUDT { m_str01 = "Foo",m_int01 = 1},new ManagedUDT { m_str01 = "bar",m_int01 = 2},};{    Console.Writeline("C#:");    for (int i = 0; i < arr.Length; i++)    {        Console.Writeline("{0},{1}",arr[i].m_str01,arr[i].m_int01);    }}{    Console.Writeline();    var arr2 = (ManagedUDT[])arr.Clone();    GetResultSafeArray(ref arr2);    Console.Writeline();    Console.Writeline("C#:");    for (int i = 0; i < arr2.Length; i++)    {        Console.Writeline("{0},arr2[i].m_str01,arr2[i].m_int01);    }}{    Console.Writeline();    ManagedUDT[] arr2;    IntPtr itypeinfo = Marshal.GetITypeInfoForType(typeof(ManagedUDT));    GetResultSafeArrayOut(out arr2,itypeinfo);    Console.Writeline();    Console.Writeline("C#:");    for (int i = 0; i < arr2.Length; i++)    {        Console.Writeline("{0},arr2[i].m_int01);    }}{    Console.Writeline();    var arr2 = (ManagedUDT[])arr.Clone();    IntPtr itypeinfo = Marshal.GetITypeInfoForType(typeof(ManagedUDT));    GetResultSafeArrayRef(ref arr2,arr2[i].m_int01);    }}

GetResultSafeArray有一个很大的警告:你必须从C#传递至少一个空数组(比如新的ManagedUDT [0]).这是因为要在C中从空创建SAFEARRAY(ManagedUDT),您需要一个IRecordInfo对象.我不知道如何从C中检索它.如果你已经有了SAFEARRAY(ManagedUDT),那么显然它已经设置了IRecordInfo,所以没有问题.在给出的示例中,在C中首先进行一些健全性检查,然后打印传递的数组,然后将其清空,然后重新填充. GetResultSafeArrayOut / GetResultSafeArrayRef“作弊”:他们从C#接收一个ITypeInfo指针(很容易在C#中检索,使用Marshal.GetITypeInfoForType()),并且从Caht可以检索到IRecordInfo接口.

一些说明:

>我写了Ansi-charset-C.通常对我自己来说,我总是编写Unicode-ready C(或者直接使用Unicode-C,因为所有的windows NT都支持Unicode),但是我注意到我是一个例外…所以在代码的各个部分都有转换BSTR-> ANSI-> BSTR.>我正在检索所有函数调用的HRESulT.应该检查它们,并处理失败.> C/C++OM中最复杂的事情是知道何时释放某些东西……一般来说,总是免费/释放()一切! (无论是BSTR / IUnkNown派生接口,……)>除非有错误,否则不支持此代码.认为它是一个概念证明.出于好奇,我已经失去了不同的时间.你打破它,你修复它.

总结

以上是内存溢出为你收集整理的将SAFEARRAY从c返回到c#全部内容,希望文章能够帮你解决将SAFEARRAY从c返回到c#所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/1216792.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存