News:

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

Main Menu

Subclassing an OOP edit control

Started by HSE, July 27, 2015, 04:22:38 AM

Previous topic - Next topic

HSE

Hi !

I have a littlte problem in using the classic Hutch's subclassing example:

; ===============================================================
; Title:   EdDec.inc
; ================================================================

DEF_EdDec struc
  dCtlID      DWORD     ?         ;Contol ID
  dStyle      DWORD     ?         ;Style
  dExStyle    DWORD     ?         ;Extended style
  pTitle      PSTRING   ?         ;-> Window title
  sdPosX      SDWORD    ?         ;X position
  sdPosY      SDWORD    ?         ;Y position
  dWidth      DWORD     ?         ;Width
  dHeight     DWORD     ?         ;Height
DEF_EdDec ends
PDEF_EdDec typedef ptr DEF_EdDec

; —————————————————————————————————————————————————
; Object:  EdiDec
; Purpose: Implement a thin wrapper around the Edit GDI object.

Object EdDec, , WinControl                 ;Class "Edit"
  RedefineMethod    Done
  RedefineMethod    Init,         POINTER, HWND, PDEF_EdDec
  RedefineMethod    WndProc,      DWORD, WPARAM, LPARAM
ObjectEnd

; ===========================================================
if IMPLEMENT
; ————————————————————————————————————————————————
; Method:    Edit.Done
; Purpose:   Finalize the Edit object.
; Arguments: None.
; Return:    Nothing.

Method EdDec.Done, uses esi
    SetObject esi
    Unsubclass EdDec                           ;Uses esi
    ACall esi.Done
MethodEnd

; ——————————————————————————————————————————————————
; Method:    EdiDec.Init
; Purpose:   Initialize the Edit object.
; Arguments: Arg1: -> Owner object.
;            Arg2: Parent window HANDLE.
;            Arg3: -> DEF_Edit initialization structure.
; Return:    Nothing.
Method EdDec.Init, uses esi, pOwner:POINTER, hParent:HWND, pDefStruc:PDEF_EdDec
    SetObject esi
    mov ecx, pDefStruc
    assume ecx:PDEF_EdDec
    mov eax, [ecx].dStyle
   
    or eax, WS_VISIBLE or  WS_CHILD or \
                ES_AUTOHSCROLL or ES_NOHIDESEL
     
    invoke CreateWindowEx, [ecx].dExStyle, $OfsCStr("EDIT"), [ecx].pTitle, eax, \
                           [ecx].sdPosX, [ecx].sdPosY, [ecx].dWidth, [ecx].dHeight, \
                           hParent, [ecx].dCtlID, hInstance, 0

    assume ecx:NOTHING
    ACall esi.Init, pOwner, eax
    Subclass EdDec                             ;Uses esi
MethodEnd

; —————————————————————————————————————————————————————
; Method:    EdiDec.WndProc
; Purpose:   Processing of window messages. Before invoking it, the window must be subclassed.
; Arguments: Arg1: Message identifier.
;            Arg2: First message parameter.
;            Arg3: Second message parameter.
; Return:    eax = This value is the result of the message processing and depends on the message ID.
; Note:      Window HANDLE is passed in pSelf (hidden argument).

Method EdDec.WndProc,, uMsg:DWORD, wParam:WPARAM, lParam:LPARAM

LOCAL Buffer[32]:BYTE               ; numeros con decimales

SetObject ebx

.if uMsg == WM_CHAR
        .if wParam == 8             ; backspace
          jmp accept
        .endif

        .if wParam == "."           ; only allow one decimal point

;  *  *  *    T R O U B L E   H E R E

; Hutch's line
invoke SendMessage, [ebx].hWnd, WM_GETTEXT, sizeof Buffer, ADDR Buffer

        mov ecx, sizeof Buffer  ; byte count in ecx
   
        lea esi, Buffer         ; address in esi
@xxx:
         lodsb                   ; load byte into al

        cmp al, "."             ; if decimal point already in Buffer
        jne @xx1
        return 0              ; throw it away
@xx1:
        dec ecx
        cmp ecx, 0
        jne @xxx

        jmp accept
.endif

        .if wParam < "0"
            return 0
        .endif

        .if wParam > "9"
            return 0
        .endif
.endif

accept:

    GetSubclassingInst EdDec, pSelf
    OCall eax::EdDec.Dispatch, pSelf, uMsg, wParam, lParam

MethodEnd

endif


Ok. Not a little problem: the program crash when invoke SendMessage for string retrieving.

Thanks. HSE
Equations in Assembly: SmplMath

dedndave

if the message is sent from the WndProc to the same window, use PostMesssage

otherwise, i guess you are using pTitle ?
you didn't show us the INVOKE code

dedndave

in fact, there have been times when even that didn't work for me
a case that i call "frame lock" - although, i imagine it has some other name

the case occured when the code that followed the PostMessage was dependant on the result
my solution was to PostMessage, then start a timer that returned to the WndProc a few mS later
the WM_TIMER code then handled the code that operated on the result

probably not the cleanest solution, but it worked for me
the problem is not time, so much as the code is executed in a seperate call to the WndProc frame
that gave the posted message an opportunity to complete before the result was examined

HSE

The invoke is in EdDec.WndProc

        .if wParam == "."           ; only allow one decimal point

;  *  *  *    T R O U B L E   H E R E

; Hutch's line
invoke SendMessage, [ebx].hWnd, WM_GETTEXT, sizeof Buffer, ADDR Buffer

        mov ecx, sizeof Buffer  ; byte count in ecx
   
        lea esi, Buffer         ; address in esi
@xxx:
         lodsb                   ; load byte into al

        cmp al, "."             ; if decimal point already in Buffer
        jne @xx1
        return 0              ; throw it away
@xx1:
        dec ecx
        cmp ecx, 0
        jne @xxx

        jmp accept
.endif


using PostMessage don't crash, but apparently don't retrieve the string. It's the situation you mention, the response is later. But in plain asm (not OOP) SenMessage work very well in \masm32\examples\exampl01\filtinpt\

ObjAsm32 have some sort of dispatching mechanism, but I can't figure out how work in this case.

Thanks.
Equations in Assembly: SmplMath

dedndave

use PostMessage to get the text
then a call to SetTimer to start a timer

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644906%28v=vs.85%29.aspx

when you get the WM_TIMER message, you can stop the timer with KillTimer
then process the string in the WM_TIMER handler code

i notice you use EBX and ESI - i hope you preserve them   :t :t

Biterider

Hi HSE
The hint of dedndave is very important and maybe the reason for your crashes. In the EdDec.WndProc you are sending a message to itself and since you didn't preserve esi and ebx it crashes on the second call.
First add a "uses ebx esi" in the method definition and then solve the calling issue invoking the original WndProc, which is stored in EdDec.pPrevWndProc using CallWindowProc.

Biterider

dedndave

if you use WS_HSCROLL and/or WS_VSCROLL styles when you create the window, you get "system" scroll bars
this is probably the easiest way to get started
if you do that, the client area size is automatically adjusted to account for scroll bar size

i prefer to use CreateWindowEx and the class string "'ScrollBar",0
when you do it that way, you have to measure the scroll bar and store the value
i think there is a GetSystemMetrics value, but i usually measure it with GetWindowRect,hScrollBar,addr rcScrollBar
when you create your own, you also have to size and move the scroll bar when the window is sized


HSE

Thanks Dave!! I have a lot to read in that pages  :t.

The timer work perfect, but now I have errors when invoking Send or Post message.   
Equations in Assembly: SmplMath

Biterider

Hi HSE
Have you tried what I wrote before?

Biterider

HSE

#10
Hi Biterider!
I'm trying now. Perhaps program was crashing because my very strange setting of objects. Now I'm using a simple demo.

Edited: It's working with SendMessage, obviously was a problem of register preservation because I don't see any other diference. I will try to implement the Dave's sugestion using PostMessage and Timer.

Edited2: I think the PostMessage never return nothing.
Equations in Assembly: SmplMath

dedndave

PostMessage simply places the message in the queue and returns

WndProc is single-threaded
that means that the message you are currently handling has to exit,
before the posted message will be sent to the WndProc routine

thus, the string will not be retrieved until some time later

if you PostMessage, then try to immediately process the string, it won't work

HSE

It's posible that WM_TIMER arrive in 5s with the message still in the queue?
Equations in Assembly: SmplMath

dedndave

no it will likely be handled very quickly
the message queue pulls messages according to type, and time posted
but, that message is probably handled withing a few milliseconds

HSE

Thanks Dave!

Perhaps there is another issue that I don't see. I haven't readed the messages subject yet. Of course I used the MASM32 examples as skeletons for years but never studied the matter enough.

Ten minutes later:
in MSDN  "ComCtl32.dll version 6 should not be subclassed (or superclassed) with ANSI window procedures."   
Equations in Assembly: SmplMath