News:

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

Problems with subclass

Started by RHL, April 25, 2012, 08:08:41 AM

Previous topic - Next topic

RHL

Hi guys, i want ask help because i have problem ALWAYS i want a subclassing : ( and i do not know the reason


i have this code, I created all with CreateWindowEx function, first,  I created a dialog ( second main ) ,next,
I created two child dialogs within of second main, next, i want create control within child dialogs, well, i created...
next i want use ShowWindow function for hidde or show a child dialog, it I use a subclassing but the program i does not work and the CPU is accelerates to 50%,
always i have problems with subclassing, I readed a tutorial about subclassing made by Iczelion but a cannot do it, please you could help me guys

my full code, without res, only a main file *.asm

include \MASM32\INCLUDE\MASM32rt.inc
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.data
    ClassName db "MainWinClass",0
    AppName  db "Main Window",0
   
    classdialog db "#32770",0
    classbutton db "Button",0
   
    classname1 db "one",0
classname2 db "two",0

classname3 db "three",0
classname4 db "four",0

handleMAIN dd 0

handledialog1 dd 0
handledialog2 dd 0

handlebutton1 dd 0
handlebutton2 dd 0


subclass dd 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  hInstance
pop   wc.hInstance
mov   wc.hbrBackground,COLOR_BTNFACE+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,600,300,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

Myproc proc shWnd:HWND, suMsg:UINT, swParam:WPARAM, slParam:LPARAM

.IF suMsg==WM_COMMAND
mov edx,shWnd
.if edx==handlebutton1
invoke ShowWindow,handlebutton2,SW_HIDE
invoke ShowWindow,handlebutton1,SW_SHOW
.elseif edx==handlebutton2
invoke ShowWindow,handlebutton1,SW_HIDE
invoke ShowWindow,handlebutton2,SW_SHOW
.endif

.elseIF suMsg==WM_DESTROY
invoke SetWindowLong,subclass,GWL_WNDPROC,Myproc
    .else
        invoke CallWindowProc,subclass,shWnd,suMsg,swParam,slParam
        ret
    .endif
    xor eax,eax
    ret
Myproc endp



WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE

;===========================================================================
; create main windows
;===========================================================================
invoke CreateWindowEx,NULL,addr classdialog,addr classname1,10CA2000h, \
CW_USEDEFAULT,CW_USEDEFAULT,500,400,hWnd,NULL,hInstance,NULL
mov handleMAIN,eax
invoke ShowWindow,handleMAIN,SW_SHOW

; create second windows
invoke CreateWindowEx,NULL,addr classdialog,addr classname1,WS_BORDER or WS_VISIBLE or WS_CHILD, \
10,10,300,200,handleMAIN,NULL,hInstance,NULL
mov handledialog1,eax

; create sub controls dialog 1
invoke CreateWindowEx,NULL,addr classbutton,addr classname1,WS_CHILD or WS_VISIBLE,20,30,35,20,handledialog1,NULL,hInstance,NULL
invoke ShowWindow,handledialog1,SW_SHOW


; create second window
invoke CreateWindowEx,NULL,addr classdialog,addr classname2,WS_BORDER or WS_VISIBLE or WS_CHILD, \
310,10,300,200,handleMAIN,NULL,hInstance,NULL
mov handledialog2,eax

; create sub controls dialog 2
invoke CreateWindowEx,NULL,addr classbutton,addr classname2,WS_CHILD or WS_VISIBLE,30,40,35,20,handledialog2,NULL,hInstance,NULL
invoke ShowWindow,handledialog2,SW_HIDE

; create buttons for main windows
invoke CreateWindowEx,NULL,addr classbutton,addr classname3,50010000h, 10,220,35,20,handleMAIN,NULL,hInstance,NULL
mov handlebutton1,eax

invoke CreateWindowEx,NULL,addr classbutton,addr classname4,50010000h, 45,220,35,20,handleMAIN,NULL,hInstance,NULL
mov handlebutton2,eax


invoke SetWindowLong,handleMAIN,GWL_WNDPROC,Myproc
invoke SetWindowLong,handlebutton1,GWL_WNDPROC,Myproc
invoke SetWindowLong,handlebutton2,GWL_WNDPROC,Myproc
mov subclass,eax

.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF

xor eax,eax
ret
WndProc endp
end start

donkey

SetWindowLong is really the old way to subclass controls, you should consider SetWindowSubclass/DefSubclassProc for subclassing, it doesn't require that you save the old procedure address and allows chaining of subclassing procedures. This line in your code is definitely wrong:

invoke SetWindowLong,subclass,GWL_WNDPROC,Myproc

The subclass variable is a pointer to the original procedure not a window handle which is what the API requires. But the big problem is that you're trying to subclass a dialog and two buttons using the same procedure. That in itself is not completely wrong but you are using the same old procedure address for all of them, in this case you use the old procedure from a button. That's OK for the two buttons but will cause all sorts of problems when you try to call it as the default procedure for the dialog (handleMAIN). Next I'm not too familiar with newer versions of MASM but when you set the subclass you should be using OFFSET Myproc, for example:

invoke SetWindowLong,handlebutton2,GWL_WNDPROC,offset Myproc

Edgar
"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

dedndave

i think the biggest problem, here, is that you are using the same subclass
WndProc for different windows that were created from different classes

the handleMAIN window is created using the class string "#32770"
handlebutton1 and handlebutton2 are created using the class string "Button"

the "#32770" and "Button" classes have different original WndProc's
when you exit "Myproc", you send "#32770" messages to a "Button" WndProc
the best thing to do is probably create BtnProc and DlgProc seperately, to replace MyProc

you could use the same subclass proc, but when you exit,
you would have to point to the correct original WndProc in the CallWindowProc function
it is simpler to use different proc's for different classes

        invoke  SetWindowLong,handleMAIN,GWL_WNDPROC,DlgProc
        mov     subclassMAIN,eax
        invoke  SetWindowLong,handlebutton1,GWL_WNDPROC,BtnProc
        invoke  SetWindowLong,handlebutton2,GWL_WNDPROC,BtnProc
        mov     subclass,eax


a similar issue arises when you destroy the window
you point the subclassMAIN class to a button WndProc

--------------------
i see this a lot, and it seems to work ok - i guess - lol
i am surprised it doesn't crash more often - maybe it does, and we just don't realize it
        invoke  SetWindowLong,handleMAIN,GWL_WNDPROC,DlgProc
        mov     subclassMAIN,eax

there is a brief moment when the handleMAIN WndProc is pointing to DlgProc, and the return proc is 0  :P
the documentation does not say "we wait for you to store the returned value in a variable before sending messages"
i always prefer to call GetWindowLong to get the original WndProc address and store it before subclassing
        invoke  GetWindowLong,handleMAIN,GWL_WNDPROC
        mov     subclassMAIN,eax
        invoke  SetWindowLong,handleMAIN,GWL_WNDPROC,DlgProc

that way, the CallWindowProc parameter has a proper WndProc before you subclass
i will probably take some flack for this from other forum members
--------------------

another problem is the WM_DESTROY code
        .elseIF suMsg==WM_DESTROY
            invoke SetWindowLong,subclass,GWL_WNDPROC,Myproc

ok - you un-subclassed the window, but you forgot to destroy it afterward

dedndave

Quote from: donkey on April 25, 2012, 10:32:33 AMNext I'm not too familiar with newer versions of MASM but when you set the subclass you should be using OFFSET Myproc, for example:

invoke SetWindowLong,handlebutton2,GWL_WNDPROC,offset Myproc

Edgar

nah - masm knows it is a code label and passes the address, rather than the first four bytes of code   :P
        mov     wc.lpfnWndProc,Myproc
is also a valid form

RHL

@donkey: those APIs are new for me, thanks donkey, I will check the MSDN for it

@Dave: yeah man, also , i checked the Background.zip project, it helped me ,I saw you used the RegisterClassEx function,
for register of each window, and put all controls on it, i thought do it so, but i want check with subclassing, but always i have problems :/

now, I did the you say, use the SetWindowLong function and it works, it does not accelerates, but does not capture the WM_COMMAND message for the buttons,
those hides or show the child windows, that hard, I will check more subclassing examples :/

dedndave

is this what you're trying to do ??

when you create a WS_CHILD window or control, the CreateWindowEx hMenu parameter can (and probably should) be a control ID #

xandaz

   agreed.... Just scoring some points while you carry me on your backs. JK

dedndave

by the way - there was no need to subclass the buttons
but, i did anyways, to demonstrate that the button proc is seperate from the subclassed dialog   :P

RHL

thanks a lot dave, Is nice ur code, thanks mate