Обновление таблицы строк с помощью UpdateResource
Я задал вопрос здесь - обновление STRING TABLE через UpdateResource (добавление нескольких строк)
А теперь я снова спрашиваю, так как на этот раз я могу добавить больше деталей к вопросу.
Я пробовал это в течение прошлого дня или что-то безрезультатно. Я хочу, чтобы результат был таким (я вручную добавил строки в MSVS): как вы можете видеть, несколько записей, и это "чисто" и может быть легко доступно программе!
Прямо сейчас мой источник:
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);
}
Производит:
Что неправильно, так как кажется, что в таблицу добавлена только последняя строка, а не строки перед ней!
Когда я пытаюсь изменить источник так, чтобы MAKEINTRESOURCE(1) теперь был "MAKEINTRESOURCE(i)", результат будет таким, как показано на различных рисунках:
Успех в том, что он добавил все строки, но, похоже, создал различные таблицы строк, что не является желаемым. Хотя я заметил, что идентификаторы увеличились на 16 на каждой картинке, что могло бы что-то объяснить. По сути, я хочу, чтобы строки были отформатированы, как на первом рисунке (с несколькими строками), но я понятия не имею, как это сделать.
Спасибо за помощь.
1 ответ
Строковые ресурсы отличаются от любого другого формата ресурсов. Они не хранятся как отдельные записи, а упакованы в группы по 16 строк в каждой. Первая группа хранит строки с 0 по 15, вторая группа хранит строки с 16 по 31 и так далее. На ваших скриншотах выше группы отображаются как первый уровень под родителем в древовидной структуре слева.
Строковые ресурсы также отличаются тем, что они хранятся в виде подсчитанных строк Юникода (без нулевого терминатора), в отличие от С-строк с нулевым символом в конце. Так, например, C-строка 'T' 'e' 's' 't' '\0'
будет храниться как 0004 0054 0065 0073 0074
где первый WORD
указывает на длину и оставшиеся 4 WORD
s представляют символы Unicode.
Следствием этого формата ресурсов является то, что если в идентификаторах строк в группе есть пропуски, недостающие строки должны быть учтены с помощью строк нулевой длины, или просто 0000
в формате ресурса говорят. Так что если в вашей таблице строк есть строки с идентификаторами 2 и 5, то будет одна группа (1) с 16 записями: 0000
0000
<string 2>
0000
0000
<string 5>
0000
0000
... 0000
,
Требуется еще одна информация, а именно идентификатор ресурса, который нужно передать для lpName
параметр в вызове UpdateResource
: Поскольку группы строковых ресурсов могут быть обновлены только целиком, необходимо указать идентификатор группы, где первая группа имеет идентификатор 1. Вычисление идентификатора группы по идентификатору строки выполняется с помощью groupID = ( strID >> 4 ) + 1
в то время как относительное (основанное на нуле) смещение внутри группы strOffset = strID % 16
, Если вы посмотрите на результат, полученный от прохождения MAKEINTRESOURCE(1)
Теперь вы можете понять, почему он оказался в группе 1 с идентификатором 0.
Собрав все части вместе, вы можете обновить строковый ресурс, используя следующий код:
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 );
}
}