我想寫以下過程/函數:如何使用Delphi彈出給定文件的Windows上下文菜單?
procedure ShowSysPopup(aFile: string; x, y: integer);
將建立並顯示(在座標x和y),其中一個人看到在Windows資源管理器中的給定文件的右鍵外殼菜單。我對「展示」部分不太感興趣,但更多的是關於如何構建這樣的菜單。
我想寫以下過程/函數:如何使用Delphi彈出給定文件的Windows上下文菜單?
procedure ShowSysPopup(aFile: string; x, y: integer);
將建立並顯示(在座標x和y),其中一個人看到在Windows資源管理器中的給定文件的右鍵外殼菜單。我對「展示」部分不太感興趣,但更多的是關於如何構建這樣的菜單。
我爲您做了一個快速解決方案。 這些單位增加了「使用」部分:
... ShlObj, ActiveX, ComObj
,這裏是你的程序,我只需要添加新的參數「HND」隨身攜帶,你會用它來顯示上下文菜單的TWinControl的手柄。
procedure ShowSysPopup(aFile: string; x, y: integer; HND: HWND);
var
Root: IShellFolder;
ShellParentFolder: IShellFolder;
chEaten,dwAttributes: ULONG;
FilePIDL,ParentFolderPIDL: PItemIDList;
CM: IContextMenu;
Menu: HMenu;
Command: LongBool;
ICM2: IContextMenu2;
ICI: TCMInvokeCommandInfo;
ICmd: integer;
P: TPoint;
Begin
OleCheck(SHGetDesktopFolder(Root));//Get the Desktop IShellFolder interface
OleCheck(Root.ParseDisplayName(HND, nil,
PWideChar(WideString(ExtractFilePath(aFile))),
chEaten, ParentFolderPIDL, dwAttributes)); // Get the PItemIDList of the parent folder
OleCheck(Root.BindToObject(ParentFolderPIDL, nil, IShellFolder,
ShellParentFolder)); // Get the IShellFolder Interface of the Parent Folder
OleCheck(ShellParentFolder.ParseDisplayName(HND, nil,
PWideChar(WideString(ExtractFileName(aFile))),
chEaten, FilePIDL, dwAttributes)); // Get the relative PItemIDList of the File
ShellParentFolder.GetUIObjectOf(HND, 1, FilePIDL, IID_IContextMenu, nil, CM); // get the IContextMenu Interace for the file
if CM = nil then Exit;
P.X := X;
P.Y := Y;
Windows.ClientToScreen(HND, P);
Menu := CreatePopupMenu;
try
CM.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE or CMF_CANRENAME);
CM.QueryInterface(IID_IContextMenu2, ICM2); //To handle submenus.
try
Command := TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or
TPM_RETURNCMD, p.X, p.Y, 0, HND, nil);
finally
ICM2 := nil;
end;
if Command then
begin
ICmd := LongInt(Command) - 1;
FillChar(ICI, SizeOf(ICI), #0);
with ICI do
begin
cbSize := SizeOf(ICI);
hWND := 0;
lpVerb := MakeIntResourceA(ICmd);
nShow := SW_SHOWNORMAL;
end;
CM.InvokeCommand(ICI);
end;
finally
DestroyMenu(Menu)
end;
End;
修改/添加初始化,定稿節這樣
initialization
OleInitialize(nil);
finalization
OleUninitialize;
,在這裏你可以如何使用這個程序:
procedure TForm2.Button1Click(Sender: TObject);
begin
ShowSysPopup(Edit1.Text,Edit1.Left,Edit1.Top, Handle);
end;
我希望這會爲你工作。
問候,
編輯: 如果你想顯示多個文件檢查上下文菜單this article in my blog
你確定這就是你想要做的嗎?因爲如果你這樣做,你實際上將不得不重現Windows Shell中的所有代碼以及它的所有行爲和與大量代碼的交互。
上下文菜單基本上由「shell擴展」構成。這些是COM DLL在系統中註冊的。當調用上下文菜單時,shell遵循一組規則,這些規則確定擴展DLL的位置(在註冊表中)。
I found this to be a useful guide to these rules。
但找到擴展DLL的甚至不是故事的一半。對於每個DLL,shell然後實例化由該DLL註冊的COM對象,並通過配置或調用菜單命令來調用DLL響應的那些對象。
shell本身並不構建菜單,也不需要構建可供查詢的菜單或從任何地方直接讀取菜單 - 菜單完全由shell擴展動態構建。
shell將一個句柄傳遞給每個擴展的菜單,還有一些信息告訴擴展名它將用於添加到該菜單的任何項目的命令ID。該擴展可以添加幾乎任何它喜歡的菜單句柄,包括子菜單等,它可能會添加不同的項目,取決於當前文件選擇的屬性,而不僅僅是文件擴展名(例如龜鱉SVN客戶端添加根據與這些文件的當前SVN狀態相關的不同菜單項)。所以如果你想自己構建一個這樣的菜單,就像我說的那樣,你將不得不復制整個shell擴展框架(或者至少是那些初始化菜單的那些部分,假設出於某種原因,你不需要然後需要或需要調用自己的菜單命令)在您自己的代碼中。
也許這可能有助於解釋您爲什麼希望做到這一點以及嘗試實現什麼。可能有更簡單的方法去做。
看起來有可能是一個辦法做到這一點不復制所有shell代碼畢竟。我發現這是一個.NET示例。 http://www.andrewvos.com/?p=420 – Deltics 2009-10-17 23:44:10
儘管我同意Deltics認爲它是很多工作,但大多數(如果不是全部)項目所需的信息在註冊表中是免費提供的。在Deltics中列出的指南的答案看起來不錯,並會給你大部分的項目。很多可以在註冊表中查找基本條目,而其他需要調用COM對象。
這似乎有點不完整,IContextMenu2消息沒有處理,即HandleMenuMsg沒有響應菜單消息被調用。因此,某些子菜單(如'打開')將不會填充。 [Here](http://stackoverflow.com/a/5287265)是我正在談論的一個例子。 – 2012-11-09 23:20:35
此外,沒有實現IShellCommandVerb接口的類,您的布爾型「Handled」參數和接口本身不提供任何服務。正如你在代碼中看到的那樣,你正在查詢* nil *如果它支持接口,當然你從來沒有被賦予接口,只是擺脫了那麼多不必要的代碼和不必要的類型聲明。 – 2012-11-10 00:31:19
我冒昧地自己做。這個語句「if支持(nil,IShellCommandVerb,SCV)」真的很突出。請更正您的博客上的代碼..我的第一個評論仍然有效,但。 – 2012-11-15 23:18:16