I once appeared in The Old New Thing
mtlynch.io
mtlynch.io
Also I think the C preprocessor would be relatively unhelpful with the file format you explained in the post: As soon as you reached the first unmatched, unquoted apostrophe, cpp would assume it was inside a really long character literal and refuse to substitute any macros until the next apostrophe.
cpp is great, but it does basically require a grammar that assigns broadly the expected meaning to ' " # // /* */. Curly-brace languages fine, running English text not so much.
if (minimumPassphraseLength > MAX_PASSPHRASE_MINIMUM) {
static_assert(MAX_PASSPHRASE_MINIMUM == 20);
ShowError(ERROR_BITLOCKER_PASSPHRASE_MINIMUM_LONGER_THAN_20);
}
so that if the value of MAX_PASSPHRASE_MINIMUM ever changed, you'd get a build failure right on this line and you'd be forced to fix it (part of which should involve updating the message to match).You could make that fancier by trying to craft the name of the error message itself via the preprocessor — something like:
SymbolicName=ERROR_BITLOCKER_PASSPHRASE_MINIMUM_LONGER_THAN_20
The BitLocker minimum passphrase length cannot exceed 20.
...
#define CONCAT(x, y) x##y
#define ERROR_BITLOCKER_PASSPHRASE_MINIMUM_LONGER_THAN(x) \
CONCAT(ERROR_BITLOCKER_PASSPHRASE_MINIMUM_LONGER_THAN_, x)
#define MAX_PASSPHRASE_MINIMUM 20
if (minimumPassphraseLength > MAX_PASSPHRASE_MINIMUM) {
ShowError(ERROR_BITLOCKER_PASSPHRASE_MINIMUM_LONGER_THAN(MAX_PASSPHRASE_MINIMUM));
}
But that would just make the compiler error (when MAX_PASSPHRASE_MINIMUM changed) a lot harder to read, without changing the essential task (go find the error message and update it), so it's not a good idea.Ah, you're right! Fixed, thanks!
>Also I think the C preprocessor would be relatively unhelpful with the file format you explained in the post: As soon as you reached the first unmatched, unquoted apostrophe, cpp would assume it was inside a really long character literal and refuse to substitute any macros until the next apostrophe.
Oh, that's a good point. I'm not sure how Visual C++ does with it, but I just tried with gcc, and it falls over on an apostrophe:
$ cat values.h
#define MAX_PASSPHRASE_MINIMUM 20
$ cat example.mcp
SymbolicName=ERROR_BITLOCKER_PASSPHRASE_MINIMUM_TOO_LONG
The BitLocker minimum passphrase length can't exceed MAX_PASSPHRASE_MINIMUM.
$ gcc --version | head -n 1
gcc (GCC) 14.3.0
$ gcc --preprocess --language=c --no-line-commands --include=values.h example.mcp
SymbolicName=ERROR_BITLOCKER_PASSPHRASE_MINIMUM_TOO_LONG
example.mcp:2:44: warning: missing terminating ' character
2 | The BitLocker minimum passphrase length can't exceed MAX_PASSPHRASE_MINIMUM.
| ^
The BitLocker minimum passphrase length can't exceed MAX_PASSPHRASE_MINIMUM.My question is: how was anyone expected to make changes to the build definition if this was the only way? Wait a day to find out if it worked, and break the build for everyone if not?
I would speculate that in most parts of the company that haven't been left to rot that's hopefully no longer true, but I have no direct anecdotes about that, I just would have assumed it to be a target for someone looking for their iteration cycles to be saner at some point, and once one group managed it, etc.
it underwent a Herculean effort to modernize it, converging on the actual VS build system and from sd to git. it seemed much healthier last I looked.
You could build a subcomponent of Windows source locally, and 99% of the time, you knew which subparts of the source tree to build locally to have confidence that you wouldn't break the build.
The problem was that if I was doing something exotic nobody has tried before, I'm suddenly in the 1% case where I no longer have confidence that building locally will eliminate all issues.
https://learn.microsoft.com/en-us/windows/win32/eventlog/mes...
(You'll note that that page mentions that FormatMessage() does support printf-style format specifiers in the string resource. That's why I'm saying that their ShowError() specifically is the one that doesn't.)
… except that it might have been people from IBM. OS/2 had a DosGetMessage() API function that looked up messages in a compiled message file and inserted strings taken from an application-supplied array wherever a %1 to a %9 occurred in the message.
It was regularly used to edit the applicable filename, drive letter, numeric values, or whatnot into error messages.
"One customer" asked me to add some compile time condition based on the platform.
I told him to use the C++ preprocessor and use #if/#ifdef
It meant that when a user enables BitLocker on a drive, the BitLocker setup flow would check if group policy defined a minimum password length. If it did, BitLocker would enforce that minimum. Otherwise, BitLocker would use the default minimum.
If you have a Windows system, you can play with this easily as long as you have an admin user account for the OS. The Windows system doesn't need to be part of an org or need Active Directory. You can edit group policy by opening gpedit.msc from an elevated command prompt.