2016-11-09 7 views
0

.NETに移行するVB6アプリケーションがあります。 WPFウィンドウを開くVB6から.NET関数を呼び出しています。これらのウィンドウはメインスレッド上で実行する必要があるため、別のVB6フォームと同じように動作します。 DispatcherとSynchronizationContextが必要なので、これらの新しいウィンドウから非同期操作を実行する必要もあります。最初にWPFウィンドウを呼び出すサービスを作成するときに、新しいDispatcherとDispatcherSynchronizationContextを作成するだけです。Forms Interop ToolkitなしでVB6から呼び出されたWPF Windowsを実行できますか?

私はWPFウィンドウを開き、その境界を描画しませんでした。 私は上記のアプローチに気づいていないスレッドの問題の可能性はありますか?これはこれについて正しいことと思われますか?一般的な.netアプリケーションとは異なり、私たちがディスパッチャーを自分で管理しているので、このアプローチに競合状態や隠された問題があるのは怖いです。

私はInterop Forms Toolkitがあることを知っていますが、フォームと直接やりとりするためのvb6コードは必要ありません。我々はちょうど私のアプローチが後でなくすぐに間違っているかどうかを知ることは素晴らしいと思いますので、これらのウィンドウとこのインタフェースを書き始めています。

答えて

0

.tlbと.idlファイルを公開するWPFウィンドウ用のCOMインターフェイス(ActiveXユーザーコントロール)を用意する必要があります。

私は通常、このインターフェイスのみを扱い、WPFプロジェクトを参照する別のプロジェクトを作成します。 VB6プログラムでインスタンス化できるクラスをいくつか追加するか、必要に応じてすべてのGUIDとインターフェイスの説明を指定します。このプロジェクトでは

、いずれかのプロパティを構築するプロジェクトにオプション「COM相互運用のために登録する」を使用、または(私の好み)が.TLBとの.idlを作成するには、プロジェクトのビルド・イベント・スクリプトでます。regasmを使用しています。

WPF DLL、.tlb、および.idlを展開します。 次に、このタイプライブラリをVB6プロジェクトから参照し、必要に応じてオブジェクトを作成して使用します。

私は、VB6がCOMでSTAである傾向があるため、WPFとCOMインターフェイスコード内のすべての同期を管理することをお勧めします。このことができます:)

+0

これはまさに私たちが今行っていることです。 VB6コードと同じスレッドで実行されているこのディスパッチャで発生する可能性のある、奇妙なスレッドの問題や競合がないことを確認したかっただけです。 – bzuillsmith

0

別のオプションを

希望は独立したプロセスとしてあなたWPFウィンドウを構築し、ちょうどVB6からそれらを呼び出すことです。ここ はこれを行う方法についてのスレッドです: 再びWhat is the VB 6 equivalent of Process.Start?

、あなたはVB6から任意の相互作用を必要としない場合は特に、あなたがWPF exeファイル内のすべてのスレッドを管理する必要があります。

0

これまでのところすべてがうまくいきました。 COM可視メソッドとイベントの基本的な例:

// COM visible interfaces 
[ComVisible(true)] 
[Guid("..."), InterfaceType(ComInterfaceType.InterfaceIsDual)] 
public interface IWpfCtl 
{ 
    void Show(); 

    void Close(); 

    void ComMethod(string key); 
} 

[ComVisible(true)] 
[Guid("..."), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
public interface IWpfCtlEvents 
{ 
    void OnTestButton(string message); 
} 



// Implementation 
public delegate void TestButtonDelegate(string message); 

[ComVisible(true)] 
[Guid("..."), ComSourceInterfaces(typeof(IWpfCtlEvents)), ClassInterface(ClassInterfaceType.None)] 
public class WpfCtl : IWpfCtl, IDisposable 
{ 
    Thread _windowThread; 
    WpfWindow _wpfWindow; 

    public event TestButtonDelegate OnTestButton; 

    // Default parameterless constructor 
    public WpfCtl() 
    { 
    } 

    // Instantiate and show a WPF Window 
    public void Show() 
    { 
     // create a thread 
     _windowThread = new Thread(new ThreadStart(() => 
     { 
      // create synchronization context 
      SynchronizationContext.SetSynchronizationContext(
       new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher)); 

      // instantiate the window 
      _wpfWindow = new WpfWindow(); 

      // shut down the dispatcher on window close 
      _wpfWindow.Closed += (s, e) => 
        Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background); 

      // bind to window events 
      _wpfWindow.testButton.Click += (sender, args) => OnTestButtonClick("Test button was clicked"); 

      // show the window 
      _wpfWindow.Show(); 

      // start the dispatcher processing 
      System.Windows.Threading.Dispatcher.Run(); 
     })); 

     // set the apartment state 
     _windowThread.SetApartmentState(ApartmentState.STA); 

     // make the thread a background thread 
     _windowThread.IsBackground = true; 

     // start the thread 
     _windowThread.Start(); 
    } 

    public void Dispose() 
    { 
     Close(); 
    } 

    // Close window 
    public void Close() 
    { 
     if (_windowThread != null && _windowThread.IsAlive && _wpfWindow != null) 
     { 
      if (_wpfWindow.Dispatcher.CheckAccess()) 
       _wpfWindow.Close(); 
      else 
      { 
       _wpfWindow.Dispatcher.Invoke(() => { _wpfWindow.Close(); }); 
      } 
     } 
    } 

    // COM visible method 
    public void ComMethod(string key) 
    { 
     if (_wpfWindow != null) 
      _wpfWindow.Dispatcher.Invoke(() => { _wpfWindow.Method(key); }); 
    } 

    // COM event 
    private void OnTestButtonClick(string message) 
    { 
     if (OnTestButton != null) 
     { 
      OnTestButton.Invoke(message); 
     } 
    } 
} 
関連する問題