ひきこもりプログラマ

C++のこととか。

Visual SourceSafeでラベルから共有・取得できなくなったのでかわりにバージョン番号を使った

2013-04-08 | Software

以前にもラベルが使えなくなったことがあったのですが(Visual SourceSafeで特定のラベルが取得できない),今回はラベルにハイフンなど入っていません。しかしVisual SourceSafe エクスプローラから共有・分岐してもプロジェクトフォルダー1つだけしか共有されませんし,取得しても何も起こりません。しょうがないので,ラベルの詳細情報を表示してバージョン番号を確認し


ss.exe CP $/MyProject/trunk
ss.exe Share $/MyProject/trunk -R -E -V[バージョン番号]

で共有・分岐しました。

というか最終的には分岐してtrunkの横に1.0ブランチを作りたかったのですが,コマンドラインに「1.0」を入力する場所がなくて一体どうするんだオイと思っていたら,Shareコマンド実行後に「$/MyProject/trunk のコメント」と「新規プロジェクトの名前」の入力を求められました。なんでそこだけインタラクティブなんだ…。


ICUによるUnicodeからJISへの変換

2013-01-18 | Software

撮影装置はだいたい海外製で漢字なんて知ったこっちゃないので,生成するDICOMデータには患者名の漢字とかフリガナは含まれません。でもそれだと使い勝手が悪いということでがっつり日本製のオーダリングシステムからもらった漢字とかフリガナをDICOMデータのほうに反映してやるわけです。

で,オーダリングシステムはたいていShift JISでデータを送ってくるのですが,使っていい文字についての規定などあるわけもなく,Windowsで表示できればどんな文字でもOKという状況です。これをDICOMデータ用にJIS変換するのにICUを使っているのですが(コンバータは"JIS8"),ICUはかならずUnicodeを経由するので(そしてShift JISからUnicodeへの変換はかならず成功するみたいなので),UnicodeからJISへの変換に失敗する文字が出てきます。

失敗といっても二通りありまして,ひとつは日本語でない文字集合のエスケープシーケンス(「1b 24 41(中国語)」か「1b 24 28 43(韓国語)」)が使われるケース,もうひとつは既定の文字集合で「0x1a」に変換するケースです。いずれの場合もICUはエラーを返さないので注意が必要です。

日本語でない文字集合のエスケープシーケンスが使われてしまう文字
朗隆
0x1aに変換されてしまう文字
塚晴凞猪益礼神祥福靖精羽蘒諸逸都飯飼館鶴

ちなみに以下の文字については(たぶん正式には基本漢字に含まれないのですが)がんばって変換してくれます。

①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡㍻〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪

ICUがDICOMの半角カナを正しくUnicodeに変換できない

2012-09-27 | Program

PS 3.3 - 2011 の Table C.12-3 DEFINED TERMS FOR SINGLE-BYTE CHARACTER SETS WITH CODE EXTENSIONS によると,JIS X 0201: Katakana を使う際の ESC sequence は「ESC 02/09 04/09」となっています。これはつまり G1 working set に1バイトカタカナを指示(designate)しているわけで,DICOMでは8ビットモードを使ってねという話を考えるとなにもおかしくないのですが,ICU 4.8 でこのエスケープシーケンスから始まる半角カナをUnicodeに変換すると,エスケープシーケンスがまるっと残ってしまいます。8ビットモードなのでucnv_openに渡すconverter名は「JIS8」なのですが,どうもこいつは「カタカナをG1にってそんなんいちいち指示しなくても最初から割り当てられてますやん。そんな指示意味ないですやん」と判断しているご様子。ちょっといまソースコード読む気力がないので推測なんですが。

というわけで上述のエスケープシーケンスはICUに渡す前に「ESC 02/08 04/02」あたりに変換しておくとよいようです。

※日本語なんだから「ESC 02/08 04/10」でいいんじゃないのとも思ったのですがこれだとバックスラッシュが円記号(U+00A5)に変換されてしまってたぶんまずいことになります。


put_ValueでやっぱりDB_E_ERRORSOCCURRED(未解決)

2012-04-17 | Program

put_ValueでIDispatch error #3105 の続きです。今回はINSERT後に@@IDENTITY列の値がほしい→しかしテーブルにINSERTトリガが仕込んであるため動的プロパティ"Update Resync"を設定しなくてはいけない→adUseClientにしなくてはいけないということでサーバサイドカーソルで逃げられなかったので,トレースを仕込んでがんばってみました。ADOのバージョンはいつのまにか6.1.7601.17761です。

  • enter_01 <CRsetField::put_Value|API|ADO> 1066#, vValue: 07E9CE8C{VARIANT*}
  • enter_02 <CFoxRowset::CreateAccessor|API|RDS> 1056#, AccessorFlag: 2, BindingParam: 1, DBBinding: 07E9CCB4, DBLenggh: 0
  • enter_03 <CFoxRowset::CanConvert|API|RDS> 1056#, FromType: 12{DBTYPE}, ToType: 3{DBTYPE}, ConvertFlags: 0{DBCONVERTFLAGS}
  • <IDataConvert::CanConvert|API|OLEDB> wSrcType: 12{DBTYPE}, wDstType: 3{DBTYPE}
  • <IDataConvert::CanConvert|API|OLEDB|RET> 00000000{HRESULT}
  • <CFoxRowset::CanConvert|API|RDS|RET> 1056#, HRESULT: 0x00000000{HRESULT}
  • leave_03
  • enter_03 <CFoxRowset::CanConvert|API|RDS> 1056#, FromType: 3{DBTYPE}, ToType: 12{DBTYPE}, ConvertFlags: 0{DBCONVERTFLAGS}
  • <IDataConvert::CanConvert|API|OLEDB> wSrcType: 3{DBTYPE}, wDstType: 12{DBTYPE}
  • <IDataConvert::CanConvert|API|OLEDB|RET> 00000000{HRESULT}
  • <CFoxRowset::CanConvert|API|RDS|RET> 1056#, HRESULT: 0x00000000{HRESULT}
  • leave_03
  • <CFoxRowset::CreateAccessor|API|RDS|RET> 1056#, HRESULT: 0x00000000{HRESULT}, Accessor: 0649D9B0{HACCESSOR}, DBBindStatus: 07E9CCE8{DBBINDSTATUS}
  • leave_02
  • enter_02 <CFoxRowset::SetData|API|RDS> 1056#, hRow: 1{HROW}, accessor: 105499008{HACCESSOR}, pData: 07E9CDF8
  • <IDataConvert::DataConvert|API|OLEDB> wSrcType: 12{DBTYPE}, wDstType: 3{DBTYPE}, cbSrcLength: 0, pcbDstLength: 07E9CC40, pSrc: 07E9CDF8, pDst: 064A1299, cbDstMaxLength: 4, dbsSrcStatus: 0{DBSTATUS}, pdbsStatus: 07E9CE08{DBSTATUS*}, bPrecision: 10, bScale: 255, dwFlags: 1{DBDATACONVERT}
  • <IsLegalDBtype|OLEDB|ERR> 80040E08{HRESULT} line:8969
  • <Trace|HR> 0x80040E08{HRESULT} line 8970
  • <CDataConvert::DataConvert|OLEDB|ERR> 80040E08{HRESULT} line:7460
  • <CDataConvert::DataConvert|OLEDB|ERR> 80040E08{HRESULT} line:7666
  • <IDataConvert::DataConvert|API|OLEDB|RET> 80040E08{HRESULT}, pcbDstLength: 07E9CC40{DBLENGTH*}, pDst: 07E9C634, pdbsStatus: 07E9CE08{DBSTATUS*}
  • <Trace|HR> 0x80040E08{HRESULT} line 7669
  • <CFoxRowset::rsSetRowsetData|ADO|CE|ERR> 1056#, HRESULT: 0x80040e21{HRESULT}, iBind: 0
  • <CFoxRowset::rsSetRowsetData|RDS|ERR> HRESULT: 0x80040e21{HRESULT}

こんな感じで,途中までは調子よく進んでいるのですが,なぜかIsLegalDBtype()がDB_E_BADBINDINFOを返すため最終的にDB_E_ERRORSOCCURREDが返ってきてしまいます。お手上げです。

ちなみにトレースを仕込む際%SYSTEMROOT%\SYSTEM32\msdaDiag.dllと書くとなぜかうまくいかず,環境変数を使わないでC:\Windows\System32\msdadiag.dllと書くとOKでした。


C++/CLI 参照マネージドDLLの読み込みタイミング

2012-04-04 | Program

C++/CLIで,ネイティブ関数→同じアセンブリ内のマネージド関数→参照アセンブリ内のマネージド関数という順で呼んでいたのですが。

#pragma managed(push,off)

void MyNativeFunction()
{
    MyManagedFunction()
}

#pragma managed(pop)

void MyManagedFunction()
{
    try
    {
        MyManagedDllClass::AFunction();
    }
    catch (System::Exception^ e)
    {
        ShowError(e);
    }
}

MyManagedDllClassの格納されているアセンブリ(ここではMyManaged.dllとします)はプログラム起動時には読み込まれず,必要なときに動的に読み込まれるのですが,MyManaged.dllが存在しない状態でプログラムを起動しようとすると(まあつまりインストーラに組み込み忘れたってことですが)いきなりプログラムが落ちてしまっていました。try/catch書いてるのになんでだ! とびっくりしたのですが,MyManaged.dllはMyManagedDllClass::AFunction()が呼ばれる直前ではなくMyManagedFunction()が呼ばれる直前に読み込まれるのですね。そこで

#pragma managed(push,off)

void MyNativeFunction()
{
    MyManagedFunction()
}

#pragma managed(pop)

void MyManagedFunction()
{
    try
    {
        MyManagedFunctionIntenal();
    }
    catch (System::Exception^ e)
    {
        ShowError(e);
    }
}

void MyManagedFunctionIntenal()
{
    MyManagedDllClass::AFunction();
}

としてやったところ,MyManaged.dllが存在しなければSystem.IO.FileNotFoundExceptionがちゃんとcatchされるようになりました。