I have a windows application develop using C# .net 4.0 version.
I need to remove close button from one of my popup windows. I can do it by setting Control Box property as false. But in that case it will remove my icon as well. Else I can disable the close button. But is there any way to remove close button only (leaving the icon in place)?
This is a bit of a cleaner solution :-)
Original post
winuser.h
public partial class Form1 : Form
{
private const int CS_NOCLOSE = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams mdiCp = base.CreateParams;
mdiCp.ClassStyle = mdiCp.ClassStyle | CS_NOCLOSE;
return mdiCp;
}
}
public Form1()
{
InitializeComponent();
}
}
According to constants in the winuser.h there are no flags to get rid of the closed button completely. (Unless you want to find a way to draw over the top of the button by copying a section to the left of it - yuk.)
This code will disable your close button but will show the icon.
In your form class:
Import:
using System.Runtime.InteropServices;
In the main class:
const int MF_BYPOSITION = 0x400;
[DllImport("User32")]
private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("User32")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("User32")]
private static extern int GetMenuItemCount(IntPtr hWnd);
Event:
private void Form1_Load(object sender, EventArgs e)
{
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int menuItemCount = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, menuItemCount - 1, MF_BYPOSITION);
}
Related
I have a Form with the FormBorderStyle set to None, and I have also made my own little GUI replacing the Title Bar, I'm trying to find a way to show the Menu that shows up whenever you right click the title bar or click the icon on the title bar
I have tried using this post but after calling the function nothing happened, I'm at a loss now and I cannot find more resources about this.
When the border style of Form is set to FormBorderStyle.None, GetSystemMenu() always returns a NULL handle.
Because you remove some important Window Styles from HWND when you set the border style to None, this function doesn't return a HMENU.
Probably, it does some checks if the window has a title bar or not. This is why it returns NULL.
The workaround for the issue is to get the menu handle before setting the FoormBorderStyle to None.
using System.Runtime.InteropServices;
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern int TrackPopupMenu(IntPtr hMenu, uint uFlags, int x, int y,
int nReserved, IntPtr hWnd, IntPtr prcRect);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private IntPtr hMenu;
private const int WM_SYSCOMMAND = 0x112;
protected override void OnHandleCreated(EventArgs e)
{
// Get the system menu and set the border style after that.
hMenu = GetSystemMenu(Handle, false);
FormBorderStyle = FormBorderStyle.None;
}
protected override void OnMouseUp(MouseEventArgs e)
{
int menuIdentifier = TrackPopupMenu(hMenu, 0x102, Control.MousePosition.X, Control.MousePosition.Y, 0, Handle, IntPtr.Zero);
if(menuIdentifier != 0)
{
PostMessage(Handle, WM_SYSCOMMAND, (IntPtr)menuIdentifier, IntPtr.Zero);
}
}
}
I would like to keep the icon on my program, but would like to remove the double-click close
feature. Is there any way of doing this?
I have not found anything about this on google tho.
You can do this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Size iconSize = new Size(32,32);
Rectangle R = new Rectangle(this.Location, iconSize);
if (R.Contains(Cursor.Position) && e.CloseReason == CloseReason.UserClosing)
e.Cancel = true;
}
Here are two options. The side effect is that the window's top right X (close button) is disabled on Windows 8. I believe on windows XP it is removed completely.
Option 1: Override the Form's OnHandleCreated:
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
public static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
private static extern bool RemoveMenu(IntPtr hMenu, int uPosition, uint uFlags);
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
const uint MF_BYPOSITION = 0x00000400;
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int n = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, n-1, MF_BYPOSITION); // remove last (always close?)
}
Option 2: override the Form's CreateParams. The advantage of this one is that it does the work of also removing the separator.
// this code will hide the close X button, since there is no CloseBox Form property
protected override CreateParams CreateParams {
get {
const int CS_NOCLOSE = 0x0200;
CreateParams param = base.CreateParams;
param.ClassStyle = param.ClassStyle | CS_NOCLOSE;
return param;
}
}
I was wondering if it is possible to remove the ability to close OTHER windows using C#?
I know that you can override your windows' close() method, but is that also possible for other processes? And what about changing the window style of another process to fixed___ so it cannot be resized?
So far I have gotten the main window handle of the application and I have removed all buttons and menus, but I still need to figure out how to make it uncloseable and unresizeable.
Here's what I've got:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ThirdTest
{
class Program
{
#region Constants
//Finds a window by class name
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//Sets a window to be a child window of another window
[DllImport("USER32.DLL")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
//Sets window attributes
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
//Gets window attributes
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);
//assorted constants needed
public static uint MF_BYPOSITION = 0x400;
public static uint MF_REMOVE = 0x1000;
public static int GWL_STYLE = -16;
public static int WS_CHILD = 0x40000000; //child window
public static int WS_BORDER = 0x00800000; //window with border
public static int WS_DLGFRAME = 0x00400000; //window with double border but no title
public static int WS_CAPTION = WS_BORDER | WS_DLGFRAME; //window with a title bar
public static int WS_SYSMENU = 0x00080000; //window menu
#endregion
public static void WindowsReStyle()
{
Process[] Procs = Process.GetProcesses();
foreach (Process proc in Procs)
{
Console.WriteLine("Found process: " + proc.ProcessName.ToString());
if (proc.ProcessName.StartsWith("notepad"))
{
IntPtr pFoundWindow = proc.MainWindowHandle;
int style = GetWindowLong(pFoundWindow, GWL_STYLE);
//get menu
IntPtr HMENU = GetMenu(proc.MainWindowHandle);
//get item count
int count = GetMenuItemCount(HMENU);
//loop & remove
for (int i = 0; i < count; i++)
RemoveMenu(HMENU, 0, (MF_BYPOSITION | MF_REMOVE));
//force a redraw
DrawMenuBar(proc.MainWindowHandle);
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_SYSMENU));
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_CAPTION));
}
}
}
static void Main(string[] args)
{
WindowsReStyle();
}
}
}
Any ideas? (:
As I've put in the comments, here are some more details on the issue:
I need two applications to be side-by-side on the monitor.
None of them can be closeable or resizeable. One is a browser, the other is an application called "Z-tree".
I have already fixed the issue with Z-tree as it, by default, runs with no closebutton and no resizing and you can specify the size and position of it in the command line.
Here's another idea, create a winforms project and set the window so it cannot be resized. Then embed a single WebBrowser control in the form and navigate to your page in the form load:
private void Form1_Load(object sender, EventArgs e)
{
//catch form closing event to prevent form being closed using alt-f4
FormClosing += Form1_FormClosing;
//remove close button from toolbar and remove window border to prevent
//moving and resizing
this.ControlBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
//set position to half of the screen
this.Left = Screen.PrimaryScreen.Bounds.Width / 2;
this.Top = 0;
this.Width = Screen.PrimaryScreen.Bounds.Width / 2;
this.Height = Screen.PrimaryScreen.Bounds.Height;
//mark the window as a top level window, reducing users ability to alt-tab away
TopMost = true;
webBrowser1.Navigate("www.google.com");
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//prevent form being closed
e.Cancel = true;
}
//the only way to close the form
void DoExit()
{
//remove the closing handler first or it won't close
FormClosing -= Form1_FormClosing;
Close();
}
you can force internet explorer into an "unexitable" fullscreen mode if you start it with:
iexplore -k www.google.com
This is how shops and stuff get it to run so no-one can close it. Of course you can close it through task manager, but it just makes it difficult for most users to close it.
(CTRL-W will close it <--- secret key!)
http://support.microsoft.com/kb/154780
I'd like to know how to disable (not remove/hide) the Close button in a WPF window. I know how to hide it which makes the window's title bar look like this:
But I want to disable it meaning it should look like this:
I'm scripting in C# and using WPF (Windows Presentation Foundation).
Try this:
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
const uint MF_BYCOMMAND = 0x00000000;
const uint MF_GRAYED = 0x00000001;
const uint SC_CLOSE = 0xF060;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Disable close button
IntPtr hwnd = new WindowInteropHelper(this).Handle;
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
}
Taken from here.
Make sure you set the ResizeMode to NoResize.
You have to override and in OnCLosing event set e.cancel=true
public MyWindow()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(MyWindow_Closing);
}
void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
This post which an answer using Behavior, GetWindowLong and SetWindowLong:
public class HideCloseButtonOnWindow : System.Windows.Interactivity.Behavior<Window>
{
#region bunch of native methods
private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x80000;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
#endregion
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= OnLoaded;
base.OnDetaching();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var hwnd = new System.Windows.Interop.WindowInteropHelper(AssociatedObject).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
}
How to use it:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:w="clr-namespace:WpfApplication2">
<i:Interaction.Behaviors>
<w:HideCloseButtonOnWindow />
</i:Interaction.Behaviors>
</Window>
You can probably do it with win32 hackery.
I have done it this way: Get CustomChromeWindow(which will eventually look exactly like the one in picture), and just bind Command() property to viewmodel, and then set CanExecuteCommand=false, which will make the button disabled(How does one "disable" a button in WPF using the MVVM pattern?).
There might me this way too: How to disable close button on a window in another process with C++?
Basically, call that code with pInvoke. You can obtain WPF window handle easily.
If you would like a more generic version of Yoav's accepted answer that doesn't require adding Win API calls to your Window class, here's a extension class and method:
namespace WinApi
{
using System.Runtime.InteropServices;
using System.Windows.Interop;
public static class WinApi
{
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
const uint MF_BYCOMMAND = 0x00000000;
const uint MF_GRAYED = 0x00000001;
const uint SC_CLOSE = 0xF060;
public static void DisableCloseButton(this System.Windows.Window window)
{
// Disable close button
IntPtr hwnd = new WindowInteropHelper(window).EnsureHandle();
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
}
Then call it from your Window like so:
this.DisableCloseButton();
// or
WinApi.DisableCloseButton(this);
Since the extension uses EnsureHandle() you don't need to hook OnSourceInitialized() in your Window.
Be aware that EnsureHandle() raises OnSourceInitialized(), so don't call this until after you have done anything you want to happen prior to that call.
You can call new WindowInteropHelper(this).Handle() in your Window code if you need to check whether the handle has already been created.
I have a form that pops up on a user's screen and has TopMost=true, but it steals the focus. How can I get it to not steal focus when it first appears?
This is what worked for me. It provides TopMost but without focus-stealing.
protected override bool ShowWithoutActivation
{
get { return true; }
}
private const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_TOPMOST;
return createParams;
}
}
Remember to omit setting TopMost in Visual Studio designer, or elsewhere.
This is stolen, err, borrowed, from here (click on Workarounds):
https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost
Paste this code in your form:
protected override bool ShowWithoutActivation
{
get { return true; }
}
You can set:
this.TopMost = True;
on Load event of that form.
It's OK with me!
You can do it like this:
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(System.IntPtr hWnd, int nCmdShow);
public static void ShowInactiveTopmost(System.Windows.Forms.Form frm)
{
try
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
frm.Left, frm.Top, frm.Width, frm.Height,
SWP_NOACTIVATE);
}
catch (System.Exception ex)
{
// error handling
}
}
I tested the below code using a timer on form1 to instantiate and show form2 with form1 as owner.
In form2's Shown event I then set focus to the owner, which is the current active form.
I have a textbox on form1 and was able to continuesly write in the textbox without loosing focus during this process.
My timer code in form1:
private void timer1_Tick(object sender, EventArgs e)
{
Form2 popup = new Form2();
popup.TopMost = true;
popup.Show(this);
timer1.Enabled = false;
}
My code in the Shown event of form2:
private void Form2_Shown(object sender, EventArgs e)
{
this.Owner.Focus();
}
You can do this or simply set TopMost to false and use the override of ShowWithoutActivation as Hans Passant stated.
Edit: (Or use p/invoke as seen in Hans Passant's additional comment I missed while I wrote this)
I came across the same problem. I'm not using C# but C++. I figure this could be useful anyways:
Using windows.h:
BOOL WINAPI SetWindowPos(
__in HWND hWnd,
__in_opt HWND hWndInsertAfter,
__in int X,
__in int Y,
__in int cx,
__in int cy,
__in UINT uFlags
);
Passing the flag SWP_NOACTIVATE to the uFlags argument worked for me.
Instead of writing .setfocus()in _activated event; write it to .shown event of the form.