C++ cli 将接口数组从C#传递到C++/CLI

C++ cli 将接口数组从C#传递到C++/CLI,c++-cli,safearray,C++ Cli,Safearray,我试图将一系列接口从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 c

我试图将一系列接口从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() { } }
}
实际上,我认为这种方法将SAFEARRAY转换回.NET数组——这是我公司当时正在运行的转换项目的一部分。因此,除了使用SAFEARRAY之外,别无选择

无论如何,如果没有XX部分的代码没有bug,我会感到非常惊讶;在C++方面,我是个新手。你能帮我找出一些问题吗?如果有人能提出一种更好的方法来测试SAFEARRAY的有效性,那也会有所帮助


(顺便说一句,这是问题的一个更复杂的变体,我只是将一个int数组从C#传递到C++/CLI。)

几个问题。首先,实际上并没有在数组中存储变量。这最终是行不通的,SafeArray无法存储对托管对象的引用。垃圾回收器移动对象时,无法看到非托管代码持有的引用,因此无法更新引用


充其量,您可以创建一个VT_UNKNOWN或VT_DISPATCH的数组。但是您无法获取这些托管对象的COM接口指针,因为它们不是[ComVisible]。修复此问题时,您将使用Marshal.GetIDispatchForObject()或Marshal.getIUnknownProbject()获取存储在数组中的接口指针。

有几个问题。首先,实际上并没有在数组中存储变量。这最终是行不通的,SafeArray无法存储对托管对象的引用。垃圾回收器移动对象时,无法看到非托管代码持有的引用,因此无法更新引用


充其量,您可以创建一个VT_UNKNOWN或VT_DISPATCH的数组。但是您无法获取这些托管对象的COM接口指针,因为它们不是[ComVisible]。修复此问题时,您将使用Marshal.GetIDispatchForObject()或Marshal.GetIUnknownForObject()获取存储在数组中的接口指针。

为什么需要接口的安全数组?XX代码对该数组做了什么?谢谢您的提问,Saxon Druce。我已经编辑了这个问题,现在它可以更精确地描述这个问题。您是否可以使用put_SafeArray()方法访问对象的源代码?我认为这将取决于代码所期望的SAFEARRAY类型。不幸的是,我认为我无法访问源代码put\u SAFEARRAY()方法。键入:。。。put_SafeArray()方法的源代码。为什么您需要一个接口的SafeArray?XX代码对该数组做了什么?谢谢您的提问,Saxon Druce。我已经编辑了这个问题,现在它可以更精确地描述这个问题。您是否可以使用put_SafeArray()方法访问对象的源代码?我认为这将取决于代码所期望的SAFEARRAY类型。不幸的是,我认为我无法访问源代码put\u SAFEARRAY()方法。键入:。。。put_SafeArray()方法的源代码。谢谢!我已经尝试实现您的建议(并且我已经更新了问题中显示的代码)。但是,当我调用put_SafeArray()方法时,它仍然失败。有没有更简单的方法来确定SAFEARRAY是否已被正确初始化并复制到?我不知道“它仍然失败”是什么意思。调用put\u SAFEARRAY()方法仍然会引发SEHException。谢谢!我已经尝试实现您的建议(并且我已经更新了问题中显示的代码)。但是,当我调用put_SafeArray()方法时,它仍然失败。有没有更简单的方法来确定SAFEARRAY是否已被初始化并正确复制到?我不知道“它仍然失败”是什么意思。调用put\u SAFEARRAY()方法仍然会引发SEHException。
virtual HRESULT __stdcall put_SafeArray (
        /*[in]*/ SAFEARRAY * pRetVal ) = 0;