Передача массива интерфейсов из C # в C ++ / CLI - PullRequest
0 голосов
/ 12 августа 2010

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

(Кстати, это более сложный вариант вопроса Метод SafeArrayPutElement выбрасывает System.AccessViolationException , в котором я только что передавал массив целых чисел из C # в C ++ / CLI.)

1 Ответ

3 голосов
/ 12 августа 2010

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

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

...