home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue40 / COMCorn / UIObjs.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-11-12  |  9.2 KB  |  314 lines

  1. unit UIObjs;
  2.  
  3. interface
  4.  
  5. uses Windows, ComObj, ShlObj, ActiveX, UtilObjs;
  6.  
  7. type
  8.   // Base class for all things returned by IShellFolder.GetUIObjectOf
  9.   TBaseUIObject = class(TMultiAggregatedObject)
  10.   private
  11.     FHwndOwner: HWND;
  12.   protected
  13.     function GetFileName(const Guid: TGuid): string;
  14.   public
  15.     constructor Create(Owner: TComObject; HwndOwner: HWND); reintroduce;
  16.     property HwndOwner: HWND read FHwndOwner;
  17.   end;
  18.  
  19.   // Base class for all UI objects that work with only one object at a time
  20.   TSingleSelectUIObject = class(TBaseUIObject)
  21.   private
  22.     FServGuid: TGUID;
  23.   public
  24.     constructor Create(Owner: TComObject; HwndOwner: HWND; Guid: TGUID); reintroduce;
  25.     property ServGuid: TGUID read FServGuid;
  26.   end;
  27.  
  28.   TForEachProc = procedure (const Guid: TGUID; Data: Integer) of object;
  29.  
  30.   // Base class for all UI objects that can work with multi-selected objects
  31.   TMultiSelectUIObject = class(TBaseUIObject)
  32.   private
  33.     FServGuids: array of TGUID;
  34.     function GetServGuid(Index: Integer): TGUID;
  35.   protected
  36.     procedure ForEach(Proc: TForEachProc; Data: Integer);
  37.   public
  38.     constructor Create(Owner: TComObject; HwndOwner: HWND;
  39.       Guids: array of TGUID); reintroduce;
  40.     property ServGuids[Index: Integer]: TGUID read GetServGuid;
  41.   end;
  42.  
  43.   TContextMenu = class(TMultiSelectUIObject, IContextMenu)
  44.   private
  45.     FMenuIdx: UINT;
  46.     procedure UnregisterProc(const Guid: TGuid; Data: Integer);
  47.     procedure ShowPropertiesProc(const Guid: TGuid; Data: Integer);
  48.   protected
  49.     { IContextMenu methods }
  50.     function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
  51.       uFlags: UINT): HResult; stdcall;
  52.     function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
  53.     function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
  54.       pszName: LPSTR; cchMax: UINT): HResult; stdcall;
  55.   end;
  56.  
  57.   TExtractIcon = class(TSingleSelectUIObject, IExtractIcon)
  58.   protected
  59.     { IExtractIcon methods }
  60.     function GetIconLocation(uFlags: UINT; szIconFile: PAnsiChar; cchMax: UINT;
  61.       out piIndex: Integer; out pwFlags: UINT): HResult; stdcall;
  62.     function Extract(pszFile: PAnsiChar; nIconIndex: UINT;
  63.       out phiconLarge, phiconSmall: HICON; nIconSize: UINT): HResult; stdcall;
  64.   end;
  65.  
  66. implementation
  67.  
  68. uses ComServ, SysUtils, ShellAPI, Registry, PropForm;
  69.  
  70. { TBaseUIObject }
  71.  
  72. constructor TBaseUIObject.Create(Owner: TComObject; HwndOwner: HWND);
  73. begin
  74.   inherited Create(Owner);
  75.   FHWndOwner := HwndOwner;
  76. end;
  77.  
  78. function TBaseUIObject.GetFileName(const Guid: TGuid): string;
  79. var
  80.   Reg: TRegistry;
  81. begin
  82.   Result := '';
  83.   Reg := TRegistry.Create;
  84.   try
  85.     Reg.RootKey := HKEY_CLASSES_ROOT;
  86.     if Reg.OpenKeyReadOnly('CLSID\' + GuidToString(Guid) + '\InprocServer32') or
  87.       Reg.OpenKeyReadOnly('CLSID\' + GuidToString(Guid) + '\LocalServer32') then
  88.       Result := Reg.ReadString('');
  89.   finally
  90.     Reg.Free;
  91.   end;
  92. end;
  93.  
  94. { TSingleSelectUIObject }
  95.  
  96. constructor TSingleSelectUIObject.Create(Owner: TComObject; HwndOwner: HWND;
  97.   Guid: TGUID);
  98. begin
  99.   inherited Create(Owner, HwndOwner);
  100.   FServGuid := Guid;
  101. end;
  102.  
  103. { TMultiSelectUIObject }
  104.  
  105. constructor TMultiSelectUIObject.Create(Owner: TComObject; HwndOwner: HWND;
  106.   Guids: array of TGUID);
  107. var
  108.   I: Integer;
  109. begin
  110.   inherited Create(Owner, HwndOwner);
  111.   SetLength(FServGuids, High(Guids) + 1);
  112.   for I := Low(Guids) to High(Guids) do
  113.     FServGuids[I] := Guids[I];
  114. end;
  115.  
  116. procedure TMultiSelectUIObject.ForEach(Proc: TForEachProc; Data: Integer);
  117. var
  118.   I: Integer;
  119. begin
  120.   for I := Low(FServGuids) to High(FServGuids) do
  121.     Proc(FServGuids[I], Data);
  122. end;
  123.  
  124. function TMultiSelectUIObject.GetServGuid(Index: Integer): TGUID;
  125. begin
  126.   Result := FServGuids[Index];
  127. end;
  128.  
  129. { TContextMenu }
  130.  
  131. { TContextMenu.IContextMenu }
  132.  
  133. function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
  134.   idCmdLast, uFlags: UINT): HResult;
  135. begin
  136.   FMenuIdx := idCmdFirst;
  137.   Result := idCmdFirst;
  138.   // Add two menu items to context menu
  139.   if InsertMenu(Menu, FMenuIdx, MF_STRING or MF_BYPOSITION, idCmdFirst,
  140.     'Unregister') then
  141.     Inc(Result);
  142.   if InsertMenu(Menu, FMenuIdx + 1, MF_STRING or MF_BYPOSITION, idCmdFirst + 1,
  143.     'Properties') then
  144.     Inc(Result);
  145. end;
  146.  
  147. function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
  148. begin
  149.   Result := S_OK;
  150.   try
  151.     // Make sure we are not being called by an application
  152.     if HiWord(Integer(lpici.lpVerb)) <> 0 then
  153.     begin
  154.       Result := E_FAIL;
  155.       Exit;
  156.     end;
  157.     // Execute the command specified by lpici.lpVerb.
  158.     // Return E_INVALIDARG if we are passed an invalid argument number.
  159.     if LoWord(lpici.lpVerb) = FMenuIdx then
  160.       ForEach(UnregisterProc, 0)
  161.     else if LoWord(lpici.lpVerb) = FMenuIdx + 1 then
  162.       ForEach(ShowPropertiesProc, 0)
  163.     else
  164.       Result := E_INVALIDARG;
  165.   except
  166.     on E: TObject do
  167.       Result := Controller.SafeCallException(E, ExceptAddr);
  168.   end;
  169. end;
  170.  
  171. function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
  172.   pszName: LPSTR; cchMax: UINT): HRESULT;
  173. type
  174.   TStringType = (stVerb, stHelpString);
  175. const
  176.   CommandStrings: array[TStringType, 0..1] of PChar = (
  177.     ('Unregister', 'Properties'),
  178.     ('Unregister the selected COM server(s)',
  179.     'View the properties of the selected COM server(s)'));
  180. var
  181.   StringType: TStringType;
  182. begin
  183.   if pszName = nil then
  184.   begin
  185.     Result := E_POINTER;
  186.     Exit;
  187.   end;
  188.   Result := S_OK;
  189.   try
  190.     StrLCopy(pszName, #0#0, cchMax);  // default to empty string
  191.     if not ((idCmd = FMenuIdx) or (idCmd = FMenuIdx + 1)) then
  192.     begin
  193.       Result := E_INVALIDARG;
  194.       Exit;
  195.     end;
  196.     // check whether shell is asking for verb or a help string
  197.     if uType and GCS_VERB <> 0 then StringType := stVerb
  198.     else if uType and GCS_HELPTEXT <> 0 then StringType := stHelpString
  199.     else Exit;
  200.     // return command string for menu item
  201.     StrLCopy(pszName, CommandStrings[StringType, FMenuIdx - idCmd], cchMax)
  202.   except
  203.     on E: TObject do
  204.       Result := Controller.SafeCallException(E, ExceptAddr);
  205.   end;
  206. end;
  207.  
  208. type
  209.   TRegProc = function: HResult; stdcall;
  210.  
  211. procedure TContextMenu.UnregisterProc(const Guid: TGuid; Data: Integer);
  212. const
  213.   SUnregError = 'Unregistration Error';
  214. var
  215.   Server: string;
  216.   Handle: THandle;
  217.   RegProc: TRegProc;
  218.   SI: TStartupInfo;
  219.   PI: TProcessInformation;
  220. begin
  221.   Server := GetFileName(Guid);
  222.   if AnsiCompareText(ExtractFileExt(Server), '.dll') = 0 then
  223.   begin
  224.     Handle := LoadLibrary(PChar(Server));
  225.     if Handle <= HINSTANCE_ERROR then
  226.       MessageBox(HwndOwner, 'Could not load library', SUnregError, MB_OK);
  227.     try
  228.       RegProc := GetProcAddress(Handle, 'DllUnregisterServer');
  229.       if Assigned(RegProc) then OleCheck(RegProc)
  230.       else MessageBox(HwndOwner, 'Couldn''t unregister library', SUnregError, MB_OK);
  231.     finally
  232.       FreeLibrary(Handle);
  233.     end;
  234.   end
  235.   else if AnsiCompareText(ExtractFileExt(Server), '.exe') = 0 then
  236.   begin
  237.     FillChar(SI, SizeOf(SI), 0);
  238.     SI.cb := SizeOf(SI);
  239.     if not CreateProcess(PChar('"' + Server + '"'),
  240.       PChar('"' + Server + '" /unregserver'), nil, nil, True, 0, nil, nil,
  241.       SI, PI) then
  242.       MessageBox(HwndOwner, 'Error executing server', SUnregError, MB_OK)
  243.     else begin
  244.       CloseHandle(PI.hThread);
  245.       CloseHandle(PI.hProcess);
  246.     end;
  247.   end;
  248. end;
  249.  
  250. procedure TContextMenu.ShowPropertiesProc(const Guid: TGuid;
  251.   Data: Integer);
  252. begin
  253.   ShowRegProps(Guid);
  254. end;
  255.  
  256. { TExtractIcon }
  257.  
  258. function TExtractIcon.Extract(pszFile: PAnsiChar; nIconIndex: UINT;
  259.   out phiconLarge, phiconSmall: HICON; nIconSize: UINT): HResult;
  260. begin
  261.   // This method only needs to be implemented if the icon is stored in
  262.   // some type of user-defined data format.  Since our icon is in a
  263.   // plain old DLL, we just return S_FALSE.
  264.   Result := S_FALSE;
  265. end;
  266.  
  267. function TExtractIcon.GetIconLocation(uFlags: UINT; szIconFile: PAnsiChar;
  268.   cchMax: UINT; out piIndex: Integer; out pwFlags: UINT): HResult;
  269. var
  270.   Server, IconFile, ToolboxKey: string;
  271.   Reg: TRegistry;
  272.   CommaPos, Code: Integer;
  273. begin
  274.   Result := S_OK;
  275.   pwFlags := GIL_DONTCACHE or GIL_PERINSTANCE;
  276.   try
  277.     Server := GetFileName(ServGuid);
  278.     if AnsiCompareText(ExtractFileExt(Server), '.dll') = 0 then
  279.     begin
  280.       Reg := TRegistry.Create;
  281.       try
  282.         Reg.RootKey := HKEY_CLASSES_ROOT;
  283.         ToolboxKey := 'CLSID\' + GuidToString(ServGuid) + '\ToolboxBitmap32';
  284.         if Reg.KeyExists(ToolboxKey) then
  285.         begin
  286.           Reg.OpenKeyReadOnly(ToolboxKey);
  287.           IconFile := Reg.ReadString('');
  288.           CommaPos := LastDelimiter(',', IconFile);
  289.           if CommaPos > 0 then
  290.           begin
  291.             Val(Copy(IconFile, CommaPos + 1, Length(IconFile)), piIndex, Code);
  292.             if Code = 0 then
  293.             begin
  294.               IconFile[CommaPos] := #0;
  295.               StrLCopy(szIconFile, PChar(IconFile), cchMax);
  296.               Exit;
  297.             end;
  298.           end;
  299.         end;
  300.       finally
  301.         Reg.Free;
  302.       end;
  303.     end;
  304.     StrLCopy(szIconFile, PChar(Server), cchMax);
  305.     piIndex := 0;
  306.   except
  307.     on E: TObject do
  308.       Result := Controller.SafeCallException(E, ExceptAddr);
  309.   end;
  310. end;
  311.  
  312. end.
  313.  
  314.