日付データをCOleDateTimeに変換する
水曜日, 4月 16th, 2008 Posted in C++ | 2 Comments »iTunesのライブラリファイル(iTunes Music Library.xml)を解析してゴニョゴニョしたいなぁと思って、VC6で解析ツールを作っています。
その中で、[2008-04-14T08:49:55Z]というgmtの書式で表される日時同士を比較したいがために、COleDateTimeに変換する関数を作りました。
値のチェックとかは省略してますよ。
言語はC++です。
- BOOL ConvStrToDate( LPTSTR pstrDate, COleDateTime& dateTime )
- {
- if( !pstrDate ){
- return FALSE;
- }
- char sep[] = "-:TZ";
- char* token = NULL;
- std::vector<std::string> vDateString;
- token = strtok( pstrDate, sep );
- vDateString.push_back( token );
- while( token ){
- token = strtok( NULL, sep );
- if( token ){
- vDateString.push_back( token );
- }
- }
- if( !vDateString.size() ){
- return FALSE;
- }
- char *stopstring;
- const int year = (int)strtol( vDateString[ 0 ].c_str(), &stopstring, 10 );
- const int month = (int)strtol( vDateString[ 1 ].c_str(), &stopstring, 10 );
- const int day = (int)strtol( vDateString[ 2 ].c_str(), &stopstring, 10 );
- const int hour = (int)strtol( vDateString[ 3 ].c_str(), &stopstring, 10 );
- const int min = (int)strtol( vDateString[ 4 ].c_str(), &stopstring, 10 );
- const int sec = (int)strtol( vDateString[ 5 ].c_str(), &stopstring, 10 );
- dateTime.SetDateTime( year, month, day, hour, min, sec );
- return TRUE;
- }
なんかまずいところがあればご指摘お願いシマス!
スレッドを_endthreadで終わったらメモリリーク
火曜日, 3月 18th, 2008 Posted in C++ | 3 Comments »c++のスレッドの話。
今回はまったのは、_beginthreadで開始したスレッドを終了するとメモリリークが発生していた件。
ざっと見た感じ解放忘れとかなさそうな感じだったので原因の発見に時間がかかった。
スレッドの最後で_endthreadをコールしていたんだけど、これをコメントアウトするとメモリリークが消えた。
なんで?と思って調べてみると、簡単なことだった。
例えば次のような関数を_beginthreadで呼んだとする。
- void ThreadFunction( void* )
- {
- CString strFilePath = "G:\\test.mp3";
- //MP3を再生する関数
- PlayMp3( strFilePath );
- _endthread();
- }
あ、VCです。
strFilePathのスコープは関数内で、この関数を抜けるときにデストラクタが呼ばれる。
つまり、関数の最後の”}”まで行けばstrFilePathのデストラクタが呼ばれて幸せなんだけど、_endthread()で強引にスレッドを抜けてしまうと、デストラクタが呼ばれずにメモリリークしてしまう。
こんな簡単なコードだとわかりやすいんだけど、これが実際のコードとなるとぜんぜん気づかない・・・。
以後気をつけます。
BYTEの配列データをVARIANTのSAFEARRAY(VT_ARRAY)に変換する
木曜日, 1月 31st, 2008 Posted in C++ | 1 Comment »今回は、C++に関するエントリー。本業はC++なので、こういうのもありかなと。
VARIANTにデータを設定するのはいつもついつい調べ直してしまいます。今回は、BYTE型のデータをSAFEARRAY型に流し込む方法。調べ直していたところ、ORiN協議会◇技術解説の説明がとてもわかりやすかったので、うれしさついでに関数化してみました。
- BOOL ByteArrayToVariant(BYTE* pBytes, int size, VARIANT& v)
- {
- SAFEARRAYBOUND rgb[1];
- rgb[0].cElements = size;
- rgb[0].lLbound = 0;
- SAFEARRAY* psa = SafeArrayCreate(VT_UI1,1, rgb);
- if(!psa)
- return FALSE;
- void HUGEP *pvData;
- HRESULT hr = SafeArrayAccessData(psa, &pvData);
- if(S_OK!=hr)
- return FALSE;
- memcpy( pvData, pBytes, size );
- hr = SafeArrayUnaccessData(psa);
- if(S_OK!=hr)
- return FALSE;
- v.parray = psa;
- v.vt = VT_ARRAY | VT_UI1;
- return TRUE;
- }
関数の説明
- SAFEARRAYBOUND rgb[1];
SAFEARRAYBOUNDは、SAFEARRAYの要素数とインデックスの下限値を設定する。BOUNDには「限度,範囲」なんて意味があるので、わかりやすいネーミングですね。次に、
- SAFEARRAY* psa = SafeArrayCreate(VT_UI1,1, rgb);
で、SAFEARRAYの実体を作ります。今回は、BYTEの配列なのでVT_UI1を指定します。SAFEARRAYのデータへは、SafeArrayAccessData()をコールすることでアクセスできるようになります。
- void HUGEP *pvData;
- HRESULT hr = SafeArrayAccessData(psa, &pvData);
コピー元のデータをSafeArrayAccessData()で取得した配列へコピーします。
- memcpy( pvData, pBytes, size );
SafeArrayAccessData()したら必ず、SafeArrayUnaccessData()をコールします。
- hr = SafeArrayUnaccessData(psa);
最後にVARIANT型の引数にデータを設定しておしまいです。
- v.parray = psa;
- v.vt = VT_ARRAY | VT_UI1;
ByteArrayToVariant()の呼び元でVARIANTを使った後に、
- HRESULT SafeArrayDestroy( v.parray );
をコールするとなんか不適切なメモリを解放してしまうようで、なんとなく不安定になりました。なんででしょうねぇ。