Передача массив интерфейсов от C # на C ++ / CLI

StackOverflow https://stackoverflow.com/questions/3464901

  •  27-09-2019
  •  | 
  •  

Вопрос

Я пытаюсь пройти массив интерфейсов от 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 CART без ошибок; Я довольно новичок, когда дело доходит до C ++. Можете ли вы помочь мне определить некоторые проблемы? Если кто-то может предложить лучший способ проверить действительность SafearRay, который также будет помощь.

(Кстати, это более сложное вариация вопроса Метод SafearRayPertelement бросает систему .accessviolationException , в котором я просто проходил массив INTS от C # к C ++ / CLI.)

Это было полезно?

Решение

Несколько проблем. Для одного на самом деле вы на самом деле не храните вариант в массиве. Это в конечном итоге не денется никуда не денется, SafearRay не может хранить ссылки на управляемые объекты. Сборщик мусора перемещает объекты вокруг, он не может видеть ссылки, удерживаемые неуправляемым кодом, поэтому он не может обновить ссылку.

В лучшем случае вы можете создать массив vt_unknown или vt_dispatch. Но вы не можете получить указатель интерфейса COM для этих управляемых объектов, они не являются [невидимыми]. Когда вы исправите это, вы бы использовали Marshal.getidispatchForObject () или Marshal.getiunknownForObject (), чтобы получить указатель интерфейса для хранения в массиве.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top