使用 UpdateResource 更新字符串表

2021-12-17 00:00:00 windows c winapi resources c++

我在这里问了这个问题 - :因为字符串资源组只能作为一个整体更新提供组 ID,其中第一个组的 ID 为 1.从字符串 ID 计算组 ID 使用 groupID = ( strID >> 4 ) + 1 完成,而相对(零-based) 组内的偏移量是 strOffset = strID % 16.如果您查看通过传递 MAKEINTRESOURCE(1) 产生的结果,您现在可以明白为什么它会以 ID 为 0 的方式归入组 1.

将所有部分放在一起,您可以使用以下代码更新字符串资源:

void ReplaceStringTable() {HANDLE hRes = BeginUpdateResource( _T( "Output.exe" ), TRUE );如果 ( hRes != NULL ) {wstring data[] = { L"",//空字符串跳过字符串 ID 0L"雷蒙德",L"陈",L"是",L"我的",L"英雄!",//剩余的字符串以完成该组L"", L"", L"", L"", L"", L"", L"", L"", L"", L""};向量<字 >缓冲;for ( size_t 索引 = 0;指数<sizeof(data)/sizeof(data[0]);++索引) {size_t pos = buffer.size();buffer.resize( pos + data[ index ].size() + 1 );缓冲区[ pos++ ] = static_cast<字 >( 数据[索引].size());复制(数据[索引].开始(),数据[索引].结束(),buffer.begin() + pos );}更新资源( hRes,RT_STRING,MAKEINTRESOURCE( 1 ),MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),reinterpret_cast

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!

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:

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:

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.

解决方案

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' '' 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 );
    }
}

相关文章