I'm using AssocQueryString in order to get the executable associated to certain extensions.
It works good for extensions like .pdf and .txt. But I've noticed that it doesn't return anything for all image extensions I've tried (.bmp, .png, .jpg, .ico).
uses
ShLwApi, Windows, Dialogs;
const
// ASSOCF enumerated values mapped to integer constants
ASSOCF_INIT_NOREMAPCLSID = $00000001;
ASSOCF_INIT_BYEXENAME = $00000002;
ASSOCF_OPEN_BYEXENAME = $00000002;
ASSOCF_INIT_DEFAULTTOSTAR = $00000004;
ASSOCF_INIT_DEFAULTTOFOLDER = $00000008;
ASSOCF_NOUSERSETTINGS = $00000010;
ASSOCF_NOTRUNCATE = $00000020;
ASSOCF_VERIFY = $00000040;
ASSOCF_REMAPRUNDLL = $00000080;
ASSOCF_NOFIXUPS = $00000100;
ASSOCF_IGNOREBASECLASS = $00000200;
var
Buffer: array [0..1024] of char;
BufSize: DWord;
begin
BufSize := Sizeof(Buffer);
Buffer[0] := #0;
AssocQueryString(
ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
'open',
Buffer,
@BufSize
);
ShowMessage(Buffer);
end;
Further informations:
It also works with image extensions, but only if asking for the executable associated to 'edit' instead of 'open'.
Double-clicking on a .bmp file causes the file is opened with the default Windows 10 photo viewer.
Update
Currently, my code is:
var
Buffer: array [0..1024] of Char;
BufSize: DWord;
Res: HResult;
begin
BufSize := Length(Buffer);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
(*ASSOCSTR_DELEGATEEXECUTE missing on Delphi 2007*) 18,
'.bmp',
nil,
Buffer,
@BufSize
);
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res) + sLineBreak + SysErrorMessage(Res));
It shows "{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}". How to have the same result seen on Windows 7? (A dll or an executable filename)
Furthermore, I noticed that after changing .bmp into an non-existent (like '.abcde') return a similar result. For this I can't even know if there's an associated program.
As stated in comments, your machine's registrations for image file extensions are not using an application to open the files, they are using a DLL invoked by Rundll32 instead.
Per the ASSOCSTR documentation:
ASSOCSTR_EXECUTABLE
An executable from a Shell verb command string. For example, this string is found as the (Default) value for a subkey such asHKEY_CLASSES_ROOT\ApplicationName\shell\Open\command. If the command uses Rundll.exe, set the ASSOCF_REMAPRUNDLL flag in the flags parameter of IQueryAssociations::GetString to retrieve the target executable.Caution
Not all app associations have executables. Do not assume that an executable will always be present.
Per the ASSOCF documentation:
ASSOCF_REMAPRUNDLL
InstructsIQueryAssociationsmethods to ignoreRundll.exeand return information about its target. TypicallyIQueryAssociationsmethods return information about the first.exeor.dllin a command string. If a command usesRundll.exe, setting this flag tells the method to ignoreRundll.exeand return information about its target.
Also, when calling AssocQueryString(), try setting the pszExtra parameter to NULL instead of a specific verb.
Also, pay attention to the documentation for the last parameter of AssocQueryString():
cchOut [in, out]
Type: DWORD*A pointer to a value that, when calling the function, is set to the number of characters in the pszOut buffer. When the function returns successfully, the value is set to the number of characters actually placed in the buffer.
You are setting your BufSize variable to a byte count not a character count. Your code is assuming Sizeof(Char) is 1, but that is only true in Delphi 2007 and earlier. In Delphi 2009 and later, Sizeof(Char) is 2 instead.
And always check return values for errors.
Try this:
var
Buffer: array [0..1024] of Char;
BufSize: DWord;
Res: HResult;
begin
BufSize := Length(Buffer);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
Buffer,
@BufSize
);
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res));
end;
Alternatively:
var
Buffer: string;
BufSize: DWord;
Res: HResult;
begin
BufSize := 0;
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
nil,
@BufSize
);
if Res = S_FALSE then
begin
SetLength(Buffer, BufSize-1);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
PChar(Buffer),
@BufSize
);
end;
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res));
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With