Frage

Ich habe eine Situation, wo ich eine native C ++ DLL mit C ++ / CLI für eine eventuelle Verwendung in C # gewickelt haben.

Es gibt ein paar Callback-Funktionen, die einige Probleme während der Laufzeit verursachen. Insbesondere erhalte ich die folgende Ausnahme:

  

Eine nicht behandelte Ausnahme des Typs   'System.Runtime.InteropServices.InvalidOleVariantTypeException'   trat in ToadWrapTest.dll

     

Weitere Informationen: angegebene OLE   Variante ist ungültig.

Auf dieser Zeile Code (C ++ / CLI):

public delegate int ManagedCallbackFunction (Object^ inst, const Object^ data);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

ManagedCallbackFunction^ m_callbackFn;

int intermidiaryCallback(void * pInstance, const void * pData)
    {   
        void* temp = (void*)pData;
        System::IntPtr ip1 = IntPtr(pInstance);
        System::IntPtr ip2 = IntPtr(temp);
        Object^ oInst = Marshal::GetObjectForNativeVariant(ip1);
        Object^ oData = Marshal::GetObjectForNativeVariant(ip2);
        //invoke the callback to c#
        //return m_callbackFn::Invoke(oInst, oData);
        return 0;
    };

Der Grund, warum ich diese „Vermittler Rückruf“ gemacht habe, war ein Versuch, die ungültige Variante Ausnahme zu umgehen geworfen zu werden, wenn ich versuchte, direkt den Delegaten aus C # zu dem nativen C ++ Code abzubilden. Als Behelfslösung versucht, erkläre ich einen Delegierten auf der # Seite C und dass funcptr an den C geben ++ / CLI-Wrapper. Ich gehe dann den Vermittler funcptr auf die native C ++ und Daisy-Chain nur die Anrufe zusammen.

Was ich weiß ist, dass es funktioniert alles in native C ++ Welt. Das Problem ist die Abbildung der void * auf die verwalteten Welt. Der folgende Code zeigt die native C ++ Version des Rückrufs:

int (*CallbackFunction) (void *inst, const void *data);

Wenn jemand hier helfen kann, würde ich es wirklich schätzen.

War es hilfreich?

Lösung

Sind pInstance und pData wirklich VARIANT? Wenn sie sind, würde ich Ihre Callback-Funktion erwartet stärker eingegeben werden:

int (*CallbackFunction)(VARIANT *inst, VARIANT *data);

Wenn das der Fall ist, in Ihrem Code sollten Sie in der Lage sein, auf die tatsächliche aussehen VARIANT es zur Hand zu überprüfen. Wenn Sie nicht wirklich VARIANTs bekommen (dh, Sie sind wirklich nur immer void * Zeiger), sollten Sie nicht versuchen, sie in C # Objekte zu drehen, da es keine inhärente Bedeutung für sie ist. Sie sollten als IntPtr durchlaufen lassen. Wenn Sie wissen, dass sie eine andere Art von inhärenter Bedeutung haben sollten, müssen Sie sie als geeigneter Typ Marschall.

Andere Tipps

Big Dank auf diesem dem Sockel! Ich veröffentliche die endgültige Lösung unten an alle anderen, die mit 3rd-Party-Spaß wie dieser zu tun hat! Bitte fühlen Sie sich frei zu kritisieren, da ich nicht den Code zu optimieren fertig bin. Dies kann immer noch sein, eine Lösung bis zum Kreisverkehr.

Als erstes werden die Callback-Funktionen wurden:

public delegate int ManagedCallbackFunction (IntPtr oInst, IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
ManagedCallbackFunction^ m_callbackFn;

Große Requisiten auf diesen. Es wird einfach nur nicht, wenn Sie versuchen, von Leere zu werfen * direkt ^ Objekt. Mit Hilfe der IntPtr und mein Vermittler Rückruf:

int intermidiaryCallback(void * pInstance, const void * pData)
{   
    void* temp = (void*)pData;
    return m_callbackFn->Invoke(IntPtr(pInstance), IntPtr(temp));
};

Wir haben endlich ein funktionierendes Modell auf der C # Seite bekommen mit einigen Massieren der Objekte:

public static int hReceiveTestMessage(IntPtr pInstance, IntPtr pData)
{
   // provide object context for static member function
   helloworld2 hw = (helloworld2)GCHandle.FromIntPtr(pInstance).Target;
   if (hw == null || pData == null)
   {
      Console.WriteLine("hReceiveTestMessage received NULL data or instance pointer\n");
      return 0;
   }

   // populate message with received data
   IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataPacketWrap(pData)));
   DataPacketWrap dpw = (DataPacketWrap)GCHandle.FromIntPtr(ip2).Target;
   uint retval = hw.m_testData.load_dataSets(ref dpw);
   // display message contents
   hw.displayTestData();

   return 1;
}

ich schon erwähnt, „massieren“ die Objekte, weil die Delegierten nicht spezifisch für diese Callback-Funktion ist, und ich weiß nicht, was Objekt pData bis zur Laufzeit sein wird (von den Delegierten POV). Wegen dieses Problems habe ich mit dem pData Objekt einige zusätzliche Arbeit zu tun. Ich hatte im Grunde den Konstruktor in meinem Wrapper, um eine Überlastung einen IntPtr zu akzeptieren. Code ist für die volle "Klarheit" zu finden:

DataPacketWrap (IntPtr dp)
{ 
DataPacket* pdp = (DataPacket*)(dp.ToPointer());
m_NativeDataPacket = pdp;
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top