マーク・ルシノヴィッチ 2006年11月1日発行
Introduction
NT のアーキテクチャに関する知識がある場合は、Win32 アプリケーションで使用される API が "実際の" NT API ではないことを認識している可能性があります。 POSIX、OS/2、Win32 を含む NT のオペレーティング環境は、独自の API を介してクライアント アプリケーションと通信しますが、NT "ネイティブ" API を使用して NT と通信します。 ネイティブ API はほとんど文書化されていません。250 個の関数のうち約 25 個のみが、Windows NT Device Driver Kit で説明されています。
しかし、ほとんどの人が知らないのは、どの運用環境のクライアントでもない "ネイティブ" アプリケーションが NT 上に存在することです。 これらのプログラムはネイティブ NT API を話し、Win32 などのオペレーティング環境 API を使用できません。 このようなプログラムが必要になる理由" Win32 サブシステムが起動する前に実行する必要があるプログラム (ログオン ボックスが表示される頃) は、ネイティブ アプリケーションである必要があります。 ネイティブ アプリケーションの最も目に見える例は、初期化ブルー スクリーン中に chkdsk を実行する "autochk" プログラムです ("."画面に表示されます)。 当然ながら、Win32 オペレーティング環境サーバー (CSRSS.EXE (Client-Server ランタイム サブシステム) もネイティブ アプリケーションである必要があります。
この記事では、ネイティブ アプリケーションの構築方法と動作方法について説明します。
Autochk の実行方法
Autochk は、NT のブート ドライバーとシステム起動ドライバーが読み込まれる間、およびページングが有効になる間に実行されます。 この時点で、ブート シーケンス セッション マネージャー (smss.exe) は NT のユーザー モード環境をオフザグラウンドで取得しており、他のプログラムはアクティブになっていません。 HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute 値 (MULTI_SZ) には、セッション マネージャーによって実行されるプログラムの名前と引数が含まれており、ここで Autochk が指定されます。 この値を見ると、通常は次のようになります。ここで、"Autochk" は引数として "*" が渡されます。
Autocheck Autochk *
セッション マネージャー は、 <winnt>\system32 ディレクトリで、この値に一覧表示されている実行可能ファイルを探します。 Autochk を実行するとファイルが開かないため、 Autochk はブート ドライブを含む生モードで任意のボリュームを開き、ディスク上のデータ構造を操作できます。 これは後の時点では不可能です。
ネイティブ アプリケーションのビルド
Microsoftはそれを文書化しませんが、NT DDK ビルド ユーティリティはネイティブ アプリケーションの作成方法を認識しています (また、Autochk のコンパイルに使用される可能性があります)。 デバイス ドライバーの場合と同じように、アプリケーションを定義する SOURCES ファイルで情報を指定します。 ただし、ドライバーが必要であることをビルドに示す代わりに、次のような SOURCES ファイルにネイティブ アプリケーションが必要であることを示します。
TARGETTYPE=PROGRAM
Build ユーティリティでは、標準のメイクファイル \ddk\inc\makefile.def を使用します。このファイルは、ネイティブ アプリケーションのコンパイル時に nt.lib という名前のランタイム ライブラリを検索します。 残念ながら、MicrosoftはDDK(Server 2003 DDKに含まれています)でこのファイルを出荷していませんが、そのバージョンにリンクすると、ネイティブアプリケーションがXPまたはWindows 2000で実行されないと思われます。 ただし、この問題を回避するには、visual C++のランタイム ライブラリ msvcrt.lib を指定して nt.lib の選択をオーバーライドする makefile.def に行を含めます。
DDK の "Checked Build" 環境で Build を実行すると、\lib %BASEDIR%%CPU%\Checked (例: c:\ddk\lib\i386\checked\native.exe) の下に完全なデバッグ情報を含むネイティブ アプリケーションが生成され、"Free Build" 環境で呼び出すと、プログラムのリリース バージョンは %BASEDIR%\lib%CPU%\Free になります。 これらは、デバイス ドライバー イメージがビルドによって配置されるのと同じ場所です。
ネイティブ アプリケーションには ".exe" ファイル拡張子がありますが、Win32 .exeのように実行することはできません。 試してみると、次のメッセージが表示されます。
アプリケーションを NT モードWindows実行できません。
ネイティブ アプリケーション内で
winmain または main の代わりに、ネイティブ アプリケーションのエントリ ポイントは NtProcessStartup です。 また、他の Win32 エントリ ポイントとは異なり、ネイティブ アプリケーションは、コマンド ライン引数を検索する唯一のパラメーターとして渡されるデータ構造に到達する必要があります。
ネイティブ アプリケーションのランタイム環境の大部分は、NT のネイティブ API エクスポート ライブラリである NTDLL.DLL によって提供されます。 ネイティブ アプリケーションでは、NTDLL 関数 である RtlCreateHeap を使用してストレージを割り当てる独自のヒープを作成する必要があります。 メモリは RtlAllocateHeap を使用してヒープから割り当てられ、 RtlFreeHeap で解放されます。 ネイティブ アプリケーションが画面に何かを出力する場合は、初期化ブルー スクリーンに出力する NtDisplayString 関数を使用する必要があります。
ネイティブ アプリケーションは、Win32 プログラムのようなスタートアップ関数から単に戻るわけではありません。戻るランタイム コードがないためです。 代わりに、 NtProcessTerminate を呼び出して自分自身を終了する必要があります。
NTDLL ランタイムは、ネイティブ アプリケーションがファイル I/O を実行し、デバイス ドライバーと対話し、プロセス間通信を実行できる何百もの関数で構成されています。 残念ながら、前に述べたように、これらの機能の大部分は文書化されていません。