如何为我的应用程序注销文件格式?

How to unregister a File Format for my application?

在 Delphi 10.4.2 win-32 VCL 应用程序 Windows 10 中,我使用 DSiWin32.DSiRegisterUserFileAssoc 为我的图形应用程序注册了 .ICO 文件格式:

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);

这没有问题,当在 Windows 文件资源管理器中双击 .ICO 文件时,我的应用程序会加载 .ICO 文件。这些注册表项是使用正确的值创建的:

但是,当我尝试使用 DSiWin32.DSiUnregisterUserFileAssoc 取消注册我的图形应用程序的 .ICO 文件格式时,它不起作用:

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

UGAICOFile progID 项未从注册表中删除!在文件资源管理器中双击 .ICO 文件仍然会加载我的应用程序!

即使我在提升模式下尝试(通过以管理员身份启动程序)它也不起作用!难道是在 .ico\OpenWithProgrids 下注册的 Microsoft 应用程序可以阻止密钥被删除?

那么如何取消注册已注册的 .ICO 应用程序文件格式?

问题似乎是 DSiUnregisterUserFileAssoc 函数没有获得所需的注册表访问级别。

我在编程时的经验法则之一是除非绝对必要,否则永远不要使用第三方库,部分原因是您不了解有关它们的所有细节。在这种情况下,我不太明白添加一个相当大的库只是为了做一些简单的注册表更改有什么意义!

Making an association manually 很简单:

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);

删除它也是如此:

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);

这行得通,它不需要额外的库(有很多你不需要的东西、潜在的安全问题、潜在的错误等),而且你确切地知道代码的作用。你已经100%了解它了。


我可以通过将其更改为以下内容来使 DSi 功能正常工作:

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