从C ++回调到C#的回调

说我有一个用于计算PI的C ++库函数:

// pi.h: #ifdef BUILDING_DLL #define DLL_MACRO __declspec(dllexport) #else #define DLL_MACRO __declspec(dllimport) #endif namespace Cpp { class PI { public: static double DLL_MACRO compute(); }; }; // pi.cpp: #include "pi.h" #include  double Cpp::PI::compute() { // Leibnitz summation formulae: double sum = 0.0; for(long n = 0; n < 100*1000*1000; n++) sum += 4.0*pow(-1.0, n)/(2*n + 1.0); return sum; } 

我需要从C#调用此函数,我想使用C ++ / CLI作为“桥”。 但是这个C ++函数有点慢。 因此,调用此函数的C#代码需要获取回调函数,告诉它函数的进度是多少%。 C#代码可能需要一些状态,例如进度条来处理此信息。 所以来自C ++的回调必须进入C#端的成员函数。

所以我介绍一下:

 // piCLI.h: The C++/CLI "bridge" between C# and C++ #include "pi.h" #pragma once namespace CLI { public ref class PI abstract { public: double compute() { return Cpp::PI::compute(); } virtual void progress(int percentCompleted) = 0; }; }; 

  namespace CSharp { public class PI : CLI.PI { public override void progress(int percentCompleted) { System.Console.WriteLine(percentCompleted + "% completed."); } } } 

现在调用CSharp.PI.compute()工作正常:-)。 它按预期将调用转发给Cpp :: PI :: compute()。

但是如何在Cpp :: PI :: compute()运行时让C ++库将进度更新转发到CSharp.PI.progress()?

提前感谢您的任何答案!

我也会采用函数指针/委托方法:

 // pi.h: #pragma once #ifndef DLL_MACRO #ifdef BUILDING_DLL #define DLL_MACRO __declspec(dllexport) #else #define DLL_MACRO __declspec(dllimport) #endif #endif namespace Cpp { typedef void (__stdcall *ComputeProgressCallback)(int); class PI { public: static double DLL_MACRO compute(ComputeProgressCallback callback); }; } // pi.cpp: #include "pi.h" #include  double Cpp::PI::compute(Cpp::ComputeProgressCallback callback) { double sum = 0.; for (long n = 0L; n != 100000000L; ++n) { sum += 4. * std::pow(-1., n) / (2L * n + 1.); callback(/*impl*/); } return sum; } 
 // piCLI.h: The C++/CLI "bridge" between C# and C++ #pragma once #include "pi.h" namespace CLI { public delegate void ComputeProgressDelegate(int percentCompleted); public ref class PI abstract sealed { public: static double compute(ComputeProgressDelegate^ callback) { using System::IntPtr; using System::Runtime::InteropServices::Marshal; IntPtr cbPtr = Marshal::GetFunctionPointerForDelegate(callback); return Cpp::PI::compute( static_cast(cbPtr.ToPointer()) ); } }; } 
 namespace CSharp { public static class PI { public static double compute() { CLI.PI.compute( percentCompleted => System.Console.WriteLine( percentCompleted.ToString() + "% completed." ) ); } } } 

或者,要覆盖抽象progress方法而不是在C#端创建委托:

 // piCLI.h: The C++/CLI "bridge" between C# and C++ #pragma once #include "pi.h" namespace CLI { public ref class PI abstract { delegate void ComputeProgressDelegate(int percentCompleted); public: double compute() { using System::IntPtr; using System::Runtime::InteropServices::Marshal; ComputeProgressDelegate^ callback = gcnew ComputeProgressDelegate( this, &PI::progress ); IntPtr cbPtr = Marshal::GetFunctionPointerForDelegate(callback); return Cpp::PI::compute( static_cast(cbPtr.ToPointer()) ); } protected: virtual void progress(int percentCompleted) abstract; }; } 
 namespace CSharp { public sealed class PI : CLI.PI { protected override void progress(int percentCompleted) { System.Console.WriteLine( percentCompleted.ToString() + "% completed." ); } } } 

将C ++ / cli定义的Native函数作为回调传递给您的本机C ++,并在回调时使用gcroot来调用您的托管C#函数。