работать с циклом в неуправляемой C ++ DLL из C # (обратные вызовы) - PullRequest
1 голос
/ 06 декабря 2011

Я написал неуправляемую DLL на c ++, которая работает хорошо (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

Ответы [ 2 ]

2 голосов
/ 06 декабря 2011

Конечно, обратный вызов может работать. Вам понадобится указатель на функцию в коде 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 () необходим для того, чтобы сборщик мусора не смог забрать объект делегата слишком рано.

0 голосов
/ 06 декабря 2011

Исходя из предоставленной вами информации, я думаю, вам придется переписать вашу 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*/ };

вы можете взаимодействовать с интерфейсом в событиях ProgressChanged и WorkerCompleted, не в DoWork (он запускается в отдельном потоке).

...