SetWindowPos/MoveWindow persist issue - c#

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;
}

Related

C# Console Disable Resize

How to achieve programmatically that the console window is not resizable.
I don't want user to change the console window size with their mouse.
See the answer in this post on MSDN. It requires p-invoking:
private const int MF_BYCOMMAND = 0x00000000;
public const int SC_CLOSE = 0xF060;
public const int SC_MINIMIZE = 0xF020;
public const int SC_MAXIMIZE = 0xF030;
public const int SC_SIZE = 0xF000;//resize
[DllImport("user32.dll")]
public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GetConsoleWindow();
static void Main(string[] args)
{
IntPtr handle = GetConsoleWindow();
IntPtr sysMenu = GetSystemMenu(handle, false);
if (handle != IntPtr.Zero)
{
DeleteMenu(sysMenu, SC_CLOSE, MF_BYCOMMAND);
DeleteMenu(sysMenu, SC_MINIMIZE, MF_BYCOMMAND);
DeleteMenu(sysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
DeleteMenu(sysMenu, SC_SIZE, MF_BYCOMMAND);//resize
}
Console.Read();
}
Note that this does not prevent Windows window snapping (e.g. dragging window to edge of screen, Win+Left and Win+Right)
Since you're trying to disable resizing, I'm guessing you won't want scrollbars either. For that, see this answer to Remove space left after console scrollbars in C# (leftover after matching Console.SetWindowSize and SetBufferSize; also requires p-invoking to "fix").
I'm not sure you can avoid that kind of action.
But you may try to use WindowHeight, WindowWidth, LargestWindowHeight and LargestWindowWidth.
See this:
https://msdn.microsoft.com/pt-br/library/system.console(v=vs.110).aspx

How to check whether application is running fullscreen mode on any screen?

I'd like to check, if any screen hosts application in fullscreen mode. I have solution only for one screen which is code copied from here: [WPF] [C#] How-to : Detect if another application is running in full screen mode. This solution is based on
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
which gathers only active window handle. The problem is, I have two screens. I've searched many sites but none of them answers my question. It is not about capturing screenshot, which is simple and doesn't rely on P/Invoke.
Is this possible?
No ready-to-use solution here, but let's see..
Get list of all displayed windows and check positions and sizes of those windows - possible, lots of tools does it, many articles on that, I'll skip this one. Then, you can call MonitorFromWindow for each or some windows and compare window dimensions&position against monitor info. If windowpos ~= 0,0 and windowsize ~= monitorresolution you could assume that this window is in fullscreen mode.
On the other hand, if already having a list of all HWNDs, then why not just Query the window for its placement and check the WINDOWPLACEMENT.showCmd for SW_MAXIMIZE/SW_SHOWMAXIMIZED flags. That won't tell you which monitor is it, but should tell you at least if the window is maximized and if it's enough for you..
I don't know how fast/slow would it be to do it like that, but, yes, it seems possible.
You could use EnumWindows in conjunction with Screen.FromHandle. And maybe GetWindowRect() for calculations.
Something like (pseudo-code!):
//------------------------------
//this sample code is taken from http://pinvoke.net/default.aspx/user32/EnumWindows.html
public delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ArrayList lParam);
public static ArrayList GetWindows()
{
ArrayList windowHandles = new ArrayList();
EnumedWindow callBackPtr = GetWindowHandle;
EnumWindows(callBackPtr, windowHandles);
return windowHandles;
}
private static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles)
{
windowHandles.Add(windowHandle);
return true;
}
//------------------------------
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, [In,Out] ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
static void Main() {
foreach(IntPtr handle in GetWindows())
{
Screen scr = Screen.FromHandle(handle);
if(IsFullscreen(handle, scr))
{
// the window is fullscreen...
}
}
}
private bool IsFullscreen(IntPtr wndHandle, Screen screen)
{
Rect r = new Rect();
GetWindowRect(wndHandle, ref r);
return new Rectangle(r.Left, r.Top, r.Right-r.Left, r.Bottom-r.Top)
.Contains(screen.Bounds);
}
I wrote piece of code which is working:
namespace EnumWnd
{
using System;
using System.Runtime.InteropServices;
using System.Text;
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct MonitorInfoEx
{
public int cbSize;
public Rect rcMonitor;
public Rect rcWork;
public UInt32 dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDeviceName;
}
internal class Program
{
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("User32")]
public static extern IntPtr MonitorFromWindow(IntPtr hWnd, int dwFlags);
[DllImport("user32", EntryPoint = "GetMonitorInfo", CharSet = CharSet.Auto,
SetLastError = true)]
internal static extern bool GetMonitorInfoEx(IntPtr hMonitor, ref MonitorInfoEx lpmi);
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
const int MONITOR_DEFAULTTOPRIMARY = 1;
var mi = new MonitorInfoEx();
mi.cbSize = Marshal.SizeOf(mi);
GetMonitorInfoEx(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), ref mi);
Rect appBounds;
GetWindowRect(hWnd, out appBounds);
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
var sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
if (sb.Length > 20)
{
sb.Remove(20, sb.Length - 20);
}
int windowHeight = appBounds.Right - appBounds.Left;
int windowWidth = appBounds.Bottom - appBounds.Top;
int monitorHeight = mi.rcMonitor.Right - mi.rcMonitor.Left;
int monitorWidth = mi.rcMonitor.Bottom - mi.rcMonitor.Top;
bool fullScreen = (windowHeight == monitorHeight) && (windowWidth == monitorWidth);
sb.AppendFormat(" Wnd:({0} | {1}) Mtr:({2} | {3} | Name: {4}) - {5}", windowWidth, windowHeight, monitorWidth, monitorHeight, mi.szDeviceName, fullScreen);
Console.WriteLine(sb.ToString());
}
return true;
}
private static void Main()
{
while (true)
{
EnumWindows(EnumTheWindows, IntPtr.Zero);
Console.ReadKey();
Console.Clear();
}
}
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
}
}
Thanks for #SamAxe and #quetzalcoatl for providing me useful tips.

How to access to SysListView32 Services Tab in Windows taskmanager

I'm trying to recover some items from Windows taskmanager.
With this code i recovered the SysListView32 handle from Process TAB:
(dlgItem)
IntPtr mainWindowHandle = Process.GetProcessesByName("taskmgr")[0].MainWindowHandle;
Api.WindowPlacement lpwndpl = new Api.WindowPlacement();
lpwndpl.length = Marshal.SizeOf((object) lpwndpl);
Api.GetWindowPlacement(mainWindowHandle, ref lpwndpl);
bool flag1 = lpwndpl.showCmd == 1 || lpwndpl.showCmd == 3;
IntPtr dlgItem = Api.GetDlgItem(Api.FindWindowEx(mainWindowHandle, IntPtr.Zero, (string) null, (string) null), 1009);
How can i recover the handle for SysListView32 Services TAB?
Some API definitions im using:
internal static class Api
{
public struct Rect
{
private int left;
private int top;
private int right;
private int bottom;
}
public struct Point
{
private int x;
private int y;
}
public struct WindowPlacement
{
public int length;
public int flags;
public int showCmd;
public Api.Point ptMinPosition;
public Api.Point ptMaxPosition;
public Api.Rect rcNormalPosition;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref Api.WindowPlacement lpwndpl);
[DllImport("user32.dll")]
public static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
}
You must use FindWindowEx with a class name (lpszClass) equal to "#32770" and a Window Title (lpszWindow) equal to "Services". The ID of the child SysListView32 is then 3504 (0x0000db0).
Those datas come from Spy++, used on a French Windows Seven Pro 32bits OS.

How to use Win32 GetMonitorInfo() in .NET c#?

I have to implement a feature where the last position of the window is saved. When the application starts up this position needs to be obtained and restored.
Now it could be that a second monitor is dismantled. If the last position is on a now non-visible monitor (in other words the saved coordinates are outside the visible coordinates), this case should be caught and the coordinates shall be set to the default rather than last position.
In order to retrieve the information about monitors I need to use Win32. It is not easy for me to make this work.
I have created a Helper CLass:
public static class DisplayHelper
{
private const int MONITOR_DEFAULTTONEAREST = 2;
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int GetSystemMetrics(int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern UInt32 MonitorFromPoint(Point pt, UInt32 dwFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern bool GetMonitorInfo(UInt32 monitorHandle, ref MonitorInfo mInfo);
public static void GetMonitorInfoNow(MonitorInfo mi, Point pt)
{
UInt32 mh = MonitorFromPoint(pt, 0);
mi.cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
mi.dwFlags = 0;
bool result = GetMonitorInfo(mh, ref mi);
}
}
And these are my attempts to create the MonitorInfo and Rect classes:
[StructLayout(LayoutKind.Sequential)]
public class MonitorInfo
{
public UInt32 cbSize;
public Rectangle2 rcMonitor;
public Rectangle2 rcWork;
public UInt32 dwFlags;
public MonitorInfo()
{
rcMonitor = new Rectangle2();
rcWork = new Rectangle2();
cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
dwFlags = 0;
}
}
[StructLayout(LayoutKind.Sequential)]
public class Rectangle2
{
public UInt64 left;
public UInt64 top;
public UInt64 right;
public UInt64 bottom;
public Rectangle2()
{
left = 0;
top = 0;
right = 0;
bottom = 0;
}
}
I am using this code like this to obtain the visible monitors:
//80 means it counts only visible display monitors.
int lcdNr = DisplayHelper.GetSystemMetrics(80);
var point = new System.Drawing.Point((int) workSpaceWindow.Left, (int) workSpaceWindow.Top);
MonitorInfo monitorInfo = new MonitorInfo();
DisplayHelper.GetMonitorInfoNow(monitorInfo, point);
The last method throws an exception when trying to execute
bool result = GetMonitorInfo(mh, ref mi);
Any suggestions what I need to do to fix this?
Rather than calling a native API, you should use System.Windows.Forms.Screen. It should have everything you need, and be much easier to use.
Screen.FromPoint is the managed equivalent of your GetMonitorInfoNow function with the MONITOR_DEFAULTTONEAREST option. I just noticed you aren't using that option, so you may have to write your own or use the correct P/Invoke signatures.
Writing your own should be fairly simple, if you just reference System.Drawing and System.Windows.Forms. Both of these should work:
static Screen ScreenFromPoint1(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
return Screen.AllScreens
.Where(scr => scr.Bounds.Contains(pt))
.FirstOrDefault();
}
static Screen ScreenFromPoint2(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
var scr = Screen.FromPoint(pt);
return scr.Bounds.Contains(pt) ? scr : null;
}
If you prefer to make the Win32 calls yourself, the proper P/Invoke signatures (i.e. what you'd get from decompiling the .Net DLL) for the functions you need to call are:
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out]MONITORINFOEX info);
[DllImport("User32.dll", ExactSpelling=true)]
public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto, Pack=4)]
public class MONITORINFOEX {
public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
public char[] szDevice = new char[32];
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTSTRUCT {
public int x;
public int y;
public POINTSTRUCT(int x, int y) {
this.x = x;
this.y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int left;
public int top;
public int right;
public int bottom;
}
I found one different is
public static extern bool GetMonitorInfo(IntPtr hMonitor, [In,Out] MONITORINFO lpmi) and
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi)
In my case, the ref keywork made the function always return false.
But if remove this keyword or usr [In,Out], it work.
More info about ref vs. [In,Out] on This.
Your Rectangle2 should use Int32 or just int, not Int64. More information can be found here.
Also it needs to be a struct, not a class. Same goes for your MonitorInfo class (it should be a struct). I'd recommend trying the version from the link above, or compare them with your versions.
Since you are using the MonitorInfo class, not a struct, you must specify the [Out] attribute and not use ref in order for the marshaler to update your class correctly.
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetMonitorInfo(
IntPtr hmonitor,
[In, Out] MonitorInfo info);
You can also go to using structure and ref, then it will look like this:
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetMonitorInfo(
IntPtr hmonitor,
ref MonitorInfoEx info);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
internal struct MonitorInfoEx
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szDevice;
}
var info = new MonitorInfoEx
{
cbSize = (uint)Marshal.SizeOf(typeof(MonitorInfoEx)),
};
GetMonitorInfo(hDesktop, ref info);

How to hide/show a Process using c#?

While executing my program, I want to hide/minimize Microsoft Speech Recognition Application:
alt text http://img143.imageshack.us/img143/9380/minimize.png
and at the end I want to show/maximize using c#!
This process is not started by me so I can't give control the process startInfo.
I've tried to use user32.dll methods such as:
ShowWindow
AnimatedWindows
AnimatedWindows
SetForegroundWindow
SetWindowPos
With all of them I have the same problem.
I can hide the windows (althought I have to call one of the methods two times with SW_HIDE option), but when I call the method with a SW_SHOW flag, it simply doesn't shows..
How can I maximize/show after hiding the process?
Thanks in advance!
Here is some pieces of the code, now implemented to use SetWindowPlacement:
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPlacement(IntPtr hWnd,
[In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
public static extern Boolean ShowWindowAsync(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
public static extern Boolean SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
public static extern Boolean AnimateWindow(IntPtr hWnd, uint dwTime, uint dwFlags);
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, IntPtr pvAttribute, IntPtr lol);
//Definitions For Different Window Placement Constants
const UInt32 SW_HIDE = 0;
const UInt32 SW_SHOWNORMAL = 1;
const UInt32 SW_NORMAL = 1;
const UInt32 SW_SHOWMINIMIZED = 2;
const UInt32 SW_SHOWMAXIMIZED = 3;
const UInt32 SW_MAXIMIZE = 3;
const UInt32 SW_SHOWNOACTIVATE = 4;
const UInt32 SW_SHOW = 5;
const UInt32 SW_MINIMIZE = 6;
const UInt32 SW_SHOWMINNOACTIVE = 7;
const UInt32 SW_SHOWNA = 8;
const UInt32 SW_RESTORE = 9;
public sealed class AnimateWindowFlags
{
public const int AW_HOR_POSITIVE = 0x00000001;
public const int AW_HOR_NEGATIVE = 0x00000002;
public const int AW_VER_POSITIVE = 0x00000004;
public const int AW_VER_NEGATIVE = 0x00000008;
public const int AW_CENTER = 0x00000010;
public const int AW_HIDE = 0x00010000;
public const int AW_ACTIVATE = 0x00020000;
public const int AW_SLIDE = 0x00040000;
public const int AW_BLEND = 0x00080000;
}
public struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
//this works
param = new WINDOWPLACEMENT();
param.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
param.showCmd = (int)SW_HIDE;
lol = SetWindowPlacement(theprocess.MainWindowHandle, ref param);
// this doesn't work
WINDOWPLACEMENT param = new WINDOWPLACEMENT();
param.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
param.showCmd = SW_SHOW;
lol = GetWindowPlacement(theprocess.MainWindowHandle, ref param);
NOTE:
Does the SAPI API has a command to minimize this minimize and maximize this window?
As Tomas said, you should try to use the SW_HIDE and SW_SHOW messages.
You do that by knowing the Speech Recognition winwow name and then using something like this:
HWND hc = FindWindow("processname","Windowtitle");
ShowWindow(hc,SW_HIDE);
The whole SetForegroundWindow/ShowWindow set of functions only work when stars align! :) It's usually a matter of calling functions in the right order. Sorry can't help specifically but this might provide some ideas
http://markribau.org/blog/2005/12/29/why-dont-focus-and-setforegroundwindow-work/
Is the procoess still runing if you send it the SW_HIDE message? The application is certainly not using the standard style of GUI, so it may react to the message by closing itself.
If that's the case, you could try other tricks, such as moving the window to some invisible location (e.g. -1000, -1000), which should be also possible using the SetWindowPlacement method that you already imported.

Categories