Question

Je suis en train de passer un tableau d'interfaces de C # à C ++ / CLI. Voici le code:

// *** 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() { } }
}

Comme écrit ici, les pistes de code et proprement compiles. Cependant, lors de l'exécution de la partie « zone XX », je reçois un System.Runtime.InteropServices.SEHException.

Le code XX est juste une seule ligne qui appelle une méthode générée automatiquement l'acceptation d'un pointeur SAFEARRAY. Voici la déclaration de cette méthode (à partir d'un fichier .tlh):

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

Je pense effectivement cette méthode convertit le dos SAFEARRAY à un tableau .NET - tout cela fait partie d'un projet de conversion ma société est en cours d'exécution au moment. Donc, il n'y a pas d'alternative à l'aide d'un SAFEARRAY.

Quoi qu'il en soit, il serait vraiment surpris si le code sans la partie XX est sans bug; Je suis tout à fait un novice en matière de C ++. Pouvez-vous me aider à apercevoir quelques des problèmes? Si quelqu'un peut suggérer une meilleure façon de tester la validité du SAFEARRAY qui serait également une aide.

(Soit dit en passant, c'est une variante plus complexe de la question méthode SafeArrayPutElement lance System.AccessViolationException, dans lequel je vient de passer un tableau de ints de C # à C ++ / CLI).

Était-ce utile?

La solution

Plusieurs problèmes. D'une part, vous ne stocke pas un VARIANT dans le tableau. Ceci est en fin de compte ne va nulle part, un SafeArray ne peut pas stocker des références à des objets gérés. Le garbage collector se déplace autour des objets, il ne peut pas voir les références détenues par le code non managé ne peut donc pas mettre à jour la référence.

Au mieux, vous pouvez créer un tableau de VT_UNKNOWN ou VT_DISPATCH. Mais vous ne pouvez pas obtenir le pointeur d'interface COM pour ces objets gérés, ils ne sont pas [ComVisible]. Lorsque vous correctif, vous utiliseriez pour obtenir le pointeur d'interface pour stocker dans le tableau Marshal.GetIDispatchForObject () ou Marshal.GetIUnknownForObject ().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top