在 Delphi 的Vcl.Buttons单元中,他们调用:
Caption := LoadResString(BitBtnCaptions[Value]);
BitnBtnCaptions
如下数组在哪里:
BitnBtnCaptions: array[TBitBtnKind] of Pointer = (
nil, @SOKButton, @SCancelButton, @SHelpButton, @SYesButton, @SNoButton,
@SCloseButton, @SAbortButton, @SRetryButton, @SIgnoreButton,
@SAllButton);
常数BitnBtnCaptions
为:
resourcestring
SOKButton = 'OK';
SCancelButton = 'Cancel';
SYesButton = '&Yes';
SNoButton = '&No';
SHelpButton = '&Help';
SCloseButton = '&Close';
SIgnoreButton = '&Ignore';
SRetryButton = '&Retry';
SAbortButton = 'Abort';
SAllButton = '&All';
因此它本质上就是在调用:
resourcestring
SOKButton = 'OK';
s := LoadResString(@SOKButton);
LoadResString的声明是:
function LoadResString(ResStringRec: PResStringRec): string;
此函数需要一个指向TResStringRec的指针:
PResStringRec = ^TResStringRec;
TResStringRec = packed record
// 32bit = 8 bytes
// 64bit = 16 bytes
Module: ^HMODULE;
Identifier: NativeUint;
end;
但是我们正在传递一个资源字符串。
这是否意味着我们正在将一个字符串传递给一个仅接受PResStringRec的函数?
你为什么问这个?
我问这个问题是因为我要打电话:
Result := LoadResString(@SMsgDlgOK);
并且对于类型指针评估(即 {$T+}
或{$TYPEDADDRESS ON}
),它会给出不兼容的类型警告:
E2010 不兼容的类型:“PResStringRec”和“Pointer”
当然,我也可以用强制转换来强制执行:
Result := LoadResString(PResStringRec(@SMsgDlgOK));
硬铸?
但对于本应是正确的做法,这似乎有点苛刻。有点奇怪。
更糟糕的是,如果我要做硬石膏,我最好知道自己在做什么。
在我看来,唯一可行的方法是:
- 魔法常数
SMsgDlgOk
- 其实是一个
TResStringRec
。
我们不想盲目地使用硬铸件将三角形件强行放入方形孔中。
这让我想到了我的问题:资源字符串
resourcestring
SMsgDlgOK = 'OK';
字符串?还是一条记录?
但我一定得这么做吗?
我是否需要实际执行该Vcl.Buttons
操作?是否Vcl.Buttons
需要执行该操作?
我们不能简单地替换:
s := LoadResString(@SOKButton);
和
s := SOKButton
这难道不是resourcestring关键字的全部意义吗?它将字符串放入字符串表(本地化人员可以在其中对它们进行本地化),并在运行时执行所有神奇的操作(即LoadResString)以将resourcestrings公开为字符串?
如果这不是真的:为什么不是?
- 什么是 resourcestring?
- 它与 LoadResString(resourceString) 有何不同?
我通过拨打以下电话可以获得什么:
LoadResString(@SOKButton)
仅仅使用 SOKButton
?
如果我必须使用 LoadResString ,那么强制进行类型转换是否真的、真的、真正、真正地 100%安全?
- 理想的:
s := SOKButton
- 当前:
s := LoadResString(@SOKButton)
//类型指针检查失败 - 正确的 (?):
s := LoadResString(PResStringRec(@SOKButton))
奖金聊天
如果资源字符串实际上是,TResStringRect
那么我应该能够看到它。所以我检查它们是什么:
╔════════════════════════════╤══════════╗
║ Watch Name │ Value ║
╠════════════════════════════╪══════════╣
║ PResStringRec(@SMsgDlgOK) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgYes) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgNo) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╚════════════════════════════╧══════════╝
每个资源字符串:
- 住在同一地址
- 有相同的模块
- 具有相同的标识符
所以有些事情不对劲;对我来说这看起来不像是一个记录。
那么为什么代码可以Vcl.Buttons
工作呢?