2016-11-19 66 views
2

我有一個批處理文件sps.bat,它只包含一行:start powershell如何從PowerShell啓動PowerShell,然後在指定顯示器的特定象限中找到啓動的窗口

在PowerShell控制檯窗口中,當我鍵入sps時,將啓動一個新的PowerShell控制檯窗口,並且已預先導航到與啓動實例相同的路徑。

我想吃點什麼是獨立的腳本,不僅推出了新的PowerShell控制檯窗口,但也一經推出,隨後定位在指定的象限的任何一個新的PowerShell窗口(完全填充它除了在任務欄)我的顯示器在雙屏幕系統上。

即,我想創建這些命令:

Command  New Window Location 
—————————————————————————————————————————————————— 
    l1  Left-monitor, quadrant 1 (Upper left) 
    l2  Left-monitor, quadrant 2 (Upper Right) 
    l3  Left-monitor, quadrant 3 (Lower Right) 
    l4  Left-monitor, quadrant 4 (Lower Left) 
    r1  Right-monitor, quadrant 1 (Upper left) 
    r2  Right-monitor, quadrant 2 (Upper Right) 
    r3  Right-monitor, quadrant 3 (Lower Right) 
    r4  Right-monitor, quadrant 4 (Lower Left) 

這很容易使用C#的窗口放置和大小。但是,檢測窗口何時啓動並準備好定位可能會更棘手。

希望有人已經有此任務的工作代碼可用。

+1

這是一個有趣的問題,但相當廣泛。你能告訴我們你有多遠嗎?如果使用PowerShell中的'Start-Process'而不是批處理文件來啓動新實例,則可以添加'-PassThru',它返回一個表示剛剛創建的進程的[System.Diagnostics.Process]實例。 – mklement0

+1

我還沒有進一步提出這個問題。但是,這應該工作。必須使用'-PassThru'標誌提供的過程來調用Win32'SetWindowPos' API。看起來非常簡單。 – CalvinDale

+0

很高興聽到它;聽起來有希望我鼓勵你在有事情的時候發佈自己的答案(並且自我接受)。 – mklement0

回答

1

我無法發表評論,但是,你看過ConEmu這樣的控制檯窗口工具嗎?

http://conemu.github.io/

它可以實現窗口位置,希望你似乎有。希望這可以幫助。

+0

我還沒有見過ConEmu。但我以前至少看過一個其他類似的標籤控制檯應用程序。我不記得它的名字。不過,我更喜歡在PowerShell控制檯窗口中工作。 – CalvinDale

0

下面是一些代碼,將做到這一點:

// Interop.cs 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 


namespace WindowQuadrantPositioner { 
    public static class Interop { 
     public static class Flags { 
      static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 
      static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); 
      static readonly IntPtr HWND_TOP = new IntPtr(0); 
      static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 

      /// <summary> 
      /// Window handles (HWND) used for hWndInsertAfter 
      /// </summary> 
      public static class HWND { 
       public static IntPtr 
       NoTopMost = new IntPtr(-2), 
       TopMost = new IntPtr(-1), 
       Top = new IntPtr(0), 
       Bottom = new IntPtr(1); 
      } 

      /// <summary> 
      /// SetWindowPos Flags 
      /// </summary> 
      public static class SWP { 
       public static readonly int 
       NOSIZE = 0x0001, 
       NOMOVE = 0x0002, 
       NOZORDER = 0x0004, 
       NOREDRAW = 0x0008, 
       NOACTIVATE = 0x0010, 
       DRAWFRAME = 0x0020, 
       FRAMECHANGED = 0x0020, 
       SHOWWINDOW = 0x0040, 
       HIDEWINDOW = 0x0080, 
       NOCOPYBITS = 0x0100, 
       NOOWNERZORDER = 0x0200, 
       NOREPOSITION = 0x0200, 
       NOSENDCHANGING = 0x0400, 
       DEFERERASE = 0x2000, 
       ASYNCWINDOWPOS = 0x4000; 
      } 
     } 

     [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, 
     } 

     /// <summary> 
     ///  Changes the size, position, and Z order of a child, pop-up, or top-level window. These windows are ordered 
     ///  according to their appearance on the screen. The topmost window receives the highest rank and is the first window 
     ///  in the Z order. 
     ///  <para>See https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx for more information.</para> 
     /// </summary> 
     /// <param name="hWnd">C++ (hWnd [in]. Type: HWND)<br />A handle to the window.</param> 
     /// <param name="hWndInsertAfter"> 
     ///  C++ (hWndInsertAfter [in, optional]. Type: HWND)<br />A handle to the window to precede the positioned window in 
     ///  the Z order. This parameter must be a window handle or one of the following values. 
     ///  <list type="table"> 
     ///  <itemheader> 
     ///   <term>HWND placement</term><description>Window to precede placement</description> 
     ///  </itemheader> 
     ///  <item> 
     ///   <term>HWND_BOTTOM ((HWND)1)</term> 
     ///   <description> 
     ///   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. 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>HWND_NOTOPMOST ((HWND)-2)</term> 
     ///   <description> 
     ///   Places the window above all non-topmost windows (that is, behind all topmost windows). This 
     ///   flag has no effect if the window is already a non-topmost window. 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>HWND_TOP ((HWND)0)</term><description>Places the window at the top of the Z order.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>HWND_TOPMOST ((HWND)-1)</term> 
     ///   <description> 
     ///   Places the window above all non-topmost windows. The window maintains its topmost position 
     ///   even when it is deactivated. 
     ///   </description> 
     ///  </item> 
     ///  </list> 
     ///  <para>For more information about how this parameter is used, see the following Remarks section.</para> 
     /// </param> 
     /// <param name="X">C++ (X [in]. Type: int)<br />The new position of the left side of the window, in client coordinates.</param> 
     /// <param name="Y">C++ (Y [in]. Type: int)<br />The new position of the top of the window, in client coordinates.</param> 
     /// <param name="cx">C++ (cx [in]. Type: int)<br />The new width of the window, in pixels.</param> 
     /// <param name="cy">C++ (cy [in]. Type: int)<br />The new height of the window, in pixels.</param> 
     /// <param name="uFlags"> 
     ///  C++ (uFlags [in]. Type: UINT)<br />The window sizing and positioning flags. This parameter can be a combination 
     ///  of the following values. 
     ///  <list type="table"> 
     ///  <itemheader> 
     ///   <term>HWND sizing and positioning flags</term> 
     ///   <description>Where to place and size window. Can be a combination of any</description> 
     ///  </itemheader> 
     ///  <item> 
     ///   <term>SWP_ASYNCWINDOWPOS (0x4000)</term> 
     ///   <description> 
     ///   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. 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_DEFERERASE (0x2000)</term> 
     ///   <description>Prevents generation of the WM_SYNCPAINT message. </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_DRAWFRAME (0x0020)</term> 
     ///   <description>Draws a frame (defined in the window's class description) around the window.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_FRAMECHANGED (0x0020)</term> 
     ///   <description> 
     ///   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 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_HIDEWINDOW (0x0080)</term><description>Hides the window.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOACTIVATE (0x0010)</term> 
     ///   <description> 
     ///   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). 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOCOPYBITS (0x0100)</term> 
     ///   <description> 
     ///   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. 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOMOVE (0x0002)</term> 
     ///   <description>Retains the current position (ignores X and Y parameters).</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOOWNERZORDER (0x0200)</term> 
     ///   <description>Does not change the owner window's position in the Z order.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOREDRAW (0x0008)</term> 
     ///   <description> 
     ///   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. 
     ///   </description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOREPOSITION (0x0200)</term><description>Same as the SWP_NOOWNERZORDER flag.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOSENDCHANGING (0x0400)</term> 
     ///   <description>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOSIZE (0x0001)</term> 
     ///   <description>Retains the current size (ignores the cx and cy parameters).</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_NOZORDER (0x0004)</term> 
     ///   <description>Retains the current Z order (ignores the hWndInsertAfter parameter).</description> 
     ///  </item> 
     ///  <item> 
     ///   <term>SWP_SHOWWINDOW (0x0040)</term><description>Displays the window.</description> 
     ///  </item> 
     ///  </list> 
     /// </param> 
     /// <returns><c>true</c> or nonzero if the function succeeds, <c>false</c> or zero otherwise or if function fails.</returns> 
     /// <remarks> 
     ///  <para> 
     ///  As part of the Vista re-architecture, all services were moved off the interactive desktop into Session 0. 
     ///  hwnd and window manager operations are only effective inside a session and cross-session attempts to manipulate 
     ///  the hwnd will fail. For more information, see The Windows Vista Developer Story: Application Compatibility 
     ///  Cookbook. 
     ///  </para> 
     ///  <para> 
     ///  If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to 
     ///  take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 
     ///  SWP_FRAMECHANGED. 
     ///  </para> 
     ///  <para> 
     ///  A window can be made a topmost window either by setting the hWndInsertAfter parameter to HWND_TOPMOST and 
     ///  ensuring that the SWP_NOZORDER flag is not set, or by setting a window's position in the Z order so that it is 
     ///  above any existing topmost windows. When a non-topmost window is made topmost, its owned windows are also made 
     ///  topmost. Its owners, however, are not changed. 
     ///  </para> 
     ///  <para> 
     ///  If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that 
     ///  a window be simultaneously activated and its position in the Z order changed), the value specified in 
     ///  hWndInsertAfter is used only in the following circumstances. 
     ///  </para> 
     ///  <list type="bullet"> 
     ///  <item>Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hWndInsertAfter. </item> 
     ///  <item>The window identified by hWnd is not the active window. </item> 
     ///  </list> 
     ///  <para> 
     ///  An application cannot activate an inactive window without also bringing it to the top of the Z order. 
     ///  Applications can change an activated window's position in the Z order without restrictions, or it can activate 
     ///  a window and then move it to the top of the topmost or non-topmost windows. 
     ///  </para> 
     ///  <para> 
     ///  If a topmost window is repositioned to the bottom (HWND_BOTTOM) of the Z order or after any non-topmost 
     ///  window, it is no longer topmost. When a topmost window is made non-topmost, its owners and its owned windows 
     ///  are also made non-topmost windows. 
     ///  </para> 
     ///  <para> 
     ///  A non-topmost window can own a topmost window, but the reverse cannot occur. Any window (for example, a 
     ///  dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay 
     ///  above their owner. 
     ///  </para> 
     ///  <para> 
     ///  If an application is not in the foreground, and should be in the foreground, it must call the 
     ///  SetForegroundWindow function. 
     ///  </para> 
     ///  <para> 
     ///  To use SetWindowPos to bring a window to the top, the process that owns the window must have 
     ///  SetForegroundWindow permission. 
     ///  </para> 
     /// </remarks> 

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

     /// <summary> 
     ///  Special window handles 
     /// </summary> 
     public enum SpecialWindowHandles { 
      // ReSharper disable InconsistentNaming 
      /// <summary> 
      ///  Places the window at the top of the Z order. 
      /// </summary> 
      HWND_TOP = 0, 
      /// <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, 
      /// <summary> 
      ///  Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated. 
      /// </summary> 
      HWND_TOPMOST = -1, 
      /// <summary> 
      ///  Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window. 
      /// </summary> 
      HWND_NOTOPMOST = -2 
      // ReSharper restore InconsistentNaming 
     } 


    } 
} 

// WindowPositioner.cs 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Diagnostics; 
using System.Windows; 
using System.Windows.Forms; 
using System.Drawing; 

namespace WindowQuadrantPositioner { 
    public static class WindowPositioner { 

     private static void Main(string[] args) { 
      int processId; 
      if (args == null || args.Length != 2) { 
       MessageBox.Show("This program expects to command-line parameters:\n1) The screen/quadrant placement: L1, L2, L3, L4, R1, R2, R3, R4\n2) The Process ID for the PowerShell window", "Command-line arguments not provided", MessageBoxButtons.OK, MessageBoxIcon.Error); 
       var msg = ""; 
       MessageBox.Show(msg); 
       return; 
      } 
      if (!int.TryParse(args[1], out processId)) { 
       MessageBox.Show("The Process ID for the PowerShell window must be provided as a command-line argument", "Process ID not provided", MessageBoxButtons.OK, MessageBoxIcon.Error); 
       return; 
      } 
      switch (args[0].ToUpper()) { 
       case "L1": 
        PositionWindow(processId, ScreenPosition.Left, Quadrant.UpperLeft); 
        return; 
       case "L2": 
        PositionWindow(processId, ScreenPosition.Left, Quadrant.UpperRight); 
        return; 
       case "L3": 
        PositionWindow(processId, ScreenPosition.Left, Quadrant.LowerRight); 
        return; 
       case "L4": 
        PositionWindow(processId, ScreenPosition.Left, Quadrant.LowerLeft); 
        return; 
       case "R1": 
        PositionWindow(processId, ScreenPosition.Right, Quadrant.UpperLeft); 
        return; 
       case "R2": 
        PositionWindow(processId, ScreenPosition.Right, Quadrant.UpperRight); 
        return; 
       case "R3": 
        PositionWindow(processId, ScreenPosition.Right, Quadrant.LowerRight); 
        return; 
       case "R4": 
        PositionWindow(processId, ScreenPosition.Right, Quadrant.LowerLeft); 
        return; 
       default: 
        MessageBox.Show("The screen/quadrant code must must be provided as a command-line argument. Valid values are: 'L1, L2, L3, L4, R1, R2, R3, R4", "Screen/quadrant code not provided", MessageBoxButtons.OK, MessageBoxIcon.Error); 
        return; 
      } 
     } 

     public enum ScreenPosition { 
      Left, 
      Right 
     } 

     public enum Quadrant { 
      UpperLeft, 
      UpperRight, 
      LowerRight, 
      LowerLeft, 
     } 

     public static void PositionWindow(int processId, ScreenPosition screen, Quadrant quadrant) { 
      try { 
       var process = Process.GetProcessById(processId).MainWindowHandle; 
       var coords = GetQuadrantCoords(screen, quadrant); 
       Interop.SetWindowPos(process, (IntPtr) Interop.SpecialWindowHandles.HWND_TOP, coords.Left, coords.Top, coords.Width, coords.Height, Interop.SetWindowPosFlags.ShowWindow); 
      } catch (Exception ex) { 
       MessageBox.Show(ex.Message, "Couldn't set window position", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
     } 

     private static Rectangle GetQuadrantCoords(ScreenPosition screenPosition, Quadrant quadrant) { 
      int screenCount = Screen.AllScreens.Count(); 
      Screen screen; 
      if (screenPosition == ScreenPosition.Left) { 
       screen = Screen.AllScreens.OrderBy(_ => _.WorkingArea.Left).First(); 
      } else { 
       screen = Screen.AllScreens.OrderBy(_ => _.WorkingArea.Left).Last(); 
      } 
      var a = screen.WorkingArea; 
      switch (quadrant) { 
       case Quadrant.UpperLeft: 
        return new Rectangle(a.Left, a.Top, a.Width/2, a.Height/2); 
       case Quadrant.UpperRight: 
        return new Rectangle(a.Left + a.Width/2, a.Top, a.Width/2, a.Height/2); 
       case Quadrant.LowerRight: 
        return new Rectangle(a.Left + a.Width/2, a.Top + a.Height/2, a.Width/2, a.Height/2); 
       case Quadrant.LowerLeft: 
        return new Rectangle(a.Left, a.Top + a.Height/2, a.Width/2, a.Height/2); 
       default: 
        throw new NotImplementedException(); 
      } 
     } 

    } 
} 

// r1.ps1 
$Id = (Start-Process PowerShell -PassThru); Start-Process "WindowQuadrantPositioner.exe" -ArgumentList ("R1 " + $Id.Id) 

類似.ps1文件爲其他屏幕/象限。

放置當前窗口,創建腳本下面這個模式:

# ml1.ps1 
if (-not ("Tricks" -as [type])) { 
Add-Type @" 
    using System; 
    using System.Runtime.InteropServices; 
    public class Tricks { 
    [DllImport("user32.dll")] 
    public static extern IntPtr GetForegroundWindow(); 
} 
"@ 
} 


$a = [tricks]::GetForegroundWindow() 

$Id = get-process | ? { $_.mainwindowhandle -eq $a } 

Start-Process "WindowQuadrantPositioner.exe" -ArgumentList ("L1 " + $Id.Id)