3
我嘗試使用How to use C# BackgroundWorker to report progress in native C++ code?中的代碼更改WinForms中的progressBar。 但是,如果我創建一個窗體,從C++ dll調用的函數不會啓動(CSharpReportProgressStatus())。沒有創建的形式,它工作正常。如何更改WinForms中的progressBar以報告本機C++代碼的進度?
CppLayer.h:
#define DLLAPI __declspec(dllexport)
extern "C"
{
typedef void (__stdcall *ReportProgressCallback)(int, char *);
typedef bool (__stdcall *CancellationPendingCallback)();
struct DLLAPI WorkProgressInteropNegotiator
{
ReportProgressCallback progressCallback;
CancellationPendingCallback cancellationPending;
bool cancel;
};
DLLAPI void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator);
}
CppLayer.cpp:
#include "CppLayer.h"
#include <iostream>
#include <windows.h> //Для sleep
typedef void (__stdcall * pfnCallback)(int progress, int* cancel);
extern "C"
{
DLLAPI 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]);
}
}
};
的Program.cs:
using System;
using System.Windows.Forms;
namespace CallBackFromCpp
{
static class Program
{
[STAThread]
public static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Presenter p = new Presenter();
Application.Run(p.Init());
}
}
}
Form1.cs中:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public partial class Form1 : Form
{
public event EventHandler StartEvent;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (StartEvent != null)
StartEvent(this, e);
}
}
}
個
Presenter.cs:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace CallBackFromCpp
{
public class Presenter
{
Form1 _view;
public ApplicationContext Init()
{
_view = new Form1();
_view.StartEvent += _view_StartEvent;
return new ApplicationContext(_view);
}
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 EventWaitHandle resetEvent = null;
void _view_StartEvent(object sender, EventArgs e)
{
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();
}
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);
GCHandle gch = GCHandle.Alloc(negotiator);
CppLongFunction(negotiator);
gch.Free();
e.Cancel = negotiator.cancel;
}
void CSharpReportProgressStatus(object sender, ProgressChangedEventArgs e)
{
string message = e.UserState as string;
_view.richTextBox1.Text += String.Format("Report {0:00}% with message '{1}'", e.ProgressPercentage, message);
_view.progressBar1.PerformStep();
BackgroundWorker bw = sender as BackgroundWorker;
if (e.ProgressPercentage > 50)
bw.CancelAsync();
}
void CSharpReportComplete(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
_view.richTextBox1.Text = "Long operation canceled!";
}
else if (e.Error != null)
{
_view.richTextBox1.Text = String.Format("Long operation error: {0}", e.Error.Message);
}
else
{
_view.richTextBox1.Text += "Long operation complete!";
}
resetEvent.Set();
}
}
}
「不工作」 是不恰當的問題說明。 –