Search code examples
c++mfcwstring

MFC(unicode): how do i convert a wstring filepath to a string path?


I have a application created with MFC, C++, and uses Unicode.

I have to load a texture with a wstring file path. This wstring file path is given by the system and I don't need to display it anywhere. I just need to pass it to a texture loading method. Unfortunately, the texture loading method(from a lib) only take a string filePath. Something like below:

wstring wstringPath = L"abc路徑";// how do I convert it to a string path to used in the following method
stbi_load(stringPath, &width, &height, &nrChannels, 0); //texture loading method

I have searched a lot and didn't found a good answer(or too complex) to solve the issue. Anyone can help?

Something I have tried and not working:

size_t len = wcslen(wstringPath .c_str()) + 1;

size_t newLen = len * 2;
char* newPath = new char[newLen];

wcstombs(newPath, wstringPath .c_str(), sizeof(newPath));

glGenTextures(1, &m_textureID);

int width, height, nrComponents;
unsigned char *data = stbi_load(newPath, &width, &height, &nrComponents, 0);

Solution

  • I looked at the API stbi_load and it seems to take a const char* for the filename.

    In that case, the laziest and best way is to use the CString classes.

    #include <atlstr.h> // might not need if you already have MFC stuff included
    
    CStringA filePathA(wstringPath.c_str()); // it converts using CP_THREAD_ACP
    
    stbi_load(filePathA, ....); // automatically casts to LPCSTR (const char*)
    

    =================================================

    Since there is new information that you need to use UTF-8 to call those APIS, probably need a function like this:

    CStringA GetUtf8String(LPCWSTR lpwz)
    {
        CStringA strRet;
    
        if (lpwz == nullptr || (*lpwz == 0))
            return strRet;
    
        int len = WideCharToMultiByte(CP_UTF8, 0, lpwz, -1, NULL, 0, NULL, NULL);
    
        WideCharToMultiByte(CP_UTF8, 0, lpwz, -1, strRet.GetBufferSetLength(len), len, NULL, NULL);
    
        strRet.ReleaseBuffer();
    
        return strRet;
    }
    

    Then you'd call it like:

    wstring wstringPath = L"abc路徑";
    stbi_load(GetUtf8String(wstringPath.c_str()), blah, blah, blah);