ElementHost flickers black borders on resize - wpf

Disclaimer: This is not a duplicated post. I googled about the issue. Also read this, this and this SO questions. I tried some of those things but nothing seemed to help.
Consider the following simple example code. It's just an empty ElementHost inside a WinForm (no WPF control inside):
using System.Windows.Forms;
using System.Windows.Forms.Integration;
namespace WindowsFormsApplication15
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ElementHost host = new ElementHost();
host.Dock = DockStyle.Fill;
this.Controls.Add(host);
}
}
}
When you resize the form, you can see two black edges at the form border:
Please, ¿someone could give a working solution over my example to fix this issue?

Try this (same idea as the first link you provided, but better performance):
public class ElementHost2 : ElementHost {
public ElementHost2() {
this.AutoSize = true;
}
public override Size GetPreferredSize(Size proposedSize) {
Form f = this.FindForm();
Size s = f.ClientSize;
return s;
}
private const uint WM_SETREDRAW = 0xB;
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
private const uint NOSIZE = 0x0001;
private const uint NOMOVE = 0x0002;
private const uint NOZORDER = 0x0004;
private const uint NOREDRAW = 0x0008;
private const uint NOACTIVATE = 0x0010;
private const uint DRAWFRAME = 0x0020;
private const uint FRAMECHANGED = 0x0020;
private const uint SHOWWINDOW = 0x0040;
private const uint HIDEWINDOW = 0x0080;
private const uint NOCOPYBITS = 0x0100;
private const uint NOOWNERZORDER = 0x0200;
private const uint NOREPOSITION = 0x0200;
private const uint NOSENDCHANGING = 0x0400;
private const uint DEFERERASE = 0x2000;
private const uint ASYNCWINDOWPOS = 0x4000;
protected override void OnResize(EventArgs e) {
base.OnResize(e);
SendMessage(this.Handle, WM_SETREDRAW, 0, 0);
SendMessage(this.Handle, WM_SETREDRAW, 1, 0);
// forces window to redraw:
SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0, NOSIZE | NOMOVE| NOZORDER | NOACTIVATE | SHOWWINDOW);
}
// better performance?
protected override void OnPaintBackground(PaintEventArgs pevent) {
//base.OnPaintBackground(pevent);
}
protected override void OnPaint(PaintEventArgs e) {
//base.OnPaint(e);
}
}
class Form2 : Form {
ElementHost host = new ElementHost2();
public Form2() {
Controls.Add(host);
this.BackColor = Color.Red;
var p = new System.Windows.Controls.DockPanel();
p.Background = System.Windows.Media.Brushes.Red;
host.Child = p;
p.Children.Add(new System.Windows.Controls.TextBox { Width = 100, Height = 20 });
}
}

The issue is not related to ElementHost and Winforms. It's just a WPF issue, and I found the answer in the following SO question:
How to fix the WPF form resize - controls lagging behind and black background?

Related

Standalone WPF Form in VSTO Excel Addin Won't Keep Focus

I am creating a VSTO Plugin for Excel and my first attempt works, but I am not happy with the design. As standard VSTO only handles Windows Forms. I am getting in to WPF now and have found the options for layout and animations make for a much better user experience.
I have now found that I can add a WPF Project to the VSTO Solution and call the forms that way... Excellent!
The problem is when I load a form I do this:
Dim NewForm as New NewForm
NewForm.Show()
This works fine, and the form opens, however if I try to type in a textbox, the form drops behind excel and the text goes in to the active cell in Excel.
If I do:
Dim NewForm as New NewForm
NewForm.ShowDialog()
it works fine. Unfortunately I cannot have the form being modal for my application. How can I get around this?
I use the following class:
https://dl.dropboxusercontent.com/u/62538279/Help/OfficeDialog.cs
You'll notice that the ShowDialog() method is replaced
The class also makes the dialog look like a Word VBA form (something my clients often want)
My dialog.xaml.cs class looks like (and the xaml matches):
public partial class myDialog : OfficeDialog
-- Edit --
Here's the source code. I've been having trouble with it. It occasionally slips behind the application (very rarely)
http://stackoverflow.com/questions/40374059/why-does-my-modal-wpf-dialog-slip-behind-ms-word/40401198#40401198
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public class OfficeDialog : Window
{
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
const int ICON_SMALL = 0;
const int ICON_BIG = 1;
/// <summary>
/// Sometimes get System.ComponentModel.Win32Exception: Invalid window handle
/// I'm pretty sure that this is because Word is shit at handling windows and has an internal memory leak
/// http://stackoverflow.com/questions/222649/winforms-issue-error-creating-window-handle
/// I'm not sure why this error isn't trapped and logged by the try catch below. Somehow it bubbles up to the calling routine..
/// </summary>
public OfficeDialog()
{
this.ShowInTaskbar = false;
//this.Topmost = true;
//Uri uri = new Uri("PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\\themes/aero.normalcolor.xaml", UriKind.Relative);
//Uri uri = new Uri("PresentationFramework.Classic;V3.0.0.0;31bf3856ad364e35;component\\themes/classic.xaml", UriKind.Relative);
//Resources.MergedDictionaries.Add(Application.LoadComponent(uri) as ResourceDictionary);
//var helper = new WindowInteropHelper(this);
//using (Process currentProcess = Process.GetCurrentProcess())
// helper.Owner = currentProcess.MainWindowHandle;
}
public new void ShowDialog()
{
try
{
var helper = new WindowInteropHelper(this);
using (Process currentProcess = Process.GetCurrentProcess())
helper.Owner = currentProcess.MainWindowHandle;
base.ShowDialog();
}
catch (System.ComponentModel.Win32Exception ex)
{
Message.LogWarning(ex);
//this.Topmost = true;
var helper = new WindowInteropHelper(this);
using (Process currentProcess = Process.GetCurrentProcess())
helper.Owner = currentProcess.MainWindowHandle;
base.ShowDialog();
}
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
RemoveIcon(this);
HideMinimizeAndMaximizeButtons(this);
//using (Process currentProcess = Process.GetCurrentProcess())
// SetCentering(this, currentProcess.MainWindowHandle);
}
public static void HideMinimizeAndMaximizeButtons(Window window)
{
const int GWL_STYLE = -16;
IntPtr hwnd = new WindowInteropHelper(window).Handle;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & -131073 & -65537));
}
public static void RemoveIcon(Window w)
{
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(w).Handle;
// Change the extended window style to not show a window icon
int extendedStyle = OfficeDialog.GetWindowLong(hwnd, GWL_EXSTYLE);
OfficeDialog.SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
// reset the icon, both calls important
OfficeDialog.SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
OfficeDialog.SendMessage(hwnd, WM_SETICON, (IntPtr)ICON_BIG, IntPtr.Zero);
// Update the window's non-client area to reflect the changes
OfficeDialog.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
static void SetCentering(Window win, IntPtr ownerHandle)
{
bool isWindow = IsWindow(ownerHandle);
if (!isWindow) //Don't try and centre the window if the ownerHandle is invalid. To resolve issue with invalid window handle error
{
//Message.LogInfo(string.Format("ownerHandle IsWindow: {0}", isWindow));
return;
}
//Show in center of owner if win form.
if (ownerHandle.ToInt32() != 0)
{
var helper = new WindowInteropHelper(win);
helper.Owner = ownerHandle;
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
else
win.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindow(IntPtr hWnd);
}

What is the equal of HelpButton In Wpf Application Window? [duplicate]

How can add this button to the title bar in WPF, by it being so used in a lot of applications I thought it would be built in or something, but looks like it isn't. Anyway let me know if you know anything about this.
Thanks.
Edit:
Isn't there anything equivalent to this?
Basically, to have the ? icon in win forms, all you need to do is this:
public Form1()
{
InitializeComponent();
this.HelpButton = true;
this.MaximizeBox = false;
this.MinimizeBox = false;
}
Doesn't WPF have anything like that?
It's simple, just inset this code into your Window class.
This code uses interop to remove the WS_MINIMIZEBOX and WS_MAXIMIZEBOX styles and add the WS_EX_CONTEXTHELP extended style (the question mark will only show up if you remove the minimize and maximize buttons).
EDIT: added click detection on the help button, this is done by hooking into the WndProc using HwndSource.AddHook and listening for a WM_SYSCOMMAND message with wParam of SC_CONTEXTHELP.
When a click is detected this code will show a message box, changing this into an event, routed event or even a command (for MVVM apps) is left as an exercise for the reader.
private const uint WS_EX_CONTEXTHELP = 0x00000400;
private const uint WS_MINIMIZEBOX = 0x00020000;
private const uint WS_MAXIMIZEBOX = 0x00010000;
private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_FRAMECHANGED = 0x0020;
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_CONTEXTHELP = 0xF180;
[DllImport("user32.dll")]
private static extern uint GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hwnd, int index, uint newStyle);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
uint styles = GetWindowLong(hwnd, GWL_STYLE);
styles &= 0xFFFFFFFF ^ (WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
SetWindowLong(hwnd, GWL_STYLE, styles);
styles = GetWindowLong(hwnd, GWL_EXSTYLE);
styles |= WS_EX_CONTEXTHELP;
SetWindowLong(hwnd, GWL_EXSTYLE, styles);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
((HwndSource)PresentationSource.FromVisual(this)).AddHook(HelpHook);
}
private IntPtr HelpHook(IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam,
ref bool handled)
{
if (msg == WM_SYSCOMMAND &&
((int)wParam & 0xFFF0) == SC_CONTEXTHELP)
{
MessageBox.Show("help");
handled = true;
}
return IntPtr.Zero;
}
No help buttons come out of the box with WPF. Should'nt be a push to roll your own however.

How can I prevent focus stealing, but still get focus when returning to my app using Alt+Tab?

Following MS guidelines, my WPF application's App constructor includes the following code for proper focus behavior:
HwndSource.DefaultAcquireHwndFocusInMenuMode = false;
Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
As explained in this article, these settings prevent focus stealing.
However, setting DefaultRestoreFocusMode to None has a bad side effect. When using Alt+Tab to leave a WPF application and then return to it, the WPF application doesn't get focus. However, if I don't set DefaultRestoreFocusMode to none, it does get focus as expected. Is there a way to prevent focus stealing but have focus still set when returning to a WPF application via Alt+Tab?
-Craig
I prevent my wpf window from getting focus by doing the below and i can still activate it by using ALT-TAB or clicking on it's taskbar item.
Here you change the window styles on your window so that it has no activate.
var yourWindow = new YourWindowType();
//set the windowstyle to noactivate so the window doesn't get focus
yourWindow.SourceInitialized += (s, e) =>
{
var interopHelper = new WindowInteropHelper(yourWindow);
int exStyle = User32.GetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE);
User32.SetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE, exStyle | (int)WindowStylesEx.WS_EX_NOACTIVATE);
//If you have trouble typing into your form's textboxes then do this
ElementHost.EnableModelessKeyboardInterop(yourWindow);
};
This is something i added as an extra precaution, plus it lets you drag your window around if it is borderless:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
//don't activate the window when you click on it.
case WindowMessage.WM_MOUSEACTIVATE:
handled = true;
return (IntPtr)MouseActivate.MA_NOACTIVATE;
//For Borderless Windows: occurs while dragging. it reports new position before it has been finalized.
//otherwise you wont see the window moving while you're dragging it
case WindowMessage.WM_MOVING:
RECT rect = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
User32.SetWindowPos(new WindowInteropHelper(this).Handle, Hwnd.HWND_TOPMOST,
rect.Left, rect.Top, rect.Width, rect.Height,
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOSIZE);
break;
}
return IntPtr.Zero;
}
These add a hook so that WndProc is actually called in WPF:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
if (source == null) return;
source.AddHook(WndProc);
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
if (source == null) return;
source.RemoveHook(WndProc);
}
Just an FYI.. this still works even though you don't get focus:
private void WpfPillForm_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Here's the Win32 API declarations so you don't have to look them up:
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
public static class MouseActivate
{
public const int MA_ACTIVATE = 1;
public const int MA_ACTIVATEANDEAT = 2;
public const int MA_NOACTIVATE = 3;
public const int MA_NOACTIVATEANDEAT = 4;
}
public enum WindowLongFlags : int
{
GWL_EXSTYLE = -20,
GWLP_HINSTANCE = -6,
GWLP_HWNDPARENT = -8,
GWL_ID = -12,
GWL_STYLE = -16,
GWL_USERDATA = -21,
GWL_WNDPROC = -4,
DWLP_USER = 0x8,
DWLP_MSGRESULT = 0x0,
DWLP_DLGPROC = 0x4
}
public const int WM_MOVING = 0x0216;
public const uint WS_EX_NOACTIVATE = 0x08000000,
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowLong(IntPtr hwnd, int index);

How do I center the OpenFileDialog to its parent Window in WPF?

I'm using WPF's OpenFileDialog, and I'm looking for a way to make sure it is centered in the parent window when shown. It seems to be missing obvious properties like StartupPosition that might enable this.
Does anybody know the secret?
Update: It seems that the first time I open it, it does appear in the center of the parent, but if I move it, it then remembers its position, and doesn't open centered on subsequent occassions.
here is the code of a generic class that allows to play with "sub dialogs" like this one:
public class SubDialogManager : IDisposable
{
public SubDialogManager(Window window, Action<IntPtr> enterIdleAction)
:this(new WindowInteropHelper(window).Handle, enterIdleAction)
{
}
public SubDialogManager(IntPtr hwnd, Action<IntPtr> enterIdleAction)
{
if (enterIdleAction == null)
throw new ArgumentNullException("enterIdleAction");
EnterIdleAction = enterIdleAction;
Source = HwndSource.FromHwnd(hwnd);
Source.AddHook(WindowMessageHandler);
}
protected HwndSource Source { get; private set; }
protected Action<IntPtr> EnterIdleAction { get; private set; }
void IDisposable.Dispose()
{
if (Source != null)
{
Source.RemoveHook(WindowMessageHandler);
Source = null;
}
}
private const int WM_ENTERIDLE = 0x0121;
protected virtual IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_ENTERIDLE)
{
EnterIdleAction(lParam);
}
return IntPtr.Zero;
}
}
And this is how you would use it in a standard WPF app. Here I just copy the parent window size, but I'll let you do the center math :-)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
bool computed = false; // do this only once
int x = (int)Left;
int y = (int)Top;
int w = (int)Width;
int h = (int)Height;
using (SubDialogManager center = new SubDialogManager(this, ptr => { if (!computed) { SetWindowPos(ptr, IntPtr.Zero, x, y, w, h, 0); computed= true; } }))
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog(this);
}
}
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
}
CommonDialog in WPF does not inherit from window class, so it does not have StartupPosition property.
Check this blog post for one solution: OpenFileDialog in .NET on Vista
In short, it wraps dialog in a window and then shows it.

finding the zorder of a window

I have a wpf application, for which I need to find out if any other window is over the current window. I can not use IsActive, as that you could have 2 windows side by side (for example IE and the wpf application) and have the other application be active, but not over top of the wpf application.
Essentially I want to know if anything is phsycially over and obscuring part of the wpf window reguardless of activation.
I have tried the following
GetWindowRect
GetTopWindow
and comparing the topwindow process with the current process, this works but only seems to work once.
any ideas?
I've done something similar before and I did not find any managed way of doing this. Hence, it's not really a WPF question, but rather "back to unmanaged" or "good old PInvoke" sort of thing. Here's an extract adapted for your task:
XAML definition.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Label Name="IsSomethingOverLabel">Label</Label>
</Grid>
</Window>
CS code behind.
using System;
using System.Windows;
using System.Windows.Interop;
using System.Runtime.InteropServices;
using System.Windows.Threading;
namespace WpfApplication1 {
using LONG = System.Int32;
using UINT = System.UInt32;
public partial class Window1: Window {
DispatcherTimer tmr;
public Window1() {
InitializeComponent();
tmr = new DispatcherTimer();
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Start();
}
void tmr_Tick(object sender, EventArgs e) {
RECT Rect2 = GetWindowRect(Handle);
IntPtr h = GetWindow(Handle, GW_HWNDPREV);
while(h != IntPtr.Zero) {
if(IsWindowShown(h))//This is to check that the window found is not minimized etc.
{
RECT Rect1 = GetWindowRect(h);
if(Rect1OverlapsRect2(Rect1, Rect2)) {
IsSomethingOverLabel.Content = GetWindowText(h);
return;
}
}
h = GetWindow(h, GW_HWNDPREV);
}
IsSomethingOverLabel.Content = "Nothing over";
}
bool Rect1OverlapsRect2(RECT Rect1, RECT Rect2) {
return Rect1.left < Rect2.right && Rect1.right > Rect2.left &&
Rect1.top < Rect2.bottom && Rect1.bottom > Rect2.top;
}
private IntPtr Handle {
get { return new WindowInteropHelper(this).Handle; }
}
public const uint GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_MAX = 5;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public LONG left;
public LONG top;
public LONG right;
public LONG bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
public static RECT GetWindowRect(IntPtr hWnd) {
RECT lpRect = new RECT();
if(!GetWindowRect(hWnd, ref lpRect)) {
lpRect.top = lpRect.left = lpRect.bottom = lpRect.right = -1;
}
return lpRect;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, string lpString, int nMaxCount);
public static string GetWindowText(IntPtr hWnd) {
int len = GetWindowTextLength(hWnd) + 1;
string s = new string(' ', len);
if(GetWindowText(hWnd, s, len) != 0) {
return s.Substring(0, len - 1);
} else {
return "";
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindowVisible(IntPtr hWnd);
public const int SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
public LONG x;
public LONG y;
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT {
public UINT length;
public UINT flags;
public UINT showCmd;
public POINT ptMinPosition;
public POINT ptMaxPosition;
public RECT rcNormalPosition;
}
public static bool IsWindowShown(IntPtr hWnd) {
bool res = IsWindowVisible(hWnd);
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
if(res && GetWindowPlacement(hWnd, ref placement)) {
switch(placement.showCmd) {
case SW_RESTORE:
case SW_SHOW:
case SW_SHOWMAXIMIZED:
case SW_SHOWNA:
case SW_SHOWNORMAL:
res = true;
break;
default:
res = false;
break;
}
}
return res;
}
}
}
Having a fresh look at the code, GetWindowPlacement could probably be sufficient by itself, eliminating the GetWindowRect call, you can also try that.

Resources