[Webinar] Streamline your web hosting managementRegister Today


Launching and then reactivating another app from VB5

Posted on 1999-06-25
Medium Priority
Last Modified: 2011-09-20
I need to launch another application from my VB5 app. No problem using Shell, but if the user switches back to the 1st app and then tries to launch the second app again, I need to see if it is running already, and if so restore it whether it is minimized or not. If it was closed, I know I can just use shell again. The code I need is how to determine whether it is running. FindWindow API won't do because the second app is an MDI and the Caption varies depending on the child windows caption. Thanks.
Question by:arniels

Author Comment

ID: 1519751
Adjusted points to 200
LVL 12

Expert Comment

ID: 1519752
When you fire the SHELL you get a return value. Before you fire it a second time try an App.Activate and see if you get an error #5 back. If the app is still hot, it'll come to the front. If it's been closed the error tells you to fire SHELL again.



Author Comment

ID: 1519753
Mark2150 has come close. Yes, using AppActivate returns an error and I can then Shell again if the app is not running. If the app is running, it will then activate. But, if it is running and it is minimized, this method will not activate and restore the app as a normal window.
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

LVL 10

Expert Comment

ID: 1519754
here is what you do... you gotta assign your main form a unique class name... then you simply use FindWindow() by using the class parameter and not the caption, and if the handle returned is different than 0 then the app is running, otherwise it is not...


Author Comment

ID: 1519755
Thanks, but the app I am shelling to may be someone elses and I cannot assign or may not know the Class Name.
LVL 12

Expert Comment

ID: 1519756
App.Activate certainly *SHOULD* maximize the app! I use Adobe Acrobat as a child task and it enlarges just fine!

Let me get the code (hang on!)

... time passes ...

Ok, here is how I launch the app:

RetVal = Shell(Quote & Adobe_Path & Quote, vbMaximizedFocus)

This is sub that brings the app to the top and drives it:

Private Sub sendit(txt As String)
' Send string to child task
On Error Resume Next    'Ignore any errors that occur
AppActivate RetVal      'Make sure child task is active
DoEvents                'Give it a shot to run
SendKeys txt, True      'Tell it what to do and wait
DoEvents                'Cede some more time
End Sub

This is a sample code sequence I send:

Call log("Accessing Document: " & filename & " Page " & onpage, "I", vbBlue)
sendit ("%WA")                      'Close all windows
sendit ("%FO" & datadrive & RefPath & "\" & filename & "{enter}")
sendit ("%VG")                      ' Issue page select command
sendit (onpage & "{enter}")         ' Specify page

This code works like a top and every time a SENDIT is issued, the app comes to the top even if the operator has minimized it.



Expert Comment

ID: 1519757
you can try the code below :

Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long

Private Const GW_CHILD = 5
Private Const GW_HWNDNEXT = 2

Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Const SW_RESTORE = 9

Dim HprocessProgram As Long
Dim HwndProgram As Long

Private Sub Command1_Click()

Dim lRes As Long

If HwndProgram = 0 Then 'not running --> shell
    HprocessProgram = Shell("myapp.exe", vbNormalFocus)
    HwndProgram = GetWindowHandle(HprocessProgram)
    lRes = ShowWindow(HwndProgram, SW_RESTORE) 'running --> show
    If lRes = 0 Then 'previously running, now, not runnnig --> shell
        HprocessProgram = Shell("myapp.exe", vbNormalFocus)
        HwndProgram = GetWindowHandle(HprocessProgram)
    End If
End If

End Sub
Private Function GetWindowHandleLow(ByVal hWndStart As Long, hProcess As Long)
Dim c_hWnd As Long
Dim hWndReturn As Long
Dim hProcessCur As Long

'Get first child
Dim c As Long
c_hWnd = GetWindow(hWndStart, GW_CHILD)

'loop through all children
Do Until c_hWnd = 0

    'Get the window's process handle
    GetWindowThreadProcessId c_hWnd, hProcessCur
    'if the process handle matches, return the window's handle
    If hProcessCur = hProcess Then
        GetWindowHandleLow = c_hWnd
        Exit Function
    End If
    'search all of the children of this window
    hWndReturn = GetWindowHandleLow(c_hWnd, hProcess)
    'return handle to caller if non-zero
    If hWndReturn <> 0 Then
        GetWindowHandleLow = hWndReturn
        Exit Function
    End If
    'no match get the next window
    c_hWnd = GetWindow(c_hWnd, GW_HWNDNEXT)


'return window handle not found
GetWindowHandleLow = 0

End Function

Private Function GetWindowHandle(hProcess As Long) As Long

'Recursively collect all of the window handless
'to search for the process handle (hprocess).
'return to caller (0 if not found)

GetWindowHandle = GetWindowHandleLow(GetDesktopWindow, hProcess)

End Function


Author Comment

ID: 1519758
AppActivate doe not restore a minimized app. KHollAD's solution works fine if there is no splash screen or login screen preceeding the main mdi form, but it there is, it gets the hwnd of the login form which will not be opened when you want to reactivate the app.

I have tried the following code and it seems to work. If anyone has a better approach, let me know.

Public Sub RunApp(frm As Form, spath As String, sparam As String, stitle As String)

'where frm is the calling form, spath is the path and exe 'to run, sparam is is any command parameter, and stitle is 'the app caption to search

'(e.g. RunApp Me, "C:\folder\myapp.exe", "/Command", '"Parent Caption")

Dim hwndcurr As Long
Dim nlen As Integer
Dim wtitle As String
Dim x As Long
Dim apprunning As Boolean
Dim stitlelen As Integer

'get the length of the caption passed
'this should be just the parent part of the caption
stitlelen = Len(stitle)
apprunning = False

'add the parameter if not null
If sparam <> "" Then
   spath = spath & " " & sparam
End If

hwndcurr = GetWindow(frm.hwnd, GW_HWNDFIRST)
'loop through windows, getting caption text, to find target 'caption
Do While hwndcurr <> 0
   nlen = GetWindowTextLength(hwndcurr)
   wtitle = Space$(nlen + 1)
   nlen = GetWindowText(hwndcurr, wtitle, nlen + 1)
'if target title found then activate it. Since it may be 'an mdi app, just match on parent part of caption
   If UCase$(Left$(wtitle, stitlelen)) = stitle Then
      apprunning = True
      'restore in case it is minimized
      x = ShowWindow(hwndcurr, SW_RESTORE)
      AppActivate wtitle
      Exit Do
   End If
   hwndcurr = GetWindow(hwndcurr, GW_HWNDNEXT)

'if caption not found and thus app not running
'already, launch it
If apprunning = False Then
  x = Shell(spath, 1)
End If

End Sub

Expert Comment

ID: 1519759
Or you can try this
Public bStillRunning as boolean
Public Const STILL_ACTIVE = &H103
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (hObject As Long) As Boolean

Dim hProcess as long
Dim lRetVal as long

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, Shell("YourExe.exe")
        GetExitCodeProcess hProcess, lRetVal
        If lRetVal <> STILL_ACTIVE Then
              bStillRunning = false
               Exit Do
              bStillRunning = true
        end if
    Call CloseHandle(hProcess)
end sub

Check the variable bStillRunning and you may know you launch another application or not.

Expert Comment

ID: 1519760
 I think Torus answer will do, if doesn't you can check if the EXE is running using PSAPI.DLL or sort of, that has some API functions that let you manage processes.

Accepted Solution

poneill011098 earned 600 total points
ID: 1519761
You should be able to check for a running application by looking for it's windows by class name using the FindWindow API call - the fist argument specifies the class name.

(You will need to determine the window class name "manually" by launch the app., looking for it by caption and then retrieving it's class name using the GetClassName API first time...)

If you get a window handle back, you can activate it, otherwise you should launch the application for the first time.


Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
Suggested Courses
Course of the Month10 days, 6 hours left to enroll

591 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question