Reputation: 39
Where is a string-table resource ID stored? I am able to list the strings in a table but there doesn't appear to be any kind of identifier the "raw resource" it is just an (array of) USHORT (length) followed by wide chars (the string), there is no identifier.
PIMAGE_RESOURCE_DIR_STRING_U = ^TIMAGE_RESOURCE_DIR_STRING_U;
TIMAGE_RESOURCE_DIR_STRING_U = Record
Count : USHORT;//Word;
Name : Array [0..0] of WideChar;
End;
PIMAGE_RESOURCE_DATA =^TIMAGE_RESOURCE_DATA;
TIMAGE_RESOURCE_DATA = Record
rt_type : DWORD; //RT_STRING
lpName : ShortString; //tables name
Address : PDWORD; //address of the table
dwSize : DWORD; //size of the data
end;
procedure GUIDataToString(IRD: TIMAGE_RESOURCE_DATA);
Type
TStringArray = Array of String;
Function SplitString(P: PByte; dwplen: Int32): TStringArray;
//P is a Pointer to the string table, dwPLen is the size of the table
Var
Index : Int32;
offset: Int32;
dwLen : WORD;
ST_ID : NativeUInt;
rt_str: PIMAGE_RESOURCE_DIR_STRING_U;
Begin
Index := 0; //String Index
offset:= 0;
while (offset <= dwplen) do
Begin
SetLength(Result, Length(Result)+1);
rt_str := PIMAGE_RESOURCE_DIR_STRING_U(@P[offset]);
Result[Index] := NameToStr(rt_str);
//
Inc(offset, (rt_str.Count * sizeof(WideChar) )+ sizeof(WORD));
Inc(Index);
End;
End;
Var
Table : TStringArray;
dwStrings : DWORD;
I : Int32;
//d :
begin
Table := SplitString(PByte(IRD.Address), IRD.dwSize);
dwStrings := Length(Table);
Memo1.Lines.Add('STRINGTABLE');
Memo1.Lines.Add('{');
for I := 0 to dwStrings-1 do
Begin
Memo1.Lines.Add(#9+Table[I]); //#9 is TAB
End;
Memo1.Lines.Add('}');
end;
I read resourcestring(type) can be cast to a PResStringRec
whos .Identifier
field will give an identifier but, I tried with my "raw strings" and it's a random large number (compared IDs resedit gives), any suggestions on how to find the IDs?
Upvotes: 0
Views: 1318
Reputation: 39
Solved, where
dwGroups
is the number of groups,
dwGroup
is the group index containing the string,
Index
is the index of the string (0..15) in the group.
Function MakeRtStringId(dwGroups, dwGroup, Index: DWORD): DWORD;
Var
dwIndex : DWORD;
Begin
dwIndex := 4096 - (dwGroups - dwGroup);
Result := (dwIndex shl 4) or Index;
End;
There is a max of 65535 strings, divided in groups of 16 gives a maximum of 4096 groups. string IDs "start" at, 65535 and decrements, so if you have 15 strings there ID are 65519, 65520, 65521, [...], 65535. and so on, because the last id is always 65535. The last digit is the string is its "index" in the group becausea single hex digit is 0-F (0-15). hints "groups of 16". Thanks Remy Lebeau for the info.
Upvotes: -1
Reputation: 596407
There are no IDs stored in the stringtable itself. String resources are organized in bundles of 16. A string ID is actually a 16bit integer where the high 12 bits identify the index of the bundle within the table, and the low 4 bits identify the index of the string within the bundle. Raymond Chen discusses this on his MSDN blog:
The format of string resources
What is the highest numerical resource ID permitted by Win32?
Upvotes: 2