To reproduce my problem please do the following:
Create a new Windows Form Application in C#.
In the Properties window of Form1 set FormBorderStyle to None.
Launch program and press Windows+Up.
Now you are stuck in full screen.
In the default FormBorderStyle setting the MaximizeBox property to false will disable the Windows+Up fullscreen shortcut.
If the FormBorderStyle is set to None Microsoft decided it would be a good idea to disable all the Windows+Arrow key shortcuts except for the up arrow and then disable the disabling of the MaximizeBox property.
Is this a glitch? Any simple way to disable this shortcut function the selfsame way it is disabled on all the other FormBorderStyles?
Windows does this by calling SetWindowPos() to change the position and size of the window. A window can be notified about this by listening for the WM_WINDOWPOSCHANGING message and override the settings. Lots of things you can do, like still giving the operation a meaning by adjusting the size and position to your liking. You completely prevent it by turning on the NOSIZE and NOMOVE flags.
Paste this code into your form:
private bool AllowWindowChange;
private struct WINDOWPOS {
public IntPtr hwnd, hwndInsertAfter;
public int x, y, cx, cy;
public int flags;
}
protected override void WndProc(ref Message m) {
// Trap WM_WINDOWPOSCHANGING
if (m.Msg == 0x46 && !AllowWindowChange) {
var wpos = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
wpos.flags |= 0x03; // Turn on SWP_NOSIZE | SWP_NOMOVE
System.Runtime.InteropServices.Marshal.StructureToPtr(wpos, m.LParam, false);
}
base.WndProc(ref m);
}
When you want to change the window yourself, simply set the AllowWindowChange field temporarily to true.
Trap the WM_GETMINMAXINFO message which will allow you to specify the maximized size and location of your form. Technically your form will still change state to Maximized, but it will appear the same since we specify the maximized size/position to be the same as the normal state of the form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public struct POINTAPI
{
public Int32 X;
public Int32 Y;
}
public struct MINMAXINFO
{
public POINTAPI ptReserved;
public POINTAPI ptMaxSize;
public POINTAPI ptMaxPosition;
public POINTAPI ptMinTrackSize;
public POINTAPI ptMaxTrackSize;
}
public const Int32 WM_GETMINMAXINFO = 0x24;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_GETMINMAXINFO:
MINMAXINFO mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(MINMAXINFO));
mmi.ptMaxSize.X = this.Width;
mmi.ptMaxSize.Y = this.Height;
mmi.ptMaxPosition.X = this.Location.X;
mmi.ptMaxPosition.Y = this.Location.Y;
System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, m.LParam, true);
break;
}
base.WndProc(ref m);
}
}
Overriding the ProcessCmdKey (protected method in Form) explicitly allow us to apply custom hook and can be used in your scenario. This essentially allow us to override built-in keystroke handling.
Note: Following example demonstrate the idea of how to handle different keystroke or combination of it. Now, you probably need to fine tune the following code to work inline with your scenario. Eg: Ideally changing the FormBorderStyle or Form Size when user press the LWin+Up arrow.
public partial class Form1 : Form
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.LWin | Keys.Up))//Left windows key + up arrow
{
FormBorderStyle = FormBorderStyle.FixedDialog;
return true;
}
if (keyData == Keys.Escape) //Form will call its close method when we click Escape.
Close();
return base.ProcessCmdKey(ref msg, keyData);
}
}
Updated on How to disable windows Key in your case Lwin or RWin
public partial class Form1 : Form
{
// Structure contain information about low-level keyboard input event
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
//System level functions to be used for hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
//Declaring Global objects
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;
public Form1()
{
ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
InitializeComponent();
}
private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin) // Disabling Windows keys
{
return (IntPtr)1;
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
MessageBox.Show(e.KeyChar.ToString());
}
}
Check this solution - it removes Maximize/Minimize/Titlebar/Border by API calls.
public partial class Form1 : Form
{
// import necessary API functions to get and set Windows styles for P/Invoke
[DllImport("user32.dll")]
internal extern static int SetWindowLong(IntPtr hwnd, int index, int value);
[DllImport("user32.dll")]
internal extern static int GetWindowLong(IntPtr hwnd, int index);
// define constants like they are named in SDK in order to make source more readable
const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;
const int WS_MINIMIZEBOX = 0x00020000;
const int WS_MAXIMIZEBOX = 0x00010000;
const int WS_CAPTION = 0x00C00000;
const int WS_THICKFRAME = 0x00040000;
const int WS_EX_DLGMODALFRAME = 0x00000001;
const int WS_EX_CLIENTEDGE = 0x00000200;
const int WS_EX_STATICEDGE = 0x00020000;
// this replaces MinimizeBox=false and MaximizeBox=false
void HideMinimizeAndMaximizeButtons()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flags for MinimizeBox and MaximizeBox
style = style & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
}
// part of removing the whole border
void HideTitleBar()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flag for caption
style = style & ~WS_CAPTION;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
}
// hide the border
void HideBorder()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flag for border (could use WS_SIZEBOX which is the very same flag (see MSDN)
style = style & ~WS_THICKFRAME;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
// read current extended style
style = GetWindowLong(Handle, GWL_EXSTYLE);
Debug.WriteLine("0x{0:X}", style);
// update style by removing some additional border styles -
// may not be necessary, when current border style is not something exotic,
// i.e. as long as it "normal"
style = style & ~WS_EX_DLGMODALFRAME & ~WS_EX_CLIENTEDGE & ~WS_EX_STATICEDGE;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_EXSTYLE, style);
}
public Form1()
{
InitializeComponent();
// hide those unwanted properties - you can try to leave out one or another to see what it does
HideMinimizeAndMaximizeButtons();
HideTitleBar();
HideBorder();
}
}
This works as intended. Maximizing/minimizing by setting WindowState works as well.
One could analyze in sources what the framework does and what it does "wrong" (or not quite correct).
Edit: I added debug output of the style values. Please try this sequence of commands in Form1 constructor:
MaximizeBox = false;
FormBorderStyle = FormBorderStyle.Sizable;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
MaximizeBox = true;
MaximizeBox = false;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
HideMinimizeAndMaximizeButtons();
You'll see, that setting FormBorderStyle.None enables the WS_MAXIMIZEBOX style. This cannot be "corrected" by another MaximizeBox = false. It seems it's necessary to call API functions.
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 need to embed a qt/c++ application in a wpf mvvm application. The window of this qt/C++ has to be integrated in a wpf page displayed in a tab page.
The page Control is the following :
<page x:Class="Wpf_HostExe.Page1"
xmlns:="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1"
Loaded="OnLoaded">
<Grid>
<Border x:Name="HostUi" Background="White"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
</Grid>
</Page>
I start the app to be hosted with the instructions below :
public static Process StartProcess()
{
System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo();
processStartInfo.WorkingDirectory = "C:\\ChildApp\\";
processStartInfo.fileName = "ChildApp.exe";
processStartInfo.Arguments = "";
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(processStartInfo);
proc.WaitForInputIdle();
return proc;
}
The external window is reparented by the following instructions :
public class ApplicationHost : HwndHost
{
private const uint LBS_NOTIFY = 0x00000001;
private const uint WS_BORDER = 0x00800000;
private const int SWP_NO_ACTIVATE = 0x0010;
private const int GWL_STYLE = -16;
private const int WS_CAPTION = 0x00C00000;
private const int WS_THICKFRAME = 0x00040000;
private const uint WS_VISIBLE = 0x10000000;
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll"), SetLastError = true]
private static extern int GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
public IntPtr ApplicationHandle { get; set; }
...
protected override HandleRef BuildWindowCore (HandleRef hwndParent)
{
var result = new HandleRef(this, ApplicationHandle);
if (ApplicationHandle.ToInt32() == 0)
{
return result;
}
var oldParent = SetParent(ApplicationHandle, hwndParent.Handle);
var styles = GetWindowLong(ApplicationHandle, GWL_STYLE);
styles |= WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY;
styles &= ~WS_CAPTION;
SetWindowLong32(ApplicationHandle, GWL_STYLE, styles);
return result;
}
...
}
I also tried the following version :
...
protected override HandleRef BuildWindowCore (HandleRef hwndParent)
{
SetParent(ApplicationHandle, hwndParent.Handle);
int style = GetWindowLong(ApplicationHandle, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(ApplicationHandle, GWL_STYLE, style);
}
...
The process of the app to be hosted start without problem but the SetParent doesn't seem to work and I get the following message while the method BuildWindowCore has been passed whatever the way the setParent is done :
"An unhandled exception of type 'System.InvalidOperationException' occured in PresentationFramework.dll"
Additional Information : Hosted HWND must be a child window of the specified parent. "
I tried a lot of things found on stackoverflow but I still have this same InvalidOperationException thrown and have no clue on how to fix that.
Could you please help me ?
Regards,
I presume that you have the source to the Qt application. In that code, you must create a function that will render() the widget on a QImage. Call that function from WPF, and copy the image from QImage's data() to a WriteableBitmap, and show that using a control. You can also forward the mouse and keyboard clicks in the opposite direction, and have a function that then synthesizes the QEvents to interact with the widget.
I am writing an application that needs to draw outside of it's main window area. I already have to code to actually do the drawing:
[DllImport("User32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("User32.dll")]
public static extern void ReleaseDC(IntPtr hwnd, IntPtr dc);
IntPtr desktopPtr = GetDC(IntPtr.Zero);
Graphics g = Graphics.FromHdc(desktopPtr);
g.DrawLine(Pens.White, 0, 0, Screen.FromControl(this).WorkingArea.Width, Screen.FromControl(this).WorkingArea.Height);
g.Dispose();
ReleaseDC(IntPtr.Zero, desktopPtr);
However the on paint event is an unsuitable place to put the code because it's not called when something outside of the form is redrawn. So my question is, where could this code be placed so it is called whenever part of the screen is redrawn?
If you want content painted on the screen, you should always create a window to hold that content. Painting on the desktop (a window that you don't own) is a bad idea.
The solution is to create a window, with the extended style WS_EX_NOACTIVATE and draw on that in response to WM_PAINT messages. For a WinForms application, the runtime calls Form.OnPaint when you get a WM_PAINT so you can handle that event and do the painting there. To demonstrate:
[DllImport("User32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int index);
[DllImport("User32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int index, IntPtr value);
[DllImport("User32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOZORDER = 0x0004;
private const uint SWP_FRAMECHANGED = 0x0020;
private const uint StyleUpdateFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED;
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.Paint += Form1_Paint;
this.Shown += Form1_Shown;
}
private void Form1_Shown(object sender, EventArgs e)
{
IntPtr currentStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
int current = currentStyle.ToInt32();
current |= WS_EX_NOACTIVATE;
SetWindowLong(this.Handle, GWL_EXSTYLE, new IntPtr(current));
SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0, StyleUpdateFlags);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Black);
}
If you want your window to float on top set the form's TopMost property to true. If you want your window to stick to the bottom of the Z-Order (the exact opposite of TopMost) then add the following logic to your form:
private struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;
}
private const int WM_WINDOWPOSCHANGING = 0x0046;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINDOWPOSCHANGING)
{
if (m.LParam != IntPtr.Zero)
{
WINDOWPOS posInfo = Marshal.PtrToStructure<WINDOWPOS>(m.LParam);
posInfo.hwndInsertAfter = HWND_BOTTOM;
Marshal.StructureToPtr(posInfo, m.LParam, true);
m.Result = IntPtr.Zero;
return;
}
}
base.WndProc(ref m);
}
This handles the WM_WINDOWPOSCHANGING window message, and prevents the window from moving up in the Z-Order by telling the window manager to put it at the bottom.
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.