mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
UPD: Some code for background context menu
This commit is contained in:
parent
aacbb4e1d1
commit
fe2ca8acf9
3 changed files with 30 additions and 164 deletions
|
|
@ -31,7 +31,8 @@ uses
|
|||
{$IFDEF UNIX}
|
||||
Graphics, BaseUnix, Unix, fFileProperties, uPixMapManager;
|
||||
{$ELSE}
|
||||
FileUtil, Windows, ShlObj, uShlObjAdditional, JwaDbt, uMyWindows;
|
||||
FileUtil, Windows, ShlObj, ActiveX, uShlObjAdditional,
|
||||
JwaShlGuid, JwaDbt, uMyWindows;
|
||||
{$ENDIF}
|
||||
|
||||
const
|
||||
|
|
@ -72,7 +73,7 @@ procedure ShowFilePropertiesDialog(aFileSource: IFileSource; const Files: TFiles
|
|||
@param(X X coordinate)
|
||||
@param(Y Y coordinate)
|
||||
}
|
||||
procedure ShowContextMenu(Owner: TWinControl; var Files : TFiles; X, Y : Integer);
|
||||
procedure ShowContextMenu(Owner: TWinControl; var Files : TFiles; X, Y : Integer; Background: Boolean);
|
||||
{en
|
||||
Show drive context menu
|
||||
@param(Owner Parent window)
|
||||
|
|
@ -104,7 +105,7 @@ uses
|
|||
var
|
||||
{$IFDEF MSWINDOWS}
|
||||
OldWProc: WNDPROC;
|
||||
ShellContextMenu: IContextMenu2 = nil;
|
||||
ICM2: IContextMenu2 = nil;
|
||||
{$ELSE}
|
||||
CM : TContextMenu = nil;
|
||||
{$ENDIF}
|
||||
|
|
@ -122,9 +123,9 @@ begin
|
|||
WM_DRAWITEM,
|
||||
WM_MENUCHAR,
|
||||
WM_MEASUREITEM:
|
||||
if Assigned(ShellContextMenu) then
|
||||
if Assigned(ICM2) then
|
||||
begin
|
||||
ShellContextMenu.HandleMenuMsg(uiMsg, wParam, lParam);
|
||||
ICM2.HandleMenuMsg(uiMsg, wParam, lParam);
|
||||
Result := 0;
|
||||
end
|
||||
else
|
||||
|
|
@ -214,7 +215,7 @@ begin
|
|||
end;
|
||||
{$ENDIF}
|
||||
|
||||
procedure ShowContextMenu(Owner: TWinControl; var Files : TFiles; X, Y : Integer);
|
||||
procedure ShowContextMenu(Owner: TWinControl; var Files : TFiles; X, Y : Integer; Background: Boolean);
|
||||
{$IFDEF MSWINDOWS}
|
||||
const
|
||||
USER_CMD_ID = $1000;
|
||||
|
|
@ -223,6 +224,7 @@ var
|
|||
sl: TStringList = nil;
|
||||
i:Integer;
|
||||
sAct, sCmd: UTF8String;
|
||||
contMenu: IContextMenu;
|
||||
menu: HMENU = 0;
|
||||
hActionsSubMenu: HMENU = 0;
|
||||
cmd: UINT = 0;
|
||||
|
|
@ -237,11 +239,12 @@ begin
|
|||
try
|
||||
if Files.Count = 0 then Exit;
|
||||
|
||||
ShellContextMenu := TShellContextMenu.Create(Owner.Handle, Files, True);
|
||||
if Assigned(ShellContextMenu) then
|
||||
contMenu := GetShellContextMenu(Owner.Handle, Files, Background);
|
||||
if Assigned(contMenu) then
|
||||
try
|
||||
menu := CreatePopupMenu;
|
||||
OleCheckUTF8(ShellContextMenu.QueryContextMenu(menu, 0, 1, USER_CMD_ID - 1, CMF_EXPLORE or CMF_CANRENAME));
|
||||
OleCheckUTF8(contMenu.QueryContextMenu(menu, 0, 1, USER_CMD_ID - 1, CMF_EXPLORE or CMF_CANRENAME));
|
||||
contMenu.QueryInterface(IID_IContextMenu2, ICM2); // to handle submenus.
|
||||
//------------------------------------------------------------------------------
|
||||
{ Actions submenu }
|
||||
aFile := Files[0];
|
||||
|
|
@ -300,12 +303,13 @@ begin
|
|||
DestroyMenu(hActionsSubMenu);
|
||||
if menu <> 0 then
|
||||
DestroyMenu(menu);
|
||||
ICM2 := nil;
|
||||
end;
|
||||
|
||||
if (cmd > 0) and (cmd < USER_CMD_ID) then
|
||||
begin
|
||||
iCmd := LongInt(Cmd) - 1;
|
||||
if Succeeded(ShellContextMenu.GetCommandString(iCmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb))) then
|
||||
if Succeeded(contMenu.GetCommandString(iCmd, GCS_VERBA, nil, ZVerb, SizeOf(ZVerb))) then
|
||||
begin
|
||||
sVerb := StrPas(ZVerb);
|
||||
|
||||
|
|
@ -377,7 +381,7 @@ begin
|
|||
lpVerb := PChar(cmd - 1);
|
||||
nShow := SW_NORMAL;
|
||||
end;
|
||||
OleCheckUTF8(ShellContextMenu.InvokeCommand(cmici));
|
||||
OleCheckUTF8(contMenu.InvokeCommand(cmici));
|
||||
|
||||
// Reload after possible changes on the filesystem.
|
||||
if SameText(sVerb, sCmdVerbLink) then
|
||||
|
|
@ -410,7 +414,6 @@ begin
|
|||
end;
|
||||
end;
|
||||
finally
|
||||
ShellContextMenu := nil;
|
||||
FreeAndNil(Files);
|
||||
if Assigned(sl) then
|
||||
FreeAndNil(sl);
|
||||
|
|
@ -636,7 +639,7 @@ begin
|
|||
Files:= TFiles.Create(EmptyStr); // free in ShowContextMenu
|
||||
Files.Add(aFile);
|
||||
OldErrorMode:= SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
|
||||
ShowContextMenu(Owner, Files, X, Y);
|
||||
ShowContextMenu(Owner, Files, X, Y, False);
|
||||
SetErrorMode(OldErrorMode);
|
||||
end;
|
||||
{$ELSE}
|
||||
|
|
@ -694,12 +697,12 @@ end;
|
|||
{$ELSE}
|
||||
var
|
||||
cmici: TCMINVOKECOMMANDINFO;
|
||||
contMenu: IContextMenu2;
|
||||
contMenu: IContextMenu;
|
||||
begin
|
||||
if Files.Count = 0 then Exit;
|
||||
|
||||
try
|
||||
contMenu := TShellContextMenu.Create(frmMain.Handle, Files, False);
|
||||
contMenu := GetShellContextMenu(frmMain.Handle, Files, False);
|
||||
if Assigned(contMenu) then
|
||||
begin
|
||||
FillChar(cmici, sizeof(cmici), #0);
|
||||
|
|
|
|||
|
|
@ -27,50 +27,22 @@ unit uShellContextMenu;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, uFile, Windows, ShellAPI, ComObj, ShlObj, ActiveX,
|
||||
JwaShlGuid, uShlObjAdditional;
|
||||
Classes, SysUtils, uFile, Windows, ShellAPI, ComObj, ShlObj, ActiveX, JwaShlGuid, uShlObjAdditional;
|
||||
|
||||
type
|
||||
|
||||
{ TShellContextMenu }
|
||||
|
||||
TShellContextMenu = class(TInterfacedObject, IContextMenu2)
|
||||
private
|
||||
FShellNew: Boolean;
|
||||
FShellMenuMin : UINT; // Shell menu first command ID
|
||||
FShellMenuMax : UINT; // Shell menu last command ID
|
||||
FShellNewMenuMin : UINT; // New menu first command ID
|
||||
FShellNewMenuMax : UINT; // New menu last command ID
|
||||
FShellMenu1 : IContextMenu;
|
||||
FShellMenu2 : IContextMenu2;
|
||||
FShellNewMenu2 : IContextMenu2;
|
||||
FShellNewMenu : HMENU;
|
||||
public
|
||||
constructor Create(Handle : THandle; Files : TFiles; ShellNew: Boolean);
|
||||
destructor Destroy; override;
|
||||
// *** IContextMenu ***
|
||||
function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall;
|
||||
function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
|
||||
function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; stdcall;
|
||||
// *** IContextMenu2 ***
|
||||
function HandleMenuMsg(uMsg: UINT; wParam : WPARAM; lParam : LPARAM): HResult; stdcall;
|
||||
end;
|
||||
function GetShellContextMenu(Handle: THandle; Files: TFiles; Background: Boolean): IContextMenu;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
uMyWindows;
|
||||
|
||||
{ TShellContextMenu }
|
||||
|
||||
constructor TShellContextMenu.Create(Handle: THandle; Files: TFiles; ShellNew: Boolean);
|
||||
function GetForegroundContextMenu(Handle : THandle; Files : TFiles): IContextMenu;
|
||||
type
|
||||
PPIDLArray = ^PItemIDList;
|
||||
|
||||
var
|
||||
Folder,
|
||||
DesktopFolder: IShellFolder;
|
||||
newMenu: IShellExtInit;
|
||||
PathPIDL: PItemIDList = nil;
|
||||
tmpPIDL: PItemIDList = nil;
|
||||
S: WideString;
|
||||
|
|
@ -79,13 +51,9 @@ var
|
|||
pchEaten: ULONG;
|
||||
dwAttributes: ULONG = 0;
|
||||
begin
|
||||
FShellNew:= ShellNew;
|
||||
FShellMenu1 := nil;
|
||||
FShellMenu2 := nil;
|
||||
FShellNewMenu2 := nil;
|
||||
FShellNewMenu := INVALID_HANDLE_VALUE;
|
||||
Result := nil;
|
||||
|
||||
OleCheckUTF8(SHGetDesktopFolder(DesktopFolder));
|
||||
OleCheckUTF8(SHGetDesktopFolder(DeskTopFolder));
|
||||
try
|
||||
List := CoTaskMemAlloc(SizeOf(PItemIDList)*Files.Count);
|
||||
ZeroMemory(List, SizeOf(PItemIDList)*Files.Count);
|
||||
|
|
@ -113,24 +81,7 @@ begin
|
|||
(List + i)^ := tmpPIDL;
|
||||
end;
|
||||
|
||||
Folder.GetUIObjectOf(Handle, Files.Count, PItemIDList(List^), IID_IContextMenu, nil, FShellMenu1);
|
||||
|
||||
FShellMenu1.QueryInterface(IID_IContextMenu2, FShellMenu2); // to handle submenus.
|
||||
|
||||
// Add "New" submenu if needed
|
||||
if FShellNew and (Files.Count = 1) and Files[0].IsDirectory then
|
||||
begin
|
||||
S:= UTF8Decode(Files[0].FullPath);
|
||||
OleCheckUTF8(DesktopFolder.ParseDisplayName(Handle, nil, PWideChar(S), pchEaten, PathPIDL, dwAttributes));
|
||||
try
|
||||
CoCreateInstance(CLSID_NewMenu, nil, CLSCTX_ALL, IID_IShellExtInit, newMenu);
|
||||
newMenu.Initialize(PathPIDL, nil, 0);
|
||||
newMenu.QueryInterface(IID_IContextMenu2, FShellNewMenu2);
|
||||
finally
|
||||
newMenu:= nil;
|
||||
CoTaskMemFree(PathPIDL);
|
||||
end;
|
||||
end;
|
||||
Folder.GetUIObjectOf(Handle, Files.Count, PItemIDList(List^), IID_IContextMenu, nil, Result);
|
||||
|
||||
finally
|
||||
if Assigned(List) then
|
||||
|
|
@ -145,105 +96,17 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
destructor TShellContextMenu.Destroy;
|
||||
function GetBackgroundContextMenu(Handle : THandle; Files : TFiles): IContextMenu;
|
||||
begin
|
||||
FShellMenu1:= nil;
|
||||
FShellMenu2:= nil;
|
||||
FShellNewMenu2 := nil;
|
||||
if FShellNewMenu <> INVALID_HANDLE_VALUE then
|
||||
DestroyMenu(FShellNewMenu);
|
||||
inherited Destroy;
|
||||
|
||||
end;
|
||||
|
||||
function TShellContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
|
||||
idCmdLast, uFlags: UINT): HResult; stdcall;
|
||||
var
|
||||
iPos: LongInt;
|
||||
wsText: WideString;
|
||||
function GetShellContextMenu(Handle: THandle; Files: TFiles; Background: Boolean): IContextMenu; inline;
|
||||
begin
|
||||
FShellMenuMin:= idCmdFirst;
|
||||
FShellMenuMax:= (idCmdLast - idCmdFirst) div 2;
|
||||
FShellNewMenuMin:= FShellMenuMax + 1;
|
||||
FShellNewMenuMax:= idCmdLast;
|
||||
|
||||
Result:= FShellMenu1.QueryContextMenu(Menu, indexMenu, FShellMenuMin, FShellMenuMax, uFlags);
|
||||
iPos:= GetMenuItemCount(Menu);
|
||||
if Assigned(FShellNewMenu2) and (iPos > 0) then
|
||||
begin
|
||||
FShellNewMenu:= CreatePopupMenu;
|
||||
FShellNewMenu2.QueryContextMenu(FShellNewMenu, indexMenu, FShellNewMenuMin, FShellNewMenuMax, uFlags);
|
||||
if GetMenuItemCount(FShellNewMenu) > 0 then
|
||||
begin
|
||||
wsText:= GetMenuItemText(FShellNewMenu, 0, True);
|
||||
InsertMenuItemEx(Menu, FShellNewMenu, PWideChar(wsText), iPos - 2, FShellMenuMax, MFT_STRING);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TShellContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
|
||||
var
|
||||
idCmd: UINT;
|
||||
begin
|
||||
idCmd:= UINT(lpici.lpVerb) + 1;
|
||||
if (not FShellNew) or ((idCmd >= FShellMenuMin) and (idCmd <= FShellMenuMax)) then
|
||||
Result:= FShellMenu1.InvokeCommand(lpici)
|
||||
else if (idCmd >= FShellNewMenuMin) and (idCmd <= FShellNewMenuMax) then
|
||||
Result:= FShellNewMenu2.InvokeCommand(lpici)
|
||||
if Background then
|
||||
Result:= GetBackgroundContextMenu(Handle, Files)
|
||||
else
|
||||
Result:= E_NOTIMPL;
|
||||
end;
|
||||
|
||||
function TShellContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
|
||||
pszName: LPSTR; cchMax: UINT): HResult; stdcall;
|
||||
begin
|
||||
if (idCmd >= FShellMenuMin) and (idCmd <= FShellMenuMax) then
|
||||
Result:= FShellMenu1.GetCommandString(idCmd, uType, pwReserved, pszName, cchMax)
|
||||
else if (idCmd >= FShellNewMenuMin) and (idCmd <= FShellNewMenuMax) then
|
||||
Result:= FShellNewMenu2.GetCommandString(idCmd, uType, pwReserved, pszName, cchMax)
|
||||
else
|
||||
Result:= E_NOTIMPL;
|
||||
end;
|
||||
|
||||
function TShellContextMenu.HandleMenuMsg(uMsg: UINT; wParam: WPARAM; lParam: LPARAM
|
||||
): HResult; stdcall;
|
||||
var
|
||||
itemID : UINT;
|
||||
begin
|
||||
Result:= E_NOTIMPL;
|
||||
case uMsg of
|
||||
WM_INITMENUPOPUP:
|
||||
begin
|
||||
// wParam is a handle to the drop-down menu or submenu
|
||||
if wParam = FShellNewMenu then
|
||||
Result:= FShellNewMenu2.HandleMenuMsg(uMsg, wParam, lParam)
|
||||
else if Assigned(FShellMenu2) then
|
||||
Result:= FShellMenu2.HandleMenuMsg(uMsg, wParam, lParam);
|
||||
end;
|
||||
WM_DRAWITEM:
|
||||
begin
|
||||
itemID:= PDRAWITEMSTRUCT(lParam)^.itemID;
|
||||
if (itemID >= FShellMenuMin) and (itemID <= FShellMenuMax) then
|
||||
Result:= FShellMenu2.HandleMenuMsg(uMsg, wParam, lParam)
|
||||
else if (itemID >= FShellNewMenuMin) and (itemID <= FShellNewMenuMax) and Assigned(FShellNewMenu2) then
|
||||
Result:= FShellNewMenu2.HandleMenuMsg(uMsg, wParam, lParam);
|
||||
end;
|
||||
WM_MENUCHAR:
|
||||
begin
|
||||
// lParam is a handle to the active menu
|
||||
if lParam = FShellNewMenu then
|
||||
Result:= FShellNewMenu2.HandleMenuMsg(uMsg, wParam, lParam)
|
||||
else if Assigned(FShellMenu2) then
|
||||
Result:= FShellMenu2.HandleMenuMsg(uMsg, wParam, lParam);
|
||||
end;
|
||||
WM_MEASUREITEM:
|
||||
begin
|
||||
itemID:= PMEASUREITEMSTRUCT(lParam)^.itemID;
|
||||
if (itemID >= FShellMenuMin) and (itemID <= FShellMenuMax) then
|
||||
Result:= FShellMenu2.HandleMenuMsg(uMsg, wParam, lParam)
|
||||
else if (itemID >= FShellNewMenuMin) and (itemID <= FShellNewMenuMax) and Assigned(FShellNewMenu2) then
|
||||
Result:= FShellNewMenu2.HandleMenuMsg(uMsg, wParam, lParam);
|
||||
end;
|
||||
end;
|
||||
Result:= GetForegroundContextMenu(Handle, Files);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -683,7 +683,7 @@ begin
|
|||
try
|
||||
if aFiles.Count > 0 then
|
||||
try
|
||||
ShowContextMenu(frmMain, aFiles, X, Y);
|
||||
ShowContextMenu(frmMain, aFiles, X, Y, Background);
|
||||
except
|
||||
on e: EContextMenuException do
|
||||
ShowException(e);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue