2010年8月31日

RAD Studio XE/Delphi XE/C++Builder XE/Delphi Prism XE/RadPHP XEリリース

RAD Studio/Delphi/C++Builder/Delphi Prism/RadPHP XEのリリースが正式にアナウンスされています。

Sip from the Firehose : RAD Studio, Delphi, C++Builder, Delphi Prism and RadPHP XE are available now!
Delphi Prism XE is Available Now! « RemObjects Blogs
Paweł Głowacki : RAD Studio XE available right now! 2011=XE
Available now the new Delphi XE, C++Builder XE, Delphi Prism XE and RadPHP XE | Andreano Lanusse English Blog

ソフトウェア使用許諾およびサポート契約書, Embarcadero® RAD Studio XE

リリースノート
Embarcadero Delphi XE および C++Builder XE のリリース ノート
Delphi Prism™ XE リリース ノート
RadPHP XE: Release Notes

インストールノート
Embarcadero Delphi XE および C++Builder XE のインストール ノート
Delphi Prism XE のインストール ノート
Installation Notes for RadPHP XE

新機能解説
What's New in Delphi and C++Builder XE - RAD Studio XE
Delphi XE および C++Builder XE の新機能 - RAD Studio XE

2010/09/27追記: EDN/サポートKBにRAD Studio/Delphi/C++Builder/Delphi Prism/RadPHP XEを購入すると入手できる旧バージョンのライセンスの取得方法についてのアーティクルが追加されています(同一内容です)。

RAD Studio XE, Delphi XE, C++Builder XE, Delphi Prism XE 旧バージョンのライセンスの取得方法について (EDN)
RAD Studio XE, Delphi XE, C++Builder XE, Delphi Prism XE 旧バージョンのライセンスの取得方法について (Support KB)

またDelphi 7にUpdate 1を適用したときの問題と非公式な解決策についてはDelWikiDelphi/Delphi 7/Update 1を参照してください(ran_bousyoさんtweetから)。

2010年8月30日

クラス、レコードのオーバロード演算子

Delphi 2006以降ではclass/recordに対して演算子のオーバロードが可能になりました。オーバロード演算子の一覧は

Operator Overloading - RAD Studio
演算子のオーバーロード - RAD Studio (日本語)

にあるのですが、Jeroen Wiert Pluimersさん

Delphi operator overloading: table of operators, names, and some notes on usage and ‘glitches’ « The Wiert Corner – Jeroen Pluimers’ irregular stream of Wiert stuff

によると、BitwiseNotは存在しません(QC21927QC52318)。また過去のドキュメントではLeftShift/RightShiftがShiftLeft/ShiftRightとなっていたようですが、これは現在は修正されています。

普通はレコード型に対して演算子のオーバロードを実装することになると思いますが、Demos\DelphiWin32\VCLWin32\ComplexNumbersあたり(Delphi 2007の場合)にあるVassbotn.Vcl.Complex.TComplexが非常に参考になります。

2010年8月27日

RAD Studio XE スニークプレビュー その5

Delphi Live !が始まっていますのでその情報も含めて。

Tim Del Chiaroさんのところ。
Andreano Lanusseさんのところ。
Marco Cantuさんのところ。
Mason Wheelerさんのところ。
Jeroen Wiert Pluimersさんのところ。
David Deanさんのところ。
我らがTeam Japan
これらの記事のポイントを。
  • InterBaseも次期バージョンはInterBase XEになる模様。
  • Delphi XEからMacOS Xサポートが外れた(次のバージョンにスリップした)のは品質が基準に到達しなかったため(これはフォーラムでも同様の発言がありました)。
  • Datasnapの通信が最初から暗号化を選択できるようになる。また必要に応じてフィルタを追加することで暗号化のロジックを追加することもできる。
  • Microsft Azure接続用に専用のコンポーネント(TAzure...)が用意される。
  • IDEからAmazon EC2に作成したアプリケーションをデプロイできる。
  • C++BuilderのDelphiとの互換性を改善する。具体的には__declspec(delphirtti)__declspec(delphirecord)$HPPEMIT ENDをC++Builderが理解するようになる。さらにインターフェースから継承したメソッドを簡単にオーバライドできるようになる。

明日は行けそうにありません。中村さんとか大野さんとか珍しい方々(謎全さんがいれば完璧でしたね)がいらっしゃるようなので非常に残念ですが…。きっと当日はみんな酔っ払って誰もtweetしてくれないだろうと想像しています。

2010年8月26日

MSDNライブラリによく出る英単語 100選

ちょっと前になりますが、CodeZineに"原文をスラスラ読みたい! 「MSDNライブラリによく出る英単語 100選」"という記事がありました。MSDNに限らず英語のドキュメント類を読むのに役に立ちそうです。

原文をスラスラ読みたい! 「MSDNライブラリによく出る英単語 100選」(1/2):CodeZine
原文をスラスラ読みたい! 「MSDNライブラリによく出る英単語 100選」(2/2):CodeZine

できれば200位くらいまで記事にしてほしいですね。

2010年8月25日

アンゴラ?

いままでアクセス解析とかあまり気にしていなかったのですが、クリボウさんBlogger in Draft に待望のアクセス解析機能「統計」が追加という記事でBloggerにBlogger in Draftというベータ版サービスがあり、そこでアクセス解析が見られる機能がある、という話を知りました(1月半も前の記事ですが)。
そこで早速Blogger in Draftにアクセスし、"統計"の"参加者"という国別、ブラウザ別、OS別のページビューが確認できるページで、何気なく全期間のボタンをクリックしたところ、国別の1位が日本(あたりまえ)、2位がアメリカ(日本の10%程度で、ま、これもあたりまえ)、3位は…アンゴラ?それもPV=100で4位のカナダのほぼ倍って?アンゴラに知り合いはいない(というか知り合いに見せるブログじゃないし)ので、あちらにDelphiユーザがいらっしゃるってことなんでしょうかね。
ちなみに月平均のPVは2000-4000(まぁ10%は自分でしょうけど)ってところでした。またA7MさんのC++Builder好きの秘密基地からいらっしゃる方が多いようです(アンテナのおかげでしょうか)。

2010年8月24日

RAD Studio XE スニークプレビュー その4

第3週目のプレビューが公開されています。
XEのプロモーションサイト。
Marco Cantuさんのところ。
A7Mさんのところ。
Uwe Schusterさんのところ。
これらの記事のポイントを。
  • C++BuilderのBoostは1.39.0のまま。
  • std::stringがC++0xのムーブセマンティクスに対応する。
  • RTLに(Delphi 2009で追加されたTTextReader/TTextWriterに対応する)TBinaryReader/TBinaryWriterが追加される。
  • TTimeZoneに多少の改良が加えらる。
  • TInterlocked/TSpinWait/TSpinLockなどの同期クラスが追加される。
  • TThreadも拡張され、テンポラリスレッド内の無名メソッドの直接実行などが行えるようになる。
  • 正規表現クラスTRegExが追加される。
  • TStringsにDefaultEncodingが追加され、またarray of Stringとの相互変換がサポートされる。
  • IOUtilsユニットのTPathにクラスメソッドGetHomePathが追加され、アプリケーションデータフォルダを取得できる。
  • SysUtilsには新しいRTL関数が追加され、またクロスプラットフォームを考慮してTSymLinkなどのファイル管理関係が強化される。
  • 文字列を高速に分割するSplitStrings関数が追加される。
  • Subversion対応は単にTortoiseSVNを使用するのとは異なり、個別のファイルを選択的に管理対象にすることができる(OTAのIOTAVersionControlNotifierインタフェースのIsFileManagedで実現している)。
  • C++BuilderでDatasnapサーバが作成可能になる。
  • Datasnapを使用してAzureやAmazon EC2と連携するアプリケーションを作成できる。

2010/08/25追記: 日本語のスニークプレビューサイトでも第3週目のビデオが公開されました。中途半端感があるのは予定されていた10分x3回の中に納まりきらなかっただけだそうです。

2010年8月23日

SafeLoadLibrary

SysUtilsユニットのSafeLoadLibrary (ja)は、SetErrorMode (ja)でエラーモードを一時的に(デフォルトでSEM_NOOPENFILEERRORBOXに)変更し、FPUの制御ワードを保存した上でLoadLibrary (ja)を呼び出し、FPUの例外をクリアして、FPU制御ワードとエラーモードを復元する、というものです。DLLの初期化コード内でFPUの不正な操作を行っているなど、単なるLoadLibraryではうまく動作しないときに使用するもののようです。

元ねたはDelphi Loadlibrary returns 0 (LastErrorcde=3221225616) What does this mean ? - Stack Overflow

2010年8月20日

コンソールアプリケーションでグラスエフェクトを有効にする

Stack Overflow

How can activate a glass effect (windows Vista/7) in a console application using Delphi - Stack Overflow

というアーティクルがありました。RRUZ(Rodrigo Ruz)さんによる回答はGetConsoleWindowで取得したコンソールウィンドウにDWMのDwmEnableBlurBehindWindowでblur(グラスエフェクト)をかける、というものです。しかしこのコンソールアプリケーションはそのままではWindows 2000/XPで動作しません。そこでDwmEnableBlurBehindWindowを動的にリンクするように手を加えてみました。DWM_BLURBEHIND構造体および定数DWM_BB_...の定義はDelphi 2007のDwmAPI.pasから借りてきました。
program Project1;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils;

type
  {$EXTERNALSYM PDWM_BLURBEHIND}
  PDWM_BLURBEHIND = ^DWM_BLURBEHIND;
  {$EXTERNALSYM DWM_BLURBEHIND}
  DWM_BLURBEHIND = record
    dwFlags: DWORD;
    fEnable: BOOL;
    hRgnBlur: HRGN;
    fTransitionOnMaximized: BOOL;
  end;

  TDwmEnableBlurBehindWindow = function (hWnd: HWND;
                                         pBlurBehind: PDWM_BLURBEHIND): HResult; stdcall;

const
  DWMAPI = 'DWMAPI.DLL';

  {$EXTERNALSYM DWM_BB_ENABLE}
  DWM_BB_ENABLE                 = $00000001;  // fEnable has been specified
  {$EXTERNALSYM DWM_BB_BLURREGION}
  DWM_BB_BLURREGION             = $00000002;  // hRgnBlur has been specified
  {$EXTERNALSYM DWM_BB_TRANSITIONONMAXIMIZED}
  DWM_BB_TRANSITIONONMAXIMIZED  = $00000004;  // fTransitionOnMaximized has been specified


function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow';


var
  hDWMAPI: HMODULE;
  BB: DWM_BLURBEHIND;
  DwmEnableBlurBehindWindow: TDwmEnableBlurBehindWindow;
begin

  try
    hDWMAPI := 0;
    try
      if Win32MajorVersion >= 6 then
      begin
        hDWMAPI := LoadLibrary(DWMAPI);
        if hDWMAPI > 0 then
        begin
          @DwmEnableBlurBehindWindow := GetProcAddress(hDWMAPI,
                                                       'DwmEnableBlurBehindWindow');
          if Assigned(DwmEnableBlurBehindWindow) then
          begin
            BB.dwFlags := DWM_BB_ENABLE;
            BB.fEnable := True;
            BB.hRgnBlur := 0;
            BB.fTransitionOnMaximized := False;
            DwmEnableBlurBehindWindow(GetConsoleWindow,@BB);
          end;
        end;
      end;

      Writeln('Hit enter key');
      Readln;

    finally
      if hDWMAPI > 0 then
      begin
        FreeLibrary(hDWMAPI);
      end;
    end;

  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;

end.


2010/11/04追記: DWMAPI.DLLがKnownDLLsではない環境(Windows 2000/XP)でバイナリ(DLL)プランティングの影響を受ける可能性があったので、LoadLibrary(PChar('DWMAPI.DLL'))を行う条件としてWin32MajorVersionが6以上(Windows Vista以降)という条件を追加しました。なおDelphi(2007以降)はDWMAPI.DLLを動的にLoadLibraryする条件としてWin32MajorVersionが6以上という検査を行うようになっており、通常の使用ではDWMAPI.DLL(の不存在)を利用したバイナリプランティングは成立しません。

2010年8月19日

RDBにおけるテーブルのJOINを図解すると

エンバカデロ・テクノロジーズのKyle Haileyさんによる、RDBのテーブル同士の結合(join)のinner join/left outer join/right outer join/full outer joinのそれぞれでどのようなレコードが選択されるのかについての非常にわかりやすい説明。

DB Optimizer: Outer Joins Graphically

図解されているので説明不要でしょう。

2010年8月18日

Delphi15y Meetup

Delphiが最初のリリースから15周年ということで、藤井さんはやしさんなにやら企んでいるようです。個人的にはTwitter または Facebook のアカウントが必要です。ってのはちょっと…まぁ(いい意味で)思いつきレベルのものだからってことで。Twitter/Facebookのアカウントがない場合はここから申し込めるようになりました。ひょっとして配慮していただいたのならありがとうございます。

Delphi 15周年&「XE」発売前イベント - Delphi15y Meetup
Tweetvite :: Delphi 15周年&「XE」発売前イベント - Delphi15y Meetup
Delphi 15周年&「XE」発売前イベント - Delphi15y Meetup→Twiter/Facebookのアカウントがなければここから申し込み可能
#delphi15y - Twitter Search

そういやFirebird10th Birthdayでしたね。

2010/08/25追記: 各種リンクを追加しました。またTwiter/Facebookのアカウントがない場合の扱いについても記述を修正しました。

2010/08/30追記: 参加された方々のレポートです。

RAD Studio XE スニークプレビュー その3

第2週目のプレビューが公開されています。
EDNの記事も出ています。
Andreano Lanusseさんのところ。
Marco Cantuさんのところ。
Mason Wheelerさんのところ。
これらの記事のポイントを。
  • Final Builder Embarcadero Editionがバンドルされ(Enterprise/Architect SKUのみ)、ビルドを自動化できるようになる。
  • ビルドをカスタマイズして検査(audits)、測定(metrics)、ドキュメント生成を実行できる。
  • SmartBear(旧AutomatedQA)のAQTime StandardがIDEに統合され、パフォーマンスプロファイルを計測し、結果をコードエディタ上でも確認することができるようになる。
  • Raize SoftwareCodeSiteがバンドルされ、デバッグログ機能を簡単に使用できるようになる。

2010年8月17日

[書籍]間違いだらけのソフトウェアアーキテクチャ

啓文堂書店の渋谷店

間違いだらけのソフトウェアアーキテクチャ (amazon)/Tom Engelberg著/長谷川裕一、土岐孝平訳/技術評論社/ISBN 978-4-7741-4343-9/2,079円

を購入。ところでTom Engelbergという人は実在しているのかな?まぁ内容さえよければそんなことはどうでもよいのだけれども。

元ねたはキムラデービーさん[書評]間違いだらけのソフトウエア・アーキテクチャ

RAD Studio XE スニークプレビュー その2

前回の続き。
Marco Cantuさんのところ。
David Iさんのところ。
シニアR&DエンジニアのChris Bensenさんのところ。
Uwe Schusterさんのところ。
A7Mさんのところ。
これらの記事のポイントを。
  • 一度に全てのソースコードに適用することができない、フォーマッタの設定をカスタマイズしてもその設定をチームで共有できない、というDelphi 2010のコードフォーマッタの問題点を改善し、プロジェクトの全てのファイルにフォーマッタを適用したり設定をXML形式で保存、読込できるようになった。
  • 検索機能が強化され、プロジェクトにモデリングサポートを追加しなくても"Search for Usages"を行えるようになった。既存のリファレンスの検索と"Search for Usages"の違いは柔軟性で、色々な条件やスコープを指定して検索することができる。
  • XE、XE2、XE3というような新しいブランド上の表記のほかに従来通りの内部的なバージョン番号(internal technical version numbers)も当然存在し、Delphi XEはVersion 15.0.XXXXというバージョン番号を持っている。
  • RTLにsymlinks(シンボリックリンク)を作成する関数が追加される。
  • C++ではATLに代わってDAX(Delphi ActiveX framework)がデフォルトになる(従来通りATLを使用することもできる)。
  • COMの登録は従来通りの全てのユーザに対してだけでなく、現在のユーザだけに行うこともできるようになる。
  • Datasnapウィザードが非常に使いやすくなる。
  • インストールコンポーネントウィザードが追加される。
  • OTAの新しいIOTAVersionControlNotifier150インタフェースでIDEのVSCサポートが実装される。

2010年8月16日

任意の年の夏時間の実施状況を取得する(Windows Vista SP1以降)

アプリケーションの国際化対応(i18n)に必要なことはいろいろあります。画面、リソース文字列の翻訳と実行時ロケールによる切り替え(これらはRAD Studio/VCLの機能で対応できます)、通貨記号や小数点などの形式(これらはSysUtilsのグローバル変数から取得できます)、文字コードの問題(これはDelphi 2009以降のUnicode対応で一応の解決が得られました)、そして夏時間(DST、daylight saving time)への対応があります。ところが従来Windowsでは夏時間に関する情報をその年の分の情報しか持っておらず、GetTimeZoneInformation (ja)を使用しても十分な結果は得られませんでした。たとえば今年ではない特定の日付に夏時間が実施されていたのか、とか、UTCベースで与えられた今年以外の日時が現地時間でどうなるのか、などはWindowsに依存せず自前でロジックの実装と実施状況の保持を行う必要がありました。
さすがにMicrosoftもこれは駄目だと考えたのか、Windows Server 2008(=Windows Vista SP1)でGetTimeZoneInformationForYearが実装され、これ以降のOSでは指定した年のタイムゾーンの設定情報を取得できるようになりました。GetTimeZoneInformationForYearの第2パラメータ(pdtzi)はタイムゾーンを明示的に指定するときに使用しますが、通常はNULL(現在のタイムゾーン)でしょう。第3パラメータ(ptzi)はTIME_ZONE_INFORMATION構造体で、ここに指定した年と指定したタイムゾーンに関する設定情報が格納されます。
ところがTIME_ZONE_INFORMATION構造体のStandardDate/DaylightDateメンバはSYSTEMTIME構造体であるにもかかわらずSYSTEMTIMEの仕様から外れたデータが格納されることがあるため、解釈は一筋縄では行きません。まずwMonthが0のときは夏時間が無効であることを意味します。次にwYearが0のときは直接的に日付を表さず、wDayOfWeekが曜日でwDayが何番目か(第1○曜日..第5○曜日)という形で表現されます。さらにwDayに5が格納されている場合は第5○曜日ではなく最終○曜日という意味を含んでおり、その月に第5○曜日がなければ第4○曜日になります。さらに時刻部分(wHour/wMinute/wSecond/wMilliseconds)が23:59:59:999になっている場合、実際にはその翌日を意味します。つまり×月第○曜日の翌日、ということです。
さらにGetTimeZoneInformationForYearの指定年の情報を取得できる、という仕様そのものにも問題があります。例えばフランスでは3月最終日曜日に夏時間が始まってその年の10月最終日曜日に終わります。でも南半球だと夏時間は当年中に終わりません。例えばシドニー(オーストラリア東部標準時)の夏時間は10月第1日曜日から次の年の4月第1日曜日までです(2010/08/16現在)。つまりStandardDateとDaylightDateの関係を見て、必要に応じて翌年の情報も取得する必要があるわけです。
ではまずGetTimeZoneInformationForYearに必要な定義を用意します。ですがこの関数はWindows Vista(GOLD)およびそれ以前のOSには存在しません。ということで実行時にGetProcAddress (ja)で動的リンクすることにします。
type
  _TIME_DYNAMIC_ZONE_INFORMATION = record
    Bias: Longint;
    StandardName: array [0..31] of WCHAR;
    StandardDate: SYSTEMTIME;
    StandardBias: Longint;
    DaylightName: array [0..31] of WCHAR;
    DaylightDate: SYSTEMTIME;
    DaylightBias: Longint;
    TimeZoneKeyName: array [0..127] of WCHAR;
    DynamicDaylightTimeDisabled: BOOL;
  end;
  {$EXTERNALSYM _TIME_DYNAMIC_ZONE_INFORMATION}
  DYNAMIC_TIME_ZONE_INFORMATION = _TIME_DYNAMIC_ZONE_INFORMATION;
  {$EXTERNALSYM DYNAMIC_TIME_ZONE_INFORMATION}
  PDYNAMIC_TIME_ZONE_INFORMATION = ^DYNAMIC_TIME_ZONE_INFORMATION;
  {$EXTERNALSYM PDYNAMIC_TIME_ZONE_INFORMATION}

  TGetTimeZoneInformationForYear = function (wYear: Word;
                                             pdtzi: PDYNAMIC_TIME_ZONE_INFORMATION;
                                             var ptzi: TIME_ZONE_INFORMATION): BOOL; stdcall;
次に上記の面倒な部分の処理です。
function CompareSystemTime(ST1: TSystemTime; ST2: TSystemTime): Integer;
begin

  Result := ST1.wYear - ST2.wYear;
  if Result = 0 then
  begin
    Result := ST1.wMonth - ST2.wMonth;
    if Result = 0 then
    begin
      Result := ST1.wDay - ST2.wDay;
    end;
  end;

end;
CompareSystemTimeはTSystemTime型の日付の比較を行います(翌年に繰り越すかどうかの判断で必要になります)。
function CanonicalizeSystemTime(Year: Integer; const ST: TSystemTime): TSystemTime;
var
  D: TDateTime;
  DoW: Integer;
begin

  Result := ST;

  with Result do
  begin
    if wYear > 0 then
    begin
      { Absolute date }
      Exit;
    end;

    wYear := Year;

    { Get DoW of first date of the month }
    D := EncodeDate(wYear,wMonth,1);
    DoW := DayOfWeek(D) - 1;  // 0 is Sunday

    { Convert to date of the month }
    wDay := (wDayOfWeek + (wDay * 7) + 1) - (DoW + Ord(wDayOfWeek >= DoW) * 7);
    while wDay > MonthDays[IsLeapYear(Year),wMonth] do
    begin
      wDay := wDay - 7;
    end;

    { Next day }
    if (wHour = 23) and (wMinute = 59) then
    begin
      wHour         := 0;
      wMinute       := 0;
      wSecond       := 0;
      wMilliseconds := 0;

      DecodeDate(EncodeDate(wYear,wMonth,wDay) + 1,wYear,wMonth,wDay);
      wDayOfWeek := (wDayOfWeek + 1) mod 7;
    end;
  end;

end;
CanonicalizeSystemTimeはTSystemTimeの相対表現を指定年の絶対表現に変換します。
resourcestring
//  RFirst  = '1st ';
//  RSecond = '2nd ';
//  RThird  = '3rd ';
//  RFourth = '4th ';
//  RLast   = 'last ';
//  RNext   = '''s next day';
  RFirst  = '第1';
  RSecond = '第2';
  RThird  = '第3';
  RFourth = '第4';
  RLast   = '最終';
  RNext   = 'の翌日';

const
  WeekOfMonth: array [1..4] of String =
                 (RFirst, RSecond, RThird, RFourth);

function SystemTimeToDescription(const ST: TSystemTime): String;
begin

  if ST.wYear = 0 then
  begin
    Result := LongMonthNames[ST.wMonth];

    case ST.wDay of
      1..4:
      begin
        Result := Result + WeekOfMonth[ST.wDay];
      end;

      else
      begin
        Result := Result + RLast;
      end;
    end;

    Result := Result + LongDayNames[ST.wDayOfWeek + 1];

    if (ST.wHour = 23) and (ST.wMinute = 59) then
    begin
      Result := Result + RNext;
    end;
  end
  else
  begin
    Result := FormatDateTime(LongDateFormat,SystemTimeToDateTime(ST));
  end;

end;
SystemTimeToDescriptionはTSystemTimeの相対表現を文字列化します。

いよいよ指定年の夏時間の実施状況を取得する関数です。EGetProcAddressはkernel32.dllにGetTimeZoneInformationForYearが存在しないときにraiseされる例外です(Delphi 2010以降では定義済なのでこの定義は不要)。
type
  { EGetProcAddress }
  EGetProcAddress = class(Exception)
  end;

function GetDSTInfoByYear(Year: Integer;
                          var Offset: Integer; var Name: String;
                          var DTStart: TDateTime;
                          var DescriptionStart: String;
                          var DTEnd: TDateTime;
                          var DescriptionEnd: String): Boolean;
var
  GetTimeZoneInformationForYear: TGetTimeZoneInformationForYear;
  TZI: TIME_ZONE_INFORMATION;
  STS: TSystemTime;
  STD: TSystemTime;
begin

  { Check GetTimeZoneInformationForYear function }
  @GetTimeZoneInformationForYear := GetProcAddress(GetModuleHandle(kernel32),
                                                   'GetTimeZoneInformationForYear');
  if Assigned(GetTimeZoneInformationForYear) = False then
  begin
    raise EGetProcAddress.Create('Could not load ' +
                                 'GetTimeZoneInformationForYear' +
                                 ' from ' + kernel32);
  end;

  if (GetTimeZoneInformationForYear(Year,nil,TZI) = False) or
     (TZI.StandardDate.wMonth = 0) then
  begin
    Result := False;
    Exit;
  end;

  { Offset }
  Offset := TZI.DaylightBias;

  { Name }
  Name := TZI.DaylightName;

  { Convert to absolute }
  STS := CanonicalizeSystemTime(Year,TZI.StandardDate);
  STD := CanonicalizeSystemTime(Year,TZI.DaylightDate);

  { Start date }
  DTStart := SystemTimeToDateTime(STD);
  DescriptionStart := SystemTimeToDescription(TZI.DaylightDate);

  if CompareSystemTime(STS,STD) > 0 then
  begin
    { Northern hemisphere }
    DTEnd := SystemTimeToDateTime(STS);
    DescriptionEnd := SystemTimeToDescription((TZI.StandardDate));
  end
  else
  begin
    { Southern hemisphere }
    if (GetTimeZoneInformationForYear(Year + 1,nil,TZI) = True) and
       (TZI.StandardDate.wMonth > 0) then
    begin
      { Convert to absolute }
      STS := CanonicalizeSystemTime(Year + 1,TZI.StandardDate);

      { End date }
      DTEnd := SystemTimeToDateTime(STS);
      DescriptionEnd := SystemTimeToDescription((TZI.StandardDate));
    end
    else
    begin
      DTEnd := 0;
      DescriptionEnd := '';
    end;
  end;

  Result := True;

end;

GetTimeZoneInformationForYearのアドレスを取得して(取得できない場合は例外が送出されます)呼び出し、取得した情報の解釈を行い(必要なら翌年の情報も取得します)、正常に終了したらTrueを返します。情報の取得に失敗したり、指定した年に夏時間が実施されない場合はFalseを返します。
ただしMicrosoftは原則として半年に1回しか夏時間に関する更新情報を配信しないため、南半球でその年(の下半期)に始まる夏時間の情報がない(前年から継続している夏時間の情報しかない)と、その年の01/01から前年に始まった夏時間の終了までの情報が重複して取得されます。夏時間の情報は重複しないと思っていると落とし穴にはまるかもしれませんので注意が必要です。

2010年8月13日

RAD Studio Roadmap 2010/08版

公式forumでクロスプラットフォームサポートはどこにいっちゃったの?というツッコミに対してAllen BauerさんがMichael Rozlogがロードマップ更新してるんでちょっと待っててと発言していましたが、その更新されたロードマップが公開されています(向こうの人にはお盆休みは理解できないんでしょう、自分たちは平気で何週間もバカンス取るのにね)。

RAD Studio, Delphi and C++Builder Roadmap
RAD Studio, Delphi, C++Builder, Delphi Prism のロードマップについて

現在進行中のプロジェクトには
  • Pulsar (MacOS Xサポート)
  • 64bit Compiler Preview (x64のプレビュー版)
  • Wheelhouse (Linuxサポート)
  • Commodore (x64サポート)
があげられています。
  • 64bit Compiler Previewはコマンドライン版のみ、Windows x64のコード生成を可能にした新コンパイラで、2011年前半にリリース予定。

  • Pulsarはクロス環境の雪辱戦で、DelphiのWindows x64サポートとMacOS X x86のサポート、具体的にはMacOS X用のリモートデバッグ環境、VCLライクなクロスプラットフォーム用のコンポーネントライブラリ、C++のエディタの更新、VCLの更新、ヘルプ統合の再デザイン、ユニットテストの自動生成、クロスクラウドAPIサポートの追加が含まれています。

  • WheelhouseはC++BuilderのWindows x64サポートとWindows、MacOS Xに加えてLinux Severのサポート、具体的にはLinux上のDatasnapサーバ用のDelphi 32bitコンパイラ、新しいアーキテクチャのC++コンパイラの導入、リモートデバッグ環境のLinuxサポート、クロスプラットフォームのVCLライクなコンポーネントライブラリ、ApacheのWebModules/WebBroker統合のサポート、新しいデータバインディングアーキテクチャ、VCL/クロスプラットフォームコンポーネントライブラリへのNatural Inputの更なる統合が含まれています。

  • Commodoreはx64のフルサポート、具体的にはコンパイラ、RTL、VCL/クロスプラットフォームライブラリの全面64bitコンパイラサポート、ARMのサポート、マルチコア/マルチスレッドアプリケーション開発の拡張、パラレル化のRTLサポート、マルチコアサポートとデバッグのためのパラレル可能化ライブラリ、ソーシャルネットワーク統合が含まれています。

ということで現時点ではPulsarは2011年、Wheelhouseは2012年、Commodoreは2013年と考えるのが妥当かと(注:もっと短いサイクルでリリースされることを否定するものではありません)。またLinuxのGUIクライアントサポートは一旦消えたと思われます。

2010/08/17追記: 日本語(ロードマップそのものは英語のままですが)のアーティクルのリンクを追加しました。

2010/08/17追記: 公式フォーラムのRoadmap: Clarification Required PleaseというスレッドのAllen Bauerさんの回答によれば、PulsarにおけるDelphiのWindows x64サポートはコンパイラ、デバッガ、VCLなど全てが実装されることが目標である、とのことです。また64bit版Delphiは2011年、64bit版C++は2012年を目標としている、とも発言しています。元ねたはJolyon SmithさんXE Roadmap Clarified

2010年8月12日

FirebirdConfig

Firebird newsを見ていたらFirebirdの設定ファイルであるfirebird.confを編集するFirebirdConfigというツールがありました(最新バージョンは0.2.0.39)。誰か日本語リソース作ってくれないかな…。

元ねたはFirebird News » #FirebirdConfig for #Firebird returns now with new Version and new wepages in English and Spanish

2010年8月11日

Microsoft Monthly Update 2010/08

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

Windows 2000 Service Pack 4の延長サポートフェーズ終了を待っていた(=故意にWindows 2000のセキュリティホールを放置してサポート終了を待った)としか考えられないアップデートの数です。延長サポートフェーズ最後の定例アップデートのOSの分にはWindows 2000に影響しない公知のセキュリティホールしか含まれていないことからも明らかといえるでしょう。

2010/08/18追記: MS10-060の.NET Framework 2.0 Service Pack 1/2用の更新プログラム(ファイル名がNDP20で始まるもの)はWindows 2000 Service Pack 4/XP Service Pack 2にもそのまま適用可能なようです。

2010年8月10日

RAD Studio XE スニークプレビュー その1

FulcrumことRAD Studio XE(!)のsneak previewが始まったようです。

まずはDelphiソリューションプロダクトマネージャのMichael Rozlogさんのところ。
エンバカデロ・テクノロジーズの公式ページ。
Andreano Lanusseさんのところ。
製品マーケティングマネージャのTim Del Chiaroさんのところ。
EDNのリリース。
チーフエバンジェリストのDavid Iさんのところ。
発売はESD版が2010/09/02、パッケージ版は2010/09/中旬の予定の模様です。

XEというネーミングはよく見りゃ5月の時点でNick HodgesさんがRandom Thoughts on the Passing Scene #158の中でRAD Studio will eventually become an “XE Product”って書いていましたね。見落としてました。

これらの記事のポイントを。
  • RAD Studio XEにはDelphi XE、C++Builder XE、Delphi Prism XE、RadPHP XE(Delphi for PHP)が含まれる。
  • Delphi/C++Builder/Delphi PrismではIDEにSubversionサポートが追加される。またその他のSCM(Source Code Management)の統合が可能になるようにOTA(Open Tools API)が用意されている。
  • Beyond Compareなどのサードパーティ製のツールがバンドルされ、IDEか呼び出すことができる。
  • コードエディタの検索、フォーマッタ、ナビゲーションがアップデートされ、フォーマッタのプロファイルを保存して共有することができるようになる。
  • 最新のデータベースへの対応とDatasnapの機能拡張。
  • 生産性を向上させるいろいろな"ちょっとした"改善も含まれる。
  • VCL/RTL、Boost、標準C++ライブラリの改善、正規表現ライブラリ(Regex)の追加、ジェネリクスの更新が含まれる。
  • Delphi/C++Builder/RadPHPのデバッガには新しい機能が追加される。
  • Delphi XEのモデリング機能が強化され、コードからのクラス図、シーケンス図の生成ができる。またモデルからより高品質のコードが生成できるようになる。
  • Delphi for PHPはRadPHPとなってRAD Studioに含まれるようになる。またRadPHPのIDEはDelphi/C++Builderと同様のものになる(同一かどうかは?)。facebookサポートが追加され、Facebookアプリケーションを簡単に作成できる(個人的にはfacebookの何がいいのかさっぱりわかりませんけど)。またjQueryQooxdooを利用したコンポーネントも追加されている。さらにDatasnapコンポーネントでDatasnapクライアントを作成することもできる。
  • Delphi 2010で追加された(Delphi 7のような)クラシックデザイナも継続して使用できる。
  • XEというブランドはheterogeneous(=X)、embarcadero(=E)から連想したもので、2011はXE、その後はXE2、XE3とする予定。

2010/08/11追記: ComponentSourceさんSEShop.comさんで価格も表示されています。それより気になるのは

また、XEシリーズでは、主要な旧バージョンの製品が追加コストなしに利用が可能となります。
XEにて利用可能な旧バージョン製品:

  • Delphi XE・・・Delphi 2010、2009、2007、7
  • C++Builder XE・・・C++Builder 2010、2009、2007、6
  • Delphi Prism XE・・・Delphi Prism 2011、2010、2009
  • RAD Studio XE・・・上記全ての製品


というところです。これで『どのバージョンを買えばいいのでしょう?』という質問にも『XE買っとけ』でいいことになります。別に古いプロダクトを同梱したからってコストが上がるわけでもないでしょうし。

2010/08/17追記: 更新完了。

データを暗号化して保存する(2)

前回CryptProtectDataCryptUnprotectDataでバイナリデータをTStream経由で暗号化、復号化しましたが、通常は単純に文字列を扱いたいことのほうが多いと思います。そこで簡略版として文字列のみで処理を構成してみました。
uses
  Windows, Classes, SysUtils;

function BlobToString(P: PByte; Size: DWORD): String;
begin

  Result := '';

  while Size > 0 do
  begin
    Result := Result + IntToHex(P^,2);
    Inc(P,1);
    Size := Size - 1;
  end;

end;

procedure ProtectString(const Source: String; var Dest: String;
                        const Description: String; const Entropy: String;
                        LocalMachine: Boolean);
var
  DataIn: DATA_BLOB;
  OptionalEntropy: DATA_BLOB;
  POptionalEntropy: PDATA_BLOB;
  DataOut: DATA_BLOB;
{$IFDEF Unicode}
  WDescription: String;
{$ELSE}
  WDescription: WideString;
{$ENDIF}
  Flags: DWORD;
  MemorySource: TMemoryStream;
  MemoryEntropy: TMemoryStream;
begin

  MemorySource := nil;
  MemoryEntropy := nil;
  try
    MemorySource := TMemoryStream.Create;
    MemoryEntropy := TMemoryStream.Create;

    { DataIn }
    with MemorySource do
    begin
      Write(PChar(Source)^,Length(Source) * SizeOf(Char));
      DataIn.cbData := Size;
      DataIn.pbData := Memory;
    end;

    { OptionalEntropy }
    if Entropy = '' then
    begin
      POptionalEntropy := nil;
    end
    else
    begin
      with MemoryEntropy do
      begin
        Write(PChar(Entropy)^,Length(Entropy) * SizeOf(Char));
        OptionalEntropy.cbData := Size;
        OptionalEntropy.pbData := Memory;
      end;
      POptionalEntropy := @OptionalEntropy;
    end;

    { Description }
    WDescription := Description;

    { Flags }
    Flags := 0;
    if LocalMachine = True then
    begin
      Flags := CRYPTPROTECT_LOCAL_MACHINE;
    end;

    { DataOut }
    FillChar(DataOut,SizeOf(DataOut),0);

    { Protect data }
    if CryptProtectData(@DataIn,PWideChar(WDescription),POptionalEntropy,nil,
                        nil,Flags,@DataOut) = False then
    begin
      RaiseLastOSError;
    end;

    { Result }
    Dest := BlobToString(DataOut.pbData,DataOut.cbData);

    { Free allocated memory }
    LocalFree(HLOCAL(DataOut.pbData));

  finally
    MemorySource.Free;
    MemoryEntropy.Free;
  end;

end;

Source、Description、Entropyに文字列を渡すとDestに暗号化されたデータが16進文字列化されて格納されます。
復号化も同様に
function StringToBlob(const S: String; Stream: TStream): Boolean;
var
  Index: Integer;
  Data: Byte;
  L: Integer;
begin

  Index := 1;
  L := Length(S);

  while Index <= L do
  begin
    try
      Data := StrToInt('$' + Copy(S,Index,2));
    except
      Result := False;
      Exit;
    end;

    Stream.Write(Data,SizeOf(Data));

    Index := Index + 2;
  end;

  Result := True;

end;

function  UnprotectString(const Source: String; var Dest: String;
                          var Description: String; const Entropy: String): Boolean;
var
  DataIn: DATA_BLOB;
  OptionalEntropy: DATA_BLOB;
  POptionalEntropy: PDATA_BLOB;
  DataOut: DATA_BLOB;
  PDescription: PWideChar;
  MemorySource: TMemoryStream;
  MemoryEntropy: TMemoryStream;
begin

  MemorySource := nil;
  MemoryEntropy := nil;
  try
    MemorySource := TMemoryStream.Create;
    MemoryEntropy := TMemoryStream.Create;

    { DataIn }
    if StringToBlob(Source,MemorySource) = False then
    begin
      Result := False;
      Exit;
    end;
    with MemorySource do
    begin
      DataIn.cbData := Size;
      DataIn.pbData := Memory;
    end;

    { OptionalEntropy }
    if Entropy = '' then
    begin
      POptionalEntropy := nil;
    end
    else
    begin
      with MemoryEntropy do
      begin
        Write(PChar(Entropy)^,Length(Entropy) * SizeOf(Char));
        OptionalEntropy.cbData := Size;
        OptionalEntropy.pbData := Memory;
      end;
      POptionalEntropy := @OptionalEntropy;
    end;

    { DataOut }
    FillChar(DataOut,SizeOf(DataOut),0);

    { Unprotect data }
    if CryptUnprotectData(@DataIn,PDescription,POptionalEntropy,nil,
                          nil,0,@DataOut) = False then
    begin
      Result := False;
      Exit;
    end;

    { Result }
    SetString(Dest,PChar(DataOut.pbData),DataOut.cbData div SizeOf(Char));

    { Description }
    Description := PDescription;

    { Free allocated memory }
    LocalFree(HLOCAL(DataOut.pbData));
    LocalFree(HLOCAL(PDescription));

    Result := True;

  finally
    MemorySource.Free;
    MemoryEntropy.Free;
  end;

end;
Source、Entropyに文字列を渡すとDest、Descriptionに復号化された文字列が格納されます。 蛇足ですが、自システムのパスワードはSHAなど(MD5はいまさらな気も)何らかの形でハッシュして保存しておき、入力も同様の方法でハッシュして結果の一致を確認する、という手法が一般的です。

2010年8月7日

[書籍]プログラミングの魔導書 ~Programmers' Grimoire~ vol.1

プログラミングの魔導書 ~Programmers' Grimoire~が発売になりました(PDF版がダウンロード可能になったという意味で)。

プログラミングの魔導書 ~Programmers’ Grimoire~ vol.1/ロングゲート/ISBN 978-4-9905296-0-4(書籍版)、ISBN 978-4-9905296-1-1(PDF版)/1,500円(書籍版)、1,000円(PDF版)

書籍版は完全予約制のため、発売時点以降ではPDF版のみが購入可能です。また書籍版については予約期間終了後に印刷を発注するため、書籍の発送は、8/20以降となる予定です。とのことです。

予告では次号は"Evolution of Programming Languages"と題してHaskell 2.0、D 3.0、Java 7、Scala 2.8、C++0xを扱うようです。またインタビューはDave Abrahamsさん(C++標準化委員会のメンバでBoostの偉い人)だそうです。

2010/08/25追記: 書籍版が08/23に届きました。やはりPDFとは印象が違いますね。できれば光沢のない紙のほうがいいのですが。

2011/10/05追記: リンクをVol.1のサポートページのものに置き換えました。

2010年8月6日

データを暗号化して保存する(1)

他システムやデータベース、FTPサーバなどのパスワードをファイルやレジストリに保存する必要がある場合、何らかの形で暗号化して保存し、使用するときに復号化する、ということが必要になります。このようなときにCryptProtectDataCryptUnprotectDataを使用する方法が考えられます。もちろんこれで万全かといわれると難しいところですが、少なくとも生のまま保存するよりはまし、といったところでしょうか。
CryptProtectDataで暗号化するときに第6パラメータ(dwFlags)にCRYPTPROTECT_LOCAL_MACHINEを含めると同一PC上の全てのユーザで復号化できてしまいますが、含めなければ同一PC上の同一のユーザでのみ復号化できます。また第3パラメータ(pOptionalEntropy)でエントロピを指定して暗号化しておけばCryptUnprotectDataで同じエントロピを指定しないと復号化できないようにすることができます。なおWindows 2000では第2パラメータのszDataDescrを省略する(NULLにする)ことができないので注意が必要です。
まず使用するCryptAPIと構造体を定義します。
uses
  Windows;

type
  _CRYPTOAPI_BLOB = record
    cbData: DWORD;
    pbData: PBYTE;
  end;
  {$EXTERNALSYM _CRYPTOAPI_BLOB}

  DATA_BLOB = _CRYPTOAPI_BLOB;
  {$EXTERNALSYM DATA_BLOB}
  PDATA_BLOB = ^DATA_BLOB;
  {$EXTERNALSYM PDATA_BLOB}

  PCRYPTPROTECT_PROMPTSTRUCT = ^CRYPTPROTECT_PROMPTSTRUCT;
  {$EXTERNALSYM PCRYPTPROTECT_PROMPTSTRUCT}
  _CRYPTPROTECT_PROMPTSTRUCT = record
    cbSize: DWORD;
    dwPromptFlags: DWORD;
    hwndApp: HWND;
    szPrompt: LPCWSTR;
  end;
  {$EXTERNALSYM _CRYPTPROTECT_PROMPTSTRUCT}
  CRYPTPROTECT_PROMPTSTRUCT = _CRYPTPROTECT_PROMPTSTRUCT;
  {$EXTERNALSYM CRYPTPROTECT_PROMPTSTRUCT}

const
  CRYPTPROTECT_LOCAL_MACHINE = $4;
  {$EXTERNALSYM CRYPTPROTECT_LOCAL_MACHINE}

function CryptProtectData(pDataIn: PDATA_BLOB; szDataDescr: PWideChar;
                          pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer;
                          pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT;
                          dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;
  external 'crypt32.dll' name 'CryptProtectData';
{$EXTERNALSYM CryptProtectData}

function CryptUnprotectData(pDataIn: PDATA_BLOB; var ppszDataDescr: PWideChar;
                            pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer;
                            pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT;
                            dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;
  external 'crypt32.dll' name 'CryptUnprotectData';
{$EXTERNALSYM CryptUnprotectData}

CryptProtectData/CryptUnprotectDataで扱うデータは基本的にバイナリなので、まずはTStreamを暗号化してみます。
uses
  Windows, Classes, SysUtils;

procedure ProtectStream(Source: TStream; Dest: TStream;
{$IFDEF Unicode}
                        const Description: String;
{$ELSE}
                        const Description: WideString;
{$ENDIF}
                        Entropy: TStream; LocalMachine: Boolean);
var
  DataIn: DATA_BLOB;
  OptionalEntropy: DATA_BLOB;
  POptionalEntropy: PDATA_BLOB;
  DataOut: DATA_BLOB;
  Flags: DWORD;
  MemorySource: TMemoryStream;
  MemoryEntropy: TMemoryStream;
begin

  MemorySource := nil;
  MemoryEntropy := nil;
  try
    MemorySource := TMemoryStream.Create;
    MemoryEntropy := TMemoryStream.Create;

    { DataIn }
    with MemorySource do
    begin
      Source.Position := 0;
      LoadFromStream(Source);
      DataIn.cbData := Size;
      DataIn.pbData := Memory;
    end;

    { OptionalEntropy }
    if Entropy = nil then
    begin
      POptionalEntropy := nil;
    end
    else
    begin
      with MemoryEntropy do
      begin
        Entropy.Position := 0;
        LoadFromStream(Entropy);
        OptionalEntropy.cbData := Size;
        OptionalEntropy.pbData := Memory;
      end;
      POptionalEntropy := @OptionalEntropy;
    end;

    { Flags }
    Flags := 0;
    if LocalMachine = True then
    begin
      Flags := CRYPTPROTECT_LOCAL_MACHINE;
    end;

    { DataOut }
    FillChar(DataOut,SizeOf(DataOut),0);

    { Protect data }
    if CryptProtectData(@DataIn,PWideChar(Description),POptionalEntropy,nil,
                        nil,Flags,@DataOut) = False then
    begin
      RaiseLastOSError;
    end;

    { Result }
    Dest.Write(DataOut.pbData^,DataOut.cbData);

    { Free allocated memory }
    LocalFree(HLOCAL(DataOut.pbData));

  finally
    MemorySource.Free;
    MemoryEntropy.Free;
  end;

end;

対象データと(指定されていれば)エントロピをTMemoryStreamに格納してそのMemory/SizeプロパティをDATA_BLOB構造体(=CRYPT_INTEGER_BLOB構造体)のpbData/cbDataにセットし、CryptProtectDataを呼び出します。DataOutには暗号化されたデータが格納されていますので、これを取り出し、最後に忘れずにLocalFreeでDataOutの内容を解放します。
復号化も同様に
function UnprotectStream(Source: TStream; Dest: TStream;
{$IFDEF Unicode}
                         var Description: String;
{$ELSE}
                         var Description: WideString;
{$ENDIF}
                         Entropy: TStream): Boolean;
var
  DataIn: DATA_BLOB;
  OptionalEntropy: DATA_BLOB;
  POptionalEntropy: PDATA_BLOB;
  DataOut: DATA_BLOB;
  PDescription: PWideChar;
  MemorySource: TMemoryStream;
  MemoryEntropy: TMemoryStream;
begin

  MemorySource := nil;
  MemoryEntropy := nil;
  try
    MemorySource := TMemoryStream.Create;
    MemoryEntropy := TMemoryStream.Create;

    { DataIn }
    with MemorySource do
    begin
      Source.Position := 0;
      LoadFromStream(Source);
      DataIn.cbData := Size;
      DataIn.pbData := Memory;
    end;

    { OptionalEntropy }
    if Entropy = nil then
    begin
      POptionalEntropy := nil;
    end
    else
    begin
      with MemoryEntropy do
      begin
        Entropy.Position := 0;
        LoadFromStream(Entropy);
        OptionalEntropy.cbData := Size;
        OptionalEntropy.pbData := Memory;
      end;
      POptionalEntropy := @OptionalEntropy;
    end;

    { DataOut }
    FillChar(DataOut,SizeOf(DataOut),0);

    { Unprotect data }
    if CryptUnprotectData(@DataIn,PDescription,POptionalEntropy,nil,
                          nil,0,@DataOut) = False then
    begin
      Result := False;
      Exit;
    end;

    { Result }
    Dest.Write(DataOut.pbData^,DataOut.cbData);

    { Description }
    Description := PDescription;

    { Free allocated memory }
    LocalFree(HLOCAL(DataOut.pbData));
    LocalFree(HLOCAL(PDescription));

    Result := True;

  finally
    MemorySource.Free;
    MemoryEntropy.Free;
  end;

end;

対象データと(指定されていれば)エントロピをTMemoryStreamに格納してそのMemory/SizeプロパティをDATA_BLOB構造体のpbData/cbDataにセットし、CryptUnprotectDataを呼び出します。DataOutとPDescriptionには復号化されたデータと暗号化のときに指定したDescriptionが格納されていますので、これらを取り出し、最後に忘れずにLocalFreeでDataOutとPDescriptionの内容を解放します。もし復号化に失敗した場合は戻値がFalseになります。

長くなったので続きます。

元ねたはNyaRuRuさんローカルストレージに保存するデータの暗号化 ― Windows の場合 - NyaRuRuの日記EternalWindowsさんDPAPIによる暗号化

2010年8月5日

ユニット間の依存関係を解析する

それなりの規模のプロジェクトでユニット間の依存関係を調べたい、あるいは必要のないusesを削除したい、ということが時々あります。そのようなときに使えそうなフリーのツール3種類です。

Peganza - ICARUS
解析結果がレポート形式で表示されます。日本語を含むソースの場合は[Options]→[Project Properties...]→[Parser]の"Allow multi-byte characters"をチェックオンする必要があります。usesの必要のないユニットやinterface部ではなくimplementation部にusesすれば十分なユニットがマークされるので便利です。

ModelMaker Tools :: Unit Dependency Analyzer ; unit uses / used by relations and cyclic dependencies.
解析結果はツリー形式で表示されます。usesしているユニット、usesされているユニット、循環参照がわかります。またツリー部分で選択しているuses/used byのユニットを[Ctrl]+[Enter]でたどっていくこともできます。

またCnPack Open Source ProjectsのCnWizardsには"Uses Unit Cleaner Wizard"という不要なusesを自動的にクリーンアップする機能があるようです。

元ねたはStack OverflowDelphi - Reverse Lookup ' who includes this unit'How to "automatically" remove unused units from uses clause?

2010年8月3日

Microsoft OOB Update 2010/08

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

Windows 2000 Service Pack 4は延長サポートフェーズが終了しており更新プログラムが提供されていないため、サードパーティによる対策ツールを使用するのが望ましいです…。

G Data Software AGさん「アイコン表示ウイルス」対策無償ツール
ソフォスさんWindows Shortcut Exploit Protection Tool

どちらもWindows 2000で動作します。