January 15th, 2026
likeintriguing4 reactions

When programs assume that the system will never change, episode 4: Stealing strings

A customer had a program that automated a workflow, and one of the steps was to run a console program that came with Windows, and that console program printed a confirmation prompt “Are you sure (Y/N)?“. They wanted to programmatically say Yes, but since the customer had employees around the world, they couldn’t hard code the letter Y into their program. (For example, in German, it would be J/N instead of Y/N.) They also realized that the characters for affirmative and negative replies were stored in resources in the executable, so instead of having a big table of affirmative and negative replies for each language, they could load those strings from the executable and use them to answer the questions. They wanted to know if this is acceptable and supported.

No, it’s neither supported nor acceptable.

Unless documented otherwise, resource strings are considered implementation details of the program. Absent any promises to the contrary, Windows reserves the right to change any resource string, or to move them to another location.

Indeed, one of my colleagues gave an example of how this actually happened in recent memory.

The translation team received a bug report that one of the programs had mistranslated “Y/N”. They fixed the translation, but since the fix was going out in a servicing release, they couldn’t change the existing incorrect string because that would invalidate Language Interface Packs. Instead, they had to abandon the old string and create a new one. All the languages would then translate the new string to Yes and No, which would just be copied from the existing translation, except for the language that had an incorrect translation, in which case it would be re-translated, but correctly this time. The program would switch to using the new better-translated string for determining whether the user responded in the affirmative or negative, and the old string would become orphaned, waiting to be cleaned up at the next major release.

If the customer had been extracting strings directly from the binary, they would continue extracting the yes/no string from its old location, even though the program was using the string in its new location.

The customer should provide appropriate affirmative and negative answers, or even better, avoid having to answer the question at all. I forget which program it was, but maybe it had a /F or /Q option to suppress the confirmation prompt. Even better would to avoid the console program at all and access the underlying functionality in a programmatic way. (For example, use Copy-Item or CopyFile instead of xcopy.exe; or use Set-ItemProperty or RegSetValueEx instead of reg.exe.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

26 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Daniel Flöijer

    I don't like calling executables programmatically either, but sometimes they provide something that's not available another way. Besides many 3rd party executables one example that I ran into is appcmd.exe that can shutdown an appool in IIS syncronously while the powershell command PS module WebAdministration only offers async. That means that if you're waiting for the apppool to shut down before doing something, like updating a database, you have to create a loop to check if the appool has finished shutting down. You then run into the issue of if you should wait between each check in the loop, creating...

    Read more
  • Ivan Kljajic

    Isn’t the solution to this to just have the program make a call to an online LLM to resolve the mismatch and act based on the response? The first letter of the acronym literally describes the issue…. ..

    • Richard Ward

      “Large”?

  • Mason Wright

    A useful reminder that resource strings are not an API surface and should never be treated as one. The example with LIPs and servicing updates illustrates the core risk clearly: even a “minor” localization fix can invalidate any logic that scrapes strings from binaries. From an automation and reliability standpoint, the only safe options are documented switches (e.g., /Q, /F), structured APIs, or higher-level tooling designed for non-interactive use. Anything else is effectively coupling to an implementation detail and will eventually break, often silently.

  • alan robinson · Edited

    you know, I can see both sides of this. Really the solution that would be kindest is some kind of global string table for common prompts that would potentially be improved or changed over time but still would have the same ID number so that your static reference could be unchanging for all time.

    Since that doesn’t exist of course people go looking for an equivalent like, you have. Without endorsing your solution I’m curious how often you’ve actually had to update your program because of breaking issues relating to this? It sounds like not at all.

    • Jan Ringoš

      Ah, I didn't notice this was directed at me.
      How often did I actually had to update any of my programs because Microsoft made a breaking change? Zero times!

      Or rather: Almost once...

      In one of my very old projects (embedded SW running on XP/POSReady09) I used a few strings from CMD.EXE in an administrative tool. This device run for 15 years without anyone ever updating the OS or touching anything, and then was scrapped. But once the client considered upgrading it to 8.1 (Industrial Embedded), and in early test I noticed some strings were not showing in the tool. They abandoned...

      Read more
      • Jan Ringoš · Edited

        Raymond, regarding me externalizing the costs, I perfectly well understand your sentiment here. But you are arguing something that hasn't been the case for maybe 15 years now.

        For one) Over my recent career I've never even heard of anyone successfully filling an appcompat bug with Microsoft, certainly not against highly custom software from a small company like ours. I don't even think it would occur to our customers to do that, instead of just reporting it to us. The joke about their printer, I made below, isn't exactly a joke.

        But I hear all over X and Reddit from people reporting...

        Read more
      • Raymond ChenMicrosoft employee Author · Edited

        : How often did I actually had to update any of my programs because Microsoft made a breaking change? Zero times

        Has it occurred to you that perhaps the reason is that the Windows team tried to change the string and got an app compat bug filed against them? You’re externalizing the cost of translation.

        If you want the word “bytes” you can use SHFormatByteSize.

    • Raymond ChenMicrosoft employee Author

      “It sounds like not at all.” I literally gave an example in the article.

      • Raymond ChenMicrosoft employee Author · Edited

        : Of the risks, yes. But not an actual example of a place where it broke.

        @alan robinson: The scenario I described in the article actually happened. It is not theoretical. (Went back and double-checked. Yup the article says “actually happened”.)

      • alan robinson

        Of the risks, yes. But not an actual example of a place where it broke? However, to be clear this comment was directed at Jan Ringoš, and Microsoft’s not very good blog system erroneously attached it to the top level of the thread, rather than the actual subpost. Or maybe I clicked “wrong”.