Link to home
Start Free TrialLog in
Avatar of DSOM
DSOMFlag for United States of America

asked on

registering a dll on Vista/W7

I have a DLL that I am trying to register as a shell extension and it works perfectly on Windows2k and WindowsXP but fails without an error on Vista and Windows7.

Included is the code for the shell extension dll.  My question is, has WindowsVista/7 changed something?  What do I need to do to get the extension working?

I am using Delphi 2009.  I ran the installer as admin and registered the server manually as admin.
library tcshellex;
 
uses
  madExcept,
  madLinkDisAsm,
  madListHardware,
  madListProcesses,
  madListModules,
  Windows,
  ShlObj,
  ComObj,
  ComServ,
  ActiveX,
  ShellApi,
  SysUtils,
  Registry,
  madkernel;
 
{$R *.RES}
 
const
 IID_IMalloc: TGUID = '{2DE506B9-4320-11d3-8E42-002035221EDA}';
 
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;
 
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
          idCmdLast, uFlags: UINT): HResult;
begin
  // Add one menu item to context menu
  InsertMenu (Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
    'Scan with The App');
  // Return number of menu items added
  Result := 1;
end;
 
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var
  H: THandle;
  R: tregistry;
  t: string;
begin
  // Make sure we are not being called by an application
  if HiWord(Integer(lpici.lpVerb)) <> 0 then
  begin
    Result := E_FAIL;
    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.
  if LoWord(lpici.lpVerb) = 0 then
  begin
    R:=tregistry.create;
    R.rootkey:=HKEY_CURRENT_USER;
    r.openkey('\Software\Company\TheApp\', false);
    t:=r.readstring('tcshellex');
    r.closekey;
    r.Free;
    NewProcess(t,szfile);
  end;
  Result := NOERROR;
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
      strlCopy(pszName, 'Scan with The App',cchmax-1);
    Result := NOERROR;
  end
  else
    Result := E_INVALIDARG;
end;
 
function TContextMenu.Initialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
  hKeyProgID: HKEY): HResult;
var
  medium: TStgMedium;
  fe: TFormatEtc;
  i,c,size: integer;
  temp: string;
begin
  with fe do
  begin
    cfFormat := CF_HDROP;
    ptd := Nil;
    dwAspect := DVASPECT_CONTENT;
    lindex := -1;
    tymed := TYMED_HGLOBAL;
  end;
  // Fail the call if lpdobj is Nil.
  if lpdobj = Nil then
  begin
    Result := E_FAIL;
    Exit;
  end;
  // Render the data referenced by the IDataObject pointer to an HGLOBAL
  // storage medium in CF_HDROP format.
  Result := lpdobj.GetData(fe, medium);
  if Failed(Result) then Exit;
  // If only one file is selected, retrieve the file name and store it in
  // szFile. Otherwise fail the call.
//  if DragQueryFile(medium.hGlobal, $FFFFFFFF, Nil, 0) = 1 then
  begin
    try
      temp:='';
      c:=DragQueryFile(medium.hGlobal, $FFFFFFFF, Nil, 0);
      for i:=0 to c-1 do
        begin
          size:=DragQueryFile(medium.hGlobal, i, nil, 0)+2;
          DragQueryFile(medium.hGlobal, i, szFile, size);
          temp:=temp+'"'+szfile+'"'+#32;
        end;
      if (length(temp) > MAX_PATH) then
        Result := E_FAIL
         else
        begin
          strcopy(szfile, pchar(temp));
          Result := NOERROR;
        end;
    except
      Result := E_FAIL;
    end;
  end;
  ReleaseStgMedium(medium);
end;
 
exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;
 
begin
    TComObjectFactory.Create(ComServer, TContextMenu, IID_IMalloc,
         'The.App', 'TheApp', ciMultiInstance);
end.

Open in new window

Avatar of Johnjces
Johnjces
Flag of United States of America image

A couple of thoughts come to mind...

1). Did you try registering the dll in an administrator command prompt, runas cmd.exe?

2). Does your dll have a Vista manifest resource compiled with it?  

John
Avatar of DSOM

ASKER

I registered it as admin in a cmd prompt.  It doesn't have a manifest with it, I'll try that!
Avatar of DSOM

ASKER

Well that didn't work.  I put in a messagebox and it shows that it is calling the proper file.  So the registration works, but it fails to launch the process.
One last thought, then I am out of ideas, turn all of Vista's UAC stuff off temporarily. If it still does not register, it is not a UAC or permissions issue. At least you will know for certain that it does not pertain to UAC stuff.

Is all the MAD classes Vista updated/aware?

Sorry I couldn't help you more.

John
Avatar of DSOM

ASKER

I ditched the NewProcess function for createprocess and now I get "The requested operation requires elevation."  How do you run a process that needs elevation with createprocess?
ASKER CERTIFIED SOLUTION
Avatar of Johnjces
Johnjces
Flag of United States of America 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
Avatar of DSOM

ASKER

I boiled that down to:

ShellExecute(0, 'open', pchar(t), szfile, nil, SW_SHOWNORMAL);

It works!  Thank you for leading me in the right direction!
Glad I could help! That was a lot of distilling! I was thinking a bit more complex in what you were needing.

John