Open4

Win32sのメモ

okuokuokuoku

別にWin16で頑張らなくてもWin32sがあるからそれで良いやんという気もしていたが、これはなかなか厳しそうだ。。

okuokuokuoku

Win32s とは

Win32sは元々DOSベースだったWindows3.1xにWin32 APIを 後付け したもの。WindowsにせよMacOSにせよ超絶技巧で色々と後付けされているがWin32sもなかなかのものになっている。

https://en.wikipedia.org/wiki/Win32s

... が、まともな資料が全然無い。。WebArchiveには2つのtechnoteがある。

現代のOSでは、例えばmacOSがRosetta2でIntelバイナリをARM上で動作させているが、Win32sは全く互換性の無い2つのABI(いわゆるWin16とWin32)をUniversal Thunk(UT)と呼ぶ手法で 単一プロセス内で 共存させている点が特殊と言える。

okuokuokuoku

提供するものしないもの

Win32sは以下を提供する:

  • Win3.1x向けの32bit PE(Portable Executable)ローダー
  • FPUエミュレーション 。つまりWin32アプリはFPUの存在を仮定して良い。但しFPU例外がSEH(構造化)を起動する場合の挙動が若干異なる。
  • それなりのカバー率のWin32 → Win16 APIブリッジ (殆どのコードの実装は本来のWin3.1のものを直接使用する = 機能性は全体にWin3.1に制約される)
  • UTによる、Win32向けWin16 DLL呼出し機構(ABIおよびポインタの変換、キャッシュ)
  • Win16プロセス ←→ Win32プロセス間のプロセス間通信(Windowメッセージ、OLE、クリップボード)
  • 限定的なUnicodeサポート

しかし、Win32を完全に実装しているわけではなく、以下が使用できない:

  • DOSやBIOSの直接呼出し -- Win3.1の.exeは実質的にDOSの.exeなのでこれらを実施できた。ちなみにWin9x時代はI/Oポートの利用は許容されていたためハードウェアの直接アクセスはWin32でも可能な時期が存在した。
  • スレッドとプリエンプティブなマルチタスク -- 近代のWebブラウザ等と同様にシステム全体で1つのメッセージキューを使用している状況になる。ただし Yield(実行権限の明示的な受けわたし) は可能。
  • Sleep はYieldでエミュレートされる。Win3.1は協調的マルチタスクなのでSleepは意味が無い。
  • TLS(Thread Local Storage)はエミュレートされるが、Win3.1はシングルスレッドなので当然1つしか存在しない。特にDLLの場合Win3.1ではDLLのデータ自体がシステムで1つなのでその制約も引き継がれる。
  • Path、ベジェ曲線などWin32で拡張されたGDI機能全て
  • mmap(MapViewOfFile)できるファイルオフセットは4GiBまで
  • APIに渡せる配列のサイズは64KiBまで
  • マルチメディアAPIのうち、Win3.1で割り込みコンテキストを使用して実装されているものは動作しない。 midiOutOpenmidiInOpentimeSetEventtimeKillEvent
  • PlaySound APIのうち SND_ALIASSND_FILENAMESND_NOWAIT の各フラグは未実装となっている

現代的なPC向けOSと異なり、Windows 3.1xは全てのプロセスが基本的に単一のメモリ空間を共有するため、

  • .exeはPosition Independentでなければならない
  • GlobalAllocの実装が他のWin32と異なる(Win3.1側のGlobalAllocをそのまま使う)

という追加の制約がある。特に、前者の制約のためWin32sで動作するWin32アプリは(簡単に言えば)DLLとしてリンクされる必要がある。

(Windows 3.1xまでのWindowsは、アプリケーションが全てDLLであると考えると理解しやすい。アプリケーションは個々のWindowのコールバックを提供するのみで、近代的なOSにおけるプロセスの概念はほぼ通用しない。このため、1つのアプリケーションのクラッシュが破滅的な結果となる。Windows NTやWindows CEは完全なプロセス分離をサポートしているが、いわゆるChicago系列のOS -- Win95/98/ME -- は16bitアプリとの互換性のために単一プロセスに近いモデルを維持しつづける事になった。)

後者の制約はちょっと理解しづらいが、いわゆる "Win32s環境ではプロセスは16MiBのメモリしか使えない" の根拠となる。Win3.1の GlobalAlloc はプロセスあたり16MiB - 64KiBの領域しか割りあてられない。Win32sはWin16側との交信領域として、スタックまたはグローバルヒープを使うので、結果的にアプリケーション側が利用できるメモリ量が制約されることになる。

Win32はリソース類をUnicode化したが、Win3.1はUnicode以前のOSなので、Win32sのランタイム側で暗黙に変換されるようになっている。また、Unicode版のAPIは実装されていない。