Troy Mitchel
Troy Mitchel

Reputation: 1810

How to check processes for application that terminated unexpectedly

I would like to detect hidden instances of SolidWorks.exe before connecting to the object in my application. The reason is that SolidWorks sometimes closes unexpectedly but is still open in background processes as indicated with task manager. So when my application starts I want to connect to a visible instance or create a new instance making sure that no hidden instances exist.

How can I kill the hidden instance?

 Dim procs() As Process = Process.GetProcessesByName("SLDWORKS")
 For Each proc As Process In procs

    '.hidden is not a real property for proc, but for questioning only
    if proc.hidden = true Then
        proc.kill()
    End If  

 Next

Upvotes: 0

Views: 1400

Answers (2)

Troy Mitchel
Troy Mitchel

Reputation: 1810

Here is a solution that I ended up creating that works for our needs. You can verify the results by using the task manager.

VB Version

 Public Function ConnectToSolidWorks() As sldworks.SldWorks
    Dim sw As sldworks.SldWorks = Nothing
    Dim ProcessID As Integer = 0

    'GetObject
    'Will only attach to an active solidworks session in the (Apps)
    'Will NOT attach to solidworks session in (Background processes)
    Try
        sw = GetObject(, "SldWorks.Application")
        If sw IsNot Nothing Then
            If sw.Visible = False Then sw.Visible = True
            ProcessID = sw.GetProcessID
        End If
    Catch ex As Exception
    End Try

    'Kill any other session of solidworks other than the active session
    'by comparing the ProcessID's
    Dim procs() As Process = Process.GetProcessesByName("SLDWORKS")
    For Each proc As Process In procs
        If proc.Id <> ProcessID Then
            proc.Kill()
        End If
    Next

    'CreateObject
    'If GetObject did not attach to an active session of solidworks then 
    'create a brand new instance of solidworks session
    If sw Is Nothing Then
        sw = CreateObject("SldWorks.Application")
        If sw IsNot Nothing Then
            If sw.Visible = False Then sw.Visible = True
        End If
    End If

    Return sw

End Function

C# Version

public sldworks.SldWorks ConnectToSolidWorks()

{ sldworks.SldWorks sw = null; int ProcessID = 0;

//GetObject
//Will only attach to an active solidworks session in the (Apps)
//Will NOT attach to solidworks session in (Background processes)
try {
    sw = Interaction.GetObject(, "SldWorks.Application");
    if (sw != null) {
        if (sw.Visible == false)
            sw.Visible = true;
        ProcessID = sw.GetProcessID;
    }
} catch (Exception ex) {
}

//Kill any other session of solidworks other than the active session
//by comparing the ProcessID's
Process[] procs = Process.GetProcessesByName("SLDWORKS");
foreach (Process proc in procs) {
    if (proc.Id != ProcessID) {
        proc.Kill();
    }
}

//CreateObject
//If GetObject did not attach to an active session of solidworks then 
//create a brand new instance of solidworks session
if (sw == null) {
    sw = Interaction.CreateObject("SldWorks.Application");
    if (sw != null) {
        if (sw.Visible == false)
            sw.Visible = true;
    }
}

return sw;

}

Upvotes: 0

Chris Barlow
Chris Barlow

Reputation: 3314

You can get the window state of the process and use that to determine whether or not it is currently visible to the user, as described in this StackOverflow question:

Get window state of another process

This will involve using P/Invoke (unmanaged code), just FYI.

For your convenience, here's the same code from that answer translated to VB:

  Shared Sub Main(args() As String)
     Dim procs() As Process = Process.GetProcesses()

     For Each proc As Process In procs
        If proc.ProcessName = "notepad" Then
           Dim placement = GetPlacement(proc.MainWindowHandle)
           MessageBox.Show(placement.showCmd.ToString())
        End If
     Next
  End Sub

  Private Shared Function GetPlacement(hwnd As IntPtr) As WINDOWPLACEMENT
      Dim placement As WINDOWPLACEMENT = New WINDOWPLACEMENT()
      placement.length = Marshal.SizeOf(placement)
      GetWindowPlacement(hwnd, placement)
      Return placement
  End Function

  <DllImport("user32.dll", SetLastError:=True)>
  Friend Shared Function GetWindowPlacement(ByVal hWnd As IntPtr, ByRef lpwndpl As WINDOWPLACEMENT) As <MarshalAs(UnmanagedType.Bool)> Boolean
  End Function

  <Serializable>
  <StructLayout(LayoutKind.Sequential)>
     Friend Structure WINDOWPLACEMENT
     Public length As Integer
     Public flags As Integer
     Public showCmd As ShowWindowCommands
     Public ptMinPosition As System.Drawing.Point
     Public ptMaxPosition As System.Drawing.Point
     Public rcNormalPosition As System.Drawing.Rectangle
  End Structure

  Friend Enum ShowWindowCommands As Integer
     Hide = 0
     Normal = 1
     Minimized = 2
     Maximized = 3
  End Enum


If the window is indeed in a "Normal" window state, then perhaps its position is not one to which you have access. Try using this code to show the position of the window.

  Dim procs() As Process = Process.GetProcesses()

  For Each proc As Process In procs
     If proc.ProcessName = "notepad" Then
        Dim placement = GetPlacement(proc.MainWindowHandle)
        MessageBox.Show(placement.showCmd.ToString())
        Dim windowRect As Rectangle = New Rectangle()
        GetWindowRect(proc.MainWindowHandle, windowRect)
        MessageBox.Show(windowRect.Top.ToString() + " | " + windowRect.Left.ToString() + " | " + windowRect.Bottom.ToString() + " | " + windowRect.Right.ToString())
     End If
  Next

And here's the declaration for GetWindowRect

<DllImport("user32.dll", SetLastError:=True)> _
Friend Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lprect As Rectangle) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function


Since the window border is non-traditional, let's try this guy:

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Friend Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
End Function

Upvotes: 1

Related Questions