アセンブラーでのグラフィックプリミティブの作成

使用の面で興味深く有用なものを検討したいので、選択はアセンブラー、つまりプリミティブグラフィックスの作成に委ねられました。



アセンブラは、低レベルのプログラミング言語、またはアセンブリ言語で記述されたプログラムのソースコードを機械語のプログラムに変換するプログラムです。 言語は、いくつかの標準では複雑ですが、グラフィックプリミティブの作成はここから始まります。 Windows用のアセンブラー、つまりMASMを検討します。MASMは 、Visual Studioとともに、最近グラフィックプリミティブを作成するために使用されました。 イラストと詳細を含むこれについて。 さらに。



はじめに


Windows用のアプリケーションを作成するために必要なマロマルスキーの単純な構造を考えてみましょう。

1)Windowsに関連するすべての定数、構造、および関数を.asmファイルの先頭に置きます-時間とエネルギーを節約します。

2)includelibディレクトリを使用してインポートライブラリを示します。これにより、プログラムがこれらのインポートライブラリの関数を使用することをコンパイラに示します。

3)Windowsのインクルードファイルと同じ名前を使用して、インクルードファイルでAPI関数、構造、および/または定数のプロトタイプを宣言します。少なくとも試してみてください。

4)makefileを使用して、コンパイルプロセスを自動化します。



私はいくつかの場所で何とかして戻ってきますが、全体としてはかなり興味深いプリミティブを描画する優れたプログラムを取得する必要があります。 アセンブラーのプログラム構造の例を見てみましょう(リスト1を参照)



リスト1.プログラム構造の例


.type_process ;

.model ;



include lib ; inc

includelib lib ; lib



.DATA ; p

;



.DATA? ; p

; pp



.CODE ;









グラフィックプリミティブの定義




デバイスコンテキストとWM_PAINT


Windowsでは、ウィンドウ自体が再描画を担当します。 ウィンドウを再描画するには、WM_PAINTメッセージを受信する必要があります。



通常、次の3つの方法のいずれかが使用されます。



a)ワークスペースは、計算を使用してその内容が形成される場合に復元できます。

b)作業領域を形成する一連のイベントを保存し、必要な回数だけ「再生」できます。

c)仮想ウィンドウを作成し、すべての出力を仮想ウィンドウに送ることができます。メインウィンドウがWM_PAINTメッセージを受信したら、仮想ウィンドウの内容をメインウィンドウにコピーします(後で記述されるアプリケーションのデモに使用されます)。



現在位置の設定


現在位置を設定するには、MoveToEx()関数を使用します。この関数の説明は次のとおりです。



WINGDIAPI BOOL WINAPI MoveToEx(HDC、int、int、LPPOINT);



最初の引数はデバイスコンテキスト、2番目と3番目は現在のグラフィックス位置が設定されるポイントの座標です。 最後の引数は、POINT型の構造体へのポインターで、関数は古い現在位置の座標を書き込みます。



線画


線を描くには、LineTo()関数を使用します。この関数の説明は次のとおりです。



WINGDIAPI BOOL WINAPI LineTo(HDC、int、int);



最初の引数はデバイスコンテキスト、2番目と3番目の引数はポイントの座標です。



長方形を描く


長方形を描くには、Rectangle()関数を使用します。この関数は次のように記述されます。



WINGDIAPI BOOL WINAPI Rectangle(HDC、int、int、int、int);



最初の引数はデバイスコンテキストですが、残りの引数は四角形の左上隅と右下隅の座標です。



楕円を描く


楕円を描画するには、Ellipse()関数を呼び出す必要があります。この関数の説明は次のとおりです。



WINGDIAPI BOOL WINAPI Ellipse(HDC、int、int、int、int);



最初の引数はデバイスコンテキストです。

注:楕円は長方形によって制限されており、描画された楕円が決定されるのはこの長方形の座標を介してです。 2番目と3番目の引数は長方形の左上隅の座標であり、4番目と5番目の引数は右下隅の座標です。



角丸長方形の描画


角丸長方形を描画するには、RoundRect()関数を使用します。この関数の説明は次のとおりです。



WINGDIAPI BOOL WINAPI RoundRect(HDC、int、int、int、int、int、int);



最初の5つの引数は、Rectangle()関数の引数と完全に同一です。 最後の2つの引数には、円弧を定義する楕円の幅と高さが含まれています。



.asmコードの記述と解析




プリミティブを作成するには、グラフィックの作成とレンダリングに必要な手順を検討してください。

1)プログラムへのハンドルを取得します。

2)ウィンドウクラスの登録。

3)ウィンドウの作成。

4)画面上のウィンドウ表示。

5)ウィンドウ内の画面の内容を更新します。

6)プログラムを終了します。



作成を始めましょうが、最初にVisual Studioで新しいプロジェクトを作成します。ファイル->新しいプロジェクト



画像



空のプロジェクトを選択:空のプロジェクト



画像



新しいファイルを作成します。[ソース]-> [追加]-> [新しいアイテム]を右クリックします。



画像



新しいファイル(.asm)を作成します。

最初の方法は、新しいファイルを作成するときにfile.asmを追加することです(この方法で作成しました)

2番目の方法-ファイル拡張子を作成後に変更する(file.txt-> rename-> file.asm)



画像



Visual Studioでmasmを使用します。プロジェクトを右クリック->カスタマイズのビルド



画像



これと同じmasmを設定します:masmの前に目盛りを付けます



画像



この非常に原始的なものとリスト自体を書き始めます。以下を参照してください。



リスト2.アセンブリコードの記述


.386

.model stdcall, flat

option casemap:none



includelib kernel32.lib

include kernel32.inc

includelib user32.lib

include user32.inc

include windows.inc

include gdi32.inc



.data



hwnd dd 0

hInst dd 0

szTitleName db '. №6', 0

szClassName db ' Win32', 0

msg MONMSGSTRUCT <?>

wc WNDCLASS <?>

ps PAINTSTRUCT <?>



.code



Main PROC

invoke GetModuleHandle, 0 ; . ,

mov hInst, eax ; .

mov wc.style, CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS

mov wc.lpfnWndProc, offset WndProc ;

mov wc.cbClsExtra, 0

mov wc.cbWndExtra, 0

mov eax, hInst ;

mov wc.hInstance, eax ; hInstance

invoke LoadIcon, 0, IDI_APPLICATION

mov wc.hIcon, eax ; hIcon

invoke LoadCursorA, 0, IDC_ARROW

mov wc.hCursor, eax ; hCursor

mov wc.hbrBackground, WHITE_BRUSH ;

mov dword ptr wc.lpszMenuName, 0 ;

mov dword ptr wc.lpszClassName, offset szClassName ;

invoke RegisterClassA, offset wc ;

invoke CreateWindowEx, 0, offset szClassName, offset szTitleName, \

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, \

CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInst, 0

mov hwnd, eax ;

invoke ShowWindow, hwnd, SW_SHOWNORMAL ;

invoke UpdateWindow, hwnd ;

cycle1: ;

invoke GetMessage, offset msg, 0, 0, 0

cmp ax, 0

je end_c

invoke TranslateMessage, offset msg ;

invoke DispatchMessage, offset msg ;

;

jmp cycle1

end_c:

invoke ExitProcess, 0 ;

Main ENDP



WndProc PROC USES ebx edi esi, _hwnd:DWORD, _wmsg:DWORD, _wparam:DWORD, _lparam:DWORD

local _hdc:DWORD

cmp _wmsg, WM_DESTROY

je wmdestroy

cmp _wmsg, WM_PAINT

je wmpaint

invoke DefWindowProcA, _hwnd, _wmsg, _wparam, _lparam ;.

jmp exit_proc

wmpaint:

invoke BeginPaint, _hwnd, offset ps ;

mov _hdc, eax

invoke Rectangle, _hdc, 170, 120, 310, 260 ;

invoke Rectangle, _hdc, 120, 120, 170, 140 ;

invoke Rectangle, _hdc, 310, 120, 360, 140 ;

invoke Rectangle, _hdc, 170, 260, 190, 310 ;

invoke Rectangle, _hdc, 290, 260, 310, 310 ;

invoke Rectangle, _hdc, 210, 80, 270, 120 ;

invoke Rectangle, _hdc, 220, 85, 225, 90 ;

invoke Rectangle, _hdc, 250, 85, 255, 90 ;

invoke Rectangle, _hdc, 225, 105, 255, 120 ;

invoke EndPaint, _hdc, offset ps ;

mov eax, 0 ; - 0

jmp exit_proc

wmdestroy:

invoke PostQuitMessage, 0 ; WM_QUIT

mov eax, 0 ; - 0

exit_proc:

ret

WndProc ENDP

END Main









結果




画像



アクションとコードの作成の過程でコメントを書きましたが、完全な本質を理解するために、私がやったことや書いたことすべてをより詳細に検討します。



デブリーフィング


.386の行は、プロセッサ80386の命令セットが使用されていることをMASMに伝え、.model stdcall、flat行は、フラットメモリモデルが使用されることをMASMに伝えます。 また、パラメータ転送自体は、デフォルトとしてSTDCALLタイプで使用されました。

プログラムにプリミティブを実装するために必要なシステム構造と定数が含まれているため、コードの最初にwindows.incを接続しました。 プログラムは、user32.dll(CreateWindowExなど)およびkernel32.dll(ExitPocessなど)にあるWindows API関数を呼び出すため、これらも登録する必要があります。

PROCの主な機能のプロトタイプについて説明します。

次に.dataが続きます。ここで、szClassNameはウィンドウクラスの名前で、szTitleNameはウィンドウの名前です。

.codeには、コードが<label name>とend <label name>の間にあるすべての命令が含まれています。

最初の命令は、プログラムへのハンドルを取得するためのGetModuleHandleの呼び出しです。 これは、プログラムによって呼び出されるAPI関数に渡されるパラメーターとして使用されます。



次に、ウィンドウクラスの初期化が行われます。これは、アイコン、カーソル、ウィンドウを担当する関数など、いくつかの重要なウィンドウ特性を定義します。 ここでは、アプリケーション自体のハンドル、アイコンのハンドル、カーソルのハンドルについて説明します。 実装されたアプリケーションにはメニュー記述子はありません。これはプログラムコードを増加させますが、特にプリミティブであり、まったく必要ないため、機能を追加しません。 ウィンドウの作成に使用できる、または使用されたパラメーター:



1)cbSize:一般的なWDNCLASSEX構造体のサイズをバイト単位で設定します。

2)スタイル:ウィンドウのスタイルを設定します。

3)cbClsExtra:プログラム自体のために予約する必要がある追加のバイト数を設定します。

4)hInstance:モジュール記述子を設定します。

5)hIcon:アイコンのハンドルを設定し、LoadIcon関数を呼び出してその受信を渡します。

6)hCursor:カーソルにハンドルを設定し、LoadCursor関数を呼び出すことでその受信を渡します。

7)hbrBackground:背景色を設定します。

8)lpszMenuName:ウィンドウのメニューハンドルが設定されます。

9)lpszClassName:ウィンドウクラス名を設定します。



RegisterClassEx関数を使用してウィンドウクラスを登録した後、CreateWindowExを呼び出して、このクラスに基づいてウィンドウを作成します。



主で重要な手順は、WndProc PROC USES ebx edi esi、_hwnd:DWORD、_wmsg:DWORD、_wparam:DWORD、_lparam:DWORDです。WndProcを呼び出す必要はありませんでした。最初のパラメーター_hwndは送信されるウィンドウハンドルです。 _wmsg-送信されたメッセージ。 _wmsgはmsg構造ではなく、単なる数字であると言う価値があります。 _wparamおよび_lparamは、一部のメッセージで使用される追加のパラメーターです。



最後に、最後の部分に来て、尋ねられた数字、それらの座標、および戻り値を説明します。 これが重要な部分です。プログラムロジックがここにあるからです。 ここでは、コンテキストのリリースについて説明し、値を返し、さらに完了のメッセージを送信します。 処理される残りのメッセージはwmdestroyのみです。このメッセージは、ウィンドウが閉じるときにウィンドウに送信されます。 その時点で、ウィンドウプロシージャがそれを受信すると、ウィンドウは既に画面から消えています。 wmdestroyが実行された後、PostQuitMessageが呼び出され、終了メッセージが送信されます。これにより、GetMessageは強制的にゼロ値をeaxに返します。これはプログラムの終了です。



All Articles