Jeka
Jeka

Reputation: 1384

Get executable path with AssocQueryString in C++

Helo! I need to query application full path in C++, like "meshlab" -> "C:\Program Files\VCG\MeshLab\meshlab.exe"

This information is present in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths, but I don't want to work with registry directly, so I am using AssocQueryString like this:

#include "pch.h"
#include <iostream>
#include <Windows.h>

#include <Shlwapi.h>

int main()
{
    char* executablePath = nullptr;
    DWORD executablePathLen = 0;
    std::string shortName = "mspaint";

    HRESULT res = AssocQueryStringA(ASSOCF_OPEN_BYEXENAME,
        ASSOCSTR_EXECUTABLE,
        shortName.c_str(),
        NULL,
        executablePath,
        &executablePathLen);

    executablePath = new char[executablePathLen];



    res = AssocQueryStringA(ASSOCF_OPEN_BYEXENAME,
        ASSOCSTR_EXECUTABLE,
        shortName.c_str(),
        NULL,
        executablePath,
        &executablePathLen);

    std::cout << executablePath; // prints: C:\Windows\system32\mspaint.exe
    delete[] executablePath;
    std::cin.get();
}

For mspaint it works as expected, but for meshlab it doesn't. HRESULT is ERROR_NO_ASSOCIATION

Any ideas what I missed?

UPDATE: Also works well with foobar200 from C:\Program Files (x86)\foobar2000\foobar2000.exe I suspect it must be related to 32/64 bit registry. I am using Windows 10 64 bit, and my application is 64 bit

Upvotes: 0

Views: 1338

Answers (1)

Anders
Anders

Reputation: 101609

I believe ASSOCF_OPEN_BYEXENAME:ASSOCSTR_EXECUTABLE searches HKEY_CLASSES_ROOT\Applications.

ShellExecuteEx searches the "normal directories" and the App Paths key:

Finding an Application Executable

When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey. Doing so avoids the need for applications to modify the system PATH environment variable.

The file is sought in the following locations:

  • The current working directory.

  • The Windows directory only (no subdirectories are searched).

  • The Windows\System32 directory.

  • Directories listed in the PATH environment variable.

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

(HKEY_CURRENT_USER is also used on recent versions of Windows)

The Assoc API is more focused on file associations.

If you are just going to execute the file then you should just use ShellExecuteEx. If you just want to find the fully qualified path you can use some helper functions to do some of the work for you:

FindExecutable seems promising but it has some compatibility workarounds and it will also find the executable used to open registered types (c:\foo\bar.txt might resolve to c:\Windows\Notepad.exe etc. because it uses ASSOCSTR_EXECUTABLE),

If you want to look for extensions like .exe and .bat automatically you can use PathResolve(..., PRF_REQUIREABSOLUTE|PRF_VERIFYEXISTS|PRF_TRYPROGRAMEXTENSIONS|PRF_DONTFINDLNK) but you must be careful that the search string does not contain \ nor :.

If you only want to look for a .exe you must manually append the extension if it is not present and then call PathFindOnPath(, NULL).

Neither of these functions looks in the App Paths key, they do not use the exact same search order as ShellExecuteEx (system32 before %windir%?) and they are most likely limited to MAX_PATH.

If those functions (or your own equivalent version) fail then you can check the App Paths key. When reading from the registry you must append .exe if there is no extension and use a helper function like SHQueryValueEx that will expand REG_EXPAND_SZ strings.

Upvotes: 2

Related Questions