简体   繁体   English

从C#COM dll返回时,C ++ SAFEARRAY包含无效数据

[英]C++ SAFEARRAY has invalid data when returned from c# COM dll

i try to get data ( in form of a class/struct array ) from ac# dll in c++. 我尝试从c ++中的ac#dll获取数据(以类/结构数组的形式)。 i tried to work with the safearray helper function but all data i recived is invalid.... 我试图使用safearray辅助函数,但我收到的所有数据均无效。...

while debugging everything works/looks perfect untill i reach the point to recive data that was generated in the dll ( only the SAFEARRAY* looks invalid ) , so maybe it is a problem with the communication between C++ application and the c# COM dll VS SAFEARRAY Debug/Auto Window VS DownloadList Debug/Auto Window 在调试时一切正常/看起来很完美,直到我到达dll中生成的接收数据为止(只有SAFEARRAY *看起来无效),所以C ++应用程序与c#COM dll VS SAFEARRAY Debug之间的通信可能有问题/自动窗口 VS DownloadList调试/自动窗口

here is a code example : C# 这是一个代码示例:C#

// data class
public class Download
{
    public string Target;
    public string Data;
    public int Port;
}

// function called from outside dll
public Download[] GetData()
{
    [...]
    return DownloadList.ToArray(); // List<Download>
}

C++ C ++

#import "[...]/MSSQL_Lib.tlb"
// pDB is a class instance which contain the GetData func
[...]
SAFEARRAY* Data = pDB->GetData();
if( Data != nullptr )
{
    // print varian type info from result
    SafeArrayLock( Data );

    VARIANT* ValueArray = (VARIANT*)Data->pvData;
    long Lower = 0, Upper = 0;
    SafeArrayGetLBound( Data, 1, &Lower );
    SafeArrayGetUBound( Data, 1, &Upper );

    for( long i = 0; i <= ( Upper - Lower ); ++i )
    {
        PrintVariant( &ValueArray[i] );
    }

    SafeArrayUnlock( Data );
    SafeArrayDestroy( Data );
}
[...]
// function end

void PrintVariant( VARIANT* pV )
{
    switch( pV->vt )
    {
        case VT_BSTR:
            wprintf( L" String : %s \n", pV->bstrVal );
            break;
        default:
            wprintf( L" Unrecognized Type : %d \n", pV->vt );
            break;
    }
}

i also tried to marshal the c# class : 我也试图封送C#类:

[StructLayout(LayoutKind.Sequential)]
public class Download
{
    [MarshalAs(UnmanagedType.BStr)]
    public string Target;
    [MarshalAs(UnmanagedType.BStr)]
    public string Data;
    public int Port;
}

but same result. 但结果相同。 with marshal i get this warning : "Type library exporter warning processing '[...].Download, [...]'. Warning: The reference type had sequential or explicit layout, and so was exported as a struct." 与marshal在一起时,我得到以下警告:“类型库导出程序警告处理'[...]。Download,[...]'。警告:引用类型具有顺序或显式布局,因此已导出为结构。” but i guess it should not result in completly invalid returned data 但我猜它不应该导致完全无效的返回数据

print results looks like : 打印结果如下:

 Unrecognized Type : 65432
 Unrecognized Type : 65048
 Unrecognized Type : 64664
 Unrecognized Type : 64280
 Unrecognized Type : 1
 Unrecognized Type : 0
 Unrecognized Type : 0
 Unrecognized Type : 43008
 Unrecognized Type : 21288
 Unrecognized Type : 1331

but they change every run a little bit. 但它们会稍微改变每次运行。

So i hope anyone could help me and find the detail i missed^^ thx for reading and feel free to ask for more details 因此,我希望有人能帮助我,找到我错过的细节^^ thx,以供阅读,并随时要求提供更多细节

Your array is not an array of VARIANT but an array of IUnknown* (a call to SafeArrayGetVartype would have told you that). 您的数组不是VARIANT的数组,而是IUnknown *的数组(对SafeArrayGetVartype的调用将告诉您)。 You'll have to change your code for something like this: 您必须为以下代码更改代码:

SAFEARRAY *psa = pDB->GetData();
if (psa)
{
    SafeArrayLock(psa);
    LONG lb;
    LONG ub;
    SafeArrayGetLBound(psa, 1, &lb);
    SafeArrayGetUBound(psa, 1, &ub);
    for (int i = lb; i <= ub; i++)
    {
        _DownloadPtr download(((IUnknown**)psa->pvData)[i]);
        wprintf(L"%s\n", (LPWSTR)download->GetTarget());
    }
    SafeArrayUnlock(psa);
}

Note it means your Download class must also be marked as [ComVisible(true)] , and the fields be transformed into public properties. 请注意,这意味着您的Download类也必须标记为[ComVisible(true)] ,并且这些字段将转换为公共属性。 Because you need an IUnknown interface in this example (to see methods such as GetTarget() automatically added to the generated C++ code), I also suggest you add a [ClassInterface(ClassInterfaceType.AutoDual)] attribute to it. 因为在此示例中您需要IUnknown接口(以查看诸如GetTarget()之类的方法自动添加到生成的C ++代码中),所以我还建议您向其添加[ClassInterface(ClassInterfaceType.AutoDual)]属性。

If you do want array of VARIANTs (why would you?), then you'll have to use object[] instead of typed objects.arrays. 如果确实要使用VARIANT数组(为什么?),则必须使用object[]而不是键入的objects.arrays。

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

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