0

I want to create a directory inside the %APPDATA% folder. I am using CreateDirectory() for this and it doesn't work. I debugged the code and it seems like the path is correct, but I can't see a new directory in my the APPDATA.

My code for creating dit in appdata:

void setAppDataDir(std::string name)
{
    char* path;
    size_t len;
    _dupenv_s(&path, &len, "APPDATA");
    AppDataPath = path;
    AppDataPath += "\\"+name;

    createDir(this->AppDataPath.c_str());
}

void createDir(const char* path)
{
    assert(CreateDirectory((PCWSTR)path, NULL) || ERROR_ALREADY_EXISTS == GetLastError()); // no exception here
}

This is how I call the function:

setAppDataDir("thisistest");

I use Visual Studio 2019 and the debugger tells me, that path is C:\\Users\\Micha\AppData\Roaming\\thisistest

What am I doing wrong?

Sherlock Holmes
  • 191
  • 1
  • 8

2 Answers2

1

CreateDirectory() is a macro that expands to CreateDirectoryW() in your case, which requires strings in UTF-16LE encoding (wchar_t*). You are casting the const char* path param to PCWSTR (const wchar_t*):

CreateDirectory((PCWSTR)path, NULL) ...

But you are not converting that string into a UTF-16LE string.

So, you need to convert your path into a wchar_t* string. There are some methods to do it, see Convert char * to LPWSTR.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Dmitry Sokolov
  • 3,118
  • 1
  • 30
  • 35
  • It would be easier to call `CreateDirectoryA()` instead, and let it handle the conversion internally for you. – Remy Lebeau Sep 01 '20 at 19:31
  • Nope. It's a bad idea. In particular, if the `path` is UTF-8 encoded this won't work. – Dmitry Sokolov Sep 01 '20 at 19:36
  • Obviously, context will matter. TYPICALLY, paths used in ANSI strings will use the user's default locale, in which case the implicit conversion of `A`-based APIs will suffice. But if you use a different charset for your ANSI strings, then obviously you have to take more care in how they are converted. And FYI, you can use UTF-8 with ANSI file path APIs in Windows 10 build 17035+, if your app explicitly opts in to that new API functionality. – Remy Lebeau Sep 01 '20 at 19:39
  • @remy it's not hard to use UTF16 throughout the process. I don't see why you'd recommend otherwise. – David Heffernan Sep 02 '20 at 06:39
0

The problem was the way I was giving path to CreateDirectory(). As @RemyLebeau pointed out, I should have used CreateDirectoryA(). This change solved the issue.

Sherlock Holmes
  • 191
  • 1
  • 8
  • 2
    This change solves your **immediate** issue, but creates a new one: You are now confined to the character set that is MBCS. MBCS has no place in this millennium. It cannot encode the entirety of Unicode code points, and since you are operating on the users' filesystems, you have no control over their choice of naming entries. You **will** run into encoding issues. The real solution is to use Unicode throughout. – IInspectable Sep 01 '20 at 19:57
  • @IInspectable What do you mean? – Sherlock Holmes Sep 02 '20 at 05:05
  • Hi, does any answer solve your issue? Please feel free to accept it if it does help. – Zeus Sep 02 '20 at 05:31
  • MBCS can encode only a subset of characters that are legal for any given path. If the `APPDATA` environment variable points to a path that happens to contain `á請हщ` you cannot represent that in *any* code page. UTF-16, on the other hand, can encode *any* sequence of characters. Unicode isn't just an option. It's the **only** character set and encoding that allows you to write correct programs. – IInspectable Sep 02 '20 at 06:26
  • Wrong solution. Use Unicode text. And use the known folder api to obtain the appdata path, rather then the environment. – David Heffernan Sep 02 '20 at 06:37