Windows 如何使用Delphi获取与文件扩展名关联的程序名?

Windows 如何使用Delphi获取与文件扩展名关联的程序名?,windows,delphi,registry,file-type,file-association,Windows,Delphi,Registry,File Type,File Association,我需要获取当前用户当前与文件扩展名关联的程序的名称。如果右键单击某个文件并选择“属性”,那么我需要的是“打开方式”行右侧的程序名 e、 g.对于“.xls”,我希望能够得到答案“MicrosoftOfficeExcel”,或者任何用户作为默认程序打开.xls文件的程序 我已经确定,这并不像进入HKEY_类_根目录并将其挑选出来那么简单,因为它也可能在HKEY_本地_机器或HKEY_当前_用户或HKEY_用户中指定 也许我只需要知道Windows用来确定这一点的啄食顺序,以及如何到达每个位置。当然

我需要获取当前用户当前与文件扩展名关联的程序的名称。如果右键单击某个文件并选择“属性”,那么我需要的是“打开方式”行右侧的程序名

e、 g.对于“.xls”,我希望能够得到答案“MicrosoftOfficeExcel”,或者任何用户作为默认程序打开.xls文件的程序

我已经确定,这并不像进入HKEY_类_根目录并将其挑选出来那么简单,因为它也可能在HKEY_本地_机器或HKEY_当前_用户或HKEY_用户中指定

也许我只需要知道Windows用来确定这一点的啄食顺序,以及如何到达每个位置。当然,一个Windows API调用来实现这一点是理想的

这是一个类似的问题: 但这个问题只回答了如何获得扩展名的描述和相关程序的图标。我找不到一种方法来扩展它,以获得相关程序的名称

我正在使用Delphi 2009,需要一个在Windows XP、Vista和7上运行的解决方案


谢谢大家的回答

看来我认为可执行文件的名称根本不在注册表中。在到处寻找一个能给出这个名字的Windows API之后,我找不到一个

我认为Mef的答案是最好的。从程序可执行文件中包含的信息中获取可执行文件的名称



后续:我发现它提供了一个很好的解决方案,可以在不同的扩展中使用默认程序打开一个程序。

这篇文章怎么样:

在Excel的具体案例中,您将在HKEY_CLASSES_根目录下找到扩展名
.xls
——该条目的默认值为
Excel.Sheet.8

当您再次在HKEY_CLASSES_根目录中搜索
Excel.Sheet.8
时,您会发现一个默认值为
Microsoft Office Excel 97-2003工作表的条目
——这可能是它得到的最好结果

第一步 获取分配给文件扩展名的可执行文件,例如,使用以下函数:

uses Registry, Windows, SysUtils;

function GetAssociation(const DocFileName: string): string;
var
  FileClass: string;
  Reg: TRegistry;
begin
  Result := '';
  Reg := TRegistry.Create(KEY_EXECUTE);
  Reg.RootKey := HKEY_CLASSES_ROOT;
  FileClass := '';
  if Reg.OpenKeyReadOnly(ExtractFileExt(DocFileName)) then
  begin
    FileClass := Reg.ReadString('');
    Reg.CloseKey;
  end;
  if FileClass <> '' then begin
    if Reg.OpenKeyReadOnly(FileClass + '\Shell\Open\Command') then
    begin
      Result := Reg.ReadString('');
      Reg.CloseKey;
    end;
  end;
  Reg.Free;
end;

但是,您必须注意,一些程序因此使用描述码(如RAD Studio本身或MS Excel),而其他程序则使用产品名称码…

Delphi附带一个单元ShellApi.pas,该单元在下面的示例代码中使用。该文件必须存在

以下是如何使用它:

function MyShellFindExecutable(const aFileName: string): string;
var
  Buffer: array[0..WINDOWS.MAX_PATH] of Char;
begin
  Result := '';
  FillChar(Buffer, SizeOf(Buffer), #0);
  if (SHELLAPI.FindExecutable(PChar(aFileName), nil, Buffer) > 32) then
    Result := Buffer;
end;

当有API函数被设计用来做你需要的事情时,不要去探索注册表

在你的情况下,你想要。您可以给它文件扩展名,它会告诉您注册的程序如何处理该扩展名(
AssocStr\u Executable
)。如果您计划运行该程序来打开文档,那么您将真正需要命令字符串,而不仅仅是可执行文件
AssocQueryString
也可以为您提供此功能(
AssocStr\u命令
)。它还可以告诉您文档类型,如Windows资源管理器中显示的内容,如“文本文档”或“Zip存档”(
AssocStr\u FriendlyDocName


该API函数是接口的包装器。如果您正在寻找来自多种文件类型的程序,或与单一类型关联的大量字符串,您可能希望实例化该接口并重新使用它,而不是反复调用API函数。

我认为您需要结合Mef和Rob Kennedy的答案

按照罗布·肯尼迪的答案,从Mef的答案中选择第二步。直接阅读注册表不是一件好事,所以你应该扔掉他的第1部分

但我不是在寻找文件类型的友好名称

AssocQueryString不仅返回文件类型()的友好名称,还可以返回打开文件()的可执行文件的名称-这就是您所需要的

更重要的是:我不确定,但可能会符合你的需要。在这种情况下,你可以只使用罗布·肯尼迪的答案

直接读取注册表的问题是它可能返回错误的信息。这是因为您读取了系统设置-这是应用程序注册的内容。但用户可以覆盖此选项。例如,他可以右键单击.xls并选择“打开…”->“其他应用程序”。->“OpenOffice”->“始终使用此应用程序”。.xls类型的注册信息不会被更改(用户首选项保存在单独的位置,因此应用程序不会弄乱它们),因此您的代码(直接读取注册表)将继续生成“MS Excel”,即使用户双击文件-OpenOffice将启动。

如果用户说“始终使用此应用程序”对于.xls文件,信息列表存储在

HK_CU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xls

密钥有一个条目“Application”,其中包含应用程序名称(例如“soffice.exe”)。它与HK\U CR中的应用程序密钥相关,例如
HK\U CR\Applications\soffice.exe\

,谢谢。我在搜索中没有看到那篇文章。但实际上它有两个问题。(1) 它只使用HKEY_CLASSES_ROOT,不一定是Windows将使用的位置(请参阅我在问题中提到的其他位置),并且(2)它提供了可执行程序的路径。但我实际上需要的是该程序的名称,而不是它的路径。实际上HKEY_CLASSES_ROOT是HKEY_CURRENT_USER\Software\CLASSES和HKEY_LOCAL_MACHINE\Software\CLASSES(按顺序)的合并视图,所以它是Windows将使用的位置。@marc_s:你的想法是对的。但是“MicrosoftOfficeExcel97-2003工作表”的值仍然描述了文档。我需要程序名。当我搜索时,我可以在“HKCR\Local Settings\Software\Microsoft\Windows\Shell\MuiCache”中找到它,它的值为“Microsoft Office Excel”,与文件路径关联。它也在我的64位机器上的“\HKCR\Wow6432Node\Local Settings\Software\Microsoft\Windows\SHell\MuiCache”中,它也在HKCU中,也可能在elsewh中
HK_CU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xls