user966939
user966939

Reputation: 719

Printing/writing wchar_t?

First off: I know there are similar topics for C++, but I am curious about standard C, and I don't believe my problem is related to previous problems.

I am trying to implement Unicode support for a simple program which just asks the user to select a directory through a folder browser and then passes it to another program (only got to the first part). But when attempting to write the received path to a file, it results in a 0-byte file. And when printing it out using wprintf_s, non-ASCII characters come out as question marks. I don't believe there is any undefined behavior or anything as I've double checked documentation. So what am I doing wrong?

The code currently looks like this (just the bare minimum for strict test conditions):

#define UNICODE
#define _UNICODE

#include <windows.h>
#include <shlobj.h>
#include <stdio.h>

int main()
{
    BROWSEINFOW bi = { 0 };
    LPITEMIDLIST pidl;
    wchar_t path[MAX_PATH];
    pidl = SHBrowseForFolderW(&bi);
    SHGetPathFromIDListW(pidl, path);
    wprintf_s(L"%s\n", path);
    return 0;
}

The above code prints it regularly. When attempting to write to a file instead, I replace the wprintf_s call with this (having declared FILE *f first of course):

if(_wfopen_s(&f, L"C:\\test.txt", L"w"))
{
    fwprintf_s(f, L"%s\n", path)
    fclose(f);
}

However, I have also tried using fwrite with both w and wb mode, but all methods results in an empty file.

Upvotes: 2

Views: 995

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

You need _O_U16TEXT for console output, and "UTF-16LE" for file output.

Also, _wfopen_s returns zero when successful according to MS documentation:

Return Value Zero if successful; an error code on failure. See errno, _doserrno, _sys_errlist, and _sys_nerr for more information about these error codes.

You should make sure return value is zero

if (0 == _wfopen_s(&f, filename, L"w, ccs=UTF-16LE")){
    //isokay ...
}

or check if f is non-NULL. For example:

#include <stdio.h>
#include <io.h> //for _setmode
#include <fcntl.h> //for _O_U16TEXT

int main()
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    const wchar_t *buf = L"ελληνική";
    wprintf(L"%s\n", buf);

    FILE *f = NULL;
    _wfopen_s(&f, L"C:\\test\\test.txt", L"w, ccs=UTF-16LE");
    if (f)
    {
        fwprintf_s(f, L"%s\n", buf);
        fclose(f);
    }

    return 0;
}

Upvotes: 2

Related Questions