如何使用C#BackgroundWorker的报告在本地C ++代码的进展如何? [英] How to use C# BackgroundWorker to report progress in native C++ code?
问题描述
在我的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;
公共CancellationPendingCallback 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:
- Interop with Native Libraries (Mono)
- How to: Marshal Callbacks and Delegates Using C++ Interop
- How to: Marshal Function Pointers Using PInvoke
这篇关于如何使用C#BackgroundWorker的报告在本地C ++代码的进展如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!