次の方法で共有


Microsoft Office VBA マクロを Visual Basic .NET および C# に変換する

Paul Cornell
Microsoft Corporation

November 7, 2002

MSDN Code Center からサンプル ファイル (office11072002.exe) をダウンロードする

概要 : Office VBA マクロを .NET、特に Visual Basic .NET および C# に移行する方法を示します。その後、そのソリューションを Visual Basic .NET マネージ COM アドインに変換する方法も示します。

ニュースグループやカンファレンスで、 多くの Microsoft Office 開発者が、 Microsoft .NET 開発プラットフォームを使ってソリューションのコードを記述する方法の学習に関心を持っていることに気が付きました。

今月のコラムでは、 Office VBA マクロを .NET、つまり Visual Basic .NET と C# の両方に変換する方法を示すつもりです。 さらに、今月のコラムの最後に付録として、 そのソリューションから Visual Basic .NET マネージ COM アドインを作成する方法も示すつもりです。

私は 1か月ほど前、Microsoft 社外のテクニカル ライタから MSDN Web サイトに公開する予定の Microsoft Word 文書をいくつか受け取りました。 テクニカル ライタは、 独自の Word 文書テンプレートを添付し、 独自の方法でテキストのスタイルを設定していました。 私は、Word でこの独自のスタイルを MSDN Web サイトの文書テンプレートに合うように変更するソリューションが必要になりました。 そこで、このプロセスを自動化するために、 Microsoft Excel ワークシートにスタイル マッピングを格納したいと考えました。 私と同僚は、Word のマクロの記録を使って、機能できるソリューションを考え出し、 その後、Office Visual Basic Editor でそのコードを変更し、ソリューションをさらに調整しました。

では、私が VBA でどのようにソリューションを作成したかを説明し、 同じソリューションのコードを Microsoft Visual Basic® .NET および C# で記述する方法を見ていきましょう。

ソリューションを作成するための Visual Basic for Applications の使用

大部分の Office 開発者は VBA ソリューションを作成する方法を理解しているので、 ここでそのことを詳しく説明するつもりはありません。 その上、おそらくこのコラムの読者なら何らかの形で .NET に関わっていることでしょう、違いますか ? ただし、ここで作業し、.NET と比較するために基準となるコードが必要なので、 私がどのように作業したかを示しておきましょう。

まず、VBA ユーザー フォームを作成し、 そのフォーム モジュールを Word で Normal.dot 文書テンプレートに添付しました。 サンプルをダウンロードし、VBAStyleChange フォルダから frmMain.frm を VBA プロジェクトにインポートするか、 ソリューションを独自に作成するために以下の手順を実行できます。 ユーザー フォームは図 1 のようになります。

Dd313958.office11072002-fig01(ja-jp,MSDN.10).gif

図 1. サンプル VBA ユーザー フォーム

このユーザー フォームのプロパティを以下のように設定しました。

項目 プロパティ
UserForm Name frmMain
  Caption Change Styles
CommandButton Name cmdWord
  Caption Select Word Document
CommandButton Name cmdExcel
  Caption Select Excel Style Change File
CommandButton Name cmdGo
  Caption Change Styles
Label Name lblWord
  Caption (空白)
Label Name lblExcel
  Caption (空白)
Label Name lblStatus
  Caption (空白)

次に、Microsoft Word 10.0 オブジェクト ライブラリ、Microsoft Excel 10.0 オブジェクト ライブラリ、 および Microsoft Office 10.0 オブジェクト ライブラリへの参照を設定しました。

その後、以下のコードを UserForm に追加しました。 ユーザーが Word ファイルと Excel ファイルのパスを最初に指定しない限り、 [Change Styles] ボタンをクリックできないように、 UserForm の Initialize イベントで、[Change Styles] ボタンを無効にしました。


Private Sub UserForm_Initialize()

    ' ユーザーは、まず Word ファイルと Excel ファイルを指定する必要があります。
    Me.cmdGo.Enabled = False
    
End Sub

ReplaceStyles サブルーチンが、 このソリューションの中心になる部分です。 基本的に、サブルーチンの Excel 部分はワークシートを 1 行ずつ調べ、 列 A の変換前のスタイルと列 B の変換後のスタイルをメモリに読み取っていきます。 コードの Word 部分は、Selection オブジェクト、Find オブジェクト、 および Replacement オブジェクトを使って、 あるテンプレートから別のテンプレートにスタイルを交換します。


Private Sub ReplaceStyles(ByVal strWordPath As String, _
        ByVal strExcelPath As String)
    
    ' 目的 : Excel 変換ファイルで指定されたとおりに、変換前の 
    ' Word スタイルを変換後の Word スタイルに置き換えます。
    
    ' 入力 :
    '   strWordPath: Word 文書へのパス。
    '   strExcelPath: Excel スタイル変換ファイルへのパス。
    
    ' 注意 : このコードは Office 10.0 オブジェクト ライブラリを使用しているので、
    ' Word 2002 と Excel 2002 のみで機能します。
    ' Office 10.0、Word 10.0、および Excel 10.0 の各オブジェクト ライブラリへの
    ' 参照を設定する必要があります。
    
    Dim wdApp As Word.Application
    Dim objDoc As Word.Document
    Dim xlApp As Excel.Application
    Dim objWB As Excel.Workbook
    Dim objWS As Excel.Worksheet
    Dim objRngOld As Excel.Range
    Dim objRngNew As Excel.Range
        
    On Error GoTo ReplaceStyles_Err
        
    ' Word 文書を開きます。
    Set wdApp = New Word.Application
    Set objDoc = wdApp.Documents.Open(FileName:=strWordPath)
    
    ' Excel ブックの最初のワークシートを開き、
    ' セル A1 から処理を始めます。
    Set xlApp = New Excel.Application
    Set objWB = xlApp.Workbooks.Open(FileName:=strExcelPath)
    Set objWS = objWB.Worksheets.Item(Index:=1)
    Set objRngOld = objWS.Range(Cell1:="A1")
                        
    ' セルが空の場合は終了します。
    Do While Not objRngOld.Value = ""
    
        ' 列 B のスタイルで置き換えます。
        Set objRngNew = objRngOld.Offset(ColumnOffset:=1)
    
        Selection.HomeKey Unit:=wdStory
        Selection.Find.ClearFormatting
        Selection.Find.Style = _
            ActiveDocument.Styles(Index:=objRngOld.Value)
        frmMain.lblStatus.Caption = "Attempting to replace " & _
            objRngOld.Value & " style..."
        DoEvents
        Selection.Find.Replacement.ClearFormatting
        Selection.Find.Replacement.Style = _
            ActiveDocument.Styles(Index:=objRngNew.Value)
        
        With Selection.Find
            .Text = ""
            .Replacement.Text = ""
            .Forward = True
            .Wrap = wdFindContinue
            .Format = True
            .MatchCase = False
            .MatchWholeWord = False
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
        End With
        
        Selection.Find.Execute Replace:=wdReplaceAll
    
        ' 次の行の列 A に移動します。
        Set objRngOld = _
            objRngNew.Offset(RowOffset:=1, ColumnOffset:=-1)
    
    Loop
    
    objDoc.Save
    frmMain.lblStatus.Caption = "Operation complete."
        
ReplaceStyles_Exit:

    ' クリーン アップ。
    wdApp.Quit
    xlApp.Quit
    Set objRngOld = Nothing
    Set objRngNew = Nothing
    Set objWS = Nothing
    Set objWB = Nothing
    Set xlApp = Nothing
    Set objDoc = Nothing
    Set wdApp = Nothing
    
    Exit Sub
    
ReplaceStyles_Err:
    
    Select Case Err.Number
        Case 5941 ' Unknown style.
            frmMain.lblStatus.Caption = "Could not change " & _
                " from style " & objRngOld & " to " & _
                objRngNew.Value
            Debug.Print "Could not change from style " & _
                objRngOld & " to " & _
                objRngNew.Value
            Resume Next
        Case 62
            Resume Next
        Case Else ' Unknown error.
            MsgBox Prompt:="Error " & Err.Number & _
                " in ReplaceStyles macro: " & Err.Description
    End Select
    
    GoTo ReplaceStyles_Exit
            
End Sub

cmdExcel_Click イベントと cmdWord_Click イベントが、Office の [ファイルを開く] ダイアログ ボックスを表示するので、 ユーザーは対象となる Word 文書と Excel のスタイル変換リスト ファイルへのパスを指定できます。


Private Sub cmdExcel_Click()

    ' ユーザーが使用する Excel ドキュメントを指定します。
    Dim objFileDialog As Office.FileDialog
    
    Set objFileDialog = Application.FileDialog _
        (FileDialogType:=msoFileDialogOpen)
    
    With objFileDialog
    
        .AllowMultiSelect = False
        .Title = "Select Excel Style Change File"
        .Filters.Clear
        .Filters.Add _
            Description:="Style Change Files", _
            Extensions:="*.xls"
        
        ' "-1" は [ファイルを開く] ダイアログ ボックスで、
        ' [開く] ボタンがクリックされたことを意味します。
        If .Show = -1 Then
        
            Me.lblExcel.Caption = .SelectedItems(1)
        
        End If
    
    End With
    
    Call CheckGoStatus
    
End Sub

Private Sub cmdWord_Click()

    ' ユーザーが使用する Word 文書を指定します。
    Dim objFileDialog As Office.FileDialog
    
    Set objFileDialog = Application.FileDialog _
        (FileDialogType:=msoFileDialogOpen)
    
    With objFileDialog
    
        .AllowMultiSelect = False
        .Title = "Select Word Document"
        .Filters.Clear
        .Filters.Add _
            Description:="Word Documents", _
            Extensions:="*.doc"
        
        ' "-1" は [ファイルを開く] ダイアログ ボックスで、
        ' [開く] ボタンがクリックされたことを意味します。
        If .Show = -1 Then
        
            Me.lblWord.Caption = .SelectedItems(1)
        
        End If
    
    End With
        
    Call CheckGoStatus
    
    Set objFileDialog = Nothing
    
End Sub

CheckGoStatus サブルーチンにより、 ユーザーは対象となる Word 文書と Excel のスタイル変換リスト ファイルが指定されているときだけ、 [Change Styles] ボタンをクリックできます。


Private Sub CheckGoStatus()

    ' [Change Styles] ボタンを有効にすべきかどうか ?
    If Me.lblWord.Caption <> "" And _
            Me.lblExcel.Caption <> "" Then
    
        Me.cmdGo.Enabled = True
        
    End If

End Sub

[Change Styles] ボタンをクリックすると、 上記で説明した ReplaceStyles サブルーチンを呼び出します。


Private Sub cmdGo_Click()

    Call ReplaceStyles(strWordPath:=Me.lblWord.Caption, _
        strExcelPath:=Me.lblExcel.Caption)

End Sub

次に、列 A に既存の (古い) Word スタイルを、 列 B に目的の (新しい) Word スタイルを保持する Excel ワークシートを作成しました。 以下は、ダウンロードのルート フォルダにある SampleStyleChangeFile.xls ファイルからの一例です。

Dd313958.office11072002-fig02(ja-jp,MSDN.10).gif

図 2. サンプル Excel スタイル変換ファイル

最後に、UserForm デザイナを表示し、F5 キーを押してソリューションを実行します。

このソリューションを配布するために、 フォーム モジュールを .frm ファイルにエクスポートします。 他のユーザーはこの .frm ファイルを Normal.dot 文書テンプレートにインポートし、 インポートしたユーザー フォームを実行できます。

では、この VBA ソリューションの .NET 版を調べてみましょう。

Visual Studio .NET を使用したソリューションの作成

多くの Office 開発者は .NET を理論上は理解していても、 これまで Visual Studio® .NET を使って Office ソリューションを作成したことがないかもしれません。 1 年以上前になりますが、 このコラムの「Introducing .NET to Office Developers」 (英語) で、 Visual Studio .NET の使い方を例示しましたが、 良い機会なのでもう一度説明しましょう。 ここでは、上記のソリューションを最初から Visual Studio .NET でコーディングする方法を示します。

まず、 開発用コンピュータに Office XP Primary Interop Assemblies (PIA) をダウンロードして、インストールします。 Office XP PIA は、Visual Studio .NET での Office XP ソリューションの開発を容易にします。 Office XP PIA の詳細については、「Working with the Office XP Primary Interop Assemblies」 (英語) と「Office XP Primary Interop Assemblies Known Issues」 (英語) を参照してください。

次に、 サンプル ダウンロードの StyleChange フォルダにある StyleChange.sln ファイルを開くか、 ソリューションを独自に作成するために以下の手順を実行できます。

Visual Basic .NET Windows アプリケーションを作成することから始めます。

  1. Visual Studio .NET を起動します。

  2. [ファイル] メニューで [新規作成] をポイントし、[プロジェクト] をクリックします。

  3. [プロジェクトの種類] ペインで、[Visual Basic プロジェクト] フォルダを開きます。

  4. [テンプレート] ペインで、[Windows アプリケーション] アイコンをクリックします。

  5. [プロジェクト名] ボックスに、「StyleChange」と入力します。

  6. [場所] ボックスに、ローカル ハード ドライブ上のフォルダを入力するか、参照します。

  7. [OK] をクリックします。

    次に、Windows フォームをカスタマイズします。

  8. [ソリューション エクスプローラ] (表示されていない場合は、[表示] メニューの [ソリューション エクスプローラ] をクリックします) で、[StyleChange] プロジェクト ノードの [Form1.vb] ファイルを右クリックし、 [名前の変更] をクリックしてファイルの名前を frmMain.vb に変更します。

  9. [StyleChange] プロジェクト ノードを右クリックし、[プロパティ] をクリックします。 [共通プロパティ] フォルダを開き、[全般] をクリックして、[スタートアップの設定] リストの [frmMain] をクリック後、[OK] をクリックします。

  10. [ツールボックス] (表示されていない場合は、[表示] メニューの [ツールボックス] をクリックします) と [プロパティ ウィンドウ] (表示されていない場合は、[表示] メニューの [プロパティ ウィンドウ] をクリックします) を使用して、Windows フォームをカスタマイズします。 Windows フォームとフォーム コントロールに使用する名前とプロパティについては、 上記のセクションを参照してください。

    **注意   ** VBA の [Caption] プロパティは .NET の [Text] プロパティに相当します。 また、Visual Studio .NET では Button という用語を使用しますが、 VBA では CommandButton という用語を使用します。

  11. 完成した Windows フォームは以下の図 3 のようになります。

    Dd313958.office11072002-fig03(ja-jp,MSDN.10).gif

    図 3. サンプル Windows フォーム

次に、Word 2002 PIA と Excel 2002 PIA への参照を設定します。

  1. [プロジェクト] メニューで、[参照の追加] をクリックします。

  2. [COM] タブをクリックします。

  3. [Microsoft Word 10.0 Object Library] と [Microsoft Excel 10.0 Object Library] をダブルクリックします。

    **注意   ** [Microsoft Office 10.0 Object Library] は既定で追加されているだけでなく、 2 つの .NET OpenFileDialog コントロールを使って同じことを実現できるので、 [Microsoft Office 10.0 Object Library] をダブルクリックする必要はありません。

  4. フォームに 2 つの OpenFileDialog コントロールを追加します。 追加したコントロールの名前をそれぞれ objWordFileDialogobjExcelFileDialog に変更します。

    次に、コードを追加します。

  5. [表示] メニューで [コード] をクリックします。

以下にコードを示します。 Visual Basic .NET プログラミングに馴染みのない方のために、ところどころ説明を入れています。


Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Word.WdUnits
Imports Microsoft.Office.Interop.Word.WdFindWrap
Imports Microsoft.Office.Interop.Word.WdReplace
Imports System.Windows.Forms.Application
Imports System.Runtime.InteropServices.Marshal

Imports ステートメントを使って、 Visual Basic .NET コードを削減し、単純化できます。 VBA では、COM タイプ ライブラリやオブジェクト ライブラリに参照を設定するときに、 プロジェクト内のすべての参照間で名前が一意であると想定して、 オブジェクト名やメンバ名の前にタイプ ライブラリ名やオブジェクト ライブラリ名を入力することを省略するオプションがありました。 .NET では、すべてのクラス名、メンバ名、および型名の前に対応する名前空間を付ける必要があります ("名前空間" はアセンブリの構成内部の論理単位で、 "アセンブリ" はタイプ ライブラリやオブジェクト ライブラリに似ています)。 たとえば、Word VBA の wdStory 定数は、 .NET では Microsoft.Office.Interop.Word.WdUnits.wdStory 定数になります。 VBA ではコードで wdStory を使用できますが、 .NET では Visual Basic .NET Imports ステートメントを使って Imports Microsoft.Office.Interop.Word.wdUnits と指定しないと、 コードで毎回 Microsoft.Office.Interop.Word.WdUnits.wdStory を使用する必要があります。


Public Class frmMain
    Inherits System.Windows.Forms.Form

.NET では、 プロジェクトのフォーム モジュール、コード モジュール、およびクラス モジュールのコードをすべて 1 つのコード ファイルに格納できます。 Visual Basic .NET でのコード ファイルの拡張子は .vb ですが、 VBA ではファイル拡張子がそれぞれ .frm、.bas、および .cls に分かれています。 .vb ファイルではコードがフォーム モジュールやクラス モジュールに所属することを示すために、 Class ... End Class ステートメントを使用します。 また、コードがコード モジュールに所属することを示すために、 Module ... End Module ステートメントを使用します。

.NET では、フォームを作成しないで、 Visual Basic .NET Inherits キーワードを使用して、 汎用の Windows フォームの機能を "流用し、拡張"します。 この場合、System.Windows.Forms.Form クラスが最小化ボタン、最大化/元に戻すボタン、および閉じるボタンを持つタイトル バーやフレームなど、 汎用の Windows フォームが必要とするすべての機能を保持します。


' この縮小したコード領域のコードを変更しないでください。
' + Windows フォーム デザイナで生成されたコード

縮小したコード領域内のコードを説明するつもりはありません。 VBA では、コンパイラがユーザー フォームを作成するためのコードはすべて覆い隠されています。 Visual Basic .NET では、ユーザーがこのコードに手を加えたければ、 すべてのコードを使用できます。 しかし、実際にこのコードを直接変更する必要性はまったくありません。 直接コードを変更する代わりに、 グラフィカルな Windows フォーム デザイナと [プロパティ] ウィンドウを使用します。


    Private Sub frmMain_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load

        ' ユーザーはまず Word ファイルと Excel ファイルを指定する必要があります。
        Me.cmdGo.Enabled = False

    End Sub

Visual Basic .NET と VBA とでは、イベントをコーディングする方法がやや異なります。 .NET では、"イベント ハンドラ" と呼ばれるイベントを処理するサブルーチンを作成します。 この場合、MyBase.Load が発生すると、つまり Windows フォームが読み込まれると、 frmMain_Load イベント ハンドラのコードが実行されます。 sender 引数と e 引数を使って、 そのイベント ハンドラによりどのオブジェクトが実行されるかなど、 より細かいプログラム制御が可能になります。


    Private Sub ReplaceStyles(ByVal strWordPath As String, _
        ByVal strExcelPath As String)

        ' 目的: Excel 変換ファイルで指定されたとおりに、変換前の 
        ' Word スタイルを変換後の Word スタイルに置き換えます。

        ' 入力:
        '   strWordPath: Word 文書へのパス。
        '   strExcelPath: Excel スタイル変換ファイルへのパス。

        ' 注意 : このコードは Word 2002 と Excel 2002 のみで機能します。
        ' Word 10.0、および Excel 10.0 の各オブジェクト ライブラリへの
        ' 参照を設定する必要があります。

        Try

エラー処理で使用する Try キーワードは Visual Basic .NET の新しいキーワードです。 必要であれば依然として VBA や Visual Basic の On Error 構成を使用できますが、 Visual Basic .NET Try...Catch...Finally ステートメントを使用すると、 Select Case Err.Number コードを使用しなくても、 エラーの種類に基づいて異なるエラー処理コードを実行できます。 Try...Catch...Finally を使用する場合は、 エラーをテストするコードを Try...End Try コード ブロックで囲みます。 エラーをキャッチするには、 特定のエラー ケースのエラー処理コードを Catch ブロックで囲みます。 "クリーン アップ" コードまたは "終了" コードを Finally ブロックで囲むことによって、 エラー処理を終了します。


            ' Word 文書を開きます。
            Dim wdApp As New Word.ApplicationClass()
            Dim objDoc As Word.Document = _
                wdApp.Documents.Open(FileName:=strWordPath)

上記のコードでは、 wdApp オブジェクト変数が、Word.Application 型ではなく Word.ApplicationClass 型になっています。 これは、現時点での Office XP PIA の制限によるものです。 .NET は Word.Application.Quit イベントと Word.Application.Quit メソッドなど、 複数のメンバ型にまたがるオーバーロード ステートメント間の違いを解決できないので、 Office XP PIA ではコンパイル時にこの違いを解決するために特殊な ... Class クラスを作成しました。

その他に 2 つ注意することがあります。 1 つは Set キーワードを使用しなくなったことで、 もう 1 つは Dim キーワードで等号を使用していることです。 Visual Basic .NET には Set キーワードが存在しなくなりました。 オブジェクトや値を変数に代入するには、 単に等号を使用します。 また、ほとんどの場合に、変数の宣言と同時に変数にオブジェクトや値を代入できるようになりました。 その結果、パフォーマンスに悪影響を及ぼすことなくキーストロークを大幅に削減できます。


            ' Excel ブックの最初のワークシートを開き、
            ' セル A1 から処理を始めます。
            Dim xlApp As New Excel.ApplicationClass()
            Dim objWB As Excel.Workbook = _
                xlApp.Workbooks.Open(FileName:=strExcelPath)
            Dim objWS As Excel.Worksheet = _
                objWB.Worksheets.Item(Index:=1)
            Dim objRngOld As Excel.Range = _
                objWS.Range(Cell1:="A1")
            Dim objRngNew As Excel.Range
            Dim objSelection As Word.Selection = wdApp.Selection

            ' セルが空の場合は終了します。
            Do While Not objRngOld.Value = ""

                ' 列 B のスタイルで置き換えます。
                objRngNew = objRngOld.Offset(ColumnOffset:=1)

                With objSelection

                    .HomeKey(Unit:=wdStory)
                    .Find.ClearFormatting()
                    .Find.Style = objDoc.Styles(Index:=objRngOld.Value)

                End With

                Me.lblStatus.Text = "Attempting to replace " & _
                    objRngOld.Value & " style..."
                DoEvents()

.NET では、メソッドが引数を受け取らない場合でも、 すべてのメソッド呼び出しの後にかっこを付ける必要があります。 つまり、VBA では DoEvents とコーディングできましたが、 .NET では DoEvents() とコーディングする必要があります。


                With objSelection.Find

                    .Replacement.ClearFormatting()
                    .Replacement.Style = _
                        objDoc.Styles(Index:=objRngNew.Value)
                    .Text = ""
                    .Replacement.Text = ""
                    .Forward = True
                    .Wrap = wdFindContinue
                    .Format = True
                    .MatchCase = False
                    .MatchWholeWord = False
                    .MatchWildcards = False
                    .MatchSoundsLike = False
                    .MatchAllWordForms = False
                    .Execute(Replace:=wdReplaceAll)

                End With

                ' 次の行の列 A に移動します。
                objRngOld = objRngNew.Offset(RowOffset:=1, _
                    ColumnOffset:=-1)

            Loop

            objDoc.Save()
            Me.lblStatus.Text = "Operation complete."
            wdApp.Quit()
            xlApp.Quit()

        Catch e As System.Exception

            MsgBox(Prompt:="Error of type " & _
                e.GetType.ToString & vbCrLf & _
                "in " & e.TargetSite.ToString & vbCrLf & _
                "of " & e.Source & ":" & vbCrLf & _
                e.Message)

        End Try

    End Sub

上記のコードの残りの部分は、VBA の対応部分とほぼ同じなので、 ここでこれ以上詳しく説明しません。


    Private Sub cmdWord_Click(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles cmdWord.Click

        ' ユーザーが使用する Word 文書を指定します。
        With Me.objWordFileDialog

            .Multiselect = False
            .Title = "Select Word Document"
            .Filter = "Word Documents (*.doc)|*.doc"

Windows フォームの OpenFileDialog コントロール (System. Windows.Forms 名前空間で定義されます) をプログラミングする方法は、 Office FileDialog オブジェクトをプログラミングする方法と多くの点で似ています。 OpenFileDialog.Filter プロパティは Office の FileDialog.Filters コレクションとは異なり、 Office で FileDialog.Filters.Add メソッドを繰り返し呼び出して行うことを、 ファイルの種類とファイル拡張子のパイプ区切り文字列を指定して行うことができます。


            If .ShowDialog = DialogResult.OK Then

ユーザーが Office の [ファイルを開く] ダイアログ ボックスで [開く] ボタンをクリックしたことを示すために、 FileDialog.Show メソッドの戻り値が -1 かどうかを確認します。 Windows フォームでは、 OpenFileDialog.ShowDialog メソッドの戻り値が DialogResult.OK かどうかを確認します。


                Me.lblWord.Text = .FileName

同様に、 Office の [ファイルを開く] ダイアログ ボックスから選択したファイル名を取得するには、 FileDialog.SelectedItems.Item(1) メソッドで値を取得しましたが、 Windows フォームでは OpenFileDialog.FileName プロパティの値を取得します。


            End If

        End With

        Call CheckGoStatus()

    End Sub

    Private Sub cmdExcel_Click(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles cmdExcel.Click

        ' ユーザーが使用する Excel ドキュメントを指定します。
        With Me.objExcelFileDialog

            .Multiselect = False
            .Title = "Select Excel Style Change File"
            .Filter = "Style Change Files (*.xls)|*.xls"

            If .ShowDialog = DialogResult.OK Then

                Me.lblExcel.Text = .FileName

            End If

        End With

        Call CheckGoStatus()

    End Sub

    Private Sub CheckGoStatus()

        ' [Change Styles] ボタンを有効にすべきかどうか ?
        If Me.lblWord.Text <> "" And Me.lblExcel.Text <> "" Then

            Me.cmdGo.Enabled = True

        End If

    End Sub

    Private Sub cmdGo_Click(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles cmdGo.Click

        Call ReplaceStyles(strWordPath:=Me.lblWord.Text, _
            strExcelPath:=Me.lblExcel.Text)

    End Sub

End Class

上記のコードの残りの部分は既に説明し、 VBA の対応部分と似ているので、ここではこれ以上詳しく説明しません。

[デバッグ] メニューの [開始] をクリックしてソリューションを実行できます。

ソリューションを配布するには、 <プロジェクト名>\StyleChange\bin フォルダ内の StyleChange.exe ファイルをパブリックにアクセスできるファイル共有にコピーし、 ファイル共有にコピーしたことをユーザーに通知します。 ユーザーはローカル コンピュータの任意の単一フォルダに StyleChange.exe ファイルをコピーし、 StyleChange.exe ファイルを実行します。 また、ユーザーが .NET Framework 再配布可能モジュールや Office XP PIA をユーザーのコンピュータに正しくインストールしていることを確認する必要があります。 インストールしていない場合は、.msi ファイルを作成し、不足している可能性のあるコンポーネントを含めるようにそのファイルをカスタマイズする必要があります。 ソリューションにこのようなコンポーネントを追加すると、 最初はファイル サイズが非常に小さかったソリューションに数 MB のコードが追加されることになるので注意してください。

では、Visual Basic .NET ソリューションの C# 版を調べることで、今月のコラムを締めくくりましょう。

C# を使用したソリューションの作成

.NET の知識がある一部の Office 開発者は、 Office ソリューションで Visual Basic .NET の代替言語として C# の調査を開始しています。 以前に「Developing Microsoft Office Solutions Using C#」 (英語) という記事を書きました。 また、「Programming Microsoft Word 2002 and Excel 2002 with Microsoft Visual C#」 (英語) という記事も書きました。C# で Office ソリューションをプログラミングするときに、 これら 2 つの記事が適切な入門書になるはずです。

開発用コンピュータに Office XP PIA をダウンロードして、インストールした後、 ダウンロードしたサンプルの CSharpStyleChange フォルダにある CSharpStyleChange.sln ファイルを開くか、 ソリューションを独自に作成するために以下の手順を実行できます。

  1. Visual Studio .NET を起動します。
  2. [ファイル] メニューで [新規作成] をポイントし、[プロジェクト] をクリックします。
  3. [プロジェクトの種類] ペインで、[Visual C# プロジェクト] フォルダを開きます。
  4. [テンプレート] ペインで、[Windows アプリケーション] アイコンをクリックします。
  5. [プロジェクト名] ボックスに、「CSharpStyleChange」と入力します。
  6. [場所] ボックスに、ローカル ハード ドライブ上のフォルダを入力するか、参照します。
  7. [OK] をクリックします。

次に、上記の Visual Basic .NET ソリューションで行ったのと同様の方法で C# 版の Windows フォームをカスタマイズします。

  1. [ソリューション エクスプローラ] (表示されていない場合は、[表示] メニューの [ソリューション エクスプローラ] をクリックします) で、[CSharpStyleChange] プロジェクト ノードの [Form1.cs] ファイルを右クリックし、 [名前の変更] をクリックしてファイルの名前を frmMain.cs に変更します。
  2. [CSharpStyleChange] プロジェクト ノードを右クリックし、[プロパティ] をクリックします。 [共通プロパティ] フォルダを開き、[全般] をクリックして、[スタートアップの設定] リストの [CSharpStyleChange.frmMain] をクリック後、[OK] をクリックします。

Visual Basic .NET ソリューションで行ったのと同様に、 Windows フォームをカスタマイズし、 Word 2002 PIA と Excel 2002 PIA への参照を設定して、 フォームに 2 つの OpenFileDialog コントロールを追加します。

次にコードを追加します。 [表示] メニューで [コード] をクリックして、以下のコードを追加します。 C# 構文と Visual Basic .NET 構文の違いについて、 コードのところどころに説明を追加しました。 行ごとに機能を比較するために、このコードをこのコラムの前半の Visual Basic .NET コードと比較できます。


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;

C# の using キーワードと Visual Basic .NET の Imports キーワードは似ていますが、 1 つ重要な違いがあります。 Visual Basic .NET ではクラス名に Imports を使用できますが、 C# ではこれを行うことができません。 たとえば、Visual Basic .NET では、 Imports Microsoft.Office.Interop.Word.WdUnits により、 コードで wdStory を使用できますが、 C# では using Microsoft.Office.Interop.Word.WdUnits により、 コードで WdUnits.wdStory だけを使用できます (この場合、C# で wdStory を単独でコーディングすると、 コンパイル エラーが発生します)。

その他に 2 つの重要な点に注意してください。 まず、C# では大文字小文字を区別します。 using の代わりに Using を使用するとコンパイル エラーになります。 次に C# では、 ステートメントがセミコロン (;) で終わり、 コード ブロックは始め中かっこ ({) で始まり、終わり中かっこ (}) で終わります。 C# は Visual Basic .NET とは異なり、 コード ステートメントやコード ブロックの終了と継続に、 キャリッジ リターンや行連結文字を使用しません。


namespace CSharpStyleChange

C# では、名前空間の宣言に namespace キーワードを使用します。 C# プロジェクトを作成するときに、 プロジェクトと同じ名前で既定の名前空間が作成されます。 Visual Basic .NET では、名前空間の宣言に Namespace キーワードを使用できます。 Visual Basic .NET では特に指定しない限り、既定の名前空間は表示されません。 [ソリューション エクスプローラ] ウィンドウでプロジェクト アイコンを右クリックし、 [プロパティ] をクリックして、 [共通プロパティ] フォルダを開いて、 [全般] をクリック後、[アセンブリ名] ボックスを見ると既定の名前空間がわかります。 また、入れ子になった名前空間を持つこともできます。 Microsoft.Office.Interop.Word 名前空間の場合、 Word 名前空間が Interop 名前空間の入れ子に、 Interop 名前空間が Office 名前空間の入れ子に、 Office 名前空間が Microsoft 名前空間の入れ子になっています。


{
    public class frmMain : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button cmdWord;
        private System.Windows.Forms.Button cmdExcel;
        private System.Windows.Forms.Button cmdGo;
        private System.Windows.Forms.Label lblWord;
        private System.Windows.Forms.Label lblExcel;
        private System.Windows.Forms.Label lblStatus;
        private System.Windows.Forms.OpenFileDialog objWordFileDialog;
        private System.Windows.Forms.OpenFileDialog objExcelFileDialog;
        private System.ComponentModel.Container components = null;

C# の public キーワード、private キーワード、および class キーワードは、 Visual Basic .NET の Public キーワード、Private キーワード、および Class キーワードとまったく同じです。 C# のコロンは Visual Basic .NET の Inherits キーワードと同じです。 この場合、frmMain クラスは Windows フォームの基本的な特性を継承します。

C# では、変数名の前で変数のデータ型を宣言します。 従って、Visual Basic .NET では Private objExcelFileDialog As System.Windows.Forms.OpenFileDialog とコーディングしますが、 C# では private System.Windows.Forms.OpenFileDialog objExcelFileDialog; とコーディングします。

C# では Visual Basic .NET とは異なり、すべてのコードをクラス内部に保持する必要があります。 このコードでは、1 つの frmMain クラスが、 Dispose メソッド、Main メソッド、frmMain_Load イベント ハンドラなどを保持しています。


        public frmMain()
        {
            InitializeComponent();

            // ユーザーはまず Word ファイルと Excel ファイルを指定する必要があります。
            this.cmdGo.Enabled = false;
        }

この frmMain コード ブロックは、 .NET では "コンストラクタ" と呼ばれており、 VBA の Initialize イベントに似ています。 コンストラクタは、そのコンストラクタを保持するクラスと同じ名前を共有します (この場合は frmMain です)。

以下の縮小したコード領域に隠されている InitializeComponent メソッドは、 後で Main メソッドで使用する Windows フォームを準備します。

この例の this キーワードは Windows フォームを表しており、 Visual Basic .NET の Me キーワードに似ています。


        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

C# では Visual Basic .NET と異なり、 メソッド名の前でメソッドの戻り値の型を宣言します。 Visual Basic .NET では同じステートメントが Overrides Sub Dispose(Disposing As Boolean) になります。 void 型は Visual Basic .NET の Nothing 型と等価です。

C# の protected キーワードは Visual Basic .NET の Protected キーワードと同じです。 この例では、このクラス自体またはこのクラスから派生する任意のクラス内部から Dispose メソッドを呼び出せることを意味します。

C# の override キーワードは Visual Basic .NETの Overrides キーワードと同じです。 継承がクラスを "流用し、拡張" するのとまったく同様に、 .NET でオーバーライドすることはクラスのメンバを "流用し、拡張" することになります。


// 次のコード領域のコードを変更しないでください。
// #region Windows フォーム デザイナで生成されたコード

Visual Basic .NET と同様に、 C# も Windows フォームの元になるコードを縮小したコード領域に隠します。 必要に応じてコードを編集できますが、 実際にはコードを編集する必要はまったくありません。

C# では、コメントはダブル スラッシュ (//) 記号で始まり、その行の終わりまでがコメントになります。 また、複数行のコメントをスラッシュとアスタリスクの組み合わせ (/*) で開始し、 アスタリスクとスラッシュの組み合わせ (*/) で終了できます。


        [STAThread]
        static void Main() 
        {
            Application.Run(new frmMain());
        }

.NET では "属性" を使って、 特別な指示でコードを修飾できます。 C# では始め角かっこ ([) と終わり角かっこ (]) を使って属性を示します。 Visual Basic .NET では始め山かっこ (<)と終わり山かっこ (>) を使って属性を示します。 (この場合 STAThread 属性はこのアプリケーションのスレッド モデルがシングル スレッド アパートメント モデルであることを示しています。)

C# の static キーワードは Visual Basic .NET の Shared キーワードと同じです。 つまり、ここで Main メソッドを直接呼び出すことができます。 frmMain.Main 呼び出しの最初に frmMain 型のオブジェクトを宣言する必要はありません。

Application.Run メソッドは単純に Windows フォーム frmMain を読み込みます。 コードの実行は以下の frmMain_Load イベント ハンドラに引き継がれます。


        private void frmMain_Load(object sender, System.EventArgs e)
        {
            // ユーザーはまず Word ファイルと Excel ファイルを指定する必要があります。
            cmdGo.Enabled = false;   
        }

        private void cmdGo_Click(object sender, System.EventArgs e)
        {
            ReplaceStyles(lblWord.Text, lblExcel.Text);
        }

        private void CheckGoStatus()
        {
            // [Change Styles] ボタンを有効にすべきかどうか ?
            if((lblWord.Text != "") && (lblExcel.Text != ""))
            {
                cmdGo.Enabled = true;
            }
        }

Visual Basic .NET の If...Then ステートメントと等価な機能を C# でコーディングするには、 単純に if ステートメントに続いてかっこを使用します。 かっこ内の式が真の場合は、 関連するコード ブロック内のステートメントが実行されます。

C# の != 演算子は Visual Basic .NET の <> 演算子と等価です。 また、C# の && 演算子は Visual Basic .NET の And キーワードと等価です。


        private void cmdWord_Click(object sender, System.EventArgs e)
        {
            // ユーザーが使用する Word 文書を指定します。.
            objWordFileDialog.Multiselect = false;
            objWordFileDialog.Filter = "Word Documents (*.doc)|*.doc";

            if(objWordFileDialog.ShowDialog() == DialogResult.OK)
            {
                this.lblWord.Text = objWordFileDialog.FileName;
            }

C# での 2 つの等号 (==) は等しいことを意味し、 1 つの等号 (=) は代入を示します。 これが C# で objWordFileDialog.ShowDialog() = DialogResult.OK (等号 1 つだけ) とコーディングできない理由です。ShowDialog メソッドは結果としてダイアログを返します。 この例では DialogResult.OK 値を ShowDialog メソッドに代入していることになり、 これは可能ではありません。値が等しいかどうかだけを確認できます。


            CheckGoStatus();
        }

        private void cmdExcel_Click(object sender, System.EventArgs e)
        {
            // ユーザーが使用する Excel ドキュメントを指定します。
            objExcelFileDialog.Multiselect = false;
            objExcelFileDialog.Title = 
                "Select Excel Style Change File";
            objExcelFileDialog.Filter = 
                "Style Change Files (*.xls)|*.xls";

            if(objExcelFileDialog.ShowDialog() == DialogResult.OK)
            {
                lblExcel.Text = objExcelFileDialog.FileName;
            }

            CheckGoStatus();
        }

        private void ReplaceStyles(string strWordPath, 
            string strExcelPath)
        {
        // 目的: Excel 変換ファイルで指定されたとおりに、変換前の 
        // Word スタイルを変換後の Word スタイルに置き換えます。

        // 入力:
        //  strWordPath: Word 文書へのパス。
        //  strExcelPath: Excel スタイル変換ファイルへのパス。

        // 注意 : このコードは Word 2002 と Excel 2002 のみで機能します。
        // Word 10.0、および Excel 10.0 の各オブジェクト ライブラリへの
        // 参照を設定する必要があります。

        object objMissing = System.Reflection.Missing.Value;

        try
        {
            // Word 文書を開きます。
            Word.ApplicationClass wdApp = new
            Word.ApplicationClass();
            object ostrWordPath = strWordPath;
            Word.Document objDoc = 
                 wdApp.Documents.Open(ref ostrWordPath,
                     ref objMissing, ref objMissing, ref objMissing, 
                     ref objMissing, ref objMissing, ref objMissing, 
                     ref objMissing, ref objMissing, ref objMissing, 
                     ref objMissing, ref objMissing, ref objMissing,
                     ref objMissing, ref objMissing);

C# ではクラス メンバで定義されているすべての引数を指定する必要があります。 引数が C# で [Optional]、または Visual Basic .NET で Optional とマークされていても、 すべて指定する必要があります。

C# では Word ドキュメント クラスの Open メソッドのシグネチャは、 Open(ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object, ref object) と定義されています。 このシグネチャは、 C# で Open メソッドは 15 個の必須引数を受け取り、 各引数の前に ref キーワードを付け、 各引数は object 型である必要があることを示しています。 最初の引数はファイル名で、通常 Visual Basic .NET では String 値なので、 C# の string 値を保持する object 型の変数を宣言する必要があります。 従って、 object ostrWordPath = strWordPath; とコーディングします。 Open メソッドでは最初の引数だけを使用する必要がありますが、 C# では引数を省略できないことを覚えておいてください。 従って、残りの 14 個の引数に object 型の変数を指定し、 変数の値として System.Reflection.Missing.Value (上記の object objMissing = System.Reflection.Missing.Value;) を保持します。 この値は、これらの引数に値を指定するつもりがないことをコンパイラに指示します。


            // Excel ブックの最初のワークシートを開き、
            // セル A1 から処理を始めます。
            Excel.ApplicationClass xlApp = 
                new Excel.ApplicationClass();

            Excel.Workbook objWB = xlApp.Workbooks.Open(strExcelPath,
                objMissing, objMissing, objMissing, 
                objMissing, objMissing, objMissing, 
                objMissing, objMissing, objMissing, 
                objMissing, objMissing, objMissing,
                objMissing, objMissing);

            Excel.Sheets objSheets = objWB.Worksheets;
            Excel.Worksheet objWS = 
                (Excel.Worksheet)objSheets.get_Item(1);

Visual Basic .NET では CType メソッドを使用して変数をある型から別の型に変換します。 C# では変数の前にかっこを使用し、そのかっこ内に変換先の型を置きます (これを "キャスト" と呼びます)。 Excel Worksheets コレクションの get_Item メソッドは object 型のオブジェクトを返すので、 型 Excel.Worksheet にキャストする必要があります。 キャストしないとコンパイル エラーになります。 そのため、コード (Excel.Worksheet) をコード objSheets.get_Item(1) の前に記述しています。 ここで、なぜ Item メソッドではなく C# get_Item メソッド (Visual Basic .NET にはありません) を使用しているか疑問に思うことでしょう。 C# オブジェクト ブラウザを見ると、 Item プロパティは見つかりますが、 get_Item メソッドは見つかりません。 IntelliSense では Item プロパティが見つかりませんが、 get_Item メソッドは見つかります。 C# では "アクセサ" (オブジェクトにアクセスするメンバ) を呼び出すために、 アクセサの get_ メソッド (存在すれば) を使用してオブジェクト変数を取得し、 アクセサの set_ メソッド (存在すれば) を使用してオブジェクト変数を設定する必要があります。


            Excel.Range objRngOld = objWS.get_Range("A1", objMissing);
            Excel.Range objRngNew;
            Word.Selection objSelection = wdApp.Selection;

            // セルが空の場合は終了します。
            while((string)objRngOld.get_Value(objMissing) != "")

C# の while ループは Visual Basic .NET の Do While...Loop ループに似ています。 また、C# には do キーワードも存在しており、 Visual Basic .NET の do キーワードと似た動作を行います。


            {
                // 列 B のスタイルで置き換えます。
                objRngNew = objRngOld.get_Offset(objMissing, 1);

                object owdStory = Word.WdUnits.wdStory;
                objSelection.HomeKey(ref owdStory, ref objMissing);

                Word.Find objFind = objSelection.Find;
                objFind.ClearFormatting();

                foreach(Word.Style objStyle in objDoc.Styles)

C# の foreach キーワードは、 Visual Basic .NET の For Each...Next ステートメントとよく似た働きをします。 foreach ステートメントの利点の 1 つは、 繰り返しオブジェクト foreach ステートメントの前で宣言するのではなく、 foreach ステートメント内で宣言できます。


                {
                    if (objStyle.NameLocal == 
                            (string)objRngNew.get_Value(objMissing))
                    {
                        lblStatus.Text = "Attempting to replace " + 
                            objRngOld.get_Value(objMissing) + 
                            "style...";

文字列を連結する場合、 Visual Basic .NET でアンパサンド演算子 (&) を使用したのと同様に、 C# では加算演算子 (+) を使用します。


                        Application.DoEvents();

                        objFind.Replacement.ClearFormatting();

                        Word.Replacement objReplace =
                            objFind.Replacement;

                        object oValue =
                            objRngNew.get_Value(objMissing);
                        objReplace.set_Style(ref oValue);

                        objFind.Text = "";
                        objFind.Replacement.Text = "";
                        objFind.Forward = true;
                        objFind.Wrap = Word.WdFindWrap.wdFindContinue;
                        objFind.Format = true;
                        objFind.MatchCase = false;
                        objFind.MatchWholeWord = false;
                        objFind.MatchWildcards = false;
                        objFind.MatchSoundsLike = false;
                        objFind.MatchAllWordForms = false;

                        object owdReplaceAll =
                            Word.WdReplace.wdReplaceAll;
                        objFind.Execute(ref objMissing, ref objMissing, 
                            ref objMissing, ref objMissing, 
                            ref objMissing, ref objMissing, 
                            ref objMissing, ref objMissing, 
                            ref objMissing, ref objMissing, 
                            ref owdReplaceAll, 
                            ref objMissing, ref objMissing, 
                            ref objMissing, ref objMissing);
                        }
                    }

                    // 次の行の列 A に移動します。
                    objRngOld = objRngNew.get_Offset(1, -1);

                    objDoc.Save();
                    lblStatus.Text = "Operation complete.";
                    wdApp.Quit(ref objMissing, ref objMissing, 
                        ref objMissing);
                    xlApp.Quit();
                }
            }

            catch(System.Exception e)
            {
                MessageBox.Show("Error of type " + 
                    e.GetType().ToString() + 
                    "\n" + "in " + e.TargetSite.ToString() + "\n" + 
                    "of " + 
                    e.Source + ":" + "\n" + e.Message);
            }
        }
    }
}

上記のコードの残りの部分は、 Visual Basic.NET セクションまたはこのセクションの前半で説明しました。 C# ソリューションの実行と配布は、以前に Visual Basic .NET ソリューションで説明したのと同じです。

付録

意欲的な Office ソリューション開発者向けに、Visual Studio .NET で COM アドイン ("マネージ アドイン" としても知られています) として Visual Basic .NET 版のマクロを作成する方法を説明します。

Visual Basic .NET を使用したマネージ アドインの作成

今年の前半のコラム「Visual Studio .NET による Office マネージ COM アドインの作成」でマネージ アドインの作成方法を説明しました。 コード全体を順を追って説明するのではなく、 Visual Basic .NET セクションで開発したコードからマネージ COM アドインを作成する方法を示しましょう。

まず、この手法では Office XP PIA を既にインストールしていると想定します。 Office XP PIA のインストール方法については、前半のセクションを参照してください。

次にサンプル ソリューションの StyleChangeAddIn フォルダにある StyleChangeAddIn.sln ファイルを開くか、 ソリューションを独自に作成するために以下の手順を実行できます。

Visual Studio .NET 共有アドイン プロジェクトを作成します。

  1. Visual Studio .NET を起動します。

  2. [ファイル] メニューで [新規作成] をポイントし、[プロジェクト] をクリックします。

  3. [プロジェクトの種類] ペインで、[その他のプロジェクト] フォルダを開き、 [機能拡張プロジェクト] フォルダを開きます。

  4. [テンプレート] ペインで、[共有アドイン] アイコンをクリックします。

  5. [プロジェクト名] ボックスに、「StyleChangeAddIn」と入力します。

  6. 場所] ボックスに、フォルダのパスを入力するか、[参照] をクリックしてフォルダ パスを選択後、 [OK] をクリックします。機能拡張ウィザードが表示されます。

  7. [次へ] をクリックします。[プログラミング言語の選択] ページが表示されます。

  8. [Visual Basic を使用してアドインを作成] をクリックして、[次へ] をクリックします。 [アプリケーション ホストの選択] ページが表示されます。

  9. [Microsoft Word] 以外のチェック ボックスをすべてクリアします。

  10. [次へ] をクリックします。[名前および説明の入力] ページが表示されます。

  11. [アドインの名前] ボックスに「Change Styles」と入力します。

  12. [アドインの説明] ボックスに「Changes Word styles based on information in an Excel style change file」と入力します。

  13. [次へ] をクリックします。[アドイン オプションを選択します。] ページが表示されます。

  14. [ホスト アプリケーションの読み込み時にアドインを読み込む] を選択します。

    **注意   ** [アドインがインストールされているコンピュータのすべてのユーザーがこのアドインを使用できるようにする] を選択すると興味深い影響が出ます。 このオプションを選択すると、Word の [COM アドイン] ダイアログ ボックスにそのアドインが表示されません。 これは、Office アプリケーションが [COM アドイン] ダイアログ ボックスにユーザーごとのアドインだけを表示するためです。 ウィザードでこのオプションを選択すると、 アドインがユーザーごとではなく、コンピュータごとになります。 この問題の詳細については、「PRB: Visual Studio .NET Shared Add-in Is Not Displayed in Office COM Add-ins Dialog Box (Q316723)」 (英語) を参照してください。

  15. [次へ] をクリックします。[概要] ページが表示されます。

  16. [完了] をクリックし、共有アドイン プロジェクトがビルドされるのを待機します。

次に、前半のプロジェクトで説明した手順に従って Word 2002 PIA と Excel 2002 PIA への参照を設定します。 このプロジェクトには Windows フォームを追加しているので、 System.Windows.Forms.dll アセンブリと System.Drawing.dll アセンブリへの参照も設定する必要があります。 これらのアセンブリは、[参照の追加] ダイアログ ボックスの [.NET] タブで見つかります。

続いて、前半のプロジェクトで作成した Windows フォームを追加します。

  1. [ソリューション エクスプローラ] で、[StyleChangeAddIn] プロジェクト ノードを右クリックし、 [追加] をポイントして [既存項目の追加] をクリックします。

  2. 前半のプロジェクトで作成した frmMain.vb ファイルを検索し、クリック後、[OK] をクリックします。

    次に、 ユーザーがアドインを実行するときに frmMain.vb ファイルを表示するために、Connect.vb ファイルのコードをカスタマイズします。 これを行うには、[ソリューション エクスプローラ] で Connect.vb ファイルをダブル クリックし、以下のコードを追加します。

    
    Imports Microsoft.Office.Core
    imports Extensibility
    Imports System.Runtime.InteropServices
    ' *** カスタム コードの開始。 ***
    Imports Microsoft.Office.Core.MsoControlType
    Imports Microsoft.Office.Core.MsoButtonStyle
    
    ' このコード セクションのコードを変更しないでください。
    '+ アドインのインストールとセットアップ情報についてはここをお読みください。
    
    <GuidAttribute("67A4095A-F5EA-4321-BE51-C24BEF97534F"), _
        ProgIdAttribute("StyleChangeAddIn.Connect")> _
    Public Class Connect
    
        Implements Extensibility.IDTExtensibility2
    
        Dim applicationObject As Object
        Dim addInInstance As Object
    
        ' *** カスタム コードの開始。 ***
        Dim WithEvents objCommandBarButton As CommandBarButton
        ' *** カスタム コードの終了。 ***
    
        Public Sub OnBeginShutdown(ByRef custom As System.Array) _
                Implements Extensibility.IDTExtensibility2.OnBeginShutdown
    
            ' *** カスタム コードの開始。 ***
            objCommandBarButton.Delete()
            ' *** カスタム コードの終了。 ***
    
        End Sub
    
        Public Sub OnAddInsUpdate(ByRef custom As System.Array) _
                Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
    
            ' *** カスタム コードの開始。 ***
            ' このメソッドにはコードは必要ありません。
            ' *** カスタム コードの終了。 ***
    
        End Sub
    
        Public Sub OnStartupComplete(ByRef custom As System.Array) _
                Implements _
                Extensibility.IDTExtensibility2.OnStartupComplete
    
            ' *** カスタム コードの開始。 ***
            Dim objCommandBars As CommandBars
            Dim objCommandBar As CommandBar
            Dim objCommandBarControl As CommandBarControl
    
            ' [Format] メニューのメニュー コマンドを作成します。
            objCommandBars = applicationObject.CommandBars
            objCommandBar = objCommandBars.Item("Format")
    
            ' メニュー コマンドが存在しないことを確認します。
            For Each objCommandBarControl In objCommandBar.Controls
    
                If objCommandBarControl.Caption = "Change Styles..." Then
    
                    objCommandBar.Controls.Item _
                        ("Change Styles...").Delete()
    
                End If
    
            Next objCommandBarControl
    
            objCommandBarButton = _
                objCommandBar.Controls.Add(msoControlButton)
    
            With objCommandBarButton
                .Caption = "Change Styles..."
                .Style = msoButtonCaption
                .Tag = "Change Styles..."
                .OnAction = "!<StyleChangeAddIn.Connect>"
                .Visible = True
            End With
            ' *** カスタム コードの終了。 ***
    
        End Sub
    
        Public Sub OnDisconnection _
                (ByVal RemoveMode As Extensibility.ext_DisconnectMode, _
                ByRef custom As System.Array) _
                Implements Extensibility.IDTExtensibility2.OnDisconnection
    
            ' *** カスタム コードの開始。 ***
            On Error Resume Next
    
            ' ホスト アプリケーションがシャットダウン
            ' されなかったとしても、共有アドインを
            ' 切断します。
            If RemoveMode <> _
                    Extensibility.ext_DisconnectMode.ext_dm_HostShutdown Then _
                Call OnBeginShutdown(custom)
    
            applicationObject = Nothing
            ' *** カスタム コードの終了。 ***
    
        End Sub
    
        Public Sub OnConnection(ByVal application As Object, _
                ByVal connectMode As Extensibility.ext_ConnectMode, _
                ByVal addInInst As Object, ByRef custom As System.Array) _
                Implements Extensibility.IDTExtensibility2.OnConnection
    
            applicationObject = application
            addInInstance = addInInst
    
            ' *** カスタム コードの開始。 ***
            ' ホスト アプリケーションが開始されなくても、
            ' 共有アドインを接続します。
            If (connectMode <> _
                    Extensibility.ext_ConnectMode.ext_cm_Startup) Then _
                Call OnStartupComplete(custom)
            ' *** カスタム コードの終了。 ***
    
        End Sub
    
        ' *** カスタム コードの開始。 ***
        Private Sub objCommandBarButton_Click _
                (ByVal Ctrl As CommandBarButton, _
                ByRef CancelDefault As Boolean) _
                Handles objCommandBarButton.Click
    
            ' Windows フォームを表示します。
            Dim frmMain As New frmMain()
            frmMain.Show()
    
        End Sub
        ' *** カスタム コードの終了。 ***
    
    End Class
    

    次に、プロジェクトをテストするときに、Word を起動することを指定します。

  3. [ソリューション エクスプローラ] で、[StyleChangeAddIn] プロジェクト ノードを右クリックし、 [プロパティ] をクリックします。

  4. [構成プロパティ] フォルダを開き、[デバッグ] をクリックし、[外部プログラムの開始] オプションをオンし、 ローカル コンピュータの WINWORD.EXE へのパスを入力後、[OK] をクリックします。

次に、実行しているすべての Microsoft Word のインスタンスを終了後 [デバッグ] メニューの [開始] をクリックして、 ソリューションを実行します。

このソリューションを配置するには、 機能拡張ウィザードが生成した Setup プロジェクトをカスタマイズする必要があります。 また、コンピュータの Office セキュリティ設定を尊重するには、 ソリューションに対して shim と呼ばれるプロキシ コードを作成し、追加する必要があります。 これを行う方法の詳細については、 「Using the COM Add-in Shim Solution to Deploy Managed COM Add-ins in Office XP」 (英語) を参照してください。

Paul Cornell MSDN Online Office Developer Center および Office 開発者向けドキュメント チームに所属しています。 Paul は、Office Assistance Center のコラム「Office Power User Corner」も担当しています。 プライベートは、妻と 2 人の娘と共に過ごしています。