设置隐藏窗口的窗口状态

时间:2015-11-01 01:59:11

标签: c# .net vb.net pinvoke showwindow

以前我问过这个问题,这里解决了:

但是现在,由于未知原因,提供的C#或Vb.Net代码无法正常工作,我不明白为什么不这样做。

我对那里提供的原始代码做了一些修改,但是我测试了原件而没有用。

发生的事情是我无法解决隐藏的过程,我不知道我失败的地方。在第一个视图中,我认为我使用FindWindowEx得到的句柄并不真正对应于我想要的句柄。

这些是我的P / Invoking函数签名和showwindow枚举:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto, 
           BestFitMapping:=False, ThrowOnUnmappablechar:=True)>
Friend Shared Function FindWindow(
                 ByVal lpClassName As String,
                 ByVal lpWindowName As String
) As IntPtr
End Function

<DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto, 
           BestFitMapping:=False, ThrowOnUnmappablechar:=True)>
Friend Shared Function FindWindowEx(
                 ByVal hwndParent As IntPtr,
                 ByVal hwndChildAfter As IntPtr,
                 ByVal strClassName As String,
                 ByVal strWindowName As String
) As IntPtr
End Function

<DllImport("user32.dll")>
Friend Shared Function GetWindowThreadProcessId(
                 ByVal hWnd As IntPtr,
                 ByRef processId As Integer
) As Integer
End Function

<DllImport("User32", SetLastError:=False)>
Friend Shared Function ShowWindow(
                 ByVal hwnd As IntPtr,
                 ByVal nCmdShow As ProcessUtil.WindowState
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Enum WindowState As Integer
    Hide = 0
    Normal = 1
    ShowMinimized = 2
    Maximize = 3
    ShowMaximized = Maximize
    ShowNoActivate = 4
    Show = 5
    Minimize = 6
    ShowMinNoActive = 7
    ShowNA = 8
    Restore = 9
    ShowDefault = 10
    ForceMinimize = 11
End Enum

功能:

Public Function SetWindowState(ByVal p As Process,
                               ByVal windowState As ProcessUtil.WindowState) As Boolean

    Dim pHandle As IntPtr = IntPtr.Zero
    Dim pid As Integer

    ' If window is visible then...
    If (p.MainWindowHandle <> IntPtr.Zero) Then
        Return ProcessUtil.NativeMethods.ShowWindow(p.MainWindowHandle, windowState)

    Else ' window is hidden.

        ' Check all open windows (not only the process we are looking), 
        ' begining from the child of the desktop.
        While (pid <> p.Id)

            ' Get child handle of window who's handle is "pHandle".
            pHandle = NativeMethods.FindWindowEx(IntPtr.Zero, pHandle, Nothing, Nothing)

            ' Get PID from "pHandle".
            NativeMethods.GetWindowThreadProcessId(pHandle, pid)

        End While

        Return NativeMethods.ShowWindow(pHandle, windowState)

    End If

End Function

我尝试测试该功能的方式,首先我隐藏了记事本进程的窗口,然后我试着取消隐藏它。

Dim p As Process = Process.GetProcessesByName("notepad").First
ProcessUtil.SetWindowState(p, ProcessUtil.WindowState.Hide)

' I find again the process to renew the "p.MainWindowHandle" as IntPtr.Zero.
p = Process.GetProcessesByName("notepad").First
ProcessUtil.SetWindowState(p, ProcessUtil.WindowState.Restore)

2 个答案:

答案 0 :(得分:2)

记事本的问题在于它有3个窗口( spy ++ 类名):

  

<强> 1。 “记事本”
  的 2。 “MSCTFIME UI”
  第3。 “IME”

你正在掌握第二个(我还是得到了), MSCTFIME UI ,这就是为什么你无法展示它。您需要指定类名记事本才能获得正确的句柄:

pHandle = FindWindowEx(IntPtr.Zero, pHandle, "Notepad", Nothing)

答案 1 :(得分:2)

现在是您开始使用.NET Framework源代码的时候了,这样您就可以发现为什么这样的代码不能自己运行。访问Reference Source web site即可开始使用。

在搜索框中输入&#34; Process.MainWindowHandle&#34;,您将到达this page。很容易看出是完成工作的ProcessManager.GetMainWindowHandle。点击&#34; GetMainWindowHandle&#34;。它非常小,点击&#34; FindMainWindow&#34;。注意它如何枚举窗口,向右滚动一点以查看它&#34; EnumWindowsCallback&#34;完成工作。点击它,很容易看到它&#34; IsMainWindow&#34;决定窗口是否是主窗口。点击它:

    bool IsMainWindow(IntPtr handle) {

        if (NativeMethods.GetWindow(new HandleRef(this, handle), NativeMethods.GW_OWNER) != (IntPtr)0
            || !NativeMethods.IsWindowVisible(new HandleRef(this, handle)))
            return false;

        return true;
    }

如果它是一个拥有的窗口,那么它就是而不是主窗口句柄。 或者如果它不可见

后一条当然是你的克星。你隐藏了窗口,现在框架代码不再认为它可以成为主窗口。因此,Process.MainWindowHandle返回IntPtr.Zero,您的代码将无法再运行。

一个明显的解决方法是简单地重写.NET Framework代码并跳过IsWindowVisible()测试。然而,这是一个重要的测试,它避免了找到几乎任何进程创建的消息窗口#34;它们用于内部管道。另一个答案提到了他们。你可以用Spy ++看到它们,Notepad有两个。如果没有按照使您找到它们的顺序创建,您将首先找到主窗口。这并不能保证在任何过程中都会发生。

正确的解决方法是,您必须不要忘记您对该窗口做了非常不友好的事情。记事本本身从不隐藏其主窗口。你基本上把它变成了僵尸,用户再也无法恢复窗口。剩下的唯一选择是使用任务管理器来终止进程。因此,完全可以让它再次可见。一个你不能忽视的工作,你必须在你的程序退出之前恢复它们。

或者只是不这样做,弄乱用户的窗户就像这样只是一种敌意。