Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

updating a string table with UpdateResource

I asked the question here - updating STRING TABLE via UpdateResource (adding multiple strings)

And now I am asking again, as this time I can add alot more detail to the question.

I've been trying this for the past day or something to no real avail. What I want the outcome to be is like this (I manually added the strings in MSVS): As you can see, multiple entries, and it's "clean" and can be easily accessed by the program! enter image description here

Right now, my source:

wstring buffer[5] = {L" Meow",L" I",L" Am",L" A",L" Dinosaur"}; // ignore the string
if (HANDLE hRes = BeginUpdateResource("Output.exe",TRUE))
{
    for (int i = 0; i < 5; i++)
    {
    wchar_t * temp;
    temp = new wchar_t[(buffer[i].length()+1)];
    wcscpy(temp,buffer[i].c_str());
    wcout << temp << endl;
    UpdateResource(hRes,RT_STRING,MAKEINTRESOURCE(1),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                   temp, 48); //buffer[i].length()+1
    delete[] temp;
    }
    EndUpdateResource(hRes,FALSE);

}

Produces: enter image description here

Which is wrong, as it seems to only have added the last string to the table, not the strings before it!

When I try modifying the source so MAKEINTRESOURCE(1) is now "MAKEINTRESOURCE(i)", the outcome is this as shown in various pictures: http://gyazo.com/5fa7a6682d5da2def4683227533b2755.pnghttp://gyazo.com/e77f6e90cb3dbfe21d07b3d55c931acb.pnghttp://gyazo.com/2e632768e2cdfcea8ab9cd08caea9cc8.pnghttp://gyazo.com/f9dcd68c671923d8faefce76877bc3be.png

Success in the fact it added all the strings, but it seems to have created various string tables which is not what was desired. Although I do notice the ID's have incremented by 16 in each picture which could possibly explain something. Basically, I want the strings to be formatted as in the first picture (with the multiple strings), but have no real idea how to do this.

Thank you for your assistance.

like image 417
James Avatar asked Dec 30 '12 03:12

James


1 Answers

String resources are different from any other resource format. They are not stored as individual entries but packaged into groups of 16 strings each. The first group stores strings 0 through 15, the second group stores strings 16 through 31, and so on. In your screenshots above the groups are displayed as the first level underneath the parent in the treeview towards the left.

String resources are also different in that they are stored as counted Unicode strings (without a zero terminator) as opposed to zero-terminated C-strings. So for example the C-string 'T' 'e' 's' 't' '\0' will be stored as 0004 0054 0065 0073 0074 where the first WORD indicates the length and the remaining 4 WORDs represent the Unicode characters.

A consequence of this resource format is that if there are gaps in the string IDs within a group the missing strings have to be accounted for with zero-length strings, or simply 0000 in resource format speak. So if your string table has strings with IDs 2 and 5 there would be a single group (1) with 16 entries: 0000 0000 <string 2> 0000 0000 <string 5> 0000 0000 ... 0000.

There's still one more piece of information required, namely which resource ID to pass for the lpName parameter in the call to UpdateResource: Since string resource groups can only be updated as a whole you have to provide the group ID, where the first group has ID 1. Calculating the group ID from a string ID is done with groupID = ( strID >> 4 ) + 1, while the relative (zero-based) offset within a group is strOffset = strID % 16. If you look at the result produced from passing MAKEINTRESOURCE(1) you can now see why it wound up in group 1 with an ID of 0.

Putting all the pieces together you can update a string resource using the following code:

void ReplaceStringTable() {

    HANDLE hRes = BeginUpdateResource( _T( "Output.exe" ), TRUE );
    if ( hRes != NULL ) {
        wstring data[] = { L"",   // empty string to skip string ID 0
                           L"Raymond",
                           L"Chen",
                           L"is",
                           L"my",
                           L"Hero!", 
                           // remaining strings to complete the group
                           L"", L"", L"", L"", L"", L"", L"", L"", L"", L""
                         };

        vector< WORD > buffer;
        for ( size_t index = 0;
              index < sizeof( data ) / sizeof( data[ 0 ] );
              ++index ) {

            size_t pos = buffer.size();
            buffer.resize( pos + data[ index ].size() + 1 );
            buffer[ pos++ ] = static_cast< WORD >( data[ index ].size() );
            copy( data[ index ].begin(), data[ index ].end(),
                  buffer.begin() + pos );
        }
        UpdateResource( hRes,
                        RT_STRING,
                        MAKEINTRESOURCE( 1 ),
                        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                        reinterpret_cast< void* >( &buffer[ 0 ] ),
                        buffer.size() * sizeof( WORD ) );

        EndUpdateResource( hRes, FALSE );
    }
}
like image 189
IInspectable Avatar answered Oct 01 '22 03:10

IInspectable