Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you open a resource string in Visual C++ 2010?

I created a basic stringtable resource in Visual C++. I am trying to access that resource. However, my program can't seem to find the resource. Here:

int main(int argc, char* argv[])
{
    HRSRC hRsrc;
    hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDS_STRING102), RT_STRING);
    if (hRsrc == NULL) {
        printf("Not found\n");
    } else {
        printf("Found\n");
    }
}

This program can't find the resource and always returns null.

I created a simple bitmap resource and this new program identifies that just fine. Here:

int main(int argc, char* argv[])
{
    HRSRC hRsrc;
    hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP);
    if (hRsrc == NULL) {
        printf("Not found\n");
    } else {
        printf("Found\n");
    }
}

This finds the bitmap.

Do stringtable resources get handled somehow differently?

like image 336
Steve Quezadas Avatar asked Feb 23 '23 13:02

Steve Quezadas


2 Answers

Assuming you do not want to use LoadString() this should help...

Strings and string tables are indeed treated differently when using FindResource() and FindResourceEx(). From this KB article:

String resources are stored as blocks of strings. Each block can have up to sixteen strings and represents the smallest granularity of string resource that can be loaded/updated. Each block is identified by an identifier (ID), starting with one (1). We use this ID when calling the FindResource, LoadResource and UpdateResource functions.

A string with ID, nStringID, is located in the block with ID, nBlockID, given by the following formula:

nBlockID = (nStringID / 16) + 1; // Note integer division.

The lower 4 bits of nStringID indicates which entry in the block contains the actual string. Once you have calculated the block ID to pass to FindResource() and the index in the block where the string exists you have to scan through it's contents to find the string you are looking for.

The following code should get you started.

const WCHAR *stringPtr;
WCHAR stringLen;

//  Get the id of the string table block containing the target string
const DWORD blockID = (nID >> 4) + 1;

//  Get the offset of teh target string in the block
const DWORD itemID = nID % 0x10;

//  Find the resource
HRSRC hRes = FindResourceEx(
    hInst,
    RT_STRING,
    MAKEINTRESOURCE(blockID),
    wLanguage);
if (hRes)
{
    HGLOBAL hBlock = LoadResource(hInst, hRes);
    const WCHAR *tableDataBlock = reinterpret_cast<LPCWSTR>(LockResource(hBlock));
    const DWORD tableBlockSize = SizeofResource(hInst, hRes);
    DWORD searchOffset = 0;
    DWORD stringIndex = 0;

    //  Search through the section for the appropriate entry.
    //  The first two bytes of each entry is the length of the string
    //  followed by the Unicode string itself. All strings entries 
    //  are stored one after another with no padding.
    while(searchOffset < tableBlockSize)
    {
        if (stringIndex == itemID)
        {
            //  If the string has size. use it!
            if (tableDataBlock[searchOffset] != 0x0000)
            {
                stringPtr = &tableDataBlock[searchOffset + 1];
                stringLen = tableDataBlock[searchOffset];
            }
            //  Nothing there -
            else
            {
                stringPtr = NULL;
                stringLen = 0;
            }

            //  Done
            break;
        }

        //  Go to the next string in the table
        searchOffset += tableDataBlock[searchOffset] + 1;

        //  Bump the index
        stringIndex++;
    }
}
like image 63
Captain Obvlious Avatar answered Feb 26 '23 14:02

Captain Obvlious


You could use LoadString directly instead. Here's some text from the MSDN FindResource documentation...

An application can use FindResource to find any type of resource, but this function should be used only if the application must access the binary resource data by making subsequent calls to LoadResource and then to LockResource.

To use a resource immediately...

...use LoadString!

like image 42
Ben Avatar answered Feb 26 '23 14:02

Ben