News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Subclass button control

Started by newAsm, June 04, 2013, 07:36:21 PM

Previous topic - Next topic

Dubby

hmm... let get this straight...

a button is indeed a window...

that's it...
please correct me if I'm wrong..

qWord

nearly the same as dave's, but marks the errors/changes:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

      .486                      ; create 32 bit code
      .model flat, stdcall      ; 32 bit memory model
      option casemap :none      ; case sensitive

      include Button.inc        ; local includes for this file

procBtnCtrl PROTO :DWORD, :DWORD, :DWORD, :DWORD

.code

start:

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

    ; ------------------
    ; set global values
    ; ------------------
      mov hInstance,   FUNC(GetModuleHandle, NULL)
      mov CommandLine, FUNC(GetCommandLine)
      mov hIcon,       FUNC(LoadIcon,hInstance,500)
      mov hCursor,     FUNC(LoadCursor,NULL,IDC_ARROW)
      mov sWid,        FUNC(GetSystemMetrics,SM_CXSCREEN)
      mov sHgt,        FUNC(GetSystemMetrics,SM_CYSCREEN)

      call Main

      invoke ExitProcess,eax

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

Main proc

    LOCAL Wwd:DWORD,Wht:DWORD,Wtx:DWORD,Wty:DWORD

    STRING szClassName,"Prostart_Class"

  ; --------------------------------------------
  ; register class name for CreateWindowEx call
  ; --------------------------------------------
    invoke RegisterWinClass,ADDR WndProc,ADDR szClassName,
                       hIcon,hCursor,COLOR_BTNFACE+1

  ; -------------------------------------------------
  ; macro to autoscale window co-ordinates to screen
  ; percentages and centre window at those sizes.
  ; -------------------------------------------------
    AutoScale 75, 70

    invoke CreateWindowEx,WS_EX_LEFT,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPEDWINDOW,
                          Wtx,Wty,Wwd,Wht,
                          NULL,NULL,
                          hInstance,NULL
    mov hWnd,eax

  ; ---------------------------
  ; macros for unchanging code
  ; ---------------------------
    DisplayWindow hWnd,SW_SHOWNORMAL

    call MsgLoop
    ret

Main endp

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

RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
                      Icon:DWORD, Cursor:DWORD, bColor:DWORD

    LOCAL wc:WNDCLASSEX

    mov wc.cbSize,         sizeof WNDCLASSEX
    mov wc.style,          CS_BYTEALIGNCLIENT or \
                           CS_BYTEALIGNWINDOW
    m2m wc.lpfnWndProc,    lpWndProc
    mov wc.cbClsExtra,     NULL
    mov wc.cbWndExtra,     NULL
    m2m wc.hInstance,      hInstance
    m2m wc.hbrBackground,  bColor
    mov wc.lpszMenuName,   NULL
    m2m wc.lpszClassName,  lpClassName
    m2m wc.hIcon,          Icon
    m2m wc.hCursor,        Cursor
    m2m wc.hIconSm,        Icon

    invoke RegisterClassEx, ADDR wc

    ret

RegisterWinClass endp

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

MsgLoop proc

    LOCAL msg:MSG

    push esi
    push edi
    xor edi, edi                        ; clear EDI
    lea esi, msg                        ; Structure address in ESI
    jmp jumpin

    StartLoop:
      invoke TranslateMessage, esi
    ; --------------------------------------
    ; perform any required key processing here
    ; --------------------------------------
      invoke DispatchMessage,  esi
    jumpin:
      invoke GetMessage,esi,edi,edi,edi
      test eax, eax
      jnz StartLoop

    mov eax, msg.wParam
    pop edi
    pop esi

    ret

MsgLoop endp

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

; "uses esi edi ebx" doesn't hurt!
WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

    LOCAL var    :DWORD
    LOCAL caW    :DWORD
    LOCAL caH    :DWORD
    LOCAL Rct    :RECT
    LOCAL buffer1[260]:BYTE  ; these are two spare buffers
    LOCAL buffer2[260]:BYTE  ; for text manipulation etc..

    Switch uMsg
      Case WM_COMMAND

movzx eax,word ptr wParam[2] ;
movzx edx,word ptr wParam
;shr eax,16 ;<----------------
;and edx,0FFFFh ;<----------------

;cmp bx,BN_CLICKED ; button clicked
.if eax == BN_CLICKED
cmp edx,100 ; button clicked?
jne Noclick ; no, Exit
invoke MessageBox,hWnd,ADDR s_MClicked, ADDR szDisplayName,MB_OKCANCEL
;return 0
sub eax,eax
ret
.endif
Noclick:
      Case WM_CREATE
invoke CreateWindowEx,0,offset ButtonClass,offset pszClass,\
WS_CHILD or WS_VISIBLE, \
100,100,60,30,hWin,100,
hInstance,NULL
      mov  [hBtn],eax

;lea esi,procBtnCtrl ; <---------------- WinABI!
INVOKE SetWindowLong, eax, GWL_WNDPROC, procBtnCtrl
mov [lpBtnProc],eax
      Case WM_SYSCOLORCHANGE

      Case WM_SIZE

      Case WM_CLOSE
invoke DestroyWindow,hWin ; <----------------
      Case WM_DESTROY
        invoke PostQuitMessage,NULL
      Default
      invoke DefWindowProc,hWin,uMsg,wParam,lParam ; <-------
ret ;<-------
    Endsw

   
xor eax,eax ;<--------
    ret

WndProc endp

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

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

TopXY proc wDim:DWORD, sDim:DWORD

    mov eax, [esp+8]
    sub eax, [esp+4]
    shr eax, 1

    ret 8

TopXY endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

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

procBtnCtrl proc hwnd:DWORD, uMsg:DWORD,wParam:DWORD,lParam:DWORD
.if uMsg == WM_LBUTTONDOWN
invoke MessageBeep,MB_OK
.endif
invoke CallWindowProc,lpBtnProc ,hwnd,uMsg,wParam,lParam
ret
procBtnCtrl endp

end start
MREAL macros - when you need floating point arithmetic while assembling!

qWord

Quote from: Dubby on June 05, 2013, 12:51:58 AM
a button is indeed a window...
yes, more precisely a child window.
MREAL macros - when you need floating point arithmetic while assembling!

newAsm

Hi dedndave,

You example worked :greenclp:Thanks. I heard a short beep and the message.

One question, in my example BN_CLICKED was not recognized.

You used WM_LBUTTONDOWN and it worked. I will experiment with BN_CLICKED using your example but I am curious as where did I do wrong. Was it due to the notification type or what?

Appreciate your example and help. It has been very helpful and now I have to seriously consider using WM_LBUTTONDOWN than BN_CLICKED.

Thanks..newAsm

dedndave

i used WM_LBTNDOWN in the subclassed button proc
i used WM_COMMAND/BN_CLICKED in WndProc
the BN_CLICKED is assumed, as i mentioned before - BN_CLICKED=0

Dubby

Hi newAsm,
please allow me to elaborate my previous statement..

according to the MSDN BN_CLICKED is notification message sent by a button (a child window) to it's parent window.

and about GWL_WNDPROC, according to MSDN the GWL_WNDPROC Sets a new address for the window procedure.

thus, by subclassing a button (replacing the procedure of a button), now you have a full control to act as a button itself...

the BN_CLICKED notification message only exist in parent window, because the child window (button) sent it to the parent.

hope this helps..

dedndave

let me clarify that a little....

    mov     eax,uMsg
    .if eax==WM_COMMAND
        .if wParam==CID_BUTTON1
            INVOKE  MessageBox,hWin,ADDR s_MClicked, ADDR szDisplayName,MB_OKCANCEL
        .endif
        xor     eax,eax    ;return 0

    .elseif eax==WM_CREATE


to be "more correct", that should read
        .if wParam==CID_BUTTON1 + (65536*BN_CLICKED)

because BN_CLICKED = 0, we can leave the "+ (65536*BN_CLICKED)" part out   :P

newAsm

Thanks Dubby for the clarification. Sometimes, it is a bit confusing to think that a button is a window.

Thanks dedbdave and qWord for your "guru" help and example.  :greenclp:
..newAsm