2012年12月25日

[書籍]デバッグの理論と実践

MARUZEN&ジュンク堂書店 渋谷店Why Programs Fail, 2nd Editionの翻訳である

デバッグの理論と実践 (amazon)/Andreas Zeller著/今田昌宏、大岩尚宏、竹田香苗、宮原久美子、宗形紗織訳/中田秀基監訳/オライリージャパン/ISBN 978-4-87311-593-1/3,360円

を購入。

2012年12月24日

[eBook]Parallel Programming with OmniThreadLibrary

LeanpubでPrimoz GabrijelcicさんによるDelphi上のマルチスレッドライブラリOmniThreadLibrary(OTL)の解説書である

Parallel Programming with OmniThreadLibrary/Primoz Gabrijelcic著/Leanpub/30.00USD

を購入(PDF/EPUB/MOBIをダウンロード可能)。

この本は現在も執筆中で、状況はThe Delphi Geek: Parallel Programming with OmniThreadLibrary – Current Statusで確認できます。現時点(2012/12/24)ではだいたい半分ちょっとまで書き進んだ感じです。

2012年12月19日

IDE Fix Pack 5.2

Andreas HausladenさんIDE Fix Pack 2009-XE2がアップデートされてVersion 5.2になっています。Delphi 2009用のIDE Fix PackがWindows 8上でクラッシュする問題が修正されています(Delphi 2009以外のものは5.1のままです)。

IDE Fix Pack 5.2 for Delphi 2009 – Windows 8 fix | Andy's Blog and Tools

2012年12月12日

2012年12月10日

RAD Studio/Delphi/C++Builder XE3 Update 1

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

28984 Delphi XE3 and C++Builder XE3 ISO (includes Update 1)
28985 Delphi XE3 and C++Builder XE3 ISO (includes Update 1)

Update 1 for RAD Studio XE3, Delphi XE3 and C++Builder XE3
RAD Studio XE3/Delphi XE3/C++Builder XE3 Update 1

RAD Studio XE3(Delphi XE3/C++Builder XE3) Update 1 における不具合修正リスト (en)

C++Builder 64 ビット Windows 版のリリース ノート - RAD Studio XE3 (en)
リリース ノート: Delphi XE3 および C++Builder XE3 Help Update 2 - RAD Studio XE3 (en)

C++Builder XE3のWindows x64版に関係するオンラインヘルプの項目:2013/01/21追記: XE3 Update 1にはXE3 Help Update 2が含まれているようです。関連リンクを追加しました。

OVERFLOWCHECKS/RANGECHECKSオプションの効果

このアーティクルはDelphi Advent Calendar 2012に参加しています(7日ぶり2回目)。

Delphiにはオーバフローチェックと範囲チェックというコンパイラオプションがあります。

オーバーフローのチェック(Delphi) - RAD Studio XE3
範囲チェック - RAD Studio XE3

いずれもプロジェクトオプションのコンパイラで指定するか、{$OVERFLOWCHECKS ON|OFF}{$RANGECHECKS ON|OFF}で任意の範囲に対して指定することができます。しかしデフォルトの状態ではどちらもOFFなので、ONにした場合の

オーバーフローのチェックを有効にすると,プログラムは遅くなり,またいくらか大きくなるため,{$Q+} はデバッグにのみ使用してください。

範囲チェックを有効にすると、プログラムの処理速度が遅くなり、サイズも多少大きくなります。

が実際にどのようなことを示しているのかを知っている人は意外に少ないのではないでしょうか。そこでこれらのオプションによるペナルティがどのようなものなのかを確認してみます(Delphi XE2/Windows x86/Debugビルドで検証)。

まず{$OVERFLOWCHECKS ON}(短縮形{$Q+})です。
var
  a: Integer;
  b: Integer;
  c: Integer;
begin
{$OVERFLOWCHECKS ON}
  a := $44444444;
  b := $44444444;
  c := a + b;
{$OVERFLOWCHECKS OFF}
end;
このコードは以下のように展開されます。

Unit1.pas.36: a := $44444444;
0051139C C745F844444444   mov [ebp-$08],$44444444
Unit1.pas.37: b := $44444444;
005113A3 C745F444444444   mov [ebp-$0c],$44444444
Unit1.pas.38: c := a + b;
005113AA 8B45F8           mov eax,[ebp-$08]
005113AD 0345F4           add eax,[ebp-$0c]
005113B0 7105             jno $005113b7
005113B2 E8BD39EFFF       call @IntOver
005113B7 8945F0           mov [ebp-$10],eax
赤で示した2行が{$OVERFLOWCHECKS ON}で追加される命令になります。直前のadd命令の結果、OF(overflow flag)がセットされていればIntOver(System.pasのprocedure _IntOver)を呼び出して例外EIntOverflowが生成されます。{$OVERFLOWCHECKS ON}とすることで、特定の整数算術演算(+,-,*,Abs,Sqr,Succ,Pred,Inc,および Dec)毎にこのコードが追加で生成される、ということのようです。

一方{$RANGECHECKS ON}(短縮形{$R+})ですが、これには配列および文字列の添字のチェックとスカラ型/部分範囲型変数への代入時の範囲チェックの2つの効果があります。まず添字のチェックですが、ちょっとわかりづらいので{$RANGECHECKS OFF}のものと両方を並べてみます。
var
  s: String;
  c: Char;
begin
  s := 'TEST';
  c := s[6];
{$RANGECHECKS ON}
  c := s[6];
{$RANGECHECKS OFF}
end;
このコードは以下のように展開されます。

Unit1.pas.52: c := s[6];
00511464 8B45F8           mov eax,[ebp-$08]
00511467 668B400A         mov ax,[eax+$0a]
0051146B 668945F6         mov [ebp-$0a],ax
Unit1.pas.54: c := s[6];
0051146F B806000000       mov eax,$00000006
00511474 8B55F8           mov edx,[ebp-$08]
00511477 48               dec eax
00511478 85D2             test edx,edx
0051147A 7405             jz $00511481
0051147C 3B42FC           cmp eax,[edx-$04]
0051147F 7205             jb $00511486
00511481 E8E638EFFF       call @BoundErr
00511486 40               inc eax
00511487 668B4442FE       mov ax,[edx+eax*2-$02]
0051148C 668945F6         mov [ebp-$0a],ax
{$RANGECHECKS OFF}の場合は単に文字列の格納されているアドレスに添字-(1*SizeOf(Char))を足した場所にアクセスしているだけですが、{$RANGECHECKS ON}では空文字列かどうかのチェック(赤字)と文字列長以内かどうかのチェック(青字)が行われていることを含め、添字の一時的なデクリメント(文字列の添字が1オリジンなので)など、結構複雑な処理が行われていることがわかります(こちらは例外ERangeErrorが生成されます)。

最後に部分範囲型の変数への代入を見てみます。
type
  TSubInt = 8..15;
var
  a: TSubInt;
  b: TSubInt;
  c: TSubInt;
begin
{$RANGECHECKS ON}
  a := 8;
  b := 8;
  c := a + b;
  a := 9;
  b := 8;
  c := a - b;
{$RANGECHECKS OFF}
end;
加算と減算の両方を確認してみます。

Unit1.pas.69: a := 8;
005114D8 C645FB08         mov byte ptr [ebp-$05],$08
Unit1.pas.70: b := 8;
005114DC C645FA08         mov byte ptr [ebp-$06],$08
Unit1.pas.71: c := a + b;
005114E0 33C0             xor eax,eax
005114E2 8A45FB           mov al,[ebp-$05]
005114E5 33D2             xor edx,edx
005114E7 8A55FA           mov dl,[ebp-$06]
005114EA 03C2             add eax,edx
005114EC 83C0F8           add eax,-$08
005114EF 83F807           cmp eax,$07
005114F2 7605             jbe $005114f9
005114F4 E87338EFFF       call @BoundErr
005114F9 83C008           add eax,$08
005114FC 8845F9           mov [ebp-$07],al
Unit1.pas.72: a := 9;
005114FF C645FB09         mov byte ptr [ebp-$05],$09
Unit1.pas.73: b := 8;
00511503 C645FA08         mov byte ptr [ebp-$06],$08
Unit1.pas.74: c := a - b;
00511507 33C0             xor eax,eax
00511509 8A45FB           mov al,[ebp-$05]
0051150C 33D2             xor edx,edx
0051150E 8A55FA           mov dl,[ebp-$06]
00511511 2BC2             sub eax,edx
00511513 83C0F8           add eax,-$08
00511516 83F807           cmp eax,$07
00511519 7605             jbe $00511520
0051151B E84C38EFFF       call @BoundErr
00511520 83C008           add eax,$08
00511523 8845F9           mov [ebp-$07],al
加算、減算とも計算後に一時的に部分範囲の最小値を引いて、部分範囲におさまっているかどうかのチェックを行い(赤字)、改めて最小値を足す(青字)など、これもまた複雑な処理になっています。

ということで、オーバフローチェックはFLAGSレジスタのOFを検査するだけなので比較的ペナルティは小さく、オーバフローを検出したい状況では積極的にONにしても問題なさそうです。一方範囲チェックは範囲の最小値が0でないと処理が複雑になることもあり、明示的に必要な範囲チェックのコードを記述したほうがいいような気もします。

2012年12月7日

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

本日10:00から第24回エンバカデロ・デベロッパーキャンプ東京ビッグサイト(東京国際展示場)の会議棟6Fで行われます。今回も一部のセッションがUStreamで中継されますが、残念ながらG6は中継なしとのことです。
  • 【A1】HTML5チュートリアルセッション「HTML5によるモバイル/タブレットアプリケーション開発」
  • 【B1】Delphiチュートリアルセッション「Delphiで学ぶ楽しいプログラミング基礎 - 出来るプログラマになる第一歩」
  • 【A2】Delphi/C++Builderテクニカルセッション「“FireMonkey が得意とするビジネスアプリ” の考察」
  • 【B2】C++テクニカルセッション「C++言語新機能を使おう!」
  • 【G3】ジェネラルセッション「エンバカデロ・プロダクトアップデート」
  • 【A4】Delphi/C++Builderテクニカルセッション「RAD Studio XE3によるWindows 8開発」
  • 【B4】 Delphi/C++Builderテクニカルワークショップ「Delphi / C++Builder 旧バージョンアプリケーションの移行」
  • 【A5】 Delphiテクニカルセッション「Delphi+Visual LiveBindingによるデータベースアプリケーション開発」
  • 【B5】 C++テクニカルセッション「C++Builder 64-bit Deep Dive」
  • 【G6】 Q & Aセッション「アスク・エンバカデロ」
第24回 エンバカデロ・デベロッパーキャンプ - セッション資料ダウンロード

2012/12/11追記: いろいろ忙しくてアーティクルの更新を忘れていました。最後の最後にどんでん返しがありましたが、無事に終了しました。セッションスピーカ、参加者、関係者の皆さん、おつかれさまでした。今回のデベロッパーキャンプでの情報としては
  • C++Builder x64版は2012/12/10リリース予定(既にリリース済ですが)
  • Mobile StudioはまもなくiOSについてベータ開始、春頃?リリース希望
  • Mobile Studio for AndroidはiOSのあと、今年の前半にはリリース希望
  • Mobile StudioのDelphiコンパイラは既にLLVMベースで動作?(未確認)
  • Mobile Studioのベータに参加してこんな機能がほしいという希望を出してほしい
  • Windows用のインストーラについては現在いろいろな製品を評価中
といったところでしょうか。また早くもセッション資料とリプレイビデオがアップロードされています。

2012年12月6日

C++Builder 64-bit Compiler Preview

C++Builder 64-bit Compiler Previewが公開されています。

29197 C++Builder 64-bit Compiler Preview

YouTubeにも同じビデオがアップロードされています(限定公開のようなので上記のリンクからたどってください)。

2012年12月3日

ジェネリックスの型パラメータに対する制約

このアーティクルはDelphi Advent Calendar 2012に参加しています。

ジェネリックスでは渡される型パラメータに関する制約を指定することができます。

ジェネリックスの制約 - RAD Studio XE3

ここで制約としてインタフェース型またはクラス型を指定すると型パラメータは必然的にそのクラス型、インタフェース型になります。またconstructorを指定すると型パラメータはクラス型になります(レコード型はパラメータを持たないコンストラクタを定義できないため)。classを指定するとこれもまたクラス型、インタフェース型になります(ヘルプ参照)。

では最後に残ったrecordを指定(レコード指定)した場合、型パラメータに許される型はレコード型だけなのでしょうか?実際にはレコード型だけではなく、いわゆる値型(参照型ではないもの)であればいいようで、IntegerやCardinal、あるいは部分範囲型や列挙型も指定することができます。
type
  TConstraintTest<T: record> = record
    class procedure TestProc(Value: Integer); static;
  end;

class procedure TConstraintTest<T>.TestProc(Value: Integer);
begin
  { No operation }
end;
このようなジェネリックスを定義すると、
type
  TTestRange = 1..5;
  TTestEnum = (One, Two, Three);

begin
  TConstraintTest<TPoint>.TestProc(0);
  TConstraintTest<Integer>.TestProc(0);
  TConstraintTest<Cardinal>.TestProc(0);
  TConstraintTest<TTestRange>.TestProc(0);
  TConstraintTest<TTestEnum>.TestProc(0);
end;
これらはすべて正しくコンパイルされます。

ただしString型は参照型でありながらクラス型ではないため、constructor以外の制約を指定された型パラメータにStringを指定するとコンパイルエラーになります("class"を指定するとE2511 型パラメータ 'T' はクラス型が必要です、"record"を指定するとE2512 型パラメータ 'T' は非 null 値型が必要ですとなる)。つまり文字列型を受け入れるためには型パラメータに制約を指定しないか、constructor制約を指定するかのいずれかが必要ということになります。

元ねたはDelphi XE2 Foundations

2013/07/03追記: constructor制約については細川さんによる考察が参考になります。

2012年11月25日

[ebook]Delphi XE2 Foundations

Amazon KindleストアでChris RollistonさんDelphi XE2 Foundationsのebook(Kindle)版である

Delphi XE2 Foundations - Part 1 [Kindle版]/Chris Rolliston著/Amazon Services International, Inc./792円
Delphi XE2 Foundations - Part 2 [Kindle版]/Chris Rolliston著/Amazon Services International, Inc./792円
Delphi XE2 Foundations - Part 3 [Kindle版]/Chris Rolliston著/Amazon Services International, Inc./792円

を購入。書籍版も買いましたが、あの分厚いのを持ち歩くのは結構大変だし、3分冊合わせても2,400円しない(書籍版は4,500円くらいかかる)のでまぁいいかと。

2012年11月19日

Kindle Paperwhite

Amazon.co.jpで注文した

Kindle Paperwhite/7,980円

が配送されてきました(今回の配送はクロネコヤマト)。

2012年11月16日

[書籍]実践 パケット解析 第2版

ブックファースト 渋谷文化村通り店Practical Packet Analysis, 2nd Edition (O'Reilly, amazon)の翻訳である

実践 パケット解析 第2版 (amazon)/Chris Sanders著/岡真由美訳/高橋基信、宮本久仁男監訳/オライリージャパン/ISBN 978-4-87311-569-6/2,940円

を購入。

2012年11月14日

Microsoft Monthly Update 2012/11

今日はMicrosoftのセキュリティアップデートの日です。
MS12-071
MS12-072
MS12-073
MS12-074
MS12-075
MS12-076

2012年11月7日

Firebird 2.5.2

Firebird Ver2.5.2がリリースされています。

Firebird: Firebird 2.5.2
Firebird 2.5 Release Notes (PDF)

なお2.5.1から2.5.2以降にバージョンアップする場合はgbakによるバックアップ/リストアを行うことが強く推奨されているので注意が必要です(これが不可能な場合は少なくとも複合インデックスをリビルドすること)。詳細はリリースノートを参照してください。

元ねたはFirebird News » Firebird 2.5.2 sub-release is available with many bugfixes

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

第24回エンバカデロ・デベロッパーキャンプは2012年12月07日に開催されます。

エンバカデロ・デベロッパーキャンプ | ホーム
エンバカデロ、12月7日に開発者向け技術イベントを開催 | Press Releases
第24回 エンバカデロ・デベロッパーキャンプ | Facebook
Delphi Talks 3 | Facebook

今回はRAD StudioプロダクトディレクタのJT@EmbarcaderoことJohn Thomasさんとローカライズ/ドキュメント担当マネージャの新井正広さんがいらっしゃるとのことです。目玉はC++Builderのx64コンパイラでしょうか。またPress ReleaseにはC++Builderの64-bitサポートは、すでにC++Builder XE3またはRAD Studio XE3を購入したユーザーには、無償ダウンロードで提供される予定です。という記述もありますね。

Marco CantuがDelphiプロダクトマネージャに

現在進行中のCodeRage 7のTechnical Session #4 PRODUCT ADDRESS: Delphi & C++Builderで、Delphi HandbookシリーズなどでおなじみのMarco Cantuさんが新しいDelphiのプロダクトマネージャになったことがアナウンスされました。David Iさんのtweetから。

https://twitter.com/davidi99/status/265847230009835520
Delphi Product Address session starting now. John Thomas, Sarina Dupont and new Delphi product manager Marco Cantu

Marco Cantuさんのtweetも。

https://twitter.com/marcocantu/status/265849281007722497
So it's official now: I'm joining Embarcadero as Delphi Product Manager. Will still be based in Italy.

Marco Cantuさんのblogにもアーティクルがあがっています。

Joining Embarcadero as Delphi Product Manager

JTさんのblogにも。

JT @ Embarcadero » Welcome Marco Cantu - Delphi Product Manager

2012年11月1日

2012/11開催のウェブセミナー

2012/11/21追記: CodeRage 7のセッションリプレイがCodeCentralとYoutubeにアップロードされていますが、David Iさんのところにリンクがまとめられています。

Sip from the Firehose : CodeRage 7 Delphi conference sessions are ready to watch and download

RAD Studio/Delphi/C++Builder XE3 Help Update 1

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

29134 Help Update 1 for Delphi, C++Builder and RAD Studio XE3
リリース ノート: Delphi XE3 および C++Builder XE3 Help Update 1 - RAD Studio XE3 (en)

2012年10月24日

RAD Studio/Delphi/C++Builder XE3 Hotfix 4

RAD Studio/Delphi/C++Builder XE3のHotfix 4がリリースされています。FireMonkeyにおける韓国語IMEの問題を解決するものです。

29089 RAD Studio XE3 Hotfix 4
Hotfix 4 for RAD Studio XE3, Delphi XE3 and C++Builder XE3

2012年10月10日

Microsoft Monthly Update 2012/10

今日はMicrosoftのセキュリティアップデートの日です。
MS12-064
MS12-065
MS12-066
MS12-067
MS12-068
MS12-069
MS12-070

2012年10月4日

[書籍]インサイドWindows第6版(上)

ブックファースト 新宿店Windows Internals, 6th edition Part 1 (amazon)の翻訳である

インサイドWindows 第6版 上 (amazon)/Mark E. RussinovichDavid A. SolomonAlex Ionescu著/株式会社クイープ訳/日経BP/ISBN 978-4-82229-470-0/7,980円

を購入。なお下巻(Part 2)は2013年春の出版予定とのことです。

ファイルがSSDに書き込まれるかどうかを調べる(2)

前回の続きです。パート2としてATA8-ACSを使用して"nominal media rotation rate"を取得する方法を試してみます(こちらもNyaRuRuさんのコードそのままなので詳細な説明は省略します)。

まずはDeviceIOControlで使用する構造体、定数などを定義します。
type
  { ATA_PASS_THROUGH_EX }
  _ATA_PASS_THROUGH_EX = packed record
    Length: Word;
    AtaFlags: Word;
    PathId: UCHAR;
    TargetId: UCHAR;
    Lun: UCHAR;
    ReservedAsUchar: UCHAR;
    DataTransferLength: ULONG;
    TimeOutValue: ULONG;
    ReservedAsUlong: ULONG;
    DataBufferOffset: ULONG_PTR;
    PreviousTaskFile: array [0..7] of UCHAR;
    CurrentTaskFile: array [0..7] of UCHAR;
  end;
  {$EXTERNALSYM _ATA_PASS_THROUGH_EX}
  ATA_PASS_THROUGH_EX = _ATA_PASS_THROUGH_EX;
  {$EXTERNALSYM  ATA_PASS_THROUGH_EX}
  TAtaPassThroughEx   = _ATA_PASS_THROUGH_EX;
  PAtaPassThroughEx   = ^TAtaPassThroughEx;

  { ATAIdentifyDeviceQuery }
  TATAIdentifyDeviceQuery = packed record
    header: ATA_PASS_THROUGH_EX;
    data: array [0..255] of Word;
  end;

const
{$IF RTLVersion < 22.0}
  FILE_DEVICE_CONTROLLER  = $00000004;
  {$EXTERNALSYM FILE_DEVICE_CONTROLLER}

  FILE_READ_ACCESS        = $0001;
  {$EXTERNALSYM FILE_READ_ACCESS}

  FILE_WRITE_ACCESS       = $0002;
  {$EXTERNALSYM FILE_WRITE_ACCESS}
{$IFEND}

  ATA_FLAGS_DRDY_REQUIRED = $01;
  ATA_FLAGS_DATA_IN       = $02;
  ATA_FLAGS_DATA_OUT      = $04;
  ATA_FLAGS_48BIT_COMMAND = $08;
  ATA_FLAGS_USE_DMA       = $10;
  ATA_FLAGS_NO_MULTIPLE   = $20;

  IOCTL_SCSI_BASE         = FILE_DEVICE_CONTROLLER;
  IOCTL_ATA_PASS_THROUGH  = (IOCTL_SCSI_BASE shl 16) or
                            ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or
                            ($040B shl 2) or
                            (METHOD_BUFFERED);
FILE_DEVICE_CONTROLLER、FILE_READ_ACCESS、FILE_WRITE_ACCESSはDelphi XE以降では定義済ですので、Delphi 2009およびそれ以前のバージョン用に定義しています。 これらを使用して物理ドライブ名"\\.\PhysicalDrive#"で指定したドライブが"nominal media rotation rate"かどうかを調べる関数です。
function HasNominalMediaRotationRate(const PhysicalDrivePath: String): Boolean;
var
  h: THandle;
  ATAIdentifyDeviceQuery: TATAIdentifyDeviceQuery;
  RSize: DWORD;
begin

  h := CreateFile(PChar(PhysicalDrivePath),GENERIC_READ or GENERIC_WRITE,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    FillChar(ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),0);
    with ATAIdentifyDeviceQuery do
    begin
      header.Length := SizeOf(header);
      header.AtaFlags := ATA_FLAGS_DATA_IN;
      header.DataTransferLength := SizeOf(data);
      header.TimeOutValue := 3;  // sec
      header.DataBufferOffset := SizeOf(header);
      header.CurrentTaskFile[6] := $EC;  // ATA IDENTIFY DEVICE command
    end;

    RSize := 0;
    if DeviceIoControl(h,IOCTL_ATA_PASS_THROUGH,
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       @ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
                       RSize,nil) = False then
    begin
      RaiseLastOSError;
    end;

    Result := (ATAIdentifyDeviceQuery.data[217] = 1);

  finally
    CloseHandle(h);
  end;

end;
Trueが返ってくればそのドライブはnominal media rotation rateである、つまりSSDと判断できる、ということになります。こちらの方法はデバイスがATA8-ACSに対応していればWindows 2000およびそれ以降のすべてのOSで使用できますが、Windows Vista以降では管理者権限が必要になります。Delphiで作ったアプリケーションが管理者権限を要求するようにする方法についてはWindows Vista上で管理者権限を要求するアプリケーションを作成するを参照してください。なおWindows Vista以降の環境で管理者権限を要求するアプリケーションをデバッグするときはDelphiのIDEそのものも管理者権限で実行する必要があるようですので注意してください。 ファイル名/パス名から物理ドライブ番号("\\.\PhysicalDrive#"の#)を取得する方法は前回のものを使用できますので、こちらもファイル/パスがSSD上に書き込まれるかどうかを調べてみます。
var
  Index: Integer;
  Filename: String;
  PhysicalDrives: TIntegerDynArray;
  PhysicalDrivePath: String;
  IsSSD: Boolean;
begin

  Filename := "C:\";  // 例: "C:\"を調べます

  SetLength(PhysicalDrives,0);
  PathnameToPhysicalDriveNumber(Filename,PhysicalDrives);

  try
    IsSSD := False;
    for Index := Low(PhysicalDrives) to High(PhysicalDrives) do
    begin
      PhysicalDrivePath := Format('\\.\PhysicalDrive%d',[PhysicalDrives[Index]]);
      try
        IsSSD := IsSSD or HasNominalMediaRotationRate(PhysicalDrivePath);

      except
        { Ignore }
      end;

      if IsSSD = True then
      begin
        Break;
      end;
    end;

    if IsSSD = True then
    begin
      MessageDlg(Format('ファイル ''%s'' はSSDに書き込まれます。',[Filename]),
                 mtInformation,[mbOk],0);
    end
    else
    begin
      MessageDlg(Format('ファイル ''%s'' はSSDには書き込まれません。',[Filename]),
                 mtInformation,[mbOk],0);
    end;

  finally
    SetLength(PhysicalDrives,0);
  end;

end;
OSによって判定方法を切り替えるのであれば、
if CheckWin32Version(6,1) = True then
begin
  { Windows 7 or later }
  IsSSD := IsSSD or HasNoSeekPenalty(PhysicalDrivePath);
end
else
begin
  { Windows Vista or earlier }
  IsSSD := IsSSD or HasNominalMediaRotationRate(PhysicalDrivePath);
end;
とすればよいのですが、こうしたところでアプリケーション全体としては管理者権限が必要になってしまうので微妙な感じです(Vistaを考えなければ管理者権限を要求する必要がなくなりますが…)。

2012年10月3日

ファイルがSSDに書き込まれるかどうかを調べる(1)

プログラムの動作ログをファイルに記録するということはよくあることだと思いますが、単にCreateFile (en)でファイルをオープンするだけだと書き込み内容がOSでキャッシュされてしまい、OSがクラッシュしたり突然の電源断で書き込み内容の一部が失われてしまう可能性があります。これを防ぐにはMSDNのCreateFileのCaching Behaviorの説明に

If FILE_FLAG_WRITE_THROUGH is used but FILE_FLAG_NO_BUFFERING is not also specified, so that system caching is in effect, then the data is written to the system cache but is flushed to disk without delay.

てきとうな訳: FILE_FLAG_NO_BUFFERINGを指定せずにFILE_FLAG_WRITE_THROUGHを指定すると、システムキャッシュは有効となり、データはWindowsのシステムキャッシュに書き込まれますがディスクには遅延なくフラッシュされます。

とあるように、CreateFileの第6パラメータdwFlagsAndAttributesにFILE_FLAG_WRITE_THROUGHを指定します。

しかし大量のログを保存するようなケースで保存先がSSDだと、FILE_FLAG_WRITE_THROUGHの指定によりSSDの劣化が通常よりも早く進行することが予想されます。ということで保存先がSSDかどうかでこれらのフラグを付加するかどうかを決めるようにすればいい、ということになります。しかしドライブがSSDかどうかについては、(1)DeviceIOControl (en)でPropertyIdにStorageDeviceSeekPenaltyPropertyを指定したIOCTL_STORAGE_QUERY_PROPERTYを発行してDEVICE_SEEK_PENALTY_DESCRIPTOR構造体のIncursSeekPenaltyが0(False)になっている("no seek penalty")、(2)ATA8-ACSでドライブの回転数を取得してNominal Media Rotation Rate(0x01)になっている、のどちらかで調べることができる、ということまではわかったものの、さて実際のコード例はというとなかなか参考になるものがなく、手詰まりになっていました。

ところがその数日後、NyaRuRuさんがほぼそのまんまの

SSD なら動作を変えるアプリケーションを作る - NyaRuRuが地球にいたころ

という記事を書いているのを見つけました。これだけきちんとしたサンプルがあればDelphiに置き換えるのも簡単です。ということでパート1として(1)の"no seek penalty"を取得する方法を試してみます(以下NyaRuRuさんのコードそのままなので詳細な説明は省略します)。

まずはDeviceIOControlで使用する構造体、定数などを定義します。
{$IF RTLversion < 22.0}
const
  FILE_READ_DATA               = $0001;
  {$EXTERNALSYM FILE_READ_DATA}

  FILE_READ_ATTRIBUTES         = $0080;
  {$EXTERNALSYM FILE_READ_ATTRIBUTES}

  FILE_DEVICE_MASS_STORAGE     = $0000002d;
  {$EXTERNALSYM FILE_DEVICE_MASS_STORAGE}

  IOCTL_STORAGE_BASE           = FILE_DEVICE_MASS_STORAGE;
  {$EXTERNALSYM IOCTL_STORAGE_BASE}

  FILE_ANY_ACCESS              = 0;
  {$EXTERNALSYM FILE_ANY_ACCESS}

  METHOD_BUFFERED              = 0;
  {$EXTERNALSYM METHOD_BUFFERED}

  IOCTL_STORAGE_QUERY_PROPERTY = (IOCTL_STORAGE_BASE shl 16) or
                                 (FILE_ANY_ACCESS shl 14) or
                                 ($0500 shl 2) or
                                 (METHOD_BUFFERED);
  {$EXTERNALSYM IOCTL_STORAGE_QUERY_PROPERTY}
{$IFEND}

type
  { STORAGE_PROPERTY_ID }
  _STORAGE_PROPERTY_ID = (
    StorageDeviceProperty                 =  0,
    StorageAdapterProperty                =  1,
    StorageDeviceIdProperty               =  2,
    StorageDeviceUniqueIdProperty         =  3,
    StorageDeviceWriteCacheProperty       =  4,
    StorageMiniportProperty               =  5,
    StorageAccessAlignmentProperty        =  6,
    StorageDeviceSeekPenaltyProperty      =  7,
    StorageDeviceTrimProperty             =  8,
    StorageDeviceWriteAggregationProperty =  9,
    StorageDeviceDeviceTelemetryProperty  = 10
  );
  {$EXTERNALSYM _STORAGE_PROPERTY_ID}
  STORAGE_PROPERTY_ID = _STORAGE_PROPERTY_ID;
  {$EXTERNALSYM  STORAGE_PROPERTY_ID}
  TStoragePropertyId  = _STORAGE_PROPERTY_ID;
  PStoragePropertyId  = ^TStoragePropertyId;

  { STORAGE_QUERY_TYPE }
  _STORAGE_QUERY_TYPE = (
    PropertyStandardQuery   = 0,
    PropertyExistsQuery     = 1,
    PropertyMaskQuery       = 2,
    PropertyQueryMaxDefined = 3
  );
  {$EXTERNALSYM _STORAGE_QUERY_TYPE}
  STORAGE_QUERY_TYPE = _STORAGE_QUERY_TYPE;
  {$EXTERNALSYM  STORAGE_QUERY_TYPE}
  TStorageQueryType  = _STORAGE_QUERY_TYPE;
  PStorageQueryType  = ^TStorageQueryType;

  { STORAGE_PROPERTY_QUERY }
  _STORAGE_PROPERTY_QUERY = packed record
    PropertyId: DWORD;
    QueryType: DWORD;
    AdditionalParameters: array[0..9] of Byte;
  end;
  {$EXTERNALSYM _STORAGE_PROPERTY_QUERY}
  STORAGE_PROPERTY_QUERY = _STORAGE_PROPERTY_QUERY;
  {$EXTERNALSYM  STORAGE_PROPERTY_QUERY}
  TStoragePropertyQuery  = _STORAGE_PROPERTY_QUERY;
  PStoragePropertyQuery  = ^TStoragePropertyQuery;

  { DEVICE_SEEK_PENALTY_DESCRIPTOR }
  _DEVICE_SEEK_PENALTY_DESCRIPTOR = packed record
    Version: DWORD;
    Size: DWORD;
    IncursSeekPenalty: ByteBool;
    Reserved: array[0..2] of Byte;
  end;
  {$EXTERNALSYM _DEVICE_SEEK_PENALTY_DESCRIPTOR}
  DEVICE_SEEK_PENALTY_DESCRIPTOR = _DEVICE_SEEK_PENALTY_DESCRIPTOR;
  {$EXTERNALSYM  DEVICE_SEEK_PENALTY_DESCRIPTOR}
  TDeviceSeekPenaltyDescriptor   = _DEVICE_SEEK_PENALTY_DESCRIPTOR;
  PDeviceSeekPenaltyDescriptor   = ^TDeviceSeekPenaltyDescriptor;
FILE_READ_DATA、FILE_READ_ATTRIBUTES、FILE_DEVICE_MASS_STORAGE、FILE_ANY_ACCESS、METHOD_BUFFERED、IOCTL_STORAGE_QUERY_PROPERTYはDelphi XE以降では定義済ですので、Delphi 2009およびそれ以前のバージョン用として定義しています。 これらを使用して物理ドライブ名"\\.\PhysicalDrive#"で指定したドライブが"no seek penalty"かどうかを調べる関数です。
function HasNoSeekPenalty(const PhysicalDrivePath: String): Boolean;
var
  h :THandle;
  StoragePropertyQuery: TStoragePropertyQuery;
  DeviceSeekPenaltyDescriptor: TDeviceSeekPenaltyDescriptor;
  RSize: DWORD;
begin

  h := CreateFile(PChar(PhysicalDrivePath),FILE_READ_ATTRIBUTES,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    with StoragePropertyQuery do
    begin
      PropertyId := Ord(StorageDeviceSeekPenaltyProperty);
      QueryType  := Ord(PropertyStandardQuery);
    end;

    FillChar(DeviceSeekPenaltyDescriptor,SizeOf(DeviceSeekPenaltyDescriptor),0);
    RSize := 0;
    if DeviceIoControl(h,IOCTL_STORAGE_QUERY_PROPERTY,
                       @StoragePropertyQuery,SizeOf(StoragePropertyQuery),
                       @DeviceSeekPenaltyDescriptor,SizeOf(DeviceSeekPenaltyDescriptor),
                       RSize,nil) = False then
    begin
      RaiseLastOSError;
    end;

    Result := not DeviceSeekPenaltyDescriptor.IncursSeekPenalty;

  finally
    CloseHandle(h);
  end;

end;
Trueが返ってくればそのドライブはseek penaltyがない、つまりSSDと判断できる、ということになります。ただしこの方法はWindows 7およびそれ以降でしか使用できません(そのかわり管理者権限は不要です)。 次にファイル名/パス名から物理ドライブ番号("\\.\PhysicalDrive#"の#)を取得する方法です。まず構造体、定数などの定義です。
type
  { DISK_EXTENT }
  _DISK_EXTENT = packed record
    DiskNumber: DWORD;
    StartingOffset: LARGE_INTEGER;
    ExtentLength: LARGE_INTEGER;
    Reserved: array [0..3] of Byte;
  end;
  {$EXTERNALSYM _DISK_EXTENT}
  DISK_EXTENT = _DISK_EXTENT;
  {$EXTERNALSYM  DISK_EXTENT}
  TDiskExtent = _DISK_EXTENT;
  PDiskExtent = ^TDiskExtent;

  { VOLUME_DISK_EXTENTS }
  _VOLUME_DISK_EXTENTS = packed record
    NumberOfDiskExtents: DWORD;
    Reserved: array [0..3] of Byte;
    Extents: array [0..0] of DISK_EXTENT;
  end;
  {$EXTERNALSYM _VOLUME_DISK_EXTENTS}
  VOLUME_DISK_EXTENTS = _VOLUME_DISK_EXTENTS;
  {$EXTERNALSYM  VOLUME_DISK_EXTENTS}
  TVolumeDiskExtents  =  VOLUME_DISK_EXTENTS;
  PVolumeDiskExtents  = ^TVolumeDiskExtents;

{$IF RTLVersion < 22.0}
const
  IOCTL_VOLUME_BASE                    = $00000056;
  {$EXTERNALSYM IOCTL_VOLUME_BASE}

  IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = (IOCTL_VOLUME_BASE shl 16) or
                                         (FILE_ANY_ACCESS shl 14) or
                                         (0 shl 2) or
                                         (METHOD_BUFFERED);
  {$EXTERNALSYM IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS}
{$IFEND}
さきほどと同様にIOCTL_VOLUME_GET_VOLUME_DISK_EXTENTSはDelphi XE以降で定義済ですのでDelphi 2009およびそれ以前のバージョンでのみ定義が必要です。 指定したファイル名/パス名の存在する物理ドライブ番号を動的配列に格納する関数です。
uses
  Types;

procedure PathnameToPhysicalDriveNumber(const Path: String; var PhysicalDrives: TIntegerDynArray);
var
  h: THandle;
  I: Integer;
  MountPoint: String;
  VolumeName: String;
  Size: DWORD;
  RSize: DWORD;
  P: PVolumeDiskExtents;
begin

  SetLength(PhysicalDrives,0);

  { Pathname to mount point }
  Size := GetFullPathName(PChar(Path),0,nil,nil);
  SetLength(MountPoint,Size);
  if GetVolumePathName(PChar(Path),PChar(MountPoint),Size) = False then
  begin
    RaiseLastOSError;
  end;
  SetLength(MountPoint,StrLen(PChar(MountPoint)));

  { Mount point to logical volume name }
  Size := 50;  // Recomended size from http://msdn.microsoft.com/en-us/library/windows/desktop/aa364994.aspx
  SetLength(VolumeName,Size);
  if GetVolumeNameForVolumeMountPoint(PChar(MountPoint),PChar(VolumeName),Size) = False then
  begin
    RaiseLastOSError;
  end;
  SetLength(VolumeName,StrLen(PChar(VolumeName)));
  VolumeName := ExcludeTrailingPathDelimiter(VolumeName);

  { Open volume }
  h := CreateFile(PChar(VolumeName),FILE_READ_ATTRIBUTES,
                  FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
                  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if h = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;

  try
    Size := SizeOf(TVolumeDiskExtents);
    P := AllocMem(Size);
    try
      FillChar(P^,Size,0);
      RSize := 0;
      if DeviceIoControl(h,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                         nil,0,
                         P,Size,
                         RSize,nil) = False then
      begin
        if GetLastError <> ERROR_MORE_DATA then
        begin
          RaiseLastOSError;
        end;

        Size := SizeOf(TVolumeDiskExtents) +
                SizeOf(DISK_EXTENT) * (P^.NumberOfDiskExtents - 1);
        ReallocMem(P,Size);
        FillChar(P^,Size,0);
        if DeviceIoControl(h,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                           nil,0,
                           P,Size,
                           RSize,nil) = False then
        begin
          RaiseLastOSError;
        end;
      end;

      SetLength(PhysicalDrives,P^.NumberOfDiskExtents);
      for I := 0 to P^.NumberOfDiskExtents - 1 do
      begin
        PhysicalDrives[I] := P^.Extents[I].DiskNumber;
      end;

    finally
      FreeMem(P);
    end;

  finally
    CloseHandle(h);
  end;

end;
これで第2パラメータPhysicalDrivesに物理ドライブ番号が格納されます。 これらの関数を組み合わせて指定したファイル/パスがSSD上に書き込まれるかどうかを調べてみます。
var
  Index: Integer;
  Filename: String;
  PhysicalDrives: TIntegerDynArray;
  PhysicalDrivePath: String;
  IsSSD: Boolean;
begin

  Filename := "C:\";  // 例: "C:\"を調べます

  SetLength(PhysicalDrives,0);
  PathnameToPhysicalDriveNumber(Filename,PhysicalDrives);

  try
    IsSSD := False;
    for Index := Low(PhysicalDrives) to High(PhysicalDrives) do
    begin
      PhysicalDrivePath := Format('\\.\PhysicalDrive%d',[PhysicalDrives[Index]]);
      try
        IsSSD := IsSSD or HasNoSeekPenalty(PhysicalDrivePath);

      except
        { Ignore }
      end;

      if IsSSD = True then
      begin
        Break;
      end;
    end;

    if IsSSD = True then
    begin
      MessageDlg(Format('ファイル ''%s'' はSSDに書き込まれます。',[Filename]),
                 mtInformation,[mbOk],0);
    end
    else
    begin
      MessageDlg(Format('ファイル ''%s'' はSSDには書き込まれません。',[Filename]),
                 mtInformation,[mbOk],0);
    end;

  finally
    SetLength(PhysicalDrives,0);
  end;

end;
ATA8-ACSでドライブの回転数を取得する方法については次のアーティクルで。 元ねたはもちろんNyaRuRuさんのSSD なら動作を変えるアプリケーションを作る - NyaRuRuが地球にいたころ。すばらしいサンプルを書いていただいたNyaRuRuさんに深く感謝いたします。

2012/10/05追記: CreateFileのフラグについて当初FILE_FLAG_NO_BUFFERINGとFILE_FLAG_WRITE_THROUGHの両方を指定するという記述がありましたが、FILE_FLAG_NO_BUFFERINGを指定したファイルへの書き込みにはFile Bufferingにあるように制限があり、通常の使用には向かないと考えられるため、この点を削除しました。

Prism XE3 Update 1

Prism XE3 Update 1がリリースされています。

29056 Embarcadero Prism XE3 Update 1 (September release)
Embarcadero Prism XE3 Update 1 (September 2012 Release) が公開されました
Embarcadero Prism XE3 Update 1 (September 2012 Release) is now available

2012年9月27日

RAD Studio/Delphi/C++Builder XE3 Hotfix 1,2,3

RAD Studio/Delphi/C++Builder XE3のHotfix 1/Hotfix 2/Hotfix 3がリリースされています。Hotfix 1はMac OS上のFireMonkeyのShowMessageの問題を、Hotfix 2はFireMonkeyのGestureManagerの問題を、Hotfix 3はPro SKUのSQLiteドライバの問題を、それぞれ解決するものです。

29050 RAD Studio XE3 Hotfix 1
29051 RAD Studio XE3 Hotfix 2
29052 RAD Studio XE3 Hotfix 3

RAD Studio XE3/Delphi XE3/C++Builder XE3 向け Hotfix 1/2/3 が公開されました
Hotfixes 1, 2 and 3 for RAD Studio XE3, Delphi XE3 and C++Builder XE3

2012年9月22日

Microsoft OOB Update 2012/09

Microsoftの定例外のセキュリティアップデートがリリースされています。
MS12-063

2012年9月21日

[書籍]アプリケーションをつくる英語

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

アプリケーションをつくる英語 (amazon)/西野竜太郎著/インプレスジャパン/ISBN 978-4-8443-3284-8/2,520円

を購入。

RAD Studio Mobile Roadmap公開

RAD Studio MobileのRoadmapが公開されています。

RAD Studio Mobile Roadmap

当面iOSとAndroidがターゲットで、今年中にベータが始まり、2013年の前半にiOS版、2013年の中頃にAndroid版がリリースされる予定となっています。またiOS Options(iOSのみ)あるいMobile Options(iOS+Android)として基本的にはXE3とは別売り(Low cost option)になるようです。

2012年9月12日

Microsoft Monthly Update 2012/09

今日はMicrosoftのセキュリティアップデートの日です。
MS12-061
MS12-062

2012年9月11日

JVCL 3.46/3.47

JVCL(JEDI Visual Component Library)がアップデートされてVersion 3.46Version 3.47(JCL Version 2.4.1)になっています。

JEDI VCL for Delphi - Browse /JVCL 3/JVCL 3.46 at SourceForge.net
JEDI VCL for Delphi - Browse /JVCL 3/JVCL 3.47 at SourceForge.net

ただしJVCLのニュースグループにはGenerateDefines.pasの46行目がDelphi 2007/2009/2010/XEでコンパイルエラーになるという問題が報告されています。

ANN: JVCL 3.46 Released!

修正はSVNにチェックインされたようですが、とりあえずは該当箇所を

{$IFDEF HAS_UNITSCOPE}
System.Types,
{$ELSE HAS_UNITSCOPE}
Types,
{$ENDIF HAS_UNITSCOPE}

とすることで回避できます。

GenerateDefines.pasの問題を修正した3.47がリリースされています。

2012年9月5日

FastMM 4.991

Delphi/C++Builder用のメモリマネージャFastMMが4.991に更新されています。Delphi XE3対応とOS Xサポートの追加が行われたようです。

元ねたはFastMM4 download available for Delphi XE3 « The Wiert Corner – irregular stream of Wiert stuff

2012/09開催のウェブセミナー

2012年9月4日

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

本日10:00から第23回エンバカデロ・デベロッパーキャンプが行われています。場所は秋葉原の秋葉原UDXの4F、UDXギャラリーNEXTです。また今回のUstream中継は午後のG3、A4、A5、G6セッションのみとなっています(後日公開用に録画はしてるみたいです)。

とりあえずメモ。
ライブ タイルでの Metropolis UI アプリケーションのサポート - RAD Studio XE3
Metropolis UI 用ライブ タイルの開発環境のセットアップ - RAD Studio XE3

全セッション、親睦会とも無事終了。参加者のみなさん、セッションスピーカのみなさん、関係者のみなさん、お疲れさまでした。G3とA5のDavidIさんのセッションはあとでまとめを書くかもしれません。

2012/09/06追記: Facebookのほうのリンクもおいときます。

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

2012/09/12追記: セッション資料、サンプルコードがダウンロードできるようになっています。会場で配布されたセッション資料とは一部異なるものがありますので、最新のものをダウンロードして確認するといいかもしれません。

第23回 エンバカデロ・デベロッパーキャンプ - セッション資料ダウンロード

2012/09/18追記: A2およびG3のリプレイがYoutubeにアップロードされています。

2012/09/24追記: A5のリプレイがYoutubeにアップロードされています。
  • 【A5】 Delphi/C++Builderテクニカルセッション 「RAD Studio次期バージョンの新機能」

2012/10/30追記: A4のリプレイがYoutubeにアップロードされています。
  • 【A4】 Delphiテクニカルセッション 「Delphi+IntraWeb+FastReportによるWeb、モバイル、タブレットアプリ開発」

2012年9月3日

RAD Studio/Delphi/C++Builder/Prism/HTML5 Builder XE3リリース

RAD Studio/Delphi/C++Builder/Prism/HTML5 Builder XE3が正式にリリースされたようです。なおサポートされる開発環境からWindows XP(SP3)が外され、Windows Vista SP2/Windows 7 SP1/Windows 8のみとなっているという点に注意が必要です(Windows 7上のXPモードでは動かないということになります)。サポートされる開発環境からWindows XP(SP3)が外されてWindows Vista SP2/Windows 7 SP1/Windows 8のみになっていますが、Windows XPで動かないということではなく、正式にサポートする範囲から外れただけ、とのことです(検証が十分ではないのでうまく動かない部分はあるかもしれないけれども、基本的には動くはず、だそうです)。また作成したプログラムの動作環境からWindows 2000(SP4)が外され、Windows XP以降、MacOS 10.6以降となっています。

Delphi Insider: Delphi and RAD Studio XE3 products, upgrades and trials available now

28984 Delphi XE3 and C++Builder XE3 ISO
28988 Embarcadero Prism XE3 ISO
28989 HTML5 Builder ISO

28990 FireMonkey Premium Style for RAD Studio XE3

28966 IP*Works for Delphi XE3
28438 IP*Works for C++Builder XE3

28980 Mida Embarcadero XE3 Edition VCL to FireMonkey Converter

またオンラインヘルプも見られるようになっています。

Delphi® XE3 および C++Builder® XE3 オンライン ヘルプ - RAD Studio XE3
Delphi XE3 および C++Builder XE3 の新機能 - RAD Studio XE3
XE3 のリリース ノート - RAD Studio XE3
XE3 のインストール ノート - RAD Studio XE3

メインページ - HTML5 Builder
新機能 - HTML5 Builder

Read Me:Embarcadero Prism - The Oxygene Language Wiki

José León – HTML5 Builder – Introduction

2012/09/05追記: Windows XP上でのXE3の動作についての記述を修正しました。

2012/10/07追記: Delphi/C++Builder XE3における不具合修正リストが公開されています。

Embarcadero Delphi XE3/C++Builder XE3 における不具合修正リスト
Fix List for Embarcadero Delphi XE3 and C++Builder XE3

2012年9月1日

2012年8月24日

非ActiveDirectory環境でのWindows Timeサービス

ActiveDirectoryに属していない(スタンドアロンの)環境では、コントロールパネルの"日付と時刻"の"インターネット時刻"タブで"インターネット時刻サーバー"に有効なNTPサーバを指定してあってもOSの起動時にWindows Time(W32Time)サービスそのものが自動的に停止されてしまい、結果として時刻同期が正常に行われないことになります。

Windows 7 および Windows Server 2008 R2 のスタンドアロン環境で Windows Time サービスが自動的に起動しない

この記事にあるように、Windows Timeサービスのスタートアップの種類を"自動 (遅延開始)"にすることで正常にサービスを起動し、時刻同期が行われるようになります。

また指定するNTPサーバとしては、所属する組織内のネットワーク(あるいはプロバイダ)に用意されているNTPサーバを指定するか、日本国内であれば"ntp.nict.jp"(独立行政法人 情報通信研究機構 電磁波計測研究所 時空標準研究室 日本標準時グループ)、"ntp.jst.mfeed.ad.jp"(インターネットマルチフィード株式会社 時刻情報サービス for Public)、"ntp.ring.gr.jp"(Ring Server Project NTP service)のような公開NTPサーバがお勧めです(WindowsのデフォルトであるMicrosoftの"time.windows.com"はネットワーク的に遠い上にエラーになりやすいのでお勧めしません)。

2012年8月21日

RAD Studio/Delphi/C++Builer XE3情報

あと30分ほどでドイツはハンブルクでワールドツアーが始まりますが、これに先立ってRAD Studioツールのプロダクトマネージメントディレクタ(director of product management for RAD Studio tools)のJT @ Embarcadero(John Thomas)さん

JT @ Embarcadero » XE3 and beyond

という記事を書いています。

気になるのはXE3では当初モバイル向け開発が提供されない(まだベータ段階)という点です。Delphi/FireMonkeyの仕様変更に伴い、XE3のコードはXCODEのFPC(Free Pascel Compiler)ではコンパイルできなくなり、正式にXE3でiOS/Android対応が行われるまではXE2上で開発することになる、とのことです(いまのところMountain Lion(OS X 10.8)上に直接開発環境を用意できない(Lion 10.7にXCODE 4.2.1とFPC/FireMonkeyパッケージを入れてからOSとXCODEをバージョンアップするという手順が必要?)らしいのは微妙な話ですね)。

2012/08/22追記: 先ほど始まったオーストラリアのシドニーでのセッションの内容をAustralian Delphi User Group (ADUG)のLachlanGさんがGoogle+に実況しています。

The TIndex - Google+

まとめ記事も出ています。

Highlights of the Sydney XE3 event | Australian Delphi User Group Members

またXE3のプレビューページもオープンしています。

Welcome to the RAD Studio XE3 Preview | 製品

2012/08/23追記: プレビューページのビデオに日本語字幕を入れたものが公開されています。

RAD Studio XE3の概要 - YouTube

2012/09/05追記: 確認したところXE2+XcodeによるiOS開発ではMountain Lion(10.8)に直接必要な環境をインストールすることはできない、とのことです。新しくMacを買われる方は注意が必要です。

2012年8月15日

RAD Studio XE3 World Tour

RAD Studio XE3のワールドツアーの日程が公開されています。

See what’s new in RAD Studio XE3 at a free World Tour event near you | Landing Pages
Delphi Insider: RAD Studio and Delphi XE3 World Tour dates announced

これによるとXE3のワールドツアーは2012/08/21のドイツ・ハンブルクがスタートのようです。またRAD Studio XE3に含まれるものとしてDelphi, C++Builder, Prism, InterBase and new HTML5 Builderとなっており、(おそらくは)RadPHPの替わりとなるHTML5 Builderが登場するようです。

Microsoft Monthly Update 2012/08

今日はMicrosoftのセキュリティアップデートの日です。
MS12-052
MS12-053
MS12-054
MS12-055
MS12-056
MS12-057
MS12-058
MS12-059
MS12-060

2012年7月28日

2012年7月18日

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

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

エンバカデロ・デベロッパーキャンプ | ホーム

今回はおなじみエンバカデロ・テクノロージーズ チーフエヴァンジェリストのDavid I (David Intersimone)さんがいらっしゃるそうです。時期的にもXE3にフォーカスした感じでしょうか。またライトニングトーク参加者絶賛募集中とのことです。

2012年7月13日

[書籍]Delphi XE2 Foundations

Amazon.comで注文した

Delphi XE 2 Foundations (createspace, Amazon US)/Chris Rolliston著/CreateSpace/ISBN 978-1477550892/49.99USD

が配送されてきました(今回の配送はDeutsche Postでした)。2012/06/27に注文して16日目の到着、49.99USDにShippingの5.48USDで締めて55.47USD=4,582JPY(暫定、1USD=82.603JPY)でした。

サンプルコードはGoogle Codeからダウンロードできます。

delphi-foundations - Delphi sample code - Google Project Hosting

Delphi Talks開催

第22回エンバカデロ・デベロッパーキャンプ(東京)のライトニングトークでsakaikさんから提案されていたDelphi Talksが2012/07/17にスタートするそうです。

Delphi Talks 1 | Facebook
Delphi のおしゃべりをする会 Delphi Talks やります! 7/17 - sakaikの日々雑感~(T)編

2012/07/18追記: 主催者の開催レポートです。

第1回 Delphi Talks 開催しました - sakaikの日々雑感~(T)編

2012年7月11日

Microsoft Monthly Update 2012/07

今日はMicrosoftのセキュリティアップデートの日です。
MS12-043
MS12-044
MS12-045
MS12-046
MS12-047
MS12-048
MS12-049
MS12-050
MS12-051

2012年7月8日

4th anniversary

早いものでまた1年が過ぎてしまいました。この1年間(2011/07/08-2012/07/07)のエントリは156で、週平均3弱といまひとつでしたね。続いてアクセス解析の統計情報から月別ページビュー(PV)を。

2011/07: 5,687
2011/08: 8,038
2011/09: 7,682
2011/10: 6,667
2011/11: 7,216
2011/12: 6,979
2012/01: 6,511
2012/02: 6,712
2012/03: 6,750
2012/04: 5,903
2012/05: 6,912
2012/06: 7,885
2011/07-2012/06合計: 82,942

昨年が66,977でしたから、約20%の増加となっています。ページ別では相変わらずWindowsのSNP(Scalable Networking Pack)を無効にするが圧倒的に多く、依然として全体の10%以上を占めています(なにやら最近はさらに増加傾向)。また第22回エンバカデロ・デベロッパーキャンプ(東京)まとめは6月だけに限れば約6%で2番目に多く、XE3でC++BuilderにClang+LLVMが採用されることに対する関心の高さと、それに相反して情報がまだ少ないことの反映と考えられます(韓国の掲示板に記事が転載されたということもPVが増えた要因のようです)。
一方国と地域別では日本、アメリカ合衆国、大韓民国、ロシアの順で、ロシア>大韓民国だった5月までの状況が上記のデベロッパーキャンプのまとめ記事の影響で一気に逆転しました。

今年はこの後のXE3がFireMonkeyによるさらなるマルチプラットフォーム化(Windows/MacOS X/iOS/Android)の推進と、C++BuilderのClang+LLVM採用によるC++11標準への対応の向上により、従来のRAD Studio/Delphi/C++Builderのユーザとは違った層にも関心を持たれるようになってくるのではないでしょうか。ただしそれを製品の普及につなげるにはFireMonkeyの更なる機能強化と不具合の修正、そしてなによりIDEのデザイナの改善が不可欠なのではないかと思います。また日本国内のコミュニティでも新たな動きがあるようです。

補足ですが、BloggerではCategory(ラベル)に"+"を使うとそのラベルによるアーティクルの表示ができない、という不具合があるようです。このため"C++Builder"はCBuilder、"C++11"はCPP11というラベルに変更してあります。この件を2ちゃんねるで指摘していただいた方に感謝いたします(CPP11の記事が期待はずれですいません)。

2012年7月6日

RAD Studio XE3の新コンパイラはC++/x64だけ?

例年通りだとあと2ヶ月ほどで発売になるものと思われるRAD Studio XE3について、気になる情報が出ています。

Embarcadero adopts open source Clang for future C++ versions « Tim Anderson’s ITWriting

Tim AndersonさんがDavid Iさんに聞いたという話では、XE3(の少なくとも最初のリリース)ではClang+LLVMへの移行はC++/x64のみで、C++/x86やDelphiについては現状のコンパイラが使用される、ということのようです(行間を読めば、C++/x86はひょっとしたらアップデートで入れ替えがあるかもしれないけど、Delphiは明らかにXE4待ち)。これはちょっと問題です。同じC++のソースコードがx86とx64でコンパイルできたりできなかったりといった状況は、せっかくの"C++ is Back"に水をさすものではないでしょうか?次のメジャーリリース待ちということではなく、なるべく早い時期にC++のコンパイラがClang+LLVMで統一されることが望ましいと思います。

直接関係ありませんが、AppleのChris LattnerさんがLLVMのアーキテクチャを解説した記事がありました(The Architecture of Open Source Applications Volume Iという本の一部でもあるようです)。

The Architecture of Open Source Applications: LLVM

元ねたはどちらも公式フォーラムのEmbarcadero Discussion Forums: LLVM based Compiler for Delphi

Prism XE2.5 Update 2

Prism XE2.5 Update 2がリリースされています。

28936 Embarcadero Prism XE2.5 Update 2 (June 2012 Release)
Embarcadero Prism XE2.5 Update 2 is now available
Embarcadero Prism XE2.5 Update 2 が公開されました

RAD Studio/Delphi/C++Builder XE2 Help Update 6

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

28935 Help Update 6 for Delphi, C++Builder and RAD Studio XE2
Help Update 6 for Delphi XE2, C++Builder XE2 and RAD Studio XE2
リリース ノート: Delphi XE2 および C++Builder XE2 Help Update 6 - RAD Studio XE2 (en)

2012年7月4日

Why did Borland fail?

以前BorlandでDelphiのIDEやVCLを担当していたDanny Thorpeさんによる「なぜBorlandは失敗したのか?」という疑問に対する考察。興味深い。とりあえずメモ。

Danny Thorpe's answer to Borland (company): Why did Borland fail? - Quora

元ねたはHadi Haririさんtweet(RANさん経由)。

2012年6月24日

[書籍]リーダブルコード

ブックファースト 新宿店The Art of Readable Code (amazon)の翻訳である

リーダブルコード (amazon)/Dustin Boswell、Trevor Foucher著/角征典訳/オライリージャパン/ISBN 978-4-87311-565-8/2,520円

を購入。

Firebird 2.1.5

Firebird Ver2.1.5がリリースされています。

Firebird: Firebird 2.1.5
Firebird 2.1 Release Notes (PDF)

元ねたはFirebird News » Firebird 2.1.5 sub-release is available

2012年6月13日

Microsoft Monthly Update 2012/06

今日はMicrosoftのセキュリティアップデートの日です。
MS12-036
MS12-037
MS12-038
MS12-039
MS12-040
MS12-041
MS12-042

2012年6月7日

第22回エンバカデロ・デベロッパーキャンプ(東京)まとめ

第22回エンバカデロ・デベロッパーキャンプ(東京)の個人的なまとめです。なお以下の内容については無保証ですのでご注意ください

【G1】キーノートセッション「エンバカデロ2012年製品戦略」
  • 公式レポート: 第22回 エンバカデロ・デベロッパーキャンプ キーノートセッションレポート

  • 2011年の業績は好調で、売り上げは10%成長して約75億円だった。手元資金は潤沢である。

  • 2012年以降に向けて3つのことを考えている。
    1. 既存製品: RAD Studio XE3、ER/Studio portal
    2. 買収: 資金的な余裕があり、景気の低迷で相対的に安く買収を行えるため、年内に1~3社程度の買収を目指している
    3. AppWave

  • 2012年の製品計画
    • 新世代コンパイラアーキテクチャ
      • LLVMをベースとし、

        Delphi F/EまたはC++ F/E(=Clang+PME) → LLVM IR → LLVM Intel/ARM/Other CPU Code Gen

        という構成にコンパイラを再構築する(コンパイラにおけるフロントエンド、バックエンドについてはwikipediaのコンパイラの設計の項を参照)。
    • XE3
      • Delphi/C++: iOSにネイティブ対応
      • C++Builder: x64対応
      • FireMonkey: Hyper-Real 3D UI、ホログラフィック 3D UI
      • HTML5: ビジュアルHTML5/CSS3クライアント開発 - Delphi/C++Builder/RadPHP

  • C++Builder 2012ロードマップ
    • 64bitツールチェーン: IISシェルエクステンション、SQL Serverインタフェース、64bitデバイスドライバ
    • C++11: BoostACEに対応
    • ARM: iOS/Andriodサポート、ARMv7バイナリの出力、FireMonkeyでデバイス(GPSや加速度計などのセンサ)のネイティブサポート
    • スケジュール:
      • 現在ベータ1で、まもなくベータ2が始まる
      • 2012年後半(Q3): C++11、x64、Hyper-Real Holographic(HRH)
      • 2013年初め: ARM iOS/Android

  • ER/Studio
    • データガバナンス、クロスモデルトレーサビリティ
    • メタデータのソーシャライズ
    • Social Portal
    • 最大の競合先であるCA(おそらくERWinシリーズ)が日本語へのローカライズを今年からやめる(注:本当かどうかは確認できませんでした)のでチャンスと考えている

  • AppWave: 今年も積極的にバージョンアップを進める

【T2】Delphi/C++Builderテクニカルセッション「RAD Studio次期バージョンプレビュー ~ 64-bit化を進めるC++Builder」
  • C++Builder
    • C99C++11標準への準拠度の向上
    • LLVMベース(ベータ1ではまだx64のみ)
    • ARM上ではGDBでデバッグすることになる
    • STL(Dinkumware)、Boost(BoostPro)、ACE(ADAPTIVE Communication Environment)、CORBA(TAO)をサポートする予定
    • Windows x64、iOS(シミュレータ、デバイス)、Android

  • Delphi XE3
    • FireMonkeyの強化
      • アクションリスト
      • ジェスチャ
      • アンカー
      • レイアウトマネージャ
      • Audio/Video: DirectShow/QuickTime
      • 物理エンジン
      • Indy for iOS
      • dbExpress for iOS
    • FPCベースからLLVMベースへの移行

  • C++11: C++で追加された便利な機能の紹介 - autoによる型推論lambdaなど

【T3】Delphi/C++Builderテクニカルセッション「FireMonkey道場」
【T4】Delphi/C++Builderテクニカルセッション「アプリの肥大化、チームメンバーの増大など!プロジェクトの拡大にRAD環境でどう対応するか?」
【G5】Q&Aセッション「何でも質問!アスク・エンバカデロ」
  • エンバカデロ・テクノロジーズの全世界における日本の売り上げの比率は8%程度
  • Clang/LLVMはおそらくオープンソースプロジェクトのものからフォークした独自のものとなる(ような雰囲気のことを言っていた)
  • PC上のIDEのシェアはMicrosoftが80%、Embarcaderoが10%、それ以外が10%程度と認識している

【G6】ライトニングトーク「共有!みんなの開発事例、開発経験、テクニック」
個人的な感想など:
  • これからの1年は筑木さんのターンらしいです。C++11とかBoostとか。
  • ClangやLLVMをベースに、とはいっても、いまどきのモダンなIDEではコンパイラから非常に多くの情報を取り出しており、それらの部分はまったく新規に作り込みが必要なので結構大変らしいです。
  • コンパイラの再構築についてはXE3で全部まとめて、という形にはならないのかも。デモで使用していたベータ1ではC++Builder/x64(=Clang+PME、x64 CodeGen)のみが新しくなっており、RTMまでにDelphi F/Eやx86/ARM CodeGenが出揃うかどうかは…。(以下自粛)
  • 資金的な余裕があるのならインストーラのメーカを買収するとかオープンソースのインストーラに出資するとか考えてほしいですね。
  • 参加されたある方から『午前中にキーノートなどの偉い人向けのものをやっても偉い人は朝っぱらから来られるわけがない、ましてや五十日(ごとおび)や月末なんて無理、偉い人の理解がなければ下っ端はこんなところに1日中いられないんだからそこのところを考えてほしい』というお話を聞きました(懇親会で)。確かにそのとおりですよね。"デベロッパー"キャンプとはいえ、勤務時間中に自由に行動できる人はそれほど多くはないわけで(自分は勝手気ままにやらせてもらってますけどね)。キーノートは夕方ラス前くらいに設定して、それ以前の時間にテクニカル系のセッションをやるというのもひとつの考え方かもしれません。

2012/06/08追記: セッション資料のダウンロードが可能になっています(T3、G6のみ)。ライトニングトークは時間の関係で説明されなかった部分などがあるのでダウンロードして確認がお勧め。

第22回 エンバカデロ・デベロッパーキャンプ - セッション資料ダウンロード

2012/06/11追記: キーノートの公式レポートのリンクを追加しました。

2012/06/15追記: CodeZineに関連記事が掲載されています。

次期C++Builderはアーキテクチャを刷新 ~「エンバカデロ・デベロッパーキャンプ東京」レポート(1/3):CodeZine
開発ツールベンダーの老舗が語る C++によるソフトウェア開発の今と将来性(1/3):CodeZine

2012/07/02追記: IT Leadersに関連記事が掲載されています。

コンパイラを全面改良、異機種クライアント向けアプリの生産性向上へ~米エンバカデロ・テクノロジーズ | IT Leaders

2012年6月6日

指定されたビットを交換する

整数型の値の指定された任意の2つのビットを交換する方法。
function ExchangeBits(Value: Integer; Pos1: Integer; Pos2: Integer): Integer;
var
  n: Integer;
  t: Integer;
begin

  Result := Value;

  n := Pos1 - Pos2;
  if n = 0 then
  begin
    Exit;
  end;
  if n < 0 then
  begin
    Pos2 := Pos1;
    n := -n;
  end;

  t := ((Value shr n) xor Value) and (1 shl Pos2);
  Result := Result xor t;
  Result := Result xor (t shl n);

end;
元ねたはびびすけさんのビット交換 (RunRunDietOnline)。昔からある(バッド)ノウハウのひとつであるXORによる値の交換の応用ですね。

2012年6月1日

2012/06開催のウェブセミナー

2012年5月31日

第22回エンバカデロ・デベロッパーキャンプ(東京)

本日10:00から第22回エンバカデロ・デベロッパーキャンプ(東京)が行われます。場所は新宿の新宿NSビルの30階、スカイカンファレンスルーム1です。今回は一部のセッションを除いてUStreamで中継があります。

USTREAM: developer-camp-japan: エンバカデロ・デベロッパーキャンプのライブ中継をご覧いただけます。

Nigel BrownさんのG1終了。Delphi/C++BuilderをCLang(or Delphi F/E)+LLVM上で再構築とな。CLang+PMEの話はJTさんが書いてましたね。

高橋さんのT2も終了。RAD Studio(C++Builder) XE3のベータ版でデモ。x86とx64でコンパイラが違うのかぁ(現時点での話です)。

午後は高橋さんのT3からです。FireMonkeyは面白そうだけど、画面描画を伴う処理を処理系非依存でどう作るのかとか、そもそもクロスプラットフォームの必要性とか、微妙ですよね。XE3からが本番だと思いますけど。

パネルディスカッションのT4も終了。エンバカデロで使ってるツールを外販するとかオープンソース化するとかいかがですかね?

Nigel BrownさんのQ&AのG5も終了。営業の人は話が長いな…。

まもなくラスト、T6のライトニングトークです。今日は8人だとか。時間厳守ですって。

懇親会を含め全て終了。参加者のみなさん、セッションスピーカのみなさん、エンバカデロ・テクノロジーズのみなさん、お疲れさまでした。

2012/06/08追記: まとめはこちら

2012年5月25日

[書籍]PDF構造解説

ジュンク堂書店 吉祥寺店PDF Explained (amazon)の翻訳である

PDF構造解説 (amazon)/John Whitington著/村上雅章訳/オライリージャパン/ISBN 978-4-87311-549-8/2,310円

を購入。

2012年5月19日

RAD Studio roadmap 2012 Q2版

RAD Studio XE2のリリース以来長らく放置状態だったロードマップがRADプロダクトマネージメントディレクタのJohn Ray Thomasさんによって更新されています。

C++向けRAD IDEで、近い将来64-bit、C++11、ARM、iOS、Androidをサポート!
Coming soon to a RAD IDE near you, the future of C++ - 64bit, C++11, ARM, iOS and Android

てきとうな要約:
  • 主要な目標はWindows x64対応、C++11対応、ARM(iOSおよびAndroid)対応で、多くの機能は2012年H2に、そのほかについても2013年H1にかけてのリリースを予定している。
  • C++の新しいコンパイラのターゲットプラットフォームはWindows x64、iOS(ARM)、Android(ARM)。Windows x64では当然VCLとFireMonkeyの両方をサポートする。
  • C++ツールチェーンは新しいプラットフォームのサポートを予定しており、まずはARMプロセッサのシェアドコードベースでのネイティブ開発(iOS、Android)について作業している。新しいコンパイラはネイティブなARM v7バイナリを生成する。FireMonkeyもC++によるiOS/Androidプラットフォームへの対応(GPS、カメラ、加速度などのセンサを含む)のため更新される。
  • 新しいC++コンパイラはC++11およびC99標準とBoostやACEなどの重要なライブラリの最新版に対応する。
  • このロードマップは現時点のもので(以下略)といういつものお約束。現在はBeta 1で、まもなくBeta 2フェーズに入る予定。現在の計画ではC++11、Windows x64、iOSは2012年の後半、Androidは2013年の前半を予定している。


またC++Builderを含む製品とメンテナンス契約でプレビュープログラムに参加できるというキャンペーンも始まったようです(メンテナンス契約なのでXE3も自動的に含まれる)。2012/04/20から2012/06/29が対象期間のようです。

Michael Swindell » Avalanche of C++ news - C++11, Win 64-bit, iOS and Android
Get your ticket to the future of C++ and save an additional 20%

2012/05/22追記: 日本語版のリンクを追加しました。

2012/05/30追記: キャンペーン(C++Builder XE2 Future Ticket版)の件が日本でも発表されています。

エンバカデロ、64-bit、iOS、AndroidをサポートするC++Builderの将来バージョンへのパスを提供 | Press Releases
C++Builder XE2を将来バージョンへのチケットと一緒に購入すれば20% OFF

RAD Studio/Delphi/C++Builder XE2 Update 4 Hotfix 1

RAD Studio/Delphi/C++Builder XE2 Update 4のHotfix 1がリリースされています。適用後のバージョンは16.0.4504.48759です。主にUpdate 4で生じたFireMonkey関係の問題を修正するもののようです。

28881 RAD Studio XE2 Update 4 Hotfix for FireMonkey and C++
28882 Delphi XE2 and C++Builder XE2 ISO (includs Update 4 Hotfix)
Delphi XE2/C++Builder XE2/RAD Studio XE2 Update 4 Hotfix 1 が公開されました
Update 4 Hotfix 1 now available for Delphi, C++Builder and RAD Studio XE2

2012年5月16日

Prism XE2.5

Prism XE2.5がリリースされています。RAD Studio XE2のメンテナンス契約をしているか、2012/05/15から2012/09/01の間にRAD Studio XE2を購入した場合(2012/09/15まで有効)にのみ使用できるようです。またこのキャンペーンが日本でも有効なのかどうかは今のところ不明です。

Buy RAD Studio XE2, get Embarcadero Prism XE2.5 Free! | Landing Pages

28871 Embarcadero Prism XE2.5 ISO
28872 Embarcadero Prism XE2.5 ISO
28873 Embarcadero Prism XE2.5 Full Installer (Japanese)
28876 Embarcadero Prism XE2.5 Full Installer (English)

2012/05/17追記: Prism XE2.5の関連リンクです。

Embarcadero Announces Support for Windows 8 Metro Development with Release of Embarcadero Prism XE2.5
Delphi Insider: Embarcadero Prism XE2.5 is now available - develop Windows 8 apps
Announcing Oxygene 5.1 and Embarcadero Prism XE2.5 | RemObjects Blogs

2012年5月9日

Microsoft Monthly Update 2012/05

今日はMicrosoftのセキュリティアップデートの日です。
MS12-029
MS12-030
MS12-031
MS12-032
MS12-033
MS12-034
MS12-035

2012年5月8日

列挙型と列挙子名(文字列)の相互変換(ジェネリックス版)

ずいぶん前に列挙型の値と列挙子の名前を相互変換する方法について取り上げましたが、これを関数化しようとすると結局のところ必要な列挙型すべてについて個別に実装の必要がありました。ところがLynaたんさん(talesさん)ジェネリクスを使って少しだけ手軽に列挙型の値を文字列に変換する。 - 全力わはーではDelphi 2009の新機能のジェネリックスを利用することでこれを単一の実装で実現しています。ということでLynaたんさんが提示した手法で列挙型と列挙子名の相互変換を関数化してみました(単なるパクリですいません)。ここではクラスではなく高度なレコード型を使用します。またジェネリックスを使いますので当然のことながらDelphi 2009以降でのみ有効です。
uses
  TypInfo, SysUtils, SysConst;

type
  TEnumHelper = record
    class function GetEnumName<T>(Value: T): String; static;
    class function GetEnumValue<T>(const Name: String): T; static;
  end;

class function TEnumHelper.GetEnumName<T>(Value: T): String;
var
  P: PTypeInfo;
  IValue: Integer;
begin

  P := TypeInfo(T);
  if P = nil then
  begin
    raise EInvalidOpException.CreateRes(@SVarNotImplemented);
  end;

  IValue := 0;
  Move(Value,IValue,SizeOf(T));
  Result := TypInfo.GetEnumName(P,IValue);

end;

class function TEnumHelper.GetEnumValue<T>(const Name: String): T;
var
  P: PTypeInfo;
  IValue: Integer;
begin

  P := TypeInfo(T);
  if P = nil then
  begin
    raise EInvalidOpException.CreateRes(@SVarNotImplemented);
  end;

  IValue := TypInfo.GetEnumValue(P,Name);

  with GetTypeData(P)^ do
  begin
    if (IValue < MinValue) or (IValue > MaxValue) then
    begin
      raise ERangeError.CreateRes(@SRangeError);
    end;

    Result := Default(T);
    Move(IValue,Result,SizeOf(T));
  end;

end;

TEnumHelper.GetEnumNameの型パラメータは省略可能です(引数の型から自動的に推論されます)が、TEnumHelper.GetEnumValueについては型パラメータが必須となります。
var
  Alignment: TAlignment;
begin

  Alignment := TEnumHelper.GetEnumValue<TAlignment>('taLeftJustify');

end;

var
  S: String;
begin

  S := TEnumHelper.GetEnumName(taLeftJustify);

end;

こんな感じで使うことができます。

2012年5月1日

2012/05開催のウェブセミナー


2012/05/03追記: Developer Direct Webセミナーシリーズのリンクを追加。毎週火曜日の13:00-14:00ですね。

2012/06/12追記: 2012/05/15分のリプレイビデオのリンクを追加しました。

2012/06/18追記: 2012/05/29分のリプレイビデオのリンクを追加しました。