Как да внедря интерфейс за обратно извикване от неуправляван DLL към .net приложение?

в следващия си проект искам да внедря GUI за вече съществуващ код в C++. Моят план е да обвия C++ частта в DLL и да внедря GUI в C#. Проблемът ми е, че не знам как да внедря обратно извикване от неуправляваната DLL в управлявания C# код. Вече направих някои разработки в C#, но взаимодействието между управляван и неуправляван код е ново за мен. Може ли някой да ми даде някои съвети или съвети за четене или прост пример, от който да започна? За съжаление не можах да намеря нищо полезно.


person chrmue    schedule 30.01.2010    source източник


Отговори (4)


Не е необходимо да използвате Marshal.GetFunctionPointerForDelegate(), P/Invoke marshaller го прави автоматично. Ще трябва да декларирате делегат от страната на C#, чийто подпис е съвместим с декларацията на указател на функция от страната на C++. Например:

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

И съответният C++ код, използван за създаване на неуправлявана 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");
}

Това е достатъчно, за да започнете с него. Има милион детайли, които могат да ви създадат проблеми, непременно ще се натъкнете на някои от тях. Много по-продуктивният начин за стартиране на този вид код е писането на обвивка на езика C++/CLI. Това също ви позволява да обвиете C++ клас, нещо, което не можете да направите с P/Invoke. Достоен урок е достъпен тук.

person Hans Passant    schedule 30.01.2010
comment
Благодаря nobugz, ще го пробвам скоро. И се надявам, че няма да си навлека много проблеми ;-) - person chrmue; 30.01.2010

P/Invoke може да обработва маршалинг на управляван делегат към указател на функция. Така че, ако изложите API, които регистрират функция за обратно извикване от вашата DLL и в C# предадете делегат на тази функция.

Има пример в MSDN за това с функцията EnumWindows. В тази статия внимавайте да обърнете внимание на реда в точка 4, който гласи:

Ако обаче функцията за обратно извикване може да бъде извикана след връщане на повикването, управляваният повикващ трябва да предприеме стъпки, за да гарантира, че делегатът остава несъбран, докато функцията за обратно извикване приключи. За подробна информация относно предотвратяването на събирането на отпадъци вижте Interop Marshaling с Platform Invoke.

Това, което казва, е, че трябва да се уверите, че вашият делегат не е събиран за боклук, докато след като управляваният код приключи с извикването му, като запазите препратка към него във вашия код или го закачите.

person shf301    schedule 30.01.2010
comment
+1 за критично - използването само на P/Invoke гарантира само валидността на показалеца по време на повикването - ако го кеширате, трябва да го закачите (не мога да говоря за скриване на препратка, подозрителен съм, но това не не означава много :-) - person Mark Mullin; 09.01.2013

Вижте Marshal.GetFunctionPointerForDelegate, който ще ви даде функционален указател за извикване на управляван (т.е. C# код) от неуправляван код.

person Håvard S    schedule 30.01.2010

Разгледайте това, Marshal.GetDelegateForFunctionPointer?

person t0mm13b    schedule 30.01.2010