カテゴリー: general

  • C++Builder 2007 でのウィンドウメッセージ処理

    エンバカデロによる買収が決まったCodeGearですが、個人的には応援しています。

    Delphi は使いやすく、情報も豊富なのですが、私はとっくに Pascal よりも C++ に慣れてしまったので、できれば C++ Builder をメインに使いたいところです。

    Delphi の参考書や資料の多くは VCL について説明しているので、そのノウハウのかなりの部分は使えます。

    しかし C++ Builder に固有の話題についての情報はとても少ないのが現状です。

    Windowsプログラミング逆引きクロス大辞典

    Windowsプログラミング逆引きクロス大辞典

    「Windowsプログラミング逆引きクロス大辞典」にはTurbo DelphiとTurbo C++というかたちで、VB6 や .Net との比較がなされています。

    Turbo C++はC++Builderだと思って読むことができるので、CodeGear RAD Studio 2007を使う上で重宝しそうです。

    Delphi で「メッセージメソッド」と呼ばれている機能の実現方法が今日やっとわかりました。忘れないように書いておきます。

    mciSendString を使って mp3 ファイルを再生して、再生終了のメッセージを MCI から受け取る例です。

    VCLフォームアプリケーションにボタンをひとつ貼り付けて、以下のように記述。

    mmsystem.h をインクルードしないと MM_MCINOTIFY が未定義になります。

    C:\tone_a.mp3 を用意してボタンを押すと、音声再生が終了したらメッセージボックスが表示されます。

    //---------------------------------------------------------------------------
    // Unit1.h
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    //---------------------------------------------------------------------------
    // by nishimotz
    #include <mmsystem.h>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// IDE 管理のコンポーネント
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
    private:	// ユーザー宣言
    void __fastcall MMMCINotify(TMessage &Msg);
    BEGIN_MESSAGE_MAP
    VCL_MESSAGE_HANDLER(MM_MCINOTIFY, TMessage, MMMCINotify)
    END_MESSAGE_MAP(TForm);
    public:		// ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    
    //---------------------------------------------------------------------------
    // Unit1.cpp
    #include <vcl.h>
    #pragma hdrstop
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    mciSendString("open \"c:\\tone_a.mp3\" type Mpegvideo alias mp3", NULL, 0, 0);
    mciSendString("play mp3 notify", NULL, 0, Form1->Handle);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::MMMCINotify(TMessage &Msg)
    {
    ShowMessage("done.");
    mciSendString("close mp3", NULL, 0, 0);
    }
    

    END_MESSAGE_MAP(TForm) の後ろのセミコロンを忘れて、しばらくはまりました。

    VCL_MESSAGE_HANDLER に関する情報は RAD Studio のヘルプでも CodeGear のサイトでも見つけることができず、個人の方のウェブサイトを参考にさせていただきました。

  • 日記の表示モード

    先日、はてな日記の設定に「表示モード」という項目があることに気づきました。

    「日記モード」から「日記モード・見出し別ページ」「ブログモード」に変更することがいつでもできます、と書かれていたので、変更してみたのですが、そうすると他の方からブックマークしていただいたり「はてなスター」をいただいたものが無効になってしまうことに気づき、約1日で「日記モード」に戻しました。

    私がモードを変えている間に「はてなスター」をつけてくださった方がおられるのですが、そんな事情でご迷惑をおかけしてしまったようです。ごめんなさい。

    たまたま査読の仕事を抱えているときに「査読マニュアル」の存在を思い出すことができ、感謝しています。。。

  • 分散バージョン管理の意義

    いくつかのシステムに Mercurial をインストールして使い方を勉強しつつ、なぜ「バージョン管理システムを使うのか」について改めて考えました。

    まず「バージョン管理システムはバックアップツールだ」という主張は一見わかりやすいのですが、どうも違和感があるので、さらに考えた末、以前から考えてきたこと(数年前にソフトバンクのCVS本に書いたこと)と重複するのですが

    • バージョン管理システムは「無駄なバックアップを安全に消去するツール」である
    • バージョン管理システムは「リファクタリングを安全に行うツール」である

    と思えてきました。

    まず「バックアップの消去」について説明したいと思います。

    Windows のユーティリティに undup という重複ファイル削除ソフトがあるらしいのですが、バージョン管理システムは「賢いundup」ではないかと思うのです。

    以前と比べてバックアップを取ることは簡単になりました。モバイルPCも安価になり手軽になり、複数のマシンにコピーして作業することも日常的になりました。USBメモリも外付けドライブもネットワークストレージも手軽に使えるようになり、ついあちこちに気軽にバックアップコピーを取ってしまいがちです。

    しかし、本当に難しいのは「バックアップを取ること」ではなく「バックアップを捨てること」ではないでしょうか? あちこちにばらまかれてしまった重複ファイルを安全に削除するためにはどうしたらいいでしょうか? 完全に同じファイルなら安全に消すことができますが、もし改変があるなら、それを保存するべきかどうかを簡単に判断できるでしょうか?

    消去すべきファイルは、重複ファイルだけではありません。

    不要なファイルを簡単に見分けるための工夫として、ここ数年、私はファイル名の付け方の規則として

    • 一時ファイルには、先頭文字がアンダースコア(_)で始まるファイル名をつける

    ということを教わって実践しています。しかし、いろいろなソフトウェアの事情があり、この規則を徹底できない場合があったとすると、「保存するべきファイルか、一時的なファイルであるか」という区別は、ファイルそのものに記憶させるのではなく、メタ情報として外部に保存する必要が出てきます。

    バージョン管理システムのリポジトリとはまず「バックアップをすべきファイルかどうかを表す属性情報である」と捉えてはどうでしょうか。重複ファイルも一時ファイルも簡単に判断できる手段を提供するのがバージョン管理システムだと思うのです。

    もう一つの「リファクタリングの道具としてのバージョン管理」については、すでに多くが語られていると思うのですが、「プログラムを、機能を変えずに、構造を改良する」という作業のためには、「確実かつ効率的に過去の状態を参照できる(元の状態に戻せる)」という作業環境が求められます。ファイル群を丸ごとコピーしてしまうと、効率的に差分を表示することが難しくなります。

    バックアップとリファクタリングは目的が違います。バックアップは物理的に別のデバイスに保存する必要があるため、ネットワークを介した通信機能は必要です。しかし、リファクタリングはネットワークから切断された状態でも行われるべき作業なので、リポジトリがローカルに存在しないのはとても不便です。

    このように考えてみると Mercurial の分散バージョン管理という仕組みは、昨今のコンピュータ利用の現状にふさわしい枠組みではないか、と思います。

    ロック・アンロックをベースにしたRCSが大人数での分散作業に向いていない、ということで、コピー・マージ方式を導入したCVSが数年前に広く普及しました。それと同時に「伽藍とバザール」のモデル比較が話題になり、CVSはバザール型のオープンソース開発にふさわしいツールである、と考えられた時代がありました。しかしいま振り返ると、CVSは「バザール開発のツール」というよりも「みんなで分担してひとつの大きなものを作る」ための共同作業ツールであったように思えます。

    しかし現実に求められている問題の多くは「みんながそれぞれ自分のための派生物を作る」ことであり、さらに「派生物の差分を取捨選択して共有する」ことだったりします。そのためには、みんなが別々にリポジトリを持つ必要があり、しかもリポジトリ同士でマージを行うメカニズムがやはり必要なのだろう、と思います。