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円)。

2011年4月8日

[書籍]Delphi in Depth: ClientDataSets

CreateSpaceで注文した

Delphi in Depth: ClientDataSets (CreateSpace, amazon US)/Cary Jensen著/CreateSpace/ISBN 978-1461008583/44.99USD

が配送されてきました(2011/04/01に注文、Shippingの7.38USDを加えて52.37USD=4,537JPY(暫定値)4,450JPY(1USD=84.973JPY))。

元ねたはCary Jensen "Let's Get Technical": Delphi in Depth: ClientDataSets

2011/04/14追記: 日本のAmazonでも扱いが始まったようです。4,795円ですので、CreateSpaceで買うのとあまり変わりませんね。

Amazon.co.jp: Delphi in Depth: Clientdatasets: Cary, Ph.d. Jensen: 洋書

元ねたはOldTPFunさんのtweet

2011/04/28追記: カードの利用明細によると4,450円で決済された模様(円高ですね)。と、確認してみたらamazon.co.jpでの扱いが止まっているようです。Shippingを加えてもCreateSpaceで買ったほうがいいようですね。

2011年4月5日

Delphi 64bitコンパイラスニークプレビュー

64bitコンパイラのスニークプレビューとベータプログラムがアナウンスされています。

Delphi 64-bit コンパイラ・スニークプレビュー (EDN/ja)
Delphi 64-bit Compiler Sneak Preview (日本語情報、プレビュービデオに日本語字幕付き)

Delphi 64-bit Compiler Sneak Preview (EDN/en)
Delphi 64-bit Compiler Sneak Preview
Delphi Insider: Delphi 64-bit Compiler Sneak Preview and Beta - Official Announcement
Delphi 64-bit Compiler Preview and Beta Program | Andreano Lanusse Blog | Technology and Software Development

スニークプレビューは先日のデベロッパーキャンプのT1セッションのものとほぼ同一(素材はおそらく前日の韓国向けのもの)でした。ベータプログラムはRAD Studio/Delphi XEユーザを優先、という話は64-bit版Delphiフィールドテストのご案内にもあるとおりです。

プレビュービデオを見ていて、呼出規約が原則として単一になる、というところで、safecall (ja)は依然として特別扱いになる(safecall is still "special")、という一文があることに気付きました。safecallとはヘルプにsafecall 規約は、例外 'firewalls' を実装しています。 Win32 では、これがプロセス間の COM エラー通知を実装しています。とあるようにCOMインタフェースにおける例外保護を追加したものになります(Wikipediaにも解説がありますね)。

RAD Studio/Delphi/C++Builder XE付属のFinalBuilderのアップデート

RAD Studio/Delphi/C++Builder XEにバンドルされているFinalBuilderがアップデートされ、FinalBuilder Embarcadero Edition(Ent/Arc SKUのみ)が7.0.0.1105になっています。

FinalBuilder Update for RAD Studio XE, Delphi XE and C++Builder XE
RAD Studio XE, Delphi XE, C++Builder XE向け FinalBuilder アップデート
28278 FinalBuilder for Delphi, C++Builder and RAD Studio XE

FinalBuilder 7 Version History

2011年4月1日

Pulsarフィールドテスト

先日のデベロッパーキャンプのときにも話に出ていた次期版Delphi(Pulsar)のフィールドテスタ募集のお知らせです。

64-bit版Delphiフィールドテストのご案内

今回は「品質向上のためのフィードバックを目的としたフィールドテスト」(今回募集)と「新バージョンに向けての動作検証や開発準備を目的としたフィールドテスト」(後日募集予定)に(時期や目的を)分けて行うようです。64bit版Delphiが欲しくて仕方がなかった人は積極的に参加してみてはいかがでしょう。

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

2011/04/14 15:00-16:00(JST) 次世代ToolCloud - AppWaveによるアプリケーション配布の管理
2011/04/19 17:00-18:00(JST) 次世代ToolCloud - AppWaveによるアプリケーション配布の管理
2011/04/21 17:00-18:00(JST) データベース開発者のためのDB PowerStudio入門
2011/04/27 17:00-18:00(JST) DB PowerStudioで実現するデータベース管理の効率化