ReactOS開発の手引き 2023-11-12

当サイトではアフィリエイト広告を利用しております。

ReactOS

概要

「Windows互換を目指すOS」ReactOSについて、開発者になるために必要な知識を解説します。

強力なデバッガであるWinDbgを使うと、WindowsやReactOSをデバッグしてどのように動作しているのかを調査できます。

必須条件

  • WindowsXP以降のPCを持っている
  • C言語の素養がある
  • 時間と精神力がある
  • メインメモリ4GB以上
  • 8GB以上の空きがあるSSD

ReactOSを試しに使ってみる

すでに用意されたISOイメージを使ってReactOSを気軽に試すことができます。

  1. ReactOSのホームページをよく読む(英語)。
  2. 仮想マシン(VirtualBox推奨)をインストールする (Other Windows (32-bit)) 。現在利用できるフリーの仮想マシンには、 QEMUVirtualBoxVMWare Workstation Player があります。
  3. ReactOSのISOイメージをダウンロードする。最新の正式リリースは0.4.14です(2023年3月現在)。正式リリースよりもNightly Buildが新しいですが、正式リリースに含まれている日本語フォントがありません。
  4. ISOイメージを使って仮想マシンにReactOSをインストールする。
  5. 仮想マシンでReactOSを試しに使ってみる。

ISOイメージは、CD-Rなどに焼いて実機で使うことができます(オススメはしませんが)。日本語フォントファイルがないISOファイルでは、アプリマネージャで「ReactOS JPN Package」をインストールすると日本語化できます。

ReactOSをビルドして使ってみる(MinGWの場合)

ReactOSの開発を始めたい、ReactOSを改変して試したい場合は、自分でReactOSをビルドする必要があります。

  1. ReactOS Development Wikiをよく読む(英語)。
  2. ReactOS Build Environment (RosBE)をhttps://reactos.org/wiki/ReactOS_Build_Environmentからインストールする(※C:\RosBEへのインストール推奨)。RosBEにはMinGWの開発環境が含まれています。
  3. お好みのGitクライアントをインストールする(Git for WindowsかMSYS2のどちらかインストールでgitコマンドを使えるようになる)。BashとGitについて少し勉強する。
  4. GitHubにSign upして、自分のGitHubアカウントを作成する。
  5. https://github.com/reactos/reactos をForkする(GitHub上でForkボタンを押す)。
  6. 適当な開発用のフォルダでGitクライアントで、「git clone http://github.com/(自分のGitHub ID)/reactos」を実行する。「reactos」フォルダができる。
  7. 日本語が必要ならば、「reactos/modules」フォルダに「optional」フォルダを作成して、その中にフォント「DroidSansFallback.ttf」ファイルを置く(https://svn.reactos.org/optional/ からダウンロードできます)。ブラウザが必要であれば、「modules/optional」フォルダに「wine_gecko-2.40-x86.msi」ファイルを置く。
  8. reactos」フォルダの中へ「cd」コマンドで移動し、RosBEで「configure -DENABLE_ROSTESTS=1 -DENABLE_ROSAPPS=1 -DCMAKE_GENERATOR:STRING=Ninja」を実行する(※1)。「output-MinGW-i386」フォルダが作成される。
  9. cd output-MinGW-i386」コマンドでフォルダの中に移動する。
  10. ninja bootcd」でビルド。コーヒーでも飲みながら待つ。「output-MinGW-i386」フォルダの中にISOファイル「bootcd.iso」が作成される。
  11. ビルドしたISOイメージを使って仮想マシン (Other Windows (32-bit)) にReactOSをインストールする。
  12. ビルドしたReactOSを使ってみる。

※1:「オレはRosTestsなんて使わねーよ」という人は「-DENABLE_ROSTESTS=1」を指定しないことでビルド時間・インストール時間が節約できます。

ReactOSをビルドして使ってみる(Visual Studioの場合)

WinDbgでReactOSをデバッグしたい場合は、Visual Studioでビルドして、シンボルファイル(*.pdb)を生成する必要があります。事前にVisual StudioのインストーラでVisual C++をインストールする必要があります。以下では、Visual Studio 2019を想定しています。

  1. ReactOS Development Wikiをよく読む(英語)。
  2. ReactOS Build Environment (RosBE)をhttps://reactos.org/wiki/ReactOS_Build_Environmentからインストールする(※C:\RosBEへのインストール推奨)。
  3. お好みのGitクライアントをインストールする(Git for WindowsかMSYS2のどちらかインストールでgitコマンドを使えるようになる)。BashとGitについて少し勉強する。
  4. GitHubにSign upして、自分のGitHubアカウントを作成する。
  5. https://github.com/reactos/reactos をForkする(GitHub上でForkボタンを押す)。
  6. 適当な開発用のフォルダでGitクライアントで、「git clone http://github.com/(自分のGitHub ID)/reactos」を実行する。「reactos」フォルダができる。
  7. 日本語が必要ならば、「reactos/modules」フォルダに「optional」フォルダを作成して、その中にフォント「DroidSansFallback.ttf」ファイルを置く(https://svn.reactos.org/optional/ からダウンロードできます)。ブラウザが必要であれば、「modules/optional」フォルダに「wine_gecko-2.40-x86.msi」ファイルを置く。
  8. VS Command Prompt (x86があればx86のコマンドプロンプトを使う) で「reactos」フォルダの中へcdコマンドで移動し、以下のコマンドを順番に実行する(※1)。
    • set PATH=C:\RosBE\bin;%PATH%
    • set M4=C:\RosBE\Bin\m4.exe
    • set BISON_PKGDATADIR=C:\RosBE\share\bison
    • configure.cmd -DENABLE_ROSTESTS=1 -DENABLE_ROSAPPS=1 -DCMAKE_GENERATOR:STRING=Ninja
  9. output-VS-i386」フォルダが作成される。
  10. output-VS-i386」フォルダの中にcdコマンドで移動し、「ninja bootcd」を実行してビルドする。お茶でも飲みながら待つ。
  11. しばらく待つと「output-VS-i386」フォルダの中にISOファイル「bootcd.iso」が作成される。
  12. output-VS-i386」フォルダの中にmsvc_pdbフォルダがある。これがWinDbgで使えるシンボルファイル(*.pdb)が含まれているフォルダです。
  13. ビルドしたISOイメージを使って仮想マシンにReactOS (Other Windows (32-bit)) をインストールする。
  14. ビルドしたReactOSを使ってみる。

※1:「オレはRosTestsなんて使わねーよ」という人は「-DENABLE_ROSTESTS=1」を指定しないことでビルド時間・インストール時間が節約できます。
※2:RosBEのCMakeは少しハックされたCMakeです。オリジナルのCMakeとはちょっと違います。

Win2003評価版のデバッグ方法(WinDbgを使用)

ReactOSはWindows Server 2003を参考にして作られています。Win2003の動作を深く調査するためには、Win2003をデバッグする必要があります。

  1. WinDbg Preview をストア(Microsoft Store)からインストールする。
  2. Win2003 Server評価版 をVirtualBoxにインストールする(評価版は期限切れのため、システム日時の変更が必要。日付を2008-01-01などに設定する)。
  3. 画面が停止して長時間、動かない場合は、手動でリセットする必要があるかもしれません(電源管理が古い。「仮想マシン」→「リセット」)。
  4. Win2003の電源を切る前に管理者権限のコマンドプロンプトで「bootcfg /debug ON /PORT COM1 /ID 1」を実行する。また、VirtualBox Guest Additionsも忘れずインストールする。
  1. Win2003の電源が切れたら、VirtualBoxの設定でシリアルポートCOM1にパイプ(\\.\pipe\com1)を設定する(下の画像参照)。「シリアルポート」の「シリアルポートを有効化」にチェックを入れ、「ポートモード」を「ホストにパイプ」に変更して、「パス/アドレス」に「\\.\pipe\com1」を指定する。チェックボックス「存在するパイプ/ソケットに接続」のチェックをはずす。※「\」は、半角の円記号です。
  1. WinDbgを起動し、「Settings」の「Debugging settings」で「Default symbol path」に「srv*」を設定。
  1. 「ファイル」メニューから「Attach to Kernel」を選択し、「Pipe」「Reconnect」にチェックを入れ、「Port」に「\\.\pipe\com1」を設定し、「OK」ボタンを押す。
  1. その後、Win2003を再起動すればデバッグが開始される。

仮想マシンの状態を保存するために、VirtualBoxを操作して仮想マシンのスナップショットを作成する。

WinDbgのコマンドについては以下を参照。

注意:システム日時が古い状態でソースファイルを編集しないで下さい。ターゲットファイルよりタイムスタンプの古いファイルは、更新なしと見なされます。

Win2003のデバッグの練習(WinDbgを使用)

では、実際にWin2003とWinDbgを使ってデバッグを試してみよう。今回は、explorer.exeSHELL32!SHFileOperationWをデバッグしてみます。SHFileOperationW関数は、文字通りファイルやフォルダをコピー・移動・削除などするシェル関数です。

  1. 期限切れ対策のためにシステム日時を変更する。
  2. 「ファイル」メニューから「Attach to Kernel」を選択し、「OK」をクリックする。
  3. デバッガが再接続待ちになる。デバッグを開始するためにWin2003を再起動する。
  4. 「Break」ボタンを押してブレークする。これでデバッガコマンドが入力できる状態になる。
  5. デバッガで「!process 0 0」コマンドを実行。プロセスのリストが表示される。そのリストの中からexplorer.exeを探す。
...
PROCESS 81dec8b0  SessionId: 0  Cid: 06f4    Peb: 7ffdf000  ParentCid: 06d0
    DirBase: 14d28000  ObjectTable: e1937640  HandleCount: 350.
    Image: explorer.exe
...
  1. explorer.exe」という項目に「PROCESS 81dec8b0」と書いてあるから、これを使ってexplorer.exeのプロセスを アタッチする。「.process 81dec8b0」コマンドを実行。さらに「.reload /user」コマンドを実行してユーザモードのデバッグを可能にする。
  2. LM」コマンドを実行して、モジュールのリストを表示する。
kd> LM

...
7c800000 7c8c2000   ntdll      (pdb symbols)          C:\symbols\ntdll.pdb\4613B105DA224E789F26051F952BE5A82\ntdll.pdb
7c8d0000 7d0cf000   SHELL32    (deferred)
7d1e0000 7d27c000   ADVAPI32   (deferred)
...
  1. モジュールにSHELL32があるのが分かる。さらにシンボルを検索するために「x SHELL32!SHFile*」を実行する。
kd> x SHELL32!SHFile*

7c9a1cde          SHELL32!SHFileOperationW (_SHFileOperationW@4)
7c9a1fc6          SHELL32!SHFileOperationA (_SHFileOperationA@4)
7c959535          SHELL32!SHFileSysBindToStorage (_SHFileSysBindToStorage@24)
  1. ここでシンボル「SHELL32!SHFileOperationW」にデバッグブレークを設定するために「bp SHELL32!SHFileOperationW」を実行する。
  2. g」コマンドでWin2003のデバッグ実行を再開する。
  3. Win2003を操作して、ファイルをコピーして貼り付けしようとすると、ブレークが発生する。
kd> g
Breakpoint 0 hit
SHELL32!SHFileOperationW:
001b:7c9a1cde 8bff            mov     edi,edi
  1. 「kp」コマンドを実行すると呼び出し履歴が得られる。
kd> kp
 # ChildEBP RetAddr  
00 01aef86c 7ca05f85 SHELL32!SHFileOperationW
01 01aefce0 7ca062a3 SHELL32!CFSDropTarget::_MoveCopy+0x1ff
02 01aeff38 7ca06349 SHELL32!CFSDropTarget::_DoDrop+0x270
03 01aeff54 77da3f12 SHELL32!CFSDropTarget::_DoDropThreadProc+0x46
04 01aeffb8 77e6482f SHLWAPI!WrapperThreadProc+0x94
05 01aeffec 00000000 kernel32!BaseThreadStart+0x34

これはSHFileOperationW関数がCFSDropTarget::_MoveCopy 関数から呼び出されているのが分かる。さらにステップ実行すれば、SHELL32!SHFileOperationWのデバッグが可能になる。

ReactOSのデバッグ方法 (MinGW + KDB の場合)

WinDbgは強力なデバッガですが、ReactOSにはKDB(またはKdbg)という別のカーネルデバッガが組み込まれています。KDBはWinDbgと比べると貧相ですが、WinDbgよりも高速にデバッグができます。

MinGW + KDBでReactOSをデバッグする方法は以下の通りです。

  1. VirtualBoxにMinGWでビルドしたReactOSをインストールした後、電源OFFの状態でVirtualBoxの「設定」でシリアルポートを有効化し、適当な場所のRawファイルに出力するようにする。
  1. ReactOSを起動し、起動メニューで「ReactOS (Debug)」を選ぶ。
  1. するとデバッグモードで起動し、Rawファイルにデバッグ情報が出力される。

ReactOSでは、ソースコードの中でDPRINT1文(もしくはERR文)をC言語のprintfのように使えばデバッグ出力されるようになっている(デバッグしたいプロジェクト内に「WINE_DEFAULT_DEBUG_CHANNEL(...);」のような記載があるときはデバッグ出力に「ERR」を、ないときは「DPRINT1」を使って下さい)。

キーボードのTab+Kを押せば、デバッガに強制的に移行する。 デバッガに入ると、VirtualBoxの画面の動きが止まるが、 気にせず、Rawファイルを監視しながら、VirtualBoxの画面をアクティブにした状態でキーボードでデバッガに入力できる。「cont」コマンドでデバッガから復帰できる。

KDBのコマンドについてはこちらを参照して下さい:

ReactOSのデバッグの練習(KDBの場合)

今回は、「explorer.exe」プロセスの中の「kernel32.dll」にある CreateDirectoryWkernel32!CreateDirectoryW)をデバッグする。CreateDirectoryWはフォルダを作成する関数だ。

  1. CreateDirectoryWのアドレスが欲しいので "dll/win32/kernel32/client/file/dir.c" の CreateDirectoryWの関数の中に次の行を追加してリビルドする。
DPRINT1("CreateDirectoryW address: %p\n", CreateDirectoryW);
  1. ReactOSにGuest Additionsをインストールした後、デバッグモードで起動する。
  2. デスクトップにフォルダを作成すると「CreateDirectoryW address: ...」のような行がデバッグ出力されるはずだ。
(dll/win32/kernel32/client/file/dir.c:102) CreateDirectoryW address: 7C5DA9D0

CreateDirectoryWのアドレスは0x7c5da9d0だとわかる。これを使って後でブレークポイントを設定する。

  1. Tab+K でデバッガに入る。

Entered debugger on embedded INT3 at 0x0008:0x80958ae8.
  1. proc list」でプロセスの一覧を得る。
kdb:> proc list
  PID         State       Filename
  0x00000004  In Memory   System
  0x00000068  In Memory   smss.exe
  0x00000098  In Memory   csrss.exe
  0x000000ac  In Memory   winlogon.exe
  0x000000c4  In Memory   services.exe
...
  0x000001d8  In Memory   explorer.exe
...
  1. 一覧の中から「explorer.exe」を探すと
  0x000001d8  In Memory   explorer.exe

という行が見つかるので、「explorer.exe」プロセスにアタッチするために「proc attach 0x1d8」を実行する。

kdb:> proc attach 0x1d8
Attached to process 0x000001d8, thread 0x000001db.
  1. CreateDirectoryWのアドレスは0x7c5da9d0だった。 これを使ってブレークポイントを設定する。
kdb:> bpx 0x7c5da9d0
Breakpoint 0 inserted.
Breakpoint 0 enabled.
kdb:> set condition INT3 first always
  1. cont」コマンドで実行を再開し、再びフォルダを作ってみる。ブレークポイントで停止する。
kdb:> cont

Entered debugger on breakpoint #0: EXEC 0x001b:0x7c5da9d0
kdb:>
  1. bt」コマンドで呼び出し履歴を取得してみる。
kdb:> bt
Eip:
<kernel32.dll:2a9d0>
Frames:
<shell32.dll:55876>
<shell32.dll:55db3>
<shell32.dll:570a7>
<shell32.dll:48654>
<shell32.dll:4985e>
<shell32.dll:49f70>
<shell32.dll:29af8>
<shell32.dll:70d9b>
<shell32.dll:71e40>
<shell32.dll:71edc>
<shell32.dll:6a456>
<shell32.dll:6a9cf>
...

ここで「kernel32.dll:2a9d0」やら「shell32.dll:55876」など、わけのわからないものが 書かれているが、これらは、RosBEの「raddr2line」というコマンドラインツールを使えば、 ソースコードの行番号として解読できる。

※ うまくいかない場合はビルドされたshell32.dllへの相対パスを指定すること。

解読した結果は次の通り。

<kernel32.dll:2a9d0>: dll/win32/kernel32/client/file/dir.c:92 (CreateDirectoryW)
<shell32.dll:55876>: dll/win32/shell32/shlfileop.cpp:1310 (copy_dir_to_dir)
<shell32.dll:55db3>: dll/win32/shell32/shlfileop.cpp:1502 (copy_files)
<shell32.dll:570a7>: dll/win32/shell32/shlfileop.cpp:1966 (SHFileOperationW)
<shell32.dll:48654>: dll/win32/shell32/droptargets/CFSDropTarget.cpp:90 (CFSDropTarget::_CopyItems)
<shell32.dll:4985e>: dll/win32/shell32/droptargets/CFSDropTarget.cpp:647 (CFSDropTarget::_DoDrop)
<shell32.dll:49f70>: dll/win32/shell32/droptargets/CFSDropTarget.cpp:442 (CFSDropTarget::Drop)
<shell32.dll:29af8>: dll/win32/shell32/CShellLink.cpp:3167 (CShellLink::Drop)
<shell32.dll:70d9b>: dll/win32/shell32/CSendToMenu.cpp:91 (CSendToMenu::DoDrop)
<shell32.dll:71e40>: dll/win32/shell32/CSendToMenu.cpp:439 (CSendToMenu::DoSendToItem)
<shell32.dll:71edc>: dll/win32/shell32/CSendToMenu.cpp:499 (CSendToMenu::InvokeCommand)
<shell32.dll:6a456>: dll/win32/shell32/CDefaultContextMenu.cpp:1020 (CDefaultContextMenu::InvokeShellExt)
<shell32.dll:6a9cf>: dll/win32/shell32/CDefaultContextMenu.cpp:1195 (CDefaultContextMenu::InvokeCommand)
<shell32.dll:5e0ee>: dll/win32/shell32/CDefView.cpp:1391 (CDefView::InvokeContextMenuCommand)
<shell32.dll:5e61b>: dll/win32/shell32/CDefView.cpp:1539 (CDefView::OnContextMenu)
<shell32.dll:d1e84>: dll/win32/shell32/CDefView.cpp:321 (CDefView::ProcessWindowMessage)
<shell32.dll:d1a3e>: sdk/lib/atl/atlwin.h:1565 (CDefView::WindowProc)

ReactOSのデバッグ方法 (Visual Studio + WinDbgの場合)

  1. VirtualBoxで新しい仮想マシン (Other Windows (32-bit)) を作成し、そこにVSでビルドしたbootcd.isoを使ってReactOSをインストールする。
  2. 仮想マシンの状態を保存するために、VirtualBoxを操作して仮想マシンのスナップショットを作成する。
  3. 仮想マシンをいったん終了し、仮想マシンのシリアルポートの設定をする。シリアルポートCOM1にパイプ(\\.\pipe\com1)を設定する。「シリアルポート」の「シリアルポートを有効化」にチェックを入れ、「ポートモード」を「ホストにパイプ」に変更して、「パス/アドレス」に「\\.\pipe\com1」を指定する。チェックボックス「存在するパイプ/ソケットに接続」のチェックをはずす。
  4. WinDbgを起動し、「Settings」の「Debugging settings」で「Default symbol path」にシンボルの場所(msvc_pdbフォルダの場所)を設定。「ファイル」メニューから「Attach to Kernel」を選択し、「Pipe」「Reconnect」にチェックを入れ、「Port」に「\\.\pipe\com1」を設定し、「OK」ボタンを押す。
  5. 仮想マシンを起動する。うまくいけばReactOSをWinDbgでデバッグできる。

日本語WinXPのデバッグ方法(WinDbgを使用)

上記のWin2003は、英語版でしたので、日本語に関する開発をするときには役に立たないことがあります。Microsoftから正式に配布されたXPモードに含まれている日本語WinXPを使えば、日本語の開発が可能です。

  1. 日本語XPモードの配布ファイル「WindowsXPMode_ja-jp.exe」をどこかから拾ってくる(Wayback Machineに配布元URLを入力して下さい)。2022年現在、配布元( https://www.microsoft.com/ja-jp/download/details.aspx?id=8002 )からは直接はダウンロードできないようです。
  2. WindowsXPMode_ja-jp.exe」を7-Zipで展開する。ファイル「xpminstl32.msi」ができる。
  3. さらに「msiexec.exe /a xpminstl32.msi targetdir="%~dp0xpmode"」という内容のバッチファイル(拡張子.bat)を適当な名前で作成、xpminstl32.msiと同じ場所に置き、ダブルクリックして実行する。
  4. しばらく待つとファイル "Windows XP Mode base.vhd"が展開される。このファイルのプロパティの「読み込み専用」を解除。
  5. 期限切れのため、システム時計を過去(2008-01-01)に戻して仮想マシンのWinXPにログオンする。
  6. WinXPの電源を切る前に管理者権限のコマンドプロンプトで「bootcfg /debug ON /PORT COM1 /ID 1」を実行する。また、VirtualBox Guest Additionsも忘れずインストールする。 ※ただし、「許可されていないプログラムから……保護する」はチェックを外すこと。
  7. 仮想マシンの状態を保存するために、VirtualBoxを操作して仮想マシンのスナップショットを作成する。
  8. 仮想マシンをいったん終了し、仮想マシンのシリアルポートの設定をする。シリアルポートCOM1にパイプ(\\.\pipe\com1)を設定する。「シリアルポート」の「シリアルポートを有効化」にチェックを入れ、「ポートモード」を「ホストにパイプ」に変更して、「パス/アドレス」に「\\.\pipe\com1」を指定する。チェックボックス「存在するパイプ/ソケットに接続」のチェックをはずす。
  9. WinDbgを起動し、「Settings」の「Debugging settings」で「Default symbol path」に「srv*」を設定。「ファイル」メニューから「Attach to Kernel」を選択し、「Pipe」「Reconnect」にチェックを入れ、「Port」に「\\.\pipe\com1」を設定し、「OK」ボタンを押す。
  10. 仮想マシンを起動する。うまくいけばWinXPをWinDbgでデバッグできる。

※ COM1に空きがないとか、COM1とは別のポートを使いたい人は、COM2などを代わりに使ったりできるようです。
※ Default symbol pathは、複数のパスが指定できます。「srv*」はインターネットから読み込まれるパスのようです。 シンボルファイルはフォルダとタイムスタンプなどで厳密に管理されているので、バイナリと合わない間違ったシンボルファイルが読み込まれる恐れはないようです。

実際に開発に参加する

  • ReactOS JIRAで不具合の報告を見ることができます。不具合や修正パッチを報告するには、ReactOSアカウントが必要です。アカウントがない場合はこちらから登録下さい。
  • GitHubのreactos/reactosにプルリクエストすることでReactOSの修正を提案することができます。ただし、Git/GitHubのアカウント設定で本名とメールアドレスを公開する必要があります。
  • チャットルームでは気軽に質問をすることができます。ReactOSアカウントが必要です。
  • 日本語ReactOSの公式Twitterアカウントもありますのでご利用下さい。

ローカルのReactOSを最新に保つ

ときどき、ローカルのReactOSを最新に更新したいことがあるかもしれません。そのときは次のようにコマンドを実行します。

# upstreamという名前で公式ReactOSのリモートリポジトリのURLを登録する。
git remote set-url upstream https://github.com/reactos/reactos.git

# ローカルの変更を元に戻す。
git checkout .

# masterブランチに移動。
git checkout master

# upstreamの変更点を取り込む。
git fetch upstream

# upstreamの変更点を適用する。
git rebase upstream/master

開発のこつ

  • 複数ファイルから特定のテキストを探す場合は、grepというツールを使うと便利です。
  • こちらのページから 高速grepできます。
  • ASSERT(0)DebugBreak()などを使えば特定の場所でデバッガを停止できます。

連絡先

この記事に書いてあることがうまくいかなかったときは、必ずご報告下さい。電子メールで katayama.hirofumi.mz@gmail.com まで。

コメント

タイトルとURLをコピーしました
inserted by FC2 system