Link to home
Start Free TrialLog in
Avatar of luizpaulo
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\*\ShellEx) 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
Avatar of Mohammed Nasman
Mohammed Nasman
Flag of Palestine, State of image

you will fine an example came with delphi, look at the project called contmenu.dpr in this path

\Delphi5\Demos\Activex\Shellext

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
Avatar of luizpaulo
luizpaulo

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
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-51839D60C9C2}';

implementation

uses ComServ, SysUtils, ShellApi, Registry;

function TContextMenu.SEIInitialize(pidlFolder: 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.hGlobal, $FFFFFFFF, nil, 0) > 0) then begin
             Count := DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0);
             for Loop := 0 to Count - 1 do begin
                   DragQueryFile(StgMedium.hGlobal, Loop, FFileName, SizeOf(FFileName));
                   FFileNameList := FFileNameList + FFileName+' ';
             end;
             //       if (DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0) = 1) then begin
             //       DragQueryFile(StgMedium.hGlobal, 0, FFileName, SizeOf(FFileName));
             Result := NOERROR;
       end
       else begin
             FFileName[0] := #0;
             Result := E_FAIL;
       end;
       ReleaseStgMedium(StgMedium);
end;

function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
       idCmdLast, uFlags: UINT): HResult;
begin
       Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
       //Load the image from RES file.
       if BT = nil then
             BT := TBitmap.Create;
       BT.LoadFromResourceName(HInstance, '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_SUCCESS, 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(Result);
                   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.lpVerb)) <> 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(ExtractFilePath(FFileName)) then
                   raise Exception.CreateRes(@sPathError);

             H := WinExec(PChar(Format(GetjEditPath, [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.GetCommandString(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.UpdateRegistry(Register: Boolean);
var
       ClassID: string;
begin
       if Register then begin
             inherited UpdateRegistry(Register);

             ClassID := GUIDToString(Class_ContextMenu);
             CreateRegKey('IQL\shellex', '', '');
             CreateRegKey('IQL\shellex\ContextMenuHandlers', '', '');
             CreateRegKey('IQL\shellex\ContextMenuHandlers\ContMenu', '', ClassID);

             if (Win32Platform = VER_PLATFORM_WIN32_NT) then
                   with TRegistry.Create do
                   try
                         RootKey := HKEY_LOCAL_MACHINE;
                         OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True);
                         OpenKey('Approved', True);
                         WriteString(ClassID, 'jEdit Context Menu Shell Extension');
                   finally
                         Free;
                   end;
       end
       else begin
             DeleteRegKey('IQL\shellex\ContextMenuHandlers\ContMenu');
             DeleteRegKey('IQL\shellex\ContextMenuHandlers');
             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.
ASKER CERTIFIED SOLUTION
Avatar of Mohammed Nasman
Mohammed Nasman
Flag of Palestine, State of image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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