Incompatible Application Tales

Original author: Raymond Chen
  • Transfer
These are excerpts from the free chapter in The Old New Thing. They are not trying to teach anything; these are just short fun episodes from the everyday life of fighters for compatibility of new versions of Windows with old applications.

Change the version number of Windows

Changing the version number that Windows tells programs is not easy as it seems. For example, some programs check the version number as follows:
UINT Ver = GetVersion ();
UINT MajorVersion = LOBYTE (uVer);
UINT MinorVersion = HIBYTE (uVer);
if (MajorVersion <3 || MinorVersion <10) {
    Error ("This program requires Windows 3.1");

Imagine how this code works on Windows 95, which has a version number of 4.0. The second check is triggered due to the fact that 0 is less than 10.
And well, the program would simply display an error message and exit. Many collapsed: it was obvious that their behavior on "unsupported" versions of Windows was never tested.

There were so many such programs that we stopped fixing them one at a time, and simply changed the returned version number from 4.0 to 3.95.

Programs for MS-DOS, too, did not all respond smoothly to changing the OS version. This is surprising because by then MS-DOS already had dozens of released versions and sub-versions, and it would be time for developers to learn how to check the version number. But for example, one software package used the DOS version number as an index in the function table: by its own function for each released version. The table had five functions: from MS-DOS 1.x to 5.x. When the program started under MS-DOS 6.0, it called the address outside the table and crashed.

Changing the version number that Windows tells programs is a necessary but very difficult step. A couple of keys pressed, and hundreds of applications that have worked so far well fall; Now the compatibility department will have to spend an extra thousand man-hours to catch other people's bugs.

We inform developers about a bug in their program

Specifically, this conversation is fictitious, but essentially similar conversations have occurred more than once.

—Hello, this is such and such, from the Microsoft Windows compatibility department. We found a bug in your program due to which it did not work. We were forced to add code to bypass this bug in Windows 95 so that your program continues to work.
- Remarkably, thank you very much! Bye. ( Short beeps. )
(We dial the number again.) “
“Hello, uh ... You don’t even want to know what the bug was?”
-What's the difference? You corrected everything. Thanks! What would we do without you!
“But, uh, a bypass code will only work with the current version of your program.” When you release the next version, it will not work.
“That's how it is? .. Well, wait, I'll connect you with our programmers.”

Developers do not pay attention to you at all until you mention that their program will stop working.

When I was engaged in backward compatibility with programs for MS-DOS (mostly these were games), it often happened that I called to inform developers that their program does not work under Windows 95. Many developers answered simply “That's right, we do not work with Windows. "

We remind users to act strictly according to the instructions

A neighbor of one of our developers bought a program that crashed immediately upon launch. The developer and his colleagues started with the standard procedure - they changed drivers, started on another computer - but nothing helped. Desperate to cope with the problem on their own, they called the developers.

Technical support explained to them: if during installation you do not fill in all three fields - name, organization and serial number - then the installation is successful, but the program will crash at startup. And this is not a sophisticated copy protection, but a documented bug.

Put the cart in front of the horse

Sometimes such terrible bugs are found in programs that it is not clear how they even work.

The installer of one popular program is trying to replace the system file with its own version. It replaces the file, even if this native version is older than the one already installed in the system: the installer does not bother with version checking.
Great, the Windows file protection system is closely monitoring such programs, and it will restore the correct version as soon as the installation is complete. That is not the problem.

If the system file that the installer is trying to replace is busy, the installer overwrites it with the option MOVEFILE_DELAY_UNTIL_REBOOTto have the busy file replaced when the system reboots:
// Code simplified for clarity
MoveFileEx ("", "sysfile.dll", MOVEFILE_DELAY_UNTIL_REBOOT);
CopyFile ("D: \\ CDROM \\ INSTALL \\ sysfile.dll", "");

So it is - the program is trying to copy a file that does not yet exist!
This code really worked on Windows NT, because there the function MoveFileEx, when it was called from MOVEFILE_DELAY_UNTIL_REBOOT, did not check if the file being copied exists. In the beta version of Windows 2000, we added a more stringent parameter check; now MoveFileExreturned an error. The installer considered this error to be fatal, and terminated the installation.

Windows 2000 had to allow copying of nonexistent files with the option MOVEFILE_DELAY_UNTIL_REBOOT. MoveFileExreports successful execution - in the hope that by the time of the reboot the copied file will indeed appear.

The strangest way to verify call success

I have no idea what they think the developers a multimedia program that checking the success of Call of multimedia functions, did not compare the return MMRESULTwith MMSYSERR_NOERROR, and received for a text description of the error number, and then compares this string with «The specified command complete successfully.»
On in fact, she compared only the first sixteen characters with “The specified co” - probably someone was looking at the code and decided to optimize this place.
In one version of Windows, when we paraphrased this message a little, the program stopped working. Needless to say, it never worked on non-English versions of Windows.

A stranger than the strangest way to test call success

What would you think? There is an even stranger way. At a minimum, the previous program worked with a return error code. Another program that used MCI to play videos completely ignored the value returned by the call MCIWndOpen. Instead, she read the title of the MCI window and compared it to the “No Device” line to determine if the file was opened successfully.

In Windows 95, the title of the MCI window when opening a file was set with a slight delay. Now that program could not open the videos: she checked the window title too early.

How to make a mistake in a function from one line

Once an employee came into my office and asked: “Hey, do you want a sound card?” I didn’t have my own sound card, so I agreed.

It turned out that he gave me this card for a reason: he could not get it to work under Windows 95. Now he is not, but I was a loser with a broken sound engine. Soon I realized why he so wanted to get rid of her: periodically she destroyed the whole system. A debug version of Windows was installed on my machine so that I could find out the cause of the crashes.

The developers of the driver for this sound card took a function from one line, a sample of which is given in the DDK, and they managed to make a mistake in it.
Here is a sample function in DDK:
void FAR PASCAL midiCallback (NPPORTALLOC pPortAlloc, WORD msg,
                             DWORD dwParam1, DWORD dwParm2) {
  if (pPostAlloc-> dwCallback)
    DriverCallBack (pPortalloc-> dwCallback, HIWORD (pPortalloc-> dwFlags),
                   pPortalloc-> hMidi, msg, dwParam1, dwParam2);
It is called by the system during a hardware interrupt.

This is what this function looked like in that driver:
void FAR PASCAL midiCallback (NPPORTALLOC pPortAlloc, WORD msg,
                             DWORD dwParam1, DWORD dwParm2) {
  char szBuf [80];
  if (pPostAlloc-> dwCallback) {
    wsprintf (szBuf, "Dc (hMidi =% X, wMsg =% X)", pPortalloc-> hMidi, msg);
#ifdef DEBUG
    OutputDebugString (szBuf);
    DriverCallBack (pPortalloc-> dwCallback, HIWORD (pPortalloc-> dwFlags),
                   pPortalloc-> hMidi, msg, dwParam1, dwParam2);

They not only left the remains of debugging code in the final version of the driver; during a hardware interrupt, they call a function that cannot be called at this time. If it is wsprintfunloaded from memory, then the system receives a new “missing segment” interrupt during a hardware interrupt, and that’s it. Even if you are lucky and wsprintfare in memory, this function changes the upper word of 32-bit registers, and the hardware interrupt handler saves only the lower word. This means that the interrupted code is waiting for a very rude awakening when the interrupt processing is completed.

Despite all this, the sound card received the award of one popular computer magazine.
But this was not the end of the injustice: the card manufacturer wanted Windows 95 to include a new version of their driver. And what did we see in the new version? The same bug crashing the system is the one we showed them to programmers a few months ago. As you might guess, the new version of the driver was not included in Windows 95.

Sound editor and annoying parasite

We came across one tutorial that parasitized on the standard Sound Editor and clung to it so deeply that the further we studied it, the more we were struck.

The first problem was banal: the program launched in sound editor named its 16-bit version SOUNDREC.EXE. In Windows 95, the Sound Editor was 32-bit, and was called SNDREC32.EXE- just like in Windows NT. We renamed the file back to a 16-bit name, and we thought that now the program would work.

But she did not work. Having successfully launched the editor, the program searches for its window by title. First she tries to find the English headline, then Italian (the program was developed for Italians). Not so bad: many developers did not even think about supporting localized editions of Windows. True, Italians living, say, in France, will not be able to take advantage of this program; but that is not our concern.
In Windows 95, the title of the Sound Editor has changed: we added the name of the open file there. Now the program could not find the editor window that launched.

Then we changed the title of the 16-bit Sound Editor to exactly match the title used in Windows 3.1. Finally, the program started. We followed her and found that she never used the running editor! Why did she run it?

It turned out that in certain conditions she really uses it. Usually it plays sounds using a special component ( apparently it was VBX ), which supports asynchronous sound card drivers, but does not support the synchronous driver SPEAKER.DRV, which allows computers without sound cards to play sounds through the speaker.
The developers were looking for something that could work with this synchronous driver - and found the Sound Editor. To imitate the keystrokes in his window - and a cheap replacement for the player component is ready.

But if you pay attention at the time the program starts, you can notice how the Sound Editor window flickers and disappears immediately, leaving only a strip on the left of the screen. Programmers did not want the editor window to be visible. But they did not know how to make the window invisible, so they did everything in their power: they "dragged" the window off the screen. Well, almost beyond. They did not even know how to move the window programmatically, so they imitated clicks and mouse movements, as if they were dragging the window by the title bar. When only a narrow strip remains on the screen, which the mouse can no longer drag further to the left, programmers consider their task to be completed: “We removed the window behind the screen - probably no one will notice it.”

I advise you to look at the same time my last translation - Favorite "iron" bug

Also popular now: