Add screen modes in settings - c#

I've created UI options menu for graphics and screen. The thing is that I was able to add obly a boolean value for fullScreen mode. I need to add a dropdown with 3 modes: fullscreen, windowed, and windowed with no frame (stretched to the entire screen size). How do I get the third mode?

Check out this sample code. It uses the user32.dll library, though, so you most likely need to reference it in your project.
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Diagnostics;
using UnityEngine;
public class WindowMod : MonoBehaviour
{
public Rect screenPosition;
[DllImport("user32.dll")]
static extern IntPtr SetWindowLong (IntPtr hwnd,int _nIndex ,int dwNewLong);
[DllImport("user32.dll")]
static extern bool SetWindowPos (IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow ();
// not used rigth now
//const uint SWP_NOMOVE = 0x2;
//const uint SWP_NOSIZE = 1;
//const uint SWP_NOZORDER = 0x4;
//const uint SWP_HIDEWINDOW = 0x0080;
const uint SWP_SHOWWINDOW = 0x0040;
const int GWL_STYLE = -16;
const int WS_BORDER = 1;
void Start ()
{
SetWindowLong(GetForegroundWindow (), GWL_STYLE, WS_BORDER);
bool result = SetWindowPos (GetForegroundWindow (), 0,(int)screenPosition.x,(int)screenPosition.y, (int)screenPosition.width,(int) screenPosition.height, SWP_SHOWWINDOW);
}
With this method your best bet would be to:
Create an enum for all options, for example public enum WindowMode { FullScreen, Borderless, Window }
Create a manager class with a method that takes the enum as an argument: public void SetWindowMode(WindowMode wm // or int) {...}
Wire it up so that the method is called whenever an item is selected from the ComboBox on the Options menu with the UUI's EventSystem thingy
That's pretty much it.

Related

Process that started in an MDI Container stays always on top

I am working on a Winforms product. This product has an MDI main window, data presentation forms and a software that is developed for this project which is started in the Main Window if the related button is clicked. The software is called as a process when the button is clicked and it's parent is set to the main window. Let's say the software is the TeraTerm for the demonstration.
private void barButtonItem2_ItemClick(object sender, ItemClickEventArgs e)
{
Process p2 = new Process();
ProcessStartInfo ps2 = new ProcessStartInfo(#"C:\Program Files (x86)\teraterm\ttermpro.exe", "");
p2 = Process.Start(ps2);
p2.EnableRaisingEvents = true;
var processResult = p2.WaitForInputIdle(10000); // Allow the process to open it's window
appWin1 = p2.MainWindowHandle;
// Put it into this form
Utilities.HideMinimizeButton(p2.MainWindowHandle);
Utilities.SetWindowPos(p2.MainWindowHandle, Utilities.HWND_BOTTOM, 0, 0, 0, 0, Utilities.SETPOS_FLAGS);
Utilities.SetParent(p2.MainWindowHandle, this.Handle);
}
Utilities class is basically a dll import class for the window handling of the processes. Its code is:
public static class Utilities
{
public static int GWL_STYLE = -16;
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 readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
public const UInt32 SWP_NOSIZE = 0x0001;
public const UInt32 SWP_NOOWNERZORDER = 0x0200;
public const UInt32 SWP_NOMOVE = 0x0002;
public const UInt32 SWP_SHOWWINDOW = 0x0040;
public const UInt32 SWP_NOZORDER = 0x0040;
public const UInt32 SETPOS_FLAGS = SWP_NOSIZE | SWP_SHOWWINDOW;
public const int SW_MAXIMIZE = 3;
public const int SW_MINIMIZE = 6;
public const int SW_SHOWDEFAULT = 10;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[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);
[DllImport("user32")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
internal static void HideMinimizeAndMaximizeButtons(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX));
}
internal static void HideMinimizeButton(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MINIMIZEBOX));
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
This code is works to put my process as an MDI child. The problem is; the process window is always top of the every child form. I tried calling SetWindowPos with HWND_BOTTOM but no luck.
You may see from here and here the process is at the top even it is not activated.
I achieved success using most of the code you used. Here is my image:
There are a number of minor but obviously important issues in your posted code, making it impossible to know what you're actually doing that is causing the error.
You call the HideMinimizeButton method but do not provide its definition. In my working code, I called the HideMinimizeAndMaximizeButtons method you expose in your Utilities class.
You omitted your static extern for GetWindowsLong and SetWindowLong, so we can't see what you did there...
Your SetWindowLong call in your utilities class tries to cast the final argument to int when the SetWindowsLong WinAPI function I see says that it should be uint.
My version of your Utilities class looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp8
{
class Utilities
{
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
public const UInt32 SWP_NOSIZE = 0x0001;
public const UInt32 SWP_NOOWNERZORDER = 0x0200;
public const UInt32 SWP_NOMOVE = 0x0002;
public const UInt32 SWP_SHOWWINDOW = 0x0040;
public const UInt32 SWP_NOZORDER = 0x0040;
public const UInt32 SETPOS_FLAGS = SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
[DllImport("user32")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
internal static void HideMinimizeAndMaximizeButtons(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (uint)(value & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX));
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
}
}
Clearly, this works for me. If it works for you too, kindly accept as the answer.

How to hide game form's close button?

It's somewhat easy to find a way to do this in a winforms application, but in XNA I can't make the code snippets work as intended. I also don't want to disable the system buttons at all, I still need maximize and minimize buttons.
How do I disable the close button (x) on XNA game form without disabling the other buttons?
Define this in your code
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
internal const UInt32 SC_CLOSE = 0xF060;
internal const UInt32 MF_ENABLED = 0x00000000;
internal const UInt32 MF_GRAYED = 0x00000001;
internal const UInt32 MF_DISABLED = 0x00000002;
internal const uint MF_BYCOMMAND = 0x00000000;
Then use this function to disable or enable the close button
public void EnableOrDisableCloseButton(bool Enabled)
{
IntPtr hSystemMenu = GetSystemMenu(this.Window.Handle, false);
EnableMenuItem(hSystemMenu, SC_CLOSE, (uint)(MF_ENABLED | (Enabled ? MF_ENABLED : MF_GRAYED)));
}

programmatically mouse click in another window

Is it possible to click programmatically a location in another window without moving the mouse to that location and even if the window is not on-top? I want to send a kind of message to another window to simulate a mouse click on a location.
I tried to accomplish this with PostMessage:
PostMessage(WindowHandle, 0x201, IntPtr.Zero, CreateLParam(300,300));
PostMessage(WindowHandle, 0x202, IntPtr.Zero, CreateLParam(300,300));
I made the CreateLParam function this way:
private static IntPtr CreateLParam(int LoWord, int HiWord)
{
return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}
The problem is that the window gets locked on his location. I think that my application clicks on the (1,1) coordinate. Can some on help me with this problem?
Edit:
This is PostMessage:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr WindowHandle, int Msg, IntPtr wParam, IntPtr lParam);
And 0x201 and 0x202 are WM_LBUTTONDOWN and WM_LBUTTONUP respectively.
You can't do that by sending messages, instead use SendInput Windows API.
Call method ClickOnPoint, this is an example from form click event, so this.handle is form handle, note that these are client coordinates on window witch handle is send, you can easily change this and send screen coordinates, and in that case you don't need handle or ClientToScreen call below.
ClickOnPoint(this.Handle, new Point(375, 340));
UPDATE: using SendInput now, tnx Tom.
btw. I used only declarations needed for this sample, for anything more there is a nice library : Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse)
public class ClickOnPointTool
{
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
#pragma warning disable 649
internal struct INPUT
{
public UInt32 Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
[StructLayout(LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public MOUSEINPUT Mouse;
}
internal struct MOUSEINPUT
{
public Int32 X;
public Int32 Y;
public UInt32 MouseData;
public UInt32 Flags;
public UInt32 Time;
public IntPtr ExtraInfo;
}
#pragma warning restore 649
public static void ClickOnPoint(IntPtr wndHandle , Point clientPoint)
{
var oldPos = Cursor.Position;
/// get screen coordinates
ClientToScreen(wndHandle, ref clientPoint);
/// set cursor on coords, and press mouse
Cursor.Position = new Point(clientPoint.X, clientPoint.Y);
var inputMouseDown = new INPUT();
inputMouseDown.Type = 0; /// input type mouse
inputMouseDown.Data.Mouse.Flags = 0x0002; /// left button down
var inputMouseUp = new INPUT();
inputMouseUp.Type = 0; /// input type mouse
inputMouseUp.Data.Mouse.Flags = 0x0004; /// left button up
var inputs = new INPUT[] { inputMouseDown, inputMouseUp };
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
/// return mouse
Cursor.Position = oldPos;
}
}
I found in the past, a way to send message to Windows Media Player
so I used that to simulate click in application I wanted!
Using this class (code below) to find the window and to send messages you want!
using System;
using System.Runtime.InteropServices;
namespace Mouse_Click_Simulator
{
/// <summary>
/// Summary description for Win32.
/// </summary>
public class Win32
{
// The WM_COMMAND message is sent when the user selects a command item from
// a menu, when a control sends a notification message to its parent window,
// or when an accelerator keystroke is translated.
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_COMMAND = 0x111;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_LBUTTONUP = 0x202;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_RBUTTONUP = 0x205;
public const int WM_RBUTTONDBLCLK = 0x206;
// The FindWindow function retrieves a handle to the top-level window whose
// class name and window name match the specified strings.
// This function does not search child windows.
// This function does not perform a case-sensitive search.
[DllImport("User32.dll")]
public static extern int FindWindow(string strClassName, string strWindowName);
// The FindWindowEx function retrieves a handle to a window whose class name
// and window name match the specified strings.
// The function searches child windows, beginning with the one following the
// specified child window.
// This function does not perform a case-sensitive search.
[DllImport("User32.dll")]
public static extern int FindWindowEx(
int hwndParent,
int hwndChildAfter,
string strClassName,
string strWindowName);
// The SendMessage function sends the specified message to a window or windows.
// It calls the window procedure for the specified window and does not return
// until the window procedure has processed the message.
[DllImport("User32.dll")]
public static extern Int32 SendMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
[MarshalAs(UnmanagedType.LPStr)] string lParam); // second message parameter
[DllImport("User32.dll")]
public static extern Int32 SendMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
int lParam); // second message parameter
}
}
For Example:
Win32.SendMessage(iHandle, Win32.WM_LBUTTONDOWN, 0x00000001, 0x1E5025B);
Here's My Application Source Code that I Created to auto click in "BlueStacks" Application in a specific interval!
For FindWindow, wParam, lParam, etc. you can feel free to ask me how to do it! it's not too hard :) ;)
Hope it helped! :)
I can't add a comment :D
Work for me:
[DllImport("User32.dll")]
public static extern Int32 SendMessage(
int hWnd,
int Msg,
int wParam,
IntPtr lParam);
and combine coord in lParam like this:
private static IntPtr CreateLParam(int LoWord, int HiWord)
{
return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}
and use:
Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONDOWN, 0x00000001, CreateLParam(150,150));
Clicktoapp.SendMessage(0x00040156, Clicktoapp.WM_LBUTTONUP, 0x00000000, CreateLParam(150, 150));
0x00040156 - Window Handle.
I was looking for a window handle using spy ++
Each time it is new, so it's better to use FindWindow.
P.S
Screenshot of the application window even if the window is not on top
https://stackoverflow.com/a/911225/12928587
i use this solution. work great.

SetWindowPos/MoveWindow persist issue

I am using SetWindowPos and MoveWindow to resize and center windows. It works fine, but on several windows like Windows Media Player or Control Panel, when you close the window and open it again, the new resizing/moving is not reflected. When I resize manually, the changes are reflected the next time I open the window. Even if I call UpdateWindow, the changes don't reflect. Is there something I need to send the window so the changes get saved? Would RedrawWindow help? Thanks?
You should be using the GetWindowPlacement and SetWindowPlacement functions instead to retrieve and alter the restored, minimized, and maximized positions of a window. This ensures that the window sizes are properly saved by the application so that they can be restored on the next launch.
Since you're using C#, you'll need to P/Invoke these functions from the Windows API:
const int SW_HIDE = 0;
const int SW_SHOWNORMAL = 1;
const int SW_SHOWMINIMIZED = 2;
const int SW_SHOWMAXIMIZED = 3;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public Point ptMinPosition;
public Point ptMaxPosition;
public RECT rcNormalPosition;
}

Why are Maximize/Minimize events causing the Close Button to be re-enabled after disabling it?

I have used P/Invoke to call GetSystemMenu and EnableMenuItem (win32api) to disable the close functionality. However, after minimizing or maximizing my Windows Forms application the button is re-enabled.
Obviously minimizing or maximizing is causing the behavior, but how? I'm not sure where to look to prevent this behavior.
Should I be preventing the maximize and minimize behavior or is there something particularly wrong with the way in which I P/Invoked the calls? Once the application (main form) has loaded, I call the static method from a button click.
class PInvoke
{
// P/Invoke signatures
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
// SysCommand (WM_SYSCOMMAND) constant
internal const UInt32 SC_CLOSE = 0xF060;
// Constants used with Add/Check/EnableMenuItem
internal const UInt32 MF_BYCOMMAND = 0x00000000;
internal const UInt32 MF_ENABLED = 0x00000000;
internal const UInt32 MF_GRAYED = 0x00000001;
internal const UInt32 MF_DISABLED = 0x00000002;
/// <summary>
/// Sets the state of the Close (X) button and the System Menu close functionality.
/// </summary>
/// <param name="window">Window or Form</param>
/// <param name="bEnabled">Enabled state</param>
public static void EnableCloseButton(IWin32Window window, bool bEnabled)
{
IntPtr hSystemMenu = GetSystemMenu(window.Handle, false);
EnableMenuItem(hSystemMenu, SC_CLOSE, MF_BYCOMMAND | (bEnabled ? MF_ENABLED : MF_GRAYED));
}
}
Each window has a window class, which defines styles for all windows of that class. You can use CS_NOCLOSE class style to remove the close button for windows of that class. See here and here for details how to set this class flag.
If this doesn't give you what you want, I wouldn't disable minimize/maximize for sake of usability, but you could listen for minimize/maximimize events and re-run the code to disable the close button. Finally, it is possible to handle the close event, and simply not close. Then you know your window will definitely not be closed, even if the close button does inadvertently become enabled.
The accepted answer does propose a possible workaround to the problem (and one that I've used many times), but it simply doesn't answer the question that was originally asked:
How/why does maximizing or minimizing the form cause the close button to be re-enabled after it was disabled using the GetSystemMenu and EnableMenuItem API functions?
I arrived at this question during the course of a completely fruitless Google search after discovering this seemingly unexplainable behavior for myself. Not finding an answer that actually explained the behavior,I was forced to resort to some digging of my own.
For reference, note that the exact same code as shown in the original question works fine in a native Win32 application. The re-enabling of the Close menu item seems limited to WinForms applications.
Studying the source code for the System.Windows.Forms.Form class uncovers an interesting implementation detail: The .NET Framework designers apparently decided to adjust the form's system menu each time that the form's WindowState changes, which includes maximize and minimize events sent by the system.
Specifically, there are two methods by the name AdjustSystemMenu that are responsible for altering the system menu in response to the these events (and messing up any customization that you may have done yourself). If you're interested in examining the code (which I have abstained from posting here for the benefit of those involved with projects such as Mono), grab a free copy of .NET Reflector.
I'm not entirely sure why this decision was made, but at least I have my explanation now.
I had the same requirement. After trying several ways to disable the close menu option and then deleting and trying to recreate it (correctly), I found this hack from Microsoft http://support.microsoft.com/kb/184686 .
Works like a charm. It's still a hack, but it works.
Here's my (loose) C# conversion of the VB original
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);
public static void EnableCloseButton(Form frm, bool enabled) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
n = GetMenuItemCount(hMenu);
if (n > 0) {
if (enabled) {
EnableClose(frm);
}
else {
DisableClose(frm);
}
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
DrawMenuBar(frm.Handle);
Application.DoEvents();
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MENUITEMINFO {
public uint cbSize;
public uint fMask;
public uint fType;
public uint fState;
public int wID;
public int hSubMenu;
public int hbmpChecked;
public int hbmpUnchecked;
public int dwItemData;
public string dwTypeData;
public uint cch;
// public int hbmpItem;
}
internal const UInt32 SC_CLOSE = 0xF060;
//SetMenuItemInfo fMask constants.
const UInt32 MIIM_STATE = 0x1;
const UInt32 MIIM_ID = 0x2;
//'SetMenuItemInfo fState constants.
const UInt32 MFS_ENABLED = 0x0;
const UInt32 MFS_GRAYED = 0x3;
const UInt32 MFS_CHECKED = 0x8;
internal const int MFS_DEFAULT = 0x1000;
[DllImport("user32.dll")]
static extern bool SetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, [In] ref MENUITEMINFO lpmii);
[DllImport("user32.dll")]
static extern bool GetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, ref MENUITEMINFO lpmii);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private const UInt32 WM_NCACTIVATE = 0x0086;
private static void DisableClose(Form frm) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
MENUITEMINFO mif = new MENUITEMINFO();
mif.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));
mif.fMask = MIIM_ID | MIIM_STATE;
mif.fType = 0;
mif.dwTypeData = null;
bool a = GetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
mif.fState = MFS_GRAYED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
mif.wID = -10;
mif.fState = MFS_GRAYED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
}
}
private static void EnableClose(Form frm) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
MENUITEMINFO mif = new MENUITEMINFO();
mif.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));
mif.fMask = MIIM_ID | MIIM_STATE;
mif.fType = 0;
mif.dwTypeData = null;
bool a = GetMenuItemInfo(hMenu, -10, false, ref mif);
mif.wID = (int)SC_CLOSE;
SetMenuItemInfo(hMenu, -10, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
mif.fState = MFS_ENABLED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
}
}

Categories