2016-05-13 20 views
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(); 
     } 
    } 
} 
+3

「不工作」 是不恰當的問題說明。 –

回答

2

問題經由調用解決轉印DLL呼叫在一個單獨的線程和GUI更新從該線程。

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); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      if (StopEvent != null) 
       StopEvent(this, e); 
     } 
    } 
} 

Presenter.cs:

using System; 
using System.Threading; 
using System.Windows.Forms; 

namespace CallBackFromCpp 
{ 
    public class Presenter 
    { 
     Form1 _view; 
     WorkerClass _wc; 

     public ApplicationContext Init() 
     { 
      _view = new Form1(); 
      _view.StartEvent += _view_StartEvent; 
      _view.StopEvent += _view_StopEvent; 

      return new ApplicationContext(_view); 
     } 

     void _view_StopEvent(object sender, EventArgs e) 
     { 
      if (_wc != null) 
       _wc.Stop = true; 
     } 

     delegate void ShowProgressDelegate(int progressPercentage, string message); 

     private void ShowProgress(int progressPercentage, string message) 
     { 
      _view.richTextBox1.Text += String.Format("Report {0:00}% with message '{1}'\n", progressPercentage, message); 
      _view.progressBar1.PerformStep(); 
     } 

     void _view_StartEvent(object sender, EventArgs e) 
     { 
      ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress); 
      _wc = new WorkerClass(_view, showProgress); 
      Thread t = new Thread(new ThreadStart(_wc.RunProcess)); 
      t.IsBackground = true; //make them a daemon - prevent thread callback issues 
      t.Start(); 
     } 
    } 
} 

WorkerClass.cs:

using System; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 

namespace CallBackFromCpp 
{ 
    public class WorkerClass 
    { 
     /// <summary> 
     /// Usually a form or a winform control that implements "Invoke/BeginInvode" 
     /// </summary> 
     ContainerControl _sender = null; 

     /// <summary> 
     /// The delegate method (callback) on the sender to call 
     /// </summary> 
     Delegate _senderDelegate = null; 

     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); 

     /// <summary> 
     /// Constructor called by calle using ThreadPool OR ThreadStart 
     /// </summary> 
     public WorkerClass(ContainerControl sender, Delegate senderDelegate) 
     { 
      _sender = sender; 
      _senderDelegate = senderDelegate; 
     } 

     /// <summary> 
     /// Method for ThreadStart delegate 
     /// </summary> 
     public void RunProcess() 
     { 
      Thread.CurrentThread.IsBackground = true; //make them a daemon 

      WorkProgressInteropNegotiator negotiator = new WorkProgressInteropNegotiator(); 
      negotiator.reportProgress = new ReportProgressCallback(ReportProgress); 
      negotiator.cancellationPending = new CancellationPendingCallback(() => { return Stop; }); 

      // 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(); 
     } 

     private void ReportProgress(int progressPercentage, string message) 
     { 
      _sender.BeginInvoke(_senderDelegate, new object[] { progressPercentage, message }); 
     } 

     volatile bool _stop = false; 
     public bool Stop 
     { 
      set 
      { 
       _stop = value; 
      } 
      get 
      { 
       return _stop; 
      } 
     } 
    } 
} 
相關問題