C++Builder好きの秘密基地 このページをアンテナに追加 RSSフィード

2013-06-16

第5回 Delphi talksに参加してきた

この手のイベントに参加するのは本当に久しぶり。楽しい時間を過ごせました。
LTのネタは諸事情により2年3ヶ月ほど塩漬け状態な、コードフォーマッタープラグインネタ。

あまり役に立たない、昨日使用したプレゼンを公開します。
ちなみに、プラグインそのもの(RAD Studio XE用)はhttp://a7m.sakura.ne.jp/APPS/UncrustifyRS_1.00.7zにて公開中。ソースはMPLで配布しているので、ご自由にお使いください。ビルドし直せばXE4とかでも動くはず。(多分)
デブキャンでネタにしたOpen Tools APIについてはここで公開しています。

2012-12-09

UnicodeからShift-JISへの変換、どうする?

なし崩し的にDelphi Advent Calendar 2012に記事を書く羽目になった件について。(ぉぃ
まぁ、実業務でのちょっとした覚え書きな件もあるので、いい機会だし久しぶりに更新してみる。

ここ数年でプログラミング環境はUnicodeを意識せざるを得なくなった。DBエンコーディングUTF-8であることなんて良くあること。コードを書く側としてはエンコーディング変換とかはフレームワークの類いがよろしくやってくれるから余り気にする必要は無いはず。
それに、C++11でUnicodeリテラルが導入されたから、こんな感じで、いろいろアレなことが出来る。

#include <vcl.h>
#include <stdio.h>
#pragma hdrstop

#include <tchar.h>

#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
    UnicodeString str(U"\u264aジェミニ\u264aの黄金聖闘士ご来席!\u264aジェミニ\u264aの黄金聖闘士ご来席!");
    ShowMessage(str);
    return 0;
}

こいつを実行するとこんな感じで、しっかりと星座記号が出力される。
f:id:A7M:20121208180432p:image

アプリケーションの内部はUnicodeだけど、それを加工してCSVに吐き出す場合、お客さんはUTF-8UTF-16なんてことは、わけわかめな世界であることが多々あることなので、要件定義として「CSVファイルのエンコーディングはShiftーJISとすること」ってのが追加されているはず。

VCLUnicodeからShiftーJISに変換する場合、素直にUnicodeStringからAnsiStringにキャストするのが定番と言えば定番。
以下のコードを追加して、Shift-JISに無い文字を出力するとどうなるか?

    AnsiString sjStr(str);
    printf("%s",  sjStr.c_str());

こんな感じで、コンソールに「?」マークとして出力される。
f:id:A7M:20121208182228p:image
結果をodでダンプすると、こんな感じ。
f:id:A7M:20121208182839p:image
0x3fなので、文字としてはShift-JISに存在しない文字は「?」に変換される。

でも、お客さんは「?」じゃ気に入らない。他の文字にしてくれとなるとどうするか?例えば、「_」(アンダースコア)にしてくれとか。
「s/?/_/g」じゃ駄目だよね?元々あった「?」までも置換されてしまう。

そんな場合は仕方ないので、WideCharToMultiByte APIを直呼びをする。

int _tmain(int argc, _TCHAR* argv[])
{
    UnicodeString str(U"\u264aジェミニ\u264aの黄金聖闘士ご来席!\u264aジェミニ\u264aの黄金聖闘士ご来席!");
    ShowMessage(str);

    // 変換出来無かった場合のデフォルトの文字(スペースに変換)
    const char* DefStr = " ";

    // バッファのサイズを取得
    int BufferSize = ::WideCharToMultiByte(932, 0, str.c_str(), -1, NULL, 0, DefStr, NULL);
    std::unique_ptr<char[]> szBuffer(new char[BufferSize]);

    // 文字列の変換
    int ret = ::WideCharToMultiByte(932, WC_NO_BEST_FIT_CHARS, str.c_str(), -1, szBuffer.get(), BufferSize, DefStr, NULL);

    printf("%s",  szBuffer.get());
}

でも、こいつには罠があって、変換できなかった文字に下駄文字(「〓」)のような全角文字は指定できない模様。その場合はどうしよう…。1文字単位でWideCharToMultiByteを呼び出してlpUsedDefaultCharの値をチェックするしか無いかも。

追記:
Delphiのコードが無い。ん〜!? なんのことかな フフフ…

2011-08-28

RAD Studio XEとF-Secure Internet Security 2011の相性問題

メインマシンのセキュリティソフトをウイルスバスターからエフセキュア インターネット セキュリティ 2011に乗り換えたのだけど、RAD Studio XEを起動すると「使用許諾コードが不正」と判断されてRAD Studioが起動しなかった
これは、エフセキュア インターネット セキュリティのディープガードに由来するもので、以下の手順でBDS.EXEをディープガードの検索対象から外せばOK。

  1. F-Secure Internet Security 2011を開く
  2. [コンピュータ|ウイルスとスパイウェア スキャン]を選択
  3. [除外したオブジェクトを表示]をクリック
  4. [オブジェクト]タブを選択
  5. [追加]をクリックして、"C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\bin\bds.exe"を選択
  6. [OK]をクリック
  7. [OK]をクリック
  8. [閉じる]をクリック

以上でRAD Studioが検索対象から外れるので、RAD Studioが問題なく実行される。

2011-08-17

C++BuilderではOpen Tools APIを使ったアドオンをデバッグできない件についての回避方法

C++BuilderではOpen Tools APIを使ったアドオンをデバッグできない件があり、これをQC#92188として登録したのだけど、Embarcaderoから回答があって一応の解決法が見つかりました。

以下の手順でアドオンのデバッグが可能。

  1. OTAを使ったプロジェクトをC++Builderで作成する。
  2. プロジェクトをビルドして、アドオンをインストールする。
  3. 一旦IDEを終了する。
  4. もう一度、IDEを起動してOTAを使ったプロジェクトを読み込む。
  5. ブレークポイントを設定する。
  6. プロジェクトを読み込んだIDEとは別のIDEを起動する。この段階であとから起動したIDEでもアドオンは有効になっている。
  7. プロジェクトを読み込んだIDEで、[実行|プロセスにアタッチ]を選択し、あとから起動したIDEのプロセスにデバッガをアタッチする。
  8. アタッチしたIDEでアドオンを実行する。

いわゆる「運用で回避」と言えなくはないけど、Delphiと比べて少々面倒なのは事実。
C++Builderでのアドオン作成は諦めていたから、朗報と言えば朗報。

2011-05-26

TBalloonHint::ShowHintの使い方

TBalloonHint::ShowHintに問題があるみたいで、代替にJVCLのTJvBalloonHintを使うというエントリーを書いたのだけれども、Embarcaderoの高橋さんからコメントがあって、再テスト。自分の勘違いで問題が無いことが確認できたのだけれども、以下の点に注意。

  • TBalloonHintは動的に生成せずにフォームに貼ったコンポーネントを使い回すこと。
  • ShowHintメソッドで指定する座標はフォームの座標ではなく、スクリーン座標を指定する。
  • ShowHintメソッドはヒント表示後すぐに終了する。HideAfterプロパティで指定した時間を待たないので、直後にdeleteなどで破棄するとヒントそのものが表示されない。

以下は正しく動作するコード例。TBalloonHintはコンポーネントとしてフォームに貼ること。

C++Builderの例:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  BalloonHint1->Title = _T("ヒントのタイトル");
  BalloonHint1->Description = _T("バルーンヒントを表示してみる。");
  BalloonHint1->HideAfter = 2000;

  BalloonHint1->ShowHint(Button1->ClientToScreen(Button1->ClientRect.CenterPoint()));
}

Delphiの例:

procedure TForm1.Button1Click(Sender: TObject);
begin
  BalloonHint1.Title := 'ヒントのタイトル';
  BalloonHint1.Description := 'バルーンヒントを表示してみる。';
  BalloonHint1.HideAfter := 1500;

  BalloonHint1.ShowHint(Button1.ClientToScreen(CenterPoint(Button1.ClientRect)));
end;

でも、TBalloonHint::ShowHintのヘルプがないんだよな…。