Wordを起動時にエラー(型が定義されていません)

タグの編集
投稿者 Jptaro  (社会人) 投稿日時 2013/5/9 00:34:38
お世話になります。

次の3行のコードで2種類のエラーが発生しています。
なにをチェックすれば、良いでしょうか?
よろしくお願いいたします。

--------------------------------
エラーは:
 ・型Applicationが定義されていません。
 ・型Documentが定義されていません。

環境は:
 ・VB2010
 ・Win7 Pro 32bit
-------------------------------

Dim wdApp As Word.Application
Dim wdDoc As Word.Document
wdApp = CreateObject("Word.Application")

-------------------------------
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2013/5/9 11:28:06
> なにをチェックすれば、良いでしょうか?

次の順序で確認してみてください。

(1)開発環境と実行環境に、同じバージョンの Word がインストールされているか確認する。
→Word がインストールされていない環境では動作しない。

(2)Microsoft Word x.x Object Library が参照されている確認する。
http://homepage1.nifty.com/rucio/main/kiso/Kiso13Reference.htm

(3)As Word.Application を As Microsoft.Office.Interop.Word.Application に変更してみる。
→これで動くようなら、Microsoft.Office.Interop.Word を Imports しておく。
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard44.htm
投稿者 るきお  (社会人) 投稿日時 2013/5/9 12:48:39
参照設定の問題であり、チェックすべき内容は魔界の仮面弁士さんが書いている通りです。

投稿された3行の部分だけ見れば次のように変更して動かすことができる場合もあります。
Dim wdApp As Object
Dim wdDoc As Object
wdApp = CreateObject("Word.Application")
投稿者 Jptaro  (社会人) 投稿日時 2013/5/9 21:09:27
魔界の仮面弁士さん、るきおさん、ありがとうございます。

以下、ご報告いたします。
>(1)Wordは、2010 です。
>(2)Microsoft Word x.x Object Library が参照されている確認する。
参照されていません。
Project→参照の追加で追加しようとしても、Microsoft Word x.x Object Library 
が、リストされません。
>(3)As Word.Application を As Microsoft.Office.Interop.Word.Application に変更
Dim wdApp As Microsoft.Office.Interop.Word.Application 
Dim wdDoc As Microsoft.Office.Interop.Word.Application 
wdApp = CreateObject("Word.Application")
までは、問題なく動いています。
次の
wdDoc = wdApp.Documents.Open("E:\Test.doc")
で、「Test.docは編集のためにロックされています。次のいずれかを選択してください。」
のエラーが発生します。wdDoc = wdApp.Documents.Open("E:\Test.doc")が
間違えているような気がするのですが、どうでしょうか?

>投稿された3行の部分だけ見れば次のように変更して動かすことができる場合もあります。
は、うまくいきませんでした。Microsoft Word x.x Object Library が参照されていないことが
原因のような気がしています。

なお、当初、Word2010は、お試し版(インストール後、10日ぐらい)でした。
参照されないのは、これが原因かな?と推測しいったん、アンインストール後、
再インストールして、認証を行いました。結果は、同じでした。

お手数をおかけいたしますが、引き続きよろしくお願いいたします。


投稿者 魔界の仮面弁士  (社会人) 投稿日時 2013/5/9 22:13:23
> リストされません。
参照設定の画面で、「COM」タブを開いてみてください。そこにもありませんか?

なお、PIA がインストールされている環境であれば、「.NET」タブに
「Microsoft.Office.Interop.Word」が表示される場合もあります。


> なお、当初、Word2010は、お試し版(インストール後、10日ぐらい)でした。
Office 2010 評価版の一部のエディションでは、Click-to-Run (クイック実行) という
テクノロジが採用されているため、うまく参照できないことがあるようです。その場合には
製品版 DVD やダウンロード版インストーラーから Office をインストールしてみてください。


> 「Test.docは編集のためにロックされています。次のいずれかを選択してください。」
同ファイルが既に開かれた状態になっているようですね。

アプリケーションを閉じて、同ファイルをエクスプローラーで移動させてみてください。
移動できないようであれば、ファイルが開かれたままになっていると思いますので、
いったん OS を再起動してから試したほうが良いでしょう。

ファイルを移動できるにもかかわらず、編集ロックのエラーが出るのだとすれば、
どこかで二重に開かれてしまっているのだと思います。
事前に、Word の[ファイル]-[オプション]画面で「セキュリティセンター」を開き、
"信頼できる場所" に E:\ を追加するか、もしくは、"保護されたビュー" の
チェックを Off にしておいた場合、実行結果は変化するでしょうか?
投稿者 Jptaro  (社会人) 投稿日時 2013/5/9 23:44:35
魔界の仮面弁士さん、ありがとうございます。

ご報告します。
>参照設定の画面で、「COM」タブを開いてみてください。そこにもありませんか?
「Microsoft Word 14 Object Library」がありました。 
選択後、[OK]をクリックしましたが、なんの変化もありませんでした。

>なお、PIA がインストールされている環境であれば、「.NET」タブに
>「Microsoft.Office.Interop.Word」が表示される場合もあります。
はい、ありました。
ただしPIA を意図してインストールした記憶はありません。(PIAって?という感じです)

ソリューションエクスプローラの参照設定には
「Microsoft.Office.Interop.Word」だけがあります。

>Office 2010 評価版の一部のエディションでは、Click-to-Run (クイック実行) という
>テクノロジが採用されているため、うまく参照できないことがあるようです。その場合には
>製品版 DVD やダウンロード版インストーラーから Office をインストールしてみてください。
はい、Office Personal 2010 NetDawnLoad評価版をアンインストール後、
製品版 Office Personal 2010 DVD より再インストールし認証手続きも完了させました。

>同ファイルが既に開かれた状態になっているようですね
いろいろな現象が起きています。整理してご報告します。

以上、ご面倒をおかけしますがよろしくお願いします。
投稿者 魔界の仮面弁士  (高校生) 投稿日時 2013/5/10 09:51:55
> ただしPIA を意図してインストールした記憶はありません。
この機能は、Office 2010 では既定のインストールに含まれていますので、
通常は、インストールされた状態になっているはずです。

カスタムインストールを選択されていた場合には、
「.NET プログラミング サポート」の項で追加されるはずです。
あるいは、再頒布可能パッケージからの手動インストールも可能ですが、
今回は手動インストールの必要は無いでしょうね。
http://www.microsoft.com/en-us/download/details.aspx?id=3508


> (PIAって?という感じです)
PIA については、先に紹介した URL 内で触れられています。もう一度載せておきますね。
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard44.htm


> 選択後、[OK]をクリックしましたが、なんの変化もありませんでした。
状況を整理させてください。
変化が無いというのは、最初の質問にあった
>> ・型Applicationが定義されていません。
が動作しない状態になっている、という意味でしょうか?

参照されていれば、ソリューション エクスプローラーで [My Project]を開いたときに、
「参照」タブに表示される一覧に、COM コンポーネントとして以下の 3 つが
追加されると思いますが、この一覧にすら変化が無い状況なのでしょうか。

・Microsoft Office 14.0 Object Library
・Microsoft Visual Basic for Application Extensibility 5.3
・Microsoft Word 14.0 Object Library


もしも一覧が変化しているのであれば、
> (3)As Word.Application を As Microsoft.Office.Interop.Word.Application に変更してみる。
が使えるはずです。

実際のところ、そもそもすでに
>> Dim wdApp As Microsoft.Office.Interop.Word.Application 
>> wdApp = CreateObject("Word.Application")
>> までは、問題なく動いています。
までは完了していたはずなので、参照設定の問題はクリア済みかと思っていました。
参照設定が終わっていなければ、
『型 'Microsoft.Office.Interop.Word.Application' が定義されていません。』
のエラーになってしまっているはずですので…。

ちなみに、最初の回答で述べた
>>> →これで動くようなら、Microsoft.Office.Interop.Word を Imports しておく。
というのは、具体的には最初に使っていたコードの
Public Class Form1
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim wdApp As Word.Application   '←ここでエラーになっていた 
        wdApp = CreateObject("Word.Application")
がコンパイルエラーになるという状態を、参照設定を追加した上でのコード修正で
Public Class Form1
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
         'このように書き換えると、実行できるようになった 
        Dim wdApp As Microsoft.Office.Interop.Word.Application
        wdApp = CreateObject("Word.Application")
として実行可能となったのであれば、それをさらに
'Imports 宣言を追加 
Imports Microsoft.Office.Interop
Imports Word = Microsoft.Office.Interop.Word
Public Class Form1
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim wdApp As Word.Application   'Imports してあるため、元の Word.Application という単純表記でOK 
        wdApp = CreateObject("Word.Application")
と書き換えていく、という話です。

なお、参照設定を施している状況であれば、
wdApp = CreateObject("Word.Application")
ではなく、
'wdApp = New Word.Application() 
wdApp = New Microsoft.Office.Interop.Word.Application()
のように、New を使って生成したほうが望ましいです。

もし、CreateObject で生成する方針をとるのであれば、むしろ参照設定を施す必要すらないので、 先のるきおさんの回答にもあるように、Word 名前空間の型を使わず、Object 型に変更することでも対応可能となります。
ただしObject 型を使う方法の場合、入力ヒント機能(インテリセンス)が使えなくなりますし、オブジェクト解放の処理も複雑化することがありますので、可能な限り、参照設定を用いた方が望ましいです。


> いろいろな現象が起きています。整理してご報告します。
もう一つ確認したいのですが、実行中のコードに『wdApp.Visible = True』という記述はありますか?

プログラムから呼び出された Word は、非表示の状態で起動されますので、
.Visilbe = True の記述が無い場合、画面上の変化は特に生じません。
タスクマネージャの[プロセス]タブには、WINWORD.EXE が表示される程度です。

もし、非表示の Word に E:\Test.doc を開かせていたとしたら、次回実行時には
E:\Test.doc が二重に開かれた状態になってしまい、結果として
>> 「Test.docは編集のためにロックされています。次のいずれかを選択してください。」
という状態になってしまうことも考えられます。
投稿者 Jptaro  (社会人) 投稿日時 2013/5/11 01:45:30
魔界の仮面弁士さん、ご丁寧な説明をいただきありがとうございました。

・結論から申しますと、次のコードで動きました:

Imports Microsoft.Office.Interop
Imports word = Microsoft.Office.Interop.Word
'
Public Class Form9
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            :
            :
    'Word 起動------------------------------------------------------
        Dim wdApp As Microsoft.Office.Interop.Word.Application
        wdApp = CreateObject("Word.Application")
        Dim wdDoc = wdApp.Documents.Open("E:\Test.docx")
        wdApp.Visible = True

ただし、Dim wdApp As Microsoft.Office.Interop.Word.Application を
Dim wdApp As Word.Application とするとエラー「型Word.Application が定義されていません」が
発生します。
> 「Test.docは編集のためにロックされています。次のいずれかを選択してください。」
は、ご指摘の通り wdApp.Visible = True が記述されていないことによるものでした。


・.NET より Office をコントロールするのに PIA が必要:
ということもわかりました。紹介いただいた
>http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard44.htm
は、わかりやすかったです。当初は、どこに記述されているのか?で
魔界の仮面弁士さんの意図が不明でしたが
今回読み直してわかりました。「4.Excelの操作」ですね。
>http://msdn.microsoft.com/ja-jp/library/dd313954.aspx も読んで見ました。

・参照設定の問題:
参照設定
 .NET には
  Microsoft.office.interop.word
    Microsoft.VisualBasic があります。
 .COM には
  Microsoft Office 14.0 objectLibrary
    Microsoft Word 14.0 objectLibrary があります。

ソリューションエクスプローラ→すべてのファイルを表示→参照設定
  Mirosoft.office.core
    Microsoft.office.interop.word があります。

現在上記のように参照設定されていますが、正しいでしょうか?
(次の2つのLibraryが、ソリューションエクスプローラ→すべてのファイルを表示→参照設定
にリストされていないのはOKでしょうか?と思っているのです。)
 Microsoft Office 14.0 objectLibrary
 Microsoft Word 14.0 objectLibrary
.comにリストされている、この2つを選択して[OK]しても、ソリューションエクスプローラ→すべてのファイルを表示→参照設定には変化がありません。

基本的には、解決しました。ありがとうございました。

PS:
魔界の仮面弁士さんの説明方法、指導方法に感激です。
もっとも必要とされる具体的コードだけでなくその解説をいただいていることには、感謝です。
忍耐づよくお付き合いいただき、感謝に感謝です。ありがとうございます。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2013/5/11 23:38:35
> 結論から申しますと、次のコードで動きました:
良かったですね。

ただ、そのコードを見る限り、お使いの Visual Basic 2010 には
Service Pack が適用されていないように見受けられます。
最新の環境に更新するために、Microsoft Update を実行しておいてください。


> ・.NET より Office をコントロールするのに PIA が必要:
PIA (Primary Interop Assembly) が無くても一応動かせますが、
あった方が良いですね。


> 当初は、どこに記述されているのか?で
> 魔界の仮面弁士さんの意図が不明でしたが
> 今回読み直してわかりました。「4.Excelの操作」ですね。

管理人さん宛:
 長文の記事では、該当記事へのリンクを shokyu/standard44.htm#hoge などと
 紹介できるように、h1 タグのところに id 付きの a タグを入れてあると
 便利かと思います。今後作成される記事にてご一考ください。


> ご指摘の通り wdApp.Visible = True が記述されていないことによるものでした。
Word をプログラムから操作した際には、[Ctrl]+[Shift]+[ESC}等で
「タスクマネージャー」を起動して、『プロセス』タブに winword.exe が
残ってしまっていないかを確認しておいた方が良いでしょう。

これは、プログラムの不具合(表示し忘れ、終了操作漏れ、解放処理の不足など)により、
ワードが画面上に表示されていないまま、裏に残り続けてしまうことがあるためです。


> Dim wdApp As Microsoft.Office.Interop.Word.Application
> wdApp = CreateObject("Word.Application")
> Dim wdDoc = wdApp.Documents.Open("E:\Test.docx")
> wdApp.Visible = True

できることならば、Documents も変数に受けておくことが望ましいです。
具体的にはこんな感じ。
'Imports System.Runtime.InteropServices 
Dim wdApp As New Microsoft.Office.Interop.Word.Application()
wdApp.Visible = True
Dim wdDocs = wdApp.Documents    '◀◀◀ Documents オブジェクトを変数に受ける 
Dim wdDoc = wdDocs.Open("E:\Test.docx")
MsgBox("文書を閉じます。", vbInformation Or vbSystemModal)
wdDoc.Close(False)    '文書を閉じる。 
Marshal.ReleaseComObject(wdDoc)    '◁◁◁ 後始末 
Marshal.ReleaseComObject(wdDocs)   '◁◁◁ 後始末 
wdApp.Quit()    'ワードを終了させる。 
Marshal.ReleaseComObject(wdApp)    '◁◁◁ 後始末 
MsgBox("Wordを終了させました。", vbInformation Or vbSystemModal)


System.Runtime.InteropServices 名前空間の Marshal.ReleaseComObject メソッドは、
COM オブジェクトを使い終わった後の、解放処理(≠開放処理)に使われます。
これをさぼると、winword.exe が非表示で裏に残ってしまうなどの
弊害が出ることがあるので注意してください。

ただ、この COM の解放作業というものは、慣れないうちは分かりにくいですし、
比較的面倒な処理です。自動解放の仕組みもあるので、個人利用のコードなら
明示的解放をさぼってしまうのもアリですが、もしも業務利用の開発だとすれば
即時解放しないと都合が悪い場合も多いので、ReleaseComObject についても
追って習得しておくことをお奨めします。


> 現在上記のように参照設定されていますが、正しいでしょうか?
Word 2010 を参照設定して操作する場合、以下の「いずれか」を使ってください。
両方を同時に参照設定しないようご注意を。

(1).NET タブの "Microsoft.Office.Interop.Word" バージョン 14.0
(2) COM タブの "Microsoft Word 14.0 Object Library"


まず (1) ですが、この本体は、Microsoft.Office.Interop.Word.dll です。
既定のインストール先は、
C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.Word\14.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Word.dll
ですが、C:\Windows\assembly\ は特殊なフォルダーなので、
エクスプローラーからだと、上記までのパスを表示することはできません。


一方、(2) の本体は、MSWORD.OLB というファイルです。ただしこれは
型情報を持っているだけのライブラリであり、.NET の DLL ではありません。

実際にはレジストリに記載された型情報をもとにして PIA が参照されるため、
結局は Microsoft.Office.Interop.Word.dll に行きつくことになります。
ついでに Microsoft.Office.Core.dll や Microsoft.Vbe.Interop.dll も
参照設定に加わりますので、この点が (1) との違いですね。


なお、PIA がインストールされていない場合、(1)は一覧に載りません。
(2) を選んだ場合は、代わりに IA が自動生成されることになりますが、
この場合、生成されるファイル名は Interop.Excel.DLL となり、
使用する名前空間も変わってきます。


> 参照設定にリストされていないのはOKでしょうか

ソリューションエクスプローラーのツリーに掲載されているものが
COM の参照設定の画面に現れる項目名と一致しないのは、
参照設定画面に表示されているものが、「コンポーネント名」であるためです。

COM タブに表示される「コンポーネント名」は、レジストリに
記録されている文字列となります。今回の場合で言うと、
HKEY_CLASSES_ROOT\TypeLib\{00020905-0000-0000-C000-000000000046}\8.5
の箇所に相当します。

一方、ツリーに表示されている方は、参照しているファイルの
「アセンブリの短縮名」なので、必ずしも同じ名前とはなりません。
一つのコンポーネントが、複数のファイルへの参照情報を持っていることもありますし。
投稿者 Jptaro  (社会人) 投稿日時 2013/5/12 11:04:30
魔界の仮面弁士 さん、ありがとうございます。

本当にご丁寧な説明、よくわかりました。

>Marshal.ReleaseComObject(wdApp)
追加しまます

>Visual Basic 2010 にはService Pack 
このメールの送信後、実行します

>Word 2010 を参照設定して操作する場合、以下の「いずれか」を使ってください。
>両方を同時に参照設定しないようご注意を。
わかりました。了解です。

解決とさせていただきます。感謝に感謝です。ありがとうございました。
投稿者 Jptaro  (社会人) 投稿日時 2013/5/12 11:07:49
チェックマークをわすれました。

(ありがとうございました)をもう一度、言う機会ができました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2013/5/12 12:22:50
追記 & 修正。

> この場合、生成されるファイル名は Interop.Excel.DLL となり、
> 使用する名前空間も変わってきます。

失礼。「Interop.Excel.DLL」ではなく、今回は「Interop.Word.DLL」ですね。


> なお、PIA がインストールされていない場合、(1)は一覧に載りません。
> (2) を選んだ場合は、代わりに IA が自動生成されることになりますが、

そもそも、「IA(Interop Assemblies)」についても説明していませんでしたね。
日本語訳では「相互運用機能アセンブリ」とも呼ばれる機能で、COM 型の定義を含むアセンブリのことです。
(PIA も IA の一種です)


Microsoft Office は COM コンポーネントの集合体です。
.NET と COM では仕組みが違うため、その中継役となるものが必要です。

この中継役となるのは、以下の仕組みです。
・.NET が COM を呼び出すための ランタイム呼び出し可能ラッパー(RCW)
・COM が .NET を呼び出すための COM 呼び出し可能ラッパー(CCW)

これにより、VB.NET のアプリから Office を操作することができ、
あるいは Office から VB.NET 製の DLL を呼び出すことができます。
今回使うのは RCW : ランタイム呼び出し可能ラッパー (Runtime Callable Wrapper) の方ですね。


.NET アプリが COM オブジェクトをアクティブにすると、ランタイムは、RCW のインスタンスを生成してその COM 型をラップします。
RCW は、COM のコクラスをラップする .NET Framework クラスの型であり、それらの型情報を持つものが相互運用機能アセンブリ(IA)です。
図中の「相互運用機能アセンブリ」が、参照設定のツリーに並んだ Microsoft.office.interop.Word のファイルに相当します。

VBから呼びだされると、ラップされた RCW を通じて COM 型への変換が行われます。



Visual Studio から COM コンポーネントを参照設定した場合、実際に参照されるのがこれら IA です。
相互運用機能アセンブリ(IA)は、参照設定時に自動生成されますが、TlbImp.exe を使って作成することもできます。

それらの IA のうち、特に、製造元から「公式」に発行された IA が、PIA(プライマリ IA) と呼ばれるアセンブリです。
Microsoft.Office.Interop.Word.dll も PIA です。
自動生成された IA とは異なり、PIA は発行者によるテストを受けた上でデジタル署名されたライブラリなので、互換性・安全性の面で優れています。
http://msdn.microsoft.com/ja-jp/library/cc375821.aspx


PIA は通常、GAC(グローバル アセンブリ キャッシュ)と呼ばれる場所で管理されています。また、システムに PIA が既にインストール済みであった場合、Visual Studio から参照設定で COM コンポーネントを指定したときに、インストール済みの PIA (またはそのコピー)が参照されます。
"Microsoft Word 14.0 Object Library" である MSWORD.OLB を参照設定した場合、PIA が導入されていれば Microsoft.Office.Interop.Word.dll が使われ、それが無い場合には、Interop.Word.DLL という IA が生成されます。
投稿者 Jptaro  (社会人) 投稿日時 2013/5/19 12:15:25
魔界の仮面弁士さん

5月12日に拝見していましたが
あらためて、解決チェックマークをつけました。

本当にありがとうございます。