En-/Disable Window Min, Max & Close Buttons

Share your advanced PureBasic knowledge/code with the community.
User avatar
nco2k
Addict
Addict
Posts: 1344
Joined: Mon Sep 15, 2003 5:55 am

En-/Disable Window Min, Max & Close Buttons

Post by nco2k »

Code updated for 5.20+

hi folks,

i just searched the forums for something like this, but i have only found a way to (completely) remove the close menu-item, but not to disable (and gray) it or maybe i didn't searched long enough. :P

however, i did a quick research on msdn and here is the result:

Code: Select all

Procedure SetWindowCloseButton(hWnd, Enabled)
  If hWnd And (Enabled = #True Or Enabled = #False)
    hSysMenu = GetSystemMenu_(hWnd, #False)
    If hSysMenu
      EnableMenuItem_(hSysMenu, #SC_CLOSE, #MF_BYCOMMAND | Enabled ! 1)
      DrawMenuBar_(hWnd)
    EndIf
  EndIf
EndProcedure

Enumeration
  #GadgetButton_DisableCloseBox
  #GadgetButton_Exit
EndEnumeration

If OpenWindow(0, 0, 0, 200, 95, "Disable Window Close Box - Example", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
  ButtonGadget(#GadgetButton_DisableCloseBox, 5, 10, 190, 25, "Disable Close Box", #PB_Button_Toggle)
  ButtonGadget(#GadgetButton_Exit, 5, 60, 190, 25, "Exit")
  AddKeyboardShortcut(0, #PB_Shortcut_Alt | #PB_Shortcut_F4, 0)
 
  Repeat
    WinEvent = WaitWindowEvent()
    If WinEvent = #PB_Event_Gadget
      Select EventGadget()
        Case #GadgetButton_DisableCloseBox
          SetWindowCloseButton(WindowID(0), GetGadgetState(#GadgetButton_DisableCloseBox) ! 1)
        Case #GadgetButton_Exit
          If GetGadgetState(#GadgetButton_DisableCloseBox) = 0
            End
          EndIf
      EndSelect
    ElseIf WinEvent = #PB_Event_Menu And EventMenu() = 0
      If GetGadgetState(#GadgetButton_DisableCloseBox) = 0
        End
      EndIf
    EndIf
  Until WinEvent = #PB_Event_CloseWindow
EndIf

End
i hope it will become usefull for you guys. have fun. :wink:

// EDIT:

i have put now everything in procedures:

Code: Select all

Procedure SetWindowMinButton(hWnd.l, Enabled.l)
  If (Enabled = #True Or Enabled = #False) And hWnd
    nWindowLong.l = GetWindowLong_(hWnd, #GWL_STYLE)
    If nWindowLong
      If Enabled = #True
        SetWindowLong_(hWnd, #GWL_STYLE, nWindowLong | #WS_MINIMIZEBOX)
      ElseIf Enabled = #False
        SetWindowLong_(hWnd, #GWL_STYLE, nWindowLong & (#WS_MINIMIZEBOX ! - 1))
      EndIf
      SetWindowPos_(hWnd, 0, 0, 0, 0, 0, #SWP_NOZORDER | #SWP_NOMOVE | #SWP_NOSIZE | #SWP_FRAMECHANGED)
    EndIf
  EndIf
EndProcedure

Procedure SetWindowMaxButton(hWnd.l, Enabled.l)
  If (Enabled = #True Or Enabled = #False) And hWnd
    nWindowLong.l = GetWindowLong_(hWnd, #GWL_STYLE)
    If nWindowLong
      If Enabled = #True
        SetWindowLong_(hWnd, #GWL_STYLE, nWindowLong | #WS_MAXIMIZEBOX)
      ElseIf Enabled = #False
        SetWindowLong_(hWnd, #GWL_STYLE, nWindowLong & (#WS_MAXIMIZEBOX ! - 1))
      EndIf
      SetWindowPos_(hWnd, 0, 0, 0, 0, 0, #SWP_NOZORDER | #SWP_NOMOVE | #SWP_NOSIZE | #SWP_FRAMECHANGED)
    EndIf
  EndIf
EndProcedure

Procedure SetWindowCloseButton(hWnd.l, Enabled.l)
  If (Enabled = #True Or Enabled = #False) And hWnd
    hSysMenu = GetSystemMenu_(hWnd, #False)
    If hSysMenu
      EnableMenuItem_(hSysMenu, #SC_CLOSE, #MF_BYCOMMAND | Enabled ! 1)
      DrawMenuBar_(hWnd)
    EndIf
  EndIf
EndProcedure

Enumeration
  #GadgetButton_DisableMinBox
  #GadgetButton_DisableMaxBox
  #GadgetButton_DisableCloseBox
  #GadgetButton_Exit
EndEnumeration

If OpenWindow(0, 0, 0, 200, 145, "Disable Window Close Box - Example", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)
  ButtonGadget(#GadgetButton_DisableMinBox, 5, 5, 190, 25, "Disable Minimize Box", #PB_Button_Toggle)
  ButtonGadget(#GadgetButton_DisableMaxBox, 5, 35, 190, 25, "Disable Maximize Box", #PB_Button_Toggle)
  ButtonGadget(#GadgetButton_DisableCloseBox, 5, 65, 190, 25, "Disable Close Box", #PB_Button_Toggle)
  ButtonGadget(#GadgetButton_Exit, 5, 115, 190, 25, "Exit")
  AddKeyboardShortcut(0, #PB_Shortcut_Alt | #PB_Shortcut_F4, 0)
  AddKeyboardShortcut(0, #PB_Shortcut_Escape, 0)
  
  Repeat
    WinEvent.l = WaitWindowEvent()
    If WinEvent = #PB_Event_Gadget
      Select EventGadget()
        Case #GadgetButton_DisableMinBox
          SetWindowMinButton(WindowID(0), GetGadgetState(#GadgetButton_DisableMinBox) ! 1)
        Case #GadgetButton_DisableMaxBox
          SetWindowMaxButton(WindowID(0), GetGadgetState(#GadgetButton_DisableMaxBox) ! 1)
        Case #GadgetButton_DisableCloseBox
          SetWindowCloseButton(WindowID(0), GetGadgetState(#GadgetButton_DisableCloseBox) ! 1)
        Case #GadgetButton_Exit
          If GetGadgetState(#GadgetButton_DisableCloseBox) = 0
            End
          EndIf
      EndSelect
    ElseIf WinEvent = #PB_Event_Menu And EventMenu() = 0
      If GetGadgetState(#GadgetButton_DisableCloseBox) = 0
        End
      EndIf
    EndIf
  Until WinEvent = #PB_Event_CloseWindow
  
EndIf

End
have fun. :)

c ya,
nco2k
Last edited by nco2k on Fri Jan 20, 2006 7:10 pm, edited 1 time in total.
If OSVersion() = #PB_OS_Windows_ME : End : EndIf
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Works great, did you realize disabling that button also disables <alt><F4> from closing the window as well? So it can't be closed at all. For some of my windows I've wanted to put a minimize without maximize available, not grayed out, just not there. Might that be possible?
Last edited by netmaestro on Tue Feb 21, 2006 9:45 pm, edited 3 times in total.
BERESHEIT
User avatar
nco2k
Addict
Addict
Posts: 1344
Joined: Mon Sep 15, 2003 5:55 am

Post by nco2k »

> disabling that button also disables <ALT><F4> from closing the window
thats because i added AddKeyboardShortcut(0, #PB_Shortcut_Alt | #PB_Shortcut_F4, 0) if you want to close the window due alt+f4 even if the close box is disabled, simply remove this shortcut. :)

> Do you think that's possible
nope, the min and max buttons need each other, its a limitation by windows.

Code: Select all

;#WS_MINIMIZEBOX = 131072
;#WS_MAXIMIZEBOX = 65536

hWnd.l = OpenWindow(0, 0, 0, 300, 300, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered | #PB_Window_SystemMenu, "Example")
If hWnd
  
  ;ON:
  ;SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) | #WS_MINIMIZEBOX)
  SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) | #WS_MAXIMIZEBOX)
  
  ;OFF:
  SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) & (#WS_MINIMIZEBOX ! - 1))
  ;SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) & (#WS_MAXIMIZEBOX ! - 1))
  
  ;SWITCH:
  ;SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) ! #WS_MINIMIZEBOX)
  ;SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE) ! #WS_MAXIMIZEBOX)
  
  ;REDRAW:
  SetWindowPos_(hWnd, 0, 0, 0, 0, 0, #SWP_NOZORDER | #SWP_NOMOVE | #SWP_NOSIZE | #SWP_FRAMECHANGED)
  
  While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
  
EndIf
if you disable min and max buttons, then both will disappear.

p.s.: maybe there is a way due some hardcore "hacking" but, never mess with a users pc/os/settings/whatever. :twisted: :wink:

c ya,
nco2k
If OSVersion() = #PB_OS_Windows_ME : End : EndIf
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Enable/Disable Window Close Button/Box

Post by PB »

> i just searched the forums for something like this, but i have only found
> a way to (completely) remove the close menu-item, but not to disable
> (and gray) it or maybe i didn't searched long enough. :P

You didn't search long enough. ;)

A search for "disable close button" shows this 2002 post:

viewtopic.php?t=3712

Apparently I posted one earlier too, but I can't find it now... I may have deleted
it after the tip above, because I conceded that it was superior to mine.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
nco2k
Addict
Addict
Posts: 1344
Joined: Mon Sep 15, 2003 5:55 am

Post by nco2k »

@PB
yes, that was the only usefull post i could find, but removing <> disabling. :D

and btw imo its better to remove/edit a menu-item by #MF_BYCOMMAND instead of #MF_BYPOSITION. you never know, what extra fancy tools the user has installed, which could add extra items in the menu.

c ya,
nco2k
If OSVersion() = #PB_OS_Windows_ME : End : EndIf
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> @PB
> yes, that was the only usefull post i could find, but removing <> disabling

It doesn't remove the X button, it disables/greys it. Did you try it? :)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
nco2k
Addict
Addict
Posts: 1344
Joined: Mon Sep 15, 2003 5:55 am

Post by nco2k »

ohh whoops, its not the link i thought it is. looked same at first for me. :oops:

i meant this one: viewtopic.php?t=3697

sorry for that. :D

edit: but in the end, both remove the close item in the context menu (right click) and thats what i dont want. :D

the difference is, i am using EnableMenuItem_() instead of RemoveMenu_() thats the trick. :wink:

c ya,
nco2k
If OSVersion() = #PB_OS_Windows_ME : End : EndIf
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

Hehe, that's my post that I couldn't find (due to not having the word "close"),
but again, it's basically the same code as in the other link, and it also disables
the X button and doesn't remove it, which is precisely what you asked.

EDIT: I just realised that we're talking about two different things here: your
topic subject talks about disabling the close BUTTON, but your message body
talks about disabling the CONTEXT MENU. :)

EDIT #2: Ah crap, I just realised what you're talking about (the menu item
being removed). Forget I spoke. :oops:
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
nco2k
Addict
Addict
Posts: 1344
Joined: Mon Sep 15, 2003 5:55 am

Post by nco2k »

:lol:

but hey, you got your post back. :D

c ya,
nco2k
If OSVersion() = #PB_OS_Windows_ME : End : EndIf
User avatar
skywalk
Addict
Addict
Posts: 4215
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: En-/Disable Window Min, Max & Close Buttons

Post by skywalk »

Thanks nco2k! :)
I could not figure out why my OpenWindow() cmd always leaves the Maximize button grayed out.
After I applied all gadgets, menus, toolbars, statusbars while hidden.
This did the trick!
SetWindowLongPtr_(hW, #GWL_STYLE, GetWindowLongPtr_(hW, #GWL_STYLE) | #WS_MAXIMIZEBOX)
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 4167
Joined: Thu Apr 18, 2019 8:17 am

Re: En-/Disable Window Min, Max & Close Buttons

Post by BarryG »

Code: Select all

Procedure SetWindowCloseButton(hWnd, Enabled)
  If hWnd And (Enabled = #True Or Enabled = #False)
    hSysMenu = GetSystemMenu_(hWnd, #False)
    If hSysMenu
      EnableMenuItem_(hSysMenu, #SC_CLOSE, #MF_BYCOMMAND | Enabled ! 1)
      DrawMenuBar_(hWnd)
    EndIf
  EndIf
EndProcedure
I want to use this code to toggle a Close button on a third-party window (such as Notepad), but I need to get Notepad's Close button status first (enabled/disabled). Anyone know how? Thanks.

I found this link (see the "Update" code) which may do it -> https://stackoverflow.com/q/37090878/7908170 but I don't know how to convert it. Sorry.
Axolotl
Addict
Addict
Posts: 831
Joined: Wed Dec 31, 2008 3:36 pm

Re: En-/Disable Window Min, Max & Close Buttons

Post by Axolotl »

Good Day!

I adopted some older code to your needs.
so far ALT+F4 is still working with this.

Code: Select all


Procedure EnableMenuItem(hWnd, ItemID, State=#PB_Ignore) ;­ State: use #False, #True for State
  Protected result, hSysMenu, mii.MENUITEMINFO

  mii\cbSize = SizeOf(MENUITEMINFO)
  mii\fMask  = #MIIM_STATE

  hSysMenu = GetSystemMenu_(hWnd, #False)
  If hSysMenu 
    If State = #PB_Ignore  ;' return the current state 
      If GetMenuItemInfo_(hSysMenu, ItemID, 0, @mii)   ;:Debug "  old state="+Hex(mii\fState)
        result = Bool(mii\fState = #MFS_ENABLED) 
      EndIf
    Else ;' change the current state 
      If State = #True : mii\fState = #MFS_ENABLED
      Else             : mii\fState = #MFS_DISABLED : EndIf
      If SetMenuItemInfo_(hSysMenu, ItemID, 0, @mii) 
        result = Bool(mii\fState = #MFS_ENABLED) 
      EndIf
    EndIf 
  EndIf 
  ProcedureReturn result 
EndProcedure ;() 


Procedure ToggleMenuItem(hwnd, ItemID)  ;' toggle the current state, returns the new state 
  Protected state 
  state = EnableMenuItem(hwnd, ItemID)   :Debug "state before "+state 
  state ! 1 
  EnableMenuItem(hwnd, ItemID, state)    :Debug "state after  "+state  
  ProcedureReturn state 
EndProcedure ;() 



Procedure.i FindWindowByClass(ClassName$)  ;'  returns window handle or 0 if not found 
  Protected hWnd, hWndFound, t${#MAX_PATH}

  hWnd = GetWindow_(GetDesktopWindow_(), #GW_CHILD)    ;' start with desktop 
  Repeat
    GetClassName_(hWnd, @t$, #MAX_PATH)            ;:Debug " 0x" + hex(hWnd) + " -> '" + t$ + "'"

    If t$ And FindString(t$, ClassName$, 0) <> 0 And IsWindowVisible_(hWnd) = #True 
      hWndFound = hWnd 
      Break 
    Else
      hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)    ;' look at the next window in the list 
    EndIf
  Until hWnd = 0 Or hWndFound <> 0
  ProcedureReturn hWndFound
EndProcedure ;() 


  Define hwndNotepad  

  If OpenWindow(0, 0, 0, 230, 120, "Example...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
   ButtonGadget  (1, 10, 30, 200, 20, "Start Notepad") 
   CheckBoxGadget(2, 10, 60, 200, 20, "Notepad Close State")
   SetGadgetState(2, 1) 

   Repeat
     Event = WaitWindowEvent()
     
     Select Event    
       Case #PB_Event_Gadget
         Select EventGadget()
           Case 1 
            RunProgram("notepad.exe") 
            Delay(100) 
            hwndNotepad = FindWindowByClass("Notepad") 
            If hwndNotepad <> 0 
              Debug " 0x"+Hex(hwndNotepad) 
              Debug "Close State = " + EnableMenuItem(hwndNotepad, #SC_CLOSE) 
            EndIf 
   
           Case 2 
            If hwndNotepad <> 0 
              If GetGadgetState(2) 
                Debug "Close State = " + EnableMenuItem(hwndNotepad, #SC_CLOSE, #True) 
              Else
                Debug "Close State = " + EnableMenuItem(hwndNotepad, #SC_CLOSE, #False) 
              EndIf 
            EndIf 
         EndSelect
     EndSelect
   Until Event = #PB_Event_CloseWindow
 EndIf
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
User avatar
mk-soft
Always Here
Always Here
Posts: 6242
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: En-/Disable Window Min, Max & Close Buttons

Post by mk-soft »

ALT+F4 is not the button !
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Axolotl
Addict
Addict
Posts: 831
Joined: Wed Dec 31, 2008 3:36 pm

Re: En-/Disable Window Min, Max & Close Buttons

Post by Axolotl »

I know.
I only mentioned that, because of the earlier discussion about alt+f4.
BTW: with autohotkey and

Code: Select all

#IfWinActive ahk_class Notepad
  !F4::return
return 
it is possible to deactivate alt+f4 (not tested)
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
BarryG
Addict
Addict
Posts: 4167
Joined: Thu Apr 18, 2019 8:17 am

Re: En-/Disable Window Min, Max & Close Buttons

Post by BarryG »

Axolotl, your code doesn't work because it only works with windows created from RunProgram() that your app launched. It won't work with other windows that aren't launched by your app. Try it.

All I need is a quick way to test if X (close button) is enabled or not for any given hWnd that I throw at it. Can you please amend your code to work without using RunProgram()? My goal is below.

Code: Select all

Procedure IsXEnabled(hWnd)
  mii.MENUITEMINFO
  mii\cbSize=SizeOf(MENUITEMINFO)
  mii\fMask=#MIIM_STATE
  result=999
  hSysMenu=GetSystemMenu_(hWnd,#False)
  Debug hSysMenu ; 374605515 (OK)
  If hSysMenu
    info=GetMenuItemInfo_(hSysMenu,#SC_CLOSE,0,@mii)
    Debug info ; 0 (Failure)
    If info
      result=Bool(mii\fState=#MFS_ENABLED)
    EndIf
  EndIf
  ProcedureReturn result
EndProcedure

hWnd=FindWindow_(0,"Untitled - Notepad")
If hWnd=0
  Debug "Please start Notepad manually and run this code TWICE to see the problem!"
Else
  Debug IsXEnabled(hWnd) ; Returns 999 on SECOND run because "info" var is 0 (failed).
EndIf
Post Reply