2010年11月4日

$WARNによる警告の制御

Delphiではコンパイラディレクティブ$WARNを使用して警告を有効/無効/エラーに昇格/デフォルトに戻すという指定をすることができます(エラーに昇格、デフォルトに戻すの2つはDelphi 2009以降の新機能)。

{$WARN identifier ON | OFF | ERROR | DEFAULT}
ONを指定するとその警告が有効に、OFFで無効に、ERRORでその警告をエラーに昇格、DEFAULTで指定をプロジェクトオプションで指定したものに戻す、という動作になります。

指定可能な警告とエラーコードは以下のとおりです。
SYMBOL_DEPRECATED
W1000 (ja)
SYMBOL_LIBRARY
W1001 (ja)
SYMBOL_PLATFORM
W1002 (ja)
SYMBOL_EXPERIMENTAL
W1003 (ja)
UNIT_LIBRARY
W1004 (ja)
UNIT_PLATFORM
W1005 (ja)
UNIT_DEPRECATED
W1006 (ja)
UNIT_EXPERIMENTAL
W1007 (ja)
HRESULT_COMPAT
W1008 (ja)
HIDING_MEMBER
W1009 (ja)
HIDDEN_VIRTUAL
W1010 (ja)
GARBAGE
W1011 (ja)
BOUNDS_ERROR
x1012 (ja)
ZERO_NIL_COMPAT
W1013 (ja)
STRING_CONST_TRUNCED
W1014 (ja)
FOR_LOOP_VAR_VARPAR
W1015 (ja)
TYPED_CONST_VARPAR
W1016 (ja)
ASG_TO_TYPED_CONST
W1017 (ja)
CASE_LABEL_RANGE
W1018 (ja)
FOR_VARIABLE
x1019 (ja)
CONSTRUCTING_ABSTRACT
x1020 (ja)
COMPARISON_FALSE
W1021 (ja)
COMPARISON_TRUE
W1022 (ja)
COMPARING_SIGNED_UNSIGNED
W1023 (ja)
COMBINING_SIGNED_UNSIGNED
W1024 (ja)
UNSUPPORTED_CONSTRUCT
x1025 (ja)
FILE_OPEN
x1026 (ja)
FILE_OPEN_UNITSRC
F1027 (ja)
BAD_GLOBAL_SYMBOL
x1028 (ja)
DUPLICATE_CTOR_DTOR
W1029 (ja)
INVALID_DIRECTIVE
x1030 (ja)
PACKAGE_NO_LINK
W1031 (ja)
PACKAGED_THREADVAR
W1032 (ja)
IMPLICIT_IMPORT
x1033 (ja)
HPPEMIT_IGNORED
W1034 (ja)
NO_RETVAL
W1035 (ja)
USE_BEFORE_DEF
W1036 (ja)
FOR_LOOP_VAR_UNDEF
W1037 (ja)
UNIT_NAME_MISMATCH
E1038 (ja)
NO_CFG_FILE_FOUND
W1039 (ja)
IMPLICIT_VARIANTS
W1040 (ja)
UNICODE_TO_LOCALE
W1041 (ja)
LOCALE_TO_UNICODE
W1042 (ja)
IMAGEBASE_MULTIPLE
W1043 (ja)
SUSPICIOUS_TYPECAST
W1044 (ja)
PRIVATE_PROPACCESSOR
W1045 (ja)
UNSAFE_TYPE
W1046 (ja)
UNSAFE_CODE
W1047 (ja)
UNSAFE_CAST
W1048 (ja)
OPTION_TRUNCATED
W1049 (ja)
WIDECHAR_REDUCED
W1050 (ja)
DUPLICATES_IGNORED
W1051 (ja)
UNIT_INIT_SEQ
W1052 (ja)
LOCAL_PINVOKE
W1053 (ja)
MESSAGE_DIRECTIVE
x1054 (ja)
TYPEINFO_IMPLICITLY_ADDED
W1055 (ja)
RLINK_WARNING
x1056 (ja)
IMPLICIT_STRING_CAST
W1057 (ja)
IMPLICIT_STRING_CAST_LOSS
W1058 (ja)
EXPLICIT_STRING_CAST
W1059 (ja)
EXPLICIT_STRING_CAST_LOSS
W1060 (ja)
CVT_WCHAR_TO_ACHAR
W1061 (ja)
CVT_NARROWING_STRING_LOST
W1062 (ja)
CVT_ACHAR_TO_WCHAR
W1063 (ja)
CVT_WIDENING_STRING_LOST
W1064 (ja)
NON_PORTABLE_TYPECAST
W1065 (ja)
LOST_EXTENDED_PRECISION
W1066 (ja)
LNKDFM_NOTFOUND
W1067 (ja)
IMMUTABLE_STRINGS
W1068 (ja)
MOBILE_DELPHI
W1069 (ja)
UNSAFE_VOID_POINTER
W1070 (ja)
IMPLICIT_INTEGER_CAST_LOSS
W1071 (ja)
IMPLICIT_CONVERSION_LOSS
W1072 (ja)
COMBINING_SIGNED_UNSIGNED64
W1073 (ja)
UNKNOWN_CUSTOM_ATTRIBUTE
W1074 (ja)
OVERLOADING_ARRAY_PROPERTY
W1075 (ja)
POINTER_CAST_NARROWER
W1076 (ja)
POINTER_CAST_MIGRATION
W1077 (ja)
POPOPT_WITH_NO_MATCHING
W1078 (ja)
MISSING_POPOPT
W1079 (ja)
INVALID_NORETURN
W1080 (ja)
XML_WHITESPACE_NOT_ALLOWED
W1201 (ja)
XML_UNKNOWN_ENTITY
W1202 (ja)
XML_INVALID_NAME_START
W1203 (ja)
XML_INVALID_NAME
W1204 (ja)
XML_EXPECTED_CHARACTER
W1205 (ja)
XML_CREF_NO_RESOLVE
W1206 (ja)
XML_NO_PARM
W1207 (ja)
XML_NO_MATCHING_PARM
W1208 (ja)
元ねたはSource\ToolsAPI\DCCStrs.pas警告メッセージ(Delphi) - RAD Studio (en)、エラーと警告のメッセージ(Delphi) - RAD Studio (en)。

2016/04/28追記: Delphi 10.1 Berlinの情報を追加。
2017/04/04追記: Delphi 10.2 Tokyoで追加されたW1071/W1072/W1073の情報を追加。
2018/12/01追記: Delphi 10.3 Rioで追加されたW1074の情報を追加。
2019/02/27追記: W1067/W1069/W1070/W1071/W1072/W1073のリンクを追加。
2023/11/09追記: W1074のリンクを追加。
2026/03/22追記: Delphi 13 Florenceで追加されたW1075/W1076/W1077/W1078/W1079およびDelphi 13.1 Florenceで追加されたW1080の情報を追加。

2010年11月2日

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

第18回エンバカデロ・デベロッパーキャンプは(かねてからの予告どおり)2010年12月07日に開催されます。

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

またT6セッション『ライトニングトーク「共有!みんなの開発事例、開発経験、 テクニック」』のスピーカを募集しています。

【募集】第18回 エンバカデロ・デベロッパーキャンプ - ライトニングトークスピーカー

2010/11/04追記: ライトニングトークに高橋さんが参戦するようです。

Team Japan » ライトニングトークで喋ってみませんか?

ん~。いいネタを思いつかないし、ネタから考えるには仕事が忙しい気がするし…。

2010/11/10追記: 今回はUStreamとLiveMeeting(事前登録はここから)の両方で中継するそうです。あれ、エンバカデロ本社の誰かがCodeRage 5の後で次回からLiveMeetingはやめて他のシステムを使うようなことをいっていたような(クロスプラットフォームといいながらMac/Linuxで見られないのはいかがなものかという話の流れで)。

2010/11/19追記: UStreamでMalcolm Grovesさん出演の事前放送が行われるとのことです。

2010/11/25 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回
2010/11/26 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回(再放送) (リンク先の日付が11/19になっていますが、11/26が正しいはず)

2010/11/27追記: Team Japanに関連アーティクルが出ています。

Team Japan » 12月7日は第18回 エンバカデロ・デベロッパーキャンプです

2010/11/30追記: UStreamでJason Tiretさん出演の事前放送が行われます。

2010/12/02 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回
2010/12/03 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回(再放送)

2010/12/02 追記: Team Japanに会場へのアクセスについてのアーティクルが出ています。

Team Japan » 第18回 エンバカデロ・デベロッパーキャンプ会場へのアクセス

2010年10月28日

CodeRage 5 セッションリプレイ

CodeRage 5セッションリプレイが見られるようになりました。

個人的に要チェックなセッション(全部は無理だろうけど):
また一部ですがスピーカの方々によるセッション資料、サンプルコードの公開も行われています。

Marco Cantuさん(Day 1: Session 1/2, Day 2: Session 14/15)
CodeRage 5 Slides and Code Downloads

Cary Jensenさん(Day 2: Session 20)
28044 CDSDemo Simple ClientDataSet Demonstration

John Kasterさん(Day 5: Session 57)
28067 Deep dive into dbExpress CodeRage 5 slides
DbxUtils(svn)

2010年10月25日

WMI Delphi Code Creator

RRUZ(Rodrigo Ruz)さんによるDelphiでWMI(Windows Management Instrumentation)を扱うコード(コンソールアプリケーションおよびアクセスメソッド)を生成するツール。興味深い。とりあえずメモ。

WMI Delphi Code Creator « The Road to Delphi – a Blog About Delphi Programming (mostly)

ただしWindows 2000では正常に動作しません(GetText_メソッドがサポートされていないというエラーが発生します)。

2010/10/26追記: WMI Delphi Code Creatorが1.0.0.1から1.0.0.11に更新されています。

WMI Delphi Code Creator – New Features « The Road to Delphi – a Blog About Delphi Programming (mostly)

インストーラ形式になったほか、生成したコードを直接コンパイル/実行したりDelphiのIDEで開く機能や、WMIのメソッド呼び出し/イベントのサポートなどが追加されています。

2010/11/29追記: OSによりWMIのインタフェースのサポートするメソッドが異なるので注意しましょう、という補足記事が出ています。

Be careful when you import the Microsoft WMIScripting Library « The Road to Delphi – a Blog About Delphi Programming (mostly)

てきとうな要約: Microsoft WMIScripting LibraryをDelphiのインポートウィザードで取り込んで生成したWMIのインタフェースは環境(というより"%System32%\wbem\wbemdisp.TLB")に依存してしまうため、新しいOSで追加されたインタフェースには気をつける必要がある。環境に依存しないようにするには、対応する予定のOSの最も古いもののインタフェースのみを使用する。例としてあげられているISWbemObjectSetのItemIndexメソッドはWindows XPには存在しないがWindows 7には存在するため、気付かずにItemIndexを使用しているとWindows XPで実行時にアクセスバイオレーションを引き起こしてしまう。これを防ぐにはItemIndexを使用せず、代わりに_NewEnumメソッドで取得したIEnumVariantインタフェースのNextメソッドを使用する。

2010年10月22日

InterBase XEリリース

どうやらInterBase XEがリリースされているようです。バージョンはWindows x86が10.0.0.247、Windows x64が10.0.0.258となっています。まだ日本語の情報は出ていないようなので、英語の登録、導入、ライセンスに関する情報のリンクを再掲しておきます。

Embarcadero InterBase News - New InterBase XE
Download a Free Trial for InterBase

Installation, Registration, and Licensing Information for Embarcadero ® InterBase® XE
InterBase XE Readme

2010年10月21日

Firebird 2.5 日本語インストーラリリース

Firebird日本ユーザ会からFirebird 2.5(Win32)の日本語インストーラがリリースされています。ただし
本インストーラーのFirebirdは、はやしがMS VisualStudio2008でビルドしたものです。公式に配布されているバイナリはVisualStudio2005でビルドされているもので、必要なMSのランタイムライブラリのバージョンが違っています。必要なランタイムライブラリはインストーラーがインストールしますが、問題がある場合には英語版の公式インストーラーをご利用下さい。
とのことなので注意が必要です。ダウンロードページからダウンロード可能です。

元ねたはFirebird News » Japanese Firebird 2.5.0 installer is ready (Windows 32-bit versions)

2010年10月15日

FFR yarai 脆弱性防御機能 for Windows 2000 動作検知用スクリプト

Windows 2000(Service Pack 4)は2010/07/13で延長サポートフェーズが終了しています。企業などでは延長サポートが終了したOSはPCごと更新してしまうのが望ましいわけですが、色々な(お金やリソースの)事情でなかなか更新できない、ということもあります。そのような場合の延命策のひとつとして、フォティーンフォティ技術研究所(FFR)のFFR yarai 脆弱性防御機能 for Windows 2000(yarai2000)を導入している場合もあるのではないでしょうか。ところがこのツール、異常な動作を検知してもイベントログにイベントを記録するだけで、ユーザに明示的に通知するようにはなっていません。そこでyarai2000がイベントログにイベントを追加するのを監視して、エラーダイアログを表示するスクリプト(VBS)をでっち上げてみました。
strComputer = "."

Set objWMIService = GetObject("winmgmts:{(Security)}\\" & _
                              strComputer & "\root\cimv2")

Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
                         ("Select * from __InstanceCreationEvent Where " & _
                          "TargetInstance ISA 'Win32_NTLogEvent' " & _
                          "and TargetInstance.SourceName = 'yarai ZDP' ")

Do
  Set objLatestEvent = colMonitoredEvents.NextEvent
  If objLatestEvent.TargetInstance.EventCode = 1 Then
    Call MsgBox("FFR yarai 2000が異常を検知しました。" & _
                vbCrLf & vbCrLf & _
                "メッセージ: " & _
                objLatestEvent.TargetInstance.Message & _
                "イベントコード: " & _
                objLatestEvent.TargetInstance.EventCode, _
                vbYes + vbError,"Error")
  End If
Loop
このスクリプトを拡張子.vbsで適当な場所に保存し、
%windir%\system32\cscript.exe <scriptfile>
(<scriptfile>は保存したスクリプトのフルパス名)という内容のコマンドラインをスタートアップで最小化状態で起動しておけば、yarai2000が異常を検知したときにエラーダイアログを表示して知らせてくれます。

元ねたはMicrosoft | TechnetHey, Scripting Guy! イベント ログで特定のイベントの発生を監視する方法はありますかHey, Scripting Guy! イベント ログ メッセージに特定の単語が含まれるかどうかを監視する方法はありますかスクリプトとは何ですか | スクリプト センターあたり。

2010年10月12日

Delphiのインラインアセンブラ解説

Ernesto De SpiritoさんによるDelphiのインラインアセンブラに関する解説。興味深い。とりあえずメモ。

Inline Assembler in Delphi
将来のMacOS XやLinux、x86以外のCPU(x64、ARM...)のサポートを考えれば、インラインアセンブラは使わない方向に向かうのでしょうが。

2010年10月8日

FastMM 4.97リリース

忘れかけていましたが、FastMMのVersion 4.97がリリースされています。

元ねたは公式フォーラムのThread: FastMM 4.96 available。なにやらマルチスレッド環境下のLockの問題で揉めているようですが…。

2010年10月5日

Delphiのメモリマネージャ(その2)

以前のアーティクルで標準メモリマネージャ、FastMM中村さんのNkMMの3種類のメモリマネージャについて触れましたが、これ以外に2種類のメモリマネージャを見つけました。

TopsoftwareのIvo TopsさんによるTopMemoryManager(最新版はv3.55)は、標準メモリマネージャやFastMMに比べて特にマルチプロセッサ、マルチスレッド環境下でのパフォーマンスが優れているとのことです。ドキュメントによれば特にライセンス条件はなく、自由に使用して構わないようです。

一方でIntelのTBB(Threading Building Blocks)を使用したZach SawさんによるTBBMM(最新版は09-09-2010)というものもあります。こちらはBorlndMM.dllを置き換えてTBBを呼び出すようにするようです。TBBのライセンスは"GPL v2 with Run-time Exception"となっていて、商用製品にも組み込み可能なようです。XLsoftのIntel TBBの"お知らせ"のFAQの項にある
TBB ライブラリーのオープンソースは GNU Runtime Exception (GNU GPLv2) を採用しています。そのため、TBB ライブラリーのソースコードに何も変更を加えていない場合はソースコード開示義務は発生しないとインテル社では考えております。最終的には御社法務ご担当者のご判断に基づきます。
という表現からも特に問題にはならないと思われます。これ以外のTBBMM.dllとBorlandMM.dllは自由に配布してよい、となっています。

元ねたは公式フォーラムのThread: FastMM 4.96 available

2010年10月4日

Firebird 2.5リリース

長い間登場が待ち望まれていたFirebird Ver2.5が(ついに)リリースされています。

Firebird File Repositories(download)
Firebird 2.5 Release Notes

また2010/10/05 01:00(JST)からFirebird Foundation代表のPhilippe MakowskiさんとリードデベロッパのDmitry YemanovさんによるLaunch Webinarが行われます。

2010年10月1日

2010/10開催のウェブセミナー

2010/10/04 21:00-2010/10/05 09:45(JST) CodeRage 5 Day 1
2010/10/05 21:00-2010/10/06 09:45(JST) CodeRage 5 Day 2
2010/10/06 21:00-2010/10/07 09:45(JST) CodeRage 5 Day 3
2010/10/07 21:00-2010/10/08 09:45(JST) CodeRage 5 Day 4
2010/10/08 21:00-2010/10/09 03:45(JST) CodeRage 5 Day 5
2010/10/21 17:30-18:30(JST) 10/21 - Webセミナー「RadPHPで始めるビジュアルWebプログラミング」

CodeRage 5は英語で深夜で、となかなか厳しいですが、面白そうなセッションが結構ありますし後でセッションリプレイが見られるようになるとのことなので、可能な範囲でトライしてみましょうか。

2010年9月29日

Microsoft OOB Update 2010/09

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

2010/09/30追記: MS10-060と同様に、MS10-070の.NET Framework 1.1 SP1/2.0用の更新プログラム(ファイル名がNDP1.1sp1およびNDP20で始まるもの)はWindows 2000 SP4/XP SP2にも適用可能なようです。

2010年9月28日

LockWindowUpdateとWM_SETREDRAW

Raymond ChenさんのThe Old New ThingLockWindowUpdate (ja)(とWM_SETREDRAW)に関する興味深い一連のアーティクルがありました。
てきとうな要約:
  • LockWindowUpdateはシステム(デスクトップ)全体で1つのウィンドウしかロックできない。
  • LockWindowUpdateはドラッグ操作(アイテムのドラッグアンドドロップやウィンドウのドラッグ)でウィンドウの描画更新を止めるときに使う(本来はそのために存在している)。
  • LockWindowUpdateで描画更新を止めているウィンドウに追加的に描画を行う必要があるときはGetDCEx (ja)のflagsにDCX_LOCKWINDOWUPDATEを含めて作成したDCに描画する。
  • それ以外の状況ではLockWindowUpdateではなくWM_SETREDRAWを使用するべきである。
  • LockWindowUpdateはWindows 3.1(Win16)のリソースが限定されていた時代に作られたもので、いまどきはDirectXオーバレイ、リージョン化ウィンドウ、レイヤードウィンドウ、アルファブレンド、デスクトップコンポジションといったものがあるのだから、これらでエフェクトをかけるほうが多機能だし望ましい。

The Old New Thingは書籍(日本語訳はWindowsプログラミングの極意)にもなっていますが、MSDNのリファレンスには載っていない色々な"理由"を解説してくれる素晴らしいblogです(英語なので厳しいですが…)。

2010年9月27日

Windows 7のタスクバーの制御

Delphi 2010で追加されたWindows 7サポート機能を使用して、Windows 7のタスクバーの拡張機能であるプレビューにボタンを追加したりプログレスを表示したりする方法を説明した記事。興味深い。とりあえずメモ。

Dr.Bob Examines... #125: Fun with the Windows 7 Taskbar

またJEDI Windows APIUsing Windows 7 Taskbar-features via componentsという記事経由の情報で、theunknownones - Project Hosting on Google CodeにDelphi 2006-2009で使用できるTaskbarListComponentsというコンポーネントセットもあります(JEDI Windows APIが必要)。ただしライセンスがGNU LGPLとなっていて、Delphiのコンポーネントは実行時パッケージを使わない限り静的リンクでありLGPLv2の6a項あるいはLGPLv3の4d0項に該当する可能性が高いため、商用アプリケーションでは非常に注意が必要と考えられます(Wikipedia(ja)のLGPLの解説を参照)。

日本語の情報では第15回エンバカデロ・デベロッパーキャンプ

【B6】Delphiテクニカルセッション「Delphi 2010 で探る! Windows 7 新機能」

細川さんのプレゼンテーション資料のp.15-22も非常にわかりやすく、参考になります。またこの資料にもあるアプリケーションユーザモデルID(グループ化やジャンプリストで必要になる)についてはMSDNの

アプリケーション ユーザー モデル ID (AppID)
SetCurrentProcessExplicitAppUserModelID Function (Windows)

に説明があります。

2010/09/28追記: Daniel Wischnewskiさんによる"Windows 7 Component Library"がCode Crunching - Windows 7 Components - Betaからダウンロードできます(betaですが)。こちらはコンポーネントライブラリを作るのに使うならGPLで、アプリケーションに使うならGPL/LGPL/MPLのいずれかで、というライセンスになっています。benokさん、情報ありがとうございます。

2010年9月24日

RAD Studio XEのヘルプについて

Dee EllingさんNotes for XE Helpによれば、RAD Studio XEの(ローカル)ヘルプにはデフォルトでMicrosoft SDKヘルプが含まれないようになっているとのことです(インストール時のオプションで含めることも可能)。また最低でも2回のアップデートを予定しているそうです。

またオンラインヘルプ(docwiki)はRAD Studio XEのものが

Online Help for RAD Studio XE (ja)

に配置されているのに対して、RAD Studio 2010のものも

Online Help for RAD Studio 2010 (ja)

から見ることができるようになっています。検索もGoogleベースになっています。また"Recent changes"(MainVCLCodeSample)およびそのRSS/ATOMで更新状況を確認できます。

ところでMicrosoftはVisual Studio 2010でDocumentExplorer(hxs形式)を放棄してヘルプをwebブラウザベースに変更したようですが、RAD Studioはどうするのでしょうか?

2010年9月22日

InterBase Expressについての解説

InterBase Expressを使用しているプログラムでTIBTransactionの設定を変更しようと思い、詳細な情報をOnline Help (ja)で探してみたのですが、現在のGetting Started with InterBase Express - RAD Studio (日本語はInterBase Express の概要 - RAD Studio)には有用な情報が皆無でした。そこであちこちさまよった結果、Internet ArchiveでBorland(borland.co.jp)のころの解説を見つけました。
またこれらのページの元となったと思われるEDNのIntroduction to InterBaseExpressというアーティクルやIBPhoenixIntroduction To InterBase Express (IBX)というページも見つかりました(どちらも内容はほぼ同じだけどborland.co.jpの日本語のもののほうが詳しい)。

2010年9月21日

InterBase XE World Tour

ちょっと前にInterBaseの次期バージョンがInterBase XEになるという情報がありましたが、InterBase XE World Tourが2010/09/21(フランクフルト/ドイツ)、22(アムステルフェーン/オランダ)、29(モスクワ/ロシア)の日程で行われるようです。ここでもう少し具体的な情報が出てくるのかもしれません。

と書いた直後にInterBase XEのページがオープンになっています。新機能としては
  • Stronger password protection with SHA-1 cryptographic hash function
  • Support for Dynamic SQL in Stored Procedures
  • Support for increase buffer caches for improved performance
  • Optimized performance of large objects with Stream methods
  • Improved scalability with the ability to handle 8 times more data
  • 64-bit native binary application
  • Table-Specific Blocking Factors
  • Larger index key segment size
  • Support for larger external files
が挙げられていますが、一方で動作環境からWindows 2000(SP4)およびWindows Server 2003が削除されています。

元ねたはAndreano LanusseさんのSoftware Development, technologies and other matters #2

2010/09/24追記: InterBase XEのインストール、登録、ライセンスに関する情報とReadmeが公開されています。リリースは近いということでしょうか。

Installation, Registration, and Licensing Information for Embarcadero ® InterBase® XE
InterBase XE Readme

2010年9月17日

Windows Updateのデータストアをクリアする(Windows 2000/XP/Server 2003)

Windows Update/Microsoft Updateはデータベースやログを%windir%\SoftwareDistribution\DataStoreに保存します。このデータが極端に大きくなったり、データの不整合が発生してWindows Update/Microsoft Updateでエラーが発生することがあります。このような場合は以下の手順でDataStoreの内容をクリアする必要があります。
  1. サービスマネージャで"Automatic Update"サービスを停止する。
  2. %windir%\SoftwareDistribution\DataStoreフォルダの内容の全て削除する。
  3. サービスマネージャで"Automatic Update"サービスを開始する。

ただしDataStoreの内容をクリアすると、Windows Update/Microsoft Updateで非表示にした項目などの設定がすべてクリアされるので注意が必要です。

元ねたはWindows Update サイトで利用可能な更新を検索すると 0x80248013 エラーが表示される

2010年9月16日

フォルダのDACLを設定する

JEDI Windows Security Library(JWSCL)を使用してフォルダのセキュリティの詳細設定(随意アクセス制御リスト、Discretionary Access Control List(DACL))を設定する方法を解説した記事。興味深い。とりあえずメモ。

Setting Folder Security by JEDI Windows API

2010年9月15日

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

会場なう。受け付け開始。地下2階でもFOMAはアンテナ2本。後は電源か。

Developer Camp Live (USTREAM)でストリーミング配信されています。

午前のジェネラルセッションは終了。G1のプレゼンテーションの資料は後で配布されるのでしょうか?
ところでTrack Aのセッション資料の半分はA4なんですが…。

無事に終了しました。スピーカおよび関係者のみなさま、おつかれさまでした。

USTREAMで中継したものはdeveloper-camp-japan on USTREAMで見られます。

2010/09/21追記: セッション資料および一部のセッションのサンプルコードがダウンロードできるようになっています。

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

Microsoft Monthly Update 2010/09

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

2010年9月13日

JVCL 3.40リリース

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

Browse JEDI VCL for Delphi Files on SourceForge.net

元ねたは公式フォーラムのThread: ANN: JVCL 3.40 Released!

2010年9月12日

IDE Fix Pack 3.5/DDevExtensions 2.1リリース

Andreas HausladenさんIDE Fix Pack 2009/2010/XEがアップデートされてVersion 3.5に、DDevExtensionsもアップデートされてVersion 2.1になっています。またDDevExtensions 2.0 snapshot for Delphi 2007もリリースされています(Delphi 2007用のDDevExtensionsの正式版は1.61)。

Andy’s Blog and Tools » IDE FixPack, DDevExtension and AsyncCalls updates for 2009/2010/XE

2010年9月10日

リモートデバッガの使い方

Delphi Wikiにリモートデバッガの使い方を説明したRemote Debugger - Delphi Programmingというページがあります。忘れがちなのでメモ。

てきとうな要約:
  • ターゲットマシンではリモートデバッガを"-listen"オプション付きで実行しておく。

  • Delphi 2009 ESD版にはリモートデバッガのインストーラがないので
    • bccide.dll
    • bordbk120.dll
    • bordbk120N.dll
    • comp32x.dll
    • DCC120.dll
    • rmtdbg120.exe
    をコピーして
    regsvr32 /s bordbk120.dll
    regsvr32 /s bordbk120n.dll
    とする。

  • リモートデバッグの対象となるプロジェクト(当然デバッグビルド)のオプションのリンカオプションで"(TD32)デバッグ情報"と"リモートデバッグシンボル"を含めるようにする。

  • ターゲットマシンにリモートデバッグ対象のアプリケーションをコピーしたら、[実行]→[プロセスのロード]で"リモート"を選択して、"リモートパス"にはターゲットマシン上のプログラムのフルパスを、"リモートホスト"にはターゲットマシンのIPアドレスを、"作業ディレクトリ"にはターゲットマシン上のプログラムの配置パスを、それぞれ指定し("パラメータ"は必要に応じて)、[読み込み]ボタンをクリックするとターゲット上でプログラムがロードされて実行可能になる。

元ねたはCannot get the remote debugger for Delphi 2007 to work correctly? - Stack Overflow

2010年9月9日

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

一応スニークプレビューの最後のまとめということで。

シニアソフトウェアデベロッパのMat DeLongさんのところ。QAディレクタのChris Pattinsonさんのところ。Uwe Schusterさんのところ。Team JapanMichael Rozlogさんのところ。Twitterの某所さんのまとめ。DEKOさんのところ。Jeroen Pluimersさんのところ。Cary Jensenさんのところ。Robert Loveさんのところ。Andreas Hausladenさんのところ。Mason Wheelerさんのところ。A7Mさんのところ。Barry Kellyさんのところ。Darren Kosinskiさんのところ。Tim Del Chiaroさんのところ。Alexandru Ciobanuさんのところ。
またXE発売記念のキャンペーンをやるようです。
RAD Studio/Delphi/C++Buider 2005およびそれ以前のバージョンからは
XE Professional 特別アップグレードキャンペーン (2010/12/25まで)

RAD Studio/Delphi/C++Buider 2006およびそれ以降のバージョンからは
Delphi / C++Builder / RAD Studio XEシリーズ 早期バージョンアップ申込キャンペーン (2010/09/30まで)

2010年9月8日

Firebird 2.5がまもなくリリースへ

Firebird NewsFB 2.5 final is comingによれば、現在Firebird 2.5の最終版のリリースを準備中とのことです。

2010/10/01追記: Firebird NewsFirebird 2.5 will be released October 4, 2010によればFirebird 2.5は2010/10/04にリリースされるようです。またLaunch Webinarを2010/10/05 01:00(JST)から予定しているとのことです。

WindowsのSNP(Scalable Networking Pack)を無効にする

ITpro[Windows 7編]ネットワーク設定を標準で使ってはいけない - ITアーキテクトの「やってはいけない」:ITpro (要登録)という記事がありました。
SNP(Scalable Networking Pack)という機能がWindows Server 2003 Service Pack 2で導入されています。MicrosoftによるとSNP とは TCP に関するネットワーク処理を、ネットワーク インターフェース カード (NIC) および NIC のミニポート ドライバーを利用して最適化するためのテクノロジー及びその実装の総称です。ということですが、例によって熟成不足で、SNPを有効にしているとネットワーク関係が安定しなくなるなどの問題が生じているようです。この問題についてはMicrosoft日本法人のAsk the Network & AD Support Teamに詳しく解説されていますが、SNP の有効化により効果が期待できるような環境は、10 GbE 程度の NIC を搭載し、数 Gbps 程度の通信を頻繁に行うような環境となります。ということなので、通常の環境ではSNPを使用する必要は全くない、ということになります。ところがWindows Vista/7では標準でSNPが有効になっているため、以下のように明示的に無効化する必要があります。なおWindows 8/Server 2012ではRSSのみ既定で有効、TCP Chimney Offloadは既定で無効、NetDMAは機能削除となっています。

Windows Vista/Server 2008の場合
RSSおよびTCP Chimney Offloadを無効にするには管理者権限を持つコマンドプロンプトから
netsh int tcp set global rss=disabled
netsh int tcp set global chimney=disabled
とします。これに加えてNetDMAを無効にするためにレジストリの
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
のEnableTCPA(DWORD値)(存在しなければ作成する)の値を0に変更して再起動する必要があります。

Windows 7/Server 2008 R2の場合
RSS、TCP Chimney Offload、NetDMAを無効にするには管理者権限を持つコマンドプロンプトから
netsh int tcp set global rss=disabled
netsh int tcp set global chimney=disabled
netsh int tcp set global netdma=disabled
とします。

Windows 8/Server 2012の場合
RSS、TCP Chimney Offloadを無効にするには管理者権限を持つコマンドプロンプトから
netsh int tcp set global rss=disabled
netsh int tcp set global chimney=disabled
とします(NetDMAは機能削除されており、設定不要)。

現在の設定を確認するにはコマンドプロンプトで
netsh int tcp show global
とします。

なおWindows 7/Server 2008 R2以外でSNPをを有効にする場合は修正モジュール、修正プログラム、回避策の適用が必要ですので注意してください。

2011/07/01追記: 現在の設定の確認方法を追加しました。

2013/03/07追記: Windows 8/Server 2012に関する記述およびマイクロソフト Network & AD サポートチーム公式ブログのWindows 8/Server 2012に関する記事のリンクを追加しました。

2010年9月7日

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

2010/09/17 12:30-13:30(JST) Webセミナー - デベロッパーキャンプ・リキャップ「いよいよ登場!RAD Studio XEの新機能」
2010/09/21 17:30-18:30(JST) Webセミナー - デベロッパーキャンプ・リキャップ「いよいよ登場!RAD Studio XEの新機能」

いずれもエンバカデロ Webセミナー 参加申込フォームから申し込むことができます。

2010/09/27追記: RAD Studio XE製品デモのページから"Webセミナービデオ - デベロッパーキャンプ・リキャップ「いよいよ登場!RAD Studio XEの新機能」"を見られるようになっています(mp4形式)。

2010年9月5日

FastMM 4.96リリース

FastMMのVersion 4.96がリリースされています。いくつかの機能拡張のほかにDelphi/C++Builder XE対応も行われています。

元ねたは公式フォーラムのThread: FastMM 4.96 available

2010年9月3日

RAD Studio XEのhotfixを準備中

DEKOさんが予言をしている DEKOさんが予言をしているようですが、公式フォーラムのThread: Delphi XE memory leak?にあるように、Delphi 2009/2010/XEに
var
  i: Integer;
begin
  if i < (
end;
と")"で閉じていない"< ("があるときにメモリを食い尽くしてしまうという不具合があるようです(QC87753としてレポートされています)。 John Kasterさんによれば既にhotfixが準備されているとのことです。またAndreas Hausladenさんによる非公式なバイナリパッチ(de) (en訂正分)も公開されています。

ちなみにDelphi 2009/2010のhotfixが用意されているのかどうかはわかりませんが、必要な方は上記のスレッドでリクエストしてみたらいいと思います。

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で動作します。