简体   繁体   English

通过c#在非托管c ++ dll中使用循环进行操作(回调)

[英]operate with loop in unmanaged c++ dll from c#(callbacks)

I have written an unmanaged c++ dll that works good (IPinvoke))) There is one resource-consuming function in it - there is a loop with complex time consuming logic. 我已经编写了一个运行良好的非托管c ++ dll(IPinvoke)))其中有一个资源消耗函数-存在一个循环,其中包含复杂的耗时逻辑。 What is the best way to calculate percentage of this loop progress and sending break to this loop - using callbacks or may be passing parameters? 计算此循环进度百分比并向该循环发送中断的最佳方法是什么-使用回调或可能传递参数? If callbacks is the most good variant - could anyone provide sample? 如果回调是最好的变体-有人可以提供示例吗?

in dll: 在dll中:

extern "C" _declspec(dllexport) uint8* resourceConsumingFunction(uint8* dataBufer)
{
  //there is a loop with many math here
  return dataBuffer;
}

in c# 在C#中

[DllImport("MyLib.DLL", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern byte* resourceConsumingFunction(byte* dataBuf);
//.....
byte* bufbuf = resourceConsumingFunction(data);//there I need to break this function and to get //percentage

Sure, a callback can work. 当然,回调可以工作。 You'll need a function pointer in the C++ code, something like this: 您将在C ++代码中需要一个函数指针,如下所示:

typedef void (__stdcall * pfnCallback)(int progress, int* cancel);

extern "C" _declspec(dllexport) 
uint8* resourceConsumingFunction(uint8* dataBuffer, pfnCallback callback)
{
    for (int progress = 0;;) {
        int cancel = 0;
        callback(progress, &cancel);
        if (cancel) return null;
        // More code
        //...
    }
    return dataBuffer;
}

And the equivalent C# code would be: 等效的C#代码为:

private void delegate pfnCallback(int progress, out bool cancel);

private void makeCall() {
    var callback = new pfnCallback(showProgress);
    var bufptr = resourceConsumingFunction(somebuf, callback);
    GC.KeepAlive(callback);
    // etc...
}

private void showProgress(int progress, out bool cancel) {
   // etc...
}

Using __stdcall for the callback helps keep the delegate declaration simple. 对回调使用__stdcall有助于简化委托声明。 The GC.KeepAlive() call is necessary to stop the garbage collector from collecting the delegate object too soon. 必须使用GC.KeepAlive()来阻止垃圾回收器过早地收集委托对象。

Based on the info you provided, I think you'll have to rewrite your dll from scratch. 根据您提供的信息,我认为您必须从头开始重写dll。

I'd make it a BackgroundWorker, like this (pseudocode, look it up on MSDN): 我将其设置为BackgroundWorker,如下所示(伪代码,在MSDN上查找):

BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;

worker.DoWork += (s,e) => 
{
    loop(loopcondition)
    {
        ... math magic, in which you also calculate percentage ...
        worker.ReportProgress(percentage); // fire 'ProgressChanged' event handled below
    }
};

worker.ProgressChanged += (s,e) => { /*e.ProgressPercentage is the value you passed, here you handle it*/ };

//WARNING: i don't remember the exact event name right now, look it up!
worker.WorkerCompleted += (s,e) => { /*when job is done, you can do something here*/ };

you can interact with UI in the ProgressChanged and WorkerCompleted events, not in DoWork (it's being run in a separate thread). 您可以在ProgressChangedWorkerCompleted事件中与UI进行交互,而不是在DoWork进行交互(它在单独的线程中运行)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM