The format of string resources

This article give a detail of usage of FindResourceEx for string table: http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx

Unlike the other resource formats, where the resource identifieris the same as the value listed in the *.rc file, string resourcesare packaged in "bundles".There is a rather terse description of this inKnowledge Base article Q196774.Today we're going to expand that terse description into actual code.

The strings listed in the *.rc file are grouped together inbundles of sixteen. So the first bundle contains strings0 through 15, the second bundle contains strings 16 through 31,and so on. In general, bundle N contains strings (N-1)*16through (N-1)*16+15.

The strings in each bundle are stored as counted UNICODE strings,not null-terminated strings. If there are gaps in the numbering,null strings are used. So for example if your string tablehad only strings 16 and 31, there would be one bundle (number 2),which consists of string 16, fourteen null strings, then string 31.

(Note that this means there is no way to tell the differencebetween "string 20 is a string that has length zero" and"string 20 doesn't exist".)

The LoadString function is rather limiting in a few ways:

  • You can't pass a language ID. If your resources are multilingual, you can't load strings from a nondefault language.
  • You can't query the length of a resource string.

Let's write some functions that remove these limitations.

LPCWSTR FindStringResourceEx(HINSTANCE hinst,
 UINT uId, UINT langId)
{
 // Convert the string ID into a bundle number
 LPCWSTR pwsz = NULL;
 HRSRC hrsrc = FindResourceEx(hinst, RT_STRING,
                     MAKEINTRESOURCE(uId / 16 + 1),
                     langId);
 if (hrsrc) {
  HGLOBAL hglob = LoadResource(hinst, hrsrc);
  if (hglob) {
   pwsz = reinterpret_cast<LPCWSTR>
              (LockResource(hglob));
   if (pwsz) {
    // okay now walk the string table
    for (int i = 0; i < uId & 15; i++) {
     pwsz += 1 + (UINT)*pwsz;
    }
    UnlockResource(pwsz);
   }
   FreeResource(hglob);
  }
 }
 return pwsz;
}

After converting the string ID into a bundle number,we find the bundle, load it, and lock it. (That'san awful lot of paperwork just to access a resource.It's a throwback to the Windows 3.1 way of managingresources; more on that in a future entry.)

We then walk through the table skipping over thedesired number of strings until we find the one we want.The first WCHAR in each string entry is the length ofthe string, so adding 1 skips over the count andadding the count skips over the string.

When we finish walking, pwsz is left pointing to thecounted string.

With this basic function we can create fancier functions.

The function FindStringResource is a simple wrapperthat searches for the string in the default thread language.

LPCWSTR FindStringResource(HINSTANCE hinst, UINT uId)
{
 return FindStringResourceEx(hinst, uId,
     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
}

The function GetResourceStringLengthEx returns the lengthof the corresponding string, including the null terminator.

UINT GetStringResourceLengthEx(HINSTANCE hinst,
 UINT uId, UINT langId)
{
 LPCWSTR pwsz = FindStringResourceEx
                       (hinst, uId, langId);
 return 1 + (pwsz ? *pwsz : 0);
}

And the function AllocStringFromResourceEx loads the entirestring resource into a heap-allocated memory block.

LPWSTR AllocStringFromResourceEx(HINSTANCE hinst,
 UINT uId, UINT langId)
{
 LPCWSTR pwszRes = FindStringResourceEx
                       (hinst, uId, langId);
 if (!pwszRes) pwszRes = L"";
 LPWSTR pwsz = new WCHAR[(UINT)*pwszRes+1];
 if (pwsz) {
   pwsz[(UINT)*pwszRes] = L'\0';
   CopyMemory(pwsz, pwszRes+1,
              *pwszRes * sizeof(WCHAR));
 }
 return pwsz;
}

(Writing the non-Ex functionsGetStringResourceLength and AllocStringFromResourceis left as an exercise.)

Note that we must explicitly null-terminate the stringsince the string in the resource is not null-terminated.Note also thatthe string returned by AllocStringFromResourceExmust be freed with delete[]. For example:

LPWSTR pwsz = AllocStringFromResource(hinst, uId);
if (pwsz) {
  ... use pwsz ...
  delete[] pwsz;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值