# Visual Basic > Visual Basic 6 and Earlier >  [RESOLVED] How to disable a form's "Move", "Resize", and "Maximize" dynamically

## Elroy

I'm still tweaking on my GIF screen capture work.

And one problem it has is, when it's in its capture loop, I need to disable the main form's non-client stuff.  The way it is, it disrupts the capture timing if you start dragging the form around.

I'd like to disable it in a way that it can be re-enabled once the capture loop is finished.

While I'm waiting on y'all's ideas, I'll play around with monitoring the WM_??? messages coming through the form's message pump, and see if I can figure it out.

----------


## VanGoghGaming

There's already a recent thread about this: https://www.vbforums.com/showthread....nd-a-solution)

You could also hide the form or minimize it during the screen capture.

----------


## baka

my "screenrecorder" is an external exe that I control using sendmessage.
so its formless. I use a key (print screen) to start/stop the recording.
when recording, a "red" rectangle is shown around the "hdc" and when its saving it show "yellow" so the user notice something is going on.
now, the screenrecorder is taking my own picturebox inside my form, but it could easily take anything with a hdc.

if I where u, I would create a screenrecorder that would:
- [start] button, will place the program in traybar. 
- theres options in the program "how to" start. "delayed start", "key", "mouse click" etc.
- theres also option "what" to take. whole screen, rectangle, a specific hwnd, a specific hdc, picker mode.
- the "picker mode" is used to check the screen if its possible to get its hwnd/hdc/rect.

so, not sure what U mean by disable forms resize etc. the importance is to remove everything in the way if u want to record something. the form should not be visible at all.

----------


## Elroy

> You could also hide the form or minimize it during the screen capture.


I'd prefer not to do that, as the "Stop Capture" button is on the form.  So I can't disable it either.

----------


## VanGoghGaming

Another idea would be to register some global hotkeys to manage the screen capture.

----------


## Elroy

It turned out to not be too bad.

Here's some code I put into a *BAS module* to do a bit of subclassing:



```

Option Explicit
'
Private bSetWhenSubclassing_UsedByIdeStop As Boolean    ' Never goes false once set by first subclassing, unless IDE Stop button is clicked.
Private Const WM_DESTROY                As Long = &H2&  ' All other needed constants are declared within the procedures.
'
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 GetWindowSubclass Lib "comctl32.dll" Alias "#411" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, pdwRefData 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 NextSubclassProcOnChain Lib "comctl32.dll" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'


Public Sub DisableNonClientActions(frm As Form)
    SubclassSomeWindow frm.hWnd, AddressOf DisableNonClientActions_Proc
End Sub

Public Sub EnableNonClientActions(frm As Form)
    UnSubclassSomeWindow frm.hWnd, AddressOf DisableNonClientActions_Proc
End Sub



Private Function DisableNonClientActions_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
    If uMsg = WM_DESTROY Then
        UnSubclassSomeWindow hWnd, AddressOf_DisableNonClientActions_Proc, uIdSubclass
        DisableNonClientActions_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
        Exit Function
    End If
    If IdeStopButtonClicked Then ' Protect the IDE.  Don't execute any specific stuff if we're stopping.  We may run into COM objects or other variables that no longer exist.
        DisableNonClientActions_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
        Exit Function
    End If
    '
    Const WM_NCLBUTTONDOWN  As Long = 161&
    Const WM_NCRBUTTONDOWN  As Long = 164&
    Const WM_SYSCOMMAND     As Long = 274&
    Select Case uMsg
    Case WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_SYSCOMMAND
        Exit Function
    End Select
    '
    DisableNonClientActions_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
End Function

Private Function AddressOf_DisableNonClientActions_Proc() As Long
    AddressOf_DisableNonClientActions_Proc = ProcedureAddress(AddressOf DisableNonClientActions_Proc)
End Function



```

And this also goes into the above *BAS module*.  I neglected to include it when I originally made this post.



```


Private Sub SubclassSomeWindow(hWnd As Long, AddressOf_ProcToSubclass As Long, Optional dwRefData As Long, Optional uIdSubclass As Long)
    If uIdSubclass = 0& Then uIdSubclass = hWnd
    bSetWhenSubclassing_UsedByIdeStop = True
    Call SetWindowSubclass(hWnd, AddressOf_ProcToSubclass, uIdSubclass, dwRefData)
End Sub

Private Sub UnSubclassSomeWindow(hWnd As Long, AddressOf_ProcToSubclass As Long, Optional uIdSubclass As Long)
    If uIdSubclass = 0& Then uIdSubclass = hWnd
    Call RemoveWindowSubclass(hWnd, AddressOf_ProcToSubclass, uIdSubclass)
End Sub

Private Function ProcedureAddress(AddressOf_TheProc As Long) As Long
    ProcedureAddress = AddressOf_TheProc
End Function

Private Function IdeStopButtonClicked() As Boolean
    IdeStopButtonClicked = Not bSetWhenSubclassing_UsedByIdeStop
End Function


```


And here's code for a* Form1* to test:



```

Option Explicit
Dim bCancel As Boolean

Private Sub Form_Activate()
    DisableNonClientActions Me
    Do
        DoEvents
        Debug.Print Rnd;
        If bCancel Then Exit Do
    Loop
End Sub

Private Sub Form_Click()
    EnableNonClientActions Me
    bCancel = True
End Sub


```

When DisableNonClientActions is called, you can't do anything (resize, maximize, minimize, move) which is exactly what I wanted.

I did the loop to illustrate that we're not interrupting a running loop, which is perfect.

----------


## VanGoghGaming

I haven't played much with subclassing (beside some basic tests to see how it works) but I've always thought it was done by calling "SetWindowLong" and changing the default window procedure to one of your own defined in a module...

Looking at your code I never knew these different subclassing functions even existed! Checking out their MSDN page (https://learn.microsoft.com/en-us/wi...l-subclassproc), this tidbit caught my eye:

_dwRefData

Type: DWORD_PTR

The reference data provided to the SetWindowSubclass function. This can be used to associate the subclass instance with a "this" pointer._

If I'm reading it correctly this means you could (in theory) implement a "subclassing interface class" (for lack of a better word) and then subclass a form as well as all the controls on that form under the same window procedure without having to clog up a ".bas" module with lots of WndProcs. This should open up a whole new world of possibilities.

----------


## Elroy

I often put the ObjPtr of the form I'm subclassing into dwRefData.  Having done that, I can get back to the form's VB6 object within the subclassing procedure, all without any need for global (or module level) variables.  And yeah, this allows me to use one subclassing call to simultaneously subclass as many forms as I like.

And the same ideas hold for controls as well.  Yes, that dwRefData is quite useful.  They're not in the above, but I also have procedures for using ComCtl32 subclassing to store extra tidbits of dwRefData under a single call to subclass something.

In my primary project (with 100s of forms and modules), I do quite a bit of subclassing, and don't carry a single global (or module level) variable at all.

ALSO:  I neglected to include everything for the BAS module in post #6, but I've now added the rest of the code for it.

----------


## Elroy

And here, this code isn't "complete", but it shows an example of how I might use the dwRefData.



```

Private Declare Function vbaObjSetAddref Lib "msvbvm60" Alias "__vbaObjSetAddref" (ByRef dstObject As Any, ByRef srcObjPtr As Any) As Long


Public Sub SubclassToDetectMoves(frm As VB.Form)
    SubclassSomeWindow frm.hWnd, AddressOf ToDetectMoves_Proc, ObjPtr(frm)
End Sub

Private Function ToDetectMoves_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
    If uMsg = WM_DESTROY Then
        UnSubclassSomeWindow hWnd, AddressOf_ToDetectMoves_Proc, uIdSubclass
        ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
        Exit Function
    End If
    If IdeStopButtonClicked Then    ' Protect the IDE.  Don't execute any specific stuff if we're stopping.  We may run into COM objects or other variables that no longer exist.
        ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
        Exit Function
    End If
    '
    Const WM_WINDOWPOSCHANGED   As Long = 71&
    Dim frm As VB.Form
    '
    If uMsg = WM_WINDOWPOSCHANGED Then
        On Error Resume Next
            Set frm = FormObjectFromPtr(dwRefData)
            frm.Form_Moved          ' MUST be Public (not Friend) to find it from here.
        On Error GoTo 0
    End If
    '
    ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
End Function

Private Function FormObjectFromPtr(ByVal Ptr As Long) As VB.Form
    vbaObjSetAddref FormObjectFromPtr, ByVal Ptr
End Function


```

I can simultaneously do this to as many forms as I like, all using the same subclassing procedure, and they won't ever interfere with each other.

----------


## Elroy

And I don't refer to them much anymore, but here are some notes I wrote when initially figuring out ComCtl32 subclassing:




> ' Notes on subclassing with Comctl32.DLL:
> '
> '   1.  A subclassed function will get executed even AFTER the IDE "Stop" button is pressed.
> '       This gives us an opportunity to un-subclass everything if things are done correctly.
> '       Things that will still crash the IDE:
> '
> '       *   Executing the "END" statement in code.
> '       *   Clicking IDE "Stop" on modal form loaded after something else is subclassed.
> '       *   Clicking the "End" button after a runtime error on the "End", "Debug", "Help" form.
> ...

----------


## VanGoghGaming

It seems you like to take the "procedural" programming style to a whole new level!  :Stick Out Tongue:  I was thinking of a more "object-oriented" style using "Implements" with a subclassing interface. It should make the code more readable and easier to maintain. On the bright side, I learned of yet another new function from you, "vbaObjSetAddref"!  :Smilie:

----------


## Elroy

> It seems you like to take the "procedural" programming style to a whole new level!  I was thinking of a more "object-oriented" style using "Implements" with a subclassing interface. It should make the code more readable and easier to maintain. On the bright side, I learned of yet another new function from you, "vbaObjSetAddref"!


Ohh, I can definitely go either way.  As an example, here's where I sorted how to do callbacks (including subclassing) wholly contained within an object (with no need for a BAS stub).

I'm certainly not one of those who wants/needs for everything to be in classes though.  When it works, a regular ole BAS module is just fine, and they're also a bit faster and more compiler efficient than class modules (which is everything but a BAS module).

Ohhh, and just an FYI.  That vbaObjSetAddref works with _any_ object pointer, not just form pointers.

----------


## VanGoghGaming

> That vbaObjSetAddref works with _any_ object pointer, not just form pointers.


I'm sure it does but I can't see a scenario where you'd want to use such a function, maybe it's needed in VBA, I wouldn't know... Even in your example, if you declared _dwRefData as Any_ then it should work with object types out of the box without the need to use this additional function...

----------

