tags:

views:

642

answers:

2

The documentation for AppActivate(ProcessID) states...

The AppActivate function changes the focus to the named application or window but does not affect whether it is maximized or minimized.

Unfortunately, it doesn't then advise how you CAN un-Minimize an application from the task bar when you want it activated.

I can't find something like a SetWindowState on the Process object, so given I have a ProcessID and/or a Process object, what can be done to bring the window into a Normal or Maximized state?

A: 

I don't see any way other than interop.

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_SYSCOMMAND = 0x0112;
const UInt32 SC_RESTORE    = 0xF120;

if (Process.MainWindowHandle != IntPtr.Zero)
   SendMessage(Process.MainWindowHandle, WM_SYSCOMMAND, SC_RESTORE, 0);

You could use PostMessage as well, if you don't need to know when it has been restored.

John Knoeller
I'm using a new Win7-64bit machine, so I'm not sure if that's a side issue. When I saw the .MainWindowHandle property in your code I wondered why I hadn't seen it before, and discovered the intellisense was defaulting to Common instead of All.However, the SendMessage call doesn't seem to do anything either, irrespective of whether I pass SC_RESTORE, SC_MAXIMIZE or SC_MINIMIZE???
Bill
Is it a GUI process or a console process? Not all processes have a main window handle.
John Knoeller
You could also use Spy++ to get the window handle, and hard-code that into your app in order to see if the problem is the handle or not. It's possible that this application just doesn't respond to restore messages. Remember that the window handle is only valid until the app exits, you will have to spy it again for each run.
John Knoeller
I've established that ShowWindow(hwnd,SW_NORMAL) works fine when calling Calc.exe or Notepad.exe, but fails when calling the business application. The minimized application is a VB6 WinForm app, and I suspect the value being returned by Process.MainWindowHandle is not the real thing. Fortunately I have access to the VB6 code, so maybe I can see why this might be and find a workaround. ie. If it is just this application or something peculiar to VB6.
Bill
If the caption of the window for the business application is unique, you can try using FindWindow. It might be interesting to know if FindWindow returns the same value as MainWindowHandle.
John Knoeller
Hi John. I've established that the Process.MainWindowHandle value returned for a (sample) VB6 application is NOT the same as what is returned for the FindWindow call on the same running application. Because the titlebar caption on the target application is not a constant value, I've constructed a workaround that searches through the currently running windows, and have posted the code in another answer to this question.
Bill
A: 

For unknown reasons, it appears that the Process.MainWindowHandle value returned from a VB6 application is not the appropriate value to pass to ShowWindow in order to restore the application from a minimized state.

In the situation where the application caption is not constant, the FindWindow API call is not useful. This code below provides a function that will return the handle to a running application based on the window's caption STARTING with a specified value.

Sample usage : Identifying the IDs...

Dim hwnd As Integer
Dim iProcessID As Integer

iProcessID = Shell("SampleApp.exe", AppWinStyle.NormalFocus)
hwnd = API.GetFirstWindowhandle("Sample App")

... restoring the application...

AppActivate(iProcessID)

If API.IsMinimized(hwnd) Then
   API.ShowWindow(hwnd)
End If

... the functional routines ...

Imports System.Runtime.InteropServices

Public Class API

   Private Declare Function apiGetTopWindow Lib "user32" Alias "GetTopWindow" (ByVal hwnd As Integer) As Integer
   Private Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Integer
   Private Declare Function apiGetWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Integer, ByVal wCmd As Integer) As Integer
   Private Declare Function apiGetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Integer) As Integer
   Private Declare Function apiGetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String, ByVal cch As Integer) As Integer
   Private Declare Function apiShowWindow Lib "user32" Alias "ShowWindow" (ByVal hwnd As IntPtr, ByVal nCmdShow As Integer) As Integer
   Private Declare Function apiIsIconic Lib "user32" Alias "IsIconic" (ByVal hwnd As IntPtr) As Boolean

   Private Const GW_HWNDNEXT As Integer = 2
   Private Const SW_NORMAL As Integer = 1

   Public Shared Function GetFirstWindowHandle(ByVal sStartingWith As String) As Integer

      Dim hwnd As Integer
      Dim sWindowName As String

      Dim iHandle As Integer = 0

      hwnd = apiGetTopWindow(apiGetDesktopWindow)

      Do While hwnd <> 0
         sWindowName = zGetWindowName(hwnd)
         If sWindowName.StartsWith(sStartingWith) Then
            iHandle = hwnd
            Exit Do
         End If
         hwnd = apiGetWindow(hwnd, GW_HWNDNEXT)
      Loop

      Return iHandle

   End Function

   Public Shared Function IsMinimized(ByVal hwnd As Integer) As Boolean

      Dim ip As New IntPtr(hwnd)

      Return apiIsIconic(ip)

   End Function

   Public Shared Sub ShowWindow(ByVal hwnd As Integer)

      Dim ip As New IntPtr(hwnd)

      apiShowWindow(ip, SW_NORMAL)

   End Sub

   Private Shared Function zGetWindowName(ByVal hWnd As Integer) As String

      Dim nBufferLength As Integer
      Dim nTextLength As Integer
      Dim sName As String

      nBufferLength = apiGetWindowTextLength(hWnd) + 4
      sName = New String(" "c, nBufferLength)

      nTextLength = apiGetWindowText(hWnd, sName, nBufferLength)
      sName = sName.Substring(0, nTextLength) 

      Return sName

   End Function

End Class
Bill