ここで紹介するプログラムは,Windowsアプリケーションから物理メモリを直接操作するプログラムの第2段です.このプログラムを使うと,自分の好きな物理アドレスを直接操作できるようになります. 前節で紹介したものと異なり,どのアドレスでも操作できます.前節のものはWindowsが用意したアドレスしか操作できませんでした.
サンプルプログラムは小さいですが,内容の理解にはi386以上のCPU(Pentium等)のメモリ管理機能の理解が必要です.もっとも,それがわからなくても,物理メモリを直接操作する方法は理解できます.
プログラムは,WinMainとWinMainから呼び出されるサブルーチンしかありません(図1-3).WinProcなどはありません,とてもシンプルです. <図1-3> プログラムの構造
● ヘッダーファイル #include <dos.h> windows.hをインクルードするのは当たり前ですが,本プログラムではセグメントレジスタ(注1-3)を参照するので,dos.hもインクルードしておく必要があります.
プログラムは,WinMain()とCreateSelector()の二つのルーチンからなっています.まずCreateSelector()から説明しましょう. ● 変数:CreateSelector() DWORD linerAddress ; HANDLE selector = 0 ; struct SREGS sregs ;
これは,単純な宣言文です.特に変わったところはありません,sregsはdsを参照するので宣言しました. ● セグメントレジスタを取得:CreateSelector() segread( &sregs ) ;
セグメントレジスタの現在の値を取得し,sregsが指し示す構造体に入れます.後でDSを使用するので現在の値を読み出しています. ● セレクタの割り当て:CreateSelector() if( (selector = AllocSelector( sregs.ds )) ) AllocSelector関数は,新しいセレクタを割り当てます(注1-4).
関数が正常に終了した場合は,既存のセレクタのコピー,または初期化されていない新しいセレクタを返します.それ以外の場合は,0が返されます. ● リニアアドレスの算出:CreateSelector() linerAddress = ((DWORD)segment << 4L ) + offset ;
パラメータで渡されたsegmentとoffsetから,32ビット(DWORD)のリニアなアドレスを計算します.計算方法は,8086のセグメントアドレス:オフセットアドレスの方法と同じです. ● セレクタのベースを設定:CreateSelector() SetSelectorBase( selector, linerAddress ) ; SetSelectorBase関数は,セレクタのベースを設定します.selectorは,設定するセレクタを指定します.linerAddressは新しいベース値を指定します.この値は,セレクタが示す先頭のアドレスです(注1-6). ● セレクタのリミットを設定:CreateSelector() SetSelectorLimit( selector, length ) ; SetSelectorLimit関数は,セレクタのリミットを設定します.selectorは設定するセレクタを指定します.lengthは設定するセレクタの新しいリミット値を指定します(注1-7).
これで,CreateSelector()の説明は終わりです.次はWinMain()を説明します. ● 変数:WinMain() HANDLE selector = 0 ; LPSTR lpScreen ; unsigned int loop ;
単純な宣言文です.特に変わったところはありません. ● Main()CreateSelector()の呼び出し:Win selector = CreateSelector( 0xA000, 0x0000, (DWORD)0x0000FFFF ) ;
アクセスしたいアドレスと長さを指定して,前述したCreateSelectorを呼び出します.パラメータは先頭アドレス(セグメント形式),オフセット,長さです. ● ポインタを生成:WinMain() lpScreen = (LPSTR)MAKELONG( 0, selector );
作成したセレクタからポインタを作り出します. ● ビデオRAMへの書き込み:WinMain() for( loop = 0 ; loop < 0xFFFF ; loop++ ) lpScreen[loop] ^= 0xFF ;
上のコードはDOSでも見慣れたコードでしょう.A000:0000(セグメント:オフセット)から64Kバイトを0xFFでXORしています.直接VRAMと0xFFでXORを取っています. ● セレクタの解放:WinMain() FreeSelector( selector ) ; FreeSelector関数は,AllocSelector関数を使用して割り当てたセレクタを解放します.アプリケーションがこの関数を呼び出した後は,セレクタは無効になり使用不能になります(注1-8). 以上で細かい説明は終わりです.大体動作が理解できたことと思います. 注:1-3 正確には「セレクタ」です. 注:1-4 この関数は「Windowsのプログラミング規定に反するため,どうしてもしても必要なとき以外はアプリケーションでこの関数を使わないでください」と記載されています.普段は使わない方がいいAPIのようです.事実、Win32(Windows95/98/WindowsNT/Windows2000)では廃止されました。 注:1-5 セレクタに関しては,i386のマニュアルを参照してください.セレクタがわからなくても,メモリ参照のためインデックス,とでも考えれば間違いはありません. 注:1-6 細かい点については,i386のセレクタ(LDTなど)を参照してください. 注:1-7 80286,この値は0x10000未満でなければなりません. 注:1-8 この関数は「Windowsのプログラミング規定に反するため,どうしてもしても必要なとき以外はアプリケーションでこの関数を使わないでください」とう記述があります.AllocSelectorと同様に,Win32(Windows95/98/WindowsNT/Windows2000)では廃止されました。
Copyright 2000 北山 洋幸 |
|
Copyright 1997-2001 CQ Publishing Co.,Ltd.