1

I've read that one can use SHGetSpecialFolderPath(); to get the AppData path. However, it returns a TCHAR array. I need to have an std::string.

How can it be converted to an std::string?

Update

I've read that it is possible to use getenv("APPDATA"), but that it is not available in Windows XP. I want to support Windows XP - Windows 10.

Z0q
  • 1,689
  • 3
  • 28
  • 57
  • SHGetSpecialFolderPath is not supported since Windows 2000 according to msdn, how about using SHGetFolderPath? https://msdn.microsoft.com/en-us/library/windows/desktop/bb762181(v=vs.85).aspx If you need to force the coding type, at winapi you usually have endings with W for wchar_t, A for char. Such as SHGetFolderPathA. This one should support from Win 2000 up to this day, even tho it's set for deprecation. – Geries Mar 16 '16 at 23:50

4 Answers4

2

The T type means that SHGetSpecialFolderPath is a pair of functions:

  • SHGetSpecialFolderPathA for Windows ANSI encoded char based text, and

  • SHGetSpecialFolderPathW for UTF-16 encoded wchar_t based text, Windows' “Unicode”.

The ANSI variant is just a wrapper for the Unicode variant, and it can not logically produce a correct path in all cases.

But this is what you need to use for char based data.


An alternative is to use the wide variant of the function, and use whatever machinery that you're comfortable with to convert the wide text result to a byte-oriented char based encoding of your choice, e.g. UTF-8.

Note that UTF-8 strings can't be used directly to open files etc. via the Windows API, so this approach involves even more conversion just to use the string.


However, I recommend switching over to wide text, in Windows.

For this, define the macro symbol UNICODE before including <windows.h>.

That's also the default in a Visual Studio project.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • What impact does switching over to wide text have on my project? It is currently configured as `Use Multi-Byte Character Set`. – Z0q Mar 16 '16 at 23:45
  • @Z0q: Literals and strings in calls of API functions need to be changed to wide. Mostly that's just prefixing an `L`. E.g., where with ANSI you had `"hello"`, with Unicode you have `L"Hello"`. – Cheers and hth. - Alf Mar 16 '16 at 23:48
  • If I call `fopen()` for example, how would I send a wide text as parameter? – Z0q Mar 16 '16 at 23:49
  • @Z0q: You can't use standard `fopen` to open an arbitrary file in Windows, because the path needs to be ANSI-encoded, and so it can't handle all the possible path characters. You can use Windows-specific `_wfopen` to do it. Or you can go one level higher and use the Boost filesystem sublibrary, which (possibly slightly modified) will be part of C++17. – Cheers and hth. - Alf Mar 16 '16 at 23:53
  • Would it be a problem for my application if I use the ANSI encoded char based text? It would save me a lot of time rewriting large parts of my code – Z0q Mar 16 '16 at 23:55
  • 1
    It will be unable to handle some paths, that's all. For example, if you're writing this program in the US, and someone in some Asian or Arabic or Eastern European country uses it, they may run into problems. – Cheers and hth. - Alf Mar 16 '16 at 23:58
  • Thanks. I'll use that one for now, and migrate in a future update :) – Z0q Mar 16 '16 at 23:59
1

You should use SHGetSpecialFolderPathA() to have the function deal with ANSI characters explicitly.

Then, just convert the array of char to std::string as usual.

/* to have MinGW declare SHGetSpecialFolderPathA() */
#if !defined(_WIN32_IE) || _WIN32_IE < 0x0400
#undef _WIN32_IE
#define _WIN32_IE 0x0400
#endif

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

std::string getPath(int csidl) {
    char out[MAX_PATH];
    if (SHGetSpecialFolderPathA(NULL, out, csidl, 0)) {
        return out;
    } else {
        return "";
    }
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
1

https://msdn.microsoft.com/en-gb/library/windows/desktop/dd374131%28v=vs.85%29.aspx

#ifdef UNICODE
    typedef wchar_t TCHAR;
#else
    typedef unsigned char TCHAR;
#endif

Basically you can can convert this array to std::wstring. Converting to std::string is straightforward with std::wstring_convert.

http://en.cppreference.com/w/cpp/locale/wstring_convert

0

Typedef String as either std::string or std::wstring depending on your compilation configuration. The following code might be useful:

#ifndef UNICODE  
  typedef std::string String; 
#else
  typedef std::wstring String; 
#endif
Dendi Suhubdy
  • 2,877
  • 3
  • 19
  • 20