如何防止在脚本完成时关闭out-gridview

时间:2010-01-19 23:05:36

标签: gridview powershell

我有一个使用out-gridview显示结果的脚本。这是一个简单的例子:

"hello world" | out-gridview

当我使用使用PowerShell运行运行脚本时,它将打开gridview并在打开后立即关闭它。 (我认为这是因为gridview不是模态的,脚本完成了。)

如何让PowerShell等到手动关闭gridview?

4 个答案:

答案 0 :(得分:7)

怎么样:

"hello world" | out-gridview -wait

根据the documentation of Out-GridView,选项-Wait会阻止Windows PowerShell关闭,直到Out-GridView窗口关闭。

它在Windows PowerShell 3.0中可用。

答案 1 :(得分:6)

我知道,老问题但是......

只需将'-PassThru'添加到Out-Gridview中 - 向gridview添加“OK”和“Cancel”按钮 - 现在您可以“使用powershell运行”并在完成后使用“确定”按钮关闭gridview窗口 - 太容易了!

答案 2 :(得分:4)

您可以使用-noexit运行Powershell.exe,也可以尝试:

"hello world" | out-gridview
Read-Host "press enter to exit"

更新: Out-GridView是非阻塞的,所以如果你想测试它退出,你必须求助于一些低级的Win32 API。以下代码适用于ISE(尚未在控制台主机中进行测试)。它也有一个限制 - 它基本上寻找与主机进程相关的任何窗口,而不是主机进程的主窗口。那时,它会回来。事实证明Out-GridView不是主窗口的子窗口,其标题不一致(GPS | Out-GridView或GPS | ogv或GPS | <any alias you make up>):

$src = @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace Utils
{
    public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

    public class WindowHelper 
    {
        private const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
        private IntPtr _mainHwnd;
        private IntPtr _ogvHwnd;
        private IntPtr _poshProcessHandle;
        private int _poshPid;
        private bool _ogvWindowFound;

        public WindowHelper()
        {
            Process process = Process.GetCurrentProcess();
            _mainHwnd = process.MainWindowHandle;
            _poshProcessHandle = process.Handle;
            _poshPid = process.Id;
        }

        public void WaitForOutGridViewWindowToClose()
        {
            do 
            {
                _ogvWindowFound = false;
                EnumChildWindows(IntPtr.Zero, EnumChildWindowsHandler,
                                 IntPtr.Zero);
                Thread.Sleep(500);
            } while (_ogvWindowFound);
        }

        [DllImport("User32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(
            IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

        [DllImport("Oleacc.dll")]
        public static extern IntPtr GetProcessHandleFromHwnd(IntPtr hwnd);

        [DllImport("Kernel32.dll")]
        public static extern int GetProcessId(IntPtr handle);

        [DllImport("Kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DuplicateHandle(
            IntPtr hSourceProcessHandle, 
            IntPtr hSourceHandle, 
            IntPtr hTargetProcessHandle,
            out IntPtr lpTargetHandle,
            int dwDesiredAccess,
            bool bInheritHandle,
            int dwOptions);

        [DllImport("Kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("Kernel32.dll")]
        public static extern int GetLastError();

        private bool EnumChildWindowsHandler(IntPtr hwnd, IntPtr lParam)
        {
            if (_ogvHwnd == IntPtr.Zero)
            {
                IntPtr hProcess = GetProcessHandleFromHwnd(hwnd);
                IntPtr hProcessDup;
                if (!DuplicateHandle(hProcess, hProcess, _poshProcessHandle,
                                     out hProcessDup, 
                                     PROCESS_QUERY_LIMITED_INFORMATION,
                                     false, 0))
                {
                    Console.WriteLine("Dup process handle {0:X8} error: {1}",
                                      hProcess.ToInt32(), GetLastError());
                    return true;
                }
                int processId = GetProcessId(hProcessDup);
                if (processId == 0)
                {
                    Console.WriteLine("GetProcessId error:{0}",
                                      GetLastError());
                    return true;
                }
                if (processId == _poshPid)
                {
                    if (hwnd != _mainHwnd)
                    {
                        _ogvHwnd = hwnd;
                        _ogvWindowFound = true;
                        CloseHandle(hProcessDup);
                        return false;
                    }
                }
                CloseHandle(hProcessDup);
            }
            else if (hwnd == _ogvHwnd)
            {
                _ogvWindowFound = true;
                return false;
            }
            return true;
        }
    }
}
'@

Add-Type -TypeDefinition $src

Get-Process | Out-GridView

$helper = new-object Utils.WindowHelper
$helper.WaitForOutGridViewWindowToClose()

"Done!!!!"

答案 3 :(得分:2)

Keith的解决方案因某些原因对我不起作用。当我运行它时,我得到错误,并且该过程终止而不等待网格关闭。我得到这样的输出:

...
GetProcessId error:6
Dup process handle 0000015C error: 6
GetProcessId error:6
GetProcessId error:6
Dup process handle 00000148 error: 6
GetProcessId error:6
GetProcessId error:6
...

我真的不太了解Keith解决方案中使用的Windows API。但经过一番挖掘,我确实找到了一种方法来修改更简单的解决方案。它涉及较少的API调用和导入,也不会产生任何错误。这就是我想出来的。

$src = @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace Utils
{
  public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

  public class WindowHelper
  {
    private const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
    private IntPtr _mainHwnd;
    private IntPtr _ogvHwnd;
    private IntPtr _poshProcessHandle;
    private int _poshPid;
    private bool _ogvWindowFound;

    public WindowHelper()
    {
      Process process = Process.GetCurrentProcess();
      _mainHwnd = process.MainWindowHandle;
      _poshProcessHandle = process.Handle;
      _poshPid = process.Id;
    }

    public void WaitForOutGridViewWindowToClose()
    {
      do
      {
        _ogvWindowFound = false;
        EnumChildWindows(IntPtr.Zero, EnumChildWindowsHandler,
                 IntPtr.Zero);
        Thread.Sleep(500);
      } while (_ogvWindowFound);
    }

    [DllImport("User32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumChildWindows(
      IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

    [DllImport("User32.dll")]
    public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);

    [DllImport("Kernel32.dll")]
    public static extern int GetLastError();

    private bool EnumChildWindowsHandler(IntPtr hwnd, IntPtr lParam)
    {
      if (_ogvHwnd == IntPtr.Zero)
      {
        int processId;
        int thread = GetWindowThreadProcessId(hwnd, out processId);

        if (processId == 0)
        {
          Console.WriteLine("GetWindowThreadProcessId error:{0}",
                   GetLastError());
          return true;
        }
        if (processId == _poshPid)
        {
          if (hwnd != _mainHwnd)
          {
            _ogvHwnd = hwnd;
            _ogvWindowFound = true;
            return false;
          }
        }
      }
      else if (hwnd == _ogvHwnd)
      {
        _ogvWindowFound = true;
        return false;
      }
      return true;
    }
  }
}
'@

Add-Type -TypeDefinition $src

Get-Process | Out-GridView       
$helper = new-object Utils.WindowHelper 
$helper.WaitForOutGridViewWindowToClose()

希望这会使其他人免于我遇到的同样问题。