CalvinDay
asked on
Windows sub-menu
Referencing Q.10189074. You can use the registry to create a Windows Explorer Menu popup. How do you add a sub menu popup?
also curious..
A shell extension is needed here. I don't know a way to do that without. It's quite complicated.
I also think that you can't create sub menus without a shell extension except the "sent to" menu there it's already done by windows.
Yep, that's a shell extension too. I checked that out before I posted my previous comment.
CalvinDay, I may be able to solve this problem but it will take far too much time that I don't have right now.
Delphi 3 and 4 come with a context menu demo (contmenu.dpr) which add an item to the menu when you right-click drag-and-drop. That demo can be modified to construct a submenu.
Then the DLL must be registered the right way.
It's tricky stuff so be carefull.
Eps.
CalvinDay, I may be able to solve this problem but it will take far too much time that I don't have right now.
Delphi 3 and 4 come with a context menu demo (contmenu.dpr) which add an item to the menu when you right-click drag-and-drop. That demo can be modified to construct a submenu.
Then the DLL must be registered the right way.
It's tricky stuff so be carefull.
Eps.
ASKER
I couldn't get contmenu.dpr to work. I then realized I must copy contmenu.dll to C:\windows\system. It works fine.
ASKER
So far I've added this. (and it works)
function TContextMenu.QueryContextM enu(Menu: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
var
popMenu:HMENU;
begin
popMenu:=CreatePopupMenu;
InsertMenu(popMenu,0,MF_ST RING or MF_BYPOSITION,0,'Sub 1');
InsertMenu(popMenu,1,MF_ST RING or MF_BYPOSITION,1,'Sub 2');
InsertMenu(popMenu,2,MF_ST RING or MF_BYPOSITION,2,'Sub 3');
InsertMenu(popMenu,3,MF_ST RING or MF_BYPOSITION,3,'Sub 4');
InsertMenu(Menu,indexMenu, MF_STRING or MF_POPUP,popMenu,'Compile. ..');
Result := 1;
end;
function TContextMenu.QueryContextM
idCmdLast, uFlags: UINT): HResult;
var
popMenu:HMENU;
begin
popMenu:=CreatePopupMenu;
InsertMenu(popMenu,0,MF_ST
InsertMenu(popMenu,1,MF_ST
InsertMenu(popMenu,2,MF_ST
InsertMenu(popMenu,3,MF_ST
InsertMenu(Menu,indexMenu,
Result := 1;
end;
ASKER
Other posting was wrong, this is correct: I have written a little utility to sort file names and print them according to sort criteria. It is called xprint.exe. Now with this little shell extension, I can highlight a group of files, right click and select the printed sort order on the fly.
Here's the final code:
unit ContextM;
interface
uses
Windows, ComObj, ComServ, ShlObj, ActiveX, ShellApi, SysUtils, Classes;
Const
CLSID_ContextMenuShellExte nsion: TGUID = (
D1:$8e3e0f0a; D2:$0fcc; D3:$11ce; D4:($bc, $b0, $b3, $fd, $0e, $25, $38, $1a));
type
TContextMenu = class(TComObject, IShellExtInit, IContextMenu)
private
szFile: array[0..MAX_PATH] of Char;
public
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;
function Initialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
end;
var
t:TStringStream;
implementation
function GetCompilerPath(sort:integ er): string;
const
SortName='ntsd';
var
sWinDir,s:string;
l:integer;
begin
SetLength(sWinDir,255);
l:=GetWindowsDirectory(PCh ar(sWinDir ),255);
SetLength(sWinDir,l);
Result := sWinDir+'\xPrint.exe /'+SortName[sort+1]+' %s';
end;
function TContextMenu.QueryContextM enu(Menu:H MENU;index Menu,idCmd First,idCm dLast,uFla gs:UINT):H Result;
const
CmdName: array[0..3] of string=('by &Name','by &Type','by &Size','by &Date');
var
popMenu:HMENU;
i:integer;
begin
popMenu:=CreatePopupMenu;
for i:=0 to High(CmdName) do
InsertMenu(popMenu,i,MF_ST RING or MF_BYCOMMAND,idCmdFirst+i, PChar(CmdN ame[i]));
InsertMenu(Menu,indexMenu, MF_STRING or MF_POPUP,popMenu,'xPrint ...');
Result:=High(CmdName)+1;
end;
function TContextMenu.InvokeCommand (var lpici: TCMInvokeCommandInfo): HResult;
var
H: THandle;
begin
Result:=E_FAIL;
if HiWord(Integer(lpici.lpVer b))<>0 then exit;
H:=WinExec(PChar(Format(Ge tCompilerP ath(LoWord (lpici.lpV erb)),[t.D ataString] )),lpici.n Show);
if H<32 then
MessageBox(lpici.hWnd, 'Error executing xPrint.', 'Error',MB_ICONERROR or MB_OK);
end;
function TContextMenu.GetCommandStr ing(idCmd, uType:UINT ;pwReserve d:PUINT;ps zName:LPST R;cchMax:U INT):HRESU LT;
const
CmdHint: array[0..3] of string=('Name','Type','Siz e','Date') ;
begin
Result:=NOERROR;
if (idCmd>=0) and (idCmd<=High(CmdHint)) then
StrPCopy(pszName,'Prints selected items sorted by '+CmdHint[idCmd])
else
Result:=E_INVALIDARG;
end;
function TContextMenu.Initialize(pi dlFolder:P ItemIDList ;lpdobj:ID ataObject; hKeyProgID :HKEY):HRe sult;
var
medium: TStgMedium;
fe: TFormatEtc;
i,count:integer;
begin
with fe do
begin
cfFormat:=CF_HDROP;
ptd:=nil;
dwAspect:=DVASPECT_CONTENT ;
lindex:=-1;
tymed:=TYMED_HGLOBAL;
end;
Result:=E_FAIL;
if lpdobj=nil then exit;
Result:=lpdobj.GetData(fe, medium);
if Failed(Result) then exit;
count:=DragQueryFile(mediu m.hGlobal, $FFFFFFFF, nil,0);
t.Position:=0;
for i:=0 to count-1 do
begin
DragQueryFile(medium.hGlob al,i,szFil e,SizeOf(s zFile));
t.WriteString('"'+string(s zFile)+'" ');
end;
Result:=NOERROR;
ReleaseStgMedium(medium);
end;
initialization
t:=TStringStream.Create('' );
TComObjectFactory.Create(C omServer, TContextMenu, CLSID_ContextMenuShellExte nsion,
'', 'Delphi 3.0 ContextMenu Example', ciMultiInstance);
finalization
t.Free;
end.
Epsylon, please post an answer for your wonderful suggestion.
Here's the final code:
unit ContextM;
interface
uses
Windows, ComObj, ComServ, ShlObj, ActiveX, ShellApi, SysUtils, Classes;
Const
CLSID_ContextMenuShellExte
D1:$8e3e0f0a; D2:$0fcc; D3:$11ce; D4:($bc, $b0, $b3, $fd, $0e, $25, $38, $1a));
type
TContextMenu = class(TComObject, IShellExtInit, IContextMenu)
private
szFile: array[0..MAX_PATH] of Char;
public
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;
function Initialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
end;
var
t:TStringStream;
implementation
function GetCompilerPath(sort:integ
const
SortName='ntsd';
var
sWinDir,s:string;
l:integer;
begin
SetLength(sWinDir,255);
l:=GetWindowsDirectory(PCh
SetLength(sWinDir,l);
Result := sWinDir+'\xPrint.exe /'+SortName[sort+1]+' %s';
end;
function TContextMenu.QueryContextM
const
CmdName: array[0..3] of string=('by &Name','by &Type','by &Size','by &Date');
var
popMenu:HMENU;
i:integer;
begin
popMenu:=CreatePopupMenu;
for i:=0 to High(CmdName) do
InsertMenu(popMenu,i,MF_ST
InsertMenu(Menu,indexMenu,
Result:=High(CmdName)+1;
end;
function TContextMenu.InvokeCommand
var
H: THandle;
begin
Result:=E_FAIL;
if HiWord(Integer(lpici.lpVer
H:=WinExec(PChar(Format(Ge
if H<32 then
MessageBox(lpici.hWnd, 'Error executing xPrint.', 'Error',MB_ICONERROR or MB_OK);
end;
function TContextMenu.GetCommandStr
const
CmdHint: array[0..3] of string=('Name','Type','Siz
begin
Result:=NOERROR;
if (idCmd>=0) and (idCmd<=High(CmdHint)) then
StrPCopy(pszName,'Prints selected items sorted by '+CmdHint[idCmd])
else
Result:=E_INVALIDARG;
end;
function TContextMenu.Initialize(pi
var
medium: TStgMedium;
fe: TFormatEtc;
i,count:integer;
begin
with fe do
begin
cfFormat:=CF_HDROP;
ptd:=nil;
dwAspect:=DVASPECT_CONTENT
lindex:=-1;
tymed:=TYMED_HGLOBAL;
end;
Result:=E_FAIL;
if lpdobj=nil then exit;
Result:=lpdobj.GetData(fe,
if Failed(Result) then exit;
count:=DragQueryFile(mediu
t.Position:=0;
for i:=0 to count-1 do
begin
DragQueryFile(medium.hGlob
t.WriteString('"'+string(s
end;
Result:=NOERROR;
ReleaseStgMedium(medium);
end;
initialization
t:=TStringStream.Create(''
TComObjectFactory.Create(C
'', 'Delphi 3.0 ContextMenu Example', ciMultiInstance);
finalization
t.Free;
end.
Epsylon, please post an answer for your wonderful suggestion.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks, epsylon, I did learn alot. The only thing I'm missing is the little bitmap next to the menu. I may have to post a question to do that.
If anyone wants the xPrint program, drop me your email. it's pretty good when trying to compare dll's and such.
If anyone wants the xPrint program, drop me your email. it's pretty good when trying to compare dll's and such.