Author Topic: Subclassing in a dialog  (Read 3434 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Guest
Subclassing in a dialog
« on: October 09, 2018, 05:52:36 AM »
Hello,

I doubt a bit about the benefits of subclassing / superclassing controls in dialogs, but it is possible to some extent.

This is a sample using Edit and Label control. It will work in 32-bit and 64-bit. It uses the approach for the versions of ComCtl32.dll prior to version 6.

Code: OxygenBasic
  1. ' Subclassing in a Dialog
  2. $ filename "DlgSubclass.exe"
  3.  
  4. 'uses rtl32
  5. 'uses rtl64
  6.  
  7. '% review
  8. uses dialogs
  9.  
  10. % GWLP_WNDPROC= -4
  11. % DS_3DLOOK  0x0004L
  12. % DS_NOFAILCREATE  0x0010L
  13. % DS_MODALFRAME  0x80L
  14.  
  15. 'Equates
  16. % IDC_EDIT    = 1001
  17. % IDC_LABEL   = 1002
  18.  
  19. sys hEdit
  20. sys hLabel
  21.  
  22.  
  23. '=================================
  24. sub WinMain()
  25.  
  26.  Dialog( 0, 0, 302, 160, "Edit Subclass in a Dialog",
  27.          WS_POPUP | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_CLIPSIBLINGS | WS_VISIBLE | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | DS_SETFONT | DS_CENTER,
  28.           8, "MS Sans Serif",
  29.           WS_EX_CONTROLPARENT | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR)
  30.      
  31.     EDITTEXT("", IDC_EDIT, 8, 8, 217, 84,
  32.                        WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | WS_VISIBLE | ES_WANTRETURN | ES_LEFT | WS_BORDER,
  33.                        WS_EX_CLIENTEDGE)
  34.  
  35.     LText( "", IDC_LABEL, 8, 110, 120, 24)
  36.  
  37.     CreateModalDialog( null, @DlgProc, 0)    
  38. end function
  39.    
  40. WinMain()
  41. '=================================
  42.  
  43. function DlgProc( sys hDlg, uint uMsg, sys wParam, lParam ) as sys callback
  44.    hEdit= GetDlgItem(hDlg, IDC_EDIT)
  45.    hLabel=GetDlgItem(hDlg, IDC_LABEL)
  46.  
  47.    select case uMsg
  48.  
  49.     case WM_INITDIALOG
  50.        SetProp(hEdit, "OldEditProc", SetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))
  51.  
  52.     case WM_CLOSE
  53.        'Remove control subclassing
  54.       RemoveProp(hEdit, "OldEditProc", GetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))      
  55.            
  56.        EndDialog( hDlg, null )
  57.     end select    
  58.  
  59.     return 0
  60. end function
  61.  
  62. '======================================
  63. ' Subclass procedure for the Edit control to detect what  ASCII values were key in
  64. function EditProc(sys hDlg, uint wMsg, sys wParam, lParam) as sys callback
  65.  
  66.    select case wMsg        
  67.         case WM_KEYDOWN
  68.            SetWindowText (hLabel, "You have entered ASCII " str(wParam))
  69.    end select
  70.  
  71.    return CallWindowProc(GetProp(hEdit, "OldEditProc"), hEdit, wMsg, wParam, lParam)
  72.  
  73. end function
  74.  

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #1 on: February 13, 2020, 06:17:38 AM »
Hello Arnold

I recveive strange errors in this example.
First you missmatch

CreateModalDialog( null, @DlgProc, 0, 0)  '<- missmatch here
   'CreateModalDialog( sys hParent, sys *lpDialogProc, dwInitParam, lpdt) as sys 


Ok that is not problematic then , i just add one more NULL on the end.
then
GetDialog item is not declared in include "Dialogs"
then i get "too many brackets" even there are no to many as i see here:

 RemoveProp(hEdit, "OldEditProc", GetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))   

I see that you have working example so i am wandering how?
why i asking ?
I recently trying to subclass richedit control to get margin and line numbers so i am looking into
something similar...
Are you interested maybe ?   :)

thanks

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #2 on: February 13, 2020, 08:07:02 AM »
I found some errors in includes and in declaration
then after fixing , o2 say Ok ,but when i try to run then program just crush.

this one is critical

RemoveProp Lib "user32.dll" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long

and we have in program this:

RemoveProp(hEdit, "OldEditProc", GetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))

...so i don't know how this even compile  ::)

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #3 on: February 13, 2020, 08:16:00 AM »
Here is my code :
Code: [Select]
' Subclassing in a Dialog
$ filename "DlgSubclass.exe"

uses rtl32
'uses rtl64

'% review
uses dialogs
! SetWindowLong    Lib "user32.dll" Alias "SetWindowLongA"(hwnd AS INT,nIndex AS INT,dwNewLong AS INT) as INT
! SetWindowLongPtr Lib "user32.dll" Alias "SetWindowLongA"(ByVal hWnd As Int,byVal nIndex As Int, ByVal dwNewLong As Int) As Int
! SetProp          Lib "user32.dll" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
! GetProp          Lib "user32.dll" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long
! CallWindowProc   Lib "user32.dll" Alias "CallWindowProcA"(lpPrevWndFunc AS INT,hWnd AS INT,Msg AS INT,wParam AS INT,lParam AS INT) as INT
! RemoveProp Lib "user32.dll" Alias "RemovePropA" (ByVal hWnd As Long, ByVal lpString As String) As Long

% GWLP_WNDPROC= -4
% DS_3DLOOK  0x0004L
% DS_NOFAILCREATE  0x0010L
% DS_MODALFRAME  0x80L
% DS_CENTER = 2048

'Equates
% IDC_EDIT    = 1001
% IDC_LABEL   = 1002

sys hEdit
sys hLabel
int hDlg

'=================================
sub WinMain()
 
 hDlg = Dialog( 0, 0, 302, 160, "Edit Subclass in a Dialog",
         WS_POPUP | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_CLIPSIBLINGS | WS_VISIBLE | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | DS_SETFONT | DS_CENTER,
          8, "MS Sans Serif",
          WS_EX_CONTROLPARENT | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR)
     
    EDITTEXT("", IDC_EDIT, 8, 8, 217, 84,
                       WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | WS_VISIBLE | ES_WANTRETURN | ES_LEFT | WS_BORDER,
                       WS_EX_CLIENTEDGE)

    LText( "", IDC_LABEL, 8, 110, 120, 24)

    CreateModalDialog( null, @DlgProc, 0, 0)  '<- missmatch here
   'CreateModalDialog( sys hParent, sys *lpDialogProc, dwInitParam, lpdt) as sys   
end sub
   
WinMain()
'=================================

function DlgProc( sys hDlg, uint uMsg, sys wParam, lParam ) as sys callback
   hEdit  = GetDlgItem(hDlg, IDC_EDIT)
   hLabel = GetDlgItem(hDlg, IDC_LABEL)

   select case uMsg

    case WM_INITDIALOG
       SetProp(hEdit, "OldEditProc", SetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))

    case WM_CLOSE
       'Remove control subclassing
       'RemoveProp(hEdit, "OldEditProc", GetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc)) 
       RemoveProp( hEdit, "OldEditProc")
           
       EndDialog( hDlg, null )
    end select   
 
    return 0
end function

'======================================
' Subclass procedure for the Edit control to detect what  ASCII values were key in
function EditProc(sys hDlg, uint wMsg, sys wParam, lParam) as sys callback

   select case wMsg       
        case WM_KEYDOWN
           SetWindowText (hLabel, "You have entered ASCII " str(wParam))
   end select

   return CallWindowProc(GetProp(hEdit, "OldEditProc"), hEdit, wMsg, wParam, lParam)

end function

Arnold

  • Guest
Re: Subclassing in a dialog
« Reply #4 on: February 13, 2020, 10:03:52 AM »
Hi Aurel,

it seems that you still use an older version? Dialogs.inc has changed in the meantime, only three parameters are necessary, the fourth argument should be omitted, it points automatically to a DLGTEMPLATE structure. If you use an older version you must look in the examples there how lpdt is created and applied.

You do not include corewin, but your declarations seem to be wrong. Look in win32help file e.g. for RemoveProp: -> lpString. There are two alternatives. Corewin unprototyped solves this better than your prototyping. You also forgot GetWindowLong. For 32-bit GetWindowLongPtr and SetWindowLongPtr is not available in user32.dll.

This is my re-modyfied code, which again works in version 0.2.8 (32-bit only):

Code: [Select]
' Subclassing in a Dialog
$ filename "DlgSubclass.exe"

'uses rtl32

'% review
uses dialogs
! SetWindowLong    Lib "user32.dll" Alias "SetWindowLongA"
! GetWindowLong    lib "user32.dll" alias "GetWindowLongA"
! SetProp          Lib "user32.dll" Alias "SetPropA"
! GetProp          Lib "user32.dll" Alias "GetPropA"
! CallWindowProc   Lib "user32.dll" Alias "CallWindowProcA"
! RemoveProp Lib "user32.dll" Alias "RemovePropA"

% GWLP_WNDPROC= -4
% DS_3DLOOK  0x0004L
% DS_NOFAILCREATE  0x0010L
% DS_MODALFRAME  0x80L
% DS_CENTER = 2048

'Equates
% IDC_EDIT    = 1001
% IDC_LABEL   = 1002

sys hEdit
sys hLabel
int hDlg

'=================================
sub WinMain()
 
 hDlg = Dialog( 0, 0, 302, 160, "Edit Subclass in a Dialog",
         WS_POPUP | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_CLIPSIBLINGS | WS_VISIBLE | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | DS_SETFONT | DS_CENTER,
          8, "MS Sans Serif",
          WS_EX_CONTROLPARENT | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR)
     
    EDITTEXT("", IDC_EDIT, 8, 8, 217, 84,
                       WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | WS_VISIBLE | ES_WANTRETURN | ES_LEFT | WS_BORDER,
                       WS_EX_CLIENTEDGE)

    LText( "", IDC_LABEL, 8, 110, 120, 24)

    CreateModalDialog( null, @DlgProc, 0)

end sub
   
WinMain()
'=================================

function DlgProc( sys hDlg, uint uMsg, sys wParam, lParam ) as sys callback
   hEdit  = GetDlgItem(hDlg, IDC_EDIT)
   hLabel = GetDlgItem(hDlg, IDC_LABEL)

   select case uMsg

    case WM_INITDIALOG
       SetProp(hEdit, "OldEditProc", SetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))

    case WM_CLOSE
       'Remove control subclassing
       RemoveProp(hEdit, "OldEditProc", GetWindowLongPtr(hEdit, GWLP_WNDPROC, @EditProc))
       'RemoveProp( hEdit, "OldEditProc")
           
       EndDialog( hDlg, null )
    end select   
 
    return 0
end function

'======================================
' Subclass procedure for the Edit control to detect what  ASCII values were key in
function EditProc(sys hDlg, uint wMsg, sys wParam, lParam) as sys callback

   select case wMsg       
        case WM_KEYDOWN
           SetWindowText (hLabel, "You have entered ASCII " str(wParam))
   end select

   return CallWindowProc(GetProp(hEdit, "OldEditProc"), hEdit, wMsg, wParam, lParam)

end function

You will find information about subclassing here:

https://docs.microsoft.com/en-us/windows/win32/controls/subclassing-overview

There is an advanced and an old approach for subclassing. In the example of the first message above I used the old subclassing method.

Roland

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #5 on: February 13, 2020, 10:27:39 AM »
OK Arnold
I will try your version with latest 0.2.8 vaesion 32bit.
We have really too much include versions and what is the strangst , declarations are in conflict with
standard VB versions published on many places on the internet.
oh my...ok  ::)

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #6 on: February 13, 2020, 10:41:06 AM »
Yipie
Thanks Arnold ..
finally work in 0.2.8 32bit even ,...i still not tested how anything work on my win7_64bit  ::)

About subclassing ,well like you said i was sceptic, i found one old code from PureBasic
so i am in translation to o2..i hope that will work for line numbering in richedit control.  :D

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #7 on: February 14, 2020, 12:08:38 PM »
Just new unexpected discovery on masm32 forum.
Example work like a charm...code is in masm32...so i will not post it here.
I hope that i know how to translate it to o2 code  :D
masm32 code is here:
https://aurelsoft.ucoz.com/forum/3-26-1#45
« Last Edit: February 15, 2020, 02:05:13 AM by Aurel »

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #8 on: February 19, 2020, 12:04:34 PM »
In my research i found that method used in Dialog not work well or better to say not work for Window class.
i found some VB code which use different aproach with this api calls:

Private Declare Function DefSubclassProc Lib "comctl32.dll" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowSubclass Lib "comctl32.dll" Alias "#410" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, Optional ByVal dwRefData As Long) As Long
Private Declare Function RemoveWindowSubclass Lib "comctl32.dll" Alias "#412" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long
Private Declare Function SendMessageW Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Arnold

  • Guest
Re: Subclassing in a dialog
« Reply #9 on: February 20, 2020, 12:10:11 AM »
Hi Aurel,

I do not use VB, but this would be interesting to know:

DefSubclassProc Lib "comctl32.dll" Alias "#413" etc:
which WinApi functions are meant with #413, #410, #412

ByVal uIdSubclass As Long, Optional ByVal dwRefData As Long) As Long
seems to be a user defined function

SendMessageW --> does the code apply Unicode? This would be a total different approach.

I learned this about subclassing:
Subclassing means to define a new class that has the properties of an old class (the "superclass") with some changes. E.g. an edit control which needs some more feature. Most of the time the controls do almost everything you want.

Roland

jack

  • Guest
Re: Subclassing in a dialog
« Reply #10 on: February 20, 2020, 03:26:17 AM »
perhaps this will answer your question http://vb.mvps.org/samples/HookXP/
Quote
Way back in the dark ages, when comctl32.dll version 4.72 shipped with Windows 98 and Internet Explorer 4.01, Microsoft slipped an absolute gem of a tool into it. They provided a native means of subclassing windows that automatically handled the issues related to improper teardown. But, I hate to say, they played the typical Microsoft games, and didn't document these fabulous calls. It wasn't until they shipped Windows XP, many years later, that these four functions were actually documented. Until then, they were only exported by ordinal, and indeed even today only three of the four are exported by name.

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #11 on: February 20, 2020, 04:17:35 AM »
Hi Roland
well most examples i found is with VB
and declaration of api calls are same ,that is why i am looking at that examples.
Charles translate masm code to o2 and work perfect but it is dialog based program and i don't use
dialogs in my programs, of course i can add dialog to window as child form for easy solution.
and i am not shure which approach is wrong and which is right.
I will see...

@jack ,thank you for link !

Arnold

  • Guest
Re: Subclassing in a dialog
« Reply #12 on: February 20, 2020, 05:58:17 AM »
Hi Aurel,

it is not necessary to use dialogs.inc in any way. You can always apply CreateWindow or CreateWindowEx to create windows and controls. You can also create dialogs and controls with a resource editor in a .rc file, compile this file e.g. with gorc.exe to a .res file and link the .res file to an exe file.

With help of dialogs.inc it is possible to create small apps with dialogs and controls during runtime. So it is not necessary to compile the file each time to an exe file and I can see at once if changing the code will work or fail. But dialogs.inc is definitely not necessary to create a working app.

Aurel

  • Guest
Re: Subclassing in a dialog
« Reply #13 on: February 20, 2020, 06:28:19 AM »
Hi Roland

Thanks on stuff , but i alredy know that ,by the way i made first awinh.inc long time ago.
It is not problem in dialogs or Windows then in proper subclassing of  control.

For example i want to add line numbering in my existing richedit control in Window.
Window use his own well known WndProc.
In dialog based program SetWindowLong is under WM_INITDIALOG and i tried to use it in window under
WM_CREATE message , but my line numbering routine is in separate function and there peoblem appear.

In editProc ... separate callback function i try to start WM_PAINT which not respond at all to lineNumbering function.
So that is why i think that must be written in another way...i am not sure which one.
i have one PureBasic example but when i replicate (translate that code) i get nothing.
As you can see from Line numbering topic , this new subclassed calleback is called before numbering start and is called
inside WM_PAINT message.

Probably should be better to open new topic about subclasing controls in Window form?
I see it looks that my main mistake is because i replace WndProc in dialog app with main procedure which is in fact
DialogProc - callback .
When i figure this things much clear to me .I will open new topic for that.
« Last Edit: February 20, 2020, 07:30:14 AM by Aurel »