互換性のないアプリケーションの話

これらはThe Old New Thingの無料章からの抜粋です。 彼らは何も教えようとしません。 これらは、新しいバージョンのWindowsと古いアプリケーションとの互換性についての戦闘機の日常生活からの短い楽しいエピソードです。

Windowsのバージョン番号を変更する


Windowsがプログラムに通知するバージョン番号を変更するのは、見た目ほど簡単ではありません。 たとえば、一部のプログラムは次のようにバージョン番号を確認します。
 UINT Ver = GetVersion();
 UINT MajorVersion = LOBYTE(uVer);
 UINT MinorVersion = HIBYTE(uVer);
 if(MajorVersion <3 || MinorVersion <10){
    エラー(「このプログラムにはWindows 3.1が必要です」);
 }

バージョン番号が4.0のWindows 95でこのコードがどのように機能するかを想像してください。 2番目のチェックは、0が10より小さいためにトリガーされます。
そして、プログラムは単にエラーメッセージを表示して終了します。 多くが崩壊しました。「サポートされていない」バージョンのWindowsでの動作がテストされなかったことは明らかでした。

そのようなプログラムが非常に多かったため、一度に1つずつ修正するのをやめ、返されたバージョン番号を4.0から3.95に変更しました。

MS-DOS用のプログラムも、OSバージョンの変更にすべてスムーズに反応しませんでした。 MS-DOSにはすでに多数のリリースバージョンとサブバージョンがあり、開発者がバージョン番号を確認する方法を学ぶ時が来たので、これは驚くべきことです。 しかし、たとえば、あるソフトウェアパッケージでは、DOSバージョン番号を関数テーブルのインデックスとして使用していました。リリースされた各バージョンの独自の関数です。 テーブルには、MS-DOS 1.xから5.xまでの5つの機能がありました。 プログラムがMS-DOS 6.0で起動すると、テーブル外のアドレスを呼び出してクラッシュしました。

Windowsがプログラムに通知するバージョン番号を変更することは、必要ですが非常に難しい手順です。 いくつかのキーが押され、今までうまく機能していた何百ものアプリケーションが落ちます。 これで、互換性部門は他の人のバグをキャッチするためにさらに1,000時間を費やす必要があります。

開発者にプログラムのバグについて通知します


具体的には、この会話は架空のものですが、本質的に同様の会話が複数回発生しています。

「こんにちは?」
—こんにちは、これはMicrosoft Windows互換性部門からのものです。 プログラムでバグが見つかりましたが、機能していません。 プログラムが引き続き機能するように、Windows 95でこのバグをバイパスするコードを追加する必要がありました。
-驚くことに、どうもありがとう! またね ( 短いビープ音。
(再度番号をダイヤルします。)
「こんにちは?」
「こんにちは、あの...バグが何なのか知りたくないですか?」
「違いは何ですか?」 すべてを修正しました。 よろしくお願いします! あなたなしでは何をするでしょう!
「ただし、バイパスコードは、現在のバージョンのプログラムでのみ機能します。」 次のバージョンをリリースすると、機能しなくなります。
「それはどうですか?..まあ、待って、私たちをプログラマーとつなげます。」

開発者は、プログラムが機能しなくなると言及するまで、まったく注意を払いません。

MS-DOSのプログラム(主にこれらはゲーム)との下位互換性に従事していたときに、プログラムがWindows 95で動作しないことを開発者に通知するために電話をかけることがよくありました。 Windows。」

指示に従って厳密に行動することをユーザーに思い出させます


開発者の1人の隣人が、起動直後にクラッシュするプログラムを購入しました。 開発者と彼の同僚は、標準の手順から始めました-彼らはドライバーを変えて、別のコンピューターで始めました-しかし、何も助けませんでした。 自分で問題に対処するために必死で、彼らは開発者に電話しました。

技術サポートはそれらに説明しました:インストールの間に3つのフィールドすべて-名前、組織およびシリアル番号-を記入しない場合インストールは成功しますが、プログラムは起動時にクラッシュします。 そして、これは洗練されたコピー保護ではなく、文書化されたバグです。

カートを馬の前に置きます


そのような恐ろしいバグがプログラムで見つかることがあり、それらがどのように機能するかさえ明確ではないことがあります。

人気のあるプログラムのインストーラーは、システムファイルを独自のバージョンに置き換えようとしています。 このネイティブバージョンがシステムに既にインストールされているものよりも古い場合でも、ファイルを置き換えます。インストーラーはバージョンチェックを気にしません。
すばらしいことに、Windowsファイル保護システムはそのようなプログラムを注意深く監視しており、インストールが完了するとすぐに正しいバージョンを復元します。 それは問題ではありません。

インストーラーが置き換えようとしているシステムファイルがビジーの場合、インストーラーはそれをMOVEFILE_DELAY_UNTIL_REBOOTオプションで上書きし、システムの再起動時にビジーファイルが置き換えられるようにします。
 //わかりやすくするためにコードを簡素化
 MoveFileEx( "sysfile.new"、 "sysfile.dll"、MOVEFILE_DELAY_UNTIL_REBOOT);
 CopyFile( "D:\\ CDROM \\ INSTALL \\ sysfile.dll"、 "sysfile.new");

そうです-プログラムは、まだ存在しないファイルをコピーしようとしています!
MOVEFILE_DELAY_UNTIL_REBOOTMoveFileEx関数が呼び出されたMOVEFILE_DELAY_UNTIL_REBOOT 、コピーされるファイルが存在するかどうかをチェックしなかったため、このコードはWindows NTで実際に機能しました。 Windows 2000のベータ版では、より厳密なパラメーターチェックを追加しました。 MoveFileExがエラーを返しました。 インストーラーはこのエラーを致命的であると見なし、インストールを終了しました。

MOVEFILE_DELAY_UNTIL_REBOOTオプションを使用して、Windows 2000が存在しないファイルをコピーできるようにするMOVEFILE_DELAY_UNTIL_REBOOTました。 MoveFileExは、実行が成功したことを報告します-再起動の時点で、コピーされたファイルが実際に表示されることを期待して。

呼び出しの成功を確認する最も奇妙な方法


あるマルチメディアプログラムの開発者が何を考えているのかMMRESULTません。マルチメディア関数の呼び出しの成功をチェックし、返されたMMRESULTMMSYSERR_NOERROR比較せず、エラー番号のテキスト説明を受け取り、この行を「指定されたコマンドが正常に完了しました。 」
実際、彼女は最初の16文字のみを「指定されたco」と比較しました。おそらく誰かがコードを見て、この場所を最適化することを決めたのでしょう。
Windowsのあるバージョンでは、このメッセージを少し言い換えると、プログラムが動作しなくなりました。 言うまでもなく、英語版以外のWindowsでは機能しませんでした。

コールの成功をテストする最も奇妙な方法よりも見知らぬ人


どう思いますか? さらに奇妙な方法があります。 少なくとも、以前のプログラムは戻りエラーコードで動作しました。 MCIを使用してビデオを再生する別のプログラムは、 MCIWndOpenを呼び出して返される値を完全に無視しMCIWndOpen 。 代わりに、MCIウィンドウのタイトルを読み取り、「デバイスなし」行と比較して、ファイルが正常に開かれたかどうかを判断しました。

Windows 95では、ファイルを開くときのMCIウィンドウのタイトルが少し遅れて設定されていました。 そのプログラムはビデオを開くことができませんでした。彼女はウィンドウタイトルを早めにチェックしました。

関数を1行から間違える方法


従業員が私のオフィスに来て「ねえ、あなたはサウンドカードが欲しいですか?」と尋ねたら、私は自分のサウンドカードを持っていなかったので、私は同意しました。

彼はこのカードをWindows 95で動作させることができなかったので、私にこのカードを渡してくれたことが判明しました。今はそうではありませんが、私は壊れたサウンドエンジンで負けました。 すぐに私は彼がなぜ彼女を追い出したかったのかを理解しました。彼女は定期的にシステム全体を破壊しました。 クラッシュの原因を特定できるように、デバッグバージョンのWindowsがマシンにインストールされました。

このサウンドカードのドライバーの開発者は、1行から関数を取得しましたが、そのサンプルはDDKに記載されており、なんとか間違えました。
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);
 }
ハードウェア割り込み中にシステムによって呼び出されます。

これは、このドライバーでこの関数がどのように見えるかです。
 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);
 #endif
     DriverCallBack(pPortalloc-> dwCallback、HIWORD(pPortalloc-> dwFlags)、
                    pPortalloc-> hMidi、msg、dwParam1、dwParam2);
   }
 }

これらは、ドライバーの最終バージョンにデバッグコードの残りを残すだけではありません。 ハードウェア割り込み中に、現時点では呼び出せない関数を呼び出します。 wsprintfメモリからアンロードされると、システムはハードウェア割り込み中に新しい「欠落セグメント」割り込みを受け取ります。 幸運にも、 wsprintfがメモリ内にある場合、この関数は32ビットレジスタの上位ワードを変更し、ハードウェア割り込みハンドラーは下位ワードのみを保存します。 これは、割り込み処理が完了すると、中断されたコードが非常に失礼な目覚めを待っていることを意味します。

これらすべてにもかかわらず、サウンドカードは、ある人気のコンピューター雑誌の賞を受賞しました。
しかし、これは不正の終わりではありませんでした。カードの製造元は、Windows 95に新しいバージョンのドライバーを含めることを望んでいました。 そして、私たちは新しいバージョンで何を見ましたか? システムをクラッシュさせるのと同じバグは、数か月前にプログラマに見せたものです。 ご想像のとおり、新しいバージョンのドライバーはWindows 95に含まれていませんでした。

サウンドエディターと迷惑な寄生虫


標準のサウンドエディタに寄生する1つのチュートリアルに出くわし、それを深くしがみついたので、それをさらに研究すればするほど、私たちは感動しました。

最初の問題はありふれたものでした。プログラムは、16ビットバージョンSOUNDREC.EXE名前でサウンドエディタをSOUNDREC.EXE 。 Windows 95では、サウンドエディターは32ビットで、 SNDREC32.EXEと呼ばれていました-Windows NTと同じです。 ファイルの名前を16ビットの名前に戻し、プログラムが動作するようになったと考えました。

しかし、彼女は働きませんでした。 エディターの起動に成功すると、プログラムはタイトルでウィンドウを検索します。 彼女は最初に英語の見出しを見つけようとし、次にイタリア語を探します(プログラムはイタリア人向けに開発されました)。 それほど悪くない:多くの開発者は、Windowsのローカライズ版のサポートについても考えていませんでした。 確かに、フランスに住んでいるイタリア人は、このプログラムを利用することはできません。 しかし、それは私たちの関心事ではありません。
Windows 95では、サウンドエディターのタイトルが変更されました。開いているファイルの名前をそこに追加しました。 これで、プログラムは起動したエディターウィンドウを見つけることができませんでした。

次に、16ビットサウンドエディターのタイトルを、Windows 3.1で使用されているタイトルと正確に一致するように変更しました。 最後に、プログラムが開始されました。 彼女をフォローしたところ、彼女は実行中のエディターを使用したことがないことがわかりました! なぜ彼女はそれを実行したのですか?

ある条件では、彼女はそれを本当に使用することが判明しました。 通常、非同期サウンドカードドライバーをサポートする特別なコンポーネント( 明らかにVBX )を使用してサウンドを再生しますが、同期ドライバーSPEAKER.DRVサポートしません。これにより、コンピューターはサウンドカードなしでスピーカーからサウンドを再生できます。
開発者は、この同期ドライバーで動作するものを探していました-そして、サウンドエディターを見つけました。 彼のウィンドウのキーストロークを模倣するために-プレイヤーコンポーネントの安価な代替品が用意されています。

ただし、プログラムの起動時に注意を払うと、サウンドエディタウィンドウがちらつき、すぐに消えて、画面の左側にストリップだけが残ることに気付くことができます。 プログラマーは、エディターウィンドウを表示したくありませんでした。 しかし、彼らはウィンドウを見えなくする方法を知らなかったので、彼らは力ですべてをしました:彼らはウィンドウを画面から「引きずりました」。 まあ、ほとんど超えています。 プログラムでウィンドウを移動する方法すら知らなかったため、タイトルバーでウィンドウをドラッグしているように、クリックやマウスの動きを模倣していました。 マウスが画面の左にドラッグできなくなった狭いストリップのみが残っている場合、プログラマはタスクが完了したと考えます。「画面の後ろのウィンドウを削除しました。おそらく誰も気付かないでしょう。」



私の最後の翻訳- お気に入りの「鉄」バグを同時に見ることをお勧めします

Source: https://habr.com/ru/post/J103598/


All Articles