I developed an application that I can assign programs to specific monitors so that when I dock my laptop, which results in all my open windows being pushed to my main monitor, I can press a global hotkey, Alt+d, and all the applications that have been assigned to a monitor get pushed to their assigned monitor. I also have 3 other hotkeys, Alt+1, Alt+2 and Alt+3, which move the window in focus to the corresponding monitor. I have noticed that when returning to my desk and docking my laptop while it is sleeping and then logging back into Windows that the monitor working area returned in the code does not match what is shown in the display settings.
Here is the monitor layout that Windows shows. In red is what my code is showing.
If I undock and then dock everything matches back up.
Here is my code for moving the currently focused window to a specific monitor.
Alt+1 sends a 0, Alt+2 sends a 1 and Alt+3 sends a 2:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[Flags]
public enum SpecialWindowHandles
{
/// <summary>
/// Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
/// </summary>
HWND_BOTTOM = 1
}
[Flags]
public enum SetWindowPosFlags : uint
{
/// <summary>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004
}
private 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;
}
/// <summary>
/// Moves the user process retaining start to the provided monitor
/// </summary>
/// <param name="monitor"></param>
public void DockWindow(int monitor)
{
var screens = Screen.AllScreens.Count();
if (monitor == 1 && screens < 2 || monitor == 2 && screens < 3) // Prevent moving widnow to monitor that doesn't exist
return;
var hwnd = GetForegroundWindow(); // Gets the handle for the focused window
var screenLocation = Screen.AllScreens[monitor].WorkingArea; // Gets the working area of the windows associated monitor
var placement = new WINDOWPLACEMENT();
GetWindowPlacement(hwnd, ref placement); // Gest window placement info
switch (placement.showCmd)
{
case 3: // Maximized
ShowWindow(hwnd, 9); // Switch to regular window
SetWindowPos(hwnd, (IntPtr)SpecialWindowHandles.HWND_BOTTOM, screenLocation.X + 100, screenLocation.Y + 100, 0, 0, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOSIZE); // Move window
ShowWindow(hwnd, 3); // Maximize window
break;
default: // Regular window
SetWindowPos(hwnd, (IntPtr)SpecialWindowHandles.HWND_BOTTOM, screenLocation.X + 100, screenLocation.Y + 100, 0 ,0, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOSIZE); // Move window
break;
}
}
UPDATE
I did a little more debugging and Screen.AllScreens
returns different arrays depending on the state my computer is in when docking:
Any ideas why this happens?