open excel file without creating new instance - excel

i've looked up all topics regarding this and still can't find solution.
My main issue is that any time I'm opening excel file from my application it gets opened in new instance. What i want - detect if there's running excel, if there is - use this instance, if not - create new one.
This is not working:
Dim xlsApp As Object
Dim AllExcelProcess() As Process = System.Diagnostics.Process.GetProcessesByName("Excel")
If AllExcelProcess.Length = 0 Then xlsApp = New Excel.Application Else xlsApp = GetObject(, "Excel.Application")
AllExcelProcess works correctly returning that there's running excel application, yet the GetObject always returns nothing. What am I doing wrong?

This works for me from within Word and an excel instance already open. Microsoft 365.
Sub main()
On Error Resume Next
Set excelapp = GetObject(class:="Excel.Application")
'Clear the error between errors
Err.Clear
If excelapp Is Nothing Then Set excelapp = CreateObject(class:="Excel.Application")
If Err.Number = 429 Then
MsgBox "Excel could not be found, aborting."
Exit Sub
End If
On Error GoTo 0
excelapp.Workbooks("Book2").sheets("Sheet1").Range("j2").Value = 2
End Sub

Easier way to do what I wanted:
On Error Resume Next
Dim xlsApp As Object = GetObject(, "Excel.Application")
On Error GoTo 0
If xlsApp Is Nothing Then xlsApp = New Excel.Application
I had 2 issues you might want to check out:
You have Microsoft Excel library loaded under References. If you can't find it, add existing EXCEL.EXE to it
If still not working, try GetObject on other objects, can VS detect their classes or not. In my case it was not working at all
Solution:
I added MS Excel library, created new solution. GetObject started working there, everything further was easy using above code.

Related

Excel VBA Run Time error the second times

Can anyone say me why the second time I run the macro I receive a runtime error?
Dim wApp as Object
Dim wDoc as Object
Set wApp = CreateObject("word.Application")
Set wDoc = wApp.Documents.Add(Template:="Test.dotm", Visible:=True)
On Microsoft support:
"Visual Basic has established a reference to Word due to a line of code that calls a Word object, method, or property without qualifying it with a Word object variable. Visual Basic does not release this reference until you end the program. This errant reference interferes with automation code when the code is run more than once."
I don't see any unqualified object or method or property in my code.
I think it's likely that MS Word is already running. So here are a couple of routines from my library to check if MS Word is already running or not, and to make a connection to the process.
Option Explicit
Public Function MSWordIsRunning() As Boolean
'--- quick check to see if an instance of MS Word is running
Dim msApp As Object
On Error Resume Next
Set msApp = GetObject(, "Word.Application")
If Err > 0 Then
'--- not running
MSWordIsRunning = False
Else
'--- running
MSWordIsRunning = True
End If
End Function
Public Function AttachToMSWordApplication() As Word.Application
'--- finds an existing and running instance of MS Word, or starts
' the application if one is not already running
Dim msApp As Word.Application
On Error Resume Next
Set msApp = GetObject(, "Word.Application")
If Err > 0 Then
'--- we have to start one
' an exception will be raised if the application is not installed
Set msApp = CreateObject("Word.Application")
End If
Set AttachToMSWordApplication = msApp
End Function

How do I use an Outlook macro to connect to an excel file that's already open?

I'm trying to write a Macro that will refer out to a file I use to track credits(I call it Master6 below). In the code excerpt below I try to do some initial testing like, see if excel is even running, or if the Master6 file is already open. I'm able to get past the line of code where it correctly determines that the Master6 file is open, but then I get a Run Time error 9 at the part where it says "Set xWb = xExcelApp.Workbooks(xExcelFile)". At this line of code I'm trying to specify what xWb(aka my workbook) should be.
Note that I originally asked this question and I got one response saying, "You need to make sure that both applications are run under the same security context (run as admin or same user). There is no way to access/automate application which is run under a different security context." I don't know how to determine what security context a file is open under/how to make it match security contexts, even though I tried researching it.
Sub SearchQueryForCredits()
'Declare some initial variables
Dim xExcelFile As String
Dim xExcelApp As excel.Application
Dim xWb As excel.Workbook
Dim xWs As excel.Worksheet
Dim xExcelRange As excel.Range
Dim Cell As Range
xExcelFile = "C:\Users\USER\Documents\Desktop Credits\MASTER6.xlsm"
'initiate Excel object...Therefore, you can use this to test if there is an Excel instance already open on your machine.
On Error Resume Next
Set ExApp = GetObject(, "Excel.Application")
On Error GoTo 0
If ExApp Is Nothing Then Set ExApp = New excel.Application
'LOGIC TO TELL IF THE MASTER6 FILE IS ALREADY OPEN
Dim Ret
Ret = IsWorkBookOpen(xExcelFile)
'What to do if the Master6 file is open
If Ret = True Then
Set xExcelApp = GetObject(, "Excel.Application")
If Err <> 0 Then
MsgBox "MASTER6 is not running"
Else
MsgBox "MASTER6 is running"
End If
Set xWb = xExcelApp.Workbooks(xExcelFile) <---- THIS IS WHERE I GET "RUN TIME ERROR '9': SUBSCRIPT OUT OF RANGE
Set xWs = xWb.Sheets("Query Run")
Set xExcelRange = xWs.Range("I:I")
'What to do if the Master6 file is NOT open
Else.......'rest of code i don't think is relevant to this issue
Also, my code above uses the function below in order to tell if my Master6 file is open.
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
Any assistance would be greatly appreciated! Thanks!
If Excel is run under a different security context your VBA macro will not find the process in the code, so the following code:
Set xExcelApp = GetObject(, "Excel.Application")
Will not be successful. You will have to create a new Excel instance and open the file anew.
' Start Excel and get Application object.
Set oXL = CreateObject("Excel.Application")
oXL.Visible = True
Read more about that in the How to automate Microsoft Excel from Visual Basic article.
Also you may consider using the Open XML SDK if you deal with open XML documents only.

VB.Net - Background Excel process REOPENS after closing file

I have been searching all over for this problem, but I can't seem to find one that quite matches my issue.
I am creating a new excel file, filling it with data, and showing it to user. While monitoring the task manager i can see that once the file has been created and open for the user, the background process disappears as it is supposed to. (The main process is still running up top because the file is open.)
The problem I have is that once the user closes the file, Excel background process pops back up in list and won't go away until program (that generated the file) is closed.
This is the clean up that I am using;
Dim xlObject As New Excel.Application
Dim xlBook As Excel.Workbook = Nothing
Dim xlSheet As Excel.Worksheet = Nothing
xlBook = xlObject.Workbooks.Add
xlSheet = xlBook.Worksheets(1)
'Fill data and do some formatting
xlBook.SaveAs("FileName")
xlObject.Visible = True
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
xlSheet = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook)
xlBook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlObject)
xlObject = Nothing
Is there something that I am missing? Why is the background process continuing and only go away once the creating program is closed?
This is using Visual Studios 2013,
Office 365 Excel,
and Windows 10 Pro
You see, in Interop, you should avoid accessing an object through another object such as
xlBook = xlObject.Workbooks.Add
This is called the two dot rule. The reasoning is that the Workbooks object is then referenced in .NET and orphaned (and should also be killed as you have the other three)
So make a reference to the Workbooks, then kill that as well.
Dim xlApp As New Excel.Application()
Dim xlBooks = xlApp.Workbooks
Dim xlBook = xlBooks.Add
Dim xlSheet = DirectCast(xlBook.Worksheets(1), Excel.Worksheet)
Try
xlBook.SaveAs("FileName.xlsx")
xlApp.Visible = True
Finally
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
xlSheet = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook)
xlBook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBooks)
xlBooks = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = Nothing
End Try
And, I always struggle with this, because according to the preeminent expert in vb.net on StackOverflow, HansPassant, the two dot rule is just superstition, as he said "Feel free to continue to ignore [the two dot rule], it is nonsense and causes nothing but grief" but in the case of your question, I can only make it work by following the two dot rule, and NOT by using Hans' solution:
GC.Collect()
GC.WaitForPendingFinalizers()
Perhaps Hans will see this and set us straight!

MS Access: Open 2016 Excel and getObject

I've been struggling with this problem for the last few hours and tried multiple solutions to no avail.
I'm trying to open an excel 2016 (64-bit) report in MS Access, the default excel is 2003 and must stay that way for now.
My code is:
Dim xlTmp As excel.Application
Shell ("C:\Program Files\Microsoft Office\root\Office16\EXCEL.exe")
Set xlTmp = GetObject(, "Excel.Application")
This code does exactly what I want only when I am stepping through in debug mode, because excel doesnt fully start up before it tries to grab the object.
If run normally it throws up an error:
Run-Time error '429'
ActiveX component can't create object
I've tried some of the following solutions to no avail:
Function OpenExcel()
x = Shell("C:\Program Files\Microsoft Office\root\Office16\EXCEL.exe", vbNormalFocus)
OpenExcel = x
End Function
Function GetOpenExcel() As excel.Application
Set GetOpenExcel = GetObject(, "Excel.Application.16")
TryAgain:
On Error GoTo NoExcel
Set xlTmp = GetObject(, "Excel.Application.16")
On Error GoTo 0
xlTmp.Visible = True
Set GetOpenExcel = xlTmp
Exit Function
NoExcel:
Resume TryAgain
End Function
And this
Set ie = Nothing
cnt = 0
cnt = xlTmp.Windows.count
sh = Shell("C:\Program Files\Microsoft Office\root\Office16\EXCEL.exe", vbNormalFocus)
Do Until xlTmp.Windows.count = cnt + 1
Loop
Set xlTmp = GetObject("excel.Application.16")
Set sh = xlTmp.Windows(xlTmp.Windows.count - 1)
I've also tried switching around my references a bit, with a little confusion, but here is what I have at the moment:
MS Access References
Thanks in advance and any help would be appreciated.
Just use
Set xlTmp = CreateObject("Excel.Application")
instead of GetObject
UPDATE
This code worked for me, I have default 2016 and not default 2010:
Private Sub Command0_Click()
Dim xlTmp As Object
Shell "D:\Program Files (x86)\Microsoft Office 2010\Office14\EXCEL.EXE", vbNormalFocus
TryAgain:
On Error GoTo NoExcel
Set xlTmp = GetObject(, "Excel.Application")
On Error GoTo 0
'here I received correct xlTmp
Exit Sub
NoExcel:
Resume TryAgain
End Sub

Access VBA: working with an existing excel workbook (Run-Time error 9, if file is already open)

I'm writing a macro in Access that (hopefully) will:
create an Excel worksheet
set up and format it based on information in the Access database
after user input, will feed entered data into an existing Excel master file
Opening the blank sheet etc. is working absolutely fine, but I'm stuck trying to set the existing master file up as a variable:
Sub XLData_EnterSurvey()
Dim appXL As Excel.Application
Dim wbXLnew, wbXLcore As Excel.Workbook
Dim wsXL As Excel.Worksheet
Dim wbXLname As String
Set appXL = CreateObject("Excel.Application")
appXL.Visible = True
wbXLname = "G:\[*full reference to file*].xlsm"
IsWBOpen = fnIsWBOpen(wbXLname)
'separate function (Boolean), using 'attempt to open file and lock it' method
'from Microsoft site.
If IsWBOpen = False Then
Set wbXLcore = appXL.Workbooks.Open(wbXLname, True, False)
'open file and set as variable.
ElseIf IsWBOpen = True Then
wbXLcore = appXL.Workbooks("ResultsOverall.xlsm") 'ERROR HERE.
'file is already open, so just set as variable.
End If
Debug.Print wbXLcore.Name
Debug.Print IsWBOpen
Set appXL = Nothing
End Sub
When the file is closed, this works perfectly. However, when it's open I get:
Run-Time error '9':
Subscript out of range
I'm only just starting to teach myself VBA (very trial and error!) and nothing else I've seen in answers here / Google quite seems to fit the problem, so I'm a bit lost...
Considering that it works fine when the file is closed, I suspect I've just made some silly error in referring to the file - perhaps something to do with the 'createobject' bit and different excel instances??
Any suggestions would be much appreciated! Thanks
Thank you #StevenWalker
Here's the working code:
Sub XLData_EnterSurvey()
Dim appXL As Excel.Application
Dim wbXLnew As Excel.Workbook, wbXLcore As Excel.Workbook
Dim wsXL As Excel.Worksheet
On Error GoTo Handler
Set appXL = GetObject(, "Excel.Application")
appXL.Visible = True
Dim wbXLname As String
wbXLname = "G:\ [...] .xlsm"
IsWBOpen = fnIsWBOpen(wbXLname)
If IsWBOpen = False Then
Set wbXLcore = appXL.Workbooks.Open(wbXLname, True, False)
ElseIf IsWBOpen = True Then
Set wbXLcore = appXL.Workbooks("ResultsOverall.xlsm")
End If
Set appXL = Nothing
'-------------------Error handling------------------
Exit Sub
' For if excel is not yet open.
Handler:
Set appXL = CreateObject("Excel.Application")
Err.Clear
Resume Next
End Sub
Sorry I'm on my phone so I can't go in to too much detail or do much with the code but at a glance I think you might need to add an error handler so that if the file is already open, a different line of code is executed.
Add 'On error go to handler' (before creating the excel object) and at the bottom
Of your code add 'handler:'. In the error handler, use get object rather than create object.
You will have to ensure you use exit sub before the error handler or it will run the handler every time you run the code.
You can see an example of what I mean here: How to insert chart or graph into body of Outlook mail
Although please note in this example it's the other way round (if error 'getting' outlook, then create it).
Example in link:
Set myOutlook = GetObject(, "Outlook.Application")
Set myMessage = myOutlook.CreateItem(olMailItem)
rest of code here
Exit Sub
'If Outlook is not open, open it
Handler:
Set myOutlook = CreateObject("Outlook.Application")
Err.Clear
Resume Next
End sub
If you move the appXL.Workbooks statement to the debugging window, you will find that the names of the items in that collection are without extension.
So in your case, I'm guessing the line should read:
wbXLcore = appXL.Workbooks("ResultsOverall")

Resources