Na unidade Vcl.Buttons do Delphi eles chamam:
Caption := LoadResString(BitBtnCaptions[Value]);
Onde BitnBtnCaptions
está uma matriz como:
BitnBtnCaptions: array[TBitBtnKind] of Pointer = (
nil, @SOKButton, @SCancelButton, @SHelpButton, @SYesButton, @SNoButton,
@SCloseButton, @SAbortButton, @SRetryButton, @SIgnoreButton,
@SAllButton);
E as BitnBtnCaptions
constantes são:
resourcestring
SOKButton = 'OK';
SCancelButton = 'Cancel';
SYesButton = '&Yes';
SNoButton = '&No';
SHelpButton = '&Help';
SCloseButton = '&Close';
SIgnoreButton = '&Ignore';
SRetryButton = '&Retry';
SAbortButton = 'Abort';
SAllButton = '&All';
Então, basicamente, ele está chamando:
resourcestring
SOKButton = 'OK';
s := LoadResString(@SOKButton);
A declaração de LoadResString é:
function LoadResString(ResStringRec: PResStringRec): string;
Esta função requer um ponteiro para um TResStringRec :
PResStringRec = ^TResStringRec;
TResStringRec = packed record
// 32bit = 8 bytes
// 64bit = 16 bytes
Module: ^HMODULE;
Identifier: NativeUint;
end;
Mas estamos passando uma resourcestring .
Isso significa que estamos passando uma string para uma função que só aceita um PResStringRec em caso de erro?
Por que você pergunta?
Pergunto porque estou chamando:
Result := LoadResString(@SMsgDlgOK);
e com avaliação de ponteiro digitado ( ie {$T+}
ou {$TYPEDADDRESS ON}
) ele emite um aviso de tipo incompatível:
E2010 Tipos incompatíveis: 'PResStringRec' e 'Pointer'
E é claro que eu posso simplesmente forçar com um elenco forte:
Result := LoadResString(PResStringRec(@SMsgDlgOK));
Elenco difícil?
Mas isso parece um pouco duro para algo que supostamente é a maneira correta de fazer algo. Cheira um pouco estranho.
E o pior é que se estou fazendo um gesso forte , é melhor saber o que estou fazendo.
E do jeito que eu vejo, a única maneira de isso funcionar é se:
- a constante mágica
SMsgDlgOk
- na verdade é um
TResStringRec
.
Não queremos forçar uma peça triangular no furo quadrado , usando um molde rígido às cegas.
O que me leva à minha pergunta: uma resourcestring
resourcestring
SMsgDlgOK = 'OK';
uma string? Ou é um registro?
Mas eu realmente tenho que fazer isso?
Eu preciso realmente fazer o que ele Vcl.Buttons
faz? Vcl.Buttons
Precisa fazer o que ele está fazendo?
Não podemos simplesmente substituir:
s := LoadResString(@SOKButton);
com
s := SOKButton
Não era esse o ponto principal da palavra-chave resourcestring ? Ela coloca as strings na tabela strings (onde os localizadores podem localizá-las) e faz toda a mágica em tempo de execução (ou seja, LoadResString ) para expor as resourcestrings como strings ?
E se isso não for verdade: por que não?
- O que é resourcestring?
- e como ele difere de LoadResString(resourceString)?
O que ganho ligando para:
LoadResString(@SOKButton)
sobre apenas usar SOKButton
?
E se eu tiver que usar LoadResString , é realmente , realmente , verdadeiramente , juro, 100% seguro forçar o typecast?
- Ideal :
s := SOKButton
- Atual :
s := LoadResString(@SOKButton)
// falha na verificação de ponteiro digitado - Correto (?) :
s := LoadResString(PResStringRec(@SOKButton))
Bate-papo bônus
Se um resourcestring realmente for um TResStringRect
, então eu deveria ser capaz de vê-lo. Então eu inspeciono o que eles são:
╔════════════════════════════╤══════════╗
║ Watch Name │ Value ║
╠════════════════════════════╪══════════╣
║ PResStringRec(@SMsgDlgOK) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgYes) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgNo) │ $AD3C54 ║
║ ├──Module │ $400000 ║
║ ╰──Identifier │ 0 ║
╚════════════════════════════╧══════════╝
Cada sequência de recursos:
- mora no mesmo endereço
- tem o mesmo módulo
- tem o mesmo identificador
Então algo não está certo; não parece um disco para mim.
Então por que o código funciona Vcl.Buttons
?