Why does Windows keep showing the old indirect strings even after I update the binary?
If your application uses indirect localized string resources,and you update the application, you may find that Windowskeeps using the old string from the previous version of theapplication.
For example,suppose that you set the localized name for a shortcut to
@C:\Program Files\Contoso\Contoso.exe,-1,and in version 1 of your program,you have
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Document Services" END LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Dokumentdienste" END
For version 2, your marketing team decides that theprogram should really be calledContoso Document System,so you change the resource file to read
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Document System" END LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Dokumentsystem" END
The user upgrades to version 2 of your program, but theshortcut on the Start menu still readsContoso Document Services.What’s going on?
The shell keeps a cache of indirect localized strings becauseloading a DLL just to read a string out of it is pretty expensive.This cache is keyed by the string location specifier,and since your string location specifier hasn’t changedfrom its previous value of
@C:\Program Files\Contoso\Contoso.exe,-1,the shell continues using the value it stored away in its cache,which if the user had previously been using version 1 of yourprogram, is the string Contoso Document Services.
Some people, having discovered this behavior, have tried to go inand tinker with the shell’s internal cache of indirect localized strings,but such a technique is doomed to failure because the location of thatcache changes pretty regularly,and besides, it’s an internal implementation detail.(And even if you find it and manage to fiddle with it,you only fix the problem for the current user.Other users will still have the stale cache entry.)
The best solution is to treat indirect strings as locked:Once you decide what a string should say, you can’t change it.When you issue version 2 of
Contoso.exe,you can create a second string
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Document Services" // shortcuts from version 1.0 use this 2 "Contoso Document System" // shortcuts from version 2.0 use this END LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL STRINGTABLE BEGIN 1 "Contoso Dokumentdienste" // shortcuts from version 1.0 use this 2 "Contoso Dokumentsystem" // shortcuts from version 2.0 use this END
and have the installer for version 2.0 create a shortcutwhose indirect localized string specifier is
I admit that this method is rather clumsy and requires more attentionon the part of the developer.Everybody wants the “cheap” way out, where the definition of “cheap”is not “cheapest for the customer” but rather “cheapest for me,the developer, because there’s a new episode ofDoctor Whotonight and I don’t want to miss it.”
We saw last time thatthe format for indirect localized string resourceshas room for a comment.And it’s the comment that we can take advantage of here.The shell uses the entire string location specifier as the key forits cache lookup, and that string includes the comment.Therefore, if you simply change the comment, that results in a cachemiss, and the shell will go and re-fetch the string.
By appending a
;v2 to the string, you made it differentfrom its predecessor, which means that the string cached by thepredecessor won’t be used.
As I noted, this is cheap for the developer, but not necessarilycheap for the customer.Suppose the customer copied the shortcut to Contoso version 1to their desktop,then upgraded to version 2.The upgrade replaces the shortcut in the Start menu, but thecopy on the desktop remains unchanged.You now have a shortcut on the desktop whose indirect string is
and a shortcut on the Start menu whose indirect string is
Since the shortcut on the desktop was created while version 1was still installed on the computer,its name will read Contoso Document Servicesbecause that was the contents of string 1.On the other hand, the shortcut on the Start menu will readContoso Document System because its use of the
;v2forced the shell to go back and look again,and this time it sees the revised string.So far so good.
But then the user does something which causes the cache to be pruned,like, say,changing their UI language to German.The shell says,“Okay, the UI language changed, I need to go reload all theseindirect strings because MUI is going to change them to the new language.”The shell sees the shortcut on the Start menu, reads string 1out of
Contoso.exe, and getsContoso Dokumentsystem.The shell then sees the shortcut on the desktop, reads string 1out of
Contoso.exe, and gets…Contoso Dokumentsystem.Not Contoso Dokumentdienste.
Notice that the name of the shortcut on the desktop was silentlyupgraded to Contoso version 2.
Even if the user changes the language back to English in an attemptto get things back to the way they were, it won’t work.The shell sees the shortcut on the Start menu, reads string 1out of
Contoso.exe, and getsContoso Document System.The shell then sees the shortcut on the desktop, reads string 1out of
Contoso.exe, and getsContoso Document System,not Contoso Document Service.The original string from the first version of
Contoso.exeis already gone; the only way to get it back is to reinstallContoso version 1.
But at least you didn’t miss your TV show.
Bonus chatter:The one case I can think of where the cheap way out isacceptable is when you are issuing a prerelease version.For your prerelease versions, you can append
;prerelease build xxxxx to your stringlocation specifier (where
xxxxx is the build number),so that each time the user upgradesto a new build, the string is reloaded from scratch.This still has the same problem described above if the userhas data left over from a previous build, but since it’sa prerelease build, you can just declare that as not asupported configuration.