如何使用C#BackgroundWorker的报告在本地C ++代码的进展如何? [英] How to use C# BackgroundWorker to report progress in native C++ code?

查看:157
本文介绍了如何使用C#BackgroundWorker的报告在本地C ++代码的进展如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Visual Studio解决方案我在C#实现的用户界面,并在本地C ++实现的一些代码



我使用的 BackgroundWorker的类以implemenent执行长操作的报告进度。



如何使用的BackgroundWorker 从我的本地C ++代码汇报进展?



在换句话说,我怎么可以重写C#代码下面本地C ++和C#调用获得的C ++代码?
。如果这是不可能低于直接重写代码,它可能是好的了解其它等同的解决方案。谢谢你。

  MyClass类
{
公共无效计算(对象发件人,DoWorkEventArgs E)
{
BackgroundWorker的工人=发件人为BackgroundWorker的;

的for(int i = 0; I< STEPCOUNT;我++)
{
如果(worker.CancellationPending)
{
e.Cancel =真正;
中断;
}

//代码,这里处理当前迭代

worker.ReportProgress(第(i + 1)* 100 / STEPCOUNT,
的进展报告信息);
}
}
}


解决方案

举例如下。
它在x86 C#和本机Visual C ++测试:



CppLayer.h:

  #IFDEF CPPLAYER_EXPORTS 
的#define CPPLAYER_API __declspec(dllexport)的
的#else
的#define CPPLAYER_API __declspec(dllimport的)
#ENDIF

的externC{
无效的typedef(__stdcall * ReportProgressCallback)(INT,CHAR *);
的typedef BOOL(__stdcall * CancellationPendingCallback)();

结构CPPLAYER_API WorkProgressInteropNegotiator
{
ReportProgressCallback progressCallback;
CancellationPendingCallback cancellationPending;
BOOL取消;
};

CPPLAYER_API无效__stdcall CppLongFunction(WorkProgressInteropNegotiator&安培;谈判);
}



CppLayer.cpp:

 的#includestdafx.h中
#包括CppLayer.h

&#包括LT; iostream的>

的externC
{
//这是导出的函数的例子。
CPPLAYER_API无效__stdcall CppLongFunction(WorkProgressInteropNegotiator&安培;谈判)
{
const int的STEP_COUNT = 12;

的char *消息[3] = {一,二,三};

的for(int i = 0; I< STEP_COUNT;我++)
{
睡眠(100);

如果(negotiator.cancellationPending()){
negotiator.cancel = TRUE;
中断;
}

的std ::法院LT&;< 计算<< I<<的std :: ENDL;
negotiator.progressCallback(第(i + 1)* 100 / STEP_COUNT,消息[则i%3]);
}
}

};



C#类互操作与C ++代码:

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;使用System.Runtime.InteropServices
;
使用System.ComponentModel;
使用的System.Threading;

命名空间CSharpLayer
{
类SandboxCppProgress
{
公众委托无效ReportProgressCallback(INT百分比,字符串消息);

公共委托布尔CancellationPendingCallback();

[StructLayout(LayoutKind.Sequential)]
公共类WorkProgressInteropNegotiator
{
公共ReportProgressCallback reportProgress;
公共Can​​cellationPendingCallback cancellationPending;

的#pragma警告禁止0649
// C#不看到这件被设置在本机代码,我们禁用警告,以避免它。
公共BOOL取消;
的#pragma警告恢复0649
}

函数[DllImport(CppLayer.dll)]
公共静态外部无效CppLongFunction([输入,输出] WorkProgressInteropNegotiator谈判代表) ;

静态无效CSharpLongFunctionWrapper(对象发件人,DoWorkEventArgs E)
{
BackgroundWorker的体重=发件人为BackgroundWorker的;

WorkProgressInteropNegotiator谈判代表=新WorkProgressInteropNegotiator();

negotiator.reportProgress =新ReportProgressCallback(bw.ReportProgress);
negotiator.cancellationPending =新CancellationPendingCallback(()=> bw.CancellationPending);

//漱口细节
//如何:元帅回调和委托使用C ++的Interop
// http://msdn.microsoft.com/en-美国/库/ 367eeye0%28V = VS.100%29.aspx
的GCHandle GCH = GCHandle.Alloc(谈判);

CppLongFunction(谈判);

gch.Free();

e.Cancel = negotiator.cancel;
}

静态的EventWaitHandle resetEvent = NULL;

静态无效CSharpReportProgressStatus(对象发件人,ProgressChangedEventArgs E)
{
字符串消息= e.UserState为字符串;
Console.WriteLine(报告{} 0:00与%的消息{1}',e.ProgressPercentage,消息);

BackgroundWorker的体重=发件人为BackgroundWorker的;
如果(e.ProgressPercentage→50)
bw.CancelAsync();
}

静态无效CSharpReportComplete(对象发件人,RunWorkerCompletedEventArgs E)
{
如果(e.Cancelled)
{
Console.WriteLine (长操作被取消!);
}
,否则如果(e.Error!= NULL)
{
Console.WriteLine(长操作错误:{0},e.Error.Message);
}
,否则
{
Console.WriteLine(长操作完成!);
}
resetEvent.Set();
}

公共静态无效的主要(字串[] args)
{
BackgroundWorker的体重=新的BackgroundWorker();
bw.WorkerReportsProgress = TRUE;
bw.WorkerSupportsCancellation = TRUE;
bw.ProgressChanged + = CSharpReportProgressStatus;
bw.DoWork + = CSharpLongFunctionWrapper;
bw.RunWorkerCompleted + = CSharpReportComplete;

resetEvent =新的AutoResetEvent(假);

bw.RunWorkerAsync();

resetEvent.WaitOne();
}
}
}



以下链接可能是有用的:




In my Visual Studio solution I have UI implemented in C# and some code implemented in native C++.

I use BackgroundWorker class to implemenent reporting progress of execution long operation.

How can I use BackgroundWorker to report progress from my native C++ code?

In other words, how can I rewrite the C# code below to native C++ and call obtained C++ code from C#? If it is not possible to rewrite the code below directly, it could be good to know about other equivalent solutions. Thanks.

class MyClass 
{
    public void Calculate(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        for (int i = 0; i < StepCount; i++)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                break;
            }

            // code which handles current iteration here

            worker.ReportProgress((i + 1) * 100 / StepCount, 
                "Report progress message");
        }
    }
}

解决方案

Example follows. It was tested on x86 C# and native Visual C++:

CppLayer.h:

    #ifdef CPPLAYER_EXPORTS
    #define CPPLAYER_API __declspec(dllexport)
    #else
    #define CPPLAYER_API __declspec(dllimport)
    #endif

    extern "C" {
        typedef void (__stdcall *ReportProgressCallback)(int, char *);
        typedef bool (__stdcall *CancellationPendingCallback)();

        struct CPPLAYER_API WorkProgressInteropNegotiator 
        {
            ReportProgressCallback progressCallback;
            CancellationPendingCallback cancellationPending;
            bool cancel;
        };

        CPPLAYER_API void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator);
    }

CppLayer.cpp:

#include "stdafx.h"
#include "CppLayer.h"

#include <iostream>

extern "C"
{
    // This is an example of an exported function.
    CPPLAYER_API void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator)
    {
        const int STEP_COUNT = 12;

        char * messages[3] = {"ONE", "TWO", "THREE"};

        for (int i = 0; i < STEP_COUNT; i++)
        {
            Sleep(100);

            if (negotiator.cancellationPending()) {
                negotiator.cancel = true; 
                break;
            }

            std::cout << "Calculate " << i << std::endl;
            negotiator.progressCallback((i + 1) * 100 / STEP_COUNT, messages[i % 3]);
        }
    }

};

C# class which interoperate with C++ code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace CSharpLayer
{
    class SandboxCppProgress
    {
        public delegate void ReportProgressCallback(int percentage, string message);

        public delegate bool CancellationPendingCallback();

        [StructLayout(LayoutKind.Sequential)]
        public class WorkProgressInteropNegotiator
        {
            public ReportProgressCallback reportProgress;
            public CancellationPendingCallback cancellationPending;

#pragma warning disable 0649
            // C# does not see this member is set up in native code, we disable warning to avoid it.
            public bool cancel;
#pragma warning restore 0649
        }

        [DllImport("CppLayer.dll")]
        public static extern void CppLongFunction([In, Out] WorkProgressInteropNegotiator negotiator);

        static void CSharpLongFunctionWrapper(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;

            WorkProgressInteropNegotiator negotiator = new WorkProgressInteropNegotiator();

            negotiator.reportProgress = new ReportProgressCallback(bw.ReportProgress);
            negotiator.cancellationPending = new CancellationPendingCallback(() => bw.CancellationPending);

            // Refer for details to
            // "How to: Marshal Callbacks and Delegates Using C++ Interop" 
            // http://msdn.microsoft.com/en-us/library/367eeye0%28v=vs.100%29.aspx
            GCHandle gch = GCHandle.Alloc(negotiator);

            CppLongFunction(negotiator);

            gch.Free();

            e.Cancel = negotiator.cancel;
        }

        static EventWaitHandle resetEvent = null;

        static void CSharpReportProgressStatus(object sender, ProgressChangedEventArgs e)
        {
            string message = e.UserState as string;
            Console.WriteLine("Report {0:00}% with message '{1}'", e.ProgressPercentage, message);

            BackgroundWorker bw = sender as BackgroundWorker;
            if (e.ProgressPercentage > 50)
                bw.CancelAsync();
        }

        static void CSharpReportComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                Console.WriteLine("Long operation canceled!");
            }
            else if (e.Error != null)
            {
                Console.WriteLine("Long operation error: {0}", e.Error.Message);
            }
            else
            {
                Console.WriteLine("Long operation complete!");
            }
            resetEvent.Set();
        }

        public static void Main(string[] args)
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.ProgressChanged += CSharpReportProgressStatus;
            bw.DoWork += CSharpLongFunctionWrapper;
            bw.RunWorkerCompleted += CSharpReportComplete;

            resetEvent = new AutoResetEvent(false);

            bw.RunWorkerAsync();

            resetEvent.WaitOne();
        }
    }
}

Following links might be useful:

这篇关于如何使用C#BackgroundWorker的报告在本地C ++代码的进展如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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