2015-09-07 32 views
1

我們在Delphi應用程序中託管.NET 4.0和許多WinForms窗口。當.NET窗口的ShowDialog返回時,重置.NET和WinForms,SynchronizationContexts被重置

我們發現,無論何時我們從Delphi最終在.NET窗體上調用ShowDialog,窗體關閉時,SynchronizationContext.Current都會重置爲使用線程池的System.Threading.SynchronizationContext

是給我們一個辦法,迫使這發生,或欺騙的代碼將其重置回WindowsFormsSynchronizationContext相反,短期添加必要的代碼來調用ShowDialog的?

我們已經託管了.NET好幾年了,但最近纔開始做涉及異步代碼的工作,並且在我們打開的第二個窗口上失敗了。

您可以複製我們正在用這個簡單的程序看,只需創建一個新的WinForms項目,將此代碼粘貼到Program.cs中:

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

namespace WindowsFormsApplication4 
{ 
    static class Program 
    { 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Debug.WriteLine("P1: " + SynchronizationContext.Current); 

      using (var fm = new Form()) 
      { 
       fm.Load += (s, e) => Debug.WriteLine("P2: " + SynchronizationContext.Current); 
       fm.ShowDialog(); 
      } 

      Debug.WriteLine("P3: " + SynchronizationContext.Current); 
     } 
    } 
} 

輸出:

P1: 
P2: System.Windows.Forms.WindowsFormsSynchronizationContext 
P3: System.Threading.SynchronizationContext 

基本上:

  • 表單打開之前,SynchronizationContext.Currentnull
  • 在Form.Load事件,SynchronizationContext.CurrentWindowsFormsSynchronizationContext
  • 實例的形式關閉後,SynchronizationContext.Current已恢復爲System.Threading.SynchronizationContext

我們已經嘗試了各種招數來試圖愚弄這樣的代碼:

  • 構建隱藏的表單
  • 構建隱藏的表單,使這個在失主ShowDialog
  • 構建在this line: Applicationcs#3445和起一個可見的形式(與Show顯示,不ShowDialog

通過我們認爲我們已經確定了可能的原因引用來源看後:

messageLoopCount--; 

if (messageLoopCount == 0) { 
    // If last message loop shutting down, install the 
    // previous op [....] context in place before we started the first 
    // message loop. 
    WindowsFormsSynchronizationContext.Uninstall(false); 
} 

由於主要的消息循環是從Delphi完成的,.NET不知道這一點,因此第一個彈出窗口的窗口在關閉時最終會在.NET認爲世界即將結束時撕裂世界。

回答

2

在您的上下文中換行WindowsFormsSynchronizationContext。 贊:

class MySynchronizationContext : SynchronizationContext 
{ 
    private SynchronizationContext context = new WindowsFormsSynchronizationContext(); 

    public override SynchronizationContext CreateCopy() 
    { 
     return context.CreateCopy(); 
    } 

    public override bool Equals(object obj) 
    { 
     return context.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     return context.GetHashCode(); 
    } 

    public override void OperationCompleted() 
    { 
     context.OperationCompleted(); 
    } 

    public override void OperationStarted() 
    { 
     context.OperationStarted(); 
    } 

    public override void Post(SendOrPostCallback d, object state) 
    { 
     context.Post(d, state); 
    } 

    public override void Send(SendOrPostCallback d, object state) 
    { 
     context.Send(d, state); 
    } 

    public override string ToString() 
    { 
     return "Wrapped"; 
    } 

    public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) 
    { 
     return context.Wait(waitHandles, waitAll, millisecondsTimeout); 
    } 
} 

並在任何窗體窗口調用之前設置它。在這種情況下,它不會被替換:

 /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 

     MySynchronizationContext context = new MySynchronizationContext(); 
     SynchronizationContext.SetSynchronizationContext(context); 
     Debug.WriteLine("P1: " + SynchronizationContext.Current); 

     using (var fm = new Form()) 
     { 
      fm.Load += (s, e) => Debug.WriteLine("P2: " + SynchronizationContext.Current); 
      fm.ShowDialog(); 
     } 

     Debug.WriteLine("P3: " + SynchronizationContext.Current); 
    } 

希望它會有所幫助。

+0

工作奇蹟,謝謝! –

相關問題