- PR -

C# Excelのプロパティ>ユーザ設定を扱う方法

投稿者投稿内容
あすか
ぬし
会議室デビュー日: 2006/07/12
投稿数: 309
投稿日時: 2006-07-13 16:48
次のように実装してみました。

Interop.Application app = new Interop.Application();
Interop.Workbooks activeWorkbooks = app.Workbooks;
Interop.Workbook activeWorkbook = activeWorkbooks.Open(@"a.xls",
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
Core.DocumentProperties docProps = (Core.DocumentProperties)activeWorkbook.CustomDocumentProperties;

そうしますと、実行時、最後のステップで
「型 'System.__ComObject' の COM オブジェクトをインターフェイス型 'Microsoft.Office.Core.DocumentProperties' にキャストできません。IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}' が指定されたインターフェイスの COM コンポーネント上での QueryInterface 呼び出しのときに次のエラーが発生したため、この操作に失敗しました: インターフェイスがサポートされていません (HRESULT からの例外: 0x80004002 (E_NOINTERFACE))。」
という良く分らないエラーが出てしまったのです。

他にも
Tools.Workbook activeWorkbook2 = (Tools.Workbook)activeWorkbook;
ということを試みてみましたが、こちらも実行時に
「型 'Microsoft.Office.Interop.Excel.WorkbookClass' の COM オブジェクトをクラス型 'Microsoft.Office.Tools.Excel.Workbook' にキャストできません。COM コンポーネントを表す型のインターフェイスを COM コンポーネントを表さない型にキャストすることはできません。ただし、基になる COM コンポーネントがインターフェイスの IID の QueryInterface 呼び出しをサポートする場合は、インターフェイスにキャストすることができます。」
というエラーが出ました。


何かお分りになりますでしょうか。

[ メッセージ編集済み 編集者: あすか 編集日時 2006-07-13 16:49 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-07-13 18:02
引用:

あすかさんの書き込み (2006-07-13 16:48) より:

何かお分りになりますでしょうか。


ごめんなさい、わかりません... (;^-^)

私も今、COM Interop で試してみたのですが、こちらでもキャストができませんでした。
一体全体、実体は何型だというんでしょうね...

ただし、VB で遅延バインディングを使用するとできてしまうのです。

コード:

    Private Shared Sub MosaMosaAA()
        Dim xlApplication As Excel.Application

        Try
            xlApplication = New Excel.Application()
            xlApplication.Visible = True
            Dim xlWorkBooks As Excel.Workbooks

            Try
                xlWorkbooks = xlApplication.Workbooks
                Dim xlWorkbook As Excel.Workbook

                Try
                    xlWorkbook = xlWorkbooks.Open("C:\MakiMakiLove.xls")
                    Dim xlCustomDocumentProperties As Object

                    Try
                        xlCustomDocumentProperties = xlWorkbook.CustomDocumentProperties
                        Dim xlCustomDocumentProperty As Object

                        Try
                            xlCustomDocumentProperty = xlCustomDocumentProperties("タイピスト")
                            MessageBox.Show(xlCustomDocumentProperty.Value.ToString())
                        Finally
                            If Not xlCustomDocumentProperty Is Nothing Then
                                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCustomDocumentProperty)
                            End If
                        End Try
                    Finally
                        If Not xlCustomDocumentProperties Is Nothing Then
                            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCustomDocumentProperties)
                        End If
                    End Try
                Finally
                    If Not xlWorkbook Is Nothing Then
                        Try
                            xlWorkbook.Close()
                        Finally
                            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbook)
                        End Try
                    End If
                End Try
            Finally
                If Not xlWorkbooks Is Nothing Then
                    Try
                        xlWorkbooks.Close()
                    Finally
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbooks)
                    End Try
                End If
            End Try
        Finally
            If Not xlApplication Is Nothing Then
                Try
                    xlApplication.Quit()
                Finally
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApplication)
                End Try
            End If
        End Try
    End Sub


うーん、やっぱり型は合っているような気もします。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-13 23:39
引用:

私も今、COM Interop で試してみたのですが、こちらでもキャストができませんでした。
一体全体、実体は何型だというんでしょうね...



ラッパクラスじゃなくて、生のインターフェース型にキャストしてみたら?
あすか
ぬし
会議室デビュー日: 2006/07/12
投稿数: 309
投稿日時: 2006-07-14 10:05
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-13 23:39) より:

ラッパクラスじゃなくて、生のインターフェース型にキャストしてみたら?




ええと、これはどういうことなのでしょうか。
私の知識では"生のインターフェース型"が分らないのですが
ご面倒でなければ、分りやすく解説していただけないでしょうか。
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-15 05:06
引用:

ええと、これはどういうことなのでしょうか。
私の知識では"生のインターフェース型"が分らないのですが
ご面倒でなければ、分りやすく解説していただけないでしょうか。



面倒です (^^;

背景を正しく理解するためには OLE/COM の基礎と .NET の型システムに関する知識が必要で、たかだか掲示板の1投稿程度の文書量で「分かりやすく」解説するのは非常に困難です。

技術的な背景や詳細については書籍等を参考にしてもらうとこととして、重要なところをかいつまんで説明すると以下のような感じになります。理解できなかったらごめんなさい。

VSTO の同梱物や tlbimp によって自動生成されたラッパクラスを使っていると忘れがちですが、OLE/COM と .NET では、簡単に言えば動作原理が全く異なります。

Excel.ApplicationClass クラスは典型的なラッパクラスであり、その内部に Excel アプリケーションのインスタンスの OLE/COM ネイティブな参照をカプセルしています。

「ラッパクラスの参照」と「OLE/COM ネイティブな参照」は全くの別物である点が重要です。

さて、ラッパクラスのメソッドには、オブジェクトインスタンスの参照を返すものがあります。

普段あまり深く考える異なることなく

コード:
HogeHogeClass hogeHoge = HogeWrapper.GetHogeHoge();



のような構文を利用していると思いますが、HogeWrapper の元ネタとなった OLE/COM レベルでのインターフェース定義(=IHoge::GetHogeHoge())では、GetHogeHoge() メソッドは IHogeHoge または IUnknown/IDispatch を返す設計であったはずです。

何故なら、OLE/COM では、すべてのオブジェクトが実装を義務付けられた IUnknown インターフェースのポインタか、OLE レベルで実装を義務付けられている IDispatch インタフェースのポインタ、または適当なカスタムインターフェースのポインタをオブジェクトインスタンスの参照として使用するからです。

例えば IHoge::GetHogeHoge() の定義が C# 風に表記すると

コード:
IHogeHoge GetHogeHoge();



である時、これを HogeWrapper 生成の際に

コード:
HogeHogeClass hogeHoge = HogeWrapper.GetHogeHoge();



のように「翻訳する」のは容易でしょう。

ですが、IHoge::GetHogeHoge() の設計が

コード:
IDispatch GetHogeHoge();



のような場合、GetHogeHoge() が返す型は何にするべきでしょうか?

特別なヒントが無い限り、object 型にする他ありません。結果として

コード:
object disp = HogeWrapper.GetHogeHoge();



となりますが、この時 hogeHoge は .NET の「COM 相互運用機能」で定義された ComObjectClass クラス(=正確な名前を忘れました (^^;)のインスタンスとなります。

ComObjectClass クラスから、HogeHogeClass クラスへのキャストは未定義というか不可能であるため

コード:
object disp = HogeWrapper.GetHogeHoge();
HogeHogeClass hogeHoge = (HogeHoge) disp;



のようなキャストは実行時エラーになります。(実際、類似の現象が起きていますよね?)

ですが、「COM 相互運用機能」は COM レベルで定義されたインターフェースを .NET のインターフェースとして解釈する機能を提供しているため、上記の擬似コードにおける disp は IHogeHoge インターフェース型にはキャストできます。(場合があります)

コード:
object disp = HogeWrapper.GetHogeHoge();
IHogeHoge hogeHoge = (IHogeHoge) disp;



この場合の「COM から .NET にインポートされたインターフェース型」を「生のインターフェース型」と呼んだのです。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-07-15 12:49
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-15 05:06) より:

上記の擬似コードにおける disp は IHogeHoge インターフェース型にはキャストできます。(場合があります)
この場合の「COM から .NET にインポートされたインターフェース型」を「生のインターフェース型」と呼んだのです。


そういう意味でしたか... 投稿見合わせていました。

そういう意味であれば、今回はできないですね。
リフレクションでも一応覗き見ましたが、該当するものはなさそうです。
(ひどりさんの説明に少しあるように、System.__ComObject としてしか存在しない)

タイプ ライブラリをゴリゴリ書いて何とかするか、
おとなしく、VB の遅延バインドマンセーでしょうかね。

# "面倒です" と言いつつも、思った以上に説明しているひどりさんw

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-07-16 05:51
引用:

リフレクションでも一応覗き見ましたが、該当するものはなさそうです。



MSDN Library を斜め読みした限りでは、Core.DocumentProperties が「生のインターフェース」に一番近いようですね。

これでキャストできないとなると

引用:

タイプ ライブラリをゴリゴリ書いて何とかするか、
おとなしく、VB の遅延バインドマンセーでしょうかね。



か、清く正しく? InbokeMember するか、ですね。

引用:

# "面倒です" と言いつつも、思った以上に説明しているひどりさんw



元投稿から「頑張っている」雰囲気が伝わってきたので ;-)


[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-07-16 05:54 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-07-16 09:29
引用:

渋木宏明(ひどり)さんの書き込み (2006-07-16 05:51) より:

MSDN Library を斜め読みした限りでは、Core.DocumentProperties が「生のインターフェース」に一番近いようですね。


ああ、何で試していたのか書いていなかったのがまずかったですね。
私も、Microsoft.Office.Core にある DocumentProperties が最も近いと思い、
  1. Microsoft.Office.Core.DocumentProperties インターフェイス
  2. Excel.CustomProperties インターフェイス
  3. Excel.ICustomProperties インターフェイス (非表示メンバ)
のように試してみましたが、ダメダメでした。

引用:

か、清く正しく? InbokeMember するか、ですね。


正しくは、InvokeMember ですね? (;^-^)
C# で 「遅延バインディング」 を行うには、System.Type.InvokeMember メソッドでしたね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌

スキルアップ/キャリアアップ(JOB@IT)