0

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
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Troy Mitchel
  • 1,790
  • 11
  • 50
  • 88

2 Answers2

1

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
Community
  • 1
  • 1
Chris Barlow
  • 3,274
  • 4
  • 31
  • 52
  • Strange, I ran the code from the link and results came back as Windows Normal on both instances even though one instance was minimized and the other was hidden in background processes. – Troy Mitchel Jul 23 '14 at 13:18
  • I just updated my code and tried it using Notepad (since that's what is in the example) and it works fine. It's possible that this SLDWORKS program is doing somethng irregular like moving the form off screen or something. Then the WindowState wouldn't show as being Minimized/Hidden. How sure are you that the window is in fact invisible? – Chris Barlow Jul 23 '14 at 13:44
  • We know for sure by using the Task Manager. It will show an instance of solidworks but will not be visible at all on the desktop. This is a known issue of SolidWorks, Users are used to going to the taks manager and Ending Process first and then starting a new instance of SolidWorks. – Troy Mitchel Jul 23 '14 at 14:09
  • The window may be "visible" and in a "normal" window state, but not visible __to the user__ on the screen though. Just because you can't see it, doesn't mean that the window is hidden or minimized. It could just be located outside the Virtual Desktop (so, off all your monitors). It could be 100% translucent. It could be in a "closing" state perpetually. You could try getting the _position_ of the window instead of its state... I'll add some code for you to try. – Chris Barlow Jul 23 '14 at 14:14
  • I updated the code, (minimized) or (not visible at all) have the same result (0 | 0 | 0 | 0 ) when getting the windowRect – Troy Mitchel Jul 28 '14 at 16:01
  • Well - there you go. =) Use that as your indicator that the window needs to be closed. – Chris Barlow Jul 28 '14 at 16:05
  • This works great for Notepad. But for solidworks the function returns 'normal' when minimized or normal, 'maximized' for maximized. Cannot figure out how to catch the minimized state for Solidworks. – Troy Mitchel Jul 30 '14 at 11:27
  • Does the SolidWorks window have a normal form border (with the usual windows title bar, minimize/maximize/close buttons, etc? Or does it look custom built? – Chris Barlow Jul 30 '14 at 12:43
  • It looks custom built and also has minimize/span displays/restore/close. see [solidworks link](http://help.solidworks.com/2014/English/SolidWorks/sldworks/c_user_interface_overview.htm) – Troy Mitchel Jul 30 '14 at 12:57
  • That's why my solution doesn't work. The API's I mentioned rely upon a traditional Windows form border. I'm posting one more API call for you to try. – Chris Barlow Jul 30 '14 at 13:09
  • I tried the new method 'IsWindowVisible' and the result was true in all cases: Maximized, Normal, Minimized, Hidden in Background Processes. Currently when we attach to the solidworks object, if we find more than one in the processes we prompt the user to close them. – Troy Mitchel Jul 31 '14 at 20:23
  • Alright, well I'm out of ideas. I can delete my answer if you like so you'll get more attention. – Chris Barlow Jul 31 '14 at 21:38
  • I will leave your answer as it may help others for standard apps, In the meantime I will keep searching for a solution for the SolidWorks issue. Thanks for all your help. – Troy Mitchel Aug 02 '14 at 12:21
0

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;

}

Troy Mitchel
  • 1,790
  • 11
  • 50
  • 88