DOBON.NET DOBON.NETプログラミング掲示板過去ログ

開いたWordファイルを保存しようとするとエラー

環境/言語:[VB2008 Windows XP Vista]
分類:[.NET]

お世話に成ります。
WordファイルをHTML形式に保存するようなツールをVB2008で作成しました。
しかし、あるWordファイルを保存しようとすると、以下のような例外
(System.Runtime.InteropServices.COMException)が発生してしまいます。

HRESULT からの例外: 0x800ADF21
場所 System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
場所 System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
場所 Microsoft.VisualBasic.CompilerServices.VBBinder.InvokeMember(String name, BindingFlags invokeAttr, Type objType, IReflect objIReflect, Object target, Object[] args, String[] namedParameters)
場所 Microsoft.VisualBasic.CompilerServices.LateBinding.InternalLateCall(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack, Boolean IgnoreReturn)
場所 Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCall(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, Boolean IgnoreReturn)
場所 (作成ツールの該当メソッド)

ちなみに、この処理を行っている箇所のコードは以下の通りです。
(処理の後に各変数のReleaseComObjectを行っていますが、これは省略します。)

Const wdFormatHTML As Integer = 8
Dim oWord As Object = Nothing
Dim oWordDoc As Object = Nothing

oWord = CreateObject("Word.Application")
oWord.Documents.Open((Wordファイルのパス))
oWordDoc = oWord.ActiveDocument

oWordDoc.SaveAs(FileName:=(保存するHTMLファイルのパス), FileFormat:=wdFormatHTML) 'ここで例外発生

なお、ファイルの保存形式をHTMLではなく、テキストにしても同様の例外となり、
また、上書き保存でも同様の例外となってしまいます。

ちなみに、この例外発生後、oWordDoc(ワード文書オブジェクト)を閉じようとすると、
今度はHRESULT からの例外: 0x800A8029という例外になります。

関係あるかどうか分かりませんが、このWord文書は、ブラウザ(IE)上に表示されていた内容を
コピー&ペーストで新規Word上に貼り付けて作成したものだということです。
このため、Webページ上のリンクがそのまま残っており、あと、なぜかこのファイルを
Word(2007)で開くと、マクロを登録したわけではないのですが、
「セキュリティの警告 マクロが無効にされました」
と表示されます。

このエラーを回避するにはどうすればいいか、お知恵をお貸しください。
なお、このエラーを確認したWordのバージョンはWord2003・2007です。
宜しくお願い申し上げます。
■No29921に返信(チーマージャンさんの記事)
> oWord.Documents.Open((Wordファイルのパス))
Documents オブジェクトも変数に受けておきましょう。


> oWordDoc = oWord.ActiveDocument
ActiveDocument プロパティを使うのではなく、
.Open メソッドの戻り値を受けるようにしましょう。


> COMException
手持ちの Word 4 製品のタイプライブラリを調べてみたところ、
バージョンによって、SaveAs のメソッド定義が異なっていました。
(残念ながら、手元に Word2003/2007 はありませんでした…)

Word98 (8.0c):
 "SaveAs"     : DispId = &H00000066 で 可視 な 引数11個 の Sub

Word2002 (10.0):
 "SaveAs2000" : DispId = &H00000066 で非表示な 引数11個 の Sub
 "SaveAs"     : DispId = &H00000178 で 可視 な 引数16個 の Sub

Word2007 (12.0) x64:
 "SaveAs2000" : DispId = &H00000066 で非表示な 引数11個 の Sub
 "SaveAs"     : DispId = &H00000178 で 可視 な 引数16個 の Sub

Word2010版 (14.0) x86:
 "SaveAs2000" : DispId = &H00000066 で非表示な 引数11個 の Sub
 "SaveAs"     : DispId = &H00000178 で非表示な 引数16個 の Sub
 "SaveAs2"    : DispId = &H00000238 で 可視 な 引数17個 の Sub

このため、使用している相互運用機能アセンブリによっては、
うまく呼び出せないという事が起きるのかも知れません。
(ちなみに Open メソッドにも、同様の引数違いバージョンが存在します)

CreateObject せず、相互運用機能アセンブリを参照設定して、
呼び出した方が安全かとおもいます。ついでに、実行環境の Word バージョンと
開発環境の Word バージョンも一致させておきましょう。


> 関係あるかどうか分かりませんが、このWord文書は、ブラウザ(IE)上に表示されていた内容を
> コピー&ペーストで新規Word上に貼り付けて作成したものだということです。
では既存の文書を開くのではなく、Documents.Add で新規文書を作って
それを保存しようとした場合はどうなりますか?
■No29922に返信(魔界の仮面弁士さんの記事)
>>oWord.Documents.Open((Wordファイルのパス))
> Documents オブジェクトも変数に受けておきましょう。

ご指摘ありがとうございました。
COMの解放を見逃すところでした。

>>oWordDoc = oWord.ActiveDocument
> ActiveDocument プロパティを使うのではなく、
> .Open メソッドの戻り値を受けるようにしましょう。

VBAでは、戻り値を意識することがなかったので、Openメソッドに戻り値があることを知りませんでした。
勉強になります。

> では既存の文書を開くのではなく、Documents.Add で新規文書を作って
> それを保存しようとした場合はどうなりますか?

Documents.Addで保存した場合は、うまく保存できました。
これをヒントに、試しに新規文書に対象のWordファイルを追加するようにしてみたら、うまくいきました。
以下がそのソースです。

Const wdFormatHTML As Integer = 8
Dim oWord As Object = Nothing
Dim oWordDocs As Object = Nothing
Dim oWordDoc As Object = Nothing

oWord = CreateObject("Word.Application")
oWordDocs = oWord.Documents
oWordDoc = oWordDocs.Add
oSel = oWord.Selection
oSel.InsertFile((Wordファイルのパス))
oWordDoc.SaveAs(FileName:=(保存するHTMLファイルのパス), FileFormat:=wdFormatHTML) '例外発生せず(ワーイ!)

なぜ、該当のファイルがエラーとなるのかは未だ不明ですが、他のWordファイルでも
試した結果、この方法で問題はなさそうです。
魔界の仮面弁士様、本当にありがとうございました。

なお、遅延バインディングを使うのは、複数のWordのバージョンに対応するためで、
一応、インストールされているWordのバージョンをWord.ApplicationのVersionより読み取り、
指定したバージョンである場合のみ、この機能を利用出来るようにしています。
解決済み!
■No29924に返信(チーマージャンさんの記事)
> VBAでは、戻り値を意識することがなかったので、Openメソッドに戻り値があることを知りませんでした。

Office 製品それぞれのバージョンのタイプライブラリを比較してみると、
Sub だったメソッドが、バージョンが上がって Function になった例もあります。

戻り値が COM オブジェクトだった場合、それももちろん解放対象となりますので
ご注意ください。
(Selection のように、戻り値の型が状況依存で変わる場合もありますので、
IsComObject 判定もあった方が良いでしょう)


> 該当のファイルがエラーとなるのかは未だ不明ですが
エラーの理由は分かりませんが、「マクロが無効にされました」と出ると
いうことは、意図せず、何らかのマクロが入り込んでしまった状態に
あるようですね。
新規ブックの場合はそれが無いので、エラーが解消したのかな…?


> 遅延バインディングを使うのは、複数のWordのバージョンに対応するためで、
遅延バインディングを用いた場合、参照カウントがさらに増加するケースも
ありますのでご注意ください。
(COM オブジェクトを引数に渡すメンバーを呼び出した場合など)
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板