将所有打开的窗口从任何进程移动到主屏幕的中心

Joh*_*sen 3 c# winforms

我正在尝试制作一个winforms程序,它允许我将所有打开的窗口从任何进程移动到我的主监视器的中心.我平均打开了15个以上的窗户,在我晚上离开之前,将所有东西移到我的主显示器上需要大约一分钟.我需要将它们移动到我的主显示器上,这样我就不必处理从屏幕上移动它们的问题,如果我为了客户端的问题而远程操作.我在这里看一个链接,但这只显示窗口名称文本和长度.我相信我需要使用EnumWindowsapi来做到这一点,但我不知道最好的方法.我也在看这里GetWindow功能,但不知道如何使用它.此外,我知道如何将我的winforms移动到屏幕的中心,这不是问题.对此有任何见解表示赞赏.

Xar*_*uth 9

EnumWindows如果要移动所有窗口,则可以使用,而不仅仅是打开应用程序拥有的窗体.

[DllImport("USER32.DLL")]
public static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
Run Code Online (Sandbox Code Playgroud)

然后,在您的代码中,您可以通过打开(和可见)Windows进行迭代:

IntPtr lShellWindow = NativeMethods.GetShellWindow();
List<IntPtr> listWindows = new List<IntPtr>();

NativeMethods.EnumWindows(delegate(IntPtr hWnd, int lParam)
{
    if (hWnd == lShellWindow) return true;
    if (!NativeMethods.IsWindowVisible(hWnd)) return true;

    // may be some other checks

    lWindows.Add(hWnd);
    return true;
}, 0);
Run Code Online (Sandbox Code Playgroud)

如你所见,我也用过IsWindowVisibleGetShellWindow

[DllImport("USER32.DLL")]
public static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport("USER32.DLL")]
public static extern IntPtr GetShellWindow();
Run Code Online (Sandbox Code Playgroud)

然后,使用Handles列表,您可以移动窗口 SetWindowPos

[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

[Flags()]
public enum SetWindowPosFlags : uint
{
    /// <summary>If the calling thread and the thread that owns the window are attached to different input queues,
    /// the system posts the request to the thread that owns the window. This prevents the calling thread from
    /// blocking its execution while other threads process the request.</summary>
    /// <remarks>SWP_ASYNCWINDOWPOS</remarks>
    AsynchronousWindowPosition = 0x4000,
    /// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
    /// <remarks>SWP_DEFERERASE</remarks>
    DeferErase = 0x2000,
    /// <summary>Draws a frame (defined in the window's class description) around the window.</summary>
    /// <remarks>SWP_DRAWFRAME</remarks>
    DrawFrame = 0x0020,
    /// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
    /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
    /// is sent only when the window's size is being changed.</summary>
    /// <remarks>SWP_FRAMECHANGED</remarks>
    FrameChanged = 0x0020,
    /// <summary>Hides the window.</summary>
    /// <remarks>SWP_HIDEWINDOW</remarks>
    HideWindow = 0x0080,
    /// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
    /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
    /// parameter).</summary>
    /// <remarks>SWP_NOACTIVATE</remarks>
    DoNotActivate = 0x0010,
    /// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
    /// contents of the client area are saved and copied back into the client area after the window is sized or
    /// repositioned.</summary>
    /// <remarks>SWP_NOCOPYBITS</remarks>
    DoNotCopyBits = 0x0100,
    /// <summary>Retains the current position (ignores X and Y parameters).</summary>
    /// <remarks>SWP_NOMOVE</remarks>
    IgnoreMove = 0x0002,
    /// <summary>Does not change the owner window's position in the Z order.</summary>
    /// <remarks>SWP_NOOWNERZORDER</remarks>
    DoNotChangeOwnerZOrder = 0x0200,
    /// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
    /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
    /// window uncovered as a result of the window being moved. When this flag is set, the application must
    /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
    /// <remarks>SWP_NOREDRAW</remarks>
    DoNotRedraw = 0x0008,
    /// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
    /// <remarks>SWP_NOREPOSITION</remarks>
    DoNotReposition = 0x0200,
    /// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
    /// <remarks>SWP_NOSENDCHANGING</remarks>
    DoNotSendChangingEvent = 0x0400,
    /// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
    /// <remarks>SWP_NOSIZE</remarks>
    IgnoreResize = 0x0001,
    /// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
    /// <remarks>SWP_NOZORDER</remarks>
    IgnoreZOrder = 0x0004,
    /// <summary>Displays the window.</summary>
    /// <remarks>SWP_SHOWWINDOW</remarks>
    ShowWindow = 0x0040,
}
Run Code Online (Sandbox Code Playgroud)

在你的代码中:

internal static void MoveWindow(IntPtr intPtr, int X, int Y)
{
    NativeMethods.SetWindowPos(intPtr, IntPtr.Zero, X, Y, 0 , 0, NativeMethods.SetWindowPosFlags.DoNotChangeOwnerZOrder  | NativeMethods.SetWindowPosFlags.IgnoreResize);
}
Run Code Online (Sandbox Code Playgroud)

如果你想让所有的窗户居中,你可以改善这一点,但这是一个好的开始;)

编辑: 要改进,你可以获得每个窗口的大小EnumWindows

List<AppWindow> listWindows = new List<AppWindow>();

NativeMethods.EnumWindows(delegate(IntPtr hWnd, int lParam)
{
    if (hWnd == lShellWindow) return true;
    if (!NativeMethods.IsWindowVisible(hWnd)) return true;

    // may be some other checks

    NativeMethods.RECT rct;

    if (NativeMethods.GetWindowRect(hWnd, out rct))
    {
        listWindows.Add(new AppWindow()
        {
            Handle = hWnd,
            Width = rct.Right - rct.Left,
            Height = rct.Bottom - rct.Top,
        });
    }
    return true;
}, 0);
Run Code Online (Sandbox Code Playgroud)

使用GetWindowRectRECT:

[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
}
Run Code Online (Sandbox Code Playgroud)

和一个名为AppWindow的类:

internal class AppWindow
{
    private IntPtr handle ;
    private Int32 height;
    private Int32 width;

    public IntPtr Handle
    {
        get { return this.handle; }
        set { this.handle = value; }
    }

    public Int32 Height
    {
        get { return this.height; }
        set { this.height= value; }
    }

    public Int32 Width
    {
        get { return this.width; }
        set { this.width= value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以计算移动窗口的位置

编辑: 如何获得主屏幕的中心?使用WinForms轻松:

int width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
int height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
Run Code Online (Sandbox Code Playgroud)

现在,屏幕的中心是width/2height/2

编辑:(结束)

foreach (AppWindow app in listWindows)
{
    this.MoveWindow(app.Handle, (this.width / 2) - (app.Width/2), (this.height / 2) - (app.Height/2));
}
Run Code Online (Sandbox Code Playgroud)

我认为这很好......(我没有尝试过这个解决方案,但它与我的一个项目非常接近)