How to unregister a File Format for my application?

Viewed 164

In a Delphi 10.4.2 win-32 VCL Application in Windows 10, I register the .ICO file format for my graphics application by using DSiWin32.DSiRegisterUserFileAssoc:

DSiRegisterUserFileAssoc(
    '.ico',                                              // extension: .ico
    'UGAICOFile',                                        // progID: UGAICOFile
    'ICO File',                                          // description: ICO File
    'C:\DELPHI\MyApp\MyApp.ico',                         // Icon File
    '"C:\DELPHI\MyApp\Win32\Debug\MyApp.exe" "%1"'       // openCommand
    );

SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);

This works without problems and when double-clicking an .ICO file in Windows File Explorer my app loads the .ICO file. These Registry keys have been created WITH THE CORRECT VALUES:

enter image description here

enter image description here

HOWEVER, when I try to UNREGISTER the .ICO file format for my graphics application by using DSiWin32.DSiUnregisterUserFileAssoc, it does not work:

procedure TForm1.btnUnregisterClick(Sender: TObject);
begin
  DSiUnregisterUserFileAssoc('UGAICOFile');
  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
end;

The UGAICOFile progID key is not being deleted from the Registry! And double-clicking an .ICO file in File Explorer still loads my app!

Even when I try it in elevated mode (by starting the program as Administrator) it does not work! Could it be that that the Microsoft apps registered under .ico\OpenWithProgrids could stop the key from being removed?

So how can I UNREGISTER the registered .ICO File Format for my application?

1 Answers

The problem seems to be the DSiUnregisterUserFileAssoc function not obtaining the required access level to the registry.

One of my rules of thumb when programming is to never use third-party libraries unless absolutely necessary, partly because you don't know all the details about them. And in this case, I don't quite see the point in adding a fairly large library just to do a few simple registry changes!

Making an association manually is trivial:

var Reg := TRegistry.Create;
try
  Reg.RootKey := HKEY_CURRENT_USER;
  if Reg.OpenKey('\Software\Classes\.myfile', True) then
    Reg.WriteString('', 'MyAppDataFile');
  if Reg.OpenKey('\Software\Classes\MyAppDataFile', True) then
    Reg.WriteString('', 'My Very Own Text File Type');
  if Reg.OpenKey('\Software\Classes\MyAppDataFile\DefaultIcon', True) then
    Reg.WriteString('', 'C:\WINDOWS\notepad.exe');
  if Reg.OpenKey('\Software\Classes\MyAppDataFile\shell\open\command', True) then
    Reg.WriteString('', 'C:\WINDOWS\notepad.exe "%1"');
finally
  Reg.Free;
end;
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);

And so is removing it:

var Reg := TRegistry.Create;
try
  Reg.RootKey := HKEY_CURRENT_USER;
  Reg.DeleteKey('\Software\Classes\MyAppDataFile');
finally
  Reg.Free;
end;
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);

This works, it requires no additional library (with a lot of things you don't need, potential security issues, potential bugs, etc.), and you know exactly what the code does. You have 100% understanding of it.


I was able to make the DSi function work by changing it to this:

DSiKillRegistry('\Software\Classes\' + progID, HKEY_CURRENT_USER, KEY_ALL_ACCESS);
Related