Howto implementare l’interfaccia di callback da unmanaged DLL .net app?

nel mio prossimo progetto che vorrei implementare una interfaccia grafica per l’utente già esistente di codice in C++.
Il mio piano è quello di avvolgere il C++ parte in una DLL e implementare la GUI in C#. Il mio problema è che non so come implementare una funzione di callback da DLL non gestita in manged di codice C#. Ho già fatto un po ‘ di sviluppo in C#, ma l’interfacciamento tra codice gestito e non gestito è nuovo per me. C’è qualcuno che può darmi un po ‘ di suggerimenti o consigli di lettura o un semplice esempio per iniziare? Purtroppo non sono riuscito a trovare nulla di utile.

InformationsquelleAutor chrmue | 2010-01-30



4 Replies
  1. 49

    Non è necessario utilizzare il Maresciallo.GetFunctionPointerForDelegate(), il P/Invoke segnalatore fa automaticamente. Avrete bisogno di dichiarare un delegato in C#, la cui firma è compatibile con la funzione di dichiarazione di puntatore in C++. Per esempio:

    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    
    class UnManagedInterop {
      private delegate int Callback(string text);
      private Callback mInstance;   //Ensure it doesn't get garbage collected
    
      public UnManagedInterop() {
        mInstance = new Callback(Handler);
        SetCallback(mInstance);
      }
      public void Test() {
        TestCallback();
      }
    
      private int Handler(string text) {
        //Do something...
        Console.WriteLine(text);
        return 42;
      }
      [DllImport("cpptemp1.dll")]
      private static extern void SetCallback(Callback fn);
      [DllImport("cpptemp1.dll")]
      private static extern void TestCallback();
    }

    E il corrispondente codice C++ utilizzato per creare la DLL non gestita:

    #include "stdafx.h"
    
    typedef int (__stdcall * Callback)(const char* text);
    
    Callback Handler = 0;
    
    extern "C" __declspec(dllexport)
    void __stdcall SetCallback(Callback handler) {
      Handler = handler;
    }
    
    extern "C" __declspec(dllexport)
    void __stdcall TestCallback() {
      int retval = Handler("hello world");
    }

    Che sufficiente per iniziare con esso. Ci sono un milione di dettagli che si può ottenere nei guai, si sono tenuti a eseguire in alcuni di loro. Molto più produttivo per ottenere questo tipo di codice è di scrivere un wrapper in C++/CLI lingua. Che, inoltre, consente di disporre di una classe C++, qualcosa che non si può fare con un P/Invoke. Un tutorial decente è disponibile qui.

    • Grazie nobugz, proverò al più presto. E spero di non esagerare troppo 😉
    • funziona perfettamente per me, grazie ancora!
  2. 6

    P/Invoke in grado di gestire il marshalling gestito delegato a un puntatore a funzione. Quindi, se si espone API, che registrano una funzione di richiamata dalla DLL in C# passare un delegato a tale funzione.

    C’è un esempio su MSDN di fare questo con il EnumWindows funzione. In questo articolo prestare attenzione a prestare attenzione alla linea, punto 4, che afferma:

    Se, tuttavia, la funzione di richiamata
    essere richiamato dopo la chiamata restituisce, il
    gestito chiamante deve prendere misure per
    assicurarsi che il delegato rimane
    non incassati fino alla richiamata
    funzione termina. Per informazioni dettagliate
    informazioni sulla prevenzione di immondizia
    collezione, vedere di Marshalling
    con Platform Invoke.

    Cosa che dice è che è necessario assicurarsi che il delegato non è spazzatura raccolti fino a dopo il codice gestito è fatto chiamare da mantenere un riferimento nel codice, o di appuntare.

    • +1 per il critico – utilizzo di P/Invoke solo solo garantisce la validità del puntatore durante la chiamata – se stai memorizzazione nella cache, è necessario pin (non si può parlare di riporre un riferimento, sono sospetti, ma che non significa molto 🙂

Lascia un commento