3

Time ago I written a code to hide/restore a process window, what I did is this:

To Hide a process:

1) Find the process name in the running processes.

2) Add the MainWindowHandle to a Container (a Dictionary in this case), this would be necessary to unhide that process later.

3) Hide the process using ShowWindow API function.

To unhide a process:

1) Find the process name in the running processes.

2) Retrieve the saved MainWindowHandle of the specified process from the container.

3) Unhide the process using ShowWindow API function.

Why I use a dictionary to unhide the process?, well, because a Hidden process have a MainWindowHandle value of Zero 0, so that is the only way that I found to retrieve the proper handle to use in the ShowWindow function to restore the process.

But I really don't want to depend on the Hide method that saves the required HWND before hidding the process, I would like to improve all this by knowing how to perform an unhide operation in VB.NET or C# only by specifying the process name (eg: cmd.exe) without saving before the MainWindowHandle, this is possible to do?

I show the code (in VB.NET) to give you an idea of what I did for the HideProcess method:

But please note that this code is not fully relevant in the question, my question is how to unhide a hidden process only by specifying the process name to avoid the code written below that needs to retrieve a saved handle to unhide a process.

' Hide-Unhide Process
'
' Usage Examples :
'
' HideProcess(Process.GetCurrentProcess().MainModule.ModuleName)
' HideProcess("notepad.exe", Recursivity:=False)
' HideProcess("notepad", Recursivity:=True)
'
' UnhideProcess(Process.GetCurrentProcess().MainModule.ModuleName)
' UnhideProcess("notepad.exe", Recursivity:=False)
' UnhideProcess("notepad", Recursivity:=True)

Private ProcessHandles As New Dictionary(Of String, IntPtr)

<System.Runtime.InteropServices.DllImport("User32")>
Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As Integer) As Integer
End Function

Private Sub HideProcess(ByVal ProcessName As String, Optional ByVal Recursivity As Boolean = False)

    If ProcessName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) Then
        ProcessName = ProcessName.Remove(ProcessName.Length - ".exe".Length)
    End If

    Dim Processes() As Process = Process.GetProcessesByName(ProcessName)

    Select Case Recursivity

        Case True
            For Each p As Process In Processes
                ProcessHandles.Add(String.Format("{0};{1}", ProcessName, CStr(p.Handle)), p.MainWindowHandle)
                ShowWindow(p.MainWindowHandle, 0)
            Next p

        Case Else
            If Not (Processes.Count = 0) AndAlso Not (Processes(0).MainWindowHandle = 0) Then
                Dim p As Process = Processes(0)
                ProcessHandles.Add(String.Format("{0};{1}", ProcessName, CStr(p.Handle)), p.MainWindowHandle)
                ShowWindow(p.MainWindowHandle, 0)
            End If

    End Select

End Sub

Private Sub UnhideProcess(ByVal ProcessName As String, Optional ByVal Recursivity As Boolean = False)

    If ProcessName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) Then
        ProcessName = ProcessName.Remove(ProcessName.Length - ".exe".Length)
    End If

    Dim TempHandles As New Dictionary(Of String, IntPtr)
    For Each Handle As KeyValuePair(Of String, IntPtr) In ProcessHandles
        TempHandles.Add(Handle.Key, Handle.Value)
    Next Handle

    For Each Handle As KeyValuePair(Of String, IntPtr) In TempHandles

        If Handle.Key.ToLower.Contains(ProcessName.ToLower) Then

            ShowWindow(Handle.Value, 9)
            ProcessHandles.Remove(Handle.Key)

            If Recursivity Then
                Exit For
            End If

        End If

    Next Handle

End Sub
Jens
  • 6,275
  • 2
  • 25
  • 51
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • please, read what I say in the question before re-tagging: ' I would like to improve all this by knowing how to perform an unhide operation in VB.NET or C#' – ElektroStudios Sep 21 '14 at 16:19
  • Your question is broad. Basically, you're asking how to do something and hoping someone will give fully working code. If you have an actual problem, you should state what it is. –  Sep 21 '14 at 16:22
  • Where I asked for a full code?, no, I'm asking for information, also, I provided my own code to demonstrate a working code, is not enough for you? what more work do you expect from an OP that needs help because doesn't know the solution of him own question?, this discussion seems absurd, really, sorry but... I tried my best. – ElektroStudios Sep 21 '14 at 16:23

2 Answers2

5

Code:

using System.Diagnostics;
using System.Runtime.InteropServices;

[DllImport("User32")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

[DllImport("User32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string strClassName, string strWindowName);

[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);

private const int SW_RESTORE = 9;

private void UnhideProcess(string processName) //Unhide Process
{
    IntPtr handle = IntPtr.Zero;
    int prcsId = 0;

    //an array of all processes with name "processName"
    Process[] localAll = Process.GetProcessesByName(processName);

    //check all open windows (not only the process we are looking) begining from the
    //child of the desktop, handle = IntPtr.Zero initialy.
    do
    {
        //get child handle of window who's handle is "handle".
        handle = FindWindowEx(IntPtr.Zero, handle, null, null);

        GetWindowThreadProcessId(handle, out prcsId); //get ProcessId from "handle"

        //if it matches what we are looking
        if (prcsId == localAll[0].Id)
        {
            ShowWindow(handle, SW_RESTORE); //Show Window

            return;
        }
    } while (handle != IntPtr.Zero);
}

If there are more instances with the same name you can use a variable eg count and increment it in the if statement

int count = 0;

if (prcsId == localAll[count].Id)
{
    ShowWindow(handle, SW_RESTORE);

    count++;
}

FindWindowEx function

The difference between FindWindowEx() and Process.MainWindowHandle() maybe is where each function is looking for handles. FindWindowEx() is looking everywhere unlike MainWindowHandle. Also a process handle is reffered as HANDLE and a window one as HWND

  • Please add a textual description of how to answer the question. Answers which contains only code are not really all that useful. – Lasse V. Karlsen Sep 21 '14 at 20:12
  • could you explain the essence of your solution?, If i understood good what I need to do is find any child window HWND that corresponds to the process?, I don't understand at all why the child windows does not have a handle value of 0 when are hidden like the main window, but it works as expected!, thanks. – ElektroStudios Sep 22 '14 at 07:28
2

I written this solution for vb.net, thanks to @γηράσκω δ' αεί πολλά διδασκόμε

<System.Runtime.InteropServices.DllImport("User32")>
Private Shared Function ShowWindow(
         ByVal hwnd As IntPtr,
         ByVal nCmdShow As Integer
) As Integer
End Function

<System.Runtime.InteropServices.DllImport("User32.dll")>
Private Shared Function FindWindowEx(
        ByVal hwndParent As IntPtr,
        ByVal hwndChildAfter As IntPtr,
        ByVal strClassName As String,
        ByVal strWindowName As String
) As IntPtr
End Function

<System.Runtime.InteropServices.DllImport("user32.dll")>
Private Shared Function GetWindowThreadProcessId(
        ByVal hWnd As IntPtr,
        ByRef ProcessId As Integer
) As Integer
End Function

Public Enum WindowState As Integer

    ''' <summary>
    ''' Hides the window and activates another window.
    ''' </summary>
    Hide = 0I

    ''' <summary>
    ''' Activates and displays a window. 
    ''' If the window is minimized or maximized, the system restores it to its original size and position.
    ''' An application should specify this flag when displaying the window for the first time.
    ''' </summary>
    Normal = 1I

    ''' <summary>
    ''' Activates the window and displays it as a minimized window.
    ''' </summary>
    ShowMinimized = 2I

    ''' <summary>
    ''' Maximizes the specified window.
    ''' </summary>
    Maximize = 3I

    ''' <summary>
    ''' Activates the window and displays it as a maximized window.
    ''' </summary>      
    ShowMaximized = Maximize

    ''' <summary>
    ''' Displays a window in its most recent size and position. 
    ''' This value is similar to <see cref="WindowVisibility.Normal"/>, except the window is not actived.
    ''' </summary>
    ShowNoActivate = 4I

    ''' <summary>
    ''' Activates the window and displays it in its current size and position.
    ''' </summary>
    Show = 5I

    ''' <summary>
    ''' Minimizes the specified window and activates the next top-level window in the Z order.
    ''' </summary>
    Minimize = 6I

    ''' <summary>
    ''' Displays the window as a minimized window. 
    ''' This value is similar to <see cref="WindowVisibility.ShowMinimized"/>, except the window is not activated.
    ''' </summary>
    ShowMinNoActive = 7I

    ''' <summary>
    ''' Displays the window in its current size and position.
    ''' This value is similar to <see cref="WindowVisibility.Show"/>, except the window is not activated.
    ''' </summary>
    ShowNA = 8I

    ''' <summary>
    ''' Activates and displays the window. 
    ''' If the window is minimized or maximized, the system restores it to its original size and position.
    ''' An application should specify this flag when restoring a minimized window.
    ''' </summary>
    Restore = 9I

    ''' <summary>
    ''' Sets the show state based on the SW_* value specified in the STARTUPINFO structure 
    ''' passed to the CreateProcess function by the program that started the application.
    ''' </summary>
    ShowDefault = 10I

    ''' <summary>
    ''' <b>Windows 2000/XP:</b> 
    ''' Minimizes a window, even if the thread that owns the window is not responding. 
    ''' This flag should only be used when minimizing windows from a different thread.
    ''' </summary>
    ForceMinimize = 11I

End Enum

Private Sub SetWindowState(ByVal ProcessName As String,
                           ByVal WindowState As WindowState,
                           Optional ByVal Recursivity As Boolean = False)

    If ProcessName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) Then
        ProcessName = ProcessName.Remove(ProcessName.Length - ".exe".Length)
    End If

    Dim pHandle As IntPtr = IntPtr.Zero
    Dim pID As Integer = 0I

    Dim Processes As Process() = Process.GetProcessesByName(ProcessName)

    ' If any process matching the name is found then...
    If Processes.Count = 0 Then
        Exit Sub
    End If

    For Each p As Process In Processes

        Do Until pID = p.Id ' Check all windows.

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

            ' Get ProcessId from "pHandle".
            GetWindowThreadProcessId(pHandle, pID)

            ' If the ProcessId matches the "pID" then...
            If pID = p.Id Then

                ShowWindow(pHandle, WindowState)

                If Not Recursivity Then
                    Exit For
                End If

            End If

        Loop

    Next p

End Sub
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417