1

From my admin installer I call SHGetKnownFolderPath(FOLDERID_LocalAppData) because I want to install to LocalAppData (I need write access to the installation directory).

This is ok when the current user is an administrator, the user gets the UAC prompt and proceeds.

However, if the current user is not an administrator, the user gets the UAC prompt, fills username+password and then this function returns the admin account's LocalAppData, not the current users'.

How can I get the current user's folder at all times?

Or, how to check if the current user was not an admin (so it had to enter credentials) so to suggest another installation location?

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • Why does the user get an uac prompt for their own folder – Daniel A. White Jul 19 '23 at 01:49
  • @DanielA.White the app requires administrator privileges. – Michael Chourdakis Jul 19 '23 at 01:50
  • Can't you just grab all the required folder locations when your app starts up, before you invoke UAC? – paddy Jul 19 '23 at 02:40
  • @paddy the app starts as admin at startup (requireAdministrator in manifest) – Michael Chourdakis Jul 19 '23 at 03:05
  • 1
    In that case, it probably boils down to supplying the appropriate access token. See relevant discussion about the `hToken` parameter for [SHGetKnownFolderPath](https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath). Looking at other processes on my system that are invoked with UAC, they still show in Task Manager with my username, so I would expect you can probably get at it easily. Check out [OpenProcessToken](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken). – paddy Jul 19 '23 at 04:28
  • "check if the current user was not an admin" you could refer to the thread: https://stackoverflow.com/questions/65038995/checking-if-the-current-user-is-in-the-administrator-group-with-winapi – Jeaninez - MSFT Jul 19 '23 at 07:52

1 Answers1

1
#include <initguid.h>
#include <knownfolders.h>
#include <shlobj_core.h>

HRESULT GetKnownFolderPath(_Outptr_ PWSTR *ppszPath, _In_ REFKNOWNFOLDERID rfid)
{
    if (HWND hwnd = GetShellWindow())
    {
        ULONG dwProcessId;
        if (GetWindowThreadProcessId(hwnd, &dwProcessId))
        {
            if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId))
            {
                HANDLE hToken;

                BOOL fOk = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken);
                
                CloseHandle(hProcess);

                if (fOk)
                {
                    HRESULT hr = SHGetKnownFolderPath(rfid, 0, hToken, ppszPath);

                    CloseHandle(hToken);

                    return hr;
                }
            }
        }

        return HRESULT_FROM_WIN32(GetLastError());
    }

    return E_FAIL;
}

    PWSTR pszPath;
    if (0 <= GetKnownFolderPath(&pszPath, FOLDERID_LocalAppData))
    {
        DbgPrint("%S\n", pszPath);
        CoTaskMemFree(pszPath);
    }
RbMm
  • 31,280
  • 3
  • 35
  • 56