16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"PopupMenuにデスクトップ項目を列挙1"
この発言に対し以下のコメントが寄せられています
#01282 Wacky さん RE:PopupMenuにデスクトップ項目を列挙1
Wacky と申します。
ポップアップメニューにデスクトップ項目を列挙するサンプルです。
すべての仮想フォルダをメニューから開くことができます。再帰処理
していますが、パスとして表現できるフォルダまでたどり着いたら、
それ以上は掘り進まないようになっています。ランチャーなどへの応
用が可能かと思います。
長いのですが全文掲載します。次の発言と合わせてユニットに貼り付
けてください。
◇動作確認
Delphi5 Professional / Windows 2000、Windows Me
◇実行
フォームに ImageList と PopupMenu を配置してください。
◇謝辞
以下の4つの関数は、Fermion さん(KHF03264@nifty.ne.jp)にご提供いただき
ました。丁寧にご指導くださった Fermion さんはじめ、FDELPHI の皆さんに
心より御礼申し上げます。
function GetNextItem( const PIDL: PItemIDList ): PItemIDList;
function GetSize( PIDL: PItemIDList ): Cardinal;
function Copy( const PIDL: PItemIDList ): PItemIDList;
function Concatenate( const PIDL1, PIDL2: PItemIDList ): PItemIDList;
//------------------------------------------------------------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Menus, ShellAPI, ShlObj, ActiveX, ComObj, ImgList, StdCtrls;
type
TForm1 = class(TForm)
ImageList1: TImageList;
PopupMenu1: TPopupMenu;
procedure GetDesktopItems(var MenuItem: TMenuItem);
procedure GetSubItems(ShellFolder: IShellFolder; itemIDList,
itemIDList_Full: PItemIDList; var SubMenuItem: TMenuItem);
procedure InsertParentFolder(var MenuItem: TMenuItem);
procedure FileExec(strFileName: String);
procedure FileExecEx(pidl: PItemIDList);
procedure OpenProperty(pPath: PChar; isFile: Boolean);
procedure PopupMenuClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
end;
var
Form1: TForm1;
IDlist: TList;
implementation
{$R *.DFM}
var
Malloc: IMalloc;
DesktopShellFolder: IShellFolder;
const
CPIDL_TERMINATOR_SIZE = SizeOf( WORD );
{*************************************************************************
PIDL 中の次の Item へのポインタを返す
・次が存在しない場合は nil を返す。
・次が存在しないという判定は mkid.cb = 0 で判断する。
//***********************************************************************}
function GetNextItem( const PIDL: PItemIDList ): PItemIDList;
var
Len: Cardinal;
begin
Result := nil;
if not Assigned( PIDL ) then Exit;
Len := PIDL^.mkid.cb;
if Len <> 0 then
Result := PItemIDList( PChar( PIDL ) + Len );
end;
{*************************************************************************
PIDL のサイズを求める
//***********************************************************************}
function GetSize( PIDL: PItemIDList ): Cardinal;
begin
Result := 0;
if not Assigned( PIDL ) then Exit;
Inc( Result, PIDL^.mkid.cb + CPIDL_TERMINATOR_SIZE );
PIDL := GetNextItem( PIDL );
while Assigned( PIDL ) do begin
Inc( Result, PIDL^.mkid.cb );
PIDL := GetNextItem( PIDL );
end;{while Assigned( PIDL ) do}
end;
{*************************************************************************
新たに PItemIDList を生成し PIDL をコピーする
//***********************************************************************}
function Copy( const PIDL: PItemIDList ): PItemIDList;
var
cb: Cardinal;
begin
Result := nil;
if not Assigned( PIDL ) then Exit;
cb := GetSize( PIDL );
Result := Malloc.Alloc( cb );
if Assigned( Result ) then
begin
FillChar( Result^, cb, 0 );
Move( PIDL^, Result^, cb );
end;
end;
{*************************************************************************
PIDL1 に PIDL2 を連結した PIDL を生成
//***********************************************************************}
function Concatenate( const PIDL1, PIDL2: PItemIDList ): PItemIDList;
var
cb1, cb2, TotalSize: Cardinal;
begin
Result := nil;
if ( not Assigned( PIDL1 )) and ( not Assigned( PIDL2 )) then Exit;
if not Assigned( PIDL1 ) then
begin
Result := Copy( PIDL2 );
Exit;
end;{if not Assigned( PIDL1 ) then}
if not Assigned( PIDL2 ) then
begin
Result := Copy( PIDL1 );
Exit;
end;{if not Assigned( PIDL2 ) then}
cb1 := GetSize( PIDL1 ) - CPIDL_TERMINATOR_SIZE;
cb2 := GetSize( PIDL2 );
TotalSize := cb1 + cb2;
Result := Malloc.Alloc( TotalSize );
if Assigned( Result ) then
begin
FillChar( Result^, TotalSize, 0 );
Move( PIDL1^, Result^, cb1 );
Move( PIDL2^, Pointer( Cardinal( Result ) + cb1 )^, cb2 );
end;{if Assigned( Result ) then}
end;
//------------------------------------------------------------------------
// デスクトップ直下のアイテムを列挙する
//------------------------------------------------------------------------
procedure TForm1.GetDesktopItems(var MenuItem: TMenuItem);
var
enumIDList: IEnumIDList;
celt: ULONG;
itemIDList: PItemIDList;
pceltFetched: ULONG;
sfi: TSHFileInfo;
Icon: TIcon;
NewMenuItem: TMenuItem;
NewImageIndex: integer;
begin
Icon := TIcon.Create;
try
// IEnumIDList インターフェースを取得
OleCheck(DesktopShellFolder.EnumObjects(Self.Handle,
SHCONTF_FOLDERS or SHCONTF_NONFOLDERS, enumIDList));
// 列挙されたそれぞれのアイテムについて
celt:= ULONG(1);
pceltFetched:= ULONG(0);
while enumIDList.Next(celt, itemIDList, pceltFetched) = NOERROR do
begin
// アイコンと表示名を取得
SHGetFileInfo(PChar(itemIDList), 0, sfi, SizeOf(TSHFileInfo),
SHGFI_PIDL or SHGFI_ICON or SHGFI_SMALLICON or SHGFI_DISPLAYNAME);
Icon.Handle := sfi.hIcon;
NewImageIndex := ImageList1.AddIcon(Icon);
// メニュー項目を作成し、アイコン・キャプション・PItemIDListを保存
NewMenuItem := TMenuItem.Create(Self);
with NewMenuItem do begin
ImageIndex := NewImageIndex;
Caption := String(sfi.szDisplayName);
Tag := IDlist.Add(itemIDList);
end;
// 下位階層のアイテムを取得
GetSubItems(DesktopShellFolder, itemIDList, itemIDList, NewMenuItem);
// 下位階層にアイテムがなければクリックイベントを設定
if NewMenuItem.Count = 0 then begin
NewMenuItem.OnClick := PopupMenuClick;
end;
MenuItem.Add(NewMenuItem);
end;
// デスクトップ自体を開くメニューを挿入
InsertParentFolder(MenuItem);
finally
Icon.ReleaseHandle;
Icon.Free;
Malloc._Release();
end;
end;
//------------------------------------------------------------------------
// サブフォルダを取得する(再帰呼び出し)
//------------------------------------------------------------------------
procedure TForm1.GetSubItems(ShellFolder: IShellFolder; itemIDList,
itemIDList_Full: PItemIDList; var SubMenuItem: TMenuItem);
var
ShellFolder_Sub: IShellFolder;
enumIDList_Sub: IEnumIDList;
itemIDList_Sub: PItemIDList;
celt: ULONG;
pceltFetched: ULONG;
sfi: TSHFileInfo;
Icon: TIcon;
NewSubMenuItem: TMenuItem;
NewSubImageIndex: Integer;
IconCaption: String;
Name: TSTRRET;
Path : array [0..MAX_PATH] of Char;
HasRealPath: Boolean;
begin
Icon := TIcon.Create;
try
// フォルダの IShellFolder を取得
if ShellFolder.BindToObject(itemIDList, nil,
IID_ISHELLFOLDER, ShellFolder_Sub) = NOERROR then
begin
// フォルダの中身を列挙する
if ShellFolder_Sub.EnumObjects(Self.Handle, SHCONTF_FOLDERS or
SHCONTF_NONFOLDERS, enumIDList_Sub) = NOERROR then
begin
// それぞれのアイテムについて
celt:= ULONG(1);
pceltFetched := ULONG(0);
while enumIDList_Sub.Next(celt,
itemIDList_Sub, pceltFetched) = NOERROR do
begin
// 表示名と
Name.uType := STRRET_CSTR;
if ShellFolder_Sub.GetDisplayNameOf(itemIDList_Sub,
SHGDN_NORMAL, Name) = NOERROR then
begin
case Name.uType of
STRRET_CSTR: IconCaption := Name.cStr;
STRRET_OFFSET: IconCaption := PChar(itemIDList_Sub) +
Name.uOffset;
STRRET_WSTR: IconCaption := Name.pOleStr;
end;
end;
// アイコンを取得
SHGetFileInfo(PChar(Concatenate(itemIDList_Full, itemIDList_Sub)),
0, sfi, SizeOf(TSHFileInfo), SHGFI_PIDL or SHGFI_ICON or
SHGFI_SMALLICON or SHGFI_DISPLAYNAME);
Icon.Handle := sfi.hIcon;
NewSubImageIndex := ImageList1.AddIcon(Icon);
// メニュー項目を作成し、アイコン・キャプション・PItemIDListを保存
NewSubMenuItem := TMenuItem.Create(Self);
with NewSubMenuItem do begin
ImageIndex := NewSubImageIndex;
Caption := IconCaption;
Tag := IDlist.Add(Concatenate(itemIDList_Full, itemIDList_Sub));
end;
// 仮想フォルダならばサブフォルダを取得
HasRealPath := SHGetPathFromIDList(
Concatenate(itemIDList_Full, itemIDList_Sub), Path);
if HasRealPath = False then
begin
GetSubItems(ShellFolder_Sub, itemIDList_Sub,
Concatenate(itemIDList_Full, itemIDList_Sub), NewSubMenuItem);
end;
// 下位階層にアイテムがなければクリックイベントを設定
if NewSubMenuItem.Count = 0 then begin
NewSubMenuItem.OnClick := PopupMenuClick;
end;
SubMenuItem.Add(NewSubMenuItem);
end;
end;
// フォルダの中身があったら、フォルダ自体を開くメニューを挿入
if SubMenuItem.Count > 0 then begin
InsertParentFolder(SubMenuItem);
end;
end;
finally
Icon.ReleaseHandle;
Icon.Free;
end;
end;
Original document by Wacky 氏 ID:(HQL05475)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|