Jump to content
Tuts 4 You

Subclass problem but why?


LCF-AT

Recommended Posts

Hi guys,

so today I wanna ask some questions about subclassing again.So I thought I would know how to subclass correctly but before a few days I got some problems and now I think I dont know how to subclass correctly.So I have following problem now.

I just created a dialog window and in this window to create just a simple static control and this I wanna subclass.So I just used CreateWIndowEx API to create static and right after this I used SetWindowLong API with the handle I got before for the static...

invoke    CreateWindowEx,0,chr$("STATIC"),NULL,WS_CHILD or WS_VISIBLE ,20, 20,200, 100,hWnd, 0,hInstance, 0
mov       hWndStatic,eax

invoke SetWindowLong,hWndStatic,GWL_WNDPROC,offset StaticSubclassProc
mov OllyWndProc,eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
StaticSubclassProc PROC hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM


.if     uMsg == WM_CTLCOLORSTATIC
        .......
        ret


.elseif uMsg == WM_CONTEXTMENU
        .......
  

.endif
invoke CallWindowProc,OllyWndProc,hWnd,uMsg,wParam,lParam 
ret

StaticSubclassProc endp

.....but if I do it on that way then I dont get the uMsg I wanna check above and nothing happens.Static gets no colors and no context menu if I click right mouse on it.The question is why I dont get the messages in this routine.

Now I tried the same again but this time I used the main routine handle on the SetWindowLong API....

invoke SetWindowLong,hWnd,GWL_WNDPROC,offset StaticSubclassProc

...and now it works....but also not so as I wanted.Problem in this case is that I only get the main handle send into this routine and not the handle of my static control.So my goal was it to subclass the single static control to get messages into this routine who just have also the handle of my static control only to color it and to get context menu on the static only and not on entire dialog window too you know.

So what is wrong now in that case?Maybe you can help and tell me what I did wrong etc.

Thank you

Link to comment

http://stackoverflow.com/questions/22255534/subclassing-static-control-to-receive-wm-ctlcolorstatic - In short: WM_CTLCOLORSTATIC is always sent to parent window. That's just how Windows work.

 

1 hour ago, LCF-AT said:

Problem in this case is that I only get the main handle send into this routine and not the handle of my static control.

Yes, you do get handle of static control, it's sent as lParam. See https://msdn.microsoft.com/en-us/library/windows/desktop/bb787524(v=vs.85).aspx

  • Like 1
Link to comment

Hi kao,

thanks for the info.Ok on that way I can check lparam for static handle to color it.But what about the other MSG WM_CONTEXTMENU?How to check there whether it has static handle or whether not if I wanna just show the conext menu on the static control itself and not anywhere else of main window.How to handle this now?

So what I dont understand is that I before always did subclass other controls like tabs and listviews with my method to use SetWIndowLong with the handle I got after CreateWIndowEx and there is was also working also WM_CONTEXTMENU.So if something was triggerd in the subclass of them then it also always has the handle of only the tab or LV into hWnd variable at routine top proc.So why isnt this not working with others like static too?So I dont wanna get the main handle into my subclass routines only the handles of controls I have subclassed to handle all simple and easy without to check the handles etxra etc you know.

Example: So what is if I wanna use other MSGs like WM_RBUTTONDOWN in my static subclass?If I use main handle to subclass static then right button down gets triggered but only with main handle and if I subclass it with static handle then I dont get WM_RBUTTONDOWN.So again its same like WM_CONTEXTMENU too and I cant check any handle there and context etc will shown on the entire window and not on static alone.

So then subclassing makkes not much sense or?So I thought I do just subclassing to handle my xy control stuff seperated in my own routine without to handle & care anymore about handle checking if I subclass any controls with a specific routine.Hmmm.So do you have any clue what to do then?

greetz

Link to comment

Hi kao,

thanks for the example.Good ok now it works with SS_NOTIFY flag but now I dont get WM_CTLCOLORSTATIC anymore and maybe other MSGs too. :( So is there no list of what MSGs I do get or not in subclasses using control x till control y?

greetz

Link to comment

Hi huntingspace,

thanks for your example code.So I see you do handle WM_CTLCOLORSTATIC from main proc to color the static but the question is why I dont get this message into the static subclass proc?So what is the sens to subclass anything and then to handle MSGs for the subclassed control into main proc?So then I dont need to subclass any control anymore and have to handle everything from main proc only you know.

So I dont understand why windows not send all the messages into the subclass procs if they hold the handles of controls which was subclassed.Like WM_CTLCOLORSTATIC for example.

DlgProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM    
..........
.elseif (uMsg==WM_CTLCOLORSTATIC)
        mov eax,lParam
        .if (eax==hStaticButton2)
            ;invoke SetTextColor,wParam,0
            invoke SetBkColor,wParam,StaticColor
            invoke CreateSolidBrush,StaticColor
            ret
        .endif

Above your code part of main routine.You do check for WM_CTLCOLORSTATIC and then you check the handle it holds in lParam and if match then color.So why does windows not check the handle to + sending them exactly this MSG into the subclass so that I then can handle it there?So in my eyes its just ridiculous.No idea so maybe I do think wrong or whatever but for me there is no logic why to subclass if I dont get the messages send to my subclass.

Another example.So at the moment I try to create a Olly plugin and did also create a static control I did subclass and where I have same trouble.So if I do subclass the static with the static handle then I dont get all messages into the routine but if I subclass the Olly handle then I get also all messages into the subclass routine but then I only get the Olly main handle and no static handle what I could check etc.Thats just bad.There is no real clear solution how to handle this correctly or I dont know it etc.

greetz

Link to comment

According to MSDN reference WM_CTLCOLORSTATIC message is only handled by parent window when the control is about to be drawn. Whereas the subclassing (child) window can handle WM_PAINT message instead of WM_CTLCOLORSTATIC message. Therefore if you include WM_PAINT message in subclass procedure WM_CTLCOLORSTATIC message will not be sent to the parent handler anymore.

Link to comment

Hi and thanks again for the example huntingspace.All in all I am still not satisfied and to choose other methods to handle some stuff on other messages instead to do it on the default messages just because I dont get them in subclass. :( Also sooner or later I will get other trouble situations too like if I need to update new position which was set etc and I dont get the infos into my subclass then.

So the question is what I should do.So it seems there is no mater way to handle this right or 100 % correctly I was looking for.

Ok I have another small question about how to build routines correctly.So I did check diffrent source codes I found and find always other routine handlings about this...

.if uMSG
...
.elseif uMSG
....
.elseif uMSG
....
.else
invoke CallWindowPro ..
ret
.endif
xor eax,eax
ret
-------------------
-------------------
.if uMSG
...
.elseif uMSG
....
.elseif uMSG
....
.endif
invoke CallWindowPro ..
ret
-------------------
------------------
.if uMSG
...
.elseif uMSG
....
.elseif uMSG
....
.else
mov eax,FALSE
ret
.endif
mov eax, TRUE
ret

So what is now the correctly way?When I have to return True or false etc?Normaly I thought if a messages was catched then I do return true and if not then false and what about some MSGs which was catched like WM_CTLCOLORSTATIC so when I know that I have to return them only on MSG?Also in some Olly plugin sources I do find some code was just does return 0 or True.So I am not sure what of them I have to return directly 0/1 or not etc you know.Do you have some small helpfully infos about that?

Thanks again.

Link to comment

MSDN references contain more detailed information about system messages and you need to learn it to understand that it is necessary to return the system.
For example, MSDN reference tells us information about the WM_INITDIALOG message:

Quote

Return value
The dialog box procedure should return TRUE to direct the system to set the keyboard focus to the control specified by wParam. Otherwise, it should return FALSE to prevent the system from setting the default keyboard focus.

That is to say this system message can return either TRUE or FALSE. It all depends on your task.

For example, the WM_PAINT message always returns FALSE:

Quote

Return value
An application returns zero if it processes this message.

And, for example, the WM_CTLCOLORSTATIC message always returns handle to a brush that the system uses to paint the background of the control:

Quote

Return value
If an application processes this message, the return value is a handle to a brush that the system uses to paint the background of the static control.

And other messages like WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORDLG, WM_CTLCOLORBTN that paint the user interface in main window handler also return handle to a brush.

Another system messages that are not handled always return FALSE.

  • Like 1
Link to comment

Hi again huntingspace,

thanks again for the infos so far.So it seems I have to check all MSGs on MSDN to find out what to return.So do you have maybe any kind of template which is empty and only holds all important MSGs you need to handle extra?I made a short one so this should be now correctly right?

.if	uMsg == WM_INITDIALOG  ;TRUE ret

.elseif uMsg == WM_COMMAND     ;FALSE ret
                mov eax,FALSE
                ret
.elseif	uMsg == WM_CLOSE       ;FALSE ret
                mov eax,FALSE
                ret
.elseif	uMsg == WM_SIZE        ;FALSE ret
                mov eax,FALSE
                ret
.elseif uMsg == WM_NOTIFY      ; Ret not important?

.elseif	uMsg == WM_ERASEBKGND  ; True ret

.elseif	uMsg == WM_CTLCOLORSTATIC ; Eax brush Handle & ret
                ret
.elseif	uMsg == WM_CONTEXTMENU ; No ret to handle

.elseif	uMsg == WM_PAINT       ; FALSE ret
                mov eax,FALSE
                ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.else
mov eax,FALSE
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.endif
mov eax,TRUE
ret

One thing about the subclass stuff and not getting all MSGs into them.So does it make sense to catch the MSGs from main proc and send them into the subclass proc manually via sendmessage API?Like this....

Main Proc

.elseif uMsg == WM_CTLCOLORSTATIC
	        
	         mov edi, lParam
	        .if edi == hWndCmd
                 invoke SendMessage,edi,uMsg,wParam,lParam	
                 ret	        
	        .else
	         mov eax,FALSE
	        .endif
	         ret

Subclass proc
.elseif uMsg == WM_CTLCOLORSTATIC

              mov eax, hWndCmd
             .if lParam == eax
             invoke GetSysColor,COLOR_INFOBK 
             invoke CreateSolidBrush,eax
             mov edi, eax
             invoke SetBkMode,wParam,TRANSPARENT 
             mov eax, edi
             ret
             .endif
             xor eax,eax
             ret

...or is it a disadvantage?I mean so I could send all MSGs into subclass I dont get there but on the other hand I could also handle all in main proc.Normaly I would only have the basic code on my main proc and dont wanna write the entire codes into this proc to keep it small and clean and if I subclass then I can handle all codes seperated etc you know.So whats better now?Just wanna also try to prevent possible problems later I dont wanna have just because I do code on a wrong way so I wanna do it correctly anyhow.

greetz

Link to comment

Not bad, LCF-AT. You begin little by little to understand the system messages.
I have recently been programming in FASM and use a such template:

MainProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    mov edx,uMsg
    cmp edx,WM_INITDIALOG
    je wminitdialog
    cmp edx,WM_COMMAND
    je wmcommand
    cmp edx,WM_CLOSE
    je wmclose
    cmp edx,WM_CTLCOLORSTATIC
    je wmcolorstatic
    cmp edx,WM_SIZE
    je wmsize
    cmp edx,WM_NOTIFY
    je wmnotify
    cmp edx,WM_CONTEXTMENU
    je wmcontextmenu
    cmp edx,WM_PAINT
    je wmpaint
    jmp exit0
wminitdialog:
    ; some code
    jmp exit1
wmcommand:
    ; some code
    jmp exit0
wmclose:
    ; some code
    jmp exit0
wmcolorstatic:
    ; some code
    jmp finish
...
wmpaint:
    ; some code
exit0:
    xor eax,eax
    ret
exit1:
    xor eax,eax
    inc eax
finish:
    ret
MainProc endp

It seems to me this template is more comfortable and optimized.
Certainly I don't know your task but I think you should do the static control without subclassing. It seems to me you are greatly complicate the issue by subclassing. In fact many messages can be processed in main proc and you need not resend messages into subclassing proc.

  • Like 1
Link to comment

Hi again,

thanks again for your answer + template.So since I dont use MultiASM plugin anymore in Olly where I need to use labels I always like to use use this if / else / endif syntax thing and dont use labels anymore (rarly) in WinASM. :) So there is not really kind of special task I wanna handle etc so I am just testing here & there and find mostly any kind of problem where I need to find any solution/s you know.Maybe your are right and subclassing isnt always good & needed so I will keep this now in my mind.

greetz

Link to comment

Hi again,

I have small new question.I wanna ask whether you know how to build any kind of custom tooltips which I can use for my systemtray icon.Normaly I do use only tray icon + the app titel in szTip of NOTIFYICONDATA struct but I would also like to show informations which gets also updated in realtime like the time for example etc.Also the szTip is limited.So do you have anything for that maybe?Below a picture what I mean...

2016-11-26_010612.png

....something like this.

greetz

Link to comment

Hi,

some more questions about creating a tooltip / Baloontip on tray icon.

- How to get the infos if the mouse pointer does stops on my tray icon?So I thought I could create any small window to show directly over the icon what I also do update maybe each second via Timer but for this I need to find out when the mouse is on my tray icon.

- So I tried the NOTIFYICONDATA again on MSDN and there I can read somethine about NIF_REALTIME flag but I am not sure whether its really possible to show a info with that what gets updated also in realtime if the info is still shown.So my tests did fail.

Has anyone any idea which could help?

greetz

Link to comment

Hi again,

ok so now I found out how to check whether mouse cursor is on my tray icon / checking my set callback from NOTIFYICONDATA for WM_MOUSEMOVE in lparam.Ok this I got now so far.If I go on my tray icon then my created window gets shown so that good so far but now I have a next problem about how to find out whether the mouse pointer is away from my tray icon.I checked again MSDN and found something to use TrackMouseEvent API and set the dwFlag to TME_LEAVE whats sending the MSG WM_MOUSELEAVE where I could close or hide the created window again.Problem in this case is that it gets triggerd the whole time and my window is shown / hidden like rapid fire.My  code look so about this so maybe you can see the problem...

.elseif uMsg == WM_MOUSELEAVE
    invoke ShowWindow,htooltip,SW_HIDE

.elseif uMsg == WM_SHELLNOTIFY  ; callback MSG
    .if wParam == IDI_TRAY && lParam == WM_MOUSEMOVE 
		     mov TRACK.cbSize, sizeof TRACKMOUSEEVENT
		     mov TRACK.dwFlags,TME_LEAVE
		     mov eax,hWnd                  ; main proc handle
		     mov TRACK.hwndTrack,eax
		     invoke TrackMouseEvent,addr TRACK
             invoke ShowWindow,htooltip,SW_SHOW

....so now that the problem about this.Now I tried to find any other solution like checking the mousecursor whether its on tray icon & outside of tray icon etc but I also dont get it working so far.Has anyone any idea how to handle that?

greetz

Link to comment

Have not read the whole topic so not entirely sure what you are trying to do. If you are only intent on checking for mouse cursor movement over the tray icon wait for WM_MOUSEMOVE in lParam of your window callback procedure. If it's not active you know you don't need to have your customised tray icon tooltip from appearing anymore. I have no idea why you are checking WM_SHELLNOTIFY?

Ted.

Link to comment

Hi Ted,

so I do already check for WM_MOUSEMOVE in lparam at my callback WM_SHELLNOTIFY / so I could also set any other etc.If I got this then I can send / show a window over my icon (GetCursorPos + movewindow API).The problem now is how to find out whethe rmouse is no more on my icon you know.If I go away from my icon then no MSG xy will send which I could check.Only thing what I can do so far is to set a timer what does show my window for 3 seconds or so + hiding / destroy my window again.Do you have any better idea maybe I could try?

PS: So you know Win7 right,so there you get also a small window to see of any stuff you have into the taskbar like notepad file etc so something like this I wanna have too just over my tray icon with actually & updated (in realtime )app infos.Yesterday I also played a little to create a window to show it but its just transparent and only see the borders (I used tooltip class for CreateWInodwEx API) and  also if I set colors with TTM_SETTIPBKCOLOR isnt working anyhow.So I have to test a lot more to get this thing showing / working like I imagine.

PS: Do you have maybe some example code for PureBasic which I could check a little etc?

greetz

Link to comment

In PureBasic it goes something like this...

Declare MenuCallback(hWnd, uMsg, wParam, lParam)

If OpenWindow(0, #Null, #Null, #Null, #Null, "", #PB_Window_Invisible)
  AddSysTrayIcon(0, WindowID(0), LoadImage_(#Null, #OIC_BANG, #IMAGE_ICON, #Null, #Null, #LR_SHARED))
  SysTrayIconToolTip(0, "I am a tooltip!")
  
  SetWindowCallback(@MenuCallback())

  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf

Procedure MenuCallback(hWnd, uMsg, wParam, lParam)
  
  Select uMsg
    Case #WM_USER + 11477
      Select lParam
        Case #WM_MOUSEMOVE
          LPTRACKMOUSEEVENT.TRACKMOUSEEVENT
          LPTRACKMOUSEEVENT\cbSize = SizeOf(LPTRACKMOUSEEVENT)
          LPTRACKMOUSEEVENT\dwFlags = #TME_LEAVE
          LPTRACKMOUSEEVENT\hwndTrack = hWnd
          LPTRACKMOUSEEVENT\dwHoverTime = #HOVER_DEFAULT
          TrackMouseEvent_(@LPTRACKMOUSEEVENT)
          
        Case #WM_RBUTTONUP
          Debug "#WM_RBUTTONUP"
          End
          
      EndSelect
      
    Case #WM_MOUSELEAVE
      Debug "#WM_MOUSELEAVE"
      
  EndSelect
  
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Ted.

Edited by Teddy Rogers
  • Like 1
Link to comment

Hi Ted,

thanks for the code but I dont get it again.So I did this before too to catch WM_MOUSEMOVE in lparam and there I set TrackMouseEvent but right there it will also send a MSG to WM_MOUSELEAVE where I hide the window again.I made a short example code & file so maybe you can see whats wrong inside.Just a tray Icon and if you go with mouse on it then it does show / hide rapidly.So it dosent just send a MSG to WM_MOUSELEAVE if I leave the icon so also if I am on it so thats the problem.

Tray Tooltip.rar

greetz

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...