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.
Learn why the map is cool in Go!
A method to design records so that they're allocated on a specific byte boundary, such as 16 bytes, 512 bytes, 4096 bytes, etc.
Learn the command line used to compile System.pas in Delphi
How to free more space on your home drive by redirecting the location for SDKs in RAD Studio