About the author
Raymond Chen wrote the original blog posts on enumerating all the programs that can launch a particular protocol and enumerating all the programs that can open a particular file extension.
I translated it to Delphi. The application below does 2 things: launching a web browser on Embarcadero and opening win.ini as a text file.
program Handlers; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Generics.Collections, Winapi.ShlObj, System.Types, Winapi.ActiveX, idoc; function GetUIObjectOfFile(Handle: THandle; const Path: string; const RIID: TGUID; var P): Boolean; var ppidl, pidlChild: PItemIDList; psfgaoOut: DWORD; LShellFolder: IShellFolder; begin Result := False; if Succeeded(SHParseDisplayName(PChar(Path), nil, ppidl, 0, psfgaoOut)) then begin if Succeeded(SHBindToParent(ppidl, IID_IShellFolder, Pointer(LShellFolder), pidlChild)) then begin Result := Succeeded(LShellFolder.GetUIObjectOf(Handle, 1, pidlChild, RIID, nil, Pointer(P))); end; CoTaskMemFree(ppidl); end; end; function LoadExtHandlers(const extension: string; filter: ASSOC_FILTER): TList<IAssocHandler> var enumerator: IEnumAssocHandlers; Fetched: Cardinal; handler: IAssocHandler; LName: PChar; begin Result := nil; SHAssocEnumHandlers(PChar(extension), filter, enumerator); repeat Fetched := 0; enumerator.Next(1, handler, Fetched); if Fetched<>0 then begin handler.GetName(LName); WriteLn('Handler: ', LName); if not Assigned(Result) then Result := TList.Create; Result.Add(handler); end; until Fetched = 0; end; function LoadProtocolHandlers(const protocol: string; filter: ASSOC_FILTER): TList<IAssocHandler>; var enumerator: IEnumAssocHandlers; AliasToEnumerator: Pointer absolute enumerator; Fetched: Cardinal; handler: IAssocHandler; LName: PChar; begin Result := nil; SHAssocEnumHandlersForProtocolByApplication(PChar(protocol), IID_IEnumAssocHandlers, AliasToEnumerator); repeat Fetched := 0; enumerator.Next(1, handler, Fetched); if Fetched<>0 then begin handler.GetName(LName); WriteLn('Handler: ', LName); if not Assigned(Result) then Result := TList.Create; Result.Add(handler); end; until Fetched = 0; end; var LProtocolHandlers, LExtHandlers: TList<IAssocHandler>; LDataObject: IDataObject; selection: Integer; begin selection := 0; LProtocolHandlers := LoadProtocolHandlers('http', ASSOC_FILTER_RECOMMENDED); GetUIObjectOfFile(0, 'http://www.embarcadero.com', IID_IDataObject, LDataObject); LProtocolHandlers[selection].Invoke(LDataObject); LProtocolHandlers.Free; LExtHandlers := LoadExtHandlers('.txt', ASSOC_FILTER_RECOMMENDED); GetUIObjectOfFile(0, 'C:\windows\win.ini', IID_IDataObject, LDataObject); LExtHandlers[selection].Invoke(LDataObject); LExtHandlers.Free; end.
Continued discussion of undocumented Delphi 8 Property Access Specifiers, and other ways of adding and removing delegates / events handlers, including clearing the list of all the delegates / event handlers.
This article discusses the new Delphi 8 property access specifiers.
A method pointer is now the same as a global procedure, ie, procedure of object = procedure.