r1gga
asked on
BIZARE: ***MDI Maximize button disabled but not for long***
Hello,
I have an MDI with many MDI children, I can disable the maximize button and several other of the MDI's features using the following code:
Option Explicit
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, _
ByVal wFlags As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Const MF_BYPOSITION = &H400&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MINIMIZEBOX = &H20000
Const WS_MAXIMIZEBOX = &H10000
Const WS_SYSMENU = &H80000
Private Sub RemoveMenus()
Dim hMenu As Long
' Get the form's system menu handle.
hMenu = GetSystemMenu(hWnd, False)
DeleteMenu hMenu, 6, MF_BYPOSITION 'Disables X Button
DeleteMenu hMenu, 5, MF_BYPOSITION 'Removes Form Seperator
DeleteMenu hMenu, 4, MF_BYPOSITION 'Disables Maximize Button
DeleteMenu hMenu, 2, MF_BYPOSITION 'Disables Resizing
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
End Sub
Private Sub MDIForm_Load()
RemoveMenus
formLogin.Show
End Sub
If I comment out the loading of the first form "formLogin" which is an MDIchild then the code works perfectly with maximize greyed out and a thin border on the MDI.
If formLogin.show is not commented out then the sysmenu changes remain i.e. they do not appear in the sysmenu, however the maximize button is not greyed and under windows XP is usable and the border of the MDI becomes thick. How do I fix this.
Thanks in Advance
r1gga
I have an MDI with many MDI children, I can disable the maximize button and several other of the MDI's features using the following code:
Option Explicit
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, _
ByVal wFlags As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Const MF_BYPOSITION = &H400&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MINIMIZEBOX = &H20000
Const WS_MAXIMIZEBOX = &H10000
Const WS_SYSMENU = &H80000
Private Sub RemoveMenus()
Dim hMenu As Long
' Get the form's system menu handle.
hMenu = GetSystemMenu(hWnd, False)
DeleteMenu hMenu, 6, MF_BYPOSITION 'Disables X Button
DeleteMenu hMenu, 5, MF_BYPOSITION 'Removes Form Seperator
DeleteMenu hMenu, 4, MF_BYPOSITION 'Disables Maximize Button
DeleteMenu hMenu, 2, MF_BYPOSITION 'Disables Resizing
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
End Sub
Private Sub MDIForm_Load()
RemoveMenus
formLogin.Show
End Sub
If I comment out the loading of the first form "formLogin" which is an MDIchild then the code works perfectly with maximize greyed out and a thin border on the MDI.
If formLogin.show is not commented out then the sysmenu changes remain i.e. they do not appear in the sysmenu, however the maximize button is not greyed and under windows XP is usable and the border of the MDI becomes thick. How do I fix this.
Thanks in Advance
r1gga
Soory just noticed
but not for long
So it does work for a short period
but not for long
So it does work for a short period
could try simply allowing the form to load and then using a timer to remove the frmmenus and then show frm login, that way the form gets drawn.
e.g.
Private Sub MDIForm_Load()
Timer1.Interval = 100
Timer1.enabled = true
End Sub
Private Sub Timer1_Timer()
timer1.enabled = false
RemoveMenus
formLogin.Show
end sub
e.g.
Private Sub MDIForm_Load()
Timer1.Interval = 100
Timer1.enabled = true
End Sub
Private Sub Timer1_Timer()
timer1.enabled = false
RemoveMenus
formLogin.Show
end sub
ASKER
Sorry I forgot to mention, I can achieve the desired effect through use of a timer, however I seek something more reliable as the timer can be beaten if the user clicks fast enough leaving the user with a maximized window that can then not be resized as the timer has occured. My timer code is:
Private Sub Timer1_Timer()
RemoveMenus
End Sub
Private Sub Timer1_Timer()
RemoveMenus
End Sub
Can you load the MDIForm with its .Visible = false, then in the timer you can show it, that way the user can never beat your timer, as they cannot see the form.
ASKER
The thing is I am looking for a more gneric solution, as this method method may allow formLogin to be displayed but then after that when formMain is displayed the same problem occurs.
Thanks r1gga
Thanks r1gga
Hi okay, i think I figured it out, justt re-read your code
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
After calling SetWindowLong, you need to redraw the window, so add these lines:
swpFlags = SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER
SetWindowPos(Me.Hwnd,0,0,0 ,0,0,swpFl ags)
Now you will notice that your remove menu function call will work properly.
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
After calling SetWindowLong, you need to redraw the window, so add these lines:
swpFlags = SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER
SetWindowPos(Me.Hwnd,0,0,0
Now you will notice that your remove menu function call will work properly.
ASKER
The thing is I am looking for a more gneric solution, as this method method may allow formLogin to be displayed but then after that when formMain is displayed the same problem occurs.
Thanks r1gga
Thanks r1gga
ASKER
I get variable not defined SWP_Framechanged
Thanks
r1gga
Thanks
r1gga
Private Const SWP_FRAMCHANGED = &H20
SWP_NOMOVE = &H2
SWP_NOSIZE = &H1
SWP_NOZORDER = &H4
And the SetWindowPos is defined in user32
SWP_NOMOVE = &H2
SWP_NOSIZE = &H1
SWP_NOZORDER = &H4
And the SetWindowPos is defined in user32
ASKER
I get variable not defined SWP_Framechanged
Thanks
r1gga
Thanks
r1gga
ASKER
sorry I pressed refresh on an old window ignor ethe last post
ASKER
setwindowpos is not a valid function i.e. it appears in red.
Have u tried this out?
Have u tried this out?
err its an API u have to declare it as :
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
ASKER
The only effect your code has is to refresh the image of the maximize button, which is useful but only in conjunction with a timer that executes the function removemenus(). Here is the code as it stands with your modification:
Option Explicit
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, _
ByVal wFlags As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Const MF_BYPOSITION = &H400&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MINIMIZEBOX = &H20000
Const WS_MAXIMIZEBOX = &H10000
Const WS_SYSMENU = &H80000
Const SWP_FRAMECHANGED = &H20
Const SWP_NOMOVE = &H2
Const SWP_NOSIZE = &H1
Const SWP_NOZORDER = &H4
Private Sub RemoveMenus()
Dim hMenu As Long
' Get the form's system menu handle.
hMenu = GetSystemMenu(hWnd, False)
DeleteMenu hMenu, 6, MF_BYPOSITION 'Disables X Button
DeleteMenu hMenu, 5, MF_BYPOSITION 'Removes Form Seperator
DeleteMenu hMenu, 4, MF_BYPOSITION 'Disables Maximize Button
DeleteMenu hMenu, 2, MF_BYPOSITION 'Disables Resizing
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
L = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER
L = SetWindowPos(Me.hWnd, 0, 0, 0, 0, 0, L)
End Sub
Private Sub MDIForm_Load()
formLogin.Show
RemoveMenus
End Sub
If you create a mockup mdi which has an intial mdi child that is replaced post-loading by on screen button clicks then you will better be able to visualise the problem. As the code stands the maximize button is ok initially but as soon as another form is loaded it becomes usable again.
Thanks for your help
r1gga
Option Explicit
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, _
ByVal wFlags As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Const MF_BYPOSITION = &H400&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MINIMIZEBOX = &H20000
Const WS_MAXIMIZEBOX = &H10000
Const WS_SYSMENU = &H80000
Const SWP_FRAMECHANGED = &H20
Const SWP_NOMOVE = &H2
Const SWP_NOSIZE = &H1
Const SWP_NOZORDER = &H4
Private Sub RemoveMenus()
Dim hMenu As Long
' Get the form's system menu handle.
hMenu = GetSystemMenu(hWnd, False)
DeleteMenu hMenu, 6, MF_BYPOSITION 'Disables X Button
DeleteMenu hMenu, 5, MF_BYPOSITION 'Removes Form Seperator
DeleteMenu hMenu, 4, MF_BYPOSITION 'Disables Maximize Button
DeleteMenu hMenu, 2, MF_BYPOSITION 'Disables Resizing
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
L = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER
L = SetWindowPos(Me.hWnd, 0, 0, 0, 0, 0, L)
End Sub
Private Sub MDIForm_Load()
formLogin.Show
RemoveMenus
End Sub
If you create a mockup mdi which has an intial mdi child that is replaced post-loading by on screen button clicks then you will better be able to visualise the problem. As the code stands the maximize button is ok initially but as soon as another form is loaded it becomes usable again.
Thanks for your help
r1gga
ASKER
So a simplification of my problem is that I need the changes to the MDI window to remain when MDI children are loaded
Hi, what I suggest you do is rather than use the DeleteMenu api is use the following code to handle your management of the form buttons. For a demo, simply create a new project add a form1 and MDIForm. Now in the MDI form paste the following code:
Option Explicit
Private Const SWP_HIDEWINDOW = &H80
Private Const SWP_NOACTIVATE = &H10
Private Const SWP_NOCOPYBITS = &H100
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOOWNERZORDER = &H200 ' Don't do owner Z ordering
Private Const SWP_NOREDRAW = &H8
Private Const SWP_NOREPOSITION = SWP_NOOWNERZORDER
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOZORDER = &H4
Private Const SWP_SHOWWINDOW = &H40
Private Const SWP_NOSENDCHANGING = &H400
Private Const SWP_FRAMECHANGED = &H20
Private swpFlags As Long
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const HWND_BOTTOM = 1
Private Const HWND_TOP = 0
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const GWL_HWNDPARENT = -8
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
' Used to get window style bits.
Private Const GWL_STYLE = (-16)
Private Const GWL_EXSTYLE = (-20)
' Style bits.
Public Enum WindowStyleBits
WS_MAXIMIZEBOX = &H10000
WS_MINIMIZEBOX = &H20000
WS_THICKFRAME = &H40000
WS_SYSMENU = &H80000
WS_CAPTION = &HC00000
End Enum
Public Sub FormAPIs_ChangeWindowAppea rance(hWnd As Long, WindowAppearanceProperty As WindowStyleBits, IsVisible As Boolean)
10 Dim lStyle As Long
' Retrieve current style bits.
20 lStyle = GetWindowLong(hWnd, GWL_STYLE)
' Set requested bit On or Off and Redraw.
60 If IsVisible = True Then
70 lStyle = lStyle Or WindowAppearanceProperty
80 Else
90 lStyle = lStyle And Not WindowAppearanceProperty
100 End If
Call SetWindowLong(hWnd, GWL_STYLE, lStyle)
' Redraw window with new style.
140 swpFlags = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOSIZE
Call SetWindowPos(hWnd, 0, 0, 0, 0, 0, swpFlags)
End Sub
Private Sub MDIForm_Load()
Call FormAPIs_ChangeWindowAppea rance(Me.h Wnd, WS_MAXIMIZEBOX, False)
End Sub
Private Sub mnuNewForm_Click()
Form1.Show
End Sub
You can ignore the line numbers, the code is cut from another project that uses line number error handling. Okay after you paste the code, use the Menu Editor and create a menu option called mnuNewForm. So when you click it it will launch the Form1. You will notice that the MDIForm does not change the maximise enabled.
The only way that the Maximise button would get re-enabled, is if somewhere in your code, it is redrawing the menu from another API call you are using. I have been using this method to block form button user menus for ages and never had the problem you are describing.
You can also use the FormAPIs_ChangeWindowAppea rance function to change the style of the other buttons. Give it a try and let me know.
Option Explicit
Private Const SWP_HIDEWINDOW = &H80
Private Const SWP_NOACTIVATE = &H10
Private Const SWP_NOCOPYBITS = &H100
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOOWNERZORDER = &H200 ' Don't do owner Z ordering
Private Const SWP_NOREDRAW = &H8
Private Const SWP_NOREPOSITION = SWP_NOOWNERZORDER
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOZORDER = &H4
Private Const SWP_SHOWWINDOW = &H40
Private Const SWP_NOSENDCHANGING = &H400
Private Const SWP_FRAMECHANGED = &H20
Private swpFlags As Long
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const HWND_BOTTOM = 1
Private Const HWND_TOP = 0
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const GWL_HWNDPARENT = -8
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
' Used to get window style bits.
Private Const GWL_STYLE = (-16)
Private Const GWL_EXSTYLE = (-20)
' Style bits.
Public Enum WindowStyleBits
WS_MAXIMIZEBOX = &H10000
WS_MINIMIZEBOX = &H20000
WS_THICKFRAME = &H40000
WS_SYSMENU = &H80000
WS_CAPTION = &HC00000
End Enum
Public Sub FormAPIs_ChangeWindowAppea
10 Dim lStyle As Long
' Retrieve current style bits.
20 lStyle = GetWindowLong(hWnd, GWL_STYLE)
' Set requested bit On or Off and Redraw.
60 If IsVisible = True Then
70 lStyle = lStyle Or WindowAppearanceProperty
80 Else
90 lStyle = lStyle And Not WindowAppearanceProperty
100 End If
Call SetWindowLong(hWnd, GWL_STYLE, lStyle)
' Redraw window with new style.
140 swpFlags = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOSIZE
Call SetWindowPos(hWnd, 0, 0, 0, 0, 0, swpFlags)
End Sub
Private Sub MDIForm_Load()
Call FormAPIs_ChangeWindowAppea
End Sub
Private Sub mnuNewForm_Click()
Form1.Show
End Sub
You can ignore the line numbers, the code is cut from another project that uses line number error handling. Okay after you paste the code, use the Menu Editor and create a menu option called mnuNewForm. So when you click it it will launch the Form1. You will notice that the MDIForm does not change the maximise enabled.
The only way that the Maximise button would get re-enabled, is if somewhere in your code, it is redrawing the menu from another API call you are using. I have been using this method to block form button user menus for ages and never had the problem you are describing.
You can also use the FormAPIs_ChangeWindowAppea
Also just read in MSDN that you have to use DrawMenuBar API after calling DeleteMenu, to see the changes, so I am assuming that when you call SetWindowLong, it is redrawing the window, but not permanently setting the buttons. So when you load the other form, the MDI is being told to refresh, and it just goes back to the original menu setup as you never called DrawMenuBar?
Well thats just a guess.
Well thats just a guess.
ASKER
You're a great help rainUK, I have discovered why the problem I am experiencing is occuring. On every single one of my MDI Child forms I have the following code:
Private Sub Form_Load()
' Set Window Caption
mdiMain.Caption = Me.Caption
End Sub
And this is what is refreshing the window. So my code should have worked from the outset if only I had omitted the reference to the MDI's caption. This said how do I go about changing the MDI's caption without experiencing the same problem?
Thanks r1gga
Private Sub Form_Load()
' Set Window Caption
mdiMain.Caption = Me.Caption
End Sub
And this is what is refreshing the window. So my code should have worked from the outset if only I had omitted the reference to the MDI's caption. This said how do I go about changing the MDI's caption without experiencing the same problem?
Thanks r1gga
ASKER
Sorry just read your post on MSDN, so could you please give me the code to define the API Draw Menubar and also call it. This should enable me to alter the caption without re-enabling the maximize button right?
Thanks
r1gga
Thanks
r1gga
Hi R1gga,
Just read MSDN again and I am sure that you not calling DrawMenuBar is not persisting the changes, so here is a proper example of using the APIs. So after you call DrawMenuBar you should not need to change any other code, as the change in caption should not affect the new window style.
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Const MF_BYPOSITION = &H400&
Const MF_REMOVE = &H1000&
Private Sub Form_Load()
Dim hSysMenu As Long, nCnt As Long
' Get handle to our form's system menu
' (Restore, Maximize, Move, close etc.)
hSysMenu = GetSystemMenu(Me.hwnd, False)
If hSysMenu Then
' Get System menu's menu count
nCnt = GetMenuItemCount(hSysMenu)
If nCnt Then
' Menu count is based on 0 (0, 1, 2, 3...)
RemoveMenu hSysMenu, nCnt - 1, MF_BYPOSITION Or MF_REMOVE
RemoveMenu hSysMenu, nCnt - 2, MF_BYPOSITION Or MF_REMOVE ' Remove the seperator
DrawMenuBar Me.hwnd
' Force caption bar's refresh. Disabling X button
Me.Caption = "Try to close me!"
End If
End If
End Sub
Just read MSDN again and I am sure that you not calling DrawMenuBar is not persisting the changes, so here is a proper example of using the APIs. So after you call DrawMenuBar you should not need to change any other code, as the change in caption should not affect the new window style.
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Const MF_BYPOSITION = &H400&
Const MF_REMOVE = &H1000&
Private Sub Form_Load()
Dim hSysMenu As Long, nCnt As Long
' Get handle to our form's system menu
' (Restore, Maximize, Move, close etc.)
hSysMenu = GetSystemMenu(Me.hwnd, False)
If hSysMenu Then
' Get System menu's menu count
nCnt = GetMenuItemCount(hSysMenu)
If nCnt Then
' Menu count is based on 0 (0, 1, 2, 3...)
RemoveMenu hSysMenu, nCnt - 1, MF_BYPOSITION Or MF_REMOVE
RemoveMenu hSysMenu, nCnt - 2, MF_BYPOSITION Or MF_REMOVE ' Remove the seperator
DrawMenuBar Me.hwnd
' Force caption bar's refresh. Disabling X button
Me.Caption = "Try to close me!"
End If
End If
End Sub
ASKER
Okay I have implemented draw menu bar as follows but the problem is still there, it only occurs when the mdiMain.Caption command is used, without this command it is okay:
Option Explicit
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Const MF_BYPOSITION = &H400&
Const MF_REMOVE = &H1000&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MAXIMIZEBOX = &H10000
Private Sub RemoveMenus()
Dim hSysMenu As Long
' Get handle to our form's system menu
' (Restore, Maximize, Move, close etc.)
hSysMenu = GetSystemMenu(Me.hWnd, False)
' Menu count is based on 0 (0, 1, 2, 3...)
RemoveMenu hSysMenu, 6, MF_BYPOSITION Or MF_REMOVE ' Removes Close
RemoveMenu hSysMenu, 5, MF_BYPOSITION Or MF_REMOVE ' Remove the seperator
RemoveMenu hSysMenu, 4, MF_BYPOSITION Or MF_REMOVE ' Removes Maximize
RemoveMenu hSysMenu, 2, MF_BYPOSITION Or MF_REMOVE ' Removes Resize
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
' Force caption bar's refresh. Disabling X button
DrawMenuBar Me.hWnd
Me.Caption = "Try to close me!"
End Sub
Private Sub MDIForm_Load()
RemoveMenus
End Sub
If you have access to VB could u try this out?
Option Explicit
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Const MF_BYPOSITION = &H400&
Const MF_REMOVE = &H1000&
Const GWL_STYLE = (-16)
Const WS_THICKFRAME = &H40000
Const WS_MAXIMIZEBOX = &H10000
Private Sub RemoveMenus()
Dim hSysMenu As Long
' Get handle to our form's system menu
' (Restore, Maximize, Move, close etc.)
hSysMenu = GetSystemMenu(Me.hWnd, False)
' Menu count is based on 0 (0, 1, 2, 3...)
RemoveMenu hSysMenu, 6, MF_BYPOSITION Or MF_REMOVE ' Removes Close
RemoveMenu hSysMenu, 5, MF_BYPOSITION Or MF_REMOVE ' Remove the seperator
RemoveMenu hSysMenu, 4, MF_BYPOSITION Or MF_REMOVE ' Removes Maximize
RemoveMenu hSysMenu, 2, MF_BYPOSITION Or MF_REMOVE ' Removes Resize
' Grey out form's Maximize Button and use thin frame
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
' Force caption bar's refresh. Disabling X button
DrawMenuBar Me.hWnd
Me.Caption = "Try to close me!"
End Sub
Private Sub MDIForm_Load()
RemoveMenus
End Sub
If you have access to VB could u try this out?
ASKER
so in short calling:
Me.Caption = "Try to Close me!"
Undoes the greying out of the maximise button (Not the close button) and also undoes the thick border.
None of the SysMenu changes are lost so with or without drawmenubar follow the removemenu API, the changes that are lost are from the following code:
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
Any clues?
Thanks r1gga
Me.Caption = "Try to Close me!"
Undoes the greying out of the maximise button (Not the close button) and also undoes the thick border.
None of the SysMenu changes are lost so with or without drawmenubar follow the removemenu API, the changes that are lost are from the following code:
Dim L As Long
L = GetWindowLong(Me.hWnd, GWL_STYLE)
L = L And Not (WS_MAXIMIZEBOX)
L = L And Not (WS_THICKFRAME)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
Any clues?
Thanks r1gga
give me 30 mins, I'll just try your code
ASKER
MSDN says:
"IF using SetWindowLong then SetWindPos must be used after this"
"IF using SetWindowLong then SetWindPos must be used after this"
yes thats right, but I just tried your code, the thing is, that you set the caption while the form is in its form loading routine, this is causing it to redraw for some reason, because if I take that out and change the caption from any other sub or form it is okay.
actually thats a lie, sorry lol
I just tried it and you are right it redraws
I just tried it and you are right it redraws
ASKER
yeah I tried implementing the Set window Pos as follows but to no avail! Is it just me or does this not make sense?
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
' Force caption bar's refresh. Disabling X button
DrawMenuBar Me.hWnd
L = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER
L = SetWindowPos(Me.hWnd, 0, 0, 0, 0, 0, L)
L = SetWindowLong(Me.hWnd, GWL_STYLE, L)
' Force caption bar's refresh. Disabling X button
DrawMenuBar Me.hWnd
L = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER
L = SetWindowPos(Me.hWnd, 0, 0, 0, 0, 0, L)
actually thats a lie, sorry lol
I just tried it and you are right it redraws
I just tried it and you are right it redraws
actually thats a lie, sorry lol
I just tried it and you are right it redraws
I just tried it and you are right it redraws
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I'm going to remove the reference to the MDI's caption, but hey thats life having to work around visual basics problems rather than visual basic working around my problems.
Anyway thanks for your help and your quick posts.
r1gga
Anyway thanks for your help and your quick posts.
r1gga
ASKER
SOrry about the C but there was no real solution reached just a compromise
glad to help, its not the grade or points, but getting your code to work the way you need it to
RemoveMenus
formLogin.Show
Also does the MDI form draw properly after the formLogin has been displayed?
And finally does formLogin need to be an MDI child.