Search code examples
c++resourcesstringreaderresourcestring

Does LoadString allocate memory for the string it writes to?


I am new in c++ and need some help. I created a resource-only dll that contains strings, i need to use this dll in a different project to read the stored strings.

I wrote the following functions to read the read the strings:

LPTSTR GetResourceStr(HMODULE resContainer,int resourceID)
{
    //The stings that are stored in the dll are:
    //
    //ID            |Value|Caption
    //__________________________________________
    //IDS_STRING101 |101  |stringggg
    //IDS_STRING102 |102  |string 102
    //IDS_STRING103 |103  |string 103

    LPTSTR strBuffer = NULL;//is a (non-const) TCHAR string
    if(0!=resContainer){
      int copied=LoadString(resContainer,resourceID ,(LPTSTR)&strBuffer,0); 
    }
    return strBuffer;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE resContainer=LoadLibraryEx(L"ResourceDll.dll",NULL, LOAD_LIBRARY_AS_DATAFILE);

    LPTSTR msg = GetResourceStr(resContainer,101);
    std::wcout<<msg<<std::endl;
    //Expected output: stringggg
    //The output that i get: stringgggstring 102 string 103
    int i = 0;
    std::cin>>i;
    return 0;
}

What should i change in my code to get the expected output - stringggg? Why is it happening? Did LoadString allocate memory for the string it read from resources, or i just got pointer to the place in memory the string is already stored? Thanks for your help!!


Solution

  • The LoadString documentation says:

    nBufferMax [in]

    Type: int

    The size of the buffer, in characters. The string is truncated and null-terminated if it is longer than the number of characters specified. If this parameter is 0, then lpBuffer receives a read-only pointer to the resource itself.

    So to answer your question directly, you just get a pointer to the memory where the resource is stored.

    But the string resource is not null-terminated (for more info, see here), so that's why you get that output. The return value of LoadString tells you the length of the individual string resource. If you need the string to be null-terminated, you have to copy the string to a separate buffer, like this:

    WCHAR* pszString;
    int iLength = ::LoadString(
        resContainer,
        resourceID,
        reinterpret_cast<LPWSTR>(&pszString),
        0
        );
    
    WCHAR* pszString2 = new WCHAR[iLength + 1];
    ::StringCchCopyN(pszString2, iLength + 1, pszString, iLength);
    

    Alternatively, you can just call LoadString with a pointer to a buffer (instead of a pointer to a pointer) as the 3rd parameter, and the length of the buffer as the 4th parameter, which will copy the string resource to the buffer and null-terminate it. The disadvantage is that the string will be truncated if you don't pass a big enough length, and there's no way to query the resource's length beforehand.