Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the Name of the Program associated with a file extension using Delphi?

I need to get the name of the program currently associated with a file extension for the current user. If you right-click on a file and select properties, then what I need is the program name that is to the right of the "Opens with" line.

e.g. For ".xls", I want to be able to get the answer "Microsoft Office Excel", or whatever program the user has as their default program to open .xls files.

I have determined it's not as easy as just going into HKEY_CLASSES_ROOT and picking it out, since it may also be specified in HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER or HKEY_USERS.

Maybe all I need to know is the pecking order used by Windows to determine this and how to get to each of the locations. Of course, a Windows API call to do this would be ideal.

This is a similar question to: How to get icon and description from file extension using Delphi? but that question only answered how to get the description of the extension and the icon of the associated program. I couldn't find a way to extend that to also get the name of the associated program.

I'm using Delphi 2009 and need a solution that works on Windows XP, Vista and 7.


Thank you all for your answers.

It appears my belief that the name of the executable is not in the Registry after all. And after looking around extensively for a Windows API that will give the name, I could not find one.

I think Mef's answer then is the best. To get the name of the executable from the information included in the program's executable.


Followup: I found David Hefferman's answer to "How do I open a file with the default text editor?" gives an excellent solution for opening one program using the default program for a different extension.

like image 491
lkessler Avatar asked Apr 05 '10 06:04

lkessler


5 Answers

Delphi comes with a unit ShellApi.pas that is used in the sample code below. The file has to exist.

Here's how to use it:

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;
like image 149
RobertFrank Avatar answered Oct 17 '22 05:10

RobertFrank


Don't go spelunking in the registry when there are API functions designed to do what you need.

In your case, you want AssocQueryString. You can give it the file-name extension, and it will tell your the program registered to handle that extension (AssocStr_Executable). If you're planning on running that program to open a document, then you'll really want the command string instead of just the executable; AssocQueryString can give you that, too (AssocStr_Command). It can also tell you the document type like what's displayed in Windows Explorer, like "Text Document" or "Zip Archive" (AssocStr_FriendlyDocName).

That API function is a wrapper for the IQueryAssociations interface. If you're looking for programs from many file types, or lots of strings associated with a single type, you may wish to instantiate that interface and re-use it instead of calling the API function over and over.

like image 26
Rob Kennedy Avatar answered Oct 17 '22 05:10

Rob Kennedy


Step 1

Get the executable which is assigned to a file extension, for instance with the following function:

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;

(See here, or marc_s' anwser to this question :-)

Step 2

Now you can read out the name of the program from the version information of this executable! The easiest way is using the TVersionInfo class you can find via Google, for instance here.

var VersionInfo: TVersionInfo;  
VersionInfo := TVersionInfo.Create('PathToExe\name.exe');  
s := VersionInfo.KeyValue['Description'];

However, you have to be aware that some programs use the description key therefore (like RAD Studio itself or MS Excel), while others use the product name key...

like image 39
Leo Avatar answered Oct 17 '22 07:10

Leo


I think that you need to combine Mef's and Rob Kennedy's answers.

Take Rob Kennedy's answer and take step 2 from Mef's answer. Reading registry directly isn't good thing to do, so you should throw away his part 1.

But I'm not looking for the friendly name of the file type.

AssocQueryString returns not only friendly name for file type (ASSOCSTR_FRIENDLYDOCNAME), but also it can return the name of executable to open file (ASSOCSTR_EXECUTABLE) - that is what you need.

Even more than that: I'm not sure, but may be ASSOCSTR_FRIENDLYAPPNAME will match your needs. In that case, you may use only Rob Kennedy's answer.

The problem with reading registry directly is that it may return wrong info. That's because you read system settings - that is what application registered. But user may override this. For example, he may right click on .xls and select "Open with..." -> "Other app." -> "OpenOffice" -> "Use this app always". Registration info for .xls type will not be altered (user preferences are saved in separate place, so apps can't mess with them), so your code (which reads registry directly) will continue to produce "MS Excel", even though when user double-clicks on file - OpenOffice will be launched.

like image 44
Alex Avatar answered Oct 17 '22 05:10

Alex


How about this article here: Determining the associated application

In the concrete case of Excel, you will find the .xls extension under HKEY_CLASSES_ROOT - the default value of that entry is Excel.Sheet.8.

When you go search for Excel.Sheet.8 again in HKEY_CLASSES_ROOT, you'll find an entry with a default value of Microsoft Office Excel 97-2003 Worksheet - that's probably as good as it gets.

like image 3
marc_s Avatar answered Oct 17 '22 06:10

marc_s