问题描述
在 Windows 10 中的 Delphi 10.4.2 win-32 VCL 应用程序中,我使用此代码在 Windows 文件资源管理器中显示目录的内容并传递路径,例如C:\MyDirectory\
:
procedure ShellOpen(const Url: string; const Params: string = '');
begin
Winapi.ShellAPI.ShellExecute(0,'Open',PChar(Url),PChar(Params),nil,SW_SHOWnorMAL);
end;
这有效。但是如何强制资源管理器使用 THUMBNAILS 显示此目录中的文件?我可以在此过程中使用任何参数吗?
我为此搜索了很多,但没有找到任何东西。
解决方法
您想使用 IFolderView::SetCurrentViewMode 方法。
这是一个 C++(使用 Visual Studio 的 ATL)示例:
int main()
{
CoInitialize(NULL);
{
// get a shell item
CComPtr<IShellItem> folder;
ATLASSERT(SUCCEEDED(SHCreateItemFromParsingName(L"c:\\myPath1\myPath2",nullptr,IID_PPV_ARGS(&folder))));
// get its PIDL
CComHeapPtr<ITEMIDLIST> pidl;
ATLASSERT(SUCCEEDED(CComQIPtr<IPersistIDList>(folder)->GetIDList(&pidl)));
// open the item
SHELLEXECUTEINFO info = { };
info.cbSize = sizeof(info);
info.fMask = SEE_MASK_IDLIST;
info.nShow = SW_SHOW;
info.lpIDList = pidl;
ATLASSERT(ShellExecuteEx(&info));
// build a variant from the PIDL
UINT size = ILGetSize(pidl);
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI1,size);
CopyMemory(psa->pvData,pidl,size);
CComVariant v;
v.parray = psa;
v.vt = VT_ARRAY | VT_UI1;
// find the opened window
CComPtr<IShellWindows> windows;
ATLASSERT(SUCCEEDED(windows.CoCreateInstance(CLSID_ShellWindows)));
CComVariant empty;
long hwnd;
CComPtr<IDispatch> disp;
do
{
windows->FindWindowSW(&v,&empty,SWC_BROWSER,&hwnd,SWFO_NEEDDISPATCH,&disp);
if (disp)
break;
// we sleep for a while but using events would be better
// see https://stackoverflow.com/a/59974072/403671
Sleep(500);
} while (true);
// get IFolderView
CComPtr<IFolderView> view;
ATLASSERT(SUCCEEDED(IUnknown_QueryService(disp,IID_IFolderView,IID_PPV_ARGS(&view))));
// change view mode
ATLASSERT(SUCCEEDED(view->SetCurrentViewMode(FOLDERVIEWMODE::FVM_THUMBNAIL)));
}
CoUninitialize();
return 0;
}
,
不,EXPLORER.EXE 没有这方面的参数 - 它 neither had one in Windows 7,nor does it have one in Windows 10。无论如何,可用的参数很少。
您最好的选择是通过 CreateProcessW()
到 obtain the handle of its main thread and finally find the new window 启动 Explorer。然后您可以操作单个控件,例如文件列表。请参阅基于 this answer 的 AutoIt: Automating Windows Explorer - 它基本上使用 IShellBrowser
和(除了 Windows XP)IFolderView2.SetViewModeAndIconSize()
然后应用 FVM_THUMBNAIL
。
这是 approach 给出的 Simon Mourier 的 Delphi 版本:
uses
ComObj,ShellAPI,ShlObj,ActiveX,SHDocVw,ShLwApi;
function IUnknown_QueryService(punk: IUnknown; const guidService: TGUID;
const IID: TGUID; out Obj): HRESULT; stdcall; external 'ShLwApi'
name 'IUnknown_QueryService';
type
TFolderViewMode = (fvmAuto,fvmIcon,fvmSmallIcon,fvmList,fvmDetails,fvmThumbnail,fvmTile,fvmThumbstrip,fvmContent);
procedure OpenFolder(AHandle: HWND; const AFolder: string; AViewMode: TFolderViewMode);
const
FolderViewModes: array[TFolderViewMode] of Cardinal =
(Cardinal(FVM_AUTO),FVM_ICON,FVM_SMALLICON,FVM_LIST,FVM_DETAILS,FVM_THUMBNAIL,FVM_TILE,FVM_THUMBSTRIP,FVM_CONTENT);
var
ShellItem: IShellItem;
PIDL: PItemIDList;
SEInfo: TShellExecuteInfo;
ILSize: Cardinal;
SafeArray: PSafeArray;
v: OleVariant;
ShellWindows: IShellWindows;
ExplorerHWND: Integer;
disp: IDispatch;
view: IFolderView;
dummy: OleVariant;
begin
OleCheck(CoInitialize(nil));
try
OleCheck(SHCreateItemFromParsingName(PChar(AFolder),nil,IShellItem,ShellItem));
try
OleCheck((ShellItem as IPersistIDList).GetIDList(PIDL));
try
ZeroMemory(@SEInfo,SizeOf(SEInfo));
SEInfo.cbSize := SizeOf(SEInfo);
SEInfo.Wnd := AHandle;
SEInfo.fMask := SEE_MASK_IDLIST;
SEInfo.nShow := SW_SHOW;
SEInfo.lpIDList := PIDL;
Win32Check(ShellExecuteEx(@SEInfo));
ILSize := ILGetSize(PIDL);
SafeArray := SafeArrayCreateVector(VT_UI1,ILSize);
CopyMemory(SafeArray.pvData,PIDL,ILSize);
PVariantArg(@v).vt := VT_ARRAY or VT_UI1;
PVariantArg(@v).parray := SafeArray;
OleCheck(CoCreateInstance(CLASS_ShellWindows,CLSCTX_LOCAL_SERVER,IShellWindows,ShellWindows));
try
dummy := Unassigned;
var c: Integer := 0;
repeat
if c > 0 then
Sleep(200);
disp := ShellWindows.FindWindowSW(v,dummy,ExplorerHWND,SWFO_NEEDDISPATCH);
Inc(c);
until Assigned(disp) or (c > 15);
if disp = nil then
Exit;
OleCheck(IUnknown_QueryService(disp,IFolderView,view));
try
OleCheck(view.SetCurrentViewMode(FolderViewModes[AViewMode]));
finally
view := nil;
end;
finally
ShellWindows := nil;
end;
finally
CoTaskMemFree(PIDL);
end;
finally
ShellItem := nil;
end;
finally
CoUninitialize;
end;
end;
我没有无限期地对窗口进行睡眠轮询(并可能杀死应用程序!),而是在 3 秒后放弃。
示例用法:
procedure TForm1.Button1Click(Sender: TObject);
begin
OpenFolder(Handle,'C:\Users\Andreas Rejbrand\Skrivbord\Test',fvmThumbnail);
end;
视图模式,
type
TFolderViewMode = (fvmAuto,fvmContent);
直接映射到 Windows 的 FOLDERVIEWMODE
s。请注意,您的 Windows 版本可能不支持所有这些。