回调从C ++回到C# [英] Callbacks from C++ back to C#

查看:294
本文介绍了回调从C ++回到C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  // pi.h:
#ifdef BUILDING_DLL
#define DLL_MACRO __declspec(dllexport)
#else
#define DLL_MACRO __declspec(dllimport)
#endif

命名空间Cpp {
class PI {
public:
static double DLL_MACRO compute();
};
};

// pi.cpp:
#includepi.h
#include< cmath>

double
Cpp :: PI :: compute(){
// Leibnitz求和公式:
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:C#和C ++之间的C ++ / CLI桥
#includepi.h
#pragma once
namespace CLI {
public ref class PI abstract {
public:
double compute(){
return Cpp :: PI :: compute();
}
virtual void progress(int percentCompleted)= 0;
};
};

 命名空间CSharp 
{
public class PI:CLI.PI
{
public override void progress(int percentCompleted)
{
System。 Console.WriteLine(percentCompleted +%completed。);
}
}
}

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



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



先感谢任何答案!

 

code> // 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) );

class PI {
public:
static double DLL_MACRO compute(ComputeProgressCallback callback);
};
}

// pi.cpp:
#includepi.h
#include< cmath>

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:C#和C ++之间的C ++ / CLI桥
#pragma once
#includepi.h

命名空间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< Cpp :: ComputeProgressCallback>(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:C#和C ++之间的C ++ / CLI桥梁
#pragma once
#includepi.h

命名空间CLI {
public ref class PI abstract {
delegate void ComputeProgressDelegate(int percentCompleted);

public:
double compute(){
使用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< Cpp :: ComputeProgressCallback>(cbPtr.ToPointer())
);
}

protected:
virtual void progress(int percentCompleted)abstract;
};
}



 命名空间Csharp {
public sealed class PI:CLI.PI {
protected override void progress(int percentCompleted){
System.Console.WriteLine(
percentCompleted.ToString() %已完成。
);
}
}
}


say I have a C++ library function for computing PI:

// 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 <cmath>

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

I need to call this function from C#, and I want to use C++/CLI as a "bridge". However this C++ function is somewhat slow. Therefore the C# code calling this function need to get callbacks telling it how far the function has come in %. The C# code might need some state, e.g. a progress bar, to deal with this info. So the callbacks from C++ must enter into a member function on the C# side.

So I introduce:

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

and

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

Now invoking CSharp.PI.compute() works fine :-). It forwards the call to Cpp::PI::compute() as intended.

But how do I get the C++ library to forward progress updates to CSharp.PI.progress() whilst Cpp::PI::compute() is running?

Thanks in advance for any answers!

解决方案

I would take a function pointer/delegate approach as well:

// 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 <cmath>

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<Cpp::ComputeProgressCallback>(cbPtr.ToPointer())
            );
        }
    };
}

namespace CSharp {
    public static class PI {
        public static double compute() {
            CLI.PI.compute(
                percentCompleted => System.Console.WriteLine(
                    percentCompleted.ToString() + "% completed."
                )
            );
        }
    }
}

Or, to override an abstract progress method rather than creating a delegate on the C# side:

// 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<Cpp::ComputeProgressCallback>(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 ++回到C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆