0

I am working on this big C++ Windows application, which runs as Local Service. It tries to get various Windows special paths (using the exact same function as shown below), of those paths it returns:

  • C:\Program Files for FOLDERID_ProgramFiles
  • C:\Program Files (x86) for FOLDERID_ProgramFilesX86
  • C:\WINDOWS for FOLDERID_Windows

But, for FOLDERID_ProgramData, it returns an empty string. When I tried to use GetLastError() after SHGetKnownFolderPath() I get error 203 (ERROR_ENVVAR_NOT_FOUND):

The system could not find the environment option that was entered.

What I have tried is, when I try to create a small snippet as below, I am able to get C:\ProgramData for FOLDERID_ProgramData. It's only when I try to run my main Windows application that it returns an empty string.

#include <shlobj.h>
#include <iostream>
#include <string>
#include <vector>
#include <iostream>

std::string fun(REFKNOWNFOLDERID  val) {
    PWSTR dirStr;
    if (S_OK == SHGetKnownFolderPath (val, 0, NULL, & dirStr))
    {
        std::wstring str = std::wstring(dirStr);
        std::string ret_str(str.begin(), str.end());
        return ret_str;
    }
    return "failed";
}

int main() {
    std::cout << fun(FOLDERID_ProgramData) << std::endl; // outputs C:\ProgramData
    std::cout << fun(FOLDERID_ProgramFiles) << std::endl; // outputs C:\Program Files
}

Could it be because I am running the application as Local Service? Do I need to request a specific user's folder by passing the hToken of Local Service?

If so, how would one go about doing that? I saw Create a user token from SID, expand environment variables in user context, but wanted to make sure if I am on right track.

One thing I noticed is C:\ProgramData is a hidden folder.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
boka
  • 69
  • 1
  • 10
  • Unrelated to the issue but _yikes_ at `std::string ret_str(str.begin(), str.end());` – Mike Vine Aug 02 '21 at 20:25
  • I agree with @MikeVine (but have reached my daily vote limit). What if the `wstring` contains characters outside the ASCII range? – Ted Lyngmo Aug 02 '21 at 20:50
  • Agreed! I was planning to crash that bridge for later :p – boka Aug 02 '21 at 20:56
  • It is odd that `FOLDERID_ProgramData` is not returning a string, since it is not tied to any specific user. You might want to try logging the result of [`GetEnvironmentStrings()`](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentstrings) to see which environment variables are actually accessible under your `LocalService` account. You may have a missing configuration in the system setup. – Remy Lebeau Aug 02 '21 at 21:58
  • @RemyLebeau When I try to print using `GetEnvironmentStrings` from a small snippet program it prints all the environment variable. But when I try to print in the same way but from main windows application I get empty string. Not sure why I am still getting C:\Program Files though. – boka Aug 03 '21 at 00:21
  • 1
    Not all `FOLDERID`s are based on environment variables, some come from the Registry instead, or are hard-coded in the OS, but there may be environment variables that mirror them (ie `%PROGRAMFILES%`, etc). Do you have a `Common AppData` value in the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders` Registry key? – Remy Lebeau Aug 03 '21 at 00:23
  • Yes, and its value is C:\ProgramData – boka Aug 03 '21 at 00:31
  • @RemyLebeau why you ask? Are you suggesting to read this value from registry? – boka Aug 03 '21 at 00:53
  • I ask because `Common AppData` contains the path to the `CSIDL_COMMON_APPDATA` folder, which `FOLDERID_ProgramData` mirrors. So make sure your Registry has it. When you checked your Registry, did you do so under the context of the `LocalService` account? You already said `GetEnvironmentStrings()` is not returning anything, and the `FOLDERID_ProgramData` doc does say it equates to `%ProgramData%` and `%SystemDrive%\ProgramData`, so it is possible without a valid environment block, you are not going to get the strings, even though they are available elsewhere (Registry, etc). – Remy Lebeau Aug 03 '21 at 00:58
  • Is your main app coded itself as a Windows service? Or is it being spawned by a service? Otherwise, why would you be using the `Local Service` account? – Remy Lebeau Aug 03 '21 at 01:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/235569/discussion-between-boka-and-remy-lebeau). – boka Aug 03 '21 at 01:28

0 Answers0