Is there an easy method to restore a minimized form to its previous state, either Normal or Maximized? I'm expecting the same functionality as clicking the taskbar (or right-clicking and choosing restore).
So far, I have this, but if the form was previously maximized, it still comes back as a normal window.
if (docView.WindowState == FormWindowState.Minimized)
docView.WindowState = FormWindowState.Normal;
Do I have to handle the state change in the form to remember the previous state?
I use the following extension method:
using System.Runtime.InteropServices;
namespace System.Windows.Forms
{
public static class Extensions
{
[DllImport( "user32.dll" )]
private static extern int ShowWindow( IntPtr hWnd, uint Msg );
private const uint SW_RESTORE = 0x09;
public static void Restore( this Form form )
{
if (form.WindowState == FormWindowState.Minimized)
{
ShowWindow(form.Handle, SW_RESTORE);
}
}
}
}
Then call form.Restore() in my code.
The easiest way to restore a form to normal state is:
if (MyForm.WindowState == FormWindowState.Minimized)
{
MyForm.WindowState = FormWindowState.Normal;
}
You could simulate clicking on the taskbar button like this:
SendMessage(docView.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
For me, the code above does NOT work.
But at last I found the working code. Here it is:
CxImports.ManagedWindowPlacement placement = new CxImports.ManagedWindowPlacement();
CxImports.GetWindowPlacement(Convert.ToUInt32(Handle.ToInt64()), placement);
if (placement.flags == CxImports.WPF_RESTORETOMAXIMIZED)
WindowState = FormWindowState.Maximized;
else
WindowState = FormWindowState.Normal;
I guess, you can find all the needed "imported" functions by simple googling.
If anybody wonders how to do that with other apps windows,this code works for me:
public void UnMinimize(IntPtr handle)
{
WINDOWPLACEMENT WinPlacement = new WINDOWPLACEMENT();
GetWindowPlacement(handle, out WinPlacement);
if(WinPlacement.flags.HasFlag(WINDOWPLACEMENT.Flags.WPF_RESTORETOMAXIMIZED))
{
ShowWindow(handle, (int)SW_MAXIMIZE);
}
else
{
ShowWindow(handle, (int)SW_RESTORE);
}
}
Stuff is here:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public Int32 Left;
public Int32 Top;
public Int32 Right;
public Int32 Bottom;
}
public struct POINT
{
public int x;
public int y;
}
public struct WINDOWPLACEMENT
{
[Flags]
public enum Flags : uint
{
WPF_ASYNCWINDOWPLACEMENT = 0x0004,
WPF_RESTORETOMAXIMIZED = 0x0002,
WPF_SETMINPOSITION = 0x0001
}
/// <summary>
/// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT).
/// </summary>
public uint length;
/// <summary>
/// The flags that control the position of the minimized window and the method by which the window is restored. This member can be one or more of the following values.
/// </summary>
///
public Flags flags;//uint flags;
/// <summary>
/// The current show state of the window. This member can be one of the following values.
/// </summary>
public uint showCmd;
/// <summary>
/// The coordinates of the window's upper-left corner when the window is minimized.
/// </summary>
public POINT ptMinPosition;
/// <summary>
/// The coordinates of the window's upper-left corner when the window is maximized.
/// </summary>
public POINT ptMaxPosition;
/// <summary>
/// The window's coordinates when the window is in the restored position.
/// </summary>
public RECT rcNormalPosition;
}
public class UnMinimizeClass
{
[DllImport("user32.dll")]
public static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_MAXIMIZE = 3;
const int SW_RESTORE = 9;
public static void UnMinimize(IntPtr handle)
{
WINDOWPLACEMENT WinPlacement = new WINDOWPLACEMENT();
GetWindowPlacement(handle, out WinPlacement);
if (WinPlacement.flags.HasFlag(WINDOWPLACEMENT.Flags.WPF_RESTORETOMAXIMIZED))
{
ShowWindow(handle, SW_MAXIMIZE);
}
else
{
ShowWindow(handle, (int)SW_RESTORE);
}
}
}
Using MainWindow.WindowState = WindowState.Normal; isn't enough
Next approach works for my WPF applcation:
MainWindow.WindowState = WindowState.Normal;
MainWindow.Show();
MainWindow.Activate();
I just added one more piece to generify the solution given by #Mesmo. It will create the instance if not created or restore and focus the form if the instance is already created from anywhere in the application. My requirement was that I didn't want to open multiple forms for some of the functionality in the application.
Utilities Class:
public static class Utilities
{
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hWnd, uint Msg);
private const uint SW_RESTORE = 0x09;
public static void Restore(this Form form)
{
if (form.WindowState == FormWindowState.Minimized)
{
ShowWindow(form.Handle, SW_RESTORE);
}
}
public static void CreateOrRestoreForm<T>() where T: Form
{
Form form = Application.OpenForms.OfType<T>().FirstOrDefault();
if (form == null)
{
form = Activator.CreateInstance<T>();
form.Show();
}
else
{
form.Restore();
form.Focus();
}
}
}
Usage:
Utilities.CreateOrRestoreForm<AboutForm>();
This is simple and works if you don't want to use any PInvoke or API trickery. Keep track of when the form has been resized, ignoring when it is minimised.
FormWindowState _PreviousWindowState;
private void TestForm_Resize(object sender, EventArgs e)
{
if (WindowState != FormWindowState.Minimized)
_PreviousWindowState = WindowState;
}
Later when you want to restore it -- for example if a tray icon is clicked:
private void Tray_MouseClick(object sender, MouseEventArgs e)
{
Activate();
if (WindowState == FormWindowState.Minimized)
WindowState = _PreviousWindowState; // former glory
}
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hWnd, ref wndRect lpRect);
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")] public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);//用来遍历所有窗口
[DllImport("user32.dll")] public static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);//获取窗口Text
[DllImport("user32.dll")] public static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);//获取窗口类名
public static List<wndInfo> GetAllDesktopWindows(bool? isVisitable_)
{
//用来保存窗口对象
List<wndInfo> wndList = new List<wndInfo>();
//enum all desktop windows
EnumWindows(delegate (IntPtr hWnd, int lParam)
{
wndInfo wnd = new wndInfo();
StringBuilder sb = new StringBuilder(256);
//get hwnd
wnd.hWnd = hWnd;
if (isVisitable_ == null || IsWindowVisible(wnd.hWnd) == isVisitable_)
{
//get window name
GetWindowTextW(hWnd, sb, sb.Capacity);
wnd.szWindowName = sb.ToString();
//get window class
GetClassNameW(hWnd, sb, sb.Capacity);
wnd.szClassName = sb.ToString();
wndList.Add(wnd);
}
return true;
}, 0);
return wndList;
}
private void Btn_Test5_Click(object sender, RoutedEventArgs e)
{
var ws = WSys.GetAllDesktopWindows(true);
foreach (var w in ws)
{
if (w.szWindowName == "计算器")
{
WSys.ShowWindow(w.hWnd, 5);
WSys.ShowWindow(w.hWnd, 9);
Log.WriteLine(w.szWindowName);
}
}
}
The above code did not quite work for me in all situations
After checking the flags I also have to check showcmd=3 and if so maximise else restore
Related
I have a WPF window that is supposed to be a "desktop gadget".
My users are asking for a way to prevent it from disappearing when they hit "Show Desktop".
Making the window always topmost works but some of my users do not want the window always on top.
Short of running a timer every x seconds to activate the window, is there a proper way to achieve this?
I ended up developing my own solution.
I scoured the internet for weeks trying to find an answer so I'm kind of proud of this one.
So what we do is use pinvoke to create a hook for the EVENT_SYSTEM_FOREGROUND window event.
This event triggers whenever the foreground window is changed.
Now what I noticed is when the "Show Desktop" command is issued, the WorkerW window class becomes foreground.
Note this WorkerW window is not the desktop and I confirmed the hwnd of this WorkerW window is not the Desktop hwnd.
So what we do is whenever the WorkerW window becomes the foreground, we set our "WPF Gadget Window" to be topmost!
Whenever a window other the WorkerW window becomes the foreground, we remove topmost from our "WPF Gadget Window".
If you want to take it a step further, you can uncomment out the part where I check if the new foreground window is also "PROGMAN", which is the Desktop window.
However, this will lead to your window becoming topmost if the user clicks their desktop on a different monitor. In my case, I did not want this behavior, but I figured some of you might.
Confirmed to work in Windows 10. Should work in older versions of Windows.
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
namespace YourNamespace
{
internal static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, ShowDesktop.WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
internal static extern int GetClassName(IntPtr hwnd, StringBuilder name, int count);
}
public static class ShowDesktop
{
private const uint WINEVENT_OUTOFCONTEXT = 0u;
private const uint EVENT_SYSTEM_FOREGROUND = 3u;
private const string WORKERW = "WorkerW";
private const string PROGMAN = "Progman";
public static void AddHook(Window window)
{
if (IsHooked)
{
return;
}
IsHooked = true;
_delegate = new WinEventDelegate(WinEventHook);
_hookIntPtr = NativeMethods.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _delegate, 0, 0, WINEVENT_OUTOFCONTEXT);
_window = window;
}
public static void RemoveHook()
{
if (!IsHooked)
{
return;
}
IsHooked = false;
NativeMethods.UnhookWinEvent(_hookIntPtr.Value);
_delegate = null;
_hookIntPtr = null;
_window = null;
}
private static string GetWindowClass(IntPtr hwnd)
{
StringBuilder _sb = new StringBuilder(32);
NativeMethods.GetClassName(hwnd, _sb, _sb.Capacity);
return _sb.ToString();
}
internal delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
private static void WinEventHook(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
string _class = GetWindowClass(hwnd);
if (string.Equals(_class, WORKERW, StringComparison.Ordinal) /*|| string.Equals(_class, PROGMAN, StringComparison.Ordinal)*/ )
{
_window.Topmost = true;
}
else
{
_window.Topmost = false;
}
}
}
public static bool IsHooked { get; private set; } = false;
private static IntPtr? _hookIntPtr { get; set; }
private static WinEventDelegate _delegate { get; set; }
private static Window _window { get; set; }
}
}
You can use "StateChanged" event of the window. It fires when "WindowState" property changes. You can use this event and maximize the window when the state changed to minimized.
UPDATE
Try this code:
private async void Window_StateChanged_1(object sender, EventArgs e)
{
await MaximizeWindow(this);
}
public Task MaximizeWindow(Window window)
{
return Task.Factory.StartNew(() =>
{
this.Dispatcher.Invoke((Action)(() =>
{
Thread.Sleep(100);
window.WindowState = System.Windows.WindowState.Maximized;
}));
});
}
I try to change my gamma of just one screen and not all my screens.
I use this code to help me
But this SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref s_ramp);
Is for all devices.
[EDIT2] I saw one weird thing : SetDeviceGammaRamp is not the same gamma of the Nvidia Panel Controller (I tried to change my value of SetDeviceGammaRamp, and it's like if i changed the value of brightness and contrast in the Nvidia panel). So i think i must to use NVidia API :/
So, how can i change this code to put my gamma on my first screen, or my second, but not both
[EDIT1] This is what i made :
class Monitor
{
[DllImport("user32.dll")]
static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
public delegate int MonitorEnumProc(IntPtr hMonitor, IntPtr hDCMonitor, ref Rect lprcMonitor, IntPtr dwData);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hmon, ref MonitorInfo mi);
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
/// <summary>
/// The struct that contains the display information
/// </summary>
public class DisplayInfo
{
public string Availability { get; set; }
public string ScreenHeight { get; set; }
public string ScreenWidth { get; set; }
public Rect MonitorArea { get; set; }
public Rect WorkArea { get; set; }
public IntPtr DC { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
public uint size;
public Rect monitor;
public Rect work;
public uint flags;
}
/// <summary>
/// Collection of display information
/// </summary>
public class DisplayInfoCollection : List<DisplayInfo>
{
}
/// <summary>
/// Returns the number of Displays using the Win32 functions
/// </summary>
/// <returns>collection of Display Info</returns>
public DisplayInfoCollection GetDisplays()
{
DisplayInfoCollection col = new DisplayInfoCollection();
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData)
{
MonitorInfo mi = new MonitorInfo();
mi.size = (uint)Marshal.SizeOf(mi);
bool success = GetMonitorInfo(hMonitor, ref mi);
if (success)
{
DisplayInfo di = new DisplayInfo();
di.ScreenWidth = (mi.monitor.right - mi.monitor.left).ToString();
di.ScreenHeight = (mi.monitor.bottom - mi.monitor.top).ToString();
di.MonitorArea = mi.monitor;
di.WorkArea = mi.work;
di.Availability = mi.flags.ToString();
di.DC = GetDC(hdcMonitor);
col.Add(di);
}
return 1;
}, IntPtr.Zero);
return col;
}
public Monitor()
{
}
}
And for SetDeviceGammaRamp, i made this :
GammaRamp gamma = new GammaRamp();
Monitor.DisplayInfoCollection monitors;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor monitor = new Monitor();
monitors = monitor.GetDisplays();
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
int value = trackBar1.Value;
gamma.SetValue(Convert.ToByte(value), monitors[1].DC);
}
GammaRamp class :
public void SetValue(byte value, IntPtr hdc)
{
Ramp gammaArray = new Ramp { Red = new ushort[256], Green = new ushort[256], Blue = new ushort[256] };
for (int i = 0; i < 256; i++)
{
gammaArray.Red[i] = gammaArray.Green[i] = gammaArray.Blue[i] = (ushort)Math.Min(i * (value + 128), ushort.MaxValue);
}
SetDeviceGammaRamp(hdc, ref gammaArray);
}
You can get the DC of another monitor by using EnumDisplayMonitors or GetMonitorInfo functions.
See complete explanations at HMONITOR and the Device Context.
EDIT
As explained in EnumDisplayMonitors,
pass IntPtr.Zero to hdc parameter (values encompasses all displays)
then in MONITORENUMPROC, hdcMonitor should contain the right DC for the current monitor being evaluated
then change your di.DC = GetDC(IntPtr.Zero); to di.DC = GetDC(hdcMonitor);
(passing Zero to GetDC will obviously specify all monitors, not what you want)
EDIT 2
Little confusion with the docs, in fact the 3rd type of call in the remarks of EnumDisplayMonitors should be performed:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow
{
private readonly List<IntPtr> _dcs = new List<IntPtr>();
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var hdc = NativeMethods.GetDC(IntPtr.Zero);
if (hdc == IntPtr.Zero)
throw new InvalidOperationException();
if (!NativeMethods.EnumDisplayMonitors(hdc, IntPtr.Zero, Monitorenumproc, IntPtr.Zero))
throw new InvalidOperationException();
if (NativeMethods.ReleaseDC(IntPtr.Zero, hdc) == 0)
throw new InvalidOperationException();
foreach (var monitorDc in _dcs)
{
// do something cool !
}
}
private int Monitorenumproc(IntPtr param0, IntPtr param1, ref tagRECT param2, IntPtr param3)
{
// optional actually ...
var info = new MonitorInfo {cbSize = (uint) Marshal.SizeOf<MonitorInfo>()};
if (!NativeMethods.GetMonitorInfoW(param0, ref info))
throw new InvalidOperationException();
_dcs.Add(param1); // grab DC for current monitor !
return 1;
}
}
public class NativeMethods
{
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
public static extern int ReleaseDC([In] IntPtr hWnd, [In] IntPtr hDC);
[DllImport("user32.dll", EntryPoint = "GetDC")]
public static extern IntPtr GetDC([In] IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetMonitorInfoW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorInfoW([In] IntPtr hMonitor, ref MonitorInfo lpmi);
[DllImport("user32.dll", EntryPoint = "EnumDisplayMonitors")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDisplayMonitors([In] IntPtr hdc, [In] IntPtr lprcClip, MONITORENUMPROC lpfnEnum,
IntPtr dwData);
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int MONITORENUMPROC(IntPtr param0, IntPtr param1, ref tagRECT param2, IntPtr param3);
[StructLayout(LayoutKind.Sequential)]
public struct MonitorInfo
{
public uint cbSize;
public tagRECT rcMonitor;
public tagRECT rcWork;
public uint dwFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagRECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}
You should be able to get per-monitor DC, (cannot 100% confirm since I only have one screen).
If all else fails then maybe that NVidia thing interferes somehow under the hood.
I'm trying to write a certificate manager, and I want to manage the permissions over the certificate file. I'd prefer not reinventing the wheel of the Windows permissions dialog, so ideally there would be some kind of shell command that I could pass the path of the item whose permissions are being managed. Then, I could just invoke it and let the shell take care of updating the permissions.
I've seen some mention here and there of a shell function, SHObjectProperties, but nothing clear on how to use it. Any help would be appreciated.
You can display the Windows file permissions dialog using ShellExecuteEx (using the "properties" verb and the "Security" parameter).
This will display a dialog like the following within your process, and the file permission viewing and editing will be fully functional just as if you had got this dialog through the Windows explorer shell:
Here is an example with Windows Forms where a file is selected and the Security properties of that file then displayed. I have used the P/Invoke code for ShellExecuteEx from this Stackoverflow answer.
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FileSecurityProperties
{
public partial class FileSelectorForm : Form
{
private static bool ShowFileSecurityProperties(string Filename, IntPtr parentHandle)
{
SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info);
info.lpVerb = "properties";
info.lpFile = Filename;
info.nShow = SW_SHOW;
info.fMask = SEE_MASK_INVOKEIDLIST;
info.hwnd = parentHandle;
info.lpParameters = "Security"; // Opens the file properties on the Security tab
return ShellExecuteEx(ref info);
}
private void fileSelectButton_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
ShowFileSecurityProperties(
openFileDialog.FileName,
this.Handle); // Pass parent window handle for properties dialog
}
}
#region P/Invoke code for ShellExecuteEx from https://stackoverflow.com/a/1936957/4486839
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHELLEXECUTEINFO
{
public int cbSize;
public uint fMask;
public IntPtr hwnd;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpVerb;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpParameters;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDirectory;
public int nShow;
public IntPtr hInstApp;
public IntPtr lpIDList;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpClass;
public IntPtr hkeyClass;
public uint dwHotKey;
public IntPtr hIcon;
public IntPtr hProcess;
}
private const int SW_SHOW = 5;
private const uint SEE_MASK_INVOKEIDLIST = 12;
#endregion
#region Irrelevant Windows forms code
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
this.fileSelectButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// openFileDialog1
//
this.openFileDialog.FileName = "";
//
// fileSelectButton
//
this.fileSelectButton.Location = new System.Drawing.Point(52, 49);
this.fileSelectButton.Name = "fileSelectButton";
this.fileSelectButton.Size = new System.Drawing.Size(131, 37);
this.fileSelectButton.TabIndex = 0;
this.fileSelectButton.Text = "Select file ...";
this.fileSelectButton.UseVisualStyleBackColor = true;
this.fileSelectButton.Click += new System.EventHandler(this.fileSelectButton_Click);
//
// FileSelectorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(248, 162);
this.Controls.Add(this.fileSelectButton);
this.Name = "FileSelectorForm";
this.Text = "File Selector";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.OpenFileDialog openFileDialog;
private System.Windows.Forms.Button fileSelectButton;
public FileSelectorForm()
{
InitializeComponent();
}
#endregion
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FileSelectorForm());
}
}
}
If you were hoping to get the file permissions dialog on its own, rather than as a tab in the general file properties dialog, that is possible using aclui.dll, e.g. using the EditSecurity function, but this will NOT then give you your other requirement of having the file permissions handling taken care of for you, because you have to provide an interface which does the getting and setting of security properties if you go down that route, and it looks like a lot of coding.
Here is a utilily class that allows you to have only the security property sheet (not all sheets the shell displays).
You can call it like this in a console app:
class Program
{
[STAThread]
static void Main(string[] args)
{
// NOTE: if the dialog looks old fashioned (for example if used in a console app),
// then add an app.manifest and uncomment the dependency section about Microsoft.Windows.Common-Controls
PermissionDialog.Show(IntPtr.Zero, #"d:\temp\killroy_was_here.png");
}
}
or like this in a winform app
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
PermissionDialog.Show(IntPtr.Zero, #"d:\temp\killroy_was_here.png");
}
}
And this is the main class. It's basically using the same thing as the shell, but in its own property sheet.
public static class PermissionDialog
{
public static bool Show(IntPtr hwndParent, string path)
{
if (path == null)
throw new ArgumentNullException("path");
SafePidlHandle folderPidl;
int hr;
hr = SHILCreateFromPath(Path.GetDirectoryName(path), out folderPidl, IntPtr.Zero);
if (hr != 0)
throw new Win32Exception(hr);
SafePidlHandle filePidl;
hr = SHILCreateFromPath(path, out filePidl, IntPtr.Zero);
if (hr != 0)
throw new Win32Exception(hr);
IntPtr file = ILFindLastID(filePidl);
System.Runtime.InteropServices.ComTypes.IDataObject ido;
hr = SHCreateDataObject(folderPidl, 1, new IntPtr[] { file }, null, typeof(System.Runtime.InteropServices.ComTypes.IDataObject).GUID, out ido);
if (hr != 0)
throw new Win32Exception(hr);
// if you get a 'no such interface' error here, make sure the running thread is STA
IShellExtInit sei = (IShellExtInit)new SecPropSheetExt();
sei.Initialize(IntPtr.Zero, ido, IntPtr.Zero);
IShellPropSheetExt spse = (IShellPropSheetExt)sei;
IntPtr securityPage = IntPtr.Zero;
spse.AddPages((p, lp) =>
{
securityPage = p;
return true;
}, IntPtr.Zero);
PROPSHEETHEADER psh = new PROPSHEETHEADER();
psh.dwSize = Marshal.SizeOf(psh);
psh.hwndParent = hwndParent;
psh.nPages = 1;
psh.phpage = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(psh.phpage, securityPage);
// TODO: adjust title & icon here, also check out the available flags
psh.pszCaption = "Permissions for '" + path + "'";
IntPtr res;
try
{
res = PropertySheet(ref psh);
}
finally
{
Marshal.FreeHGlobal(psh.phpage);
}
return res == IntPtr.Zero;
}
private class SafePidlHandle : SafeHandle
{
public SafePidlHandle()
: base(IntPtr.Zero, true)
{
}
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
protected override bool ReleaseHandle()
{
if (IsInvalid)
return false;
Marshal.FreeCoTaskMem(handle);
return true;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct PROPSHEETHEADER
{
public int dwSize;
public int dwFlags;
public IntPtr hwndParent;
public IntPtr hInstance;
public IntPtr hIcon;
public string pszCaption;
public int nPages;
public IntPtr nStartPage;
public IntPtr phpage;
public IntPtr pfnCallback;
}
[DllImport("shell32.dll")]
private static extern IntPtr ILFindLastID(SafePidlHandle pidl);
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHILCreateFromPath(string pszPath, out SafePidlHandle ppidl, IntPtr rgflnOut);
[DllImport("shell32.dll")]
private static extern int SHCreateDataObject(SafePidlHandle pidlFolder, int cidl, IntPtr[] apidl, System.Runtime.InteropServices.ComTypes.IDataObject pdtInner, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out System.Runtime.InteropServices.ComTypes.IDataObject ppv);
[DllImport("comctl32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr PropertySheet(ref PROPSHEETHEADER lppsph);
private delegate bool AddPropSheetPage(IntPtr page, IntPtr lParam);
[ComImport]
[Guid("1f2e5c40-9550-11ce-99d2-00aa006e086c")] // this GUID points to the property sheet handler for permissions
private class SecPropSheetExt
{
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214E8-0000-0000-C000-000000000046")]
private interface IShellExtInit
{
void Initialize(IntPtr pidlFolder, System.Runtime.InteropServices.ComTypes.IDataObject pdtobj, IntPtr hkeyProgID);
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214E9-0000-0000-C000-000000000046")]
private interface IShellPropSheetExt
{
void AddPages([MarshalAs(UnmanagedType.FunctionPtr)] AddPropSheetPage pfnAddPage, IntPtr lParam);
void ReplacePage(); // not fully defined, we don't use it
}
}
Opps my bad 'attrib' is how it used to be.
What you are looking to do I believe is "change security descriptors on folders and files". The command line tool is cacls.
Please see: http://en.wikipedia.org/wiki/Cacls
I'm using FlashWindowEx() to flash an application window when it needs to attract a user's attention. The window caption and taskbar button flashes continuously until the application receives focus. How can I check whether the application is currently flashing (i.e. has not received focus since it was instructed to flash).
Here are two possible solutions. One uses WH_SHELL, and one uses a NativeWindow. You will have to provide your own extension method (FlashWindow()) to start the flashing.
// base class. Two different forms subclass this form to illustrate two
// different solutions.
public class FormFlash : Form {
protected Label lb = new Label { Text = "Not flashing", Dock = DockStyle.Top };
public FormFlash() {
Controls.Add(lb);
Thread t = new Thread(() => {
Thread.Sleep(3000);
if (Form.ActiveForm == this)
SetForegroundWindow(GetDesktopWindow()); // deactivate the current form by setting the desktop as the foreground window
this.FlashWindow(); // call extension method to flash window
lb.BeginInvoke((Action) delegate {
lb.Text = "Flashing";
});
});
t.IsBackground = true;
t.Start();
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetDesktopWindow();
}
// this solution is a bit simpler. Relies on the programmer knowing when the
// flashing started. Uses a NativeWindow to detect when a WM_ACTIVATEAPP
// message happens, that signals the end of the flashing.
class FormFlashNW : FormFlash {
NW nw = null;
public FormFlashNW() {
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
nw = new NW(this.Handle, lb);
}
protected override void OnHandleDestroyed(EventArgs e) {
base.OnHandleDestroyed(e);
nw.ReleaseHandle();
}
class NW : NativeWindow {
Label lb = null;
public NW(IntPtr handle, Label lb) {
AssignHandle(handle);
this.lb = lb;
}
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
const int WM_ACTIVATEAPP = 0x1C;
if (m.Msg == WM_ACTIVATEAPP) {
lb.BeginInvoke((Action) delegate {
lb.Text = "Not flashing";
});
}
}
}
}
// this solution is more complicated. Relies on setting up the hook proc.
// The 'isFlashing' bool fires true and false alternating while the flashing
// is active.
public class FormShellHook : FormFlash {
public FormShellHook() {
FlashWindowExListener.Register(this);
FlashWindowExListener.FlashEvent += FlashExListener_FlashEvent;
}
void FlashExListener_FlashEvent(Form f, bool isFlashing) {
if (f == this) {
lb.Text = DateTime.Now.ToLongTimeString() + " is flashing: " + isFlashing;
}
}
}
public class FlashWindowExListener {
private delegate IntPtr CallShellProc(int nCode, IntPtr wParam, IntPtr lParam);
private static CallShellProc procShell = new CallShellProc(ShellProc);
private static Dictionary<IntPtr,Form> forms = new Dictionary<IntPtr,Form>();
private static IntPtr hHook = IntPtr.Zero;
public static event FlashWindowExEventHandler FlashEvent = delegate {};
public delegate void FlashWindowExEventHandler(Form f, bool isFlashing);
static FlashWindowExListener() {
int processID = GetCurrentThreadId();
// we are interested in listening to WH_SHELL events, mainly the HSHELL_REDRAW event.
hHook = SetWindowsHookEx(WH_SHELL, procShell, IntPtr.Zero, processID);
System.Windows.Forms.Application.ApplicationExit += delegate {
UnhookWindowsHookEx(hHook);
};
}
public static void Register(Form f) {
if (f.IsDisposed)
throw new ArgumentException("Cannot use disposed form.");
if (f.Handle == IntPtr.Zero) {
f.HandleCreated += delegate {
forms[f.Handle] = f;
};
}
else
forms[f.Handle] = f;
f.HandleDestroyed += delegate {
Unregister(f);
};
}
public static void Unregister(Form f) {
forms.Remove(f.Handle);
}
private static IntPtr ShellProc(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode == HSHELL_REDRAW) {
Form f = null;
// seems OK not having to call f.BeginInvoke
if (forms.TryGetValue(wParam, out f))
FlashEvent(f, (int) lParam == 1);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
private const int WH_SHELL = 10;
private const int HSHELL_REDRAW = 6;
[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, CallShellProc lpfn, IntPtr hInstance, int threadId);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
}
I written a Kiosk style C# application using visual studio that is run on startup and should expand to full-screen and cover the task-bar.
I am doing the usual setting boarder style to none, and fill extents and it works perfectly if I just launch the application manually.
When the application launches on startup (by way of a short-cut in the startup folder in the start menu), the task-bar ends up on top of the program and clicking somewhere on the form does not bring the form back to the top.
Has anyone encountered this problem before, or know of possible workarounds.
I have also done this another time:
public class Screensize
{
/// <summary>
/// Selected Win AI Function Calls
/// </summary>
public class WinApi
{
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
public static extern int GetSystemMetrics(int which);
[DllImport("user32.dll")]
public static extern void
SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter,
int X, int Y, int width, int height, uint flags);
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private static IntPtr HWND_TOP = IntPtr.Zero;
private const int SWP_SHOWWINDOW = 64; // 0x0040
public static int ScreenX
{
get { return GetSystemMetrics(SM_CXSCREEN); }
}
public static int ScreenY
{
get { return GetSystemMetrics(SM_CYSCREEN); }
}
public static void SetWinFullScreen(IntPtr hwnd)
{
SetWindowPos(hwnd, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW);
}
}
/// <summary>
/// Class used to preserve / restore state of the form
/// </summary>
public class FormState
{
private FormWindowState winState;
private FormBorderStyle brdStyle;
private bool topMost;
private Rectangle bounds;
private bool IsMaximized = false;
public void Maximize(Form targetForm)
{
if (!IsMaximized)
{
IsMaximized = true;
Save(targetForm);
targetForm.WindowState = FormWindowState.Maximized;
targetForm.FormBorderStyle = FormBorderStyle.None;
targetForm.TopMost = false;
WinApi.SetWinFullScreen(targetForm.Handle);
}
}
public void Save(Form targetForm)
{
winState = targetForm.WindowState;
brdStyle = targetForm.FormBorderStyle;
topMost = targetForm.TopMost;
bounds = targetForm.Bounds;
}
public void Restore(Form targetForm)
{
targetForm.WindowState = winState;
targetForm.FormBorderStyle = brdStyle;
targetForm.TopMost = topMost;
targetForm.Bounds = bounds;
IsMaximized = false;
}
}
and just call in your form:
screensize.Maximize(this)
I think you mean this
And now I see this post is from 2013...
Workaround: When starting, kill explorer.exe - you don't need it -> taskbar disappear.
When needed, start it using Task Manager