The FindExecutable
function looks up the executable responsible for launching a particular file. This is a dubious undertaking, because it assumes that the thing that launches a file is an executable. There are other things capable of launching a file, such as a DDE command, a context menu shell extension, or a custom drop target. What should FindExecutable
return in those cases?
Okay, so if FindExecutable
is based upon a flawed assumption, why does it even exist?
Because at the time it was originally introduced, the assumption was valid.
The FindExecutable
function comes from 16-bit Windows, and back in those days, there were no context menu shell extensions or custom drop targets. (There was DDE, but that’s okay, because programs still have to register an executable to be used in the fallback case when nobody responds to the DDE message.)
In the port to 32-bit Windows, the FindExecutable
function remains, but it works only in the case where files were registered in the 16-bit way; that is, with a command line executable. It so happens that most file types are still registered that way, so the FindExecutable
function basically still works.
Since the FindExecutable
function is basically a throwback to 16-bit Windows, there is another attempt to accommodate the 16-bit world that is not as obvious: The FindExecutable
function takes the thing you pass and converts it into a short file name before trying to look up the handler.
The effect of the conversion to a short file name depends on a bunch of things.
If the volume does not have short file name autogeneration enabled, then the conversion to a short file name has no effect. But if the volume does have short file name autogeneration enabled, then the net effect is that the extension gets truncated to three characters. foo.abcde
becomes foo~1.abc
. And then FindExecutable
looks up and returns the handler for the .abc
extension instead of the .abcde
extension.
Back in the days before long file names, all file extensions were truncated to 3 characters. if you asked for foo.abcde
, you got foo.abc
. The FindExecutable
function tries to maintain this compatibility with older applications. Newer applications shouldn’t be using FindExecutable
anyway, seeing as the handler for a file type may not even be an executable.
I accept that the concept of finding the executable associated with a file is flawed in the face of handlers that do not take the form of an executable, but I still want to get the executable associated with a file, if possible, with the understanding that the answer may be incorrect.
You can use the AssocQueryString
function to get the executable associated with the default verb of a file extension, if one exists.
HRESULT FindExecutableAssociatedWithFileExtension( _In_ PCWSTR extension, _Out_ PWSTR resultBuffer, _In_ DWORD bufferLength) { return AssocQueryString(ASSOCF_INIT_INGORENUNKNOWN, ASSOCSTR_EXECUTABLE, fullPath, nullptr, resultBuffer, &bufferLength); }
The ASSOCF_INIT_UNKNOWN
flag says that if the file extension has no handler, don’t return the “Open unknown file” handler.
This is not exactly the same as FindExecutable
because that function has special-case code for when you pass in, for example, excel.exe
. In those cases, the FindExecutable
function just returns the file itself, since executables are their own handlers.
The ASSOCF_INIT_UNKNOWN
flag was added in Windows 7. What do you do for older versions of Windows? Well, you’re in luck. Older versions of Windows didn’t have the “Open unknown file” handler, so if there is no registered handler, the call will simply fail. (Indeed, the introduction of the “Open unknown file” handler is what most likely prompted the creation of the ASSOCF_INIT_UNKNOWN
flag in the first place.) As a second mark of good fortune, the flag is ignored by older versions of Windows, so you can go ahead and pass the flag unconditionally: On versions of Windows that support it, it does what you want. And on versions of Windows that don’t support it, they already behave the way you want by default.
0 comments