チュートリアル : Windows フォームを共有スレッドに表示することによって COM 相互運用をサポートする
更新 : 2007 年 11 月
COM 相互運用機能に関する問題は、Application.Run メソッドを使って作成される .NET Framework メッセージ ループにフォームを表示することで解決できます。
COM クライアント アプリケーションから Windows フォームを正しく動作させるには、フォームを Windows フォーム メッセージ ループで実行する必要があります。この場合、次のいずれかの方法を使用します。
Form.ShowDialog メソッドを使って、Windows フォームを表示する。詳細については、「方法 : ShowDialog メソッドで Windows フォームを表示して COM 相互運用機能をサポートする」を参照してください。
各 Windows フォームを別個のスレッドに表示する。詳細については、「チュートリアル : Windows フォームを別個のスレッドに表示することによって COM 相互運用をサポートする」を参照してください。
共有メッセージ ループを .NET Framework コンポーネントの新しいスレッドに作成する。
次の手順は、共有メッセージ ループを使って Windows フォームを新しいスレッドに表示する方法を示しています。
このトピックのコードを単一のリストとしてコピーするには、「方法 : 共有スレッド上に Windows フォームを表示することで COM 相互運用をサポートする」を参照してください。
手順
これとよく似た方法は、「チュートリアル : Windows フォームを別個のスレッドに表示することによって COM 相互運用をサポートする」でも使用しています。ただし、ここでは、別個のメッセージ ループを使ってフォームを別個のスレッドに表示するのではなく、共有メッセージ ループを作成し、それを .NET Framework コンポーネント内の 1 つの新規スレッドでのみ実行します。
この方法を使うと、標準 Windows フォーム アプリケーションの動作がより正確に表されます。また、すべてのフォームが同じスレッドで実行されるため、複数のフォームでリソースを共有しやすくなります。「チュートリアル : Windows フォームを別個のスレッドに表示することによって COM 相互運用をサポートする」のソリューションでは、フォームごとに新規スレッドが作成されます。この場合は、複数のフォームでリソースを共有するには、スレッドを同期するコードが必要になります。
ここで紹介する方法は、Windows フォーム アプリケーションの動作により近いため、クライアント アプリケーションを開く .NET Framework Windows フォームは、.NET Framework メッセージ ループの停止と同時に閉じられます。この動作が起こるのは、ApplicationContext のメイン フォームとして指定されたフォームがユーザーによって閉じられたときです。ApplicationContext は、メッセージ ループを開始するために使用されます。
次のコード例では、クライアント アプリケーションから開かれる最初のフォームが、ApplicationContext のメイン フォームとして設定されます。そのため、ユーザーがそのフォーム インスタンスを閉じると、.NET Framework メッセージ ループが終了し、他のすべての Windows フォームが閉じます。
すべてのフォームが使用する新規スレッドに共有メッセージ ループを作成するには
新しいクラス ライブラリ プロジェクトを作成して、COMWinform と命名します。
既定の Class1.vb ファイルを削除します。
[プロジェクト] メニューの [クラスの追加] を選択します。
[COM クラス] テンプレートをクリックします。
[ファイル名] ボックスに「COMForm.vb」と入力し、[追加] をクリックします。
次のコード ステートメントを、COMForm ファイルの先頭部分にあるクラス定義の前に貼り付けます。
Imports System.Windows.Forms Imports System.Runtime.InteropServices
COMForm クラス定義内のコンストラクタ定義の下に、次のコードを貼り付けます。
Private WithEvents frmManager As FormManager Public Sub ShowForm1() ' Call the StartForm method by using a new instance ' of the Form1 class. StartForm(New Form1) End Sub Private Sub StartForm(ByVal frm As Form) ' This procedure is used to show all forms ' that the client application requests. When the first form ' is displayed, this code will create a new message ' loop that runs on a new thread. The new form will ' be treated as the main form. ' Later forms will be shown on the same message loop. If IsNothing(frmManager) Then frmManager = New FormManager(frm) Else frmManager.ShowForm(frm) End If End Sub Private Sub frmManager_MessageLoopExit() Handles frmManager.MessageLoopExit 'Release the reference to the frmManager object. frmManager = Nothing End Sub
[プロジェクト] メニューの [クラスの追加] をクリックします。次に、[クラス] テンプレートをクリックします。
[ファイル名] ボックスに「FormManager.vb」と入力し、[追加] をクリックします。
FormManager ファイルの内容を次のコードに置き換えます。
Imports System.Runtime.InteropServices Imports System.Threading Imports System.Windows.Forms <ComVisible(False)> _ Friend Class FormManager ' This class is used so that you can generically pass any ' form that you want to the delegate. Private WithEvents appContext As ApplicationContext Private Delegate Sub FormShowDelegate(ByVal form As Form) Event MessageLoopExit() Public Sub New(ByVal MainForm As Form) Dim t As Thread If IsNothing(appContext) Then appContext = New ApplicationContext(MainForm) t = New Thread(AddressOf StartMessageLoop) t.IsBackground = True t.SetApartmentState(ApartmentState.STA) t.Start() End If End Sub Private Sub StartMessageLoop() ' Call the Application.Run method to run the form on its own message loop. Application.Run(appContext) End Sub Public Sub ShowForm(ByVal form As Form) Dim formShow As FormShowDelegate ' Start the main form first. Otherwise, focus will stay on the ' calling form. appContext.MainForm.Activate() ' Create a new instance of the FormShowDelegate method, and ' then invoke the delegate off the MainForm object. formShow = New FormShowDelegate(AddressOf ShowFormOnMainForm_MessageLoop) appContext.MainForm.Invoke(formShow, New Object() {form}) End Sub Private Sub ShowFormOnMainForm_MessageLoop(ByVal form As Form) form.Show() End Sub Private Sub ac_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles appContext.ThreadExit appContext.MainForm.Dispose() appContext.MainForm = Nothing appContext.Dispose() appContext = Nothing RaiseEvent MessageLoopExit() End Sub End Class
[プロジェクト] メニューの [Windows フォームの追加] をクリックします。次に、[追加] をクリックします。
[Button1] をダブルクリックして Click イベント ハンドラを追加します。
Click イベント ハンドラに次のコードを追加します。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MessageBox.Show("Clicked button") End Sub
ソリューションをビルドします。
また、このステップでは、プロジェクトをこのコンピュータの COM 相互運用機能に登録します。
COM 相互運用機能を使用する実行可能ファイルを作成するには
Microsoft Visual Basic 6.0 を起動します。
新しい標準 EXE プロジェクトを作成します。
[プロジェクト] メニューの [参照設定] をクリックします。
Visual Basic 2005 ソリューションのビルド時に生成された COMWinform タイプ ライブラリへの参照を追加します。
または
このタイプ ライブラリが一覧に表示されていない場合は、[参照] をクリックしてタイプ ライブラリ (.tlb) ファイルを手動で見つけます。
フォームにボタンを追加します。
[表示] メニューの [コード] をクリックし、以下のコードをフォーム モジュールに追加します。
Option Explicit
Private Sub Command1_Click()
Dim frm As COMWinform.COMForm
Set frm = New COMWinform.COMForm
frm.ShowForm1
End Sub
[ファイル] メニューの [EXE の作成] をクリックしてプロジェクトをコンパイルします。
コンパイルされた Visual Basic 6.0 実行可能ファイルを実行します。
ボタンをクリックして、前に作成したクラス ライブラリから Windows フォームを表示します。
Windows フォームの TextBox コントロールの 1 つにフォーカスを設定してから、Tab キーを押してコントロール間を移動します。
Tab キーを使用してフォーカスを別のコントロールに移動できることを確認します。また、Enter キーを押すとボタンの Click イベントが発生することも確認します。
参照
処理手順
方法 : ShowDialog メソッドで Windows フォームを表示して COM 相互運用機能をサポートする
チュートリアル : Windows フォームを別個のスレッドに表示することによって COM 相互運用をサポートする