2011年8月2日

RAD Studio XE2 World Tour 2011

RAD Studio/Delphi/C++Builder XE2とそのお披露目のワールドツアーがアナウンスされています。まずは関係リンク。

RAD Studio XE2 World Tour
Sip from the Firehose : Want more…RAD Studio XE2
Delphi Insider: Win a copy of RAD Studio XE2 before you can buy it

RAD Studio XE2 and you | Reinvent The Wheel
A little bit about FireMonkey and Delphi XE2 | Andreano Lanusse Blog | Technology and Software Development | Delphi
FireMonkey Logo and Info (by Andreano)

Delphi / C++Builder / RAD Studioユーザー向け「XE2」先行販売のご案内

DelphiでMac向け開発。ネイティブクロス開発に踏み出すDelphi/C++Builder:Allegro Barbaro:ITmedia オルタナティブ・ブログ

発売は2011/09/01以降になる(2011/08/31以前ではない)模様です。既に特別バージョンアップ(2007/2009/2010/XEから)、ジャンプアップ(1.0~2006から)のキャンペーンもアナウンスされています。ところでXEの旧バージョンを利用できる件はXE2ではどうなるんでしょう。そしてStarter SKUについてもまだアナウンスがありませんは他のSKUから遅れて登場するようです(x64/MacOS XサポートやFireMonkeyなども含まれる模様)。

RAD Studio/Delphi/C++Builder XE2の新機能は以下の通り。
  • FireMonkeyと呼ばれる新しいUIフレームワークでHD/2D/3D描画をサポート
  • Delphiでx64をサポート
  • 単一ソースからプラットフォームを切り替えるだけでWindowsとMacOS Xのバイナリを生成(MacOS Xはクロス開発、リモートデバッグ)
  • DataSnapをモバイル、クラウド用に拡張(RAD Cloud)
  • LiveBindingsと呼ばれる新しいバインディングメカニズムで全てのビジュアル要素とデータソースを接続(DB系コンポーネントが不要に?)
  • VCLのルックアンドフィールをモダンなものに
  • RadPHPでモバイルデバイスに最適化されたwebアプリケーションやiOS/Androidデバイスのスタンドアロンアプリケーションを開発可能に
(以上意訳)

ワールドツアー(RAD Studio XE2 World Tour)は2011/08/04のオークランド(Auckland/NZ)でスタートし、2011/10/04のオーフス(Aarhus/DK)まで約2ヶ月に渡って各地でプロモーションが行われます。日本では2011/09/06の第20回エンバカデロ・デベロッパーキャンプがワールドツアーの一部、ということになります。また2011/09/12-14(PDT)にカリフォルニアのサンホセ(San Jose,CA/US)で行われるDelphi Live 2011でもプロモーションを行うようです。

またRAD Studio XE2のArc/Ent/Pro SKUがそれぞれ1名に当たるという抽選も行われます。申し込み期限は2011/08/31 23:59:59(PDT)です。詳しくはこのページの右上、"Enter to win a free copy of RAD Studio XE2 before you can buy it!"のリンクから。

さらに2011/08/04 17:00(JST)から開催のwebセミナー、9月まで待てない!7~8月はデベロッパーキャンププレセミナー 第2回 - 再演!「PHP Live! - ゼロから始めるPHPアプリの構築からデプロイまで」RadPHP XE2がチラっと見られるようです。

2011/08/04追記: 記事を更新しました。ワールドツアーの劈頭、オークランドはもう今日の09:00(NST)=06:00(JST)からです。

2011/08/04追記: オークランドのラウンチイベントをTe Waka o DelphiのJolyon Smithさんがレポートしています。

Te Waka o Delphi · RAD STUDIO XE2: Launch Event Report

2011年7月28日

RAD Studio/Delphi XEユーザ向Delphi Developer Certification無償キャンペーン締切間近

忘れかけていましたが、Delphi Certification ProgramDelphi Developer CertificationのRAD Studio/Delphi XE(Academicを除く/Starter SKUは含まれる)登録ユーザ向の無償キャンペーンの締め切り(2011/07/31)が迫っています。Delphi Certification FAQsQ: What is the free exam offer for registered Delphi XE and RAD Studio XE users?にあるように、プロモーションページでシリアル番号を入力することで無償テストコードを受け取り、そこから90日以内であれば"Developer Certification"を受験することができます。当然英語ですが、Delphi Developer Certification Exam Study Guideにあるサンプル問題程度の難易度ですので、それほどハードルは高くないと思います。

2011/07/31追記: 現時点(23:47)で上記のプロモーションは既に受け付けられない状態になっています。まぁそもそもどこの標準時を基準にしているのかも書いていない話なのでアレですが、日本人の感覚からするといかがなもんかなぁと。PDTベースだとまだ16時間もあるわけだし。

2011/08/02追記: 公式フォーラムのEmbarcadero Discussion Forums: Free Exam Offer for Delphi XE and RAD Studio XE Users, can't get test codeの情報によると現時点(2011/08/02 13:50JST)でプロモーションページが再びオープンとなっています。いつまでこの状態が続くのかはわかりませんが、まだ申し込んでいない方はお早めに。

2011年7月27日

Michael RozlogがEmbarcaderoを退職

DelphiプロダクトマネージャだったMichael Rozlogさんが2011/07/29(今週末ですな)でエンバカデロ・テクノロジーズを退職することを明らかにしました。

Michael Rozlog » Blog Archive » The time as come…

This is my last blog post for Borland/Inprise/Borland/CodeGear/Embarcadero as Friday the 29th is my last day.ということだそうです。ちょうど一年前のNick Hodgesさんの一件といい、新バージョンのリリース直前にマネージャが抜けるってのはどうなんでしょうね。直接XE2との関係はなさそうです(追記参照)。

Michael Rozlogさんの新しいblogは

TECHMANA

で、2011/07/30スタートとのことです。

2011/07/28追記: EDNプログラムマネージャだったJohn Kasterさんも2011/12/27でエンバカデロ・テクノロジーズを退職していたんですね。いまごろ気付きました。John Kasterさんの新しいblogは

John Kaster

です。

2011/07/30追記: Michael Rozlogさんは2011/01からセールスに異動していたようで、それが理由では?という見方もあるようです。というわけで一部修正。

2011年7月26日

TListの新しいメソッドSortList/IndexOfItem/ExtractItem/RemoveItemとTDirection

Delphi 2010でTListクラスにSortListIndexOfItemExtractItemRemoveItemというメソッドが追加されています。

TList.SortListはQuickSortの比較関数を"const TListSortCompareFunc" = "reference to function(Item2: Pointer, Item1: Pointer): Integer;"、つまり無名メソッドで渡すことができる、というもので、従来のSortのように比較関数を別途記述する必要がありません。たとえばフォーム上にTButtonとTMemoをひとつずつ配置しておき、
type
  TTestItem = class(TObject)
  private
    FNum: Integer;
    FStr: String;
  public
    constructor Create(ANum: Integer; const AStr: String);
    property Num: Integer read FNum;
   property Str: String read FStr;
  end;

constructor TTestItem.Create(ANum: Integer; const AStr: String);
begin
  inherited Create;
  FNum := ANum;
  FStr := AStr;
end;

procedure TForm1.Button1Click(Sender: TObject);

  procedure ShowList(List: TObjectList; const Caption: String);
  var
    Index: Integer;
    TestItem: TTestItem;
  begin
    Memo1.Lines.Add(Caption);
    for Index := 0 to List.Count - 1 do
    begin
      TestItem := List.Items[Index] as TTestItem;
      Memo1.Lines.Add(Format('Num=%d Str=%s',
                             [TestItem.Num,TestItem.Str]));
    end;
    Memo1.Lines.Add('');
  end;

var
  List: TObjectList;
begin

  List := TObjectList.Create(True);
  try
    List.Add(TTestItem.Create(5,'Five'));
    List.Add(TTestItem.Create(3,'Three'));
    List.Add(TTestItem.Create(1,'One'));
    List.Add(TTestItem.Create(2,'Two'));
    List.Add(TTestItem.Create(4,'Four'));

    ShowList(List,'Before sort');

    List.SortList(
      function (Item1, Item2: Pointer): Integer
      begin
        Result := TTestItem(Item1).Num - TTestItem(Item2).Num;
      end);

    ShowList(List,'After sort (Num)');

    List.SortList(
      function (Item1, Item2: Pointer): Integer
      begin
        Result := CompareStr(TTestItem(Item1).Str,TTestItem(Item2).Str);
      end);

    ShowList(List,'After sort (Str)');

  finally
    List.Free;
  end;

end;
こんな感じでSortListのパラメータに直接比較関数を記述できます。無名関数の記述が気持ち悪い(セミコロンの付きかたが違う、とか)という点はともかく、比較関数そのものはわかりやすく書くことができます。

一方IndexOfItem/ExtractItem/RemoveItemはIndexOf/Extract/Removeに追加のパラメータとしてFromBeginning/FromEndという2値の列挙型TList.TDirectionを受け取り、これがFromBeginningならば対象アイテムを(従来通り)先頭から検索し、FromEndならば対象アイテムを末尾から検索するというバリエーションです(なぜオーバロードにせず別のシグネチャを与えたのかはわかりません)。

元ねたはMarco CantuさんDelphi 2010 Handbook

2011年7月25日

Windows Vista/Server 2008/7/Server 2008 R2でIPv6コンポーネントを無効にする

Windows Vista以降のOSではIPv4とIPv6がデュアルIPレイヤという形で統合されて実装されていて、IPv6が不要であってもアンインストールできなくなっています。そこでIPv6が不要な(あるいは邪魔な)場合にIPv6コンポーネントを無効にする方法(ただしIPv6のループバックインタフェースは無効にならないので注意)。とりあえずメモ。

診断ツール Fix it: Windows Vista、Windows 7、および Windows Server 2008 で特定の IPv6 (Internet Protocol version 6) を無効にする方法に関する問題

直接レジストリ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\DisabledComponents
の値(DWORD)を、
  • 0: IPv6有効(デフォルト)
  • 0xFFFFFFFF: IPv6無効
  • 0x20: プレフィックスポリシーでIPv4を使用
  • 0x10: IPv6ネイティブインタフェース無効
  • 0x01: IPv6トンネルインタフェース無効
と書き換えても問題ありませんが、レジストリの書き換えを行ってくれるFix itウィザードも用意されています。

またIPv6を無効にするまでもないけれどもIPv4を優先に設定したいような場合はコマンドプロンプトから

netsh interface ipv6 show prefixpolicies
で表示されるプレフィックス"::ffff:0:0/96"(IPv4-Mapped IPv6 Address)が最優先になるように、管理者権限を持つコマンドプロンプトから

netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 100 4
(最後から2番目の値が優先度(大きいほうが優先)で最後の値が当該プレフィックスのラベル)とすればいいようです(こちらはIPv6を有効にしたWindows XPでも使えます)。デフォルトの設定に戻すときは管理者権限を持つコマンドプロンプトから

netsh interface ipv6 reset
として再起動します。

元ねたはセキュリティホール memo2011/07/12の記事と、IPv4 を IPv6 より優先にするおよびWindows 7でIPv4をIPv6に対して優先にする方法 - 徒然日記(2011-03-30)

2011年7月23日

DDevExtensions 2.4リリース

Andreas HausladenさんDDevExtensionsがアップデートされてVersion 2.4になっています。Delphi 2007/2009で[Shift]+[F3]による逆方向の検索ができるようになるなど、細かく新機能が追加されています。

DDevExtensions 2.4 | Andy’s Blog and Tools

2011年7月19日

デバッグ時にEIPを移動する

RAD Studio/Delphi/C++Builder 2010以降のIDEのデバッガ上でプログラムをデバッグ実行しているときに(ブレークポイントにヒットするなどして)実行が停止した状態で、次に実行する行を示す矢印(Instruction pointer symbol)を他の行にドラッグすることで任意の場所から実行を継続することができる、という機能が追加されています。同一ソースファイル上であれば別の関数のコードに移動することもできますが、実際に実行を継続すると概ねエラーになります(スタックの状態とか自動変数のことを考えれば当たり前ですけど)。

ヘルプを確認してみるとDelphi 2010 および C++Builder 2010 の新機能 - RAD Studio (日本語)のコード エディタの変更点の最後に
アイコンのドラッグ アンド ドロップ: コード エディタ ウィンドウの左マージン領域で、特定のアイコンを移動できるようになりました。 たとえば、
(略)
指示ポインタ記号: このアイコンは、(デバッグ中に)次に実行するコード行を示します。

とこっそりと書いてありますが、気づいていませんでした。過去のデベロッパーキャンプで聞いたことがあるような気もしますが、すっかり忘れていたのでとりあえずメモ。

元ねたはMarco CantuさんDelphi 2010 Handbook

2011年7月13日

Microsoft Monthly Update 2011/07

今日はMicrosoftのセキュリティアップデートの日です。
MS11-053
MS11-054
MS11-055
MS11-056

今回の更新をもって
  • Windows Vista Service Pack 1 (x86/x64)
  • Windows Server 2008 (RTM)
  • Office XP
  • .NET Framework 3.0/3.0 Service Pack 1/3.0 Service Pack 2/3.5
  • Exchange Server 2007 Service Pack 2
のサポートが終了になります。Windows Vista/Windows Server 2008についてはService Pack 2 (x86/x64)を、.NET Frameworkについては3.5 Service 1を、それぞれ適用することが推奨されています。元ねたはサポート ライフサイクル終了に伴うセキュリティ更新プログラム配信終了の予告 - 日本のセキュリティチーム - Site Home - TechNet Blogs

2011年7月11日

FindCmdLineSwitch関数

SysUtils.FindCmdLineSwitch関数はコマンドラインパラメータに特定のスイッチが指定されているかどうかを判定する関数で、Delphi 4以降に存在していますが、Delphi 2010までは特定のスイッチの有無を調べるだけで、それ以上のことをしようと思うと結局ParamCountParamStrのお世話になるしかなく、いま一つ使えない関数でした。ところがDelphi XEでは4つめのオーバロード関数が追加され、第4パラメータのSwitchTypesで指定した方法でスイッチのパラメータを取得できるようになり、使える関数になりました。これは非常に便利です。とりあえずメモ。

元ねたはMarco CantuさんDelphi XE Handbook

2011年7月8日

3rd anniversary

このblogを始めて丸3年になりました。当初は過疎blogでしたが、いまでは本家エンバカデロ・テクノロジーズからもリンクしていただくまでになり、ありがたく思っています。

さて、この1年間のエントリは205件(2010/07/08-2011/07/07)と週平均4エントリに迫っており、なかなか頑張った感じです。

2010/07にBloggerに追加されたアクセス解析の統計情報から月別ページビュー(PV)を。

2010/07: 4,267
2010/08: 4,518
2010/09: 4,854
2010/10: 5,547
2010/11: 5,149
2010/12: 5,570
2011/01: 5,291
2011/02: 6,010
2011/03: 5,587
2011/04: 6,308
2011/05: 6,950
2011/06: 6,882
2010/07-2011/06合計: 66,977

平均的には1日あたり平日は約250+PV、休日は約100+PVといったところでしょうか。またページ別ではWindowsのSNP(Scalable Networking Pack)を無効にするのPVが圧倒的に多く、このページだけで約5000+PV、全体の約8%を占めています。これはGoogle(jp)上の"SNP 無効"という検索で非常に上位に(それもGoogleがアルゴリズムの変更を行うまで元ねたの日本マイクロソフトのAsk the Network & AD Support Teamのアーティクルよりも上位だった)出てくるのが理由だと思われます。bing(us)では同一のキーワードでもそれほど極端に上位ではないので、Blogger上のコンテンツであることが有利に働いているのでしょう。次点はMS11-025によって発生する問題とその対策で、わずか2ヶ月で900+PVと、この問題がいかに影響が大きく、かつMicrosoftからの情報発信が不十分だったか、ということを物語っていると思われます。
一方、国と地域別では当たり前ですが90%以上を日本からが占めていて、アメリカ合衆国、オランダ、大韓民国と続いています。アンゴラやラトビアなどからは一時的に一定期間だけまとまったアクセスがあるので、これはプロキシとして利用されているのではないかと思っています。

今年はこの後RAD Studio/Delphi/C++Builder XE2(Pulsar)のリリースが控えています(8月とも9月ともいわれていますが、さて…)。去年からの宿題であるクロスプラットフォーム(MacOSサポート)やWindows x64サポートの第一歩になるDelphiのx64版など、なかなか楽しみです。

そういえばGoogleのPageRankは長らく"2"でしたが、数日前にふと確認したら"3"に成り上がっていました。これもご贔屓にしてくださっているみなさまのおかげです。

2011年7月6日

2011/07開催のウェブセミナー

2011/07/21 17:00-18:00(JST) 9月まで待てない!7~8月はデベロッパーキャンププレセミナー 第1回 - 再演!「今さら聞けない(?!)C/C++ポインター再入門」

第20回エンバカデロ・デベロッパーキャンプ開催決定

第20回エンバカデロ・デベロッパーキャンプは2011年09月06日に開催されます。

エンバカデロ・デベロッパーキャンプ
第20回 エンバカデロ・デベロッパーキャンプ

今回はエンバカデロ・テクノロジーズ チーフエヴァンジェリストのDavid I (David Intersimone)さんが来日して、RAD Studio/Delphi/C++Builder XE2(仮称、コードネームPulsar)についてディープなセッションを繰り広げる予定とのことです。またG6セッションは例によってはかせと銅鑼娘はやしさん司会の『ライトニングトーク「共有!みんなの開発事例、開発経験、テクニック」』で、参加者募集中だそうです。

また『9月まで待てない!7~8月はデベロッパーキャンププレセミナー 』というタイトルで3回に渡ってWebSeminarが行われます。第1回、第2回は以前のデベロッパーキャンプの再放送ですが、第3回はタイミング的に面白い話が聞けるかもしれません。

2011/07/21追記: プレセミナーは「再放送」ではなく「再演」なんですね。

2011/08/17追記: EDNの記事のリンクを追加しました。

2011年7月2日

[書籍]Delphi XE Handbook

Amazon.comで注文した

Delphi XE Handbook (Amazon US)/Marco Cantu著/CreateSpace/ISBN 978-1463600679/34.50USD

が配送されてきました(今回の配送は日本郵便でした)。2011/06/21に注文して11日目の到着、34.50USDにShippingの5.48USDで締めて39.98USD=3,233JPY(暫定)3,253JPY(1USD=81.366JPY)でした。

2011/07/17追記: 日本のamazonでも扱いが始まっています。

Amazon.co.jp: Delphi Xe Handbook: A Guide to New Features in Delphi Xe: Marco Cantu: 洋書

2,908円で送料がかからないので、円高が72円台に進んだりしなければamazon.co.jpのほうが安いですね。

2011/07/31追記: カードの利用明細によると3,253JPY(1.00USD=81.366JPY)で決済されました。amazon.co.jpでは2,836JPYで配送無料ですから、やはりこちらがお勧めです。

2011年7月1日

RAD Studio/Delphi/C++Builder XE Help Update 3

RAD Studio/Delphi/C++Builder XEのHelp Update 3がリリースされています。

Help Update 3 for Delphi XE and C++Builder XE now available
リリース ノート: Delphi XE および C++Builder XE Help Update 3
28256 Help Update 3 for Delphi XE and C++Builder XE

2011/07/03追記: リリースノートへのリンクを追加しました。お休みなのにごくろうさまです。

2011年6月20日

Delphi XE Handbook発売

Marco CantuさんDelphi XE Handbookが発売されました。今までのハンドブックとの内容の重複はなく、全132ページとなっています。書籍版はAmazon(US)から34.50USD(=2,768JPY)で、eBook版はFastSpringから20.00USD(=1,650JPY)で、購入することができます(eBook版については先週金曜日(2011/06/17)にMarcoさんのTwitterおよびFacebookのアカウントにpostされたディスカウントコードで5.00USD割引の15.00USD(=1,238JPY)になるとのことです)。

元ねたはDelphi XE Handbook Available

2011/06/22追記: Delphi Handbookシリーズの2007からXEまでを一つのeBookにまとめた"Delphi Handbooks Collection, Second Edition"も近日中にリリースされる予定とのことです。

Delphi Handbooks Collection, Second Edition (2007 to XE)

全1113ページで74.50USD(=5,974JPY)、同じくFastSpringで購入可能です(書籍版はページ数が多すぎて無理だそうです)。過去のeBook版の購入者にはディスカウントがあるそうです。

2011年6月14日

第20回エンバカデロ・デベロッパーキャンプ開催予告

第20回エンバカデロ・デベロッパーキャンプが2011/09/06開催で調整中とのことです。

エンバカデロ・デベロッパーキャンプ
次回のデベロッパーキャンプは、2011年9月6日に開催を予定しています。プログラムの詳細ならびに参加受付は、7月上旬より公開・開始させていただく予定です。ご期待ください。

またセッションスピーカ、ライトニングトークスピーカの募集も始まっています。

第20回 エンバカデロ・デベロッパーキャンプ セッションスピーカー募集中!
第20回 エンバカデロ・デベロッパーキャンプ ライトニングトーク スピーカー募集のお知らせ

2011/06/17追記: LTのネタについては熟慮中ということで…。なるべく早めの提出を心掛けたいと思います…。

2011年6月13日

[書籍]ユニコード戦記

MARUZEN&ジュンク堂書店 渋谷店

ユニコード戦記 文字符号の国際標準化バトル (amazon)/小林龍生著/東京電機大学出版局/ISBN 978-4-501-54970-1/2,835円

を購入。基本的には技術書ではなく読み物(戦記物?)です。ただUnicodeなどの規格の決まり方や海の向こう側の人々の考え方など、なかなか興味深い話です。

2011年6月9日

Windows 7のピン止め機能を無効にする

Windows 7の新機能の一つにタスクバーへのピン止め(pinning、日本マイクロソフトの表現では"固定表示")があります。この機能はタスクバーと従来のクイックリンクを統合したようなもので、ユーザの明示的な操作によりタスクバー上のプログラムをピン止めし、非起動状態と起動状態の区別を考慮することなく扱うことができる、というものです(プログラム側からピン止めを設定することはできない)。しかしプログラムによってはこの機能を使ってほしくないこともあります。そこでプログラム側でピン止め機能を無効化してみます。

MSDNのApplication User Model IDs (AppUserModelIDs) (Windows)Exclusion Lists for Taskbar Pinning and Recent/Frequent ListsによればAppUserModelIDを設定する前にSystem.AppUserModel.PreventPinningプロパティを設定することでピン止めが無効化されます。Windowsプロパティの設定はSHGetPropertyStoreForWindowで行います。ところがこのWindowsプロパティに関係する定義はDelphi 2010で追加されたPropSysユニット、PropKeyユニットには存在するものの、Delphi 2009およびそれ以前のバージョンでは独自に定義する必要があります。またプロパティキーPKEY_AppUserModel_PreventPinningはDelphi 2010でも定義が存在しないため、これも独自に定義します。

uses
  Windows, SysUtils, ShellAPI, ActiveX
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF RTLVersion >= 21.00}
  , PropSys, PropKey
{$IFEND}
{$ENDIF}
;

{$IFDEF CONDITIONALEXPRESSIONS}
{$IF RTLVersion < 21.00}
const
  SID_IPropertyStore = '{886d8eeb-8cf2-4446-8d02-cdba1dbdcf99}';

  IID_IPropertyStore: TGUID = SID_IPropertyStore;
  {$EXTERNALSYM IID_IPropertyStore}

type
  { interface IPropertyStore }
  IPropertyStore = interface(IUnknown)
  [SID_IPropertyStore]
    function GetCount(out cProps: DWORD): HRESULT; stdcall;
    function GetAt(iProp: DWORD; out pkey: TPropertyKey): HRESULT; stdcall;
    function GetValue(const key: TPropertyKey; out pv: TPropVariant): HRESULT; stdcall;
    function SetValue(const key: TPropertyKey; const propvar: TPropVariant): HRESULT; stdcall;
    function Commit: HRESULT; stdcall;
  end;
  {$EXTERNALSYM IPropertyStore}

type
  TSHGetPropertyStoreForWindow = function (hwnd: HWND; const riid: TGUID;
                                           var ppv: Pointer): HResult; stdcall;
{$IFEND}
{$ENDIF}

const
  PKEY_AppUserModel_PreventPinning : TPropertyKey = (
    fmtid : '{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}'; pid : 9);
  {$EXTERNALSYM PKEY_AppUserModel_PreventPinning}


function MarkWindowAsUnpinnable(handle: HWND): HRESULT;
var
  pps: IPropertyStore;
  v: TPropVariant;
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF RTLVersion < 21.00}
  hModule: THandle;
  SHGetPropertyStoreForWindow: TSHGetPropertyStoreForWindow;
{$IFEND}
{$ENDIF}
begin

  Result := 0;

  if CheckWin32Version(6,1) = False then
  begin
    Exit;
  end;

{$IFDEF CONDITIONALEXPRESSIONS}
{$IF RTLVersion < 21.00}
  hModule := LoadLibrary(shell32);
  if hModule = 0 then
  begin
    Exit;
  end;

  try
    @SHGetPropertyStoreForWindow := GetProcAddress(hModule,'SHGetPropertyStoreForWindow');
    if Assigned(SHGetPropertyStoreForWindow) = False then
    begin
      Exit;
    end;
{$IFEND}
{$ENDIF}

    Result := SHGetPropertyStoreForWindow(handle,IID_IPropertyStore,Pointer(pps));
    if Succeeded(Result) = True then
    begin
      v.vt := VT_BOOL;
      v.boolVal := True;
      Result := pps.SetValue(PKEY_AppUserModel_PreventPinning,v);
    end;
    pps := nil;

{$IFDEF CONDITIONALEXPRESSIONS}
{$IF RTLVersion < 21.00}
  finally
    FreeLibrary(hModule);
  end;
{$IFEND}
{$ENDIF}

end;
MarkWindowAsUnpinnableはメインフォームのOnCreateイベントハンドラで
procedure TForm1.FormCreate(Sender: TObject);
begin

  MarkWindowAsUnpinnable(Handle);

end;
のように呼び出します。

元ねたはRaymond ChenさんHow do I prevent users from pinning my program to the taskbar? - The Old New Thing - Site Home - MSDN Blogs

2011年6月7日

Delphi Certification Program正式アナウンス

先日お伝えしたDelphi Certification Programが正式にアナウンスされています。

Embarcadero Certification Center

Delphi Certification ProgramはDelphiプログラマの認定試験で、Delphi DeveloperDelphi Master Developerの2つのレベルが用意されています。どちらも60分間で60問出題され、80%(48問)が合格ラインになります。試験は中立の第三者機関が管理します。また認定は合格後2年間有効です。

Delphi Developer Certificationは基本的な知識を問うもので、以下の11の分野から出題されます。
  • Delphiの基礎
  • データ型、変数、定数
  • プロシージャと関数
  • クラスとオブジェクト
  • 標準手続きとI/O
  • ライブラリとパッケージ
  • オブジェクトインタフェース
  • メモリ管理
  • ジェネリクス、属性、無名メソッド
  • 例外とアサーション
  • データベースの概念
受験料は49USDで、オンラインでどこからでも受験することができます。RAD Studio/Delphi XEの登録ユーザは2011/07/31までにコードを取得して90日以内に受験することで無料で試験を受けることができます。

Delphi Master Developer Certificationは高度な知識を問うもので、以下の12の分野から出題されます。
  • Windowsの概念
  • Delphi XEのインタフェースと設定
  • DelphiのVCLとRTL
  • コンポーネントの扱い
  • Delphi言語とオブジェクト指向プログラミング
  • データベースの共通テクニック
  • dbExpress
  • DataSnap
  • DLLとパッケージの記述
  • コンポーネント設計の基本
  • インターネットプログラミング
  • XMLの扱い
受験料は149USDで、エンバカデロのパートナの認定センターが運営します。

FAQも用意されています。

Delphi Certification FAQs

と、ここまで書いておいてなんですが、残念なことに現時点では日本での扱いは決まっていないようです。

元ねたはAndreano LanusseさんDelphi Certification Program – Official Announcement | Andreano Lanusse Blog | Technology and Software Development

2011年5月25日

シリアルポートコンポーネント

シリアルポート(COM/RS-232C)はレガシーではありますが、依然として使用する機会の多いインタフェースです。そこで一般的にお勧めできそうなシリアルポートコンポーネントを探してみました(対応するDelphi/C++Builderのバージョンはあくまで目安です)。

ComPort Library
作者はDejan Crnilaさん、現在のメンテナはLars B. Dybdahlさん、Paul Dolandさん、Brian Gochnauerさんです。Delphi 3/4/5/6/7/8/2005/2006/2007/2009/2010/XE、C++Builder 3/4/5/6に対応しています。最新バージョンは4.11a(2011/05/22)、ライセンスはPublic Domainです。

TurboPower Async Professional
もともとはTurboPower Softwareの商用製品で、オープンソース化されたTurbo Powerプロジェクトの多機能通信コンポーネント群。現在のメンテナはSean B. Durkinさん、tpsfadmin(TurboPower)ことNick Hodgesさんです。Delphi 7/2005/2007/2010に対応しています。最新バージョンは5.0(2010/03/10)、ライセンスはMPL 1.1です。関連: Installing AsyncPro into Delphi XE and C++Builder XE

SynaSer serial library
Ararat s.r.o.SYNAPSE libraryに含まれるシリアル通信コンポーネント。Delphi/C++Builder 3/4/5/6/7/2005/2006に対応しています。最新バージョンはRelease 16/Version 7.2.0(2007/12/21)、ライセンスは修正BSDスタイルです。

TksComPort
Sergey Kasandrovさんによるkstoolsに含まれるシリアル通信コンポーネント。Delphi 2007/2009に対応しています。最新バージョンは0.50(2010/04/30)、ライセンスはMIT Licenseです。

ComPort component
Winsoftによる商用製品(35.00-70.0USD)。Delphi/C++Builder 5/6/7/2005/2006/2007/2009/2010/XEに対応しています。最新バージョンは3.5(2010/12/01)。

nrComm Lib
DeepSoftwareによる商用製品(69.00-599.00EUR)。Delphi/C++Builder 3/4/5/6/7/2005/2006/2007/2009/2010/XEに対応しています。最新バージョンは9.17(2011/05/11)。

お勧めはComPort LibraryかTurboPower Async Professionalでしょうか。シンプルなものがよければ前者、多機能なものがよければ後者、という感じで。

元ねたはTeam Japan » Delphi XE で COMポート(RS-232C)を操作するなど。

2011年5月24日

よりよいQCレポートの書き方

エンバカデロのQualityCentralのSysopの一人であるUwe SchusterさんHow to improve your QC reports?(QCレポートを改善する方法)というアーティクルを書いています。興味深い。

てきとうな要約: まず、最大の誤りは問題をレポートしないことです。なぜならあなたがその問題は修正されると思っていない、ということだからです。
  • Build No
    ここにはRAD Studioのフルバージョン番号を記入する(XE Update 1なら15.0.3953.35171)。これはどのUpdate/Hotfixを適用した状態なのかを知るために重要。
  • Language/Nationality
    ローカライズとは関係のない問題では"US"。表示の欠けや誤訳などのローカライズに関係する問題ではその言語を選択。不必要に言語を指定するとまずローカライゼーションチームに回されるため修正まで時間が掛かるかも。
  • Type and Severity
    この2つの項目は全てのユーザの視点で指定するべきで、高すぎる評価はSysopやQAによって修正されることがある。またコンパイラによる内部エラー("Fxxxx Internal Error")はTypeを(Crash/Data loss/Total failure)とする。
  • Steps
    Stepsには明白であっても予想される動作と実際の動作を記入する。レポートをOpenにするためには再現可能でなければならない。テストケースのないコンパイラの内部エラーは既存のレポートと重複しているものとして扱われ、修正されない可能性が高い(原因が異なっていても同じエラーになるので)。
  • Automated Reports
    IDEがJCLスタックトレース機能を使って生成するものでAIRレポートとも呼ばれ、QCのDelphi.NETに分類される。これは過去の経緯によるものなので、気にせずそのまま(Delphi/C++Builderプロジェクトに変更したりせず)送信する。
  • Voting
    新しいvoteシステムは2007年から使用されており、それぞれのレポートに+/-10の範囲でvote(投票)することができる。webクライアントは新しいvoteシステムに対応しておらずvote値を指定できないので、Win32クライアント(かQC Plus)を使用するのが望ましい。
  • Questions
    QCレポートの扱いについて質問がある場合はForum: QualityCentralへ。


QualityCentralのレポートの書き方に関しては以下のアーティクルも参考になります。

Quality Centralでのバグレポートのコツ
Quality Centralの基礎知識 - Delphi 2009 特集
バグレポートの際のコツ - Delphi 2009 特集
QualityCentral の Tips
Quality Central についての基礎知識

2011年5月19日

Windowsの互換モード上でのLCMapStringの不具合

ちょっと前になりますが、au2010さんのところで気になる話を見つけました。

Windows7でDelphi7のプログラムを動かす時の注意点 - au2010の日記

実際にLCMapString (ja)の動作を確認してみると、Windows 7で互換モードを設定(プログラムのショートカットの"互換性"タブで"互換モード"にチェックオン)すると、LCMapStringのcchDestを0にしたときだけ戻値がA版(LCMapStringA)であっても(W版と同様の)文字数で返ってくる、という不具合があります(cchDestが非0ならば戻値は仕様通り)。いろいろ調べてみましたがプログラム側から互換モードの指定状況を知る方法はなく、結果が既知の変換動作を行わせて、その戻値で判定するしかないようです。ということで半角→全角変換全角→半角変換のコードを修正しました。

2011年5月18日

C++0x FDIS(N3290)解説

C++0xの規格化作業は最終段階に差し掛かっていて、現在はN3290FDIS(Final Draft International Standards)として公開されています(もちろん英語で)。

このC++0xのN3290について、2011/05/14に行われたBoost.勉強会 #5 名古屋道化師さんが解説した資料が見られるようになっています。

C++0x総復習 (Boost.勉強会 #5 名古屋 - boostjp)

slideshareだとこちらですね。

C++0x総復習

江添さんによる本の虫: post-Madrid mailingの簡易レビューも併せて読むといいと思います。

元ねたはアキラさんBoost.勉強会 #5 名古屋でした - Faith and Brave - C++で遊ぼう

Delphiにも"= delete"(§8.4.3 Deleted definitions)があればこんなことをしなくてもすんだのに…。

2011年5月17日

DelphiでSingletonパターンを実装する(リベンジ)

DelphiでSingletonパターンを実装する(再考)ではTSingletonのインスタンスの解放を防ぐためにデストラクタ内で例外を送出する、という方法を考えてみましたが、2ちゃんねる界隈では不評だったようです。一般論からいえば確かにデストラクタからの例外の送出はいかがなものか、という気もしますが、そもそもこのアプローチは(コンストラクタからの例外の送出による複数インスタンスの生成の防止と同様に)テストレベルで問題コードを検出、修正するためのものであって、リリースコード上で実行されることを想定しているわけではありません。また前回考察したように、一旦呼び出しがなされたコンストラクタ、デストラクタのインスタンスに対する生成、破棄処理を回避するには例外の送出しかないことも確かです。ということで"より望ましい"解決方法を考えてみることにします。

まず前回の"Phoenix Singleton"ですが、デストラクタを呼び出すことでインスタンスが完全に解放されてしまうため、次回のアクセスで新しいインスタンスが生成されてもその内容は初期状態に戻ってしまいます。そこで"予備"のインスタンスを用意しておき、ここに内容を退避して再生成時に復元します。まずinitialization/finalization版から。
unit Unit32;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    procedure   Assign(Source: TSingleton);
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;
  FShadowSingleton: TSingleton;

{ TSingleton }

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Shadowing }
  if FShadowSingleton = nil then
  begin
    FShadowSingleton := TSingleton.CreateInstance;
  end;
  if FShadowSingleton <> Self then
  begin
    FShadowSingleton.Assign(Self);

    { Delete singleton reference }
    FSingleton := nil;
  end;

  { Finalize }

  inherited;

end;

procedure TSingleton.Assign(Source: TSingleton);
begin

  { Copy from source }
  TestValue := Source.TestValue;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
    if FShadowSingleton <> nil then
    begin
      FSingleton.Assign(FShadowSingleton);
    end;
  end;

  Result := FSingleton;

end;

initialization
  FSingleton := nil;
  FShadowSingleton := nil;

finalization
  FSingleton.Free;
  FShadowSingleton.Free;

end.
次にclass constructor/class destructor版です。
unit Unit34;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
      FShadowSingleton: TSingleton;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    procedure   Assign(Source: TSingleton);
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;
  FShadowSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  FSingleton.Free;
  FShadowSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Shadowing }
  if FShadowSingleton = nil then
  begin
    FShadowSingleton := TSingleton.CreateInstance;
  end;
  if FShadowSingleton <> Self then
  begin
    FShadowSingleton.Assign(Self);

    { Delete singleton reference }
    FSingleton := nil;
  end;

  { Finalize }

  inherited;

end;

procedure TSingleton.Assign(Source: TSingleton);
begin

  { Copy from source }
  TestValue := Source.TestValue;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
    if FShadowSingleton <> nil then
    begin
      FSingleton.Assign(FShadowSingleton);
    end;
  end;

  Result := FSingleton;

end;

end.
いずれもシングルトンの内容の退避、復帰のためにインスタンスの内容をコピーするprocedure Assignというメソッドを用意し、これをコンストラクタ、デストラクタで使用します。なおシングルトンが別のクラスのインスタンスを所有するような場合、Assignはいわゆる"deep copy"の動作を実装する必要があります。またpublicなconstructor Createについてはとりあえず従来どおりの例外送出のままとしてあります。

次にコンストラクタ、デストラクタでの例外の送出、というアプローチですが、これは前述のとおりテストレベルでの問題コードの検出、修正を目的としています。しかしこの方法には問題コードが実行されない限り意味をもたない(コンパイル時には検出できない)、という欠点もあります。そこで例外の送出ではなく、constructor Create、destructor Destory、そして再定義したprocedure Freeに(少々目的は異なるものの)ヒント指令deprecatedを指定しておき、これらを呼び出しているコードをコンパイル時に警告されるようにする、という解決策を考えてみます。まずinitialization/finalization版から。
unit Unit28;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
    destructor  DestroyInstance;
  public
    constructor Create;            deprecated {$IFDEF CONDITIONALEXPRESSIONS}{$IF CompilerVersion >= 20.00} 'Do not use TSingleton.Create.'  {$IFEND}{$ENDIF};
    destructor  Destroy; override; deprecated {$IFDEF CONDITIONALEXPRESSIONS}{$IF CompilerVersion >= 20.00} 'Do not use TSingleton.Destory.' {$IFEND}{$ENDIF};
    procedure   Free;              deprecated {$IFDEF CONDITIONALEXPRESSIONS}{$IF CompilerVersion >= 20.00} 'Do not use TSingleton.Free.'    {$IFEND}{$ENDIF};
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;


implementation

var
  FSingleton: TSingleton;

{ TSingleton }

constructor TSingleton.Create;
begin

  { Place holder, do not use }

end;

destructor TSingleton.Destroy;
begin

  { Place holder, do not use }

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.DestroyInstance;
begin

  { Finalize }

  inherited Destroy;

end;

procedure TSingleton.Free;
begin

  { Place holder, do not use }

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

initialization
  FSingleton := nil;

finalization
  if FSingleton <> nil then
  begin
    FSingleton.DestroyInstance;
  end;

end.
Delphi 2009以降({$IFDEF CONDITIONALEXPRESSIONS}{$IF CompilerVersion >= 20.00}で判定)ではdeprecatedに追加のメッセージを指定しています。

次にclass constructor/class destructor版です。
unit Unit30;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
    constructor CreateInstance;
    destructor  DestroyInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;            deprecated 'Do not use TSingleton.Create.';
    destructor  Destroy; override; deprecated 'Do not use TSingleton.Destory.';
    procedure   Free;              deprecated 'Do not use TSingleton.Free.';
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  if FSingleton <> nil then
  begin
    FSingleton.DestroyInstance;
  end;

end;

constructor TSingleton.Create;
begin

  { Place holder, do not use }

end;

destructor TSingleton.Destroy;
begin

  { Place holder, do not use }

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.DestroyInstance;
begin

  { Finalize }

  inherited Destroy;

end;

procedure TSingleton.Free;
begin

  { Place holder, do not use }

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

end.
どちらもDelphi 2009以降であれば"プロジェクトオプション"の"Delphiコンパイラ"の"ヒントと警告"で"使用を推奨されていないシンボル"をエラーにするか、シングルトンを使用している側のユニットに
{$WARN SYMBOL_DEPRECATED ERROR}
を指定することでconstructor Create、destructor Destory、procedure Freeの呼び出しをエラーにすることができます(通常は警告)。

2011年5月16日

IDE Fix Pack 4.1/DelphiSpeedUp 3.1リリース

Andreas HausladenさんIDE Fix Pack 2007およびIDE Fix Pack 2009/2010/XEがアップデートされてVersion 4.1に、DelphiSpeedUpもDelphi 7/2007用がアップデートされてVersion 3.1になっています。IDE Fix Pack、DelphiSpeedUpともRCからの変更はないようです。

IDE Fix Pack 4.1, DelphiSpeedUp 3.1 | Andy’s Blog and Tools

2011年5月11日

Microsoft Monthly Update 2011/05

今日はMicrosoftのセキュリティアップデートの日です。
MS11-035
MS11-036

2011年5月9日

コンストラクタとデストラクタについての考察

Delphiのコンストラクタ、デストラクタとは、ヘルプの

コンストラクタ (メソッド)
デストラクタ (メソッド)

にあるように、クラスのインスタンスを生成、破棄するための特別なメソッドです。あまり知られていませんがコンストラクタとデストラクタには

メソッド呼び出しの処理 (プログラムの制御)

にあるように、Pointer型とByte型の2つの隠しパラメータが存在します(デフォルトのregister呼出規約ではEAXレジスタとDLレジスタ)。第1パラメータ(Pointer型)はSelf(C++のthisに相当)です。一方で第2パラメータ(Byte型)は真偽値(0または非0)であり、クラスメソッドとして呼び出される場合、つまり
  Foo := TFoo.Create;
では1(真)が設定され、インスタンスメソッドとして呼び出される場合、つまり
constructor TFoo.Create;
begin
  inherited;
end;
のinherited(継承元コンストラクタの呼び出し)では0(偽)が設定されます。コンストラクタでは先頭にこの第2パラメータをチェックして真の場合はインスタンス領域の確保と初期化が行われるようなコードが生成されます(確保したインスタンス領域のアドレスはEAXに格納され、呼出元に返されます)。またデストラクタでは末尾に第2パラメータのチェックとインスタンス領域の解放が行われるようなコードが生成されます。さらにコンストラクタでは内部で例外が生成されたときに自動的にデストラクタが呼び出され、初期化後に変更されたフィールドに対してリソースの解放を行うことでコンストラクタで例外を送出したときのリソースリークを防ぐような仕組みになっています。

実際のコードで確認してみましょう(例はシングルトンパターンその1のUnit2をDelphi 2007でデバッグビルドしたものです)。

コンストラクタ呼び出し
  FSingleton := TSingleton.Create;


Unit2.pas.30: FSingleton := TSingleton.Create;
00457C35 B201             mov dl,$01
00457C37 A1D47B4500       mov eax,[$00457bd4]
00457C3C E80B000000       call TSingleton.Create
00457C41 A3CC0C4600       mov [$00460ccc],eax

となり、DLレジスタに0x01が設定されてコンストラクタ(TSingleton.Create)を呼び出しています。コンストラクタ本体の
constructor TSingleton.Create;
begin

  inherited;

  { Initialize }
  FTestValue := 0;

end;


Unit2.pas.38: begin
00457C4C 53               push ebx
00457C4D 56               push esi
00457C4E 84D2             test dl,dl
00457C50 7408             jz $00457c5a
00457C52 83C4F0           add esp,-$10
00457C55 E8B2C0FAFF       call @ClassCreate
00457C5A 8BDA             mov ebx,edx
00457C5C 8BF0             mov esi,eax
Unit2.pas.40: inherited;
00457C5E 33D2             xor edx,edx
00457C60 8BC6             mov eax,esi
00457C62 E869BDFAFF       call TObject.Create
Unit2.pas.43: FTestValue := 0;
00457C67 33C0             xor eax,eax
00457C69 894604           mov [esi+$04],eax
Unit2.pas.45: end;
00457C6C 8BC6             mov eax,esi
00457C6E 84DB             test bl,bl
00457C70 740F             jz $00457c81
00457C72 E8EDC0FAFF       call @AfterConstruction
00457C77 648F0500000000   pop dword ptr fs:[$00000000]
00457C7E 83C40C           add esp,$0c
00457C81 8BC6             mov eax,esi
00457C83 5E               pop esi
00457C84 5B               pop ebx
00457C85 C3               ret

と先頭でDLレジスタが非0ならばClassCreateを呼び出し、BLレジスタにDLレジスタの値を保存してからDLレジスタを0に変更して以下の処理を行い、最後にBLレジスタ(=呼び出されたときのDLレジスタ)が非0であればAfterConstructionを呼び出すようになっています。

次にデストラクタを見てみます。といってもサンプルではTObject.Freeで呼び出しが隠蔽されてしまっていますので、ここはDestroyを直接呼び出すようにしてみます。
  FSingleton.Destroy;


Unit2.pas.63: FSingleton.Destroy;
00457CD2 B201             mov dl,$01
00457CD4 A1CC0C4600       mov eax,[$00460ccc]
00457CD9 8B08             mov ecx,[eax]
00457CDB FF51FC           call dword ptr [ecx-$04]

となり、やはりDLレジスタに0x01を格納してからデストラクタを呼び出しています(呼出先が[ecx-$04]というのはVMT経由でデストラクタのアドレスを取得しているためです)。デストラクタ本体の
destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;


Unit2.pas.48: begin
00457C88 53               push ebx
00457C89 56               push esi
00457C8A E825C1FAFF       call @BeforeDestruction
00457C8F 8BDA             mov ebx,edx
00457C91 8BF0             mov esi,eax
Unit2.pas.52: inherited;
00457C93 8BD3             mov edx,ebx
00457C95 80E2FC           and dl,$fc
00457C98 8BC6             mov eax,esi
00457C9A E851BDFAFF       call TObject.Destroy
Unit2.pas.54: end;
00457C9F 84DB             test bl,bl
00457CA1 7E07             jle $00457caa
00457CA3 8BC6             mov eax,esi
00457CA5 E8B2C0FAFF       call @ClassDestroy
00457CAA 5E               pop esi
00457CAB 5B               pop ebx
00457CAC C3               ret

となり、まずBeforeDestructionが呼び出され、BLレジスタにDLレジスタの値を保存してから0xFCとANDをとって(DLレジスタは0x01 AND 0xFC = 0x00となっている)継承元デストラクタを呼び出し、最後にBLレジスタ(呼び出されたときのDLレジスタ)が非0であればClassDestroyを呼び出すようになっています。またデストラクタ内でExitしても

Unit2.pas.48: begin
00457C88 53               push ebx
00457C89 56               push esi
00457C8A E825C1FAFF       call @BeforeDestruction
00457C8F 8BDA             mov ebx,edx
00457C91 8BF0             mov esi,eax
Unit2.pas.50: Exit;
00457C93 EB0C             jmp $00457ca1
Unit2.pas.54: inherited;
00457C95 8BD3             mov edx,ebx
00457C97 80E2FC           and dl,$fc
00457C9A 8BC6             mov eax,esi
00457C9C E84FBDFAFF       call TObject.Destroy
Unit2.pas.56: end;
00457CA1 84DB             test bl,bl
00457CA3 7E07             jle $00457cac
00457CA5 8BC6             mov eax,esi
00457CA7 E8B0C0FAFF       call @ClassDestroy
00457CAC 5E               pop esi
00457CAD 5B               pop ebx
00457CAE C3               ret

とBLレジスタのチェックにジャンプするようになっており、DLが非0の呼び出しでは途中でExitしても必ずClassDestroyが呼び出されます。

このような事情から、コンストラクタの呼び出しによるクラスインスタンスの生成をキャンセルするためにはコンストラクタ内で例外を送出し、最外側コンストラクタ先頭で確保したインスタンス領域をデストラクタで解放させるしかありません(コンストラクタをクラスメソッドで呼び出すと必ず領域確保が行われるため)。同様にデストラクタの呼び出しによるインスタンスの破棄をキャンセルするには最外側のデストラクタの末尾までのどこかの時点で必ず例外を送出してインスタンス領域の解放を防ぐ必要があります。

元ねたはDelphiクイックリファレンス (amazon)/Ray Lischner著/光田秀、竹田知生訳/オライリー・ジャパン/ISBN4-87311-040-8/4,725円。

2011年5月2日

MS11-025によって発生する問題とその対策

2011/04のセキュリティアップデートのうち、MS11-025には、
  1. Windows 2000 SP4にKB2467175 (Visual C++ 2005 SP1 再頒布可能パッケージ セキュリティ更新プログラム (2011 年 4 月 12 日))およびKB2467174 (Visual C++ 2008 SP1 再頒布可能パッケージ セキュリティ更新プログラム (2011 年 4 月 12 日))を適用するとMFC 8.0/9.0を動的にリンクしているプログラムが起動時にエラーになる。
  2. VC2008でMFCを静的リンクしたプログラムのサイズが(VC2010と同様に)不必要に大きくなる。
  3. MFC 8.0/9.0を動的にリンクしているプログラムがMFCの言語DLLを使用しない(DLLを発見できなくなる)。
  4. Windows XP以降にしか存在しないFindActCtxSectionStringAに静的にリンクしてしまうためリビルドしたプログラムがWindows 2000で動作しなくなる。
といった問題が存在しているようです。

このうちWindows 2000とVC2005/VC2008再頒布可能パッケージ(Redist)の問題についてはKB2467175とKB2467174がWindows 2000の適用範囲外となったため、インストールしないのが正しく、もしインストールしてしまった場合は

New redists break all dynamically linked MFC 2005/2008 apps on Windows 2000 « Ted's Blog

にあるように、
  1. KB2467175とKB2467174をアンインストール
  2. Windows(WINNT)フォルダ内のWinSxSフォルダから4053と4148を検索して(フォルダが存在しなければ代わりにそれぞれ762と21022で検索)、検索結果に含まれるフォルダ内のファイル(ATLxx.DLL, MFCxx*.DLL, MFCMxx*.DLL, MSVCMxx*.DLL, MSVCPxx*.DLL, MSVCRxx*.DLL, VCOMPxx.DLL)全てを一時フォルダ("C:\MFCDLL"など)にコピー
  3. Windowsを再起動
  4. [F8]キーを押してWindows 2000拡張オプションメニューを表示し、セーフモードとコマンドプロンプトでコマンドプロンプトを選択して起動
  5. 一時フォルダ内のファイルをSystem32に
    copy C:\MFCDLL\*.* C:\Windows\System32
    (一時フォルダが"C:\MFCDLL"でWindowsのインストールフォルダが"C:\Windows"の場合)
    としてコピー
  6. EXITで再起動
という手順で回復することができます。

その他の(Visual Studio上での開発に関する)問題とその解決方法については

Problem with FindActCtxSectionString in MFC security updates on all platforms « Ted's Blog
Martin's Blog » BUG: Black Patchday for all OS from XP and later 3. – MFC 8.0 (VC-2005) or MFC 9.0 (VC-2008) linked dynamically to the MFC may not find the MFC language DLLs after installation of the security packs dated April 12th 2011
Static MFC code bloat problem from VC2010 is now in VC2008 SP1+security fix « Ted's Blog
Fixing problems with FindActCtxSectionString in MFC security updates « Ted's Blog

が参考になります。

2011/05/05追記: MicrosoftのVisual C++ Team Blogにもこの件に関する記事があります(考えてみれば当たり前か)。

MS11-025 Visual C++ Update Issue - Visual C++ Team Blog - Site Home - MSDN Blogs

これによると、Windows 2000に関する問題についてはこの時点(2011/04/26)ではMS11-025をアンインストールするしかないようですが、
Our team has identified the cause of these issues and is currently testing the fix. The update will be publicly available once testing is complete, and we will update this blog.

いい加減な訳: 我々VC++チームではこれらの問題の原因を特定し、修正したものを現在テストしているところです。テストが完了したらアップデートは一般に利用可能となり、このブログを更新します。

ということで、近日中に何らかの解決が図られるようです。

2011/06/15追記: MS11-025が更新され、以下の問題が解決したとされています。
  • ローカライズされたアプリケーションをご使用のお客様に MFC アプリケーションのリソースの一部がローカライズされずに表示されます。アプリケーションは正常に機能しますが、リソースが英語で表示されます。
  • MFC のセキュリティの修正は Microsoft Windows 2000 でサポートされていない API を使用します。Microsoft Windows 2000 システムに更新プログラムを適用した場合、インストールによっていくつかのアプリケーションの機能的な問題が引き起こされました。
  • 以前の更新プログラムは x64-based アーキテクチャの Windows 7 SDK を使用しているユーザーにはインストールされませんでした。


2011/06/21追記: Visual C++ Team Blogにも新しい更新プログラムで上記の問題を修正した、という記事が出ています。

Update on Bulletin MS11-025 - Visual C++ Team Blog - Site Home - MSDN Blogs

2011年4月27日

Delphi IDE Theme EditorがDelphi 5/6をサポート

RRUZ(Rodrigo Ruz)さんDelphi IDE Theme EditorがバージョンアップしてDelphi 5/6のIDEをサポートするようになっています。

Added support for Delphi 5 and 6 in the Delphi IDE Theme Editor « The Road to Delphi – a Blog About Delphi Programming (mostly)

現時点(2011/04/27)の最新バージョンは1.0.0.136です。

2011年4月26日

Delphi Certificate Programベータテスト

しばらく前に公式フォーラムでその存在がほのめかされていた"Delphi Certificate Program"ですが、Andreano Lanusseさんによるといよいよベータプログラムが始まるとのことです。

Delphi Certification Beta Program | Andreano Lanusse Blog | Technology and Software Development

Delphi Certificate ProgramとはDelphiプログラマのスキルレベルの認定を行うもので、最初はDeveloper、Masterの2レベルが準備されるとのことです。ベータプログラムではまずMasterレベルのテストが行われ、"Delphi Master"認定テストの内容の検証を目標としています(ベータテスター自身の合否ではなく)。ベータテストの対象は2年以上のDelphi 7以降のプログラマで、問題は以下の知識分野でグループ分けされています。
  • Delphi XE Interface and Configuration
  • Delphi VCL and RTL
  • Delphi Language and Object-Oriented Programming
  • Component Design Basics
  • Working with Components
  • Database Concepts/Data Access Techniques
  • dbExpress
  • DataSnap
  • Writing DLLs and Packages
  • Libraries and Packages
  • Windows Concepts
  • Internet Programming
  • XML

日本語バージョンは登場するのでしょうか?とりあえず連休中にチャレンジしてみようかな…。

2011年4月25日

RAD StudioのIDEでConsolasとMeiryoKe Consoleを使う(Windows 7)

前回の続きでWindows 7の場合です。Windows XP/Vistaで使用できるメイリオはVer5.00でしたが、Windows 7に付属しているメイリオはVer6.02です。とはいっても手順としてはあまり変わらず、作業フォルダに"meiryo.ttc"と"meiryob.ttc"をコピーし、

ブログ内記事で取りあげたソフト・ファイルのDL情報 『ことば・その周辺』

からダウンロードした"meiryoKe_gen_6.02rev1.zip"を同じ作業フォルダに展開し、"meiryoKe_gen_6.02rev1.exe"を実行し、生成された"meiryoKe_602r1.ttc"と"meiryoKeB_602r1.ttc"を"meiryoKe.ttc"と"meiryoKeB.ttc"にリネームし(これは好みで)、右クリック→インストールでフォントフォルダにコピーします。あとはWindows XP/Vistaの場合と同様にレジストリエディタで

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink

を開き、新規作成で複数行文字列値を作成し、名前を"Consolas"として内容を

meiryoKe.ttc,meiryoKe_Console
mingliu.ttc,MingLiU
SimSun.TTC,SimSun
gulim.ttc,GulimChe

として設定して再起動します(Windows XP/Vistaと異なりフォントファイルがTTC形式なのでレジストリ上の指定方法も異なります)。あとはRAD StudioのIDEで使用するフォントを"Consolas"にするだけです(ClearTypeのチューニングはコントロールパネル→"ディスプレイ"→"ClearTypeテキストの調整"→"ClearTypeテキストチューナ"で)。

2011年4月23日

IDE Fix Pack 4.1 RC/DelphiSpeedUp 3.1 RCリリース

Andreas HausladenさんのIDE Fix Pack 4.1 RCとDelphiSpeedUp 3.1 RCが公開されています。これは先日リリースされたIDE Fix Pack 4.0/DelphiSpeedUp 3.0でコードエディタのタブを閉じたときにアクセス違反が状況によっては発生する、という問題があるためとのことです。Delphi 6/2006については未テストとのことですので、使用する際は注意が必要です。

IDE Fix Pack 4.1 RC, DelphiSpeedUp 3.1 RC | Andy’s Blog and Tools

2011年4月22日

Project "Cooper"ベータ情報

RemObjectsからCooperのベータ版の情報とビデオが公開されています。

“Cooper” Beta details « RemObjects Blogs
Oxygene on RemObjects TV | RemObjects Software

とりあえずは順調に進んでいるということでしょうか。

RAD StudioのIDEでConsolasとMeiryoKe Consoleを使う(Windows XP/Vista)

RAD StudioなどのIDEで使用するフォントは英語圏ではConsolasとだいたい相場が決まっている(個人的な感想です)のですが、日本語を使う、となると実に微妙な状況です。特にWindows XP以降のClearType (ja)を効かせた設定にしたい場合、選択肢はメイリオかそれなりに高価な商用フォントしかありません(商用フォントを買えばもちろん幸せになれそうですが)。メイリオはご存知のとおりWindows XPまでのフォントとはメトリクスが大きく異なり、更に英数字が等幅ではないためIDE用のフォントとしてはあまり適しているとはいえません。そこでメイリオのフォントデータをパッチで改変することで従来の(MS ゴシック/MS Pゴシック/MS UIゴシックシリーズの)メトリクスに近いMeiryoKe系フォントを生成し、これをConsolasにフォントリンクすることで、Consolas + MeiryoKe_ConsoleをIDEで使用する、という方法を試してみたのでメモ。まずはWindows XP/Vista(メイリオ Ver5.00)環境の手順を。

注意事項: MeiryoKeはライセンス的に相当グレーです。あくまで自己責任で。特にMeiryoKeのフォントファイルそのものを配布するのは明らかにまずいのでご注意ください。

Windows VistaにはConsolas、メイリオとも含まれていますが、Windows XPにはデフォルトではこれらのフォントが存在しませんので、まずこれらを入手します。Microsoft Visual Studio 2005/2008のどのSKUでもよいので(Express Editionでよい)インストールし、次に

Download details: Consolas Font Pack for Microsoft Visual Studio 2005 or 2008

をダウンロード、インストールします。続いて

ダウンロードの詳細 : Windows XP 向け ClearType 対応日本語フォント

(こちらはメイリオ)をダウンロード、インストールします。

材料が揃ったところで次にMeiryoKeの生成です。フォントフォルダから作業用フォルダに"meiryo.ttc"と"meiryob.ttc"をコピーし、

ブログ内記事で取りあげたソフト・ファイルのDL情報 『ことば・その周辺』

からリンクされているページで"meiryoKe_gen_5.00rev1.zip"と"meiryoKeConsole_gen_5.00rev1.zip"をダウンロードし、これも作業フォルダに展開します。次に"meiryoKe_gen_5.00rev1.exe"と"meiryoKeConsole_gen_5.00rev1.exe"を実行し、生成されたフォントファイル("meiryoKeGothic.ttc"、"meiryoKeGothicB.ttc"、"meiryoKeConsole.ttf")を右クリック→インストールでフォントフォルダにコピーします。

これでConsolas、MeiryoKe_Consoleを使用できるようになりましたが、IDEで指定できるフォントは通常1つだけです。そこでConsolasにフォントリンクを設定し、Consolasに存在しないコードポイントに対してMeiryoKe_Consoleを使用するようにします。

レジストリエディタで

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink

を開き、新規作成で複数行文字列値を作成し、名前を"Consolas"として内容を

meiryoKeConsole.ttf
SimSun.TTC,SimSun
gulim.ttc,GulimChe
mingliu.ttc,MingLiU

(普通に使用するならmeiryoKeConsole.ttfだけで十分ですが)として再起動します。これでIDEで使用するフォントをConsolasに設定することでConsolas + MeiryoKe_Consoleの組み合わせになります。ただしWindows XPの場合はClearTypeを有効にし、さらに

Microsoft Typography - ClearType Tuner PowerToy

からClearType Tunerをダウンロード、インストールして好みの状態に調整したほうがいいでしょう。このあたりについては@ITの

Windows XPの正体 : 文字表示を滑らかにする新技術「ClearType」
ClearTypeフォントの表示方法を調整する - @IT

あたりが参考になります。

2011年4月19日

Webセミナー 次世代ToolCloud - AppWaveによるアプリケーション配布の管理

Webセミナー「次世代ToolCloud - AppWaveによるアプリケーション配布の管理」

始まりました。今日は資料ダウンロード、ビデオリプレイはありません。開発中のプロダクトについての話なので以下の内容はあくまで現時点のもので、一切の保証はありません、といういつものお約束で。詳細は今後ソフトウェア開発環境展(SODEC)(リード エグジビション ジャパン株式会社主催、2011/05/11-13、東京ビッグサイト)などで順次公開予定とのこと。

ユーザ、管理者、開発者のそれぞれの観点からみたAppWaveについて。

まずToolCloudとは、というおさらい。
配布、ライセンス管理の問題。webアプリケーション、thinクライアント、仮想化、クラウドといった方法での解決には一長一短がある。
AppWave技術で解決。クライアントサイドに仮想化環境を作りオンデマンド、ストリーミングで必要な実行モジュールを送り込む。
AppWaveブラウザを通してアプリケーションを配信して実行。プログラムからローカル資源にもアクセス可能。

ユーザの観点。評価時にも購入後もいちいちインストールしたりアンインストールしたりといった面倒な部分はAppWaveブラウザ内に閉じ込めることができ、ホストOS環境を汚染しない。AppWaveブラウザ内の状態はサーバ側に保存されるので別環境下でも同一アカウントであれば同一環境を得られる。

管理者の観点。ライセンスの一括/一元管理でもコーポレート/サイトライセンスでもライセンスの管理の維持が難しい。AppWaveではアプリケーションのユーザごとの使用の可否や使用状況を管理できる。AppWave StudioでアプリケーションをAppWave用にパッケージングする。パッケージング作業はアプリケーション固有のインストーラによる手順のキャプチャでも導入手順の手動設定でも可能。

開発者の観点。開発環境のインフラストラクチャとして。

導入イメージ。ツールやアプリケーションをAppWaveサーバから配信。部門ごとやプロジェクトごとの開発ツールの環境やライセンスを一元管理できる。市販アプリケーションのライセンス管理、最新バージョンの強制などもできる。パッケージアプリケーションの配布にも。購入済ユーザ、トライアルユーザなどライセンスの管理も簡単に。

AppWaveブラウザについて。現状はエンバカデロのツールのみ。次のステップでは管理者がAppWave Studioでパッケージングしたものを追加できるようになる。さらにAppWave Store(仮)でアプリケーションの配信、販売、という将来構想。AppWave Store(現在ベータテスト中)のメンバとなり、Storeにアプリケーション、ツール、コンポーネントなどを登録すればAppWave Store経由で販売が可能になる。

まとめ。AppWaveはToolCloudを汎用化したもので、将来はStore機能までつなげていきたい。

Q&A。オフライン実行については最長1ヶ月のライセンスの持ち出しができる。

終了。おつかれさまでした。

IDE Fix Pack 4.0/DelphiSpeedUp 3.0リリース

Andreas HausladenさんIDE Fix Pack 2007およびIDE Fix Pack 2009/2010/XEがアップデートされてVersion 4.0に、DelphiSpeedUpもDelphi 7/2007用がアップデートされてVersion 3.0になっています。

IDE Fix Pack 4.0 / DelphiSpeedUp 3.0 release | Andy’s Blog and Tools

2011年4月18日

VMware Player上のWindwos XPモードでマルチコアを有効にする

Windows 7のProfessional/Ultimate/Enterprise SKUで使用できるWindows XP モードVMware Playerにインポートして使用することができます。このときホスト側のCPUがマルチコアで、かつVMware Playerの設定でVMに複数のCPUコアを割り当てる設定にしてあっても、XPモードのHALがシングルプロセッサにのみ対応した状態のため、実際にはシングルコアでしか動作しません(Virtual PC上のXPモードがシングルプロセッサのみをサポートしているためと考えられます)。そこでHALを入れ替えることでマルチコアを有効にする方法を説明したページを見つけました。

VMware Player 3の XP Mode をマルチコアで動かす方法

要約:
  1. %systemroot%\Driver Cache\i386\sp3.cabに格納されているhalaacpi.dllおよびhalmacpi.dllを%systemroot%\system32にコピー
  2. boot.iniの起動オプションに
    multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional (ACPI/APIC)" /noexecute=optin /fastdetect /hal=halaacpi.dll
    を追加してシャットダウン
  3. VMの設定でプロセッサコア数を2に変更
  4. VMを起動してオペレーティングシステムの選択で下の項目("Microsoft Windows XP Professional (ACPI/APIC)")を選択して起動
  5. ハードウェアの変更が自動的に検出されドライバのインストール後に再起動を求められるので再起動
  6. オペレーティングシステムの選択で今度は上の項目("Microsoft Windows XP Professional")を選択して起動
  7. タスクマネージャでCPUが2つになっていることを確認
  8. boot.iniの起動オプションに追加した"Microsoft Windows XP Professional (ACPI/APIC)"を削除


このページの説明ではHALを入れ替えることなくVMのCPU割り当てを2以上にするとBSODになる、とされていますが、手元のAMD Phenom II X6環境では単純にシングルコア動作になるだけでした。

参考: VMware PlayerおよびXPモードに関する記事のリンク

Windows Server Insider 検証 - @IT
Windows XP Modeとディスク管理機能 - @IT

2011年4月15日

DelphiでSingletonパターンを実装する(再考)

初回のアーティクルにシングルトンのインスタンスは外部から破棄可能だけどいいの?(意訳)というご意見を高橋さんから頂きました。確かにどの実装も、取得したインスタンスに対してFree(あるいはDestroy)を行うことで解放できてしまいます。

シングルトンに求められる条件を考えれば、インスタンスを破棄された後でアクセスされたときはインスタンスを再度生成する("Phoenix Singleton")か、外部からは破棄できないようにするか、いずれかが望ましいと考えられます。

まず再生成する場合です。こちらはインスタンスの破棄時にインスタンスへの参照を初期化することで、次回参照時にインスタンスを再度生成します。initialization/finalization版から。
unit Unit20;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;

{ TSingleton }

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Delete singleton reference }
  FSingleton := nil;

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

initialization
  FSingleton := nil;

finalization
  FSingleton.Free;

end.
再生成する場合のclass constructor/class destructor版です。
unit Unit22;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Delete singleton reference }
  FSingleton := nil;

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

end.
次に外部からの破棄を禁止する場合です。destructor Destroy (ja)もconstructor Create (ja)と同様にTObjectでpublicとされていてスコープを狭化できないため、例外を送出することでインスタンスの破棄をブロックしています(コンストラクタと違いドキュメントなどで明示されていませんが、逆アセンブル表示で見る限りデストラクタもまた例外の送出で処理をブロックできると考えます)。ただし通常のコンストラクタ呼び出しからデストラクタが呼ばれる場合と、終了時にデストラクタが呼ばれる場合はフラグで区別して通常の処理を行います。
こちらもinitialization/finalization版から。
unit Unit24;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;

  EDestroySingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;
  FInternalDestroy: Boolean;

{ TSingleton }

constructor TSingleton.Create;
begin

  FInternalDestroy := True;
  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  if FInternalDestroy = False then
  begin
    raise EDestroySingleton.Create('TSingleton.Destroy cannnot use.');
  end;
  FInternalDestroy := False;

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

initialization
  FSingleton := nil;

finalization
  FInternalDestroy := True;
  FSingleton.Free;

end.
最後に外部から破棄を禁止する場合のclass constructor/class destructor版です。
unit Unit26;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
      FInternalDestroy: Boolean;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;

  EDestroySingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  FInternalDestroy := True;
  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  FInternalDestroy := True;
  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  if FInternalDestroy = False then
  begin
    raise EDestroySingleton.Create('TSingleton.Destroy cannnot use.');
  end;
  FInternalDestroy := False;

  { Finalize }

  inherited Destroy;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

end.

2011年4月14日

DelphiでSingletonパターンを実装する(Monitor版)

前回の実装のなかで、CriticalSectionを使用して排他をかけるもの(Unit12)がありましたが、Delphi 2009の新機能のなかにMonitor (ja)という同期メカニズムがあります。そこでCriticalSectionのかわりにMonitorを使用したバージョンを作ってみました。

unit Unit18;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
      FLock: TObject;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;
  FLock := TObject.Create;

end;

class destructor TSingleton.Destroy;
begin

  FLock.Free;
  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  System.TMonitor.Enter(FLock);
  try
    if FSingleton = nil then
    begin
      FSingleton := TSingleton.CreateInstance;
    end;

  finally
    System.TMonitor.Exit(FLock);
  end;

  Result := FSingleton;

end;

end.

元ねたは

What is TMonitor in Delphi System unit good for? - Stack Overflow
Monitor (synchronization) - Wikipedia, the free encyclopedia (ja)
Craig Stuntz’s Weblog : Why Has the Size of TObject Doubled In Delphi 2009?
The Oracle at Delphi » Simmering Unicode, bring DPL to a boil
The Oracle at Delphi » Simmering Unicode, bring DPL to a boil (Part 2)
The Oracle at Delphi » Breaking the rules

あたり。System.TMonitorの詳しい説明とかサンプルはないんでしょうか?

2011/04/15追記: .NET FrameworkのMonitorクラスの説明が参考になりそうです。

Monitor クラス (System.Threading)

実装例は第15回 エンバカデロ・デベロッパーキャンプの【A5】Delphi/C++テクニカルセッション「詳説!DataSnap 2010」のコネクションプーリングの実装あたりでしょうか(高橋さん、いつも情報ありがとうございます)。

2011年4月13日

TMS IDE Rich Clip

以前、デベロッパーキャンプなどのプレゼンテーション資料を作ったりするときにDelphiのコードをMicrosoft WordやPowerPointにきれいに貼り付けるにはどうしたらいいか、という話がありましたが、TMS SoftwareがDelphi 2010/XE用に

TMS IDE Rich Clip

というIDEプラグインを無償で公開しているのを見つけました。IDE上でコードを選択した状態で編集メニューの"Copy as RTF"あるいは"Copy as HTML"を指定すると、コードがシンタックスハイライトされたRTF/HTML形式でクリップボードにコピーされます。

ただ試した範囲ではインストーラが正しくパッケージをIDEに組み込むことができず、一旦パッケージを削除してから改めて登録する必要がありました。IDE起動時にエラーになった場合はコンポーネント|パッケージでパッケージ一覧を表示し、当該パッケージを削除した後で再度追加してみてください。

元ねたはTMS Software | Blog | Color your Delphi source code on the clipboard

Microsoft Monthly Update 2011/04

今日はMicrosoftのセキュリティアップデートの日です。
MS11-018
MS11-019
MS11-020
MS11-021
MS11-022
MS11-023
MS11-024
MS11-025
MS11-026
MS11-027
MS11-028
MS11-029
MS11-030
MS11-031
MS11-032
MS11-033
MS11-034

Windows 2000 SP4ではMS11-025のVisual C++ 2005 SP1 Redistributable Packageを適用するとMFC80*.DLLを使用するプログラムが起動しなくなるため、MBSAで警告されても無視しましょう(Windows XP以降でKernel32に追加された関数をスタティックにリンクしているため)。

2011/04/15追記: MS11-025の更新プログラムはWindows 2000あるいはWindos 2000をターゲットに開発する環境には適用するべきではないようです。

Security Update KB2467174 kills Windows 2000 compatibility of mfc90.dll
New redists break all dynamically linked MFC 2005/2008 apps on Windows 2000 « Ted's Blog

自動更新あるいはMBSAの警告に従ってWindows 2000にMS11-025のRedistributable Packageの更新プログラムを適用してしまい、FindActCtxSectionStringAが欠陥エクスポートとなってプログラムが起動できなくなった場合は、更新プログラムを削除→MFC80*.DLL/MFC90*.DLLを削除→古いRedistributable Packageをダウンロードしてインストール、という手順でとりあえず回復することができます(最終的にどのような解決が図られるのかは不明ですが)。

ダウンロードの詳細 : Visual C++ 2005 SP1 再頒布可能パッケージ (x86)
ダウンロードの詳細 : Visual C++ 2008 SP1 再頒布可能パッケージ (x86)

Visual Studioについても同様で、MS11-025の更新プログラムを適用してMFCアプリケーションをリビルドするとWindows 2000では動作しないバイナリが生成されます。

2011/05/02追記: MS11-025の問題についてはこちらのアーティクルを参照してください。

2011年4月12日

DelphiでSingletonパターンを実装する(続き)

前回の実装では基本的にinitialization (ja)/finalization (ja)部でインスタンス変数を処理していましたが、この方法だと(T)Singletonを実際には使用していなくてもDelphiのリンカがそれを認識できず、TSingletonのコードを常にリンク対象としてしまう、という問題点があります(それ以上にあんまりオブジェクト指向っぽくない、という点も…)。そこでinitialization/finalization部の処理をDelphi 2010で導入されたクラスコンストラクタ (ja)/クラスデストラクタ (ja)で置き換えて、必要ないコードのリンクが行われないようにしてみます。

まず"シングルトンもどき"です。
unit Unit4;

interface

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

function Singleton: TSingleton;


implementation

var
  FSingleton: TSingleton;

function Singleton: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.Create;
  end;

  Result := FSingleton;

end;

class constructor TSingleton.Create;
begin

  FSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  inherited;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

end.
次に"本当の"シングルトンです。
unit Unit8;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                read  FTestValue
                write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := nil;

end;

class destructor TSingleton.Destroy;
begin

  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

end.
CriticalSectionによる排他処理を加えたものです。
unit Unit12;

interface

uses
  SysUtils, Windows;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
      FCriticalSection: TRTLCriticalSection;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

type
  TInitializeCriticalSectionExFunc = function(var lpCriticalSection: TRTLCriticalSection;
                                              dwSpinCount: DWORD;
                                              Flags: DWORD): BOOL; stdcall;

const
  CRITICAL_SECTION_NO_DEBUG_INFO = $01000000;

class constructor TSingleton.Create;
var
  InitializeCriticalSectionEx: TInitializeCriticalSectionExFunc;
begin

  FSingleton := nil;

  @InitializeCriticalSectionEx := GetProcAddress(GetModuleHandle(kernel32),
                                                 'InitializeCriticalSectionEx');
  if Assigned(InitializeCriticalSectionEx) = True then
  begin
    InitializeCriticalSectionEx(FCriticalSection,0,CRITICAL_SECTION_NO_DEBUG_INFO);
  end
  else
  begin
    InitializeCriticalSectionAndSpinCount(FCriticalSection,0);
  end;

end;

class destructor TSingleton.Destroy;
begin

  DeleteCriticalSection(FCriticalSection);
  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  EnterCriticalSection(FCriticalSection);
  try
    if FSingleton = nil then
    begin
      FSingleton := TSingleton.CreateInstance;
    end;

  finally
    LeaveCriticalSection(FCriticalSection);
  end;

  Result := FSingleton;

end;

end.
最後に事前初期化版です。
unit Unit16;

interface

uses
  SysUtils, Windows;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    class var
      FSingleton: TSingleton;
    constructor CreateInstance;
  public
    class constructor Create;
    class destructor  Destroy;
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

{ TSingleton }

class constructor TSingleton.Create;
begin

  FSingleton := TSingleton.CreateInstance;

end;

class destructor TSingleton.Destroy;
begin

  FSingleton.Free;

end;

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  Result := FSingleton;

end;

end.
プロジェクト内でTSingletonを使用していない場合、TSingleton関係のコードがリンクされないことがわかります。

TMS Smooth Controls for Delphi and C++Builder XE

まだ正式なアナウンスはありませんが、RADStudio/Delphi/C++Builder XEの登録ユーザ向にTMS SoftwareのTMS Smooth Controls for Delphi and C++Builder XEがCodeCentralからダウンロードできるようになっています。

28271 TMS Smooth Controls for Delphi and C++Builder XE

どうやらUSで始まったGet RAD Studio XE at the Delphi/C++Builder Price!というキャンペーンの一環でPlus bonus TMS Smooth Controls Pack at no extra chargeということのようです。日本ではどうなるのでしょうか。高橋さん、情報ありがとうございます。

2011/06/01追記: 登録ユーザダウンロードに表示されているのでいまさらのような気がしますが、日本でもキャンペーンが始まったようです。

Team Japan » 「TMS Smooth Controls Pack for Delphi XE and C++Builder XE」を入手しよう
強力なビジュアル開発ツールスイート「RAD Studio XE」にアップグレードしよう!

2011年4月11日

DelphiでSingletonパターンを実装する

GoFによるデザインパターンシングルトンパターンをDelphiで実装することを考えてみます。シングルトンパターン(Singleton pattern)とは、
あるクラスに対してインスタンスが1つしか存在しないことを保証し、それにアクセスするためのグローバルな方法を提供する。
ことを目的とした"生成に関するパターン"の一つです。

最初に"シングルトンもどき"です。Delphiプログラマがシングルトンと聞くと、Printerオブジェクト(Printers.Printer (ja))を思い浮かべることが多いのではないでしょうか。Printerは厳密な意味でのシングルトンではありませんが、実用上はこの程度の実装で十分なことが多いのも確かです。この"シングルトンもどき"("Printerパターン"?)は、唯一となるべきインスタンスを格納する変数を隠蔽して、代わりにインスタンスを返す関数を用意しておき、最初のアクセスでインスタンスを生成する、というやりかたで、実際には複数のインスタンスを生成することが可能なのですが、逆にグローバルなインスタンスは一つでも、ローカル/一時的なインスタンスはそれとは別に生成したい、というような場合にはとても適合しています。
unit Unit2;

interface

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
  public
    constructor Create;
    destructor  Destroy; override;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

function Singleton: TSingleton;


implementation

var
  FSingleton: TSingleton;

function Singleton: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.Create;
  end;

  Result := FSingleton;

end;

constructor TSingleton.Create;
begin

  inherited;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

initialization
  FSingleton := nil;

finalization
  FSingleton.Free;

end.
Singleton関数を通してグローバルな唯一のインスタンスを取得することができ、必要に応じてコンストラクタを呼び出すことでローカル/一時的なインスタンスを生成することもできます。

次に"本当の"シングルトンを考えてみます。ただしDelphiでは、全てのクラスがpublicなconstructor Create (ja)を持つTObject (ja)から派生しており、かつメンバ関数のスコープを狭めることができないという言語仕様から、C++やJavaのように通常のコンストラクタ呼び出しをコンパイルエラーにすることができません。そこで次善の策としてpublicなコンストラクタを呼び出すと例外がraiseされ、インスタンスの生成に失敗するようにしてみました。
unit Unit6;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;

{ TSingleton }

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  if FSingleton = nil then
  begin
    FSingleton := TSingleton.CreateInstance;
  end;

  Result := FSingleton;

end;

initialization
  FSingleton := nil;

finalization
  FSingleton.Free;

end.
TSingleton.GetInstanceを呼び出すことでTSingletonの唯一のインスタンスにアクセスすることができます。

しかしよく指摘されるように、これらの実装には、マルチスレッドになっているプログラム上で別々のスレッドから競合するタイミングでTSingleton.GetInstanceを呼び出すとインスタンスが多重に生成される可能性がある、という問題が存在しています。これを避けるためにCriticalSectionで排他をかけてみます。なおWindows Vista以降ではクリティカルセクション構造体をInitializeCriticalSectionで初期化するとリソースリークし、一方でWindows 2000ではInitializeCriticalSectionで初期化すると残りメモリが逼迫したときにEnterCriticalSectionで例外が発生するという問題があるので、可能であればInitializeCriticalSectionExを、それ以外ではInitializeCriticalSectionAndSpinCount (ja)を呼び出すようにしています。
unit Unit10;

interface

uses
  SysUtils, Windows;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;
  FCriticalSection: TRTLCriticalSection;

{ TSingleton }

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  EnterCriticalSection(FCriticalSection);
  try
    if FSingleton = nil then
    begin
      FSingleton := TSingleton.CreateInstance;
    end;

  finally
    LeaveCriticalSection(FCriticalSection);
  end;

  Result := FSingleton;

end;

type
  TInitializeCriticalSectionExFunc = function(var lpCriticalSection: TRTLCriticalSection;
                                              dwSpinCount: DWORD;
                                              Flags: DWORD): BOOL; stdcall;

const
  CRITICAL_SECTION_NO_DEBUG_INFO = $01000000;

procedure InitializeSingleton;
var
  InitializeCriticalSectionEx: TInitializeCriticalSectionExFunc;
begin

  FSingleton := nil;

  @InitializeCriticalSectionEx := GetProcAddress(GetModuleHandle(kernel32),
                                                 'InitializeCriticalSectionEx');
  if Assigned(InitializeCriticalSectionEx) = True then
  begin
    InitializeCriticalSectionEx(FCriticalSection,0,CRITICAL_SECTION_NO_DEBUG_INFO);
  end
  else
  begin
    InitializeCriticalSectionAndSpinCount(FCriticalSection,0);
  end;

end;

initialization
  InitializeSingleton;

finalization
  DeleteCriticalSection(FCriticalSection);
  FSingleton.Free;

end.
上記の例と同様にTSingleton.GetInstanceでTSingletonの唯一のインスタンスにアクセスすることができますが、GetInstanceを呼び出す毎にEnterCriticalSection/LeaveCriticalSectionするため、一旦インスタンスが生成された後でも本質的に必要のないオーバヘッドが存在しています。

排他処理のコストを無視することができない場合は、通常のシングルトンパターンの実装の長所の一つである"インスタンスの生成を必要になるまで遅延する"を捨てて、インスタンスをアプリケーションの初期化時に生成してしまう、という方法もあります。
unit Unit14;

interface

uses
  SysUtils;

type
  TSingleton = class(TObject)
  private
    FTestValue: Integer;
    constructor CreateInstance;
  public
    constructor Create;
    destructor  Destroy; override;
    class function GetInstance: TSingleton;
    property    TestValue: Integer
                  read  FTestValue
                  write FTestValue;
  end;

  ECreateSingleton = class(Exception)
  end;


implementation

var
  FSingleton: TSingleton;

{ TSingleton }

constructor TSingleton.Create;
begin

  raise ECreateSingleton.Create('TSingleton.Create cannot use.');

end;

constructor TSingleton.CreateInstance;
begin

  inherited Create;

  { Initialize }
  FTestValue := 0;

end;

destructor TSingleton.Destroy;
begin

  { Finalize }

  inherited;

end;

class function TSingleton.GetInstance: TSingleton;
begin

  Result := FSingleton;

end;

initialization
  FSingleton := TSingleton.CreateInstance;

finalization
  FSingleton.Free;

end.
現実のアプリケーションでは常にトレードオフが存在しますので、必要に応じてこれらのいずれかの(あるいはこれ以外でも)実装を選択する、ということになります。なお"これらのシングルトンに必要な実装を行った基底クラス"と"実際に使用するシングルトンの派生クラス"、というアプローチは(個人的には)いろんな意味で望ましいとは思えません。

元ねたはオブジェクト指向における再利用のためのデザインパターン(改訂版) (amazon) (Erich Gamma、Richard Helm、Ralph Johnson、John M. Vlissides著/本位田 真一、吉田 和樹監訳/ソフトバンククリエイティブ/ISBN4-7973-1112-6(ISBN978-4797311129)/5,040円)とHead Firstデザインパターン (amazon) (Eric Freeman、Elisabeth Freeman、Kathy Sierra、Bert Bates著/木下 哲也、有限会社 福龍興業訳/佐藤 直生監訳/ISBN4-87311-249-4/4,830円)。