Page 1 of 2

En-/Disable Window Min, Max & Close Buttons

Posted: Fri Jan 20, 2006 8:47 am
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

Posted: Fri Jan 20, 2006 9:14 am
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?

Posted: Fri Jan 20, 2006 9:43 am
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

Re: Enable/Disable Window Close Button/Box

Posted: Fri Jan 20, 2006 10:19 am
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.

Posted: Fri Jan 20, 2006 10:24 am
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

Posted: Sat Jan 21, 2006 12:14 am
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? :)

Posted: Sat Jan 21, 2006 12:21 am
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

Posted: Sat Jan 21, 2006 1:17 am
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:

Posted: Sat Jan 21, 2006 5:55 am
by nco2k
:lol:

but hey, you got your post back. :D

c ya,
nco2k

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

Posted: Fri Nov 22, 2013 2:39 am
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)

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

Posted: Sat Jan 16, 2021 8:31 am
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.

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

Posted: Sat Jan 16, 2021 3:12 pm
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

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

Posted: Sat Jan 16, 2021 3:14 pm
by mk-soft
ALT+F4 is not the button !

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

Posted: Sat Jan 16, 2021 3:39 pm
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)

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

Posted: Sun Jan 17, 2021 5:16 am
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