0

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

Jeka
  • 1,364
  • 17
  • 33
  • What is the return value from AssocQueryStringA and what does `&executablePathLen` result in after the function call is made? – Irelia May 10 '19 at 16:25
  • Not every program has to list itself in the registry. Are you sure that meshlab does? Search your local registry and see where exactly. The key name might be something other than "meshlab". In general, finding third party executables on Windows is not an exact science, especially if they were not built with programmatic access in mind in the first place. – Seva Alekseyev May 10 '19 at 16:30
  • @SevaAlekseyev as I sad information is present in registry – Jeka May 10 '19 at 16:39
  • @Nina executablePathLen is zero; HRESULT is ERROR_NO_ASSOCIATION – Jeka May 10 '19 at 16:42
  • I'm pretty sure it doesn't search under `App Paths`, the extension/protocol associations are under HKEY_CLASSES_ROOT. Is meshlab present **there**? And what's wrong with querying the registry directly? – Seva Alekseyev May 10 '19 at 16:44
  • @SevaAlekseyev meshlab is not present in HCR. Nothing wrong, just interesting to use API method, in case if registry structure will change some day, or if there any many such places – Jeka May 10 '19 at 16:54
  • 1
    ERROR_NO_ASSOCIATION is a pretty strong signal – David Heffernan May 10 '19 at 16:58
  • Well then, read from `App Paths`. OBTW, meshlab has a command line tool, meshlabserver, which might be easier to work with. – Seva Alekseyev May 10 '19 at 17:04
  • @SevaAlekseyev looks like I will forced to use App Paths, I am just curious if ShellExecuteEx uses App Paths to resolve exe, there should be something simmilar to query path – Jeka May 10 '19 at 17:09
  • 1
    Run ShellExecuteEx with Procmon, see what does it read. OBTW, any chance maybe that meshlab is in PATH? – Seva Alekseyev May 10 '19 at 17:11
  • @SevaAlekseyev no meshlab is not in Path, I just checked. +1 for Procmon – Jeka May 10 '19 at 17:18
  • @Jeka "*I am just curious if ShellExecuteEx uses App Paths to resolve exe*" - [yes, it does](https://learn.microsoft.com/en-us/windows/desktop/shell/app-registration#finding-an-application-executable) (amongst other things). – Remy Lebeau May 11 '19 at 03:11

1 Answers1

1

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.

Community
  • 1
  • 1
Anders
  • 97,548
  • 12
  • 110
  • 164