0

I know I can use GetSystemDirectory() to get the directory of C:\Windows\System32, but I'm wondering if there's a way to get this directory path below regardless of how the OS is localized or whether I'm running as a normal user or the SYSTEM account:

C:\Windows\System32\config\systemprofile\AppData\Local\TEMP

Or at least as far as C:\Windows\System32\config\systemprofile\AppData

I tried using the SHGFP_TYPE_DEFAULT instead of SHGFP_TYPE_CURRENT option for SHGetFolderPath() but this will return the currently running user's directory instead of SYSTEM's when not running as SYSTEM.

void GetUserLocalTempPath(std::wstring& input_parameter) {
    HWND folder_handle = { 0 };
    WCHAR temp_path[MAX_PATH];
    auto get_folder = SHGetFolderPath(
        folder_handle, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, temp_path
    );
    if (get_folder == S_OK) {
        input_parameter = static_cast<const wchar_t*>(temp_path);
        input_parameter.append(L"\\TEMP");
        CloseHandle(folder_handle);
    }
}
kayleeFrye_onDeck
  • 6,648
  • 5
  • 69
  • 80
  • not clear in what is problem/question. you can get file path as is – RbMm Apr 16 '19 at 18:58
  • not clear what you're not clear about @RbMm. Are you saying localization doesn't matter and that it will always be in English? – kayleeFrye_onDeck Apr 16 '19 at 19:01
  • but function return to you filesystem path. as is. what localization you want here ? – RbMm Apr 16 '19 at 19:09
  • I don't know if this part of the path, `config\systemprofile\AppData` is ever translated, or always in English. If it's not always in English, then I need to find out how to get this part of the path, otherwise the answer to this question is, just use `GetSystemDirectory()` and append `L"\\config\\systemprofile\\AppData"` to it. – kayleeFrye_onDeck Apr 16 '19 at 20:15
  • 2
    no, correct way use `CSIDL_LOCAL_APPDATA` or `SHGetKnownFolderPath` with `FOLDERID_LocalAppData` with localsystem token or when you run/impersonate localsystem. you not need hardcode `L"\\config\\systemprofile\\AppData"` – RbMm Apr 16 '19 at 20:19
  • Okay. So could you please leave an answer then on how to do that? :) – kayleeFrye_onDeck Apr 16 '19 at 20:24
  • 1
    but `SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, SHGFP_TYPE_CURRENT, temp_path)` for example (if you run as *LocalSystem*) how you use `folder_handle` not correct - this is hwnd and in only parameter. the `CloseHandle(folder_handle);` of course wrong – RbMm Apr 16 '19 at 20:42
  • Okay. Maybe show me this stuff in an answer? – kayleeFrye_onDeck Apr 16 '19 at 21:19
  • but are you running as *LocalSystem* ? or have *LocalSystem* token ? from which context you try get this path ? are you elevated app at all ? – RbMm Apr 16 '19 at 21:22
  • The question states that I need to get this path _regardless_ of the user that launches this app and I don't know anything about this token stuff you're talking about. – kayleeFrye_onDeck Apr 16 '19 at 21:26
  • It doesn't appear what you're proposing is even possible :( https://stackoverflow.com/a/2992245/3543437 – kayleeFrye_onDeck Apr 16 '19 at 21:53
  • access system token is possible if you have debug privilege. the path is usual `%USERPROFILE%\AppData\Local` so question is how expand `%USERPROFILE%` for *LocalSystem*. not sure are this simply possible from not elevated user – RbMm Apr 16 '19 at 22:16

2 Answers2

1

You need a process running under the SYSTEM account in order to query the SYSTEM profile.

Create a separate service that runs as SYSTEM. When needed, have it call SHGetFolderPath(CSIDL_LOCAL_APPDATA) or SHGetKnownFolderPath(FOLDERID_LocalAppData), specifying NULL for the user token so that it queries the calling user's (ie SYSTEM) profile (or, just use GetTempPath(), which will also work in this context).

Then, the service can pass that path back to your main app through any session-agnostic IPC mechanism that you want (pipes, sockets, etc).

On a side note:

  • you do not need to type-cast temp_path when assigning it to input_parameter. temp_path will implicitly decay into a wchar_t* pointer, which can be passed as-is to the const wchar_t* pointer that std::wstring::operator=() takes as input.

  • rather than using input_parameter.append(L"\\TEMP") manually (which you would not need at all if you use GetTempPath()), you should consider using PathCchCombineEx() (or related) or SHGetFolderPathAndSubDir() instead. Let the OS handle the appending for you.

  • you are calling CloseHandle() with an HWND as input, which is wrong since it expects a HANDLE instead (but this is a no-op in your case since the HWND is NULL, so just remove the CloseHandle() altogether). Clearly you are not compiling your project with STRICT Type Checking enabled, otherwise the compiler would have prevented an HWND from being passed to a HANDLE parameter.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Remy Lebeau's answer is the correct way to do this programmatically. However, it might be more than what's required for you; you might not want to jump through all those hoops if your reason for needing this doesn't require multi-generation OS support. So if you're in Windows 10-land, it seems safe right now to do this. That said, I don't recommend this for its fundamental short-comings. This is just an easy sloppy workaround, so use at your own risk.

I don't have any supporting documentation for this potential solution's longevity, just anecdotal feedback and some personal testing.

I heard from a couple people that the vital OS system directories are not localized. I installed a Windows 10 Pro Japanese image onto a Hyper-V host as a Virtual Machine. Pasting and entering the string, C:\Windows\System32\config\systemprofile\AppData into the Japanese Explorer address bar worked just fine as shown below,


japanese_win10_vm_sysprof_appdata


The gist here being, after you get the value of the system directory (we can't assume C:\WINODWS\system32) you should be able to hard-code the rest with plain English. Here's a sample app that can accomplish that for you:

#define STRICT
#include <Windows.h>
#include <wchar.h>
#include <memory>

int wmain()
{
    static constexpr const wchar_t * SystemProfileAppData_RemainingPath
        = L"\\config\\systemprofile\\AppData";

    wchar_t system_path_buffer[MAX_PATH];
    const std::size_t winapi_worked = GetSystemDirectory(system_path_buffer, MAX_PATH);

    if (winapi_worked) {
        const std::size_t system32_offset = wcsnlen_s(system_path_buffer, MAX_PATH);
        const std::size_t appdata_offset  = wcsnlen_s(SystemProfileAppData_RemainingPath, MAX_PATH);
        const std::size_t path_bytes_size = (appdata_offset + system32_offset) * sizeof(wchar_t);

        memcpy_s(
            &system_path_buffer[system32_offset],
            path_bytes_size,
            SystemProfileAppData_RemainingPath,
            path_bytes_size
        );

        wprintf_s(L"SYSTEM's AppData is here: %s\r\n", system_path_buffer);

        return 0;
    }
    return 1;
}

SYSTEM's AppData is here: C:\WINDOWS\system32\config\systemprofile\AppData

kayleeFrye_onDeck
  • 6,648
  • 5
  • 69
  • 80