I have been struggling with what seems to be a common problem regarding opening, running Excel workbook macros, and closing the application from a visual basic script file (.vbs). I cannot terminate the Excel.exe.
I have found a number of recommendations about closing out the objects in the correct order, quitting before setting to nothing, being explicit about each object belonging to the parent object, but I still cannot seem to close of out EXCEL.EXE without manual intervention.
Some mention running a cmd script to kill Excel. I kick off a script like this manually when I have verified it is safe to do so but it is often not. I have dozens of individual batches kicked off each day, and some may be running halfway through during the kick off and completion of another. I would like the .vbs to close its created Excel instance so as to not overrun the memory.
Here is the skeleton of my script:
Set Params = Wscript.Arguments ' some arguments used in the run
Set eApp = CreateObject("Excel.Application")
eApp.Application.DisplayAlerts = False
' CreateObject("WScript.Shell").Run happens here for a log start
Set objWorkbook = eApp.Workbooks.Open("...")
eApp.Application.Visible = True
eApp.Windows(1).Visible = True
eApp.Worksheets(1).Activate
eApp.Application.Run "'...'!...", Cstr(Params(0)), Cstr(Params(1))
objWorkbook.Close False
eApp.Application.DisplayAlerts = True
Set objWorkbook = Nothing
' CreateObject("WScript.Shell").Run happens here for a log complete
eApp.Application.Quit
Set eApp = Nothing
Set Params = Nothing
Wscript.Quit
Is there anything that those more experienced can spot with the above code?
Related
I have made a quick app for a dept at work that takes users input text fields and writes them to an excel object. The challenge of the project was that it needed to create the worksheet, write to it, print it, clear out certain confidential information, then save it, (has to print before being saved). Everything works great except that when I use the print dialog to select which printer to send it to, it will only print to the user's default printer or last printer used. I don't want to change their default printers as that will confuse them and cause chaos with some other software we have that is really particular to it's printing locations. I've searched tirelessly online and only found solutions for if I am printing a word document and not a worksheet object.
I believe this is all the relevant code:
Imports Excel = Microsoft.Office.Interop.Excel
Dim objExcel As New Excel.Application
Dim objWorkbook As Excel.Workbook
Dim objWorksheet As Excel.Worksheet
Dim PrintDialog1 As New PrintDialog()
Dim result As DialogResult = PrintDialog1.ShowDialog()
If result = DialogResult.OK Then
PrintDialog1.PrinterSettings = PrintDocument1.PrinterSettings
objWorksheet.PrintOutEx()
MessageBox.Show(PrintDialog1.PrinterSettings.PrinterName)
MsgBox("Order Printing Completed")
ElseIf result = DialogResult.Cancel Then
objExcel.DisplayAlerts = False
objWorkbook.Saved = True
objWorkbook.Close(False)
objExcel.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorksheet)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkbook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objExcel)
ProgressBar1.Value = 200
ProgressBar1.Visible = False
Exit Sub
End If
Also first question on Exchange, so I don't have a lot of privileges, (aka won't be able to respond to comments right away until allowed), also new to coding in general, and this websites' stricter than MLA question and answer protocol, so be kind.
Open the Printers & Scanners settings in Windows.
At the bottom of your list of printers & scanners make sure that "Allow Windows to manage my default printer" is selected/checked/ticked.
Should fix your problem.
Situation - I have a macro where I need to send keystrokes to two Firefox windows in order. Unfortunately both windows have the same title. To handle this I have activated the window, sent my keystrokes, then used F6 to load the URL of the second window and then send the keystrokes then use F6 to return it to the original page.
The issue is that loading the webpages is unreliable. Page load speeds vary so much that using a wait command is not consistent or reliable to ensure the keystroke makes it to the second window.
Question -
I've read a scattering of posts that mentioned that app activate will work with Process ID's. Since each window would have its own PID that would be an ideal way to handle 2 windows with the same title. I am unable to find information specifically how to determine the PID of each window with a given name.
You can use something like the following. You'll have to tinker about with the different info available in the Win32_Process class to figure out which window is which. It's also important to keep in mind that one window could mean many processes.
Public Sub getPID()
Dim objServices As Object, objProcessSet As Object, Process As Object
Set objServices = GetObject("winmgmts:\\.\root\CIMV2")
Set objProcessSet = objServices.ExecQuery("SELECT ProcessID, name FROM Win32_Process WHERE name = ""firefox.exe""", , 48)
'you may find more than one processid depending on your search/program
For Each Process In objProcessSet
Debug.Print Process.ProcessID, Process.Name
Next
Set objProcessSet = Nothing
End Sub
Since you'll probably want to explore the options with WMI a bit, you may want to add a Tools>>References to the Microsoft WMI library so you don't have to deal with Dim bla as Object. Then you can add breakpoints and see what's going on in the Locals pane.
After adding the reference:
Public Sub getDetailsByAppName()
Dim objProcessSet As WbemScripting.SWbemObjectSet
Dim objProcess As WbemScripting.SWbemObject
Dim objServices As WbemScripting.SWbemServices
Dim objLocator As WbemScripting.SWbemLocator
'set up wmi for local computer querying
Set objLocator = New WbemScripting.SWbemLocator
Set objServices = objLocator.ConnectServer(".") 'local
'Get all the gory details for a name of a running application
Set objProcessSet = objServices.ExecQuery("SELECT * FROM Win32_Process WHERE name = ""firefox.exe""", , 48)
RecordCount = 1
'Loop through each process returned
For Each objProcess In objProcessSet
'Loop through each property/field
For Each Field In objProcess.Properties_
Debug.Print RecordCount, Field.Name, Field.Value
Next
RecordCount = RecordCount + 1
Next
Set objProcessSet = Nothing
Set objServices = Nothing
Set objLocator = Nothing
End Sub
That will print out every property of every process found for the name 'firefox.exe'.
The error occurs on
Set report = app.OpenReport("S:\Supply Chain\Scheduling\HRE\HRE.imr")
It works for some users and not others.
Any alternative methods or maybe some settings that need to be changed?
Its an objected defined error.
`Sub Update()
Dim app As Object
Dim report As Object
Dim catalog As Object
'open cognos'
Set app = CreateObject("CognosImpromptu.Application")
app.Visible True
app.Activate
'open catalog'
app.OpenCatalog "R:CognosUsers/Cognos Catalogs/SUPPLY CHAIN.cat"
app.Visible True
app.Activate
'open report'
Set report = app.OpenReport("S:\Supply Chain\Scheduling\HRE\HRE.imr")
report.RetrieveAll
'save report path'
report.Export "S:\Supply Chain\Scheduling\HRE\Raw", "X_ascii.flt"
'close cognos'
report.CloseReport
app.Quit`
You might have already looked at this, but the first thing I would check is (1) if the R:\ and S:\ are properly mapped (if you click on the R:\ and S:\ in the file explorer, does it take you where you would expect?); (2) that the user has access to the various folders/files/applications in the code.
I've got a problem with a vbscript which creates Excel objects and reads from an Excel file.
The vbscript is executed from an Excel macro, and then creates and opens the Excel file and reads from it. The problem is that the Excel object isn't allways closed, even though I'm trying to to it.
Here's the code from the vbscript:
Set ExcelObject = createobject("Excel.Application")
ExcelObject.workbooks.open testWorkBookPath
Set testActionArray = CreateObject( "System.Collections.ArrayList" )
Function getTestsCaseActions (testsPath, esheet, row, col)
Set my_sheet = ExcelObject.sheets.item(esheet)
tempArray = array(my_sheet.cells(row, col-2), "")
testActionArray.Add tempArray
Do While my_sheet.cells(row, col).Value <> ""
tempArray = array(my_sheet.cells(row, col), my_sheet.cells(row+1, col))
testActionArray.Add tempArray
col = col+1
Loop
End Function
getTestsCaseActions testWorkBookPath, testCaseSheet, 3, 4
ExcelObject.Quit
Now, if I run the above code and watch the process explorer, a new Excel process is spawned when the script is started, and then closes, as expected.
However, if I insert this code after running the function, before the ExcelObject.Quit line:
For Each ArrayItem in testActionArray
IF ArrayItem(1) = "" Then
Wscript.Echo ArrayItem(0)
Else
Wscript.Echo ArrayItem(0) & " -> " & ArrayItem(1)
End If
Next
ExcelObject.Quit (STILL HERE)
then the spawned process does NOT quit, and the process list grows until Excel goes completely bananas.
I don't understand this; All the last bit of code does is loop through the ArrayList and print the contents. Why's not the process quitting?
EDIT: At seems that at least some of the Excel objects eventually disappear from the Process Explorer, but this takes about 20-30 minutes. And it's just a few of them - most are still there. At least my list at the moment has shrinked some, but there are still about 15 Excel processes running.
Also, suddenly this message appears:
File Now Available
'filename.xlsm ' is now available for editing. Choose Read-Write to open it for editing.
This line seems to help. It doesn't completely remove all extra processes, but the number grows to five, then goes back to two, and so on. So it works pretty well.
dim book: for each book in ExcelObject.Workbooks: book.saved = true: next
I've read many post looking for my answer, but all are similar to this:
Reading excel files in vb.net leaves excel process hanging
My problem is that I don't quit the app...
The idea is this:
If a User has Excel Open, if he has the file I'm interested in open... get that Excel instance and do whatever I want to do...
But I don't to close his File after I'm done... I want him to keep working on it, the problem is that when he closes Excel... The process keeps running... and running... and running after the user closes Excel with the X button...
this is how I try to do it
This piece is used to know if he has Excel open, and in the For I check for the file name I'm interested in.
Try
oApp = GetObject(, "Excel.Application")
libroAbierto = True
For Each libro As Microsoft.Office.Interop.Excel.Workbook In oApp.Workbooks
If libro.Name = EquipoASeccionIdSeccion.Text & ".xlsm" Then
Exit Try
End If
Next
libroAbierto = False
Catch ex As Exception
oApp = New Microsoft.Office.Interop.Excel.Application
End Try
here would be my code... if he hasn't Excel open, I create a new instance, open the file and everything else.
My code ends with this:
If Not libroAbierto Then
libroSeccion.Close(SaveChanges:=True)
oApp.Quit()
Else
oApp.UserControl = True
libroSeccion.Save()
End If
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(libroOriginal)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(libroSeccion)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(origen)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(copiada)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oApp)
libroOriginal = Nothing
libroSeccion = Nothing
oApp = Nothing
origen = Nothing
copiada = Nothing
nuevosGuardados = True
So you can see that, if I opened the file, I call oApp.Quit() and everything else and the Excel Process ends after a few seconds (maybe 5 aprox.)
BUT if I mean the user to keep the file open (not calling Quit()), Excel process keeps running after the user closes Excel with the X button.
Is there any way to do what I try to do?? Control a open instance of excel and releasing everything so when the user closes it with the X button, the Excel Process dies normally???
Thanks!!!
It seems to me it would be better to use CreateObject instead of GetObject(, "Excel.Application") (see http://support.microsoft.com/kb/288902/en and http://technet.microsoft.com/en-us/library/ee176980.aspx). Then call of Quit method before calling of FinalReleaseComObject and assigninh Nothing will be have a clear sense.