Windows Vista対応アプリを作る

・ イントロダクション
  ま ずは概要を知る必要があります。「Windows Vista デベロッパ ストーリー: アプリケーション互換性解説書」をナナメ読みして下さい。

  詳 細情報が幾つかCodeGearに載せられています。

  なお、上記記事中にあるTaskDialogのアイコン指定用引数に指定すべき定数の値が間違っています。本来はIconはPWideCharで、「MakeIntResource(C++ではマクロ)」を使っ て指定しなくてはなりません。以下の定数を用いないと、全然関係のないアイコンが表示されてしまうことでしょう。

TD_ICON_BLANK          = 32512;
TD_ICON_WARNING        = 32515;
TD_ICON_QUESTION       = 32514;
TD_ICON_ERROR          = 32513;
TD_ICON_INFORMATION    = 32516;
TD_ICON_BLANK_AGAIN    = 32517;
TD_ICON_SHIELD         = 32518;

他にもあ ります。
 Vista での障害情報は"Borland Developer Network(BDN)"の"Quality Central" で探す事ができます。
ま た、このサ イトにある
も参考になると思います。とりあえずはXP対応から始 める必要があります。

 Delphi7以降であれば、メインフォームに「XPMan」をusesしてください (またはTXPManifestを貼り付けて下さい)。XP対応化を行うだけで、幾つかのコモンコントロールの機能がグレードアップされます。例えば 「TDateTimePicker」は「XPMan」をusesした時とそうでない時で挙動が異なりますし、不完全ではありますがメッセージダイアログが Vistaスタイルのものに変化します。これらの理由により、Vista対応アプリケーション作成にはDelphi7以降の開発環境を推奨します。

・致命 的な問題
 Delphi で作成したアプリケーションをVista上で動作させるにあたり、致命的な問題があります。Delphi で作成したアプリケーションをお持ちなら、それを起動し[Alt]キーを押してみましょう。単に[Alt]キーを押すだけです。この動作を行うだけで標準的なコントロールが消えてしまうの ではないかと思います。

[設計時]   [表示時]   [Alt押下時]
設計時 最初に表示された 時はいいのですが... Altキーを押す と消えてしまいます(ToT)

 Delphi7またはそれ以降であれば、「Fix for QC report 37403」にあるコンポーネントをインストールし、メインフォームにVistaAltFixUnitをusesし、 FormCreateで "TVistaAltFix.Create(Self);"と一行記述するだけで、この問題を回避する事ができます。現在Vistaをお使いでなくて も、このコンポーネントの導入を強く推 奨します。この現象は「XPMan」をusesした時、またはマニフェストファイル(*.manifest)を利用してビジュ アルスタイルに対応している場合に発生します。

・致命 的な問題(その2)
 Delphi7でのみ確認している問題です(少なくともBDS2006/Delphi2007では発生しません)。 TScrollBoxにTLabelを幾つか貼ります。実行するとちゃんとTLabelは見えま す。TScrollBoxにさらにTEditを追加します。実行すると...ラベルが見えな くなります

[設計時]   [表示時]    [TEeit貼付時]
設計時 ラベルだけなら表 示できますが、TEditを貼ると... ラベルが消えてし まいます(ToT)

 この現象は「XPMan」をusesした時、またはマニフェストファイル(*.manifest)を利用してビ ジュ アルスタイルに対応している場合に発生し、VistaAltFixUnitでも解決できません。TCustomEditから派生したコントロールを貼ると ラベルが見えなくなってしまうようです。VistaAltFixUnitを導入しない場合、Altキーを押せば一旦描画されますが、画面の外にウィンドウ を持っていくとまたラベルが消えてしまいます。回避するには、TLabelをTStaticTextで置換するしかなさそうです。置換したら置換したでフォントの色が指定できなくなってしまう問 題が出てきますが。

・ヘ ルプシステム
 Windows95から使えていた、旧来のWinHelpは使えなくなりました(記 事)。これにより、Windows95~Vistaまで一貫して使えるHelpシステムは存在しない事になります。次にOSサポート の多いHelpシステムはHTML-Help1.0(*.chm)です。「HTML -Helpを呼び出す」を参考にして下さい。但し、chm形式のヘルプシステムですら、Vista ではサポート打ち切りの予定だったようですから、今後はプレーンなHTMLを用いてヘルプファイルを構築した方がいいのかもしれませ ん。次世代ヘルプシステムは迷走しており、とても使えるレベルではありません。HTML-Help2.0(*.HxS)はVisual Studioの一機能として実装されているフシがあり、スタンドアロンなヘルプコンパイラだけではHTML-Help2.0を使ったヘルプを利用するのは 難しいでしょう(どうも開発は継続されない模様です)。Vistaの"AP Help"に至ってはSDKすら配布が行われていませんし、その配布時期/方法等も一切未定です。

  なお、WinHelpはVista版の提供が予定されています。但し、このVista版 WinHelpをアプリケーションに同梱して配布する事は禁じられています。VistaでWinHelpが本当に動作しないかと言えばそうではなく、古い OSの%SystemRoot%にある「winhlp32.exe」をVistaで動作させる事ができます(System32に存在する winhlp32.exeはスタブです)。

 (2007/03/09追記) Vista 用winhlp32.exeがリリースされました。

・アイ コン
 Windows のデスクトップに 表示されるアイコンは32×32と相場が決まっていましたが、Vistaでは48×48が標準サイズです。旧来 のサイズのアイコンしか持っていない場合には、1.5倍に拡大されるため、キレイに表示させる事ができません。しかも、Explorerを含め、 32×32サイズのアイコンを見る機会が殆どありません。できる限りアプリケーションに48×48サイズのアイ コンを含めるようにしましょう。

 Vistaでは128×128以上のアイコンを作る事が できます。256×256なんていうものもありますが、これには要注意です。画像のフォーマットがPNGになっているからです。 128×128以上のBMP形式のアイコンを旧来のアイコンフォーマットに則った形で作成しても正しく表示されないので注意が必要で す。

 Delphi 2005/2006用なら「ResEd(http://www.theunknownones.net/)」 というリソースエディタが利用できます。これを使ってVistaアイコンを埋め込む事が可能です。

・TAnimation
 OS 側で用意されていたアニメーションAVIが利用できな くなりました。アニメーションAVIは自前で用意する必要があります。

・シェ ルフォルダ
  シェルフォルダの名称が一部変更されています。シェルフォルダは決め打ちではなくAPIから取得するようにしましょう。以下に2つの関数を用意しました (ShlObj,ActiveXをusesして使って下さい)。

// Windowsのフォルダを取得
function GetFolderPath(var Path:String;nFolder:Integer):Boolean;
var
  
Buf:PChar;
begin
  
Buf :StrAlloc(MAX_PATH);
  
try
    
ZeroMemory(Buf,MAX_PATH);
    
case nFolder of
      
0:result :(GetCurrentDirectory(MAX_PATH,Buf<0)// カレントフォルダ
      
1:result :(GetWindowsDirectory(Buf,MAX_PATH<0)// Windowsフォルダ
      
2:result :(GetSystemDirectory(Buf,MAX_PATH)  <0)// Windowsシステムフォルダ
      
3:result :(GetTempPath(MAX_PATH,Buf)         <0)// テンポラリフォルダ
    
else
      
result :False;
    
end;
    
if result then
      
Path :ExcludeTrailingPathDelimiter(StrPas(Buf));
  
finally
    
StrDispose(Buf);
  
end;
end;

// Windowsの特殊フォルダを取得
function GetSpecialFolderPath(hwndOwner:THandle;var Path:String;nFolder:Integer):Boolean;
var
  
Buf:PChar;
  
{_GetSpecialFolderPath begin}
  
function _GetSpecialFolderPath(hwndOwner:THandle;var lpszPath:PChar;nFolder:Integer;fCreate:Boolean):Boolean;
  
var
    
pidl   :PItemIDList;
    
pMalloc:IMalloc;
  
begin
    
result :False;
    
if SHGetMalloc(pMalloc<NOERROR then
      
Exit;
    
if SHGetSpecialFolderLocation(hwndOwner,nFolder,pidlNOERROR then
      
Exit;
    
if SHGetPathFromIDList(pidl,lpszPaththen
      
result :True;
    
pMalloc.Free(pidl);
  
end;
  
{_GetSpecialFolderPath end}
begin
  
result :True;
  
Buf :StrAlloc(MAX_PATH);
  
try
    
if SHGetSpecialFolderPath(hwndOwner,Buf,nFolder,Falsethen
      
Path :ExcludeTrailingPathDelimiter(StrPas(Buf))
    
else if _GetSpecialFolderPath(hwndOwner,Buf,nFolder,Falsethen
      
Path :ExcludeTrailingPathDelimiter(StrPas(Buf))
    
else
      
result :False;
  
finally
    
StrDispose(Buf);
  
end;
end;

  「GetFolderPath」は一般的な Windowsのフォルダを取得します。「GetSpecialFolderPath」 はもっと詳細なフォルダを取得します。どちらの関数も「nFolder」 に取得したいフォルダのインデックス値を入れると「Path」にフォルダパスを返します。インデックスが定義されていないか、正しくフォルダパスを取得できなかった場合には戻り値にFalseが返ります。GetFolderPath」のインデックス値については関数内のコ メントをご覧下さい。

 
GetSpecialFolderPath」 のインデックス値はCSIDL値と呼ばれるものです。CSIDL値と、それが返すフォルダについてはこ ちらをご覧下さい。また、VisualStudioやWin32用gcc、Wine等から「shlobj.h」を検索すると最新の CSIDL値を調べる事ができます。CSIDL値の"実際の値"と"それが示す実際のパス"を簡単に知りたいのであれば、このサイトにある「SHSFP」 をDLし、コマンドラインから「shsfp -v」と叩いてみて下さい。

 パスを環境設定ファイルに保存する場 合には、"環境変数文字列を含むパス"で保存しておき、読み込む際に絶対パスに変換してやるようにすると問題が少なくなると思われます。以下の関数は"環 境変数文字列を含むパス"を絶対パスに変換するものです。

function ExpandEnvironmentString(S:String):String;
var
  
n:Integer;
  
Dest:String;
begin
  
:ExpandEnvironmentStrings(PChar(S)nil0);
  
SetLength(Dest,n*2);
  
ExpandEnvironmentStrings(PChar(S),PChar(Dest),n*2);
  
SetLength(Dest,StrLen(PChar(Dest)));
  
result :Dest;
end;

  この関数は先述の特殊フォルダ取得の代わりに使う事もできます。例えばWindowsフォルダを取得したいのであれば「ExpandEnvironmentString('%SystemRoot%')」、 アプリケーションデータフォルダを取得したい場合には「ExpandEnvironmentString('%AppData%')」とすれば いい事になります。

 Vista 限定の話からは外れますが、以下に「CSIDL/環境変数/各OSでの実際のパス」を一覧表にしてみました。Windows95~Vistaまで問題なく 動作するアプリケーションを作る際の手助けになれば幸いです。古いOS(95/NT4.0等)で特殊フォルダを取得するには「最新のSPとIE4.0以上 が必要」となります。

CSIDL
環 境変数(9x) 環 境変数(NT) Windows 95 with IE5.5 SP2 Windows 98/98SE with IE6 Windows MilleniumEdition with IE6 Windows NT4.0 SP6a with IE6 Windows 2000 SP4 with IE6 Windows XP SP2 Windows Vista
CSIDL_DESKTOP 0x0000     C: \WINDOWS\デスクトップ C:\WINDOWS\デスクトップ C: \WINDOWS\デスクトップ C:\WINNT\Profiles\(USER)\デスクトップ C:\Documents and Settings\(USER)\デスクトップ C:\Documents and Settings\(USER)\デスクトップ C:\Users\(USER)\Desktop
CSIDL_PROGRAMS 0x0002     C: \WINDOWS\スタート メニュー\プログラム C:\WINDOWS\スタート メニュー\プログラム C:\WINDOWS\スタート メニュー\プログラム C: \WINNT\Profiles\(USER)\スタート メニュー\プログラム C:\Documents and Settings\(USER)\スタート メニュー\プログラム C:\Documents and Settings\(USER)\スタート メニュー\プログラム C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
CSIDL_PERSONAL 0x0005     C:\My Documents C:\My Documents C:\My Documents C:\WINNT\Profiles\(USER)\Personal C:\Documents and Settings\(USER)\My Documents C:\Documents and Settings\(USER)\My Documents C:\Users\(USER)\Documents
CSIDL_FAVORITES 0x0006     C:\WINDOWS\Favorites C:\WINDOWS\Favorites C:\WINDOWS\Favorites C:\WINNT\Profiles\(USER)\Favorites C:\Documents and Settings\(USER)\Favorites C:\Documents and Settings\(USER)\Favorites C:\Users\(USER)\Favorites
CSIDL_STARTUP 0x0007     C: \WINDOWS\スタート メニュー\プログラム\スタートアップ C:\WINDOWS\スタート メニュー\プログラム\スタートアップ C:\WINDOWS\スタート メニュー\プログラム\スタートアップ C:\WINNT\Profiles\(USER)\スタート メニュー\プログラム\スタートアップ C:\Documents and Settings\(USER)\スタート メニュー\プログラム\スタートアップ C:\Documents and Settings\(USER)\スタート メニュー\プログラム\スタートアップ C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_RECENT 0x0008     C:\WINDOWS\Recent C:\WINDOWS\Recent C:\WINDOWS\Recent C:\WINNT\Profiles\(USER)\Recent C:\Documents and Settings\(USER)\Recent C:\Documents and Settings\(USER)\Recent C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Recent
CSIDL_SENDTO 0x0009     C:\WINDOWS\SendTo C:\WINDOWS\SendTo C:\WINDOWS\SendTo C:\WINNT\Profiles\(USER)\SendTo C:\Documents and Settings\(USER)\SendTo C:\Documents and Settings\(USER)\SendTo C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\SendTo
CSIDL_STARTMENU 0x000B     C: \WINDOWS\スタート メニュー C:\WINDOWS\スタート メニュー C: \WINDOWS\スタート メニュー C:\WINNT\Profiles\(USER)\スタート メニュー C:\Documents and Settings\(USER)\スタート メニュー C:\Documents and Settings\(USER)\スタート メニュー C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Start Menu
CSIDL_MYMUSIC 0x000D               C:\Documents and Settings\(USER)\My Documents\My Music C:\Users\(USER)\Music
CSIDL_MYVIDEO 0x000E               C:\Documents and Settings\(USER)\My Documents\My Videos C:\Users\(USER)\Videos
CSIDL_DESKTOPDIRECTORY 0x0010     C: \WINDOWS\デスクトップ C:\WINDOWS\デスクトップ C: \WINDOWS\デスクトップ C:\WINNT\Profiles\(USER)\デスクトップ C:\Documents and Settings\(USER)\デスクトップ C:\Documents and Settings\(USER)\デスクトップ C:\Users\(USER)\Desktop
CSIDL_NETHOOD 0x0013     C:\WINDOWS\NetHood C:\WINDOWS\NetHood C:\WINDOWS\NetHood C:\WINNT\Profiles\(USER)\NetHood C:\Documents and Settings\(USER)\NetHood C:\Documents and Settings\(USER)\NetHood C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Network Shortcuts
CSIDL_FONTS 0x0014     C:\WINDOWS\FONTS C:\WINDOWS\FONTS C:\WINDOWS\Fonts C:\WINNT\Fonts C:\WINNT\Fonts C:\WINDOWS\Fonts C:\Windows\Fonts
CSIDL_TEMPLATES 0x0015     C:\WINDOWS\ShellNew C:\WINDOWS\ShellNew C:\WINDOWS\Templates C:\WINNT\ShellNew C:\Documents and Settings\(USER)\Templates C:\Documents and Settings\(USER)\Templates C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Templates
CSIDL_COMMON_STARTMENU 0x0016           C:\WINNT\Profiles\All Users\スタート メニュー C:\Documents and Settings\All Users\スタート メニュー C:\Documents and Settings\All Users\スタート メニュー C:\ProgramData\Microsoft\Windows\Start Menu
CSIDL_COMMON_PROGRAMS 0x0017           C:\WINNT\Profiles\All Users\スタート メニュー\プログラム C:\Documents and Settings\All Users\スタート メニュー\プログラム C:\Documents and Settings\All Users\スタート メニュー\プログラム C:\ProgramData\Microsoft\Windows\Start Menu\Programs
CSIDL_COMMON_STARTUP 0x0018         C:\WINDOWS\All Users\スタート メニュー\プログラム\スタートアップ C:\WINNT\Profiles\All Users\スタート メニュー\プログラム\スタートアップ C:\Documents and Settings\All Users\スタート メニュー\プログラム\スタートアップ C:\Documents and Settings\All Users\スタート メニュー\プログラム\スタートアップ C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_COMMON_DESKTOPDIRECTORY 0x0019         C:\WINDOWS\All Users\デスクトップ C:\WINNT\Profiles\All Users\デスクトップ C:\Documents and Settings\All Users\デスクトップ C:\Documents and Settings\All Users\デスクトップ C:\Users\Public\Desktop
CSIDL_APPDATA 0x001A   %APPDATA% C:\WINDOWS\Application Data C:\WINDOWS\Application Data C:\WINDOWS\Application Data C:\WINNT\Profiles\(USER)\Application Data C:\Documents and Settings\(USER)\Application Data C:\Documents and Settings\(USER)\Application Data C:\Users\(USER)\AppData\Roaming
CSIDL_PRINTHOOD 0x001B       C:\WINDOWS\PrintHood C:\WINDOWS\PrintHood C:\WINNT\Profiles\(USER)\PrintHood C:\Documents and Settings\(USER)\PrintHood C:\Documents and Settings\(USER)\PrintHood C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Printer Shortcuts
CSIDL_LOCAL_APPDATA 0x001C         C:\WINDOWS\Application Data   C:\Documents and Settings\(USER)\Local Settings\Application Data C:\Documents and Settings\(USER)\Local Settings\Application Data C:\Users\(USER)\AppData\Local
CSIDL_ALTSTARTUP 0x001D                 C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_COMMON_ALTSTARTUP 0x001E                 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
CSIDL_COMMON_FAVORITES 0x001F             C:\Documents and Settings\All Users\Favorites C:\Documents and Settings\All Users\Favorites C:\Users\(USER)\Favorites
CSIDL_INTERNET_CACHE 0x0020     C:\WINDOWS\Temporary Internet Files C:\WINDOWS\Temporary Internet Files C:\WINDOWS\Temporary Internet Files C:\WINNT\Profiles\(USER)\Temporary Internet Files C:\Documents and Settings\(USER)\Local Settings\Temporary Internet Files C:\Documents and Settings\(USER)\Local Settings\Temporary Internet Files C:\Users\(USER)\AppData\Local\Microsoft\Windows\Temporary Internet Files
CSIDL_COOKIES 0x0021     C:\WINDOWS\Cookies C:\WINDOWS\Cookies C:\WINDOWS\Cookies :C:\WINNT\Profiles\(USER)\Cookies C:\Documents and Settings\(USER)\Cookies C:\Documents and Settings\(USER)\Cookies C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Cookies
CSIDL_HISTORY 0x0022     C:\WINDOWS\History C:\WINDOWS\History C:\WINDOWS\History C:\WINNT\Profiles\(USER)\History C:\Documents and Settings\(USER)\Local Settings\History C:\Documents and Settings\(USER)\Local Settings\History C:\Users\(USER)\AppData\Local\Microsoft\Windows\History
CSIDL_COMMON_APPDATA 0x0023         C:\WINDOWS\All Users\Application Data   C:\Documents and Settings\All Users\Application Data C:\Documents and Settings\All Users\Application Data C:\ProgramData
CSIDL_WINDOWS 0x0024 %WINDIR%
%WINBOOTDIR%
%SYSTEMROOT
%WINDIR%
    C:\WINDOWS   C:\WINNT C:\WINDOWS C:\Windows
CSIDL_SYSTEM 0x0025         C:\WINDOWS\SYSTEM   C:\WINNT\system32 C:\WINDOWS\system32 C:\Windows\system32
CSIDL_PROGRAM_FILES 0x0026   %PROGRAMFILES%     C:\Program Files   C:\Program Files C:\Program Files C:\Program Files
CSIDL_MYPICTURES 0x0027         C:\My Documents\My Pictures   C:\Documents and Settings\(USER)\My Documents\My Pictures C:\Documents and Settings\(USER)\My Documents\My Pictures C:\Users\(USER)\Pictures
CSIDL_PROFILE 0x0028   %USERPROFILE%
%HOMEPATH%
        C:\Documents and Settings\(USER) C:\Documents and Settings\(USER) C:\Users\(USER)
CSIDL_SYSTEMX86 0x0029         C:\WINDOWS\SYSTEM   C:\WINNT\system32 C:\WINDOWS\system32 C:\Windows\system32
CSIDL_PROGRAM_FILESX86 0x002A                 C:\Program Files
CSIDL_PROGRAM_FILES_COMMON 0x002B         C:\Program Files\Common Files   C:\Program Files\Common Files C:\Programs\Common Files C:\Program Files\Common Files
CSIDL_COMMON_TEMPLATES 0x002D             C:\Documents and Settings\All Users\Templates C:\Documents and Settings\All Users\Templates C:\ProgramData\Microsoft\Windows\Templates
CSIDL_COMMON_DOCUMENTS 0x002E         C:\WINDOWS\All Users\Documents   C:\Documents and Settings\All Users\Documents C:\Documents and Settings\All Users\Documents C:\Users\Public\Documents
CSIDL_COMMON_ADMINTOOLS 0x002F             C:\Documents and Settings\All Users\スタート メニュー\プログラム\管理ツール C:\Documents and Settings\All Users\スタート メニュー\プログラム\管理ツール C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools
CSIDL_ADMINTOOLS 0x0030               C:\Documents and Settings\(USER)\スタート メニュー\プログラム\管理ツール C:\Users\(USER)\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools
CSIDL_COMMON_MUSIC 0x0035               C:\Documents and Settings\All Users\Documents\My Music C:\Users\Public\Music
CSIDL_COMMON_PICTURES 0x0036               C:\Documents and Settings\All Users\Documents\My Pictures C:\Users\Public\Pictures
CSIDL_COMMON_VIDEO 0x0037               C:\Documents and Settings\All Users\Documents\My Videos C:\Users\Public\Videos
CSIDL_RESOURCES 0x0038               C:\WINDOWS\resources C:\Windows\resources
CSIDL_CDBURN_AREA 0x003B               C:\Documents and Settings\(USER)\Local Settings\Application Data\Microsoft\CD Burning C:\Users\(USER)\AppData\Local\Microsoft\Windows\Burn\Burn

  また、Vistaでは「%ProgramFiles%」へのアクセスが制限されています。「%ProgramFiles%」へのアクセスにはUAC無効化 が必要ですので、インストールフォルダは自由に指定できるようするべきです。

・メッ セージボックス
  上で少し触れたメッセージボックスですが、以下にMessageBox()/TaskDialog()を意識せずに使えるMessageBoxNewを掲載しておきます。

function MessageBoxNew(hWnd:THandle;ATitle,ADescription,AContent:String;AType:DWORD):Integer;
label
  
OLDDLG;
const
  
TD_ICON_BLANK          32512;
  
TD_ICON_WARNING        32515;
  
TD_ICON_QUESTION       32514;
  
TD_ICON_ERROR          32513;
  
TD_ICON_INFORMATION    32516;
  
TD_ICON_BLANK_AGAIN    32517;
  
TD_ICON_SHIELD         32518;

  
TD_OK         1;
  
TD_YES        2;
  
TD_NO         4;
  
TD_CANCEL     8;
  
TD_RETRY      16;
  
TD_CLOSE      32;

  
DLGRES_OK     1;
  
DLGRES_CANCEL 2;
  
DLGRES_RETRY  4;
  
DLGRES_YES    6;
  
DLGRES_NO     7;
  
DLGRES_CLOSE  8;
var
  
DLLHandleTHandle;
  
Version:TOSVERSIONINFO;
  
Buttons:Integer;
  
ICon:Integer;
  
Dmy:String;
  
resinteger;
  
wTitle,wDescription,wContentarray[0..1024of widechar;
  
TaskDialogProcfunction(HWNDTHandlehInstanceTHandlecTitlecDescriptioncContentpwidechar;
       
ButtonsIntegerIconintegerResButtonpinteger)integercdecl stdcall;
begin
  
// OSバージョンがVista以降か?
  
Version.dwOSVersionInfoSize :SizeOf(Version);
  
if not GetVersionEx(Versionthen
    
goto OLDDLG;
if (Version.dwMajorVersion < 6) then
goto OLDDLG;
  
// comctl32.dllがロードできるか?
  
DLLHandle :LoadLibrary('comctl32.dll');
  
if DLLHandle 32 then
    
goto OLDDLG;
  
// TaskDialogが利用可能か?
  
@TaskDialogProc :GetProcAddress(DLLHandle,'TaskDialog');
  
if not Assigned(TaskDialogProcthen
    
goto OLDDLG;
  
// TaskDialogを表示
  
Buttons :0;
  
if      ((AType and MB_YESNOCANCEL     MB_YESNOCANCEL     then
    
begin
      
Buttons :Buttons or TD_YES;
      
Buttons :Buttons or TD_NO;
      
Buttons :Buttons or TD_CANCEL;
    
end
  
else if ((AType and MB_RETRYCANCEL     MB_RETRYCANCEL     then
    
begin
      
Buttons :Buttons or DLGRES_RETRY;
      
Buttons :Buttons or TD_CANCEL;
    
end
  
else if ((AType and MB_ABORTRETRYIGNOREMB_ABORTRETRYIGNOREthen
    
begin
      
Buttons :Buttons or DLGRES_CLOSE;
      
Buttons :Buttons or DLGRES_RETRY;
      
Buttons :Buttons or TD_CANCEL;
    
end
  
else if ((AType and MB_OKCANCEL        MB_OKCANCEL        then
    
begin
      
Buttons :Buttons or TD_OK;
      
Buttons :Buttons or TD_CANCEL;
    
end
  
else if ((AType and MB_YESNO           MB_YESNO           then
    
begin
      
Buttons :Buttons or TD_YES;
      
Buttons :Buttons or TD_NO;
    
end
  
else if ((AType and MB_OK              MB_OK              then
    
begin
      
Buttons :Buttons or TD_OK;
    
end;
  
if      (AType and MB_ICONERROR      MB_ICONERROR       then
    
Icon :TD_ICON_ERROR
  
else if (AType and MB_ICONQUESTION   MB_ICONQUESTION    then
    
Icon :TD_ICON_QUESTION
  
else if (AType and MB_ICONINFORMATIONMB_ICONINFORMATION then
    
Icon :TD_ICON_INFORMATION
  
else if (AType and MB_ICONEXCLAMATIONMB_ICONEXCLAMATION then
    
Icon :TD_ICON_WARNING
  
else
    
Icon :TD_ICON_BLANK;
  
StringToWideChar(ATitlewTitlesizeof(wTitle));
  
StringToWideChar(ADescriptionwDescriptionsizeof(wDescription));
  
StringToWideChar(AContentwContentsizeof(wContent));
  
TaskDialogProc(hWnd0wTitlewDescriptionwContentButtons,Icon,@res);
  
result :ID_YES;
  
case res of
    
DLGRES_CANCEL:
      
result :ID_CANCEL;
    
DLGRES_RETRY:
      
result :ID_RETRY;
    
DLGRES_YES:
      
result :ID_YES;
    
DLGRES_NO:
      
result :ID_NO;
    
DLGRES_CLOSE:
      
result :ID_ABORT;
    
end;
  
Exit;

OLDDLG:;
  
// MessageBoxを表示
  
Dmy :ADescription;
  
if AContent <'' then
    
begin
      
if Dmy <'' then
        
Dmy := Dmy + #$D#$A #$D#$A;
      
Dmy :Dmy AContent;
    
end;
  
result :MessageBox(hWnd,PChar(Dmy),PChar(ATitle),AType);
end;

 なお、TaskDialog はMessageBoxの代わりはできますが、MessageDlg()の代わりには使えません。何故なら、TaskDialog()には「すべてはい/ すべていいえ」等のボタンが用意されていないからです。MessageDlg()の代わりになるものをVistaスタイルで作るにはTaskDialogIndirect()でどうにかするしかありません。

  以下に
VistaスタイルでMessageDlg()のように使えるMessageDlgNew を掲載します。

function MessageDlgNew(AHWND:THandleconst ATitleADescriptionAContentString;
  
ADlgTypeTMsgDlgTypeAButtonsTMsgDlgButtonsAHelpCtxLongint)Integer;
label
  
OLDDLG;
const
  
// アイコン定数
  
TD_ICON_BLANK          32512;
  
TD_ICON_WARNING        32515;
  
TD_ICON_QUESTION       32514;
  
TD_ICON_ERROR          32513;
  
TD_ICON_INFORMATION    32516;
  
TD_ICON_BLANK_AGAIN    32517;
  
TD_ICON_SHIELD         32518;
  
// ボタン用定数
  
MD_Help     100;
  
// ボタン文字列用配列
  
BtnTablearray [0..10of string =
    
('はい(&Y)','いいえ(&N)','OK','キャンセル','中止(&A)','再試行(&R)',
     
'無視(&I)','すべて(&A)','すべていいえ(&O)','すべてはい(&A)','ヘルプ(&H)');
  
// 戻り値用配列
  
RetTablearray [0..10of WORD =
    
(mrYes,mrNo,mrOk,mrCancel,mrAbort,mrRetry,
     
mrIgnore,mrAll,mrNoToAll,mrYesToAll,MD_Help);
type
  
TTASKDIALOGCONFIG =
    
packed record
      
cbSize uint;
      
hwndParent HWND;
      
hInstance longword;
      
dwFlags dword;
      
dwCommonButtons dword;
      
pszWindowTitle PWideChar;
      
case integer of
        
(hMainIcon HICON);
        
(pszMainIcon Integer;
             
pszMainInstruction PWideChar;
             
pszContent PWideChar;
             
cButtons uint;
             
pButtons pointer;
             
iDefaultButton integer;
             
cRadioButtons uint;
             
pRadioButtons pointer;
             
iDefaultRadioButton integer;
             
pszVerificationText,
             
pszExpandedInformation,
             
pszExpandedControlText,
             
pszCollapsedControlText PWideChar;
             
case integer of
               
(hFooterIcon HICON);
               
(pszFooterIcon Integer;
                    
pszFooterText PWideChar;
                    
pfCallback pointer;
                    
lpCallbackData pointer;
                    
cxWidth uint;));
    
end;
  
PTASKDIALOGCONFIG ^TTASKDIALOGCONFIG;
  
TTASKDIALOG_BUTTON =
    
packed record
       
nButtonId     Integer;
       
pszButtonText PWideChar;
    
end;
  
BtnCaption array [0..31of WideChar;
var
  
Btn:WORD;
  
Dmy:String;
  
DLLHandleTHandle;
  
Version:TOSVERSIONINFO;
  
TDC:TTASKDIALOGCONFIG;
  
Buttons:array of TTASKDIALOG_BUTTON;
  
BtnCaptions:array of BtnCaption;
  
BtnCnt:Integer;
  
res:Integer;
  
i:Integer;
  
wTitle,wDescription,wContentarray[0..1024of widechar;
  
TaskDialogIndirectProcfunction(ptc PTASKDIALOGCONFIGpnButtonPInteger;
    
pnRadioButtonPIntegerpfVerificationFlagCheckedPBool)HRESULT cdecl stdcall;
begin
  
// OSバージョンがVista以降か?
  
Version.dwOSVersionInfoSize :SizeOf(Version);
  
if not GetVersionEx(Versionthen
    
goto OLDDLG;
  
if (Version.dwMajorVersion 6then
    
goto OLDDLG;
  
// comctl32.dllがロードできるか?
  
DLLHandle :LoadLibrary('comctl32.dll');
  
if DLLHandle 32 then
    
goto OLDDLG;
  
// TaskDialogIndirectが利用可能か?
  
@TaskDialogIndirectProc :GetProcAddress(DLLHandle,'TaskDialogIndirect');
  
if not Assigned(TaskDialogIndirectProcthen
    
goto OLDDLG;
  
// TaskDialogIndirectを表示
  
ZeroMemory(@TDC,SizeOf(TDC));
  
TDC.cbSize :SizeOf(TDC);
  
TDC.hwndParent :AHWND;
  
TDC.hInstance  :0;
  
StringToWideChar(ATitlewTitleSizeOf(wTitle));
  
TDC.pszWindowTitle     :wTitle;
  
StringToWideChar(ADescriptionwDescriptionSizeOf(wDescription));
  
TDC.pszMainInstruction :wDescription;
  
StringToWideChar(AContentwContentSizeOf(wContent));
  
TDC.pszContent         :wContent;
  
case ADlgType of
    
mtWarning:
      
TDC.pszMainIcon :TD_ICON_WARNING;
    
mtError:
      
TDC.pszMainIcon :TD_ICON_ERROR;
    
mtInformation:
      
TDC.pszMainIcon :TD_ICON_INFORMATION;
    
mtConfirmation:
      
TDC.pszMainIcon :TD_ICON_QUESTION;
    
mtCustom:
      
TDC.pszMainIcon :TD_ICON_BLANK;
  
end;
  
TDC.dwCommonButtons :0;
  
BtnCnt :0;
  
for i:=WORD(mbYesto WORD(mbHelpdo
    
begin
      
Btn :(shl i);
      
if (WORD(AButtonsand BtnBtn then
        
begin
          
Inc(BtnCnt);
          
SetLength(Buttons,BtnCnt);
          
SetLength(BtnCaptions,BtnCnt);
          
Buttons[BtnCnt-1].nButtonId :RetTable[i];
          
StringToWideChar(BtnTable[i],BtnCaptions[BtnCnt-1],SizeOf(BtnCaption));
          
Buttons[BtnCnt-1].pszButtonText :BtnCaptions[BtnCnt-1];
        
end;
    
end;
  
TDC.cButtons :BtnCnt;
  
TDC.pButtons :@Buttons[0];
  
TaskDialogIndirectProc(@TDC@resnilnil);
  
case res of
    
MD_Help:
      
// Helpボタン押下時の処理
  
else
    
result :res;
  
end;
  
Exit;
OLDDLG:;
  
// MessageDlgを表示
  
Dmy :ADescription;
  
if AContent <'' then
    
begin
      
if Dmy <'' then
        
Dmy :Dmy #$D#$A #$D#$A;
      
Dmy :Dmy AContent;
    
end;
  
result :MessageDlg(Dmy,ADlgType,AButtons,AHelpCtx);
end;

 上 記の関数を使う場合にはロケールによって自動的にボタン文字列が変わる事はないため、多言語化の際には注意が必要です。dwCommonButtonsに標準ボタンをセットすればいいような気がするでしょうが、それをやってしまうとボタ ンの並びがMessageDlg()と異なる事になります(実際にやってみると解ります)。

・使用 許諾登録
 "Windows Vista 上で Borland Developer Stuio 2006 および Delphi 7 の使用許諾を行うには(CodeGear)" を御覧下さい。



  以上の事をあれこれ考える位なら"Delphi2007 for Win32"を購入した方が簡単でいいかもしれません。Delphi2007ではTaskDialogもスマートにVCL化されており、Alt問題も VistaAltFixUnitのような力技ではなく、個々のVCLで最初から考慮されているので描画がスムーズです。

 BACK