2007. 2. 15. 20:30
DevX Win32 Assembly Tutorial 5: More about Text

Tutorial 5: More about Text

이 번장에서는, 4장에 이어서 텍스트출력에 대한 세부적인 내용을 설명한다.
   소스       실행 결과   

Theory:

Windows에서 컬러표현은 RGB값으로 정해진다. R는 빨강, G는 초록, B는 파랑을 나타내는 파라미터다. 이러한 3개의 값을 임의로 조합해서 출력하고 싶은 색을 생성하는 것이다. RGB값은, 값이 0 에서 255 까지의 범위(1바이트)가 되고, 붉은색은 255,0,0가 되며, 흰색은 255,255,255가 된다. 이것으로 알수 있듯이 원하는 색상을 표현할려면 상당히 번거롭다는 것을 알 수가 있다.

문자열의 색이나 배경색은 SetTextColor 함수, SetBkColor 함수를 사용한다. 이 함수들은,DC핸들과 32 비트의 RGB값을 인수로 갖는다. 32 비트 RGB값의 구조체는 다음과 같이 정의되어 있다

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

이 구조체에서 주의해햐 할 것은, 처음 1바이트가 반드시 0(Zero)이 여야 한다는것이다. 나머지 3바이트는 파랑, 초록, 빨강이다. 그러나, 이 구조체는 실제로 많이 사용하지는 않는다.초기화 하기도 번거롭고 사용하는것 또한 번거롭기 때문이다. 대신에 색상을 사용할 경우에는 RGB매크로를 사용한다. 이 매크로는 3개의 인수를 가지며, RGB값을 가지게 된다. RGB값은 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 함수는, 논리 폰트 구조체의 포인터를 인수로 갖고 있어서 폰트를 자주 변경하는 경우에 주로 사용한다. 그러나, 예제에서는 단순한 예제이기 때문에, CreateFont 함수를 사용하고 있다. CreateFont 함수를 호출 한 후, 지정한 DC에 논리 폰트의 핸들이 반환된다. 그 후, 모든 문자처리에 대한 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

  • nHeight
    문자의 높이를 지정한다. 디폴크기는 0 이다.
  • nWidth
    문자의 폭을 지정한다. 보통 0 을 지정하면 Windows가 nHeight 를 기준으로 해서 자동으로 맞춰준다.본 예제에서는 16 으로 지정했다.
  • nEscapement
    문자의 기울기를 지정한다.(이탤릭을 의미하지 않는다)이는 수평각도를 기준으로 해서, X축방향으로 몇번 회전하는지를 설정한다. 단위는 10/1도로 되어 있고 보통 0을 설정해서 사용한다.
  • nOrientation
    문자의 기준선과 X축의 각을 10/1단위로 지정한다.
  • nWeight
    문자의 선굵기를 지정한다. Windows는 다음과 같은 사이즈를 미리 정의하고 있다.
      FW_DONTCARE   equ 0
      FW_THIN       equ 100
      FW_EXTRALIGHT equ 200
      FW_ULTRALIGHT equ 200
      FW_LIGHT      equ 300
      FW_NORMAL     equ 400
      FW_REGULAR    equ 400
      FW_MEDIUM     equ 500
      FW_SEMIBOLD   equ 600
      FW_DEMIBOLD   equ 600
      FW_BOLD       equ 700
      FW_EXTRABOLD  equ 800
      FW_ULTRABOLD  equ 800
      FW_HEAVY      equ 900
      FW_BLACK      equ 900
  • cItalic
    0 이외의 값일 경우, 이탤릭체가 된다. 0 이면 보통문자.
  • cUnderline
    0 이외의 값일경우, 밑줄을 표시한다. 0 이면 보통문자.
  • cStrikeOut
    0 이외의 값일 경우,문자 한가운데에 선이 출력 된다. 0 이면 보통문자.
  • cCharSet
    문자의 문자셋을 지정한다. 보통, OEM_CHARSET을 지정해서, OS에 의존한 폰트를 선택한다.
  • cOutputPrecision
    출력해상도 지정한다. 보통은 OUT_DEFAULT_PRECIS를 지정해서, 기본값을 사용한다.
  • cClipPrecision
    클리핑 정밀도를 지정한다. 클리핑 정밀도란, 지정한 클리핑영역부터 문자의 일부가 잘려나갔을경우, 그문자를 어떻게 처리하는지를 나타낸다. CLIP_DEFAULT_PRECIS으로, 디폴트설정을 지정할 수 있다.
  • cQuality
    출력 품질을 지정한다. 출력 품질이란, GDI가 논리 폰트의 속성과 실제의 물리 폰트의 속성을 어느 정도 매칭 시킬지를 정의하는 것이다. DEFAULT_QUALITY 와 PROOF_QUALITY , DRAFT_QUALITY 라는 3개의 설정값이 존재한다.
  • cPitchAndFamily
    피치와 패밀리를 지정한다. or 연산자를 사용해서, 피치와 패밀리의 값을 결합해서 사용한다.
  • lpFacename
    폰트의 이름을 나타내는 문자열의 포인터

이렇게 설명해도 이해하기 힘들것 이다. 자세한 내용은 Win32 API 도움말을 참고하기 바란다.

invoke SelectObject, hdc, eax
mov    hfont, eax

논리 폰트의 핸들을 얻었다면, SelectObject 함수를 호출해서, DC의 폰트를 새로운 논리폰트로 변경한다. SelectObject 함수는, GDI 함수로서 펜이나, 브러쉬, 폰트와같은 새로운 GDI 오브젝트를 변경해 주고, 이전의 핸들을 돌려주게 되어 있다. 추가로, GDI 오브젝트의 사용이 끝난 후에는, 변경전의 오브젝트를 저장해 두어야만 한다. SelectObject 함수를 호출 한 후에는, 문자열 출력 함수로 출력되는 모든 문자열은 변경된 논리폰트로 적용된다.

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

SetColorText 함수, SetBkColor 함수를 이용해서 문자와 문자의 배경색을 RGB매크로를 사용해서 설정한다.

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

이번에는, 작업영역에 문자를 출력하기 위해 TextOut 함수를 호출 한다. 폰트나 컬러는 이전에 설정한 값이 사용되고 있다.

invoke SelectObject, hdc, hfont

폰트사용이 끝난 후에는,DC에 이전의 폰트를 복구해주어야 한다. 이것을 잊어버린다면 에러를 경험하게 될것이다. GDI오브젝트는 반드시 사용 후 복구해야한다.


Posted by openserver