News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Custom CreateFont function

Started by jdoe, December 04, 2008, 11:09:19 PM

Previous topic - Next topic

jdoe


Hi,

While revising my functions, I had to wonder if my CreateFont was not missing a parameter... Wouldn't be good if I added a hWnd parameter to pass to GetDC function instead of NULL. I'm not sure what difference it could make and this is what I ask here.
Also, do I need to use ReleaseDC to release the device context or is it useless in this case.




;
; Creates a font from the specified parameters
; The returned handle must be freed by the caller with DeleteObject
;
; Returns the font handle or NULL if it fails
;
; p_dwPointSize  = Font size
; p_dwWeight     = FW_ constant
; p_bItalic      = Italic font (FALSE / TRUE)
; p_bUnderline   = Underline font (FALSE / TRUE)
; p_bStrikeout   = Strikeout font (FALSE / TRUE)
; p_lpszFontName = Pointer to the font name
;
AzmtCreateFontA PROC p_dwPointSize:DWORD, p_dwWeight:DWORD, p_bItalic:DWORD, \
                     p_bUnderline:DWORD, p_bStrikeout:DWORD, p_lpszFontName:DWORD

    ;
    ; nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72)
    ;

    invoke GetDC, NULL
    invoke GetDeviceCaps, eax, LOGPIXELSY
    mul p_dwPointSize
    mov ecx, 72
    add eax, 72/2   ; round the calculated point size to the nearest integer
    xor edx, edx
    div ecx
    neg eax         ; the font mapper provides the closest match for the character height (negative value)

    invoke CreateFontA, eax, 0, 0, 0, p_dwWeight, p_bItalic, p_bUnderline, p_bStrikeout, DEFAULT_CHARSET, \
                        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, p_lpszFontName

    ret

AzmtCreateFontA ENDP




Any comments about improvements are welcomed.


MichaelW

Per the documentation for the GetDC function:
QuoteThe GetDC function retrieves a common, class, or private DC depending on the class style of the specified window.
...
After painting with a common DC, the ReleaseDC function must be called to release the DC.

Per the documentation for the ReleaseDC function:
Quote
It has no effect on class or private DCs

So I think if the DC obtained with GetDC(null) is a common DC, then ReleaseDC should be able to free it. This test code, which should be compiled as a console app, indicates that the DC obtained with GetDC(null) is a common DC, and therefore should be released with ReleaseDC.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      hInst       dd          0
      hWnd        dd          0
      _x          dd          0
      _y          dd          0
      hdc_common  dd          0
      hdc_window  dd          0
      hdc_private dd          0
      wc          WNDCLASSEX  <>
      msg         MSG         <>
      className   db          "test_class",0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    mov hInst, rv(GetModuleHandle, NULL)
    mov wc.cbSize,        sizeof WNDCLASSEX
    mov wc.style,         CS_OWNDC          ; <== to create private DC
    mov wc.lpfnWndProc,   OFFSET WndProc
    mov wc.cbClsExtra,    NULL
    mov wc.cbWndExtra,    NULL
    m2m wc.hInstance,     hInst
    mov wc.hbrBackground, rv(GetStockObject, BLACK_BRUSH)
    mov wc.lpszMenuName,  NULL
    mov wc.lpszClassName, OFFSET className
    mov wc.hIcon,         rv(LoadIcon, NULL, IDI_APPLICATION)
    mov wc.hCursor,       rv(LoadCursor, NULL, IDC_ARROW)
    mov wc.hIconSm,       0
    invoke RegisterClassEx, ADDR wc

    W = 400
    H = 300
    invoke GetSystemMetrics, SM_CXSCREEN
    shr eax, 1
    sub eax, W / 2
    mov _x, eax
    invoke GetSystemMetrics, SM_CYSCREEN
    shr eax, 1
    sub eax, H / 2
    mov _y, eax

    invoke CreateWindowEx, WS_EX_OVERLAPPEDWINDOW,
                           ADDR className,
                           chr$("Test"),
                           WS_OVERLAPPED or WS_SYSMENU,
                           _x, _y, W, H,
                           NULL, NULL,
                           hInst, NULL
    mov hWnd, eax

    invoke ShowWindow, hWnd, SW_SHOWNORMAL
    invoke UpdateWindow, hWnd

  msgLoop:

    invoke GetMessage, ADDR msg, NULL, 0, 0
    .IF eax != 0
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage, ADDR msg
      jmp   msgLoop
    .ENDIF

    exit msg.wParam

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

WndProc proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    SWITCH uMsg
      CASE WM_CREATE

        invoke GetDC, NULL
        mov hdc_common, eax
        .IF hdc_common == 0
          print "GetDC(NULL) failed",13,10
        .ENDIF

        invoke GetWindowDC, hwnd
        mov hdc_window, eax
        .IF hdc_window == 0
          print "GetWindowDC(hwnd) failed",13,10
        .ENDIF

        invoke GetDC, hwnd
        mov hdc_private, eax
        .IF hdc_private == 0
          print "GetDC(hwnd) failed",13,10
        .ENDIF

        ;-----------------------------------
        ; ReleaseDC always returns success.
        ;-----------------------------------

        print "ReleaseDC(hwnd, hdc_common):",9
        invoke ReleaseDC, hwnd, hdc_common
        print ustr$(eax),13,10
        print "ReleaseDC(hwnd, hdc_window):",9
        invoke ReleaseDC, hwnd, hdc_window
        print ustr$(eax),13,10       
        print "ReleaseDC(hwnd, hdc_private):",9
        invoke ReleaseDC, hwnd, hdc_private
        print ustr$(eax),13,10,13,10

        ;------------------------------------------------
        ; ReleaseDC frees only common and window DCs, so
        ; SaveDC should now fail for a common or window
        ; DC and succeed for a private DC.
        ;------------------------------------------------

        print "SaveDC(hdc_common):",9
        invoke SaveDC, hdc_common
        .IF eax == 0
          mov eax,LastError$()
          print eax,13,10
        .ELSE
          print "OK"
        .ENDIF

        print "SaveDC(hdc_window):",9
        invoke SaveDC, hdc_window
        .IF eax == 0
          mov eax,LastError$()
          print eax,13,10
        .ELSE
          print "OK"
        .ENDIF

        print "SaveDC(hdc_private)",9
        invoke SaveDC, hdc_private
        .IF eax == 0
          print ustr$(eax),13,10
          mov eax,LastError$()
          print eax,13,10
        .ELSE
          print "OK"
        .ENDIF

      CASE WM_CLOSE
       invoke DestroyWindow, hwnd
      CASE WM_DESTROY
        invoke PostQuitMessage, NULL
      DEFAULT
        invoke DefWindowProc, hwnd, uMsg, wParam, lParam
    ENDSW
    ret
WndProc endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


ReleaseDC(hwnd, hdc_common):    1
ReleaseDC(hwnd, hdc_window):    1
ReleaseDC(hwnd, hdc_private):   1

SaveDC(hdc_common):     The handle is invalid.

SaveDC(hdc_window):     The handle is invalid.

SaveDC(hdc_private)     OK

eschew obfuscation

jdoe


Michael,

It is not all the examples I've found on the web that use ReleaseDC in a function like that and that's why I posted this question because I couldn't find a reason anywhere. Also, the difference between common, class and private DCs is not evident or should I say, is not evident for a person like me who don't know alot about the underlying knowledge of GUI stuff. MSDN is not always crystal clear for noobs.

I didn't thought to do a test like yours and, as always, your methodology is perfect.

Thanks


donkey

Quote from: jdoe on December 05, 2008, 08:01:42 PM
Also, the difference between common, class and private DCs is not evident or should I say, is not evident for a person like me who don't know alot about the underlying knowledge of GUI stuff. MSDN is not always crystal clear for noobs.

A DC is private ONLY when you create a window with the class style CS_OWNDC, all other DCs are common (Class DCs are not applicable to Win32/64, they are a legacy from 16 bit Windows and can be ignored). So, you must always call ReleaseDC except in the extremely rare case that you have decided to manage your own DC.

Hope this answers your question about DC types.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

jdoe

Quote from: donkey on December 06, 2008, 08:49:06 AM
Hope this answers your question about DC types.


For sure it does !

:U