簡體   English   中英

通過c#在非托管c ++ dll中使用循環進行操作(回調)

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

我已經編寫了一個運行良好的非托管c ++ dll(IPinvoke)))其中有一個資源消耗函數-存在一個循環,其中包含復雜的耗時邏輯。 計算此循環進度百分比並向該循環發送中斷的最佳方法是什么-使用回調或可能傳遞參數? 如果回調是最好的變體-有人可以提供示例嗎?

在dll中:

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

在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

當然,回調可以工作。 您將在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;
}

等效的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...
}

對回調使用__stdcall有助於簡化委托聲明。 必須使用GC.KeepAlive()來阻止垃圾回收器過早地收集委托對象。

根據您提供的信息,我認為您必須從頭開始重寫dll。

我將其設置為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*/ };

您可以在ProgressChangedWorkerCompleted事件中與UI進行交互,而不是在DoWork進行交互(它在單獨的線程中運行)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM