web-dev-qa-db-de.com

So implementieren Sie die Rückrufschnittstelle von nicht verwaltet DLL zur .net App?

in meinem nächsten Projekt möchte ich eine GUI für bereits vorhandenen Code in C++ implementieren. Mein Plan ist es, den C++ - Teil in ein DLL zu packen und die GUI in C # zu implementieren. Mein Problem ist, dass ich nicht weiß, wie ich einen Rückruf vom nicht verwalteten DLL in den geänderten C # -Code implementieren soll. Ich habe bereits einige Entwicklungen in C # durchgeführt, aber die Schnittstelle zwischen verwaltetem und nicht verwaltetem Code ist für mich neu. Kann mir jemand Tipps oder Lesetipps oder ein einfaches Beispiel geben, um damit anzufangen? Leider konnte ich nichts hilfreiches finden.

23
chrmue

Sie müssen Marshal.GetFunctionPointerForDelegate () nicht verwenden, der P/Invoke-Marshaller führt dies automatisch aus. Sie müssen einen Delegaten auf der C # -Seite deklarieren, dessen Signatur mit der Funktionszeigerdeklaration auf der C++ - Seite kompatibel ist. Zum Beispiel:

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();
}

Und der entsprechende C++ - Code zum Erstellen der nicht verwalteten DLL:

#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");
}

Das ist genug, damit Sie damit anfangen können. Es gibt eine Million Details, die Sie in Schwierigkeiten bringen können, und Sie werden bestimmt auf einige davon stoßen. Der wesentlich produktivere Weg, diese Art von Code in Gang zu bringen, ist das Schreiben eines Wrappers in der C++/CLI-Sprache. Damit können Sie auch eine C++ - Klasse umschließen, was Sie mit P/Invoke nicht machen können. Ein anständiges Tutorial ist verfügbar hier.

49
Hans Passant

P/Invoke kann das Marshalling eines verwalteten Delegaten zu einem Funktionszeiger verarbeiten. Wenn Sie also APIs bereitstellen, die eine Rückruffunktion von DLL registrieren, und in C # einen Delegaten an diese Funktion übergeben.

Es gibt ein Beispiel auf MSDN , das dies mit der EnumWindows-Funktion macht. Achten Sie in diesem Artikel auf die Zeile in Nummer 4, in der es heißt:

Wenn jedoch die Rückruffunktion Aufgerufen werden kann, nachdem der Anruf zurückgegeben wurde, muss der Verwaltete Anrufer Schritte bis Unternehmen, um sicherzustellen, dass der Delegat Bis zum Callback Funktion wird beendet. Ausführliche Informationen zum Verhindern der Sammlung von Müll Finden Sie unter Interop-Marshalling Mit Platform Invoke.

Das bedeutet, dass Sie sicherstellen müssen, dass Ihr Delegat keine Abfälle gesammelt hat, bis der verwaltete Code aufgerufen wurde, indem Sie ihn entweder aufrufen, indem Sie ihn in seinem Code referenzieren oder ihn anheften.

5
shf301

Siehe Marshal.GetFunctionPointerForDelegate , mit dem Sie einen Funktionszeiger zum Aufrufen von managed (d. H. C # -Code) aus nicht verwaltetem Code erhalten.

1
Håvard S

Schauen Sie sich das an, Marshal.GetDelegateForFunctionPointer ?

0
t0mm13b