Sign in to follow this  
Followers 0
FaridAgl

Need help - SetWindowSubclass

13 posts in this topic

#1 ·  Posted (edited)

Firstly, here is the Subclass functions:

Then, what I have done so far:

#include "Subclass.au3"

GUICreate('Subclass Test', 450, 200)
GUICtrlCreateButton('Default', 10, 10, 100, 25)
$TextBox = GUICtrlCreateInput('Hello world!', 10, 45, 250, 20)
GUISetState()

$hHandle = DllCallbackRegister('MY_SUBCLASSPROC', 'LRESULT', 'HWND;UINT;WPARAM;LPARAM;UINT_PTR;DWORD_PTR')
If ($hHandle == 0) Then
MsgBox(16, 'Subclass Test', 'Call to DllCallbackRegister failed.')
Exit
EndIf

SetWindowSubclass(GUICtrlGetHandle($TextBox), DllCallbackGetPtr($hHandle), 0, 0)
If (@error) Then
MsgBox(16, 'Subclass Test', 'Call to SetWindowSubclass failed.')
Exit
EndIf

While (True)
Switch (GUIGetMsg())
Case -3 ;GUI_EVENT_CLOSE
OnExit()
EndSwitch
WEnd

Func MY_SUBCLASSPROC($hWnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
ConsoleWrite($uMsg & @CRLF)

DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
EndFunc

Func OnExit()
RemoveWindowSubclass(GUICtrlGetHandle($TextBox), DllCallbackGetPtr($hHandle), 0, 0) ;This must be called. If not, the scipt will remain running in taskbar, eating 1 cpu core.
Exit
EndFunc

Looks like it's working but there are some problems, for example the Input control ($TextBox) gets freezed, however SUBCLASSPROC function gets the notifications of the control (Look at the console).

I'm pretty sure I did all good, let me know if there is any problem in the code, maybe something that I forget to take care about.

If we success in feaguring out the problem, we can write a GUICtrlRegisterMsg() function easily.

Thanks in advance.

Edit: Take a look over this article if you are interested to know what is it all about.

Edited by D4RKON3

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

After spenting some time on it, I have found another way to Subclassing a Window or Control.

Here is the code:

GUICreate('Subclass Test', 450, 200)
$TextBox = GUICtrlCreateInput('Hello world!', 10, 10, 250, 20)
GUISetState()

$hHandle = DllCallbackRegister('MY_SUBCLASSPROC', 'LRESULT', 'HWND;UINT;WPARAM;LPARAM')
If ($hHandle == 0) Then
MsgBox(16, 'Subclass Test', 'Call to DllCallbackRegister failed.')
Exit
EndIf

SetWindowLong(GUICtrlGetHandle($TextBox), -4, DllCallbackGetPtr($hHandle)) ;GWL_WNDPROC = -4
If (@error) Then
MsgBox(16, 'Subclass Test', 'Call to SetWindowLong failed.')
Exit
EndIf

While (True)
Switch (GUIGetMsg())
Case -3 ;GUI_EVENT_CLOSE
;~ Exit ;Calling Exit won't close script, it will remain running in taskbar, eating 1 cpu core.
ProcessClose(@AutoItPID) ;Just a way around
EndSwitch
WEnd

Func MY_SUBCLASSPROC($hWnd, $uMsg, $wParam, $lParam)
ConsoleWrite($uMsg & @CRLF)
EndFunc

Func SetWindowLong($hWnd, $nIndex, $dwNewLong)
Local $lResult = DllCall('User32.dll', 'long', 'SetWindowLong', _
'HWND', $hWnd, _
'int', $nIndex, _
'long', $dwNewLong)
If (@error) Or ($lResult[0] == 0) Then Return SetError(1, 0, 0)

Return SetError(0, 0, 1)
EndFunc

Unfortunately it has the same exact problem as SetWindowSubclass. Notifications of the control are sent to SUBCLASSPROC function but the control gets freezed!

After some search on the forum I found this:

I didn't read the whole thread, but in post #5, Yashied sayd: "No, DllCallbackRegister() kill the script.".

I guess it's the problem here too.

Edit: Reading post #12!

Edited by D4RKON3

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

if you will block the code nothing gonna work

#include <WinAPI.au3>
; Register callback function and obtain handle to _New_WndProc
Global $___hNew_WndProc = DllCallbackRegister("_New_WndProc", "int", "hwnd;uint;wparam;lparam")
; Get pointer to _New_WndProc
Global $___pNew_WndProc = DllCallbackGetPtr($___hNew_WndProc)

GUICreate('Testing - Phoenix XL')
Global $cEdit=GUICtrlCreateEdit('',10,10,100,100)
Global $pOld_WndProc=_Edit_SubClass(GUICtrlGetHandle(-1),$___pNew_WndProc)
GUISetState()

Func _New_WndProc($hWnd, $iMsg, $wParam, $lParam)
; Get the Messages
ConsoleWrite('Msg:'&$iMsg&@CR)
; Pass to the Original Window Procedure.
Return _WinAPI_CallWindowProc($pOld_WndProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_New_WndProc

Func _Edit_SubClass($hWnd, $pNew_WindowProc)
Local $iRes = _WinAPI_SetWindowLong($hWnd, -4, $pNew_WindowProc)
If @error Then Return SetError(1, 0, 0)
If $iRes = 0 Then Return SetError(1, 0, 0)
Return SetError(0, 0, $iRes)
EndFunc   ;==>_Edit_SubClass

While GUIGetMsg()<>-3
Sleep(10)
WEnd

; UnSubClass
_Edit_SubClass(GUICtrlGetHandle($cEdit),$pOld_WndProc)
; Now free UDF created WndProc
DllCallbackFree($___hNew_WndProc)

Exit

Hope so this helps

EDIT: For better understanding have a look at my it uses the same concepts :)

Edited by PhoenixXL

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Thank you, but did you noticed that the ConsoleWrite($uMsg & @CRLF) in the MY_SUBCLASSPROC function doesn't do anything, maybe MY_SUBCLASSPROC doesn't even get called!

nvm, change:

Global $pNewWndProc = DllCallbackRegister('_New_WndProc', 'int', 'HWND;UINT;WPARAM;LPARAM')

To

DllCallbackRegister('MY_SUBCLASSPROC', 'int', 'HWND;UINT;WPARAM;LPARAM')

Edited by D4RKON3

Share this post


Link to post
Share on other sites

But this:

#include 
#include 

GUICreate('Subclass Test', 450, 200)
$TextBox = GUICtrlCreateInput('Hello world!', 10, 10, 250, 20)
Global $pNewWndProc = DllCallbackRegister('MY_SUBCLASSPROC', 'int', 'HWND;UINT;WPARAM;LPARAM')
Global $pOldWndProc = _WinAPI_SetWindowLong(GUICtrlGetHandle(-1), -4, DllCallbackGetPtr($pNewWndProc))
GUISetState()

While True
Switch GUIGetMsg()
Case -3 ;GUI_EVENT_CLOSE
_WinAPI_SetWindowLong(GUICtrlGetHandle($TextBox), -4, $pOldWndProc)
Exit
EndSwitch
WEnd

Func MY_SUBCLASSPROC($hWnd, $uMsg, $wParam, $lParam)
If $uMsg = $EN_CHANGE Then ConsoleWrite('***')

Return _WinAPI_CallWindowProc($pOldWndProc, $hWnd, $uMsg, $wParam, $lParam)
EndFunc

Still doesn't work. Maybe I missed the point.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

looking as if you are beggining into Subclassing

Bro,

EN_CHANGE is a notification code and is posted to Window through WM_COMMAND message

and not to the Window Procedure

All the Best :)

Edited by PhoenixXL

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Hope this helps

#include <WinAPI.au3>

GUICreate('Testing - Phoenix XL')
GUICtrlCreateEdit('',10,10,100,100)
Global $cEdit=GUICtrlGetHandle(-1)
GUIRegisterMsg(0x0111,'WM_COMMAND')
GUISetState()

Func WM_COMMAND($hWnd,$iMsg,$wParam,$lParam)
Local $NotificationCode=_WinAPI_HiWord($wParam)
Switch $lParam
Case $cEdit
Switch $NotificationCode
Case 0x300 ;$EN_CHANGE
ConsoleWrite('EN_CHANGE Encountered'&@CR)
EndSwitch
EndSwitch
Return 'GUI_RUNDEFMSG'
EndFunc

While GUIGetMsg()<>-3
Sleep(10)
WEnd

Edited by PhoenixXL

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

OK then, thank you again.

May I ask about a list of $Msg(s) that can be catch by Subclassing?

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

All the Windows Message Codes are posted to the Window Procedure

Like WM_CHAR, WM_ACTIVATE, WM_KILLFOCUS, WM_#

Have a look at Windows Message Codes [Appendix]

in the Help file

Br,

Phoenix XL

Edited by PhoenixXL

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

A simple example

#include 
; Register callback function and obtain handle to _New_WndProc
Global $___hNew_WndProc = DllCallbackRegister("_New_WndProc", "int", "hwnd;uint;wparam;lparam")
; Get pointer to _New_WndProc
Global $___pNew_WndProc = DllCallbackGetPtr($___hNew_WndProc)

Global $hWnd_=GUICreate('Testing - Phoenix XL')
GUICtrlCreateEdit('',10,10,100,100)
Global $pOld_WndProc=_Edit_SubClass($hWnd_,$___pNew_WndProc)
GUISetState()

Func _New_WndProc($hWnd, $iMsg, $wParam, $lParam)
; Get the Messages
;0x0006 ==> WM_ACTIVATE
if $iMsg=0x0006 Then ConsoleWrite('WM_ACTIVATE Encountered :)'&@CR)
; Pass to the Original Window Procedure.
Return _WinAPI_CallWindowProc($pOld_WndProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc ;==>_New_WndProc

Func _Edit_SubClass($hWnd, $pNew_WindowProc)
Local $iRes = _WinAPI_SetWindowLong($hWnd, -4, $pNew_WindowProc)
If @error Then Return SetError(1, 0, 0)
If $iRes = 0 Then Return SetError(1, 0, 0)
Return SetError(0, 0, $iRes)
EndFunc ;==>_Edit_SubClass

While GUIGetMsg()<>-3
Sleep(10)
WEnd

; UnSubClass
_Edit_SubClass($hWnd_,$pOld_WndProc)
; Now free UDF created WndProc
DllCallbackFree($___hNew_WndProc)

Exit

Here we subclassed the GUI because WM_ACTIVATE is posted to the GUI

and not to the Control(s)

Feel free to ask if you have any Doubts :)


My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Good job, point taken.

Thanks for the time you spent.

BTW, any idea about why Subclass functions in the first post doesn't work?

Edit: Subclassing only work for the window(s) that are created by the process that is calling SetWindowLong, am I right?

Edited by D4RKON3

Share this post


Link to post
Share on other sites

BTW, any idea about why Subclass functions in the first post doesn't work?

yup, You have to return the Value of the Procedure orelse it wont work.

This should work

GUICreate('Subclass Test - Phoenix XL', 450, 200)
GUICtrlCreateInput('Hello world!', 10, 45, 250, 20)
$TextBox = GUICtrlGetHandle(-1)
GUISetState()

$hHandle = DllCallbackGetPtr(DllCallbackRegister('MY_SUBCLASSPROC', 'LRESULT', 'HWND;UINT;WPARAM;LPARAM;UINT_PTR;DWORD_PTR'))
If ($hHandle == 0) Then
MsgBox(16, 'Subclass Test', 'Call to DllCallbackRegister failed.')
Exit
EndIf

SetWindowSubclass($TextBox, $hHandle, 0, 0)
If (@error) Then
MsgBox(16, 'Subclass Test', 'Call to SetWindowSubclass failed.')
Exit
EndIf

While (True)
Switch (GUIGetMsg())
Case -3 ;GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd
RemoveWindowSubclass($TextBox, $hHandle, 0, 0)
Exit

Func MY_SUBCLASSPROC($hWnd, $uMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
ConsoleWrite($uMsg & @CRLF)
Return DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
EndFunc

Func SetWindowSubclass($hWnd, $pfnSubclass, $uIdSubclass, $dwRefData)
Local $bResult = DllCall('Comctl32.dll', 'BOOL', 'SetWindowSubclass', _
'HWND', $hWnd, _
'ptr', $pfnSubclass, _
'UINT_PTR', $uIdSubclass, _
'DWORD_PTR', $dwRefData)
If (@error) Or ($bResult[0] == 0) Then Return SetError(1, 0, 0)
Return SetError(0, 0, 1)
EndFunc

Func GetWindowSubclass($hWnd, $pfnSubclass, $uIdSubclass, ByRef $dwRefData)
Local $bResult = DllCall('Comctl32.dll', 'BOOL', 'GetWindowSubclass', _
'HWND', $hWnd, _
'ptr', $pfnSubclass, _
'UINT_PTR', $uIdSubclass, _
'DWORD_PTR*', 0)
If (@error) Or ($bResult[0] == 0) Then Return SetError(1, 0, 0)
$dwRefData = $bResult[4]
Return SetError(0, 0, 1)
EndFunc

Func RemoveWindowSubclass($hWnd, $pfnSubclass, $uIdSubclass, $dwRefData)
Local $bResult = DllCall('Comctl32.dll', 'BOOL', 'RemoveWindowSubclass', _
'HWND', $hWnd, _
'ptr', $pfnSubclass, _
'UINT_PTR', $uIdSubclass)
If (@error) Or ($bResult[0] == 0) Then Return SetError(1, 0, 0)
Return SetError(0, 0, 1)
EndFunc

Func DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
Local $aRet=DllCall('Comctl32.dll', 'LRESULT', 'DefSubclassProc', _
'HWND', $hWnd, _
'UINT', $uMsg, _
'WPARAM', $wParam, _
'LPARAM', $lParam)
Return $aRet[0]
EndFunc
1 person likes this

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites

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
Sign in to follow this  
Followers 0