Обратный вызов неуправляемого кода из управляемого C #

Немного урок истории здесь. Я работаю над устаревшим приложением C ++ / MFC и пытаюсь начать инкрементную модернизацию, добавляя компоненты, написанные на C # (WinForms и более поздние версии WPF).

Я застрял в использовании .Net / 1.1 и VS / 2003 по многим причинам, которые невозможно решить в ближайшем будущем.

В настоящее время в качестве доказательства концепции работает что-то вроде этого:

#pragma push_macro("new")
#undef new

WinFormA::Form1* myform;
myform = __gc new WinFormA::Form1();
myform->ShowDialog();

#pragma pop_macro("new")

Проблема, с которой я столкнулся, заключается в следующем: мне нужен неуправляемый код C ++ / MFC для передачи указателя обратного вызова в управляемый код WinForm C #, чтобы я мог фиксировать взаимодействия пользователя и обрабатывать их приложением.

Я просмотрел некоторые статьи, такие как эта статья MSDN, но она не работает в VS / 2003 (компилятору не нравится синтаксис делегата).

Есть ли другие варианты? Я не думаю, что могу использовать DLLImport, поскольку мне нужно взаимодействовать с конкретным экземпляром приложения, а не с плоским API.

Спасибо!


person Community    schedule 26.06.2009    source источник


Ответы (3)


Если другие ответы не сработают, вы всегда можете написать оболочку C, чтобы сгладить классы. Например, если класс C ++:

class TheClass {
  public:
    TheClass(int Param);
    ~TheClass();

    bool SomeFunction(int Param1,int Param2);
};

Напишу обертку:

extern "C" void *TheClass_Create(int Param) {
  return (void*) new TheClass(Param);
}

extern "C" void TheClass_Destroy(void *This) {
  delete (TheClass*) This;
}

extern "C" bool TheClass_SomeFunction(void *This,int Param1,int Param2) {
  return ((TheClass*) This)->SomeFunction(Param1,Param2);
}

Поскольку оболочка написана прямо на C, вы можете использовать P / Invoke на C # сколько душе угодно (void * This должен стать IntPtr для обеспечения совместимости при переходе на 64-разрядную версию). Иногда, если я действительно амбициозен, я на самом деле напишу оболочку C # для P / Invokes, чтобы «переклассифицировать» вещь.

person Marc Bernier    schedule 23.09.2009

Я уже забыл .NET 1. *, но:

Определите необходимые интерфейсы и зарегистрируйте свои .NET-компоненты как COM-объекты. Утилиты .NET обычно предоставляют достаточно хороший код маршалинга.

Если возможно, обращайтесь к ним как к COM-объектам из приложения C ++ вообще без какого-либо управляемого C ++. (Используйте указатели интерфейса вместо функций для обратных вызовов).

Если COM не подходит, используйте .NET Reflector, чтобы увидеть, что происходит внутри автоматически сгенерированных сборок взаимодействия - это может дать представление о том, как сделать то же самое вручную.

person ima    schedule 26.06.2009

Я никогда не пробовал сам, но проверяли ли вы структуру RuntimeMethodHandle, которая определенно существует в .net1?

SomeDelegate Handler = new SomeDelegate(SomeMethod);
IntPtr HandlerPtr = Handler.Method.MethodHandle.GetFunctionPointer();

И немного копипаста из описания MSDN .net2 Marshal :: GetDelegateForFunctionPointer Method:

В версиях 1.0 и 1.1 .NET Framework можно было передать делегат, представляющий управляемый метод, неуправляемому коду в качестве указателя на функцию, позволяя неуправляемому коду вызывать управляемый метод через указатель функции. Также неуправляемый код мог передать этот указатель функции обратно в управляемый код, и указатель был правильно преобразован в базовый управляемый метод.

person arbiter    schedule 26.06.2009