luizpaulo
asked on
Explorer Popup Menu
I'm making an application and I need for to have a option to open it on the Windows Explorer popup menu(show's when you right click a file) with all files but one(the file type my program actually reads) sort like winzip does. and for one special file type(the file type my program actually reads) I also need some special options on it's popup menu.
I've been checking the registry for it but all I saw were keys inside the ContextMenuHandlers (at HKEY_CLASSES_ROOT\*\ShellE x) with the names of programs that do such and at the (standart) of those keys were values like {FF678...423A4} and something like that.
I found those keys with those values inside the CLSID key(at HKEY_CLASSES_ROOT).
Does this have anything to do with it?
I'm making the this program in delphi reason why I'm asking here first before asking at the windows group.
I'd appreciate any help.
Luiz Paulo
I've been checking the registry for it but all I saw were keys inside the ContextMenuHandlers (at HKEY_CLASSES_ROOT\*\ShellE
I found those keys with those values inside the CLSID key(at HKEY_CLASSES_ROOT).
Does this have anything to do with it?
I'm making the this program in delphi reason why I'm asking here first before asking at the windows group.
I'd appreciate any help.
Luiz Paulo
ASKER
I have D3 and there it has a example like at \Demos\Shellext but the example doesn't say anything about
the CLSID key you have to make(I mean how to generate those {FF678...423A4} numbers), plus It doesn't explain anything about the COM stuff(which I know very little about)
Where can I read more about this?
Thanks for the help.
Luiz Paulo
the CLSID key you have to make(I mean how to generate those {FF678...423A4} numbers), plus It doesn't explain anything about the COM stuff(which I know very little about)
Where can I read more about this?
Thanks for the help.
Luiz Paulo
Hi
I mean how to generate those {FF678...423A4} numbers
In the Editor just press ctrl+shift+g
It will give u the GUID u can use it for u r application.
Another easy way have without any Com dll for the Explorer
menu.
u can just add u r application to SendTo folder in u r system.
It will actomatically come in the SendTo list of u r system.
below I have coding of jEdit Context menu
******************
unit ContextM;
interface
uses
Windows, ActiveX, ComObj, ShlObj, graphics;
type
TContextMenu = class(TComObject, IShellExtInit, IContextMenu)
private
FFileName: array[0..MAX_PATH] of Char;
FFileNameList: String;
BT: TBitmap;
protected
{ IShellExtInit }
function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
{ 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;
end;
const
Class_ContextMenu: TGUID = '{E15E69D0-E84D-4A69-9E3C- 51839D60C9 C2}';
implementation
uses ComServ, SysUtils, ShellApi, Registry;
function TContextMenu.SEIInitialize (pidlFolde r: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
Count, Loop: Byte;
begin
// Fail the call if lpdobj is Nil.
if (lpdobj = nil) then begin
Result := E_INVALIDARG;
Exit;
end;
with FormatEtc do begin
cfFormat := CF_HDROP;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
// Render the data referenced by the IDataObject pointer to an HGLOBAL
// storage medium in CF_HDROP format.
Result := lpdobj.GetData(FormatEtc, StgMedium);
if Failed(Result) then
begin
Exit;
end;
// File(s) is selected, retrieve the file name and store it in FFileName.
// FFileNameList Soters the List of files.
if (DragQueryFile(StgMedium.h Global, $FFFFFFFF, nil, 0) > 0) then begin
Count := DragQueryFile(StgMedium.hG lobal, $FFFFFFFF, nil, 0);
for Loop := 0 to Count - 1 do begin
DragQueryFile(StgMedium.hG lobal, Loop, FFileName, SizeOf(FFileName));
FFileNameList := FFileNameList + FFileName+' ';
end;
// if (DragQueryFile(StgMedium.h Global, $FFFFFFFF, nil, 0) = 1) then begin
// DragQueryFile(StgMedium.hG lobal, 0, FFileName, SizeOf(FFileName));
Result := NOERROR;
end
else begin
FFileName[0] := #0;
Result := E_FAIL;
end;
ReleaseStgMedium(StgMedium );
end;
function TContextMenu.QueryContextM enu(Menu: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
begin
Result := 0; // or use MakeResult(SEVERITY_SUCCES S, FACILITY_NULL, 0);
//Load the image from RES file.
if BT = nil then
BT := TBitmap.Create;
BT.LoadFromResourceName(HI nstance, 'BTM');
if ((uFlags and $0000000F) = CMF_NORMAL) or
((uFlags and CMF_EXPLORE) <> 0) then begin
// Add one menu item to context menu
InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
'&jEdit');
SetMenuItemBitmaps(Menu, indexMenu, MF_STRING or MF_BYPOSITION, BT.Handle, BT.Handle);
// Return number of menu items added
Result := 1; // or use MakeResult(SEVERITY_SUCCES S, FACILITY_NULL, 1)
end;
end;
function GetjEditPath: string;
// Returns string containing path to jEdit command line
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
with Reg do begin
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('\SOFTWARE\jEdit\3 .3', False);
Result := ReadString('App');
end;
if AnsiPos(' ', Result) <> 0 then
Result := ExtractShortPathName(Resul t);
Result := Result + ' %S';
finally
Reg.Free;
end;
end;
function TContextMenu.InvokeCommand (var lpici: TCMInvokeCommandInfo): HResult;
resourcestring
sPathError = 'Error setting current directory';
var
H: THandle;
PrevDir: string;
begin
Result := E_FAIL;
// Make sure we are not being called by an application
if (HiWord(Integer(lpici.lpVe rb)) <> 0) then
begin
Exit;
end;
// Make sure we aren't being passed an invalid argument number
if (LoWord(lpici.lpVerb) <> 0) then begin
Result := E_INVALIDARG;
Exit;
end;
// Execute the command specified by lpici.lpVerb
// by invoking the jEdit command line .
PrevDir := GetCurrentDir;
try
if not SetCurrentDir(ExtractFileP ath(FFileN ame)) then
raise Exception.CreateRes(@sPath Error);
H := WinExec(PChar(Format(GetjE ditPath, [FFileNameList])), lpici.nShow);
if (H < 32) then
MessageBox(lpici.hWnd, 'Error Opening jEdit .', 'Error',
MB_ICONERROR or MB_OK);
Result := NOERROR;
finally
SetCurrentDir(PrevDir);
end;
end;
function TContextMenu.GetCommandStr ing(idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HRESULT;
begin
if (idCmd = 0) then begin
if (uType = GCS_HELPTEXT) then
// return help string for menu item
StrCopy(pszName, 'Open File in jEdit');
Result := NOERROR;
end
else
Result := E_INVALIDARG;
end;
type
TContextMenuFactory = class(TComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
procedure TContextMenuFactory.Update Registry(R egister: Boolean);
var
ClassID: string;
begin
if Register then begin
inherited UpdateRegistry(Register);
ClassID := GUIDToString(Class_Context Menu);
CreateRegKey('IQL\shellex' , '', '');
CreateRegKey('IQL\shellex\ ContextMen uHandlers' , '', '');
CreateRegKey('IQL\shellex\ ContextMen uHandlers\ ContMenu', '', ClassID);
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWARE\Microsof t\Windows\ CurrentVer sion\Shell Extensions', True);
OpenKey('Approved', True);
WriteString(ClassID, 'jEdit Context Menu Shell Extension');
finally
Free;
end;
end
else begin
DeleteRegKey('IQL\shellex\ ContextMen uHandlers\ ContMenu') ;
DeleteRegKey('IQL\shellex\ ContextMen uHandlers' );
DeleteRegKey('IQL\shellex' );
inherited UpdateRegistry(Register);
end;
end;
initialization
TContextMenuFactory.Create (ComServer , TContextMenu, Class_ContextMenu,
'', 'jEdit Context Menu Shell Extension', ciMultiInstance,
tmApartment);
end.
******************
if u have any doubt mail me
regards
sbsen.
I mean how to generate those {FF678...423A4} numbers
In the Editor just press ctrl+shift+g
It will give u the GUID u can use it for u r application.
Another easy way have without any Com dll for the Explorer
menu.
u can just add u r application to SendTo folder in u r system.
It will actomatically come in the SendTo list of u r system.
below I have coding of jEdit Context menu
******************
unit ContextM;
interface
uses
Windows, ActiveX, ComObj, ShlObj, graphics;
type
TContextMenu = class(TComObject, IShellExtInit, IContextMenu)
private
FFileName: array[0..MAX_PATH] of Char;
FFileNameList: String;
BT: TBitmap;
protected
{ IShellExtInit }
function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
{ 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;
end;
const
Class_ContextMenu: TGUID = '{E15E69D0-E84D-4A69-9E3C-
implementation
uses ComServ, SysUtils, ShellApi, Registry;
function TContextMenu.SEIInitialize
hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
Count, Loop: Byte;
begin
// Fail the call if lpdobj is Nil.
if (lpdobj = nil) then begin
Result := E_INVALIDARG;
Exit;
end;
with FormatEtc do begin
cfFormat := CF_HDROP;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
// Render the data referenced by the IDataObject pointer to an HGLOBAL
// storage medium in CF_HDROP format.
Result := lpdobj.GetData(FormatEtc, StgMedium);
if Failed(Result) then
begin
Exit;
end;
// File(s) is selected, retrieve the file name and store it in FFileName.
// FFileNameList Soters the List of files.
if (DragQueryFile(StgMedium.h
Count := DragQueryFile(StgMedium.hG
for Loop := 0 to Count - 1 do begin
DragQueryFile(StgMedium.hG
FFileNameList := FFileNameList + FFileName+' ';
end;
// if (DragQueryFile(StgMedium.h
// DragQueryFile(StgMedium.hG
Result := NOERROR;
end
else begin
FFileName[0] := #0;
Result := E_FAIL;
end;
ReleaseStgMedium(StgMedium
end;
function TContextMenu.QueryContextM
idCmdLast, uFlags: UINT): HResult;
begin
Result := 0; // or use MakeResult(SEVERITY_SUCCES
//Load the image from RES file.
if BT = nil then
BT := TBitmap.Create;
BT.LoadFromResourceName(HI
if ((uFlags and $0000000F) = CMF_NORMAL) or
((uFlags and CMF_EXPLORE) <> 0) then begin
// Add one menu item to context menu
InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
'&jEdit');
SetMenuItemBitmaps(Menu, indexMenu, MF_STRING or MF_BYPOSITION, BT.Handle, BT.Handle);
// Return number of menu items added
Result := 1; // or use MakeResult(SEVERITY_SUCCES
end;
end;
function GetjEditPath: string;
// Returns string containing path to jEdit command line
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
with Reg do begin
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('\SOFTWARE\jEdit\3
Result := ReadString('App');
end;
if AnsiPos(' ', Result) <> 0 then
Result := ExtractShortPathName(Resul
Result := Result + ' %S';
finally
Reg.Free;
end;
end;
function TContextMenu.InvokeCommand
resourcestring
sPathError = 'Error setting current directory';
var
H: THandle;
PrevDir: string;
begin
Result := E_FAIL;
// Make sure we are not being called by an application
if (HiWord(Integer(lpici.lpVe
begin
Exit;
end;
// Make sure we aren't being passed an invalid argument number
if (LoWord(lpici.lpVerb) <> 0) then begin
Result := E_INVALIDARG;
Exit;
end;
// Execute the command specified by lpici.lpVerb
// by invoking the jEdit command line .
PrevDir := GetCurrentDir;
try
if not SetCurrentDir(ExtractFileP
raise Exception.CreateRes(@sPath
H := WinExec(PChar(Format(GetjE
if (H < 32) then
MessageBox(lpici.hWnd, 'Error Opening jEdit .', 'Error',
MB_ICONERROR or MB_OK);
Result := NOERROR;
finally
SetCurrentDir(PrevDir);
end;
end;
function TContextMenu.GetCommandStr
pszName: LPSTR; cchMax: UINT): HRESULT;
begin
if (idCmd = 0) then begin
if (uType = GCS_HELPTEXT) then
// return help string for menu item
StrCopy(pszName, 'Open File in jEdit');
Result := NOERROR;
end
else
Result := E_INVALIDARG;
end;
type
TContextMenuFactory = class(TComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
procedure TContextMenuFactory.Update
var
ClassID: string;
begin
if Register then begin
inherited UpdateRegistry(Register);
ClassID := GUIDToString(Class_Context
CreateRegKey('IQL\shellex'
CreateRegKey('IQL\shellex\
CreateRegKey('IQL\shellex\
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWARE\Microsof
OpenKey('Approved', True);
WriteString(ClassID, 'jEdit Context Menu Shell Extension');
finally
Free;
end;
end
else begin
DeleteRegKey('IQL\shellex\
DeleteRegKey('IQL\shellex\
DeleteRegKey('IQL\shellex'
inherited UpdateRegistry(Register);
end;
end;
initialization
TContextMenuFactory.Create
'', 'jEdit Context Menu Shell Extension', ciMultiInstance,
tmApartment);
end.
******************
if u have any doubt mail me
regards
sbsen.
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 for the help Mohammed, with your code(on the email), sbsen's code, and delphi's demo I acomplished what I desired.
I also wanna thank sbsen but I can only give points to one person, but your help was appreciated. I gave the points to Mohammed because he was the first one.
Thanks for the help.
Luiz Paulo
I also wanna thank sbsen but I can only give points to one person, but your help was appreciated. I gave the points to Mohammed because he was the first one.
Thanks for the help.
Luiz Paulo
\Delphi5\Demos\Activex\She
send me email at nasman@mogaza.org, and i will send you an article about enhanced version of this demo with the source code
Best regards
Mohammed Nasmna