从托管C#回调非托管代码

时间:2022-06-28 07:33:17

Bit of a history lesson here. I'm working on a legacy C++/MFC application and am trying to start a incremental modernization by pushing components written in C# (WinForms and later WPF).

这里有一段历史课。我正在研究传统的C ++ / MFC应用程序,并试图通过推送用C#(WinForms和更高版本的WPF)编写的组件来开始增量现代化。

I'm stucking using .Net/1.1 and VS/2003 for many reasons which are impossible to resolve in the near future.

我坚持使用.Net / 1.1和VS / 2003有很多原因,这些原因在不久的将来是无法解决的。

Currently, as a proof of concept, something like this works:

目前,作为概念证明,这样的工作:

#pragma push_macro("new")
#undef new

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

#pragma pop_macro("new")

The problem I'm having is this - I need the unmanaged C++/MFC code to pass a callback pointer into the managed C# WinForm code so that I can capture user interactions and have them processed by the application.

我遇到的问题是 - 我需要非托管的C ++ / MFC代码将回调指针传递给托管的C#WinForm代码,以便我可以捕获用户交互并让应用程序处理它们。

I've looked at some articles such as this MSDN article but it doesn't work in VS/2003 (the compiler doesn't like the delegate syntax).

我看过一些文章,比如这篇MSDN文章,但它在VS / 2003中不起作用(编译器不喜欢委托语法)。

Are there any other options? I don't think I can use DLLImport since I need to interact with the specific application instance not a flat API.

还有其他选择吗?我不认为我可以使用DLLImport,因为我需要与特定的应用程序实例进行交互而不是平面API。

Thanks!

3 个解决方案

#1


If the other answers don't work out, you could always write a C wrapper to flatten the classes. For example, if the C++ class is:

如果其他答案无法解决,您可以随时编写一个C包装器来展平类。例如,如果C ++类是:

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

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

I'll write a wrapper:

我会写一个包装器:

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

Because the wrapper is straight C, you can P/Invoke in C# to your heart's content (the void *This should become an IntPtr to ensure compatibility if you move to 64-bit). Sometimes, if I'm really ambitious, I'll actually write a C# wrapper around the P/Invokes to 're-classify' the thing.

因为包装器是直的C,所以你可以在C#中调用你的心脏内容(void *这应该成为一个IntPtr以确保兼容性,如果你移动到64位)。有时,如果我真的雄心勃勃,我实际上会在P / Invokes周围编写一个C#包装器来“重新分类”这个东西。

#2


I already forgot .NET 1.*, but:

我已经忘记了.NET 1. *,但是:

Define necessary interfaces and register your .NET components as COM objects. .NET utilities will usually provide reasonably good marshaling code.

定义必要的接口并将.NET组件注册为COM对象。 .NET实用程序通常会提供相当好的编组代码。

If possible, access them as COM objects from C++ application without any Managed C++ at all. (Use interface pointers instead of functions for callbacks).

如果可能,从C ++应用程序访问它们作为COM对象,根本不需要任何托管C ++。 (使用接口指针而不是回调函数)。

If COM is not an option, use .NET Reflector to see what's going on inside auto-generated interop assemblies - this might give an insight on how to do the same thing manually.

如果COM不是一个选项,请使用.NET Reflector查看自动生成的互操作程序集内部发生了什么 - 这可能会让您深入了解如何手动执行相同的操作。

#3


I have never tried it by myself, but did you check RuntimeMethodHandle struct which is definitely exists in .net1?

我自己从未尝试过,但是你检查了.net1中肯定存在的RuntimeMethodHandle结构吗?

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

And some copy-paste from MSDN's description .net2 Marshal::GetDelegateForFunctionPointer Method:

还有一些来自MSDN描述的复制粘贴.net2 Marshal :: GetDelegateForFunctionPointer方法:

In versions 1.0 and 1.1 of the .NET Framework, it was possible to pass a delegate representing a managed method to unmanaged code as a function pointer, allowing the unmanaged code to call the managed method through the function pointer. It was also possible for the unmanaged code to pass that function pointer back to the managed code, and the pointer was resolved properly to the underlying managed method.

在.NET Framework的1.0和1.1版本中,可以将表示托管方法的委托作为函数指针传递给非托管代码,允许非托管代码通过函数指针调用托管方法。非托管代码也可以将该函数指针传递回托管代码,并且指针已正确解析为基础托管方法。

#1


If the other answers don't work out, you could always write a C wrapper to flatten the classes. For example, if the C++ class is:

如果其他答案无法解决,您可以随时编写一个C包装器来展平类。例如,如果C ++类是:

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

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

I'll write a wrapper:

我会写一个包装器:

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

Because the wrapper is straight C, you can P/Invoke in C# to your heart's content (the void *This should become an IntPtr to ensure compatibility if you move to 64-bit). Sometimes, if I'm really ambitious, I'll actually write a C# wrapper around the P/Invokes to 're-classify' the thing.

因为包装器是直的C,所以你可以在C#中调用你的心脏内容(void *这应该成为一个IntPtr以确保兼容性,如果你移动到64位)。有时,如果我真的雄心勃勃,我实际上会在P / Invokes周围编写一个C#包装器来“重新分类”这个东西。

#2


I already forgot .NET 1.*, but:

我已经忘记了.NET 1. *,但是:

Define necessary interfaces and register your .NET components as COM objects. .NET utilities will usually provide reasonably good marshaling code.

定义必要的接口并将.NET组件注册为COM对象。 .NET实用程序通常会提供相当好的编组代码。

If possible, access them as COM objects from C++ application without any Managed C++ at all. (Use interface pointers instead of functions for callbacks).

如果可能,从C ++应用程序访问它们作为COM对象,根本不需要任何托管C ++。 (使用接口指针而不是回调函数)。

If COM is not an option, use .NET Reflector to see what's going on inside auto-generated interop assemblies - this might give an insight on how to do the same thing manually.

如果COM不是一个选项,请使用.NET Reflector查看自动生成的互操作程序集内部发生了什么 - 这可能会让您深入了解如何手动执行相同的操作。

#3


I have never tried it by myself, but did you check RuntimeMethodHandle struct which is definitely exists in .net1?

我自己从未尝试过,但是你检查了.net1中肯定存在的RuntimeMethodHandle结构吗?

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

And some copy-paste from MSDN's description .net2 Marshal::GetDelegateForFunctionPointer Method:

还有一些来自MSDN描述的复制粘贴.net2 Marshal :: GetDelegateForFunctionPointer方法:

In versions 1.0 and 1.1 of the .NET Framework, it was possible to pass a delegate representing a managed method to unmanaged code as a function pointer, allowing the unmanaged code to call the managed method through the function pointer. It was also possible for the unmanaged code to pass that function pointer back to the managed code, and the pointer was resolved properly to the underlying managed method.

在.NET Framework的1.0和1.1版本中,可以将表示托管方法的委托作为函数指针传递给非托管代码,允许非托管代码通过函数指针调用托管方法。非托管代码也可以将该函数指针传递回托管代码,并且指针已正确解析为基础托管方法。