VB.NET×Word InteropのInvalidCastException完全解決ガイド|Office 32/64bit不一致・Embed Interop Types対策【Visual Studio 2022】

VB.NET 4.8(Visual Studio 2022)のフォームアプリで Word Interop を使っていたのに、突然 System.InvalidCastException が出て Word が起動しなくなる――この症状は、Office の更新や参照設定の微妙なズレで起こりがちです。本稿ではエラーの正体と、最短で復旧するための具体的な手順、再発を予防する設定までを「コピペで使えるコード」付きで解説します。現場で役立つチェックリストや検証ポイントも網羅しました。

目次

症状

以下のようなコードを実行すると例外が発生し、過去に動いていた全てのプログラムでも Word が起動しなくなる。

Imports Word = Microsoft.Office.Interop.Word

' WinForms(.NET Framework 4.8)
Dim WordApp As New Word.Application 

表示されるメッセージの代表例:

Unable to cast COM object of type 'Microsoft.Office.Interop.Word.ApplicationClass'
to interface type 'Microsoft.Office.Interop.Word._Application'

原因の本質(なぜ起きるのか)

この例外は、COM から取得した Word アプリケーションの RCW(Runtime Callable Wrapper)の中身と、あなたのアプリが参照する型(PIA / 埋め込みインターフェイス)が一致しないときに発生します。代表的な引き金は次のとおりです。

  • ビット数の不一致:Office が 32bit、アプリが x64(またはその逆)。「Any CPU + Prefer 32-bit」設定の影響で、意図せずビット数がずれるケースもあります。原則として Office とプロセスのビット数は合わせるのが安全です。
  • Embed Interop Types(No‑PIA)問題:参照の Embed Interop Types=True のままだと、アセンブリに埋め込まれた独自のインターフェイス定義と、実機にインストールされている PIA の型がズレてキャストに失敗することがあります。
  • PIA / 参照の混在:NuGet の Microsoft.Office.Interop.Word と「COM 参照(Word 16.0 Object Library など)」を同時に参照していた、古い DLL が GAC に残っていた、など。
  • Office の COM 登録破損:Click‑to‑Run の更新や修復途中で COM 登録が乱れた場合。
  • 呼び出し順・UI 状態の不整合:起動直後に ActiveDocument にアクセスするなど、タイミングがシビアな箇所。
  • スレッドのアパートメント:Word は基本 STA を前提(WinForms は既定で STA)。コンソールやバックグラウンドスレッドで MTA のまま扱うと不安定化要因になります。

最短復旧のゴールイメージ

  • Office とアプリのビット数を一致(32bit ↔ 64bit)
  • 参照の Embed Interop Types=False に変更(PIA を使用)
  • COM 登録破損が疑わしければ Office を修復
  • 参照をクリーン追加し直し、bin/obj を削除後にクリーンビルド
  • ドキュメントのオープンと Activate の順序を見直す

解決手順(まとめ表)

手順内容補足・ポイント
1. Office とアプリのビット数を一致Word を開き ファイル → アカウント → Word のバージョン で 32bit / 64bit を確認。
Visual Studio → プロジェクトのプロパティ → ビルド → プラットフォーム対象 を Word と同じ(x86 か x64)に設定。
「Any CPU」は避ける。「Prefer 32-bit」のチェックにも注意。
2. 参照設定を見直すソリューションエクスプローラーで Microsoft.Office.Interop.Word を選択し、
Embed Interop Types = False に変更。
埋め込み型ではなく、インストール済み PIA を使用し COM と型を一致させる。
3. Office の修復コントロール パネル → プログラム → Microsoft Office → 変更 → クイック修復(改善しなければオンライン修復)。更新や Click‑to‑Run で COM 登録が壊れた場合に有効。
補助的に winword /regserver で再登録も可。
4. 参照をクリーンに再追加既存の Microsoft.Office.Interop.Word 参照を削除し、NuGet か COM 参照のどちらか一方で再追加。古い DLL が GAC に残っている影響を排除。
NuGet と COM 参照の併用は避ける。
5. コードの微調整Documents.Open の直後に ActiveDocument.Activate。UI を確認できる環境では WordApp.Visible = True を先に。起動直後の ActiveDocument 参照は避ける。安定度が上がる。

実施結果(実例)
・Office 32bit → 64bit に入れ替え、プロジェクトを x64 に変更して正常動作を確認。
・Documents.Open の後に WordApp.ActiveDocument.Activate() を移動したら安定した。

チェックポイント(詳細手順とコツ)

ビット数(x86 / x64)の合わせ方

  • Word 側:ファイル → アカウント → Word のバージョンで 32bit / 64bit を確認。
  • アプリ側:プロジェクトのプロパティ → ビルド → プラットフォーム対象 を x86 または x64 へ固定。
    「Any CPU」のままにすると、PC 環境次第でプロセスのビット数が変わりトラブルの温床になります。
  • 「Prefer 32-bit」をオフにするか、明示的に x64 を選ぶ(Office 64bit の場合)。

参照の「Embed Interop Types」を False にする理由

No‑PIA(参照の埋め込み)を使うと、プロジェクト毎にインターフェイス定義が「別物」になり、COM 側の型と齟齬が発生することがあります。Embed Interop Types=False にすると、実機の PIA(Primary Interop Assembly)をそのまま使うため、ApplicationClass ↔ _Application のキャスト不整合を回避できます。

NuGet と COM 参照の選び方

  • どちらか一方に統一(併用は不可)。
  • NuGet を使う場合は、Embed Interop Types=False にし、Specific Version=False を推奨。
  • COM 参照を使う場合は「Microsoft Word XX.X Object Library」を選択。プロジェクト構成と Office ビット数を一致させる。

Office 修復と COM 再登録

  • まずは「クイック修復」。改善しなければ「オンライン修復」。
  • 補助策として、管理者コマンドで winword /regserver を実行し COM 登録を再構成。
  • 修復後は PC 再起動 → bin/obj フォルダ削除 → クリーンビルドが確実。

安定動作のためのサンプルコード(VB.NET)

呼び出し順と解放手順を整理した、現場向けのテンプレートです。

Option Strict On
Imports Word = Microsoft.Office.Interop.Word
Imports System.Runtime.InteropServices

Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim app As Word.Application = Nothing
Dim doc As Word.Document = Nothing


    Try
        ' 既存インスタンスがあれば捕まえる(不要なら New でOK)
        ' app = CType(GetObject(, "Word.Application"), Word.Application)

        If app Is Nothing Then
            app = New Word.Application()
        End If

        ' デバッグ時は可視化すると状況が掴みやすい
        app.Visible = True

        ' 起動直後の ActiveDocument 参照は避け、まず Open
        Dim path As String = "C:\Temp\sample.docx"
        doc = app.Documents.Open(FileName:=path, ReadOnly:=False, AddToRecentFiles:=False)

        ' 次に Activate(順序が大事)
        doc.Activate()

        ' 以降で操作(例:文字列置換)
        app.Selection.Find.ClearFormatting()
        app.Selection.Find.Text = "FOO"
        app.Selection.Find.Replacement.ClearFormatting()
        app.Selection.Find.Replacement.Text = "BAR"
        app.Selection.Find.Execute(Replace:=Word.WdReplace.wdReplaceAll)

        ' 保存するなら Save()
        ' doc.Save()

    Catch ex As InvalidCastException
        MessageBox.Show("Interop の型不整合が疑われます。ビット数・参照・Embed Interop Types を確認してください。" & Environment.NewLine & ex.Message)
    Catch ex As COMException
        MessageBox.Show("COM 例外: " & ex.Message)
    Catch ex As Exception
        MessageBox.Show("一般例外: " & ex.Message)
    Finally
        ' 必要に応じて保存/クローズ
        If doc IsNot Nothing Then
            Try
                doc.Close(SaveChanges:=False)
            Finally
                Marshal.FinalReleaseComObject(doc)
                doc = Nothing
            End Try
        End If

        If app IsNot Nothing Then
            Try
                app.Quit(SaveChanges:=False)
            Finally
                Marshal.FinalReleaseComObject(app)
                app = Nothing
            End Try
        End If

        ' 通常は GC.Collect は不要。リーク調査時のみ検討
        ' GC.Collect()
        ' GC.WaitForPendingFinalizers()
    End Try
End Sub


End Class 

既存 Word プロセスへのアタッチが必要な場合

検証時や複数起動を避けたい場合は GetObject を併用すると安定します。

Dim app As Word.Application = Nothing
Try
    app = CType(GetObject(, "Word.Application"), Word.Application)
Catch
    app = New Word.Application()
End Try
app.Visible = True

C# 派生コード(参考)

using Word = Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;

void Run()
{
Word.Application app = null;
Word.Document doc = null;


try
{
    app = new Word.Application();
    app.Visible = true;

    doc = app.Documents.Open(@"C:\Temp\sample.docx", ReadOnly: false, AddToRecentFiles: false);
    doc.Activate();

    app.Selection.Find.ClearFormatting();
    app.Selection.Find.Text = "FOO";
    app.Selection.Find.Replacement.ClearFormatting();
    app.Selection.Find.Replacement.Text = "BAR";
    app.Selection.Find.Execute(Replace: Word.WdReplace.wdReplaceAll);
}
catch (InvalidCastException ex)
{
    System.Windows.Forms.MessageBox.Show("Interop 型不整合の可能性: " + ex.Message);
}
finally
{
    if (doc != null)
    {
        try { doc.Close(false); }
        finally { Marshal.FinalReleaseComObject(doc); doc = null; }
    }
    if (app != null)
    {
        try { app.Quit(false); }
        finally { Marshal.FinalReleaseComObject(app); app = null; }
    }
}


} 

検証のための「動作チェックリスト」

  • アプリのビット数(Environment.Is64BitProcess)と Office のビット数が一致しているか。
  • 参照プロパティ:Embed Interop Types=False・Specific Version=False。
  • NuGet と COM 参照の併用なし。
  • ActiveDocument を触る前に Documents.Open を呼んでいるか。
  • STA スレッドで実行しているか(WinForms は既定で OK)。
  • Office の「クイック修復」後に再起動したか。
  • bin/obj を削除してクリーンビルドしたか。

よくある落とし穴と回避策

  • Any CPU 問題:開発機では動くのにリリース機で落ちる――多くは Any CPU(Prefer 32-bit)による暗黙の 32bit 実行が原因。明示的に x86 / x64 に固定。
  • ActiveDocument 直叩き:起動直後は ActiveDocument が未定義。必ず Documents.Open → Activate の順。
  • 複数バージョン混在:Office のアップグレード後に古い Interop DLL が残りやすい。参照を削除 → 追加し直し → クリーンビルド。
  • Add-in 影響:Word のアドインが初期化に失敗して巻き添えで落ちることあり。再現テスト時は winword /safe でアドイン無効化も有効。

トラブル時の診断テクニック

  • 例外の種類で切り分け:今回の InvalidCastException は型不整合が主因。COMException(HRESULT)なら登録や権限、ファイルパスを疑う。
  • イベントログ:アプリケーションログに COM まわりの警告が出ることがある。
  • 簡易ログ:起動~Open~Activate の各ステップにタイムスタンプ付きログを書いてボトルネックを可視化。

サーバー用途での Office 自動化は非推奨

バックグラウンドサービスやサーバー側バッチでの Office 自動化はサポート対象外です。大量ドキュメント生成やノン UI 環境では、Open XML SDK・Office Scripts・Microsoft Graph 等の代替を検討してください。Word Interop は「デスクトップ・対話型」前提で割り切るのが安全です。

再発防止のベストプラクティス

  • プロジェクトの プラットフォーム対象を固定(x86 or x64)。
  • 参照は Embed Interop Types=False に統一。
  • NuGet か COM 参照のどちらかに一本化。
  • リリース前に クリーンビルド+bin/obj 削除 を定例化。
  • Office 更新後は 最小再現コードでヘルスチェック。

テンプレ:最小再現コード(VB.NET)

Imports Word = Microsoft.Office.Interop.Word
Imports System.Runtime.InteropServices

Module Module1
 Sub Main()
Dim app As Word.Application = Nothing
Dim doc As Word.Document = Nothing
Try
app = New Word.Application()
app.Visible = True
doc = app.Documents.Add()
doc.Activate()
app.Selection.TypeText("Hello Word Interop!")
Finally
If doc IsNot Nothing Then
Try : doc.Close(False) : Finally : Marshal.FinalReleaseComObject(doc) : End Try
End If
If app IsNot Nothing Then
Try : app.Quit(False)  : Finally : Marshal.FinalReleaseComObject(app) : End Try
End If
End Try
End Sub
End Module 

ケーススタディ(今回の結論)

  • Office を 64bit に入れ替え、プロジェクトのプラットフォーム対象を x64 に変更 → 正常起動。
  • Documents.Open の直後に ActiveDocument.Activate() を移動 → 操作が安定。

付録:設定の確認ポイント一覧

項目推奨値確認場所
プラットフォーム対象x86 または x64(Office と一致)プロジェクトのプロパティ → ビルド
Prefer 32-bitOffice 64bit の場合はオフプロジェクトのプロパティ → ビルド
Embed Interop TypesFalse参照(Microsoft.Office.Interop.Word)のプロパティ
参照の統一NuGet or COM 参照のいずれか片方のみソリューションエクスプローラー
スレッドモデルSTA(WinForms は既定で OK)エントリポイント属性 / スレッド生成箇所

まとめ

ApplicationClass ↔ _Application のキャスト不整合が原因の InvalidCastException は、ビット数の一致・Embed Interop Types=False・参照の再構成・Office 修復の 4 点で高確率に解消します。加えて、Documents.Open → Activate の順序や STA 前提の実行、クリーンビルドの徹底を行えば、再発リスクを大きく抑えられます。上記テンプレコードとチェックリストをチーム標準として取り入れ、Office 更新後のヘルスチェックを自動化しておくと、現場のダウンタイムを最小化できます。

補足(サーバー利用の注意)

Word Interop は対話型クライアント用途が前提です。非対話・サービス常駐環境では Open XML SDK やクラウド API を第一選択とし、Interop は「デスクトップ限定・小規模」の場面に留める設計方針をおすすめします。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次