August 04, 2007

VC++ UnicodeとMSXMLの闇

 MSXML使ってVC++2005でxml読み取るアプリ書いてたんだけど、やっと終わった。
 やたら時間かかった。おそらくC#で書いてたら、1/3の時間で済んだと思う。VC++2005は初心者がハマりやすい罠に満ちていると思った。
 Cはよくやってたけど、VC++として書くのは今回が初めてな気がする。どんくらい初心者かって言うと、書き始めるときに「LPCWSTR型って何さ?」ってとこから調べ始めたくらい。ド初心者。

【MSXML】
 MSXMLについて調べると、必ず出てくるこのページ(『デベロッパーズコーナーC++ アプリケーションから MSXML を使う(その1)』@XML SQUARE)。たしかに、xmlに接続するまではとてもお世話になった。記事が古くて、今は
#import "msxml4.dll" named_guids
 だけどね。ついでにCOMの初期化もしなくちゃなんない。
CoInitialize(NULL);
(CoUninitialize();とセット)
 こいつが上記のサイトに書いてなくてハマった。
 MSXMLで作ったノード関連のオブジェクトの後処理は普通 Release(); だと思うんだけど、私の場合はエラー出た。そこでこちらさんで紹介されてたやり方(『MSXMLを使う』)より、 Node = NULL;と、NULL代入の方法に変更する。まーどっかで私のやり方が間違ってるんだろーけどさー。

 書いたコード(の一部)を恥ずかしげもなくさらす。自分がネット上を探してるときに、他の人のコードがとてもありがたかったから。例外処理は_com_errorで受ける。
MSXML2::IXMLDOMDocument2Ptr pDoc;
MSXML2::IXMLDOMElementPtr pRoot;
try{
	pDoc.CreateInstance(MSXML2::CLSID_DOMDocument);
	pDoc->put_async(VARIANT_FALSE);	//loadメソッドが完了するまで待機
	pDoc->load(_variant_t(xmlFile));    //"xmlFile"はxmlファイル名
	pDoc->get_documentElement(&pRoot);
	//XPathを使うように設定
	pDoc->setProperty(_bstr_t(L"SelectionLanguage"),variant_t(L"XPath"));
}catch(_com_error &e){
	MessageBoxW(NULL, e.Description(), L"Debug Window", MB_OK);
}

【XPath】
 ようやくxmlに接続できたと思ったら、さっそくXPath。xmlにクエリライクにアクセスできるやり方。ココ(『msxmlについて - PukiWiki』)が素晴らしい。しかしC++初心者な私は「文字列連結ってどーすんね?」っていう疑問。SelectNodesやSelectSingleNodeに渡すのも、_bstr_t型なんだよね。こいつなら+演算子で連結できる。他の型から_bstr_t型に変換しようかって思ってたんだけど、なんか見つかんなくて、結局そのまま_bstr_tをやりとりするように関数作り直すハメになった。配列アクセスするために数字を混ぜるときは
_variant_t MyTime::HourXPath(void){
	_variant_t v(this->Hour + 1);    //this->Hourはint
	v.ChangeType(VT_BSTR);
	return v;
}
 こんなかんじ。そうそう!並列に並んでるノードにアクセスするときなんだけど、xmlの配列の添え字は"1"から始まってるよ!!"0"からじゃないのか。。意味不明なエラーはこれだった。。
 ここでも自分の書いたコード(の一部)をさらす。
MSXML2::IXMLDOMNodePtr pMin;
_variant_t varText;
try{
	this->pRoot->selectSingleNode(L"/Schedules/" + this->position + L"/" + goal + L"/" + trafic + L"/Schedule/usual/Table[" + this->Time->HourXPath().bstrVal + L"]")->get_firstChild(&pMin);
	pMin->get_text(&varText.bstrVal);
	}catch(_com_error &e){)
 これでvarTextの中にはxmlの該当箇所の中身が入る。

 ところで、いちいちXPathのフルパスでアクセスするのはパフォーマンス的にどうなの?ってのがある。さっきの『MSXMLについて』のページの一番下には
Microsoft のサイト情報によれば、ノードを再帰的に検索して目的のものを探すより、selectSingleNode? の方がパフォーマンスに優れる、とある。selectSingleNode? は一度の検索となるが、掘ってゆくタイプの場合、COM 呼び出しが頻繁に行われる為、重くなるのだとか。
と、ある。

【_variant_t】
 ”型”が厳密なC++のアイデンティティを覆すような強力凶悪な型、それが_variant_t。何がしたいんだか正直分からん。んでも、結局使う。MFCでCString使ったら負けな気がするし。上のコードでも、int型を_bstr_t型に変換するのに使ってる。
 使用には #include "comdef.h"必要。

 ところで、このChangeType(VARIANT_TYPE)ってヤツも探したけれど、なかなか見つからなかった。なんか変換してくれるらしい。VARIANT_TYPEについては、なんか色々あるらしいけど、とりあえず
VT_I4 -> int
VT_R4 -> float (4bit)
VT_R8 -> float (8bit)
VT_BSTR -> BSTR(char *なのか?)
VT_DATE -> 日付を保存できるらしい
 だけ知ってれば十分かな?って気がする。

 BSTR型をintにキャストするのは _wtoi(bstr) で桶。

--

 あー。
 3時間で書くつもりだったアプリに3日もかけちまった。
 色々とハマり杉。他にも何か思い出したら書き足すかも。

 あーあとアレだ。
 読み込むxmlファイルの場所なんだが、ソリューションのファイルがおいてあるところのdebugなりreleaseのフォルダな。一階層下のプロジェクトのファイルが入ってるところのdebug,releaseはビルド時の一時ファイル置き場だから。ビルドしてもそっちに.exeできないよ。
 という超くだらないところでハマった普段はC#屋 orz

k_yon at 21:57│Comments(2)TrackBack(0)clip!C/C++/C# 

トラックバックURL

この記事へのコメント

1. Posted by おいおい   October 14, 2007 18:19
1 初心がすっこんでろよ。
間違えて読んじまったじゃねぇ〜かよ。
2. Posted by yoneken   October 14, 2007 21:39
どんまい
世の中いっつもそんなもんですorz

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
現状報告
 KiCad解説本の重版が決定しました!ありがとうございます♪.(2016/12/10)

自己紹介
yoneken
logo
 ロボットの研究・開発をしています。

続きを読む

連絡先は
ad

Syndicate this site
 2012年からKiCad日本語版バイナリのメンテナもしています.
来てくれた人たち
  • 今日:
  • 昨日:
  • 累計:

ショップリンク
嬉しいコメント
記事について
 このブログ記事の著作権は全てyonekenに属します。
 転載や個別記事へのリンクはご自由にどうぞ。連絡は必要ありません。
 記事の内容は無保証です。古い記事の内容は当時と状況が変わっている場合があります。
 内容に関する質問はコメント欄でもらえると、他の人にも役立ちます。
記事検索
月別
リア友リンク