通过接口数组从C#到C ++ / CLI(Passing an array of interface

2019-10-29 21:37发布

我试图通过接口从C#到C ++ / CLI的阵列。 下面是代码:

// *** SafeArrayTesting_PlusPlus.cpp  ***
#include "stdafx.h"  
#include <comdef.h>

using namespace System;    
using namespace System::Runtime::InteropServices;

namespace SafeArrayTesting_PlusPlus {

public ref class MyCppClass
{       
    public:
    MyCppClass();
    ~MyCppClass();
    void SetMyInterfaces(
        array<SafeArrayTesting_Sharp::MyInterface^>^ myInterfaces);
};

MyCppClass::MyCppClass(){}
MyCppClass::~MyCppClass(){}

void MyCppClass::SetMyInterfaces(array<SafeArrayTesting_Sharp::MyInterface^>^ 
     myInterfaces)
{
    // Create safearray
    SAFEARRAY  *safeArrayPointer;
    SAFEARRAYBOUND arrayDim[1];    // one dimensional array
    arrayDim[0].lLbound= 0;
    arrayDim[0].cElements= myInterfaces->Length;

    safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);

    // copy ints to safearray
    for (long lo= 0;lo<myInterfaces->Length;lo++)
    {           
        IntPtr myIntPtr = Marshal::GetIUnknkownForObject(myInterfaces[lo]);
        SafeArrayPutElement(
            safeArrayPointer, 
            &lo, 
            static_cast<void*>(myIntPtr)
            ); 
    }

    // do something with the safearray here - area XX
}}

// *** SafeArrayTesting_Main.cs ***
using SafeArrayTesting_PlusPlus;
using SafeArrayTesting_Sharp;

namespace SafeArrayTesting_Main
{

class SafeArrayTesting_Main
{
    static void Main()
    {
        var myCppClass = new MyCppClass();
        MyInterface myInterface = new MyClass();
        myCppClass.SetMyInterfaces(new[]{ myInterface });
    }
}}  

// *** SafeArrayTesting_Sharp.cs ***
using System;
using System.Runtime.InteropServices;

namespace SafeArrayTesting_Sharp
{
    [ComVisible(true)]
    public interface MyInterface
    {
        int MyInt { get; set; }
        string MyString { get; set; }
        DateTime MyDateTime { get; set; }
    }

    [ComVisible(true)]
    public class MyClass : MyInterface
    {
        public int MyInt{get;set;}
        public string MyString{get;set;}
        public DateTime MyDateTime{get; set;}
    }

// Just to please the compiler; bear with me. 
class DummyClass { static void Main() { } }
}

至于这里写的代码和运行完全编译。 然而,在运行“区域XX”的一部分的时候,我得到一个System.Runtime.InteropServices.SEHException

的XX代码仅仅是一个单一的线,其调用自动生成方法接受SAFEARRAY指针。 下面是这个方法的声明(从.tlh文件):

virtual HRESULT __stdcall put_SafeArray (
        /*[in]*/ SAFEARRAY * pRetVal ) = 0;

其实,我觉得这个方法可转换SAFEARRAY回.NET阵列 - 这是我的公司在运行了一个转换项目的一部分。 因此,有没有替代使用SAFEARRAY。

无论如何,这真的让我惊喜,如果没有XX部分的代码是无bug; 我很是新手,当涉及到C ++。 你能帮助我发现的一些问题? 如果任何人可以提出测试SAFEARRAY,这也将是一个帮助的有效性的更好的方法。

(顺便说一句,这是问题的更复杂的变化SafeArrayPutElement方法引发System.AccessViolationException ,其中我只是路过整数数组从C#到C ++ / CLI)。

Answer 1:

几个问题。 首先,你实际上并没有存储在阵列中的变体。 这最终是不会去任何地方,一个SAFEARRAY不能存储被管理对象的引用。 垃圾收集器移动物体周围,它无法看到非托管代码持有引用,因此它不能更新引用。

在最好的情况,你可以创建VT_UNKNOWN或VT_DISPATCH的数组。 但是,你不能获得这些管理对象的COM接口指针,它们不是[标记有ComVisible特性。 当你解决这个问题,你会使用Marshal.GetIDispatchForObject()或Marshal.GetIUnknownForObject()来获取接口指针数组中存储。



文章来源: Passing an array of interfaces from C# to C++/CLI