Determine if application is running with Excel

Just want to point out that the Window Text may change when documents are open in the application instance.

For example, I was trying to bring CorelDRAW to focus and everything would work fine so long as there wasn't a document open in Corel, if there was, I would need to pass the complete name to FindWindow() including the open document.

So, instead of just:

FindWindow("CorelDRAW 2020 (64-Bit)")

It would have to be:

FindWindow("CorelDRAW 2020 (64-Bit) - C:\CompletePath\FileName.cdr")

As that is what would be returned from GetWindowText()

Obviously this is an issue as you don't know what document a user will have open in the application, so for anyone else who may be coming here, years later, who may be experiencing the same issue, here's what I did.

Option Explicit
Private Module

Private Const EXE_NAME As String = "CorelDRW.exe"
Private Const WINDOW_TEXT As String = "CorelDRAW 2020" ' This is common with all opened documents

Private Const GW_HWNDNEXT = 2
Private Const SW_RESTORE = 9

Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Public Sub FocusIfRunning(parAppName as String, parWindowText as String)

    Dim oProcs As Object
    Dim lWindowHandle As Long
    Dim sWindowText As String
    Dim sBuffer As String

    ' Create WMI object and execute a WQL query statement to find if your application
    ' is a running process. The query will return an SWbemObjectSet.

    Set oProcs = GetObject("winmgmts:").ExecQuery("SELECT * FROM win32_process WHERE " & _
                            "name = '" & parAppName & "'")

    ' The Count property of the SWbemObjectSet will be > 0 if there were
    ' matches to your query.

    If oProcs.Count > 0 Then

        ' Go through all the handles checking if the start of the GetWindowText()
        ' result matches your WindowText pre-file name.
        ' GetWindowText() needs a buffer, that's what the Space(255) is.

        lWindowHandle = FindWindow(vbEmpty, vbEmpty)

        Do While lWindowHandle

            sBuffer = Space(255)
            sWindowText = Left(sBuffer, GetWindowText(lWindowHandle, sBuffer, 255))

            If Mid(sWindowText, 1, Len(parWindowText)) Like parWindowText Then Exit Do

            ' Get the next handle. Will return 0 when there are no more.

            lWindowHandle = GetWindow(lWindowHandle, GW_HWNDNEXT)

        Loop

        Call ShowWindow(lWindowHandle , SW_RESTORE)

    End If

End Sub

Private Sub btnFocusWindow_Click()
    Call FocusIfRunning(EXE_NAME, WINDOW_TEXT)
End Sub

Hopefully somebody gets use from this and doesn't have to spend the time on it I did.


You can check this more directly by getting a list of open processes.

This will search based on the process name, returning true/false as appropriate.

Sub exampleIsProcessRunning()  
    Debug.Print IsProcessRunning("MyProgram.EXE")
    Debug.Print IsProcessRunning("NOT RUNNING.EXE")
   
End Sub

Function IsProcessRunning(process As String)
    Dim objList As Object
    
    Set objList = GetObject("winmgmts:") _
        .ExecQuery("select * from win32_process where name='" & process & "'")
    
    IsProcessRunning = objList.Count > 0
End Function

Here's how I brought the search window to front:

Private Const SW_RESTORE = 9

Private Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long

Private Sub btnSearch_Click()
    Dim x As Variant
    Dim Path As String

    If IsProcessRunning("MyProgram.exe") = False Then
        Path = "C:\Tmp\MyProgram.exe"
        x = Shell(Path, vbNormalFocus)
    Else
        Dim THandle As Long
        THandle = FindWindow(vbEmpty, "Window / Form Text")
        Dim iret As Long
        iret = BringWindowToTop(THandle)
        Call ShowWindow(THandle, SW_RESTORE)
    End If
End Sub

Now if the window was minimized and the user clicks the search button again, the window will simply pop up.

Tags:

Excel

Vba