в следващия си проект искам да внедря GUI за вече съществуващ код в C++. Моят план е да обвия C++ частта в DLL и да внедря GUI в C#. Проблемът ми е, че не знам как да внедря обратно извикване от неуправляваната DLL в управлявания C# код. Вече направих някои разработки в C#, но взаимодействието между управляван и неуправляван код е ново за мен. Може ли някой да ми даде някои съвети или съвети за четене или прост пример, от който да започна? За съжаление не можах да намеря нищо полезно.
Как да внедря интерфейс за обратно извикване от неуправляван DLL към .net приложение?
Отговори (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. Достоен урок е достъпен тук.
P/Invoke може да обработва маршалинг на управляван делегат към указател на функция. Така че, ако изложите API, които регистрират функция за обратно извикване от вашата DLL и в C# предадете делегат на тази функция.
Има пример в MSDN за това с функцията EnumWindows. В тази статия внимавайте да обърнете внимание на реда в точка 4, който гласи:
Ако обаче функцията за обратно извикване може да бъде извикана след връщане на повикването, управляваният повикващ трябва да предприеме стъпки, за да гарантира, че делегатът остава несъбран, докато функцията за обратно извикване приключи. За подробна информация относно предотвратяването на събирането на отпадъци вижте Interop Marshaling с Platform Invoke.
Това, което казва, е, че трябва да се уверите, че вашият делегат не е събиран за боклук, докато след като управляваният код приключи с извикването му, като запазите препратка към него във вашия код или го закачите.
Вижте Marshal.GetFunctionPointerForDelegate, който ще ви даде функционален указател за извикване на управляван (т.е. C# код) от неуправляван код.