我正在尝试制作一个winforms程序,它允许我将所有打开的窗口从任何进程移动到我的主监视器的中心.我平均打开了15个以上的窗户,在我晚上离开之前,将所有东西移到我的主显示器上需要大约一分钟.我需要将它们移动到我的主显示器上,这样我就不必处理从屏幕上移动它们的问题,如果我为了客户端的问题而远程操作.我在这里看一个链接,但这只显示窗口名称文本和长度.我相信我需要使用EnumWindowsapi来做到这一点,但我不知道最好的方法.我也在看这里的GetWindow功能,但不知道如何使用它.此外,我知道如何将我的winforms移动到屏幕的中心,这不是问题.对此有任何见解表示赞赏.
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)
如你所见,我也用过IsWindowVisible和GetShellWindow
[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)
使用GetWindowRect和RECT:
[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/2和height/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)
我认为这很好......(我没有尝试过这个解决方案,但它与我的一个项目非常接近)