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

发布于 2024-07-25 17:25:35 字数 700 浏览 8 评论 0原文

这里有一点历史课。 我正在开发一个遗留的 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 代码将回调指针传递到托管 C# WinForm 代码中,以便我可以捕获用户交互并拥有它们由应用程序处理。

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

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

谢谢!

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).

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

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.

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).

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.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

或十年 2024-08-01 17:25:35

如果其他答案不起作用,您始终可以编写一个 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 语言,所以您可以随心所欲地在 C# 中 P/Invoke(void *This 应该变成 IntPtr以确保迁移到 64 位时的兼容性)。 有时,如果我真的雄心勃勃,我实际上会在 P/Invoke 周围编写一个 C# 包装器来“重新分类”事物。

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:

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.

遮了一弯 2024-08-01 17:25:35

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

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

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

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

I already forgot .NET 1.*, but:

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

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

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.

薆情海 2024-08-01 17:25:35

我从来没有亲自尝试过,但是你检查过.net1中肯定存在的RuntimeMethodHandle结构吗?

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

以及一些从 MSDN 的描述中复制粘贴的 .net2 Marshal::GetDelegateForFunctionPointer 方法:

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

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

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文