Delphi Programming / Object Pascal

[掲載 2016年07月25日] [更新 2016年08月20日] Delphi サンプルプログラム集 |
| 461_特殊フォルダ等をエクスプローラで表示するシェルコマンド |
| 動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro, Delphi XE5(UP2) Pro |
 |
461_Shell_command.zip [5,248 KB] 2016年08月21日版 (EXE 同梱) |
| 01_特殊フォルダ等をエクスプローラで表示するシェルコマンド |
|
主に、エクスプローラで仮想フォルダ等の特殊フォルダを表示するために使用する Shell コマンドのサンプルプログラムです。
このコマンドは、Shell:XXX という形式となっています。これらはレジストリの以下の場所に情報があります。本サンプルは、この値をレジストリから取得してリスト表示します。
|
| HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions |
[備考 1]
64 ビット版の Windows には 64 ビット専用のコマンドがあります。32 ビットの EXE からは、それらのコマンドが実行できない場合があります。 |
[備考 2]
特殊フォルダを定義した環境変数を、エクスプローラのアドレスバーに入力すると、その特殊フォルダを表示できます。例えば %APPDATA% を入力すると、C:\Users\<ユーザー名>\AppData\Roaming のフォルダを表示します。
環境変数は [ファイル名を指定して実行] のダイアログのコマンドとしても実行できます。[ファイル名を指定して実行] のダイアログで表示すると、別のエクスプローラで表示されます。 |
 |
図1
設計時画面
- Edit1 は選択中のコマンド表示用
- このコマンドは [ファイル名を指定して実行] のダイアログで実行できる
|
 |
図2
シェルコマンドリストの取得結果
- [Buttn1] クリックで列挙
- 選択項目のダブルクリックまたは [Enter] で表示
- 筆者の環境では 104 項目を取得
- 64 ビットの EXE を実行すると 106 項目
- 定義はあるが、自システムには設定されていない機能もある
|
Shell:XXX 形式のコマンドには、コントロールパネル関係を表示するコマンドがあります。
下図はその例です。 |
 |
図3
shell:ControlPanelFolder
|
 |
図4
shell:SyncCenterFolder
- [同期センター] ダイアログ
- 64 ビット Windows では、32 ビットの EXE からは表示不可
|
リスト1
シェルコマンドで特殊フォルダ等をエクスプローラで表示 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
Label1: TLabel;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Registry,
ShellAPI;
{$R *.DFM}
//=============================================================================
// レジストリからShellコマンドのリストを取得
// usesにRegistryが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LRegistry : TRegistry;
LRegKey : string;
LRegItem : string;
LItemList : TStringList;
i : Integer;
begin
Edit1.Text := '';
LItemList := TStringList.Create;
LRegistry := TRegistry.Create;
LRegistry.Access := KEY_READ;
LRegistry.RootKey := HKEY_LOCAL_MACHINE;
LRegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions';
try
//FolderDescriptions階層下のキー名(GUID)を列挙
if LRegistry.OpenKey(LRegKey, False) then begin
LRegistry.GetKeyNames(LItemList);
end;
LRegistry.CloseKey;
//列挙したキーのName項目の値を取得してTListBoxに追加
ListBox1.Sorted := True;
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
for i := 0 to LItemList.Count - 1 do begin
try
if LRegistry.OpenKey(LRegKey + PathDelim + LItemList[i], False) then begin
if not LRegistry.ValueExists('Name') then Continue;
LRegItem := LRegistry.ReadString('Name');
if LRegItem <> '' then begin
ListBox1.Items.Add('shell:' + LRegItem);
end;
end;
finally
LRegistry.CloseKey;
end;
end;
ListBox1.Items.EndUpdate;
Label1.Caption := IntToStr(ListBox1.Items.Count);
finally
FreeAndNil(LRegistry);
FreeAndNil(LItemList);
end;
end;
//=============================================================================
// ListBox1のOnDblClickイベント処理
// TListBoxの選択中のShellコマンドを実行
//
// 64ビットWindowsでの実行
// 32ビットのEXEでは、コントロールパネル関係の一部のダイアログは表示できない
// 64ビットのEXEを作成して実行すれば表示可能
//
// usesにShellAPIが必要
//=============================================================================
procedure TForm1.ListBox1DblClick(Sender: TObject);
var
LShellCmd : string;
LRetCode : Cardinal;
begin
if ListBox1.ItemIndex < 0 then exit;
LShellCmd := ListBox1.Items[ListBox1.ItemIndex];
LRetCode := ShellExecute(Handle, '', PChar(LShellCmd), nil, nil, SW_SHOW);
if LRetCode <= 32 then begin
MessageBox(Handle, PChar(SysErrorMessage(LRetCode)), '情報', MB_OK);
end;
end;
//=============================================================================
// ListBox1のOnClickイベント処理
// Edit1にコマンド文字列を表示する(コピー用)
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
begin
if ListBox1.ItemIndex < 0 then exit;
Edit1.Text := ListBox1.Items[ListBox1.ItemIndex];
end;
//=============================================================================
// ListBox1のOnKeyDownイベント処理
//=============================================================================
procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if ListBox1.ItemIndex < 0 then exit;
if Key = VK_RETURN then begin
ListBox1DblClick(nil);
Key := 0;
end;
end;
end.
| 02_Shell コマンドが表示するフォルダのフルパスの値 |
Shell:XXX に該当するフォルダのフルパスは、Shell:XXX の項目識別子を取得すれば、その項目識別子をパス名に変換することで取得できます。そのサンプルです。
コントロールパネル関係と仮想フォルダは GUID 等を含む文字列となります。システムに実装されていない機能は空文字となります。
取得したパス名または GUID 文字列をコマンドとして実行して、エクスプローラで表示したり、コントロールパネル関係のダイアログを表示します。 |
 |
図5
Shell コマンドのフルパス |
リスト2
シェルコマンドが表示するフォルダのフルパスを取得 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Buttons;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
Label1: TLabel;
Edit1: TEdit;
SpeedButton1: TSpeedButton;
procedure Button1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure SpeedButton1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Registry,
ShellAPI,
ShlObj,
ActiveX;
{$R *.DFM}
//=============================================================================
// フォーム破棄時の処理
// ListBox1のオブジェクトを破棄
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
var
i : Integer;
begin
for i := 0 to ListBox1.Items.Count-1 do begin
Dispose(PString(ListBox1.Items.Objects[i]));
end;
end;
//=============================================================================
// レジストリからShellコマンドのリストを取得
// usesにRegistryが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
//---------------------------------------------------------------------------
// ListBox1に文字列と実行用のParsingName名をセット
//---------------------------------------------------------------------------
procedure AddItem(ACaption, APath: String);
var
pAddStr : PString;
begin
New(pAddStr);
pAddStr^ := APath;
ListBox1.AddItem(ACaption, TObject(pAddStr));
end;
//-----------------------------------------------------------------------------
var
LRegistry : TRegistry;
LRegKey : string;
LRegItemName : string;
LRegItemPars : string;
LItemList : TStringList;
i : Integer;
begin
Edit1.Text := '';
LItemList := TStringList.Create;
LRegistry := TRegistry.Create;
LRegistry.Access := KEY_READ;
LRegistry.RootKey := HKEY_LOCAL_MACHINE;
LRegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions';
try
//FolderDescriptions階層下のキー名(GUID)を列挙
if LRegistry.OpenKey(LRegKey, False) then begin
LRegistry.GetKeyNames(LItemList);
end;
LRegistry.CloseKey;
//列挙したキーのName項目の値を取得してTListBoxに追加
ListBox1.Sorted := True;
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
for i := 0 to LItemList.Count - 1 do begin
try
if LRegistry.OpenKey(LRegKey + PathDelim + LItemList[i], False) then begin
if not LRegistry.ValueExists('Name') then Continue;
LRegItemName := LRegistry.ReadString('Name');
if not LRegistry.ValueExists('ParsingName') then begin
LRegItemPars := '';
end else begin
LRegItemPars := LRegistry.Readstring('ParsingName');
end;
if LRegItemName <> '' then begin
AddItem('shell:' + LRegItemName, LRegItemPars);
end;
end;
finally
LRegistry.CloseKey;
end;
end;
ListBox1.Items.EndUpdate;
Label1.Caption := IntToStr(ListBox1.Items.Count);
finally
FreeAndNil(LRegistry);
FreeAndNil(LItemList);
end;
end;
//=============================================================================
// ListBox1のOnDblClickイベント処理
//
// TListBoxの選択中のShellコマンドを実行
//
// 64ビットWindowsでの実行
// 32ビットのEXEでは、コントロールパネル関係の一部のダイアログは表示できない
// 64ビットのEXEを作成して実行すれば表示可能
//
// usesにShellAPIが必要
//=============================================================================
procedure TForm1.ListBox1DblClick(Sender: TObject);
var
LShellCmd : string;
LRetCode : Cardinal;
begin
if ListBox1.ItemIndex < 0 then exit;
if Edit1.Text <> '' then begin
LShellCmd := Edit1.Text;
end else begin
LShellCmd := ListBox1.Items[ListBox1.ItemIndex];
end;
if LShellCmd <> '' then begin
LRetCode := ShellExecute(Handle, '', PChar(LShellCmd), nil, nil, SW_SHOW);
if LRetCode <= 32 then begin
MessageBox(Handle, PChar(SysErrorMessage(LRetCode)), '情報', MB_OK);
end;
end;
end;
//-----------------------------------------------------------------------------
// 相対項目識別子からフォルダまたはファイル名を求める
// 仮想フォルダはGUID文字列として求まる
//
// 第1引数 対象の項目識別子を取得する際に使用したシェルフォルダオブジェクト
// 第2引数 対象の項目識別子。ShFolder階層下の相対値
// 第3引数 フルパスを取得する場合は、SHGDN_FORPARSING
// ファイル名だけ取得する場合は、SHGDN_NORMALまたはSHGDN_INFOLDER
//-----------------------------------------------------------------------------
function GetDispNameFromPItemID(ShFolder: IShellFolder; ItemID:
PItemIDList;Flag: DWORD=SHGDN_NORMAL): String;
var
StrRet : TStrRet;
begin
Result := '';
if ShFolder = nil then exit;
if ItemID = nil then exit;
FillChar(StrRet, SizeOf(StrRet), 0);
if NOERROR = ShFolder.GetDisplayNameOf(ItemID, Flag, StrRet) then begin
Result := StrRet.pOleStr;
end;
end;
//=============================================================================
// ListBox1のOnClickイベント処理
// Edit1にコマンド文字列の実パス名ディレクトリ名)を表示
// 仮想フォルダとコントロールパネル関係はGUID文字列となる
//
// 項目識別子から実パスを取得するSHGetPathFromIDList関数がある
// SHGetPathFromIDListは仮想フォルダ等が取得できないので自前の関数を使用
//
// usesにShlObj,Activeが必要
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
LPathBuff : array [0..MAX_PATH - 1] of Char;
LShellCmd : string;
LPItemID : PItemIDList;
LpDesktop : IShellFolder;
begin
SpeedButton1.Visible := False;
Edit1.Text := '';
if ListBox1.ItemIndex < 0 then exit;
//項目識別子を取得
LShellCmd := ListBox1.Items[ListBox1.ItemIndex];
LPItemID := ILCreateFromPath(PChar(LShellCmd));
//項目識別子からパス名を取得
if LPItemID <> nil then begin
FillChar(LPathBuff, SizeOF(LPathBuff), #0);
SHGetPathFromIDList(LPItemID, LPathBuff);
Edit1.Text := LPathBuff;
if Edit1.Text = '' then begin
//[デスクトップ]のシェルフォルダオブジェクトを取得
SHGetDesktopFolder(LpDesktop);
//デスクトップフォルダオブジェクトの項目識別子としてパス名を取得
Edit1.Text := GetDispNameFromPItemID(LpDesktop, LPItemID, SHGDN_FORPARSING);
end;
CoTaskMemFree(LPItemID);
end;
if Edit1.Text = '' then begin
Edit1.Text := PString(ListBox1.Items.Objects[ListBox1.ItemIndex])^;
end;
SpeedButton1.Visible := Edit1.Text <> '';
end;
//=============================================================================
// ListBox1のOnKeyDownイベント処理
//=============================================================================
procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if ListBox1.ItemIndex < 0 then exit;
if Key = VK_RETURN then begin
ListBox1DblClick(nil);
Key := 0;
end;
end;
end.
|
上のコードで取得したパス名は英語表記になっています。取得した Edit1.Text の値に対して次のコードを実行すると、エクスプローラでの表示名を取得できます。
最初の図は、C:\Users\Public\Desktop のバスを分解して表示しています。この順番にエクスプローラを展開していけば shell:Common Desktop が表示する場所を表示できます。
2 番目の図は
shell:AppUpdatesFolder
の場合です。これはコントロールパネル関係です。コントロールパネルから順番に操作していくと、このシェルコマンドが表示するダイアログが表示できます。
[すべてのコントロールパネル項目] というのは、コントロールパネルの [表示方法] を [カテゴリ] 以外にすることを意味します。
|
 |
図6
フォルダの場合 |
 |
図7
コントロールパネル関係の場合 |
shell:XXX コマンドと同じく、本サンプルで取得したコマンドも [ファイル名を指定して実行] のダイアログでも実行できます。
また、エクスプローラやコマンドプロンプトでも実行できますが、以下のように、コマンドの先頭に shell: あるいは explorer.exe が必要です。
エクスプローラから実行する場合、explorer.exe があると、新規にエクスプローラを起動して表示します。explorer.exe がない場合は、現在のエクスプローラで表示します。コマンドプロンプトから実行するには explorer.exe が必要です。 |
shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0
explorer.exe shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0
explorer.exe ::{26EE0668-A00A-44D7-9371-BEB064C98683}\0 |
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
LpDesktop : IShellFolder;
LStringList : TStringList;
LPItemID : PItemIDList;
LText : string;
LPathText : string;
i : Integer;
begin
if Edit1.Text = '' then exit;
SHGetDesktopFolder(LpDesktop);
LStringList := TStringList.Create;
try
LStringList.Delimiter := PathDelim;
LStringList.StrictDelimiter := True;
LStringList.DelimitedText := Edit1.Text;
LText := '';
LPathText := '';
for i := 0 to LStringList.Count - 1 do begin
LText := LText + LStringList[i];
LPItemID := ILCreateFromPath(PChar(LText));
if i = 0 then begin
LPathText := GetDispNameFromPItemID(LpDesktop, LPItemID, SHGDN_NORMAL);
end else begin
LPathText := LPathText + sLineBreak
+ GetDispNameFromPItemID(LpDesktop, LPItemID, SHGDN_NORMAL);
end;
if i < LStringList.Count - 1 then begin
LText := LText + PathDelim;
end;
end;
CoTaskMemFree(LPItemID);
MessageBox(Handle, PChar(LPathText), 'パスリスト', MB_ICONINFORMATION);
finally
FreeAndNil(LStringList);
end;
end;
| 03_コントロールパネルの [ 表示方法 ] とカテゴリ別表示 |
上のサンプルでは shell:ControlPanelFolder のパス名が次のように表示されます。これはコントロールパネルですが、[大きいアイコン] または [小さいアイコン] で表示されます。どちらで表示されるかは、最後に [スタート] メニューから表示した時の設定によります。
このコマンドでコントロールパネルを表示しても、次回、[スタート] メニューからコントロールパネルを表示する時の [表示方法] は変わりません。 |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\0 |
 |
図8
すべてのコントロールパネル項目
- [大きいアイコン] または [小さいアイコン] の表示と同じ
|
 |
図9
[カテゴリ] 表示
|
上のコマンドの末尾の値を変更すると、下の表のように、表示カテゴリが変わります。
末尾が 2, 4 の時は同じ [ハードウェアとサウンド] カテゴリのパネルを表示します。 |
[備考]
control.exe でコントロールパネルを表示した場合は、最後に [スタート] メニューからコントロールパネルを表示した時の [表示方法] と同じになります。 |
表1
コントロールパネルの各カテゴリのダイアログを表示するコマンド |
| コマンド |
コントロールパネルのカテゴリ |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683} |
[表示方法]
[カテゴリ] と同じ表示 |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\0 |
すべてのコントロールパネル項目 |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\1 |
デスクトップのカスタマイズ |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\2 |
ハードウェアとサウンド |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\3 |
ネットワークとインターネット |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\4 |
ハードウェアとサウンド |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\5 |
システムとセキュリティ |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\6 |
時計、言語、および地域 |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\7 |
コンピューターの簡単操作 |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\8 |
プログラム |
| ::{26EE0668-A00A-44D7-9371-BEB064C98683}\9 |
ユーザーアカウントと家族のための安全設定 |
次のコマンドで [ローカルセキュリティポリシー] の設定画面を表示します。
その設定画面の [ユーザーの構成] [管理用テンプレート] [コントロールパネル] の [コントロール パネルを開くときは常にすべてのコントロール パネル項目を開く] を有効にすると、[スタート] メニューからコントロールパネルを表示する時に [すべてのコントロールパネル項目] となります。
上の表のコマンドは、この設定の影響は受けません。 |
| %SystemRoot%\System32\gpedit.msc |
|
[表示方法] の [大きいアイコン] と [小さいアイコン] の設定はレジストリに記録されています。
次のコードはレジストリを操作して、この設定を強制的に変更する関数です。[コントロールパネル] を表示する前に、このコードを実行すれば [大きいアイコン] または [小さいアイコン] で表示できまます。ただし、[スタート] メニューから表示する時もこの設定になります。
添付のサンプルでは、この設定も確認できるようにしています。
|
 |
図10
添付のサンプルの実行時画面 |
リスト4
コントロールパネルの [表示方法] を [大きいアイコン] または [小さいアイコン] にする
このコードの実行には uses に Registry が必要 |
//-----------------------------------------------------------------------------
// コントロールパネルの[表示方法]
// レジストの[表示方法]の[大きいアイコン]または[小さいアイコン]の設定
//
// AValue = -1 の時は現在の設定値の読み出し
// AValue = 0 の時は大きいアイコン
// AValue = 1 の時は小さいアイコン
//
// 戻り値は現在の設定値
// 対象の項目がない場合は-1を返す
// 書き込みに失敗した場合も-1を返す
//-----------------------------------------------------------------------------
function TForm1.IconReadWriteValue_Registry(AValue: Integer): Integer;
var
LRegistry : TRegistry;
LRegKey : String;
LRegistryItem : string;
begin
Result := -1;
LRegistryItem := 'AllItemsIconView';
LRegistry := TRegistry.Create;
try
LRegistry.Access := KEY_WRITE or KEY_READ;
LRegistry.RootKey := HKEY_CURRENT_USER;
LRegKey := 'Software\Microsoft\Windows\CurrentVersion\Explorer\'
+ 'ControlPanel';
if LRegistry.OpenKey(LRegKey, False) then begin
try
try
Result := LRegistry.ReadInteger(LRegistryItem);
if (Result >= 0) and (AValue >= 0) then begin
LRegistry.WriteInteger(LRegistryItem, AValue);
end;
except
Result := -1;
end;
finally
LRegistry.CloseKey;
end;
end;
finally
FreeAndNil(LRegistry);
end;
end;
| 04_コントロールパネルやシステムダイアログ関係の CLSID 値一覧 |
|
上のサンプルで CLSID (GUID) の文字列でコントロールパネルを表示する説明をしました。
Windows で扱うオブジェクトには CLSID (GUID) が割り当てられています。それらは CLSID 値がキー名になってレジストリに記録されています。本サンプルはそれらのキーの内、InfoTip という項目名を持つキーだけを取得して列挙します。
TListBox に一覧表示しているのはキー名である CLSID の値の先頭に Shell: を追加して、コマンドとして実行可能とした文字列です。これらのキーの InfoTip 項目の値はダイアログの説明文を格納している DLL のパス名です。その DLL から文字列リソースを取り出して表示しています。
下図の表示例は、以下のコマンドを実行した結果です。
|
| shell:::{ED7BA470-8E54-465E-825C-99712043E01C} |
 |
図11
システム関係ダイアログを表示するための CLSID 値一覧
- 筆者の Windows 7 には 6813 の CLSID 値が登録されている
|
 |
図12
表示例 - すべてのタスク
|
リスト5
コントロールパネルやシステムダイアログ関係の CLSID (GUID) 値一覧 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
Label1: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
function SHLoadIndirectString(pszSource, psuOutBuf: PWideChar; const ccOutBuf:
UINT; var ppvReserved: Pointer): HRESULT; stdcall; external 'ShLwApi.dll';
var
Form1: TForm1;
implementation
uses
Registry,
ShellAPI;
{$R *.DFM}
//=============================================================================
// フォーム破棄時の処理
// ListBox1のオブジェクトを破棄
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
var
i : Integer;
begin
for i := 0 to ListBox1.Items.Count-1 do begin
Dispose(PString(ListBox1.Items.Objects[i]));
end;
end;
//-----------------------------------------------------------------------------
// レジストリの項目に以下のようなリソースのデータの記述がある
// @%SystemRoot%\system32\shell32.dll,-31361
// この値を元にしてDLLから文字列リソースを取り出す
// 取得できなかった場合は空文字を返す
//-----------------------------------------------------------------------------
function ReadStrResourceFromRegItemValue(ARegItem: string): string;
var
LBuffer : array [0..4095] of WideChar;
LPointer : Pointer;
begin
Result := '';
FillChar(LBuffer[0], SizeOf(LBuffer), #0);
if SHLoadIndirectString(PWideChar(ARegItem),
LBuffer,
Length(Lbuffer),
LPointer) = S_OK then begin
Result := Lbuffer;
end;
end;
//=============================================================================
// コントロールパネル関係とシステム関係ダイアログ関係のCLSID(GUID)値を取得
// ダイアログの説明文はDLLのリソースから取得
//
// usesにRegistry,HTTPAppが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
//---------------------------------------------------------------------------
// ListBox1の項目とObjectsプロパティに値をセット
//---------------------------------------------------------------------------
procedure AddItem(ACaption, APath: String);
var
pAddStr : PString;
begin
New(pAddStr);
pAddStr^ := APath;
ListBox1.AddItem(ACaption, TObject(pAddStr));
end;
//---------------------------------------------------------------------------
var
LRegistry : TRegistry;
LRegKey : string;
LRegItem : string;
LItemList : TStringList;
i : Integer;
begin
Edit1.Text := '';
Edit2.Text := '';
Edit3.Text := '';
Edit1.Update;
Edit2.Update;
Edit3.Update;
LItemList := TStringList.Create;
LRegistry := TRegistry.Create;
LRegistry.Access := KEY_READ;
LRegistry.RootKey := HKEY_LOCAL_MACHINE;
LRegKey := 'SOFTWARE\Classes\CLSID';
try
//CLSIDの値を列挙
if LRegistry.OpenKey(LRegKey, False) then begin
LRegistry.GetKeyNames(LItemList);
end;
LRegistry.CloseKey;
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
for i := 0 to LItemList.Count - 1 do begin
try
if LRegistry.OpenKey(LRegKey + PathDelim + LItemList[i], False) then begin
if not LRegistry.ValueExists('InfoTip') then Continue;
LRegItem := LRegistry.ReadString('InfoTip');
//レジストリのデータから文字列リソースを取得
LRegItem := ReadStrResourceFromRegItemValue(LRegItem);
if LRegItem <> '' then begin
AddItem('shell:::' + LItemList[i], LRegItem);
end;
end;
finally
LRegistry.CloseKey;
end;
end;
ListBox1.Items.EndUpdate;
Label1.Caption := IntToStr(ListBox1.Items.Count);
finally
FreeAndNil(LRegistry);
FreeAndNil(LItemList);
end;
end;
//=============================================================================
// ListBox1のOnDblClickイベント処理
// TListBoxの選択中のShellコマンドを実行
//
// 64ビットWindowsでの実行
// 32ビットのEXEでは、コントロールパネル関係の一部のダイアログは表示できない
// 64ビットのEXEを作成して実行すれば表示可能
//
// usesにShellAPIが必要
//=============================================================================
procedure TForm1.ListBox1DblClick(Sender: TObject);
var
LShellCmd : string;
LRetCode : Cardinal;
begin
if ListBox1.ItemIndex < 0 then exit;
LShellCmd := ListBox1.Items[ListBox1.ItemIndex];
LRetCode := ShellExecute(Handle, '', PChar(LShellCmd), nil, nil, SW_SHOW);
if LRetCode <= 32 then begin
MessageBox(Handle, PChar(SysErrorMessage(LRetCode)), '情報', MB_OK);
end;
end;
//=============================================================================
// ListBox1のOnClickイベント処理
// Edit1にコマンド文字列を表示する
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
LItemText : string;
LRegistry : TRegistry;
LRegKey : string;
LRegItem : string;
begin
if ListBox1.ItemIndex < 0 then exit;
LItemText := ListBox1.Items[ListBox1.ItemIndex];
Edit1.Text := LItemText;
Edit3.Text := PString(ListBox1.Items.Objects[ListBox1.ItemIndex])^;
//参考としてLocalizedStringの値を取得して表示
LRegistry := TRegistry.Create;
LRegistry.Access := KEY_READ;
LRegistry.RootKey := HKEY_LOCAL_MACHINE;
LItemText := StringReplace(LItemText, 'shell:::', '', []);
LRegKey := 'SOFTWARE\Classes\CLSID' + PathDelim + LItemText;
try
if LRegistry.OpenKey(LRegKey, False) then begin
if LRegistry.ValueExists('LocalizedString') then begin
LRegItem := LRegistry.ReadString('LocalizedString');
//レジストリのデータから文字列リソースを取得
LRegItem := ReadStrResourceFromRegItemValue(LRegItem);
if LRegItem <> '' then begin
Edit2.Text := LRegItem;
end;
end;
LRegistry.CloseKey;
end;
finally
FreeAndNil(LRegistry);
end;
end;
//=============================================================================
// ListBox1のOnKeyDownイベント処理
//=============================================================================
procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if ListBox1.ItemIndex < 0 then exit;
if Key = VK_RETURN then begin
ListBox1DblClick(nil);
Key := 0;
end;
end;
end.
|