(09/05/01~)

09/05/01

・"C#" on ".NET Compact Framework 2.0 + Firebird 2.0.1 Data Provider for .NET Compact Framework 2.0" on "何か"
 なんとかなった。とりあえず納品完了...ってーか納品中(僕は納品に立ち会っていない)。残念な事に"開発機=実働機"だったため、"RZ-H220" はもう手元にない...プログラムの改変の際には手持ちのアドエスがテスト機として使えるので心配はないのだが。

 VisualStudio2008 で .NET CF2.0アプリを作る際の初歩の初歩を"Advanced / W-ZERO3[es] コーナー" に追加しておいた。

 今から思うに、アドエスネタは壮大な前フリだったと思う、今日この頃。


09/05/05

Windows 7 RC
 一般ダウンロードが可能となったようだ(MSDN サブスクリプション会員およびTechNet Plus サブスクリプション会員 は04/30から)。アレ?05/07がリリース予定じゃなかったっけ?

 ダウンロード開始日時は "太平洋標準時" なので、"太平洋標準時 2009/05/05 00:00" からDL可能になるとしたら、日本時間で "2009/05/05 17:00"...つまり、本日の午後5時以降にはDL可能となると思われます。

 ダウンロード終了日時は最短で "太平洋標準時 2009/06/30 まで" となっているようです。


09/05/07

Firebird Data Provider 2.0.1 for .NET Compact Framework 2.0
 Windows Mobile機 で Firebirdを使う方法の覚え書き。例によって言語は C# です。

 下準備。

  1. Firebird Data Provider 2.0.1 for .NET Compact Framework 2.0をDL。
  2. "FirebirdSql.Data.FirebirdClient.dll" を開発環境に配置("%ProgramFiles%\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE"とかに)。
  3. "参照設定"でプロジェクトに "FirebirdSql.Data.FirebirdClient.dll" を追加。

 設定が済んだら、コードの記述です。ポトリペタリは行いません。まず、using と 接続文字列を準備しておきます。

using FirebirdSql.Data.FirebirdClient;

...

string ConStr = "data source=192.168.1.10;" +
                "initial catalog=/Firebird/data.fdb;" + 
//              "initial catalog=C:\\Firebird\\data.fdb;" + 
                "server type=Default;" +
                "character set=SJIS_0208;" +
                "user id=SYSDBA;" +
                "password=masterke";

...

 Select(選択クエリ)の場合。

FbConnection con = null;
try
{
    con = new FbConnection(ConStr);
    try
    {
        con.Open();
        FbCommand cmd = con.CreateCommand();
        cmd.CommandText = "Select * From TBL_TEST Where FLG = @_FLG";
        cmd.Parameters.Add(new FbParameter("@_FLG"1));
        FbDataReader dr = cmd.ExecuteReader();
        while (dr.Read())
        {
            FieldData1 = dr["CODE"].ToString(); // フィールド名で値を取得
            FieldData2 = dr[1].ToString();      // フィールドインデックスで値を取得
        }
    }
    catch (FbException e)
    {
        MessageBox.Show("DBエラー", 
                        "エラー", 
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Hand, 
                        MessageBoxDefaultButton.Button1);
    }
}
finally
{
    if (con != null)
        con.Close();
}

 選択クエリにユニークなフィールドを指定した場合には dr.Read() の箇所が

if (dr.Read())
{

}
else
{

}

 こんな風になります。

 Delete(削除クエリ)の場合は、

FbConnection con = null;
try
{
    con = new FbConnection(ConStr);
    try
    {
        int rcv = 0;
        con.Open();
        FbCommand cmd = con.CreateCommand();
        cmd.CommandText = "Delete From TBL_TEST Where (FLG = @_FLG)";
        cmd.Parameters.Add(new FbParameter("@_FLG"0));
        rcv = cmd.ExecuteNonQuery();
    }
    catch (FbException e)
    {
        MessageBox.Show("DBエラー", 
                        "エラー", 
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Hand, 
                        MessageBoxDefaultButton.Button1);
    }
}
finally
{
    if (con != null)
        con.Close();
}

 こんな感じです。Select では FbDataReader を使って ExecuteReader()、Delete/Update/Insert のように結果を返さない場合には ExecuteNonQuery() を利用します。ExecuteNonQuery() の戻り値は作用したレコード数です。

 複数のクエリとトランザクションを扱う基本的な方法は以下のようになります。

FbConnection con = null;
try
{
    con = new FbConnection(ConStr);
    try
    {
        con.Open();

        FbTransaction trn = con.BeginTransaction();
        try
        {
            FbCommand cmd1 = con.CreateCommand();
            cmd1.Transaction = trn;
            cmd1.CommandText = "Delete From TBL_TEST1 Where (FLG = @_FLG)";
            cmd1.Parameters.Add(new FbParameter("@_FLG"0));
            cmd1.ExecuteNonQuery();

            FbCommand cmd2 = con.CreateCommand();
            cmd2.Transaction = trn;
            cmd2.CommandText = "Delete From TBL_TEST2 Where (FLG = @_FLG)";
            cmd2.Parameters.Add(new FbParameter("@_FLG"0));
            cmd2.ExecuteNonQuery();

            trn.Commit();
        }
        catch(FbException e)
        {
            trn.Rollback();
            MessageBox.Show("DBエラー", 
                            "エラー", 
                            MessageBoxButtons.OK, 
                            MessageBoxIcon.Hand, 
                            MessageBoxDefaultButton.Button1);
        }
    }
}
finally
{
    if (con != null)
        con.Close();
}

 とっかかり的なサンプルコードとしてはこのような感じになるのではないでしょうか。下準備以降は .NET Framework でも同じ("Compact" に限らない)なのですがね。

 ".NET が凄い" とか、"C# が凄い" という前に、"ビバ!Firebird" ってのが、今回の正直な感想です。


09/05/08

・彼からのメール

 "彼" はブログを再開したらしいです。

メシ休憩中に読んでたオレンジページの料理レシピが気になったからメモしてんだけど、ロードス島戦記まるっと書写した経験が意外なとこで活きたなと思った。

 それは "ファースト文庫" での出来事でしょうか?

おめでとうございます 後輩にアラフォーと言われて「頭皮はオーバーフィフティじゃ!」と言い返したものの涙がこぼれた年明けです。 所でVistaってどうなの?重いって話しだしxpの方が安定してるって聞いて、セブンがでるのを待つ方が良いのか良く分からんのです。

 後輩の "松中くん" とどっちがイケてますか?

「え!?うんこinランチ!?」って思ったらワンコインランチだった。

 (次へ移動)

ウォシュレットの水がまさに当たってる時に、空気を腹に飲み込むようなニュアンスで呼吸したら突然ゲートオープンして大量の温水を貪欲に吸い込むという人体の驚異現象を体験してしまったので、この方向で修行を積んだらコツカケも夢じゃないと思う。

 "逆バックドラフト"って感じでしょうか?

ここ数日酷い胃腸風邪こじらしてて、さっき何十年かぶりで淫乱忍法スリーピング脱糞。俺死ぬんじゃね? 泣きながら出勤前にファブリーズ買ってきた。 下痢が湯水の如く止まんねえ。

 それはちょっと...。

早出で超ヒマな時間を有意義に思索に使ってたら、昔のエロ漫画のコマ枠外に、何でかその作家が作業しながら聴いてる曲情報が書いてあったりしたのは何か意味あんのかなって気になって仕事にならなくて困ってる。SASが突拍子もなく動物園のニュース流して予備役に注意促すマスターキートンのアレみたいなモンだろうか。

 ライオンが檻からどうたらとかいう奴ね。

ジャイアン「オマエの物はオレの物、お前の悲しみは俺の悲しみだ‥」

 "混ぜるな危険"。

一昨日風邪悪化して休んだんだけど、その前日の深夜は熱でマジ体調最悪で、レジ前に置いてある画像の商品パッケージの絵がケツに見えるなーて朦朧と考えてたらもうどう見ても右に心持ち持ち上げたおねだり尻にしか見えなくなってしまい、レジ打ちながらチラチラそっち見てたら接客尻接客尻接客尻接客尻接客尻接客尻接客尻接客品出し接客尻接客尻フェースアップ尻接客尻接客尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻尻ってなっていったのでもはや生命の危機だこりゃってなったので(いかりやの真似で)仮眠中のオーナー叩き起こして30分早退しました。今は熱も引いて正常な精神状態なので悪魔超人の誰かにしか見えません。

 元メールには、この商品の画像が添付してありました。

箱○用にアマゾンでHDMIケーブル買ったんだけどさー、どう見ても本体にHDMI端子ねえよ。 何でアマゾン物売る前に俺に確認しなかったよ。 死ねよ。 偉そうに・・俺のどこがパソコンのお兄さんだ。 何が美来斗利偉・拉麺男だーっ!! (投石。シューマイが)

 たまに、Amazon の商品紹介間違ってるしね。例えば、"トランセンドジャパン COMPAQ 287496-B21準拠 512MB Proliant ML350 G3 TS512MCQ9087" を注文すると、ノート用のメモリが送られてきます("Proliant ML350" はサーバなのに)。"COMPAQ 287496-B21準拠 512MB Proliant ML350 G3" の本当の型番は "製品の特徴" にも書いてあるように、"TS512MCQ7496" が正解。"TS512MCQ9087" はノート用のメモリ。"商品の説明" には "コンパック用 287496-B21準拠 184Pins PC266 DDR Reg 512MBメモリ" とあるけど、それは間違いなくサーバ用DDRっしょ?注意喚起のメールを送ったけど音沙汰なし。ちなみに、"TS512MCQ7496" は 12,000円前後するシロモノ。

飯休憩時にオレンジページやらモーニングのクッキングパパを読み、これはと思うレシピがあれば事務所のメモ用紙を拝借して食材の切り方などの挿絵まで詳細に書写している俺のこの生き様を、世間では情報の万引きと呼ぶらしいんだぜ? GOODLUCK!!BABY!!

 ケータイのカメラで撮るヒトも居るらしいね。

TV見てたら深海魚特集でヌタウナギっていう、危険感じると水で溶いてないペペローションの倍ぐらいの粘度の粘液大量に分泌するやつ出てたんだけど、今方々に電話しまくってヌタウナギの市場押さえにかかってる。

 何に使うのかと。

ペペロンチーノとペペローションって、パッと見間違えるじゃん。 一昨日もさ、やたらヒリヒリすんなこれって思ってよく見たら

 どう間違うのかと。"ハバネロ"、"山芋"、"スピリタス" を思い出した。

今雑誌並べてたら、コミック快楽天BEASTっていうコンビニエロ漫画雑誌の表紙に「破れパンストはOKサイン〓」とか狂ったようなコピー書いてあって全くもって嘆かわしいっていうか、頭おかしいのが真に受けて片っ端からパンスト破れてる奴犯して回る事件起こったらこの出版社は社会的にどう責任取るつもりだとか、義憤っつうの?そういう感情に駆られて仕方ないんだけど、差し当たって出来る事っつったらセルフディフェンスとして穿いてるパンストに穴が空かない様に用心するだけなのが忸怩たる思いだ。

 キミは男な訳だが、パンストをどこに履く気だ?

育児スペース確保する為、高いだけで無駄に場所取るソファーを書斎に移動させるべく作業してんだけどさ、どうシミュレートしてみても俺の憩いの部屋がネカフェのPC付き個室(マビノギ・モンハン無料開放中)みたくなるのであってワープア気分満喫のステキ空間だと思う。

 第二子誕生、オメデトウ。

世界広しといえど、箱○版デッドラのゾンビをほんの5万3千人チョイ殲滅しとけっていう拷問実績「ゾンビジェノサイダー」を、二児の父という鋭いハンディキャップを背負いながらも易々と解除できるのは、北半球では俺だけだろうなと半ば確信してる。

 死んでるものをジェノサイドはできまい。

昨日見た夢で、なんかファミレスみたいな場所で営業してる風俗店で、AKB48の誰だかにクリソツのいい娘いるよとか言われ諾々と指名するも、来たのはどう見てもメイド服を着たドイツ連邦捜査局BKAのルンゲ警部似のクリーチャー(浦沢直樹のMONSTERの)。 ルンゲさんはおもむろにテーブル席の俺の横に座り、まるでアムウェイビジネスの勧誘風に逃げ道遮断。しかも俺の発言とか反応を例のあのエアキーボードでカタカタカタカタ頭のデータバンクに入力しながら熱シボを手渡したりローションを湯で溶いたりしているので僕の中の怪物がこんなに大きくなったので助けて!!!!!!!!!!!!!!!!!助けて!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!@@;;;;;;;

 浦沢直樹ネタ多いな。にしたって48人も居りゃ、誰かには似てるだろうな、きっと。

松村邦洋がマラソンしてて心肺停止状態陥ったとかいうニュース見たけどさ、そもそもあんなぬっへっほうみたいなミラクルボディにマラソン参加させるとか、誰がそんな深刻に頭悪い事企画してやがるんだ。

 無謀よな。

休みが増えて収入に危機感を感じる余りネットで週一バイト検索した結果、近所のかっぱ寿司に行こうかと思ってんだけどさ、かっぱ寿司ってやっぱ賄いはかっぱ巻きメインなわけだろ。キューカンパー撲滅協会長としての立場からも教条的にも食えないわけよ。あれだ、初日の分は「こんな御馳走、家で寝てる妻にも食べさせてやりたいので‥」って言えば免れると思うけど、それで店長の変なツボ押しちゃって次回から賄いの横にテイクアウトの包み置いてあったらもう終わりじゃん。 しかも店長あの人情ハゲ、「粋に計らってやったり」みたいなしたり顔してやがるの。イラッとくる。大体がさ、

 あり?キューカンバーはお気に召しませんでしたか。お口直しにコレなどいかがでしょうか

Office2007をゲットしました。これで私も丸ノ内でOLを続ける事ができますか。 あとその中のExcelとかいうソフトを使えば町内会のチラシ等を魔法の様に易々作成する事ができると聞いたので、帰ったらとりあえず勉強してどう見ても原版手書きの職場のレジ点検シートをエレガントに作成し、奴らの度肝を引っこ抜いてやろうと思います。

 実家の回覧板の回覧リストを作るのをやらされたな、こないだ。

俺ぐらいになると、料理レシピ見ててこの皿に合う副菜は何かとか常に考えてるんだけど、その思考が鍛えられるあまり、エクソダスという言葉が、スカトロと至高のハーモニーを奏でるマリアージュである事を発見してしまった。

 エクソダスと言えば、俺的には "時空間移動爆雷" なのだが...。

レストランで食事中とかに排便したくなった場合、男らしく、かつ同席者に不快な思いをさせる事なく中座を告げる遠喩として「ちょっとエクソダスに(不敵な微笑みと親指を立てながら)」と言うのが最適だとテーブルマナーの教本に書いてあった。

 天丼ネタか。

休憩中に廃棄のサラダ食ったら湯布院ドレッシングってのが付いてたんだけど、湯布院って湯布インッて表記したら矢追町成増っぽいのにねーって思っても周りに誰も理解してくれる人いないんで、老後はオモチャ屋の二階でTRPGコーナー経営して、一日中ヲタとじゃれあって死ぬまで過ごそうと今決めた。

 何が湯布院なのかはしらないけど、"ゆふいんドレッシング"って結構目にするね。


09/05/11

実家
 実家の隣向かいから伸びる枝に黒いものがたわわに実っていたので、「何だろう?」とよく見てみると "桑の実" だった。童謡 "赤とんぼ" の歌詞に出てくるアレだ。

 最近、どこも養蚕は盛んではないのでなかなか桑なんてお目にかからない。ちょっと実を失敬して、子供に食べさせて「ちょっと鏡で自分の舌を見てみ?」と言ってみた。このネタは実際に "桑の実" を食べた事のあるヒトなら理解できるハズだ。

 あと、グミも食べさせた...お菓子じゃないぞ。たまに渋いのに当たる事があるが、渋くはなかったらしい。

CF_TEXT
 ANSIアプリケーションだと、クリップボードテキストは CF_TEXT を処理すればいい。ANSI版Delphiだと、"Clipboard.Astext" でいい...常識的に考えればね。何だよ、"Visual Studio 2008" の仕様は?

 CF_UNICODETEXT に UTF-16LE の文字列が入るのは理解できる。しかし、"何故、CF_TEXT に UTF-8 が入ってる"訳?。そして、SHIFT-JIS はというと "CF_OEMTEXT" に入っている...なんじゃそりゃ?

 少なくとも "Visual Studio 2003" では、CF_TEXT には SHIFT-JIS が入っていた(2005は知らん)。05/11版 の TEAD 2.28 でこれを処理できるようにしておいたが、ANSI系のテキストエディタにはキツイ仕様だな。クリップボードからVSのバージョンを調べる手段はないし。


09/05/12

MECSUtils ver1.10
 Mae氏より MECSUtils のバグ報告を頂いたので、その内容を反映した "MECSUtils ver1.10" をリリースしました。具体的には、"MecsIsFullWidth() のインデックスが一つズレている" というものです。

 See Also:


09/05/13

Zlkonウィルス(通称 "GENOウィルス")/Gumblarウィルス
 お客さんのがやられたらしい。これに感染したかどうかはすぐに解る。

 複数の症状に該当する場合には、このウィルスにやられている可能性が高い。

 駆除方法はちょっと面倒。最初に以下の手順をナナメ読みし、必要なものは事前にDLしておく事。但し、DLは感染していないPCで行う事。何故なら、ウィルスの作用によってツールがDLできない事があるからだ。

  1. 使用したすべてのブラウザのキャッシュを消去
  2. レジストリエディタ(regedit.exe) を、適当な場所にコピーして "re.com" にリネーム。
    これを実行するとレジストリエディタを起動できる。
  3. レジストリエディタを起動したら、[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32] を確認。
    AUX または AUXn(n=1~9) が見慣れないフルパスのファイル名になっているので、それを控えておく。
  4. 改竄された AUX の値を "wdmaud.drv" に変更
  5. 控えておいたフルパスのファイル名をパス名とファイル名に分離。
  6. パス名の場所にあるファイルと全く同じ名前のファイルをメモ帳等で作成し、上書きコピー。
  7. SDFix.exe を実行して解凍し、"C:\SDFix" に置いておく。
  8. ComboFix.exe を解凍し、"C:\ComboFix" に置いておく。
  9. セーフモードで起動
  10. "%temp%" 内のファイルを可能な限り削除
  11. "%SystemRoot%\Temp" 内のファイルを可能な限り削除
  12. "C:\SDFix\RunThis.bat" を実行。Y/A/N と聞かれたら "Y" で。
  13. 再起動が掛かるが、ここもセーフモードで起動。自動的に2度目の SDFix が実行される。
  14. SDFix が完了したら、"C:\ComboFix\ComboFix.exe" もセーフモードで実行する。
    場合によっては "ComboFix.exe" が実行できないかもしれない。そのような時には、適当な名前にリネームして実行。
  15. ComboFix が完了したら、再起動(通常起動)。
  16. "%SystemRoot%\System32" にある "sqlsodbc.chm" を削除、または正常動作するPCから同名ファイルを上書きコピー。
  17. Adobe Reader 最新版をインストール。
  18. Adobe Flash Player 最新版をインストール。
  19. Windows Update を掛けてみる。実行できなかったら、テンポラリやキャッシュを消して再起動。
  20. パスワードを要求されるFTPのアカウントを持っていたのなら、すべてのパスワードを変更。
  21. 復元機能をオフにし、既存の復元ポイントを破棄する。
  22. 復元機能をオンにし、スタートメニューから [アクセサリ| システムツール | システムの復元] で最新の復元ポイントを作成する。
 よく解らなければ、知り合いでPCに詳しいヒトを探すしかないかも。亜種が存在するようなので、上記の駆除方法でも対処できない事例があるかもしれない。

 Webのサイト管理者がこのウィルスに感染した場合、管理していたサイトのFTPパスワードが盗まれ、Zlkonウィルス感染源となるサイトがまた一つできるらしい。Webサイトを構築している方はご注意あれ。

Zlkonウィルス(通称 "GENOウィルス")
 要は "Adobe Reader/Acrobatに新たな脆弱性、回避策はJavaScript無効化" コレを狙ったものだと思われる。時期的に "ゼロデイ・アタック" だったのね。しかも、修正パッチが出たのは昨日じゃねーか。Adobe Reader が9.1.1 よりも前のバージョンの場合には速やかに 9.1.1 にアップデートされたし。なお、現在の Flash Player の最新版は 10.0.22.87 となっている。

 現在のトコロ、Vista や Windows 7 は食らわないようだけれど、Vista/7でも感染する亜種が出ないとは限らないので、事前に対策をする事をオススメします。


09/05/16

Zlkon(GENO) / Gumblarウィルス/JSRedir-R
 パンデミック中らしい。ソフトウェア開発者のハズなのに、"何故かお客さんのPCの不調を治す仕事が多い" 私が言うのだから間違いない...今回のウィルスは "感染したら最悪" クラスだ。確かにクリーンインストールすればいいのだろうが、それで失われる時間は戻らない。仕事用のPCが感染したとして、"仕事ができるようになるまでに復旧する時間(PC環境整備の時間)" を考えたら、ちょっとだけ時間を割いて対策した方が得策ではないだろうか?

 もう少し情報を。

 Adobe Reader は [ヘルプ | Adobe Reader について...] でバージョンをチェックできる。対策されたバージョンは以下の通り。

バージョン 対策バージョン
9.x系 9.1.1以降
8.x系 8.1.5以降
7.x系 7.1.2以降

 Windows 2000/XP/Vista なら、特に事情がない限り 9.1.1 へのバージョンアップをオススメ。社内のすべてのPC用にアップデータをDLしたい場合にはこちらから。

 Adobe Flash Playerこちらからインストールされているバージョンを確認できる。とにかく最新版へのアップデータが必要。

 現在、このウィルスは "IE(IEコンポを使ったブラウザ含む) + 2000/XP"の環境を狙い撃ち している。そのため、Firefox(IE Tab とかを使っていなければ)/Opera経由では感染しない。Vista も感染しない。但し、それはスクリプトが意図的にバージョンを確認しているからで、この制限が外れた場合には今以上の感染が考えられる。「あー、俺の環境はセーフ」なんて思わないでさっさと対策すべし。

 「Webサイト持ってないもん」「ブログだからFTP使ってないもん」ってのは甘すぎる。とにかく駆除がやっかいなのだ。今のうちに情報を集めて対策するに越したことはない。亜種が出てからでは遅いのだから。

 See Also:


09/05/18

Zlkon(GENO) / Gumblarウィルス/JSRedir-R
 サイトがウィルスに感染しているかを調べる方法(安全に?ページのソースを見る方法)。

  1. メモ帳を開く。文字化けするのがヤならTEADを開く(他のテキストエディタでもできると思う)。
  2. [ファイル | 開く] でファイルオープンダイアログを表示させる。
  3. "ファイル名" に URL を入力する。
 </head> と <body> の間に、見慣れない難読化されたJavaScriptがあったらアウト。

 XP等では、特別な補助プログラムなしに "ファイルを開く" でサイトのソースを閲覧する事ができる...と思ったが、IEの機能を使ってDLするのでキャッシュに残ってしまうな。


09/05/20

MECSUtils v1.20
 作成中。MecsNormalize() が2000 に対応していたり、MecsCopyC() 等の結合文字列対応ルーチンが組み込まれています。結合文字テーブルは Mae氏の MecsUtilsExt.pas を参考にしています(早い話がパクっています)。検証が済んだら CodeCentral にポストします。ドキュメント は既に出来上がっています。

 難しい所なのですが、結合文字列はあくまでも文字列であり、コードポイントでの処理を行う必要もある事から、既存の手続き/関数を結合文字列対応させるのはやめにしました。

MECSUtils v1.20
 リリース。

結合文字列サポート関数には欠陥がある
 過度に期待されても困るので、最初に書いておきます。MECSUtils の結合文字列サポート関数はある意味普通に動作しますが、正しくサポートしているとは言えません。

 結合文字列の判定を結合文字テーブルで行っていますが、"どの基底文字とくっつくのか?" の判定が行われないため、"か+濁点" は 1文字とみなされますが、"A+濁点" のような有り得ない組み合わせも1文字とみなされてしまいます。

CharNextW
 結合文字列を判断するのに "CharNextW()" を使う事ができます。但し、Vista以降でしか結合文字列を判断せず、サロゲートペアは考慮されません。サロゲートペアを自前で考慮しようとしても、サロゲートペアの時だけ何故かLow-Surrogateへポインタが移動します(結合文字列の場合は文字の先頭なのに?)。しかも、"サロゲートペア領域の結合文字" というのが存在するため、結局は使えない事になります。Word2007 とかの部分文字列の制御用に結合文字列サポートAPIが必須なハズなので、どこかに結合文字列を判断するAPIがあるハズなのですが...?

正規化(標準化)
 正規化(標準化)APIを使う場合、XP/Serever 2003 では"Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1" または Internet Explorer 7.0 以上が必要となりますが、NT3.1 からサポートされている FoldString() でも、フラグの組み合わせによって NFC/NFD/NFKC/NFKD での正規化(標準化) が可能のようなのでロジックを変更してみました。

 ただ、時期的なことを考えると、Unicodeのすべてのコードポイントを正しく正規化(標準化)できるとは思えません。XP以前のOSではオマケの機能だと思っておいたほうがいいかもしれませんね。


09/05/21

CharNextW
 評価コードを(Delphi 2009用)。

var
  P: PWideChar;
begin
  P := PChar(Edit1.Text);
  while P^ <> '' do
    begin
      ShowMessage(P);
      P := CharNext(P);
    end;
end;
 
エレメントインデックス 1 2 3 4 5 6 7 8 9 10
バイナリ (UTF-16) 0x0041 0x0042 0xD842 0xDFB7 0x91CE 0x5C4B 0x304B 0x3099 0x0043 0x0044
コードポイント U+0041 U+0042 U+20BB7 U+91CE U+5C4B U+304B U+3099 U+0043 U+0044
文字インデックス 1 2 3 4 5 6 7 8 9
文字 A B 𠮷 C D
結合文字列インデックス 1 2 3 4 5 6 7 8
結合文字列 A B 𠮷 が C D

 Edit1 に "AB𠮷野屋がCD" を入れて実験してみると、XPの場合、エレメント単位でしか移動しない。Vistaの場合、エレメントインデックスの8(U+3099) を飛ばしてくれるのはいいが、何故かハイ・サロゲート(0xD842)を飛ばしてしまう。これでは全く使い物にならない。ロー・サロゲートだったらポインタを戻せばいいような気がするだろうが、昨日の雑談にあったように "サロゲート領域にある結合文字" を処理できないので意味はない。

 それから、結合文字列の文字幅というのはレンダリングエンジン毎に異なる。Windows なら Uniscribe のバージョンとフォント(グリフ)によって異なる。だから、結合文字列の幅をWindowsで計算したものを Mac に持っていったり Linux に持っていったりしても正しいとは限らない。"が" という結合文字列は環境によって、全角2文字幅だったり全角1文字幅だったりする訳だ。"文字単位での切り出し" と "表示幅での文字列切り出し" という2つの用途を同時に満たす処理というものは "Unicode に於いては有り得ない" という事になる。結合文字列を考慮しないのならEAWにさえ気をつければいいのだが...。

 "吉"の字が化けたり、"が" が分離して見えたりする場合には、以下のフォントを使ってみて下さい。


09/05/24

文字コードとメール
 あっちこっちで関わってしまったので、補足。

 日本語でメールを送る際は、ISO-2022-JP で送るのが無難。何故なら、メールサーバが 7bit の文字コードしか処理できない事があるからだ。今でこそそんなメールサーバ(MTA)は少なくなったが、8bitの文字コードで送ったメールを 7bit しか処理できない MTA が中継すると、1bit を削ぎ落とすので復元できない文字化けを起こす。よって、メールには 7bit 文字コードの利用が推奨される。

 ISO-2022-JP は一般的に "JISコード" と呼ばれる事がある。これが混乱の元。"ISO-2022-JP は 7bit の文字コード" なのだけれども、一般に言われる "JISコード" というのは 8bit の文字コードだったりする。簡単に言えば、"半角カナを使わない JISコード は 7bit な文字コード" という事になる。

 ISO-2022-JP にも、JISコード にもイロイロな種類があるけれど、純粋な ISO-2022-JP には 半角カナは存在しない。半角カナ(JIS X 0201 片仮名文字集合)は 0xA1-0xDF であるから、8bit となってしまう。Shift-JIS から JISコードに変換すると、処理系によってはそのまま 0xA1-0xDF を通してしまうため、"ISO-2022-JP なメールにJISコードは使えない" という、理解に苦しむ現象が起きる事となる。

 Indy の話をすると、Ansi版 Indy10 の QuickSend は、String を勝手に ISO-2022-JP に変換して送ってくれる。何も考えなくていい。半角カナが含まれていても、自動で全角カナに変換される。ただ、問題がない訳じゃない。このままだと、メーラが文字エンコーディングを判断できないので、メーラによっては文字化けを起こす。メーラで文字化けを起こさないようにするためには、IdMessage.Send() を使うしかない。その際に、CharSet と ContentTransferEncoding を適切に指定しなくてはならない。

 メールは ISO-2022-JP か UTF-8 でしか送信しないと仮定する。ちなみに前者は Ansi用 で、後者は Unicode 用だ。日本人同士でのみメールを送るのなら ISO-2022-JP 、他の国にも送る可能性があるのなら UTF-8 という訳だ。返信の際は相手の文字エンコーディングに合わせるのがいいのだが(確実に読めるので)、それは考えない事にする。とにかく2つに絞って考えてみる。

 ISO-2022-JP の場合、CharSet に "ISO-2022-JP" を指定する。基本、これだけ。

 UTF-8 の場合、CharSet に "UTF-8"、ContentTransferEncoding に "base64" を指定する。件名(Subject)は BASE64 で 7bitエンコードし、"'=?UTF-8?B?'' + BASE64化したUTF-8の件名 + ''?=''" とする。本文(Body)も BASE64 でエンコードする。こうすれば、すべて 7bit でメールを送信する事ができ、7bit しか対応しない MTA をすり抜ける事ができる。

 ...ところがなぁ。Unicode版 Indy10 だと面倒な事になるのさな。必ずBASE64化してから処理しないと暗黙の文字コード変換が行われるので、意図しない動作になってしまう。何故 BASE64化 すると正しく動くのか?と言えば、Unicode の U+0000~U+007F ...つまり、7bitの範囲は ASCII と互換性があるからあのQuickSendの変態コードはそれを逆手に取っている。だから、ISO-2022-JPには本来必要のない "件名(Subject)のBASE64化" が行ってある、という訳。

 ┐(´ー`)┌ヤレヤレ ですが、Unicode版 Indy10 の String は、単純に器を 8bit->16bit にしただけのもの と捉えておけば問題は少ないと思います。だから、その器に定数や変数を入れると Delphi の暗黙の文字コード変換が行われてマズい事になりますよ、Delphi & Indy の暗黙の文字コード変換をさせないため (&今時7bitしか受け付けないMTAのため) に BASE64 で7bit化しましょうね、と。今回の件はそういう事です。

 「これのどこが QuickSend なんじゃ!!」「つまりは QuickSend 使えん、って事かい!!」とか文句のあるヒトはフォーラムで直談判して下さい。

上の雑談を読むと...
 何のために UTF-7 が存在するのかが理解できるかと。殆ど使われてないけどね。

変態コード再び
 D2007 の QuickSend() 同等のコードは D2009 だと以下のようになる事が解ります。

var
  HostName, MailTo, MailFrom: String;
  Subject, Body: AnsiString;
  Subject2, Body2: String;
  i: Integer;
begin
  HostName := 'smtp.hoge.com';
  MailTo   := 'to@hoge.com';
  MailFrom := 'from@hoge.com';

  Subject  := '件名です(半角カナもOK)';
  SetLength(Subject2, Length(Subject));
  for i:=1 to Length(Subject) do
    Subject2[i] := Char(Ord(Subject[i]));

  Body     := '本文です';
  SetLength(Body2, Length(Body));
  for i:=1 to Length(Body) do
    Body2[i] := Char(Ord(Body[i]));

  TIdSMTP.QuickSend(HostName, Subject2, MailTo, MailFrom, Body2);
end;

 Indy10 の Unicode版 は "単純に器を 8bit->16bit にしただけ" というのを説明するにはいいコードです。但し、このコードは例え文字列定数をコントロール文字列で表したとしても日本語環境でしか正しく動作しない...つまり、ガイジンサンには再現できないコードです。"AnsiString = Shift-JIS(CP932)" という前提だからです。元々の変態コードは D2009 らしく、どの国の環境でも ISO-2022-JP なメールを送信できます。

type
  ShiftJis = type AnsiString(932);
var
  HostName, MailTo, MailFrom: String;
  Subject, Body: ShiftJis;
  Subject2, Body2: String;
  i: Integer;
begin
  HostName := 'smtp.hoge.com';
  MailTo   := 'to@hoge.com';
  MailFrom := 'from@hoge.com';

  Subject  := '件名です(半角カナもOK)';
  SetLength(Subject2, Length(Subject));
  for i:=1 to Length(Subject) do
    Subject2[i] := Char(Ord(Subject[i]));

  Body     := '本文です';
  SetLength(Body2, Length(Body));
  for i:=1 to Length(Body) do
    Body2[i] := Char(Ord(Body[i]));

  TIdSMTP.QuickSend(HostName, Subject2, MailTo, MailFrom, Body2);
end;

 これでもいいのですが...どのみちガイジンサンに説明するのは骨が折れるかもしれません。

 Unicode版は "Unicode->ISO-2022-JP" な QuickSend() を期待してしまいますが、"String = ANSIコードページ" という処理になっていますから、D2009 の場合、String(UnicodeString) には "Shift-JIS を 16bit化したもの" を格納しなくてはなりません。つまり、String(UnicodeString) には、U+0000~U+00FF 以外のコードポイントは使えない事になります。

 送られるメールは ISO-2022-JP なのに、Shift-JIS の変数が必要になるのが意味不明ですよね。"Shift-JIS -(コードポイントはそのまま)-> Unicode -> ISO-2022-JP" なんてまどろっこしくていけない。

uses
 ..., EncdDecd;


type
 ISO2022JP = type AnsiString(50220);
var
 Subject, body: ISO2022JP;
 HostName, MailTo, MailFrom: String;
 body2: String;
 i: Integer;
begin
  HostName := 'smtp.hoge.com';
  MailTo   := 'to@hoge.com';
  MailFrom := 'from@hoge.com';
 Subject  := '件名です(半角カナもOK)';
 Subject  := '=?ISO-2022-JP?B?' + EncodeBase64(PAnsiChar(Subject), Length(Subject)) + '?=';
 body     := '本文です';
 SetLength(body2, Length(body));
 for i:=1 to Length(body) do
  body2[i] := Char(Ord(body[i]));
 TIdSMTP.QuickSend(HostName, Subject, MailTo, MailFrom, body2);
end;

 元の変態コードでは、あらかじめ ISO-2022-JP を用意し、Indy の "Shift-JIS->ISO-2022-JP 変換ロジック" をすり抜けるようになっています。自前で変換した方が精神衛生上よろしいかと思いますので。

 原則 7bit なら Indy の自動変換ロジックをすり抜け可能ですが、Subject は "デフォルトの ANSIコードページ (=Shift-JIS)" 以外では BASE64 化しないとすり抜けられません。恐らく、Subject に使えない文字の判定処理(デフォルトの ANSIコードページ前提でしょうから)でコケているのだろうと思われます。


09/05/26

・Indy10
 「古いよ、RTM の Indy は?」 と理屈が通らないような事を言われた気がしたけど、とりあえず最新版をインストール。

 ...やっぱダメじゃん。挙動は変わってるし、確かにエラーにはならないけれど、本文(Body) が文字化けを起こす。

・"Delphi 2009 に最新版の Indy10 をインストールする"
 Tips を用意しておきました。


09/05/27

・Indy10
 「QuickSend() は エンコーディングしないよ?」 ...どっかで見たようなコード書いてからに。

 だーかーらー、ISO-2022-JP は7bit なんだから、QuickSend() で本文(body)がエンコーディングされなくったって正しく読めるハズじゃないか。D2007 の QuickSend() だって本文(body)は BASE64 エンコーディングされないんだから。同等の Send() のコードがよくて、QuickSend() がダメな理由にはなってないと思うんだけど?


09/05/28

・Indy10
 「くぁwせdrftgyふじこlp」 ...スミマセン、スミマセンm(_ _)m 悪いのは日本のメールのデフォルト文字エンコーディングがANSIデフォルトコードページと違う事なんですぅ(w

 私、別に変な事を言ってる訳じゃないと思うんです。ISO-2022-JP の Subject が BASE64 化されるのは構わないんです...7bit->7bit 変換にはなりますが、そうしないとメールヘッダの文字エンコーディングが何なのか判別不能なのですから。ただ、Body は Charset の指定ができるので、7bit->7bit 変換する意味がないんです。単に「Indy 10.5.5 の QuickSend() も本文を BASE64 変換しないのに文字化けするのは変でしょ?」てのが言いたかったのですが...。

 ISO-2022-JP の QuickSend() では、本文が文字化けしないようにして、かつ Charset なんかを自動で設定してくれればよかったのですが、最新版には

TIdSMTP.QuickSend(Host, Subject, MailTo, MailFrom, Body, 'text/plain''ISO-2022-JP''7bit');

 のように、MIMEタイプと文字エンコーディング、トランスファエンコーディング(Base64 / Quoted-printable / 7bit / 8bit)が指定できる、オーバーロードされたクラスメソッドが追加されたようです。ちょっとヤケクソ気味に見えますが(失礼)、変態コードを書くよりは直感的なので遥かにマシです。

 そもそも、Unicode 版 Indy はデフォルトANSIコードページやロケールに依存しちゃダメだと思うのです。元々の QuickSend() はそのアプリケーションを実行した環境によってメールの文字エンコーディングが変わってしまいますから(「QuickSend()でそんな運用をする方が悪い」と言われればそれまでですが)。文字化けの原因も "暗黙の文字コード変換" のせいだと思われるので、今後は、新設されたクラスメソッドの方を使うべきなのでしょうね。

 <!> Indy のバージョンは 最新版でも "10.5.5 のまま" な事に注意 <!>

・ちなみに

var
  Subject, Body, Host, MailTo, MailFrom: String;
begin
  Host := 'smtp.hoge.com';
  MailTo := 'to@hoge.com';
  MailFrom := 'from@hoge.com';
  Subject := 'テストです';
  Body := Subject;
  TidSMTP.QuickSend(Host, Subject, MailTo, MailFrom, Body, 'text/plain''UTF-8''base64');
end;

 コレやっちゃうと、Subject が ISO-2022-JP(with BASE64)で、Body が UTF-8 という事になっちゃいます。RFC の仕様としては間違っていませんが、メーラーによっては文字化けするので注意が必要です...って、よくよく考えたら Subject は思いっきりロケールに依存するじゃねーか...orz

Windows Vista SP2
 導入。累積パッケージじゃないので、無印にインストールする場合には "無印->SP1->SP2" としなければならない。導入後は...あんまり変わらないなぁ。実際、変更点の多くはモバイル機の方がメリットを享受できるように思う。

・ファイル名として正しいか?を判断する
 ネタ元はこちら

function IsFileName(const S: TFileName): Integer;
const
  RSV: array [0..24of String = ('CON''PRN''AUX''CLOCK$''NUL',
    'COM0''COM1''COM2''COM3''COM4''COM5''COM6''COM7''COM8''COM9',
    'LPT0''LPT1''LPT2''LPT3''LPT4''LPT5''LPT6''LPT7''LPT8''LPT9');
var
  i, ret: Integer;
begin
  result := 0;
  if Trim(S) = '' then
    begin
      result := -2;
      Exit;
    end;
  for i:=1 to Length(S) do
    begin
      ret := PathGetCharType(S[i]);
      if ((ret and GCT_LFNCHAR) = 0and ((ret and GCT_SHORTCHAR) = 0then
        begin
          result := i;
          Break;
        end;
    end;
  if result = 0 then
    if StrUtils.AnsiIndexText(ChangeFileExt(S, ''), RSV) >= 0 then
      result := -1;
end;

 戻り値が0ならOK。正の数が返ってきたらその位置の文字が不正。-1なら予約語が使われている。-2なら指定した文字列が空。コードは D2009用ですが、WideSting を用いれば D2007 またはそれ以前用の関数が作れるので試してみて下さい。

Delphi 2009 Update 3 & 4 & 5(Boost)
 導入。AnsiLeftStr/AnsiMidStr/AnsiReverseString/AnsiRightStr がラウンドトリップを起こさなくなったり、ジェネリクス関連のバグが多数潰されていたりする。矩形バグはFixedリストに載っているが、実際には直っていない。

 Vista の場合、自動アップデートではなく、更新プログラムをDLして、"管理者として実行" した方がいいかもしれない。当方の環境では、"インストールプログラムには、ファイルを修正する特権がありません" エラーが数回発生した。但し、[再試行]ボタンを押すことによってインストールは続行可能だった。

 あと、Aboutダイアログを確認すると、適用されているアップデートのトコに "Update 3" は存在せず、 "Update 1"、"Help Update 1"、"Update 4" しか見当たらない。バージョンは 12.0.3420.21218 で正しいのだが。


09/05/31

宇宙戦艦ヤマト
 今度、"復活篇" というのが公開されるとか...ただ、この話は何度も聞かされたっけなぁ。期待せずに待つことにしよう。

 やっぱり自機ですね。プラモデルもあるんですよねー。

コスモ・ゼロ(from2)

 これは 初代の1面と4面ですね。天井に地面があるのは空洞惑星だからですね。"真上と真下" にやられたのは自分でしたけどね。

ガミラス本星火山(from1)

 ザブはウザイですよね。急にワープしてくるんだもん。

瞬間物質移送器(from1)

 モアイもウザイです。

11番惑星(from2) 11番惑星(from2)

 OPでおなじみゼロス要塞です。

大型宇宙要塞(from3)

 ボスです。切らなきゃいけないのはコードじゃなくて、"自分の手足" だったりするんですけどねー。

マグネトロンウェーブコントローラ(from1)

 人工太陽はヤバいです。え?初代でした?IIじゃなかったでしたっけ?

人工太陽(from1)

 リップルレーザーは強力です。

衝撃砲(from2)

 GRADIUS2(MSX) の3面です。音楽がステキ。

11番惑星_2(from2)

 GRADIUS2(MSX) 4面の浮遊大陸です。ここ木星なんですってね。

浮遊大陸(from1)

 GRADIUS2(MSX) 5面のワンショットです。コロナはショットで撃たないと通過できません。沙羅曼蛇のプロミネンスは撃っても無駄ですけどね。

コロナを波動砲で(from1)

 GRADIUS2(MSX) 6面に出てくる緑色の機雷です。機雷はキライ。

宇宙機雷(from2)

 GRADIUS2(MSX) と言えば伝説の武器 "ファイアーブラスター" ですよね。V にも出てくるんですよね。それにしても、"目的の星に行って戻ってくる" ってのはツライ道のりですよね。

火炎直撃砲(from2)

 これが何だったのかよく解りません。ローリングオプション?ローリングシールド?

アステロイドベルト(from1)

 これもよく解りません。EPISODE II(MSX) 3面のスプレッド砲?同じく3面のブラックホール地帯?それともスプレッドボム?星が吸い込まれない奴ってありましたっけ?

ブラックホール砲(from3)

 以上、グラディウスでした、って...アレ?

グラディウス
 「グラディウスの元ネタはヤマトだろ、常考?」ってネタは以前にもやりましたが、反応が薄かったので(w 画像には代替テキストが設定してありますので、本当の意味を知りたい時には参考にして下さい。


 BACK   古いのを読む   新しいのを読む