Как реализовать интерфейс обратного вызова из неуправляемой DLL в приложение .net? - PullRequest
23 голосов
/ 30 января 2010

в моем следующем проекте я хочу реализовать графический интерфейс для уже существующего кода на C ++. Мой план состоит в том, чтобы обернуть часть C ++ в DLL и реализовать GUI в C #. Моя проблема в том, что я не знаю, как реализовать обратный вызов из неуправляемой библиотеки DLL в управляемый код C #. Я уже сделал некоторые разработки в C #, но взаимодействие между управляемым и неуправляемым кодом является новым для меня. Кто-нибудь может дать мне несколько советов или советы по чтению или простой пример для начала? К сожалению, я не смог найти ничего полезного.

Ответы [ 4 ]

49 голосов
/ 30 января 2010

Вам не нужно использовать Marshal.GetFunctionPointerForDelegate (), маршаллер P / Invoke делает это автоматически. Вам нужно будет объявить делегата на стороне 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. Приличный учебник доступен здесь.

6 голосов
/ 30 января 2010

P / Invoke может обрабатывать маршалинг управляемого делегата в указатель на функцию. Поэтому, если вы предоставляете API, которые регистрируют функцию обратного вызова из вашей DLL, и в C # передаете делегат этой функции.

На MSDN есть пример выполнения этой функции с помощью функции EnumWindows. В этой статье следует обратить внимание на строку в пункте 4, которая гласит:

Если, однако, функция обратного вызова может вызываться после возврата вызова, управляемый абонент должен убедитесь, что делегат остается не собраны до обратного вызова Функция заканчивается. Для подробного информация о предотвращении мусора Коллекция, см. Interop Marshaling с вызовом платформы.

Это означает, что вам нужно убедиться, что ваш делегат не является сборщиком мусора до тех пор, пока управляемый код не завершит его вызов, либо сохранив ссылку на него в своем коде, либо закрепив его.

1 голос
/ 30 января 2010

См. Marshal.GetFunctionPointerForDelegate , который даст вам указатель функции для вызова управляемого (то есть кода C #) из неуправляемого кода.

0 голосов
/ 30 января 2010

Посмотрите на это, Marshal.GetDelegateForFunctionPointer ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...