close instance of excel that does not have workbook associated with? - vb.net

I have some blank instance of excel opened. I want to be able to close the instances of excel that does not have a workbook associated with it.
Public xlsApp As Excel.Application
Public xlsWB As Excel.Workbook
public openExcel()
Try
Dim path As String
path = "C:\excel.xlsm"
xlsWB = xlsApp.Workbooks.Open(path)
Catch ex As Exception
My.Application.Log.WriteException(ex, TraceEventType.Error, "Additional information or details")
Exit Sub
End Try
end sub
Public Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
====when run will open one excel, if excel window is close, the instance stays on, you will see the blank excel workbook. I want to close that instance when this sub re runs.
public doThis()
releaseObject(xlsApp)
releaseObject(xlsWB)
openExcel() <<==
end sub

For Excel to close properly you have to unload all of your COM objects
Dim xl As Excel.Application = New Excel.Application()
Dim wb As Excel.Workbook = xl.Workbooks.Add()
Dim ws As Excel.Worksheet = wb.Worksheets.Add()
wb.Close()
xl.Quit()
ReleaseComObject(ws)
ReleaseComObject(wb)
ReleaseComObject(xl)
ws = Nothing
wb = Nothing
xl = Nothing
If you aren't consuming the Excel instance and you are just displaying it then maybe try this. This will kill the process as soon as it is created so you'll want to put the p.Kill() in another place. Also note that this kills the process so no changes will be saved.
Dim p As System.Diagnostics.Process = System.Diagnostics.Process.Start(path)
p.Kill()

Related

GetObject error in new version of SolidWorks

I have a user who in 2018 copied a macro from the web. After being upgraded to 2020 the macro can't get past the first line;
Set swApp = GetObject(,"Application.SldWorks")
The error is
Run-time error '429' ActiveX component can't create object
I tried to reset the libraries and have gone through multiple forum posts looking a solution. This post was the closest to my issue.
Below is the full code;
Dim swApp As SldWorks.SldWorks
Public Sub main()
Set swApp = GetObject(,"Application.SldWorks")
Dim ActiveDoc As ModelDoc2
Set ActiveDoc = GetObject(, "Sldworks.Application").ActiveDoc
If Not ActiveDoc Is Nothing Then
If ActiveDoc.GetType = 2 Then
GoTo Traverse
End If
End If
MsgBox ("This macro should be run, with an open assembly as the active document.")
Exit Sub
Traverse:
Dim myModel As ModelDoc2
Set myModel = ActiveDoc
Call Traverse(myModel, myModel.ConfigurationManager.ActiveConfiguration.Name)
MsgBox ("Done")
End Sub
You shouldn't use reserved names like ActiveDoc as a variable name. You don't need to use GetObject on objects that are already directly referenced by the host. You don't need Call anymore.
I only get the error that you see if I use the GetObject command that you have there.
I have tested this code in SolidWorks 2020:
Option Explicit
Dim swApp As Object
Sub main()
Set swApp = Application.SldWorks
Dim thisDoc As ModelDoc2
Set thisDoc = swApp.ActiveDoc
If Not thisDoc Is Nothing Then
If thisDoc.GetType = 2 Then
Dim myModel As ModelDoc2
Set myModel = thisDoc
Traverse myModel, myModel.ConfigurationManager.ActiveConfiguration.Name
MsgBox "Done"
Exit Sub
End If
End If
MsgBox "This macro should be run, with an open assembly as the active document."
End Sub

List all opened WorkBooks in the Task Bar

I am trying to list all the opened workbooks and their corresponding sheets in the task bar after that I should be able to select one workbook of the list and open it. My first try was to to show Excel process in Task-Manager but it only shows one open workbook without detecting the number of sheets.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim name As Process() = Process.GetProcessesByName("Excel")
For Each names In name
ListView1.Items.Add(names.MainWindowTitle)
If names.MainWindowTitle <> "" Then
ListBox1.Items.Add(names.MainWindowTitle)
End If
Next
End Sub
Next I tried to use this code but also I can only display one opened workbook, I don't know how to loop through them. I don't have problem of changing the whole code if you have any other method cause I am not sure that it's the solution.
Dim oXL As Microsoft.Office.Interop.Excel.Application
oXL = TryCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
oXL.WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMinimized
Dim y As String
y = oXL.ActiveWorkbook.Name
ListBox1.Items.Add(y)
Dim objExcel As Excel.Application = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
Dim objWorkBook As Excel.Workbook = Nothing
Dim totalWorkBooks As Integer = objExcel.Workbooks.Count
For i As Integer = 1 To totalWorkBooks
objWorkBook = objExcel.Workbooks(i)
With objWorkBook
FullName = .FullName
OnlyName = .Name

Code in the workbook module still runs after the file is saved as xlsx

Using a button in VB.NET form, an .xlsm file is opened and saved as .xlsx. The code in the .xlsx file (Workbook_BeforeClose event) is NOT deleted after the file is saved, therefore, when I want to close the file the code runs! After reopening the file there is no code left.
This is my VB.NET class:
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkbooks As Excel.Workbooks
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
xlApp = New Excel.Application
xlWorkbooks = xlApp.Workbooks
xlWorkBook = xlWorkbooks.Open("C:\Temp\testTemplate.xlsm")
xlApp.DisplayAlerts = False
xlWorkBook.SaveAs(Filename:="C:\Temp\testTemp.xlsx", FileFormat:=51) '51=xlOpenXMLWorkbook
xlApp.DisplayAlerts = True
xlApp.Visible = True
'Clean Up
releaseObject(xlWorkBook)
releaseObject(xlWorkbooks)
releaseObject(xlApp)
End Sub
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
GC.WaitForPendingFinalizers()
End Try
End Sub
End Class
This is in the Excel file, workbook module:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "event still runs"
End Sub
How to save the file properly so that NO code would remain in it?
You're right, the code isn't deleted until after it's closed. I suppose you could set some type of flag in the xlsm's BeforeClose event that checks its file type and only runs if it's xlsm. Or you could do a Worksheets.Copy instead of the SaveAs and save the resulting workbook (which won't contain the VBA) as an xlsx, but there could be reference issues to clean up. Or you could set xlApp.EnableEvents=False, close the newly saved xlsx, set it back to True and re-open the xlsx.
Here's a post I wrote on the second option: http://yoursumbuddy.com/copy-an-xlsm-xlsx/

Display hourglass or Please Wait message while Sub runs

I have the following sub running on my form. It can take a while for the sub to run so I want to change the cursor to an hourglass and display a Please Wait message while the code is running. Here is my procedure:
Public Sub GoToSheets(sheetName As String)
'This sub is used to open the workbook on the selected sheet.
'This checks to see if Excel workbook is opened, if not it
'opens Excel, the workbook and then the selected sheet. If the workbook is
'opened, it goes to the selected sheet.
'#param sheetName, sheet to be displayed
Try
'get an existing excel.application object
xlApp = CType(GetObject(, "Excel.Application"), Application)
Catch ex As Exception
'no existing excel.application object - create a new one
xlApp = New Excel.Application
End Try
Dim xlWBName As String = "2011.1004.Compensation Template"
Dim xlBookPath As String = Path.Combine(Directory.GetCurrentDirectory())
xlApp.Visible = True
Try
'get the opened workbook
xlBook = xlApp.Workbooks(xlWBName & ".xlsx")
Catch ex As Exception
'open it
xlBook = xlApp.Workbooks.Open(xlBookPath & "\" & xlWBName & ".xlsx")
End Try
Try
xlSheet = CType(CType(xlBook.Sheets("summarySheet"), Excel.Worksheet), Excel.Worksheet)
Dim strChckRange As String = xlSheet.Range("A2").Value
If strChckRange Is Nothing Then
Dim frmClientInfo As New frmClientInformation
frmClientInfo.ShowDialog()
closeXLApp()
Else
xlSheet = CType(CType(xlBook.Sheets(sheetName), Excel.Worksheet), Excel.Worksheet)
'close the navigation instance on the welcome page
frmNavigation.Close()
'activate requested sheet
xlSheet.Activate()
'display as dashboard
DashboardView()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
frmWelcomePage.Hide()
chkForm()
End If
Catch ex As Exception
End Try
End Sub
I have done some research on this, but so far nothing for Visual Basic.
I suggest creating a PleaseWaitForm that has the label of Please Wait... message on it and then have the form shown as mode-less, change the cursor to hourglass, do Excel work, change cursor back to default and hide the PleaseWaitForm.
Dim pleaseWait As New PleaseWaitForm
pleaseWait.Show()
' Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor
Application.DoEvents
' Execute your GoToSheets method here
' Set cursor as default arrow
Cursor.Current = Cursors.Default
' Hide the please wait form
pleaseWait.Hide()

Calling Sheet from a WorkBook

I'm trying to call the 5th sheet in an open workbook. When I open the workbook from the program I seem to be able to do it:
Dim CurrentRun As New Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
Private Sub GeneralButtonOpener_Click(sender As Object, e As EventArgs) Handles GeneralButtonOpener.Click
CurrentRun.Visible = True
CurrentBook = CurrentRun.Workbooks.Add(MainTemplatePath)
CurrentSheet = CurrentBook.Worksheets(4)
CurrentSheet.Activate()
End Sub
But all my attempts at calling the sheet if the file is already open have failed:
Dim CurrentRun As Microsoft.Office.Interop.Excel.Application
Dim CurrentBook As Microsoft.Office.Interop.Excel.Workbook
Dim CurrentSheet As Microsoft.Office.Interop.Excel.Worksheet
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.Workbooks
CurrentSheet = CurrentBook.Sheets(4)
CurrentSheet.Activate()
or
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim CurrentRun As Microsoft.Office.Interop.Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.ActiveWorkbook
CurrentSheet = CurrentBook.Sheets(4)
CurrentSheet.Activate()
End Sub
I've looked at several examples, but I can't figure out where I'm going wrong. Which surprises me as there seem to be a lot of questions on the subject. Ether a pointer to where this is solved/addressed or what I'm specifically doing wrong would be appreciated.
Thanks!
Much to my surprise, I found that I in fact had dozens of instances of Excel running in the background. When I am debugging, and launch the COM the first instance of Excel is started. The second is started when I open the windows form (the main part of the add-in).
What I didn't know, was that when an exception was thrown, and I stop things from within Visual Studio, only the first instance of Excel was closed. I have code that tries and clean up open applications of Excel, but of course it was not reached because an exception was thrown.
And here I had been thinking I would put Error handling a bit down the road when I had things a little more developed. Clearly I need to address some basic error handling much earlier in my build process. I'm entirely self taught, and somehow made it three years without that being an issue.
Hopefully someone else who wasn't been taught that can see this before pulling their hair out for 14 hours.
Solution
Close all other instances of Excel and the above code works. Address cleanup in error handling and earlier as addressed here: http://support.microsoft.com/kb/317109
Maybe also call the GC, though that seems controversial.
Final code:
....
Imports System.Runtime.InteropServices
....
Dim CurrentRun As New Excel.Application
Dim CurrentBook As Excel.Workbook
Dim CurrentSheet As Excel.Worksheet
....
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
On Error GoTo VortexInYourSoul
CurrentRun = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
CurrentBook = CurrentRun.Workbooks(1)
CurrentRun.Visible = True
CurrentSheet = CurrentBook.Sheets(8)
CurrentSheet.Activate()
CurrentBook.ActiveSheet.name = "LLAMA LALA LLAMALMALMAL"
....
Exit Sub
VortexInYourSoul:
CurrentSheet = Nothing
CurrentBook.Close(False)
CurrentBook = Nothing
CurrentRun.Quit()
CurrentRun = Nothing
MsgBox("Error: " & Err.Description)
End Sub