Trouble disabling SC_CLOSE for terminal's window #20228

Closed
opened 2026-01-31 07:07:25 +00:00 by claunia · 6 comments
Owner

Originally created by @bzm3r on GitHub (Jul 13, 2023).

Windows Terminal version

1.17.11461.0

Windows build number

10.0.19044.0

Other Software

PowerShell 7+

Steps to reproduce

I would like to disable the close (from the ALT+Space floating menu and the top-left window's "X") button for the terminal that my PowerShell session is loaded in. So, I run the following function (based on this SO answer and this blog post):

function Disable-ThisTerminalClose {
    #Calling user32.dll methods for Windows and Menus
    $MethodsCall = '
[DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable);
[DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong);
[DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable);
'
 
    #Create a new namespace for the Methods to be able to call them
    Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32
 
    Write-Host "Added NativeMethods type..."

    #WM_SYSCOMMAND Message
    $MF_GRAYED = 0x00000001L    #Indicates that the menu item is disabled and grayed so that it cannot be selected.    
    $MF_DISABLED = 0x00000002L #Indicates that the menu item is disabled, but not grayed, so it cannot be selected.
    $MF_ENABLED = 0x00000000L #Indicates that the menu item is enabled and restored from a grayed state so that it can be selected.
    #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx
 
    $SC_CLOSE = 0xF060
    #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx

 
    #Get window handle of this Powershell process (should be the Windows Terminal?)
    $PSWindow = Get-Process | Where-Object { $_.Name -like "*Terminal*" }
    Write-Host ("Found PSWindow: " + $PSWindow)
    $hwnd = $PSWindow.MainWindowHandle
    Write-Host ("hwnd: " + $hwnd)
 
    #Get System menu of windows handled
    $hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0)
 
    # #Window Style : TOOLWINDOW
    # [Win32.NativeMethods]::SetWindowLongPtr($hwnd, $GWL_EXSTYLE, $WS_EX_TOOLWINDOW) | Out-Null
 
    #Disable X Button and window itself
    Write-Host "About to disable close functionality..."
    [Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, ($MF_GRAYED + $MF_DISABLED))
 
    Write-Host "Disabled!" -ForegroundColor Red
}

Run this function (or, paste it's body into a PowerShell 7+ session.

Expected Behavior

I was hoping that the close button (both X and in floating menu) would be disabled.

Actual Behavior

Close/X are not disabled.

Originally created by @bzm3r on GitHub (Jul 13, 2023). ### Windows Terminal version 1.17.11461.0 ### Windows build number 10.0.19044.0 ### Other Software PowerShell 7+ ### Steps to reproduce I would like to disable the close (from the `ALT+Space` floating menu and the top-left window's "X") button for the `terminal` that my PowerShell session is loaded in. So, I run the following function (based on [this SO answer](https://stackoverflow.com/questions/73746912/disable-the-close-x-button-in-powershell) and [this blog post](https://www.makak.ch/disable-close-button-in-powershell-window/)): ```powershell function Disable-ThisTerminalClose { #Calling user32.dll methods for Windows and Menus $MethodsCall = ' [DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable); [DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong); [DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable); ' #Create a new namespace for the Methods to be able to call them Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32 Write-Host "Added NativeMethods type..." #WM_SYSCOMMAND Message $MF_GRAYED = 0x00000001L #Indicates that the menu item is disabled and grayed so that it cannot be selected. $MF_DISABLED = 0x00000002L #Indicates that the menu item is disabled, but not grayed, so it cannot be selected. $MF_ENABLED = 0x00000000L #Indicates that the menu item is enabled and restored from a grayed state so that it can be selected. #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx $SC_CLOSE = 0xF060 #... http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx #Get window handle of this Powershell process (should be the Windows Terminal?) $PSWindow = Get-Process | Where-Object { $_.Name -like "*Terminal*" } Write-Host ("Found PSWindow: " + $PSWindow) $hwnd = $PSWindow.MainWindowHandle Write-Host ("hwnd: " + $hwnd) #Get System menu of windows handled $hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0) # #Window Style : TOOLWINDOW # [Win32.NativeMethods]::SetWindowLongPtr($hwnd, $GWL_EXSTYLE, $WS_EX_TOOLWINDOW) | Out-Null #Disable X Button and window itself Write-Host "About to disable close functionality..." [Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, ($MF_GRAYED + $MF_DISABLED)) Write-Host "Disabled!" -ForegroundColor Red } ``` Run this function (or, paste it's body into a PowerShell 7+ session. ### Expected Behavior I was hoping that the close button (both X and in floating menu) would be disabled. ### Actual Behavior Close/X are not disabled.
claunia added the Issue-BugResolution-External labels 2026-01-31 07:07:25 +00:00
Author
Owner

@lhecker commented on GitHub (Jul 13, 2023):

Why would you like to disable the close button?

@lhecker commented on GitHub (Jul 13, 2023): Why would you like to disable the close button?
Author
Owner

@zadjii-msft commented on GitHub (Jul 13, 2023):

Yea, messing with Terminal's HWND is 100% not supported.

Focus mode might be something that interests you, though, that'll entirely hide the titlebar (including the tabs).

We could theoretically make this a window theme setting. You can already hide the close button on the tabs, so there's probably room for configuring the close button too. Something ala: https://github.com/microsoft/terminal/issues/12632#issuecomment-1246657097

@zadjii-msft commented on GitHub (Jul 13, 2023): Yea, messing with Terminal's HWND is 100% not supported. [Focus mode](https://learn.microsoft.com/en-us/windows/terminal/customize-settings/actions#toggle-focus-mode) might be something that interests you, though, that'll entirely hide the titlebar (including the tabs). We could theoretically make this a window theme setting. You can already [hide the close button on the tabs](https://learn.microsoft.com/en-us/windows/terminal/customize-settings/themes#show-close-button), so there's probably room for configuring the close button too. Something ala: https://github.com/microsoft/terminal/issues/12632#issuecomment-1246657097
Author
Owner

@bzm3r commented on GitHub (Jul 13, 2023):

Why would you like to disable the close button?

I need to trigger some cleanup scripts on exit, but PowerShell.Exiting still does not trigger correctly for when the user presses the X button. At this point, the issue has been open for so long, that I am not sure what is going on there: https://github.com/PowerShell/PowerShell/issues/8000

So, I thought I'd just try to disable the X button.

We could theoretically make this a window theme setting. You can already hide the close button on the tabs, so there's probably room for configuring the close button too. Something ala: #12632 (comment)

@zadjii-msft That would be super helpful, actually. I realize that it wouldn't disable Close in the alt+Space menu, but that would still be a major improvement. Of course, the best solution is if PowerShell.Exiting just finally worked correctly...

@bzm3r commented on GitHub (Jul 13, 2023): > Why would you like to disable the close button? I need to trigger some cleanup scripts on exit, but `PowerShell.Exiting` still does not trigger correctly for when the user presses the X button. At this point, the issue has been open for so long, that I am not sure what is going on there: https://github.com/PowerShell/PowerShell/issues/8000 So, I thought I'd just try to disable the X button. > We could theoretically make this a window theme setting. You can already [hide the close button on the tabs](https://learn.microsoft.com/en-us/windows/terminal/customize-settings/themes#show-close-button), so there's probably room for configuring the close button too. Something ala: [#12632 (comment)](https://github.com/microsoft/terminal/issues/12632#issuecomment-1246657097) @zadjii-msft That would be super helpful, actually. I realize that it wouldn't disable `Close` in the `alt+Space` menu, but that would still be a major improvement. Of course, the best solution is if `PowerShell.Exiting` just finally worked correctly...
Author
Owner

@zadjii-msft commented on GitHub (Aug 2, 2023):

Hokay, so we talked a bit with @stevel-msft about this. He's gonna take another shot at https://github.com/PowerShell/PowerShell/issues/8000. Because honestly, that's the right solution here. Just fix that. Not disable the close button for the Terminal. That seems like it's an unnecessarily big hammer for a weird edge case in the shell scripting engine 😅

/dup https://github.com/PowerShell/PowerShell/issues/8000

@zadjii-msft commented on GitHub (Aug 2, 2023): Hokay, so we talked a bit with @stevel-msft about this. He's gonna take another shot at https://github.com/PowerShell/PowerShell/issues/8000. Because honestly, that's the right solution here. Just fix that. Not _disable the close button for the Terminal_. That seems like it's an unnecessarily big hammer for a weird edge case in the shell scripting engine 😅 /dup https://github.com/PowerShell/PowerShell/issues/8000
Author
Owner

@microsoft-github-policy-service[bot] commented on GitHub (Aug 2, 2023):

Hi! We've identified this issue as a duplicate of one that exists on somebody else's Issue Tracker. Please make sure you subscribe to the referenced external issue for future updates. Thanks for your report!

@microsoft-github-policy-service[bot] commented on GitHub (Aug 2, 2023): Hi! We've identified this issue as a duplicate of one that exists on somebody else's Issue Tracker. Please make sure you subscribe to the referenced external issue for future updates. Thanks for your report!
Author
Owner

@rbeesley commented on GitHub (Nov 13, 2024):

@zadjii-msft, I recognize the reasons why EnableMenuItem may not be supported in Terminal, but documentation around those APIs should clarify limits. The biggest issue with EnableMenuItem as I see it is that in a tabbed host, modifying the host is undefined; is the app modifying the tab, the window, and/or both?

AttachConsole, GetConsoleWindow, GetConsoleTitle, SetConsoleTitle, GetSystemMenu, and GetMenuState do work, which follows the documentation. This is great, as it does allow me to create an app which has a behavior in conhost and it seemingly does the right thing in Terminal. On the other hand, SetConsoleMode and EnableMenuItem seem to work, in that the calls don't cause an exception and looking at the state changes the state seems to have been changed, but setting the flag for EnableMenuItem doesn't seem to actually disable the Close button and disable the corresponding menu item. EnableMenuItem seems like it should affect the tab Close button, and I was surprised to see that it doesn't when the underlying structure was modified using documented Windows API calls.

Image

SetConsoleMode is a little trickier to evaluate as the flags I'm changing have to do with disabling ENABLE_LINE_INPUT, disabling ENABLE_ECHO_INPUT, enabling ENABLE_EXTENDED_FLAGS, enabling ENABLE_MOUSE_INPUT, and enabling ENABLE_QUICK_EDIT_MODE, which I've only really looked at the effect in conhost.

If these APIs aren't being honored in Terminal, then the API documentation should indicate that they only affect conhost, or Terminal should support these flags for continued backwards compatibility. How do other 3rd party terminal apps handle these states?

Maybe some of these API calls will automatically detach the tab from the Terminal and transition to Focus mode? Restoring the state would then revert out of Focus mode if state has been restored and/or FreeConsole is called. It is a different behavior, but then again this might be seen as trying to follow backwards compatible behavior and intent. This suggestion seems like a hack on a hack though.

I haven't created an issue around my findings, as this was already an issue concerning the behavior around:

const auto menu = GetSystemMenu(GetConsoleWindow(), FALSE);
EnableMenuItem(menu, SC_CLOSE, MF_GRAYED);

It seemed appropriate to add to the discussion here first, and perhaps this only needs to be resolved with documentation changes if these aren't seen as backwards compatibility concerns.

Edit: It's worth noting that I was doing this experiment with new terminal instances. When I ran it again, the Close button state was showing state 3, which would suggest that it was MF_GRAYED and MF_DISABLED after I restored the state to MF_ENABLED, freed the console, and ran the app again. In comparison, conhost acts as expected. So, I may have spoken too soon that Terminal is handling these flags correctly and only ignoring changes to the view. I don't know if this has any other side effects. If ultimately Terminal doesn't support these changes, then there would also be a need for an application to know if it was running in conhost or Terminal before trying to make changes... that has other consequences too.

@rbeesley commented on GitHub (Nov 13, 2024): @zadjii-msft, I recognize the reasons why `EnableMenuItem` may not be supported in Terminal, but documentation around those APIs should clarify limits. The biggest issue with `EnableMenuItem` as I see it is that in a tabbed host, modifying the host is undefined; is the app modifying the tab, the window, and/or both? `AttachConsole`, `GetConsoleWindow`, `GetConsoleTitle`, `SetConsoleTitle`, `GetSystemMenu`, and `GetMenuState` do work, which follows the documentation. This is great, as it does allow me to create an app which has a behavior in conhost and it seemingly does the right thing in Terminal. On the other hand, `SetConsoleMode` and `EnableMenuItem` seem to work, in that the calls don't cause an exception and looking at the state changes the state seems to have been changed, but setting the flag for `EnableMenuItem` doesn't seem to actually disable the Close button and disable the corresponding menu item. `EnableMenuItem` seems like it should affect the tab Close button, and I was surprised to see that it doesn't when the underlying structure was modified using documented Windows API calls. ![Image](https://github.com/user-attachments/assets/cde39cb8-4ff3-4fe4-8b24-d51052df59ae) `SetConsoleMode` is a little trickier to evaluate as the flags I'm changing have to do with disabling `ENABLE_LINE_INPUT`, disabling `ENABLE_ECHO_INPUT`, enabling `ENABLE_EXTENDED_FLAGS`, enabling `ENABLE_MOUSE_INPUT`, and enabling `ENABLE_QUICK_EDIT_MODE`, which I've only really looked at the effect in conhost. If these APIs aren't being honored in Terminal, then the API documentation should indicate that they only affect conhost, or Terminal should support these flags for continued backwards compatibility. How do other 3rd party terminal apps handle these states? Maybe some of these API calls will automatically detach the tab from the Terminal and transition to Focus mode? Restoring the state would then revert out of Focus mode if state has been restored and/or `FreeConsole` is called. It is a different behavior, but then again this might be seen as trying to follow backwards compatible behavior and intent. This suggestion seems like a hack on a hack though. I haven't created an issue around my findings, as this was already an issue concerning the behavior around: ```cpp const auto menu = GetSystemMenu(GetConsoleWindow(), FALSE); EnableMenuItem(menu, SC_CLOSE, MF_GRAYED); ``` It seemed appropriate to add to the discussion here first, and perhaps this only needs to be resolved with documentation changes if these aren't seen as backwards compatibility concerns. Edit: It's worth noting that I was doing this experiment with new terminal instances. When I ran it again, the Close button state was showing state 3, which would suggest that it was `MF_GRAYED` and `MF_DISABLED` after I restored the state to `MF_ENABLED`, freed the console, and ran the app again. In comparison, conhost acts as expected. So, I may have spoken too soon that Terminal is handling these flags correctly and only ignoring changes to the view. I don't know if this has any other side effects. If ultimately Terminal doesn't support these changes, then there would also be a need for an application to know if it was running in conhost or Terminal before trying to make changes... that has other consequences too.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#20228