DOM プログラミングレッスン
第1回:C++ アプリケーションから MSXML を使う(その1)
(株)日本ユニテック
太田 純
<この記事はDigital
Xpress 2001 Vol.1(4-5月号)に掲載されたものです>
この連載では、主に Windows 上で C++ を使用した DOM プログラミングについて扱っていきます。みなさんはプログラムの開発において
C++ をお使いでしょうか? 最近では Visual Basic、Java、スクリプト系言語、そして HTML を使いながらシステムを構築する場合が多くなってきて、C++
はあまり使わなくなってきているかもしれません。しかしながら、高速な処理が要求される部分において C++ を使うのは依然として主流ですし、過去に
C++ で作成したアプリケーションのバージョンアップに対応する必要もあります。今回は C++ アプリケーションに XML
のサポートを追加する方法について考えていきます。
Visual C++ 6.0 を利用している方は、ヘッダーファイル msxml.h が標準添付されているので、これを使って
XML ファイルを読み込んで利用するプログラムを作成している方もおられるかもしれません。このヘッダーファイルを使用すると、Internet
Explorer 4.0 に同梱されていたバージョンの MSXML を操作することができます。IE 5.0 以後がセットアップされていても、このヘッダーファイルを使用するとIE
4.0 互換のオブジェクトが作成されます。しかしながら、このバージョンの MSXML には
・W3C 勧告の DOM 仕様とプロパティ名、メソッド名などが異なる
・編集系メソッドが存在しない
・タグ名などがすべて大文字に変換されてしまう
という問題があります。それで、MSXML を使用する場合は IE 5.0 以後のバージョンのものを利用するようお勧めいたします。IE
が 5.0 より前のバージョンの場合は、Microsoft
のサイトから XML SDK をダウンロードすることによって、新しいバージョンの MSXML を使用することができます。最新バージョンである
MSXML 3.0 が 2000 年 11 月にリリースされました。これには従来からある DOM のサポートに namespace
対応が加えられ、XSLT, XPath, SAX2 などもサポートされています。
さて、MFC アプリケーションの開発者のみなさんは Class Wizard の使用に慣れておられることと思います。MSXML
を利用するのに Class Wizard を使うことができるでしょうか?
Class Wizard を開いて、「クラスの追加」-「タイプライブラリから」を選び、DLL ファイル名を指定するとその
DLL で定義されたインターフェイスを使用できるようにヘッダーファイルとインプリメンテーションファイルが作られます。こうしてできあがるクラスは
COleDispatchDriver のサブクラスとして宣言されており、すべてのメソッド、プロパティは IDispatch
インターフェイスを通じてアクセスされます。俗に IDispatch 経由のアクセスはカスタムインターフェイス経由の場合と比べて(メソッドの中身が空の場合)100
倍遅いとも言われているので、この方法はぜひとも避けたいものです。そもそも高速アクセスが必要ないのなら C++ を使わなくても、メンテナンスが容易なスクリプト言語を使えばよかったのかもしれません。
したがって、これは MSXML に限らず、COM コンポーネントを使う場合全般について言えることですが、Class Wizard
でクラスを作成することはできるがやめておいたほうがよい、ということになります。
Class Wizard 以外で外部のコンポーネントを利用するには以下の方法があります。
・ヘッダーファイルとインプリメンテーションファイルを別途入手する
・#import ディレクティブを使う
ヘッダーファイル、インプリメンテーションファイルは XML SDK に含まれており、Microsoft のサイトからダウンロードすることができます。
ここでは、#import ディレクティブを使う方法について調べてみることにしましょう。
#import を使用する
Microsoft のサイト、Web Workshop の中に「XML に関するよく寄せられる質問」という文書があり、そこに
#import を利用して MSXML を使う方法が紹介されています。アドレスは、http://www.asia.microsoft.com/japan/developer/workshop/xml/general/xmlfaq.aspとなっています。なお、このアドレスは変更される可能性がありますし、内容も更新されるかもしれません。
この文書の中には、C++ で MSXML を利用する方法として次のようなコーディング例が書かれています。
#import "msxml.dll" named_guids
no_namespace
ここで、自分のファイルに上記の行を追加してコンパイルすると、以下のようなエラーメッセージが大量に発生してしまいます。
msxml.tlh(81) : error C2371: 'XMLELEM_TYPE'
: 再定義されています。異なる基本型です。
c:\program files\microsoft visual studio\vc98\include\msxml.h(117)
: 'XMLELEM_TYPE' の宣言を確認してください。
msxml.tlh(82) : warning C4099: 'XMLDocument' : タイプ名は最初 'class'
として使われていましたが 'struct' として使われています。
c:\program files\microsoft visual studio\vc98\include\msxml.h(58)
: 'XMLDocument' の宣言を確認してください。
ちなみにこのエラーはファイルに上記の #import 文のみを書いてほかに何も書かなくても発生します。というのは、#import
によってコンパイラが生成するファイルに #include <comdef.h> の行が含まれており、Visual
C++ 6.0 に添付されている comdef.h の中には IE 4.0 バージョンの古い MSXML を参照するコードが書かれてしまっているからです。これを解決するには、no_namespace
属性をはずさなければなりません。
#import "msxml.dll" named_guids
この修正で、上記のエラーは出なくなります。ただし、using namespace を使用すると、IE 4.0 バージョンの古い
MSXML と名前が同じインターフェイス名等を使った時にエラーが発生しますから、rename 属性を使って名前を変更しておく等の工夫が必要となります。
このようにして #import を利用すると、msxml.tlh と msxml.tli という 2 つのファイルが生成され、#import
を記述した位置でこの 2 つのファイルを #include したかのように解釈されます。
この中には、MSXML が提供するすべてのインターフェイスとそのメソッドおよびプロパティ、そして、それらのエラーチェック済みバージョンが含まれています。エラーチェック済みバージョンは、メソッドやプロパティの実行後に
HRESULT 値を調べて、エラーを示す値の場合は _com_error 例外を throw します。
この時、オリジナルのメソッド名(たとえば hasChildNodes)はエラーチェック済みバージョンの名前となり、実際のインターフェイス関数の名前には先頭に
raw_ が付けられます。プロパティについては、エラーチェック済みバージョンでは = を使用した代入ができるようになっています。たとえば、
pNode1 = pElemRoot->firstChild;
と書けば、コンパイラは pElemRoot の firstChild プロパティを呼び出すコードを生成し、結果が pNode1
に入れられます。これらのエラーチェック済みバージョンを使用する場合は、必ず使用する個所を try ブロックで囲って、_com_error
例外を catch するようになさってください。これによって、Visual Basic と同様の簡便な記述をすることができます。
一方、きめの細かいエラー処理が必要な場合などは、生のインターフェイス関数を呼び出して 1 回ごとに HRESULT 値を調べるほうがよいかもしれません。その場合は、
#import "msxml.dll" named_guids
raw_interfaces_only
というように、raw_interfaces_only 属性を付加すれば、実際のインターフェイス関数の名前でアクセスできるようになります。つまり、メソッド名はそのまま
(raw_ は付加されない)、プロパティ名は、get_、put_、putref_ などが先頭に付けられた名前になります。
>>次に、XMLファイルを読み込んでみましょう。
関連サービス
IT技術およびIT製品の可用性調査・検証業務
関連キーワード: C++
関連キーワード: MSXML
関連キーワード: プログラミング
|