Book.SaveAs部分で !COMException はハンドルされませんでした

タグの編集
投稿者 yamaV1.02β  (社会人) 投稿日時 2009/5/8 04:44:47
お世話になります。
初級講座「第44回 周辺にあるテクノロジ」4.Excelの操作 のコードの途中でエラーになります。
http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=242

Microsoft Excel 11.0 Object Libraryに参照設定して、コードを実行すると、

'▼後処理
Book.SaveAs("C:\VB\Test.xls") '保存

の部分で、

!COMException はハンドルされませんでした。
サーバーによって例外が返されました。 HRESULT からの例外:0x80010105 (RPC_E_SERVERFAULT)
                                   
トラブルシューティングのヒント:
例外のErrorCode プロパティを調べて,COM オブジェクトによって返された HRESULT を判断します。
この例外に関する一般的なヘルプを参照します。


エラーが発生しているのは、Book.SaveAs("C:\VB\Test.xls")の箇所のみです。保存先のフォルダは存在しています。保存先を変更してみたてもこのエラーは発生し続けます。
Book.SaveAs("C:\VB\Test.xls")部分をコメントアウトすると、「'Book1'への変更を保存しますか?」とダイアログが表示され、保存したファイルを見るとコートの他の部分の動作は問題なく実行されているようです。

ヘルプを辿ってみましたが、理解がおよばず、先に進めません。

試しに、レイトバインディングにしてみたところ、問題なく動作しました。
        'Dim Excel As New Microsoft.Office.Interop.Excel.Application
        'Dim Book As Microsoft.Office.Interop.Excel.Workbook
        'Dim Sheet As Microsoft.Office.Interop.Excel.Worksheet
         ↓
        Dim Excel As Object
        Dim Book As Object
        Dim Sheet As Object
        Excel = CreateObject("Excel.Application")

また、参照を Microsoft Excel 9.0 Object Library に変更してみたところ、
        Dim Excel As New Microsoft.Office.Interop.Excel.Application
        Dim Book As Microsoft.Office.Interop.Excel.Workbook
        Dim Sheet As Microsoft.Office.Interop.Excel.Worksheet

↑の3行がエラーになったので、
        Dim Excel As New Excel.Application
        Dim Book As Excel.Workbook
        Dim Sheet As Excel.Worksheet

に変更しまして、問題なく最後まで動作しました。

このエラーでは何が起きているのでしょうか。
どんなものでしょう。
投稿者 neptune  (社会人) 投稿日時 2009/5/8 07:40:40
私の書いたソースですかね?

今確認してもあのソース自体は問題なく動作してますが。。。
私の環境には
Microsoft Excel 11.0 Object Library
が入ってないものでこれも確認できません。

取りあえず、パスが存在しなければエラーになりますが、この点は問題ないそうですし。

当方、VB2008EEエディションですが、
Microsoft.Office.Interop.Excel 名前空間は
Visual Studio Tools for Office
のサポートですし、申し訳ないが、確認できません。

悪しからず。
投稿者 yamaV1.02β  (社会人) 投稿日時 2009/5/8 09:18:44
neptune さん返信ありがとうございます。

>私の書いたソースですかね?

neptuneさん=サイト作成者 でありましたか。
御大じきじきのご回答ありがとうございます。

ソースはコピペして検証いたしました。


当方、VB2008EEエディションですが、
Microsoft.Office.Interop.Excel 名前空間は
Visual Studio Tools for Office
のサポートですし、申し訳ないが、確認できません。

悪しからず。


御意
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/5/8 11:06:43
>初級講座「第44回 周辺にあるテクノロジ」4.Excelの操作 のコードの途中でエラーになります。
の執筆は rucio(るきお)さんで、
>http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=242
にあるのが、neptune さんの投稿ですね。


> このエラーでは何が起きているのでしょうか。
個人的には、相互運用機能アセンブリと、実際のタイプライブラリバージョンの
不一致では無いかな、と予想しています。

幾つか確認。

まず、エラーが発生するのは、開発環境ですか? 実行環境ですか?
(開発時にエラーが発生しているのか、それとも作成したEXEを配布した先でエラーになるのか)

それから、複数のバージョンの Excel を同一環境にインストールしていませんか?
(あるいは、開発環境のExcelバージョンと、実行環境のExcelバージョンが一致していないとか)
投稿者 yamaV1.02β  (社会人) 投稿日時 2009/5/8 19:39:47
魔界の仮面弁士さん、回答ありがとうございます。

>初級講座「第44回 周辺にあるテクノロジ」4.Excelの操作 のコードの途中でエラーになります。
の執筆は rucio(るきお)さんで、
>http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=242
にあるのが、neptune さんの投稿ですね。


サイト作成者=rucioさんでありましたか。
勘違いいたしました。ご指摘ありがとうございます。

>まず、エラーが発生するのは、開発環境ですか? 実行環境ですか?

44回までの学習では{開発環境|実行環境}について理解が及んでいるか心もとないのですが、ソリューションエクスプローラを右クリックした「発行(B)...」を実行してできる \bin\Releaceフォルダ内の.exeファイルを実行環境。VB_2008_Expressを立ち上げて操作する環境を開発環境として検証しました。

結果は同様のエラーが発生しました。


それから、複数のバージョンの Excel を同一環境にインストールしていませんか?
(あるいは、開発環境のExcelバージョンと、実行環境のExcelバージョンが一致していないとか)

!!!ご明察のとおりxl2000 と xl2003をインストールした環境で作業しています。

以下のコードで作成されるブックのバージョンを確認したところxl2000でした。

        Dim Excel As New Microsoft.Office.Interop.Excel.Application
        Dim Book As Microsoft.Office.Interop.Excel.Workbook
        Dim Sheet As Microsoft.Office.Interop.Excel.Worksheet

        '▼前処理
        Book = Excel.Workbooks.Add '新規ワークブックを作成
        Excel.Visible = True
        Stop
        Debug.Print(Excel.Version)
        Sheet = Book.Worksheets(1) '最初のワークシートを選択
    ・・・

>それから、複数のバージョンの Excel を同一環境にインストールしていませんか?

このご指摘が当たっているようです。

さて、


さて、


しばらく考えましたが、原因はわかったものの、
        Dim Excel As New Microsoft.Office.Interop.Excel.Application
の部分で xl2003 が作成されるようにする方法がわかりません。

「複数のバージョンの Excel を同一環境にインストール」をやめるべきでしょうか。

どんなものなのでしょう。




投稿者 (削除されました)  () 投稿日時 2009/5/8 22:29:00
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/5/8 22:36:33
> 44回までの学習では{開発環境|実行環境}について理解が及んでいるか心もとないのですが
たとえば、作成した EXE を他の人に使ってもらう場合、その人の使う環境と、
yamaV1.02β さんの開発環境とでは、OS あるいはインストールされているソフト等が
異なりますよね(Excelのバージョン等)。

この場合、開発環境とは「yamaV1.02β さんの環境」を指し、
実行環境とは「EXE を実際に起動させる環境」を指しています。

もし、開発した PC のみで実行させるのであれば、開発環境=実行環境 という事になります。


> Dim Excel As New Microsoft.Office.Interop.Excel.Application
> の部分で xl2003 が作成されるようにする方法がわかりません。
一つの環境に複数の Excel バージョンがインストールされていた場合、
それぞれのバージョンを切り替えて呼び出す事はできません。レジストリ登録の都合上、
どうしても後からインストールした方のライブラリの影響力が強くなってしまうためです。

混在環境におけるバージョン指定呼び出しがどうしても必要であれば、Excel をフルパス指定で
起動した上で、そのインスタンスをそれを GetObject 等を通じて取得するという手法がありますが、
基本的にはバージョン混在を避けるべきでしょう。


以下、少し専門的な話になります。


> Microsoft Excel 11.0 Object Libraryに参照設定して
これは、Excel 2003 のライブラリを参照する事になります。
(00020813-0000-0000-C000-000000000046 ; version 1.5)

> 参照を Microsoft Excel 9.0 Object Library に変更してみたところ
こちらは、Excel 2000 のライブラリですね。
(00020813-0000-0000-C000-000000000046 ; version 1.3)

で、ここからが本題。

> Book.SaveAs("C:\VB\Test.xls")
Workbook.SaveAs メソッドの定義は、2003 と 2000 とでは異なります。

Workbook.SaveAs は、Excel のバージョンによって、以下の3種のメソッド定義が存在します。
引数の数、DispId、メソッド名の違いに着目してみてください。
'★ SaveAs メソッド[1]     '★ SaveAs メソッド[2]       '★ SaveAs メソッド[3] 
<DispId(&H11C)> _           <DispId(&H785)> _           <DispId(&H11C), EditorBrowsable(Never)> _
Sub SaveAs(                 Sub SaveAs(                 Sub _SaveAs(
   Filename,                   Filename,                   Filename,
   FileFormat,                 FileFormat,                 FileFormat,
   Password,                   Password,                   Password,
   WriteResPassword,           WriteResPassword,           WriteResPassword,
   ReadOnlyRecommended,        ReadOnlyRecommended,        ReadOnlyRecommended,
   CreateBackup,               CreateBackup,               CreateBackup,
   AccessMode,                 AccessMode,                 AccessMode,
   ConflictResolution,         ConflictResolution,         ConflictResolution,
   AddToMru,                   AddToMru,                   AddToMru,
   TextCodepage,               TextCodepage,               TextCodepage,
   TextVisualLayout)           TextVisualLayout,           TextVisualLayout)
                               Local)

Excel 97, 2000 が持っているのは、[1] のみです。
Excel 2002, 2003, 2007 が持っているのは、[2] と [3] です。


そのため、たとえば Excel 2003 のライブラリを参照設定して、
> Book.SaveAs("C:\VB\Test.xls")
というコードを書き、それを Excel 2000 環境で実行した場合、
メソッドの定義が異なるため、呼び出しが失敗する事になります。

なお、2003 ライブラリで [3] を呼び出すコードや、
2000 ライブラリで [1] を呼びだすコードを書いた場合は、
 Excel 2000以下の環境 …… [1] のメソッドが呼び出される。
 Excel 2002以上の環境 …… [3] のメソッドが呼び出される。
となり、そのまま動作する可能性があります。


一方、レイトバインド(あるいは CallByName で呼び出した場合)に成功した件についてです。

まず、SaveAs メソッドは、引数がすべて省略可能(Optional)になっています。
レイトバインドでは、実行時にメソッド名からの名前解決が行われますので、
> Book.SaveAs("C:\VB\Test.xls")
というコードを呼び出した場合、
 Excel 2000以下の環境 …… [1] のメソッドが呼び出される。
 Excel 2002以上の環境 …… [2] のメソッドが呼び出される。
という呼び分けが行われる事になります。

なお、レイトバインドでの呼び出しを行うために、必ずしもすべてを
> Dim Excel As Object
> Excel = CreateObject("Excel.Application")
のように Object で記述する必要はありません。

必要な部分のみをレイトバインドすれば良いのであれば、たとえば
 CObj(Book).SaveAs("C:\VB\Test.xls")
あるいは
 Dim oBook As Object = Book
 oBook.SaveAs("C:\VB\Test.xls")
あるいは、
 CallByName(Book, "SaveAs", CallType.Method, "C:\VB\Test.xls")
といった、部分的な記述を行うだけでも効果があります。


----
なお、このような問題は SaveAs に限った事ではありません。Excel のメソッドやプロパティは、
バージョンが異なると引数の数が増加したり、以前は Sub だったメソッドが Function に
変更されるなどの変更が重ねられてきています。

そのため Excel を利用する場合には、Excel のバージョンを一つに絞っておかないと、
思わぬトラブルの元となってしまうことになります。

どうしてもバージョン混在での開発が必要なら、各 Excel バージョンのライブラリの違いを
十分に把握できる環境と知識が必要になります。それができないのであれば、
> 「複数のバージョンの Excel を同一環境にインストール」をやめるべき
だと思いますよ。
投稿者 yamaV1.02β  (社会人) 投稿日時 2009/5/9 06:07:39
魔界の仮面弁士さん、解説ありがとうございました。
以前よりVBがらみで検索したときに、何度かハンドルをお見かけしておりました。

十分すぎるほど満足な回答をありがとうございます。

スッ、スバラスィ(;´Д`)