Tutorial 5: More about Text

このチュートリアルでは、前章に引き続きテキストの描画について、さらに詳しく見ていく。
   ソース      実行結果  

Theory:

WindowsにおけるカラーシステムはRGB値で決まる。Rは赤、Gは緑、Bは青を表すパラメータだ。 これらの3つの数値を任意に組み合わせて自分の出力したい色を決定するのである。 RGB値は、それぞれの値が 0 から 255 までの範囲(1バイト)となっており、 赤なら、255,0,0、白なら255,255,255となる。 このような例からでも、 あなたが表示したい色をどのように数字を組み合わせればいいのかを知るには、 非常に難しいことがわかるはずだ。

文字列の色や背景の色は SetTextColor関数、SetBkColor関数を使用する。 これらの関数は、デバコンへのハンドルと32ビットのRGB値を引数に取る。 32ビットRGB値の構造体は以下のように定義されている

RGB_value struct
   unused  db 0
   blue    db ?
   green   db ?
   red     db ?
RGB_value ends

この構造体で注意しなければならないのは、1バイト目が0でなければならないところだ。 残り3バイトは青、緑、赤となっている。 しかし、この構造体は実は使用しない。 というのも、初期化もそうだし使用するのもわずらわしいのである。 代わりにマクロを使用する。 このマクロは3つの引数をとり、赤、緑、青の値となっている。 その3つの値を32ビットRGB値としてeaxレジスタにストアする。 そのマクロというのは、次のようになっている。

RGB macro red,green,blue
   xor eax, eax
   mov ah , blue
   shl eax, 8
   mov ah , green
   mov al , red
endm

将来、このマクロはよく使うことになるので、インクルードファイルにしておくとよい。

今度は、フォントの話になるのだが、実は、CreateFont関数やCreateFontIndirect関数を使用して、 フォントを作成することができる。 この2つの関数はどちらも同じ戻り値なのだが、引数が異なっている。 CreateFontIndirect関数は、論理フォント構造体へのポインタを引数にとることになっており、 とりわけ頻繁にフォントを変更するという場合には、2つの点で、CreateFont関数より柔軟性がある。 しかしながら、この例では単なるデモのため、1つのフォントしか作成しないので、 CreateFont関数を使用している。 CreateFont関数をCALLした後、指定したデバコンにおける論理フォントへのハンドルが返ってくる。 その後、全てのテキスト関係のAPI関数でそのフォントを使用することになる。

Content:

.386
.model flat,stdcall
option casemap:none

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

RGB macro red,green,blue
       xor eax,eax
       mov ah,blue
       shl eax,8
       mov ah,green
       mov al,red
endm

.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
TestString db "Win32 assembly is great and easy!",0
FontName db "script",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.code
 start:
   invoke GetModuleHandle, NULL
   mov   hInstance,eax
   invoke GetCommandLine
    mov CommandLine,eax
   invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
   invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
   LOCAL wc:WNDCLASSEX
   LOCAL msg:MSG
   LOCAL hwnd:HWND
   mov  wc.cbSize,SIZEOF WNDCLASSEX
   mov  wc.style, CS_HREDRAW or CS_VREDRAW
   mov  wc.lpfnWndProc, OFFSET WndProc
   mov  wc.cbClsExtra,NULL
   mov  wc.cbWndExtra,NULL
   push hInst
   pop  wc.hInstance
   mov  wc.hbrBackground,COLOR_WINDOW+1
   mov  wc.lpszMenuName,NULL
   mov  wc.lpszClassName,OFFSET ClassName
   invoke LoadIcon,NULL,IDI_APPLICATION
   mov  wc.hIcon,eax
   mov  wc.hIconSm,eax
   invoke LoadCursor,NULL,IDC_ARROW
   mov  wc.hCursor,eax
   invoke RegisterClassEx, addr wc
   invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
          WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
          CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
          hInst,NULL
   mov  hwnd,eax
   invoke ShowWindow, hwnd,SW_SHOWNORMAL
   invoke UpdateWindow, hwnd
   .WHILE TRUE
               invoke GetMessage, ADDR msg,NULL,0,0
               .BREAK .IF (!eax)
               invoke TranslateMessage, ADDR msg
               invoke DispatchMessage, ADDR msg
   .ENDW
   mov    eax,msg.wParam
   ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   LOCAL hdc:HDC
   LOCAL ps:PAINTSTRUCT
   LOCAL hfont:HFONT

   .IF uMsg==WM_DESTROY
       invoke PostQuitMessage,NULL
   .ELSEIF uMsg==WM_PAINT
       invoke BeginPaint,hWnd, ADDR ps
       mov   hdc,eax
       invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
                                      OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
                                      DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
                                      ADDR FontName
       invoke SelectObject, hdc, eax
       mov   hfont,eax
       RGB   200,200,50
       invoke SetTextColor,hdc,eax
       RGB   0,0,255
       invoke SetBkColor,hdc,eax
       invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
       invoke SelectObject,hdc, hfont
       invoke EndPaint,hWnd, ADDR ps
   .ELSE
       invoke DefWindowProc,hWnd,uMsg,wParam,lParam
       ret
   .ENDIF
   xor   eax,eax
   ret
WndProc endp

end start

Analysis:

invoke CreateFont,                    \
       24,                            \
       16,                            \
       0,                             \
       0,                             \
       400,                           \
       0,                             \
       0,                             \
       0,                             \
       OEM_CHARSET,                   \
       OUT_DEFAULT_PRECIS,            \
       CLIP_DEFAULT_PRECIS,           \
       DEFAULT_QUALITY,               \
       DEFAULT_PITCH or FF_SCRIPT,    \
       ADDR FontName

CreateFont関数は与えられた引数と利用できるフォントデータに最も近い論理フォントを作成する。 この関数はWindowsAPI関数で最も多くの引数を取る関数で、 この関数の戻り値である論理フォントのハンドルを引数にして、 SelectObject関数を使用できるようになる。 では、引数を詳しくみていこう。

CreateFont proto nHeight          :DWORD,\
                 nWidth           :DWORD,\
                 nEscapement      :DWORD,\
                 nOrientation     :DWORD,\
                 nWeight          :DWORD,\
                 cItalic          :DWORD,\
                 cUnderline       :DWORD,\
                 cStrikeOut       :DWORD,\
                 cCharSet         :DWORD,\
                 cOutputPrecision :DWORD,\
                 cClipPrecision   :DWORD,\
                 cQuality         :DWORD,\
                 cPitchAndFamily  :DWORD,\
                 lpFacename       :DWORD

以上のような説明では理解できないかもしれないが、もっと詳しく知りたければ、Win32 API 関数を参照しよう

invoke SelectObject, hdc, eax
mov    hfont,eax

論理フォントのハンドルを取得した後は、 SelectObject関数を呼んで、指定したデバコンのフォントをその論理フォントに変更する。 SelectObject関数は、GDI関数で使用するペンや、ブラシ、フォントといった新しいGDIオブジェクトを作成し、 以前の使用していたそれらのハンドルを返すことになっている。 ちなみに、自分の設定したオブジェクトを使い終えた後は、以前のオブジェクトにセットしなおすので、 変更前のオブジェクトは保存しておかなければならない。 SelectObject関数をCALLした後は、文字列出力関数で描画した文字は自分の作成したフォントになっている。

RGB    200,200,50
invoke SetTextColor,hdc,eax
RGB    0,0,255
invoke SetBkColor,hdc,eax

SetColorText関数、SetBkColor関数で使用する32ビットRGB値をRGBマクロで作成している。

invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString

今度は、クライアントエリアにテキストを描画するためにTextOut関数をCALLする。 フォントやカラーは以前設定した値となっている。

invoke SelectObject,hdc, hfont

フォントを使用した後は、 デバコンに以前のフォントをセットしなおさないといけない。 これを忘れるとひどい目に遭うので、忘れないこと。


[戻る]