VBS Start an instance of excel then detach from it - excel

So I basically have a VBS script that's supposed to post data to an Excel sheet asynchronously. I currently do this by using GetObject on the workbook's path like so:
Set xlBook = GetObject(strPath & "\Runner.xlsm")
This seems to work fine, except that the workbook will close at the end of the script if it was not open previously (not desired, I have a macro that will close and save the book when necessary).
This is similar to Question 7708039, EXCEPT I want to intentionally keep the excel instance OPEN, not force it to close (the reverse of his problem).
I think it's closing because the variables referencing the object get destroyed at the end of the script, but I can't figure out how to release those handles without destroying them (i.e. set to Nothing).

Instead of getting a reference to a specific workbook, have you tried getting a reference to Excel and then opening the workbook?
' 1a. Get an existing Excel instance...
Set Excel = GetObject(, "Excel.Application")
' 1b. Or, create one. Make it visible for testing.
Set Excel = CreateObject("Excel.Application")
Excel.Visible = True
' Load the workbook...
Set Workbook = Excel.Workbooks.Open(strPath & "\Runner.xlsm")
' Do stuff and save, if desired.
' Close workbook...
Workbook.Close
' Excel stays open. If you want to close Excel, use:
Excel.Quit

Per phd443322's two comments Comment 1 and Comment 2, this is apparently by design.
The solution here is to trick the object (in this case Excel) into thinking the user will need to interact with it or maintain interaction after the reference is destroyed.
Thus, the proper workaround is to make it interactive, in this case using:
xlApp.Visible = True
Thus Excel becomes visible and won't close just because the reference is destroyed.
Since I don't want this instance of Excel visible, I then have the VBS use xlApp.OnTime to call a macro (after one second, plenty of time for the VBS script to have exited) to hide the application window again.
This makes the application blink up on the screen for a second, but it's the best I can do in this instance.

I had the same problem using
xlApp.Visible = True
with this call on windows
wscript my-script.vbs C:/path/to/file.xml
But when I changed the separator from / to \ it worked:
wscript my-script.vbs C:\path\to\file.xml

Related

How to stop Excel opening some sheets (downloaded via VBA) in new instance, causing PERSONAL.xlsb to invoke a "File in Use" dialog?

I run a lot of macros, and lately had to change to O365, which gave me the "wonderful" 64 bit Excel. One of its most maddening shenanigans is that when I run some macros (working with SAP GUI, creating SAP reports, naming them, saving and downloading to a specific folder where the next macro step opens them and incorporates into a relevant macro sheet), the new Excel opens these in a new instance (which I don't want but cannot prevent - can you help here?), which causes a dialog "File in Use" (which I don't want but cannot prevent - can anyone help me here?) because it tries to open my PERSONAL.XLSB (which I need and therefore don't want to get rid of just because of this) and qualifies it as "locked for editing" by another user, who is myself (which is absolutely stupid but I cannot change it - can anyone help me perhaps with this part?).
Sometimes the macro finishes fine when I don't answer that dialog; sometimes it seems to cause the Excel to hang up in trying to do next steps, sometimes the macro quits on me when I click "Read only" and so on.
All this is maddening also because these files that (possibly) SAP GUI opens, I have to waste my time by closing them after the macro finishes (has anyone a possible solution in stopping SAP opening these files? I was unable to find it anywhere so far.).
In some macros I fixed it by a specific part of code which waits till when these files open up and then it closes them - yet even that wait is wasting my time and it would be better without.
But with O365 and other instances it is even more colorful, because some files open in the same instance (this issue was there even before the O365 though) and I can manually close them after the macro finishes (although again, I have to wait till they open, which is again "vanity and torture of the soul"), but those opening in the new instance (specific to O365) show as blank sheets, I have to click into them, a warning sound follows but no dialog is visible, then I have to click into them again from the Excel icon in the bottom menu bar and then it tells me that I cannot close them because a dialog is open.
Then I need to close this dialog plus the one which appeared about the "File in Use", then I finally wait for the file (that I don't need) to open (because it is already saved inside the folder and already copied and pasted onto the relevant macro sheet) and only then I can close it.
So far I was unable to find anywhere on the internet an advice for how to stop SAP opening these files (when they are already saved where I need them), neither how to stop them opening in new Excel instances. So reluctantly, I think I should aim for at least a tiny little VBA code which will cause my macro to click on the "Read Only" button. Can anyone here help me with any part of this "Excel complaint"?
I do not know how/if SAP can be 'persuaded' to not open the workbooks in discussion... But, I think, you can handle that in a different way the "PERSONAL.XLSB" behavior, from the opening point of view. Of course, if SAP itself has this "bad habit" and not your code opens it in a new session, which have to be solved in a different way...
"PERSONAL.XLSB" is located in "...AppData\Roaming\Microsoft\Excel\XLSTART" folder. All workbooks located in this folder are automatically open when an Excel session starts;
You may change the "PERSONAL.XLSB" workbook path. If you want it to be open when a specific (necessary) workbook needs it, add a reference to it.
addRef. In order to do that, modify the (standard) VBAProject (of "PERSONAL.XLSB"), in, let us say, "VBPersProj", then (being in VBE) trough 'Tools - References...` tick its check box and press 'OK';
If the exported workbook is open in a new session and, even if it does not bother you any more because of the annoying dialogs and you need to identify that specific session, you can use the next function:
Function sameExSession(wbFullName As String, Optional boolClose As Boolean) As Boolean
Dim sessEx As Excel.Application, wb As Workbook
Set sessEx = GetObject(wbFullName).Application
If sessEx.hWnd = Application.hWnd Then
sameExSession = True
Else
sameExSession = False
If boolClose Then
sessEx.Workbooks(Right(wbFullName, Len(wbFullName) - InStrRev(wbFullName, "\"))).Close False
sessEx.Quit: Set sessEx = Nothing
End If
End If
End Function
It offers the possibility to close the workbook and the session itself if it is a different against the one where the code runs. It is an Optional parameter to be used, only if you need that. You can test it in the next way:
Sub testSameExSession()
Dim wbFullName As String
wbFullName = ThisWorkbook.fullName 'use here the full name of the SAP exported workbook
If sameExSession(wbFullName, True) Then
'process the workbook if this is what you need
End If
'if not open in the active session, the workbook could be closed and session quit, choosing the above way
'You can also simply call the function, without the closing parameter, as:
Debug.Print sameExSession(wbFullName)
End Sub
In case of False function retur, it can be closed and reopen in the existing session, if needed...
Edited:
If you need personal.xlsb being used/open when ribbon controls calls some of its Subs/functions, please adapt the code to call it in the next way:
Dim x as Long
x = Run("'C:\Users\your_UserName\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB'!GiveMeFive", 4, 3)
if calling a function (with parameters), which must return. Or
Run "'C:\Users\your_UserName\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB'!YourSubName"
when calling a Sub. In such a way, "Personal.xlsb" is opened if it is closed. And, in your specific case nothing will press the ribbon controls.
But, isn't the ribbon added when a specific workbook is open? Probably, the one you are using to make the above mentioned calls... If so, adding the suggested reference at "Personal.xlsb", will configure the new ribbon tab only when it is loaded. And your mentioned "problem" does not exist, in fact. Is it an add-in?

Copy and Paste between different Excel instances

I bought a software (with a large database), and its output is a simple Excel workbook, not saved anywhere (no path), named generically "Book1", that simply pops up on my screen.
Every time I ask the software for this output, I need to copy the content of this workbook and paste into another workbook, a mother-workbook, as I named it, to consolidate all the data.
I have to repeat this action dozens of times a day, so I thought it would be a great idea to create some VBA code to automate this task.
So... I made a very simple one:
ActiveWorkbook.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
The problem is... Each time the software outputs a new workbook, it seems that it is created in a new instance of Excel, which my macro can't reach. I mean, I run the code, but nothing happens, because my mother-workbook doesn't find the generic, unsaved and located in another excel instance "Book1".
If I open the mother-workbook after the output is opened, OK, the code works, because both are in the same instance. But as I need to keep the mother-workbook open all the time, I can't do this. I don't want to save each new output file either. It would take me a lot of time.
I'm using the 2016 version of Excel, but already tried the 2010 as well. My OS is Windows 10 Pro.
Any thoughts?
This code should do it.
Dim xlapp As Object
Set xlapp = GetObject("Book1").Application
xlapp.ActiveWorkbook.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
xlapp.DisplayAlerts = False
xlapp.Quit
Note that you need to close "Book1" at the end of your code to make sure that the next time an Excel file is created it will also be called "Book1" and not "Book2". And might as well close the Excel instance while we are at it!
For more information on the GetObject function, you can have a look at this page
Thanks a lot, DecimalTurn and Patrick Lepelletier!
The GetObject really helped me. The "closing" command worked better like this:
Sub CollectA()
Dim oApp As Application
Dim oWb As Workbook
Set oWb = GetObject("Book1")
Set oApp = oWb.Parent
oWb.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
oWb.Close False
oApp.Quit
End Sub
Cheers!

Unhide Excel Application Session

I have an Excel VBA method (I didn't write it) that runs and one of the first things it does is hide the Excel session Application.Visible = False.
However, when the method has finished, it does not unhide the Excel session so it remains open and listed in the Task Manager but is hidden and seemingly unusable.
Does anyone know, without have the VBE open (so one can access the Immediate Window and run Application.Visible = True), how to unhide this Excel session? At the moment, I'm simply having to kill the session using the Task Manager.
This isn't a massive deal but I'm just interested if anyone knows how to resurrect such a session.
Like I said, it's not a big deal but was just interested if anyone knew of shortcut key or anything to bring it back.
There is no shortcut as such that I am aware of but you can do this.
Open MS Word and paste this code in the VBA Editor. Close all open instances of Excel which are visible and then run and this code. This will make a hidden instance visible. Manually close the instance and repeat the process if there are more instances.
Option Explicit
Sub Sample()
Dim oXLApp As Object
'~~> Get an existing instance of an EXCEL application object
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
On Error GoTo 0
oXLApp.Visible = True
Set oXLApp = Nothing
End Sub
I am not deliberately using a loop as the hidden instance can have a workbook which you might like to save?
If you want you can convert the above code to a VB Script document which you can directly run from the desktop.
Unfortunately, I don't have the control to make the changes required.
What do you exactly mean? Is the VBA Password Protected? If no then my suggestion is still the same as earlier
This is a case of poor programming. Even if we give a code to close
all hidden Excel instances, that won't help you. Because next time you
run that macro, you will face the same problem again. Why not edit the
existing code and add Application.Visible = True at the end? Is the
VBA password protected? – Siddharth Rout 28 mins ago
A good solution!
Open up Word, assuming you have it, and open the VBA Editor there, then open the Immediate Window (Ctrl+G) and type:
Getobject(, "Excel.Application").Visible = true
and press enter.
I had a similar problem and solved it with code line reordering.
Look for a line like this ActiveWorkbook.Close that might be the reason you cannot unhide the session.
If you can find it, put Application.Visible = True just before it and voila.
as code:
sub runthis()
dim xl as object
set xl = new excel.application 'create session
xl.workbooks.open filename:= "«yourpath»" 'open wb in the new session
xl.visible=true 'this is what you need, show it up!
'rest of the code
end sub
No need for word macro at all.
Open up another excel workbook.
Hit Ctrl+F11 to go to the VBA editor and there yoy will see the running but hidden excel file on the left.
Search the code of the hidden application file for Application.Visible = False and comment it out. Save and restart the file.
Alternatively you can get back the application to show without closing if you type Application.Visible = True in the immediate window (Ctrl+G)

Excel VBA can't open Workbook

First: I'm using Excel 2007, but the code has to work for Excel 2003 as well.
My problem is the following: I need to access cells in a different workbook, which may be closed. The following code can be found all around the web:
Function Foo()
Dim cell As Range
Dim wbk As Workbook
Set wbk = Workbooks.Open("correct absolute path")
' wbk is Nothing here so the next statement fails.
Set cell = wbk.Worksheets("Sheet1").Range("A1")
Foo = cell.Value
wbk.Close
End Function
sadly, wbk is Nothing after the open statement (I'd love to give a better error message, but no idea how I'd do that; what I'd give for a real IDE and an useful language :/). The absolute path is correct and points to a valid excel xlsx file.
Also I assume the best way to do this, is to "cache" the workbook and not open/close it every time the function is called? Any possible problems with that (apart from having to handle the situation when the workbook is already open obviously)?
Image while stepping through:
I can reproduce this problem. It only happens to me when I attempt to paste this code into a user-defined function.
I believe this is by design (the quote is for XL 2003, but the same thing happens to me on XL 2010)
Using VBA keywords in custom functions
The number of VBA keywords you can use in custom functions is smaller than the number you can use in macros. Custom functions are not allowed to do anything other than return a value to a formula in a worksheet or to an expression used in another VBA macro or function. For example, custom functions cannot resize windows, edit a formula in a cell, or change the font, color, or pattern options for the text in a cell. If you include "action" code of this kind in a function procedure, the function returns the #VALUE! error.
http://office.microsoft.com/en-us/excel-help/creating-custom-functions-HA001111701.aspx
The only workaround I've found is to call this kind of code via a normal macro. Something like selecting the cells to apply it to, then looping over Selection or the like.
You can use this (similar to what Bruno Leite proposed, but much simpler to write):
Dim excelApp As New Excel.Application
excelApp.Visible = False
Set WB = excelApp.Workbooks.Open(FileName, xlUpdateLinksNever, True)
As UDFs are called repeatedly, you should make sure to do an excelApp.Quit before exiting the function (and a WB.close(False) before) to avoid having countless Excel instances running on your box.
I spent some thoughts on it and came to the conclusion that you cannot mess around with the workbooks of the current instance of excel while executing a UDF. On the other hand, opening a second instance of excel will do the job without interference.
To get data from Workbook without is open, you can use this, with ADO connection.
To use in Excel 2007 change this
Microsoft.Jet.OLEDB.4.0
to
Provider=Microsoft.ACE.OLEDB.12.0
and
Extended Properties=\"Excel 8.0;HDR=Yes;\
to
Extended Properties=\"Excel 12.0;HDR=Yes;\
[]'s
The workaround of putting my routine into a separate macro in the workbook module, and calling that macro from the Workbook_BeforeSave code, seems to have done the trick.
I've had a similar issue, but in my case it's a "Workbooks.Open(filename)" command at the start of a small routine embedded in Workbook_BeforeSave. VBA just skips right over the line of code as if it weren't there, it doesn't even report an Err.Code or Err.Description.
The only clue for me was that it's part of the Workbook_BeforeSave routine, and the limits with Functions above seem to indicate that could be a possible cause. So I dug around further to find more details.
It seems that Workbook_BeforeSave disables Excel from opening more files, and I guess there's a good reason for doing that, since the File > Open option is still visible in the File menu, but it can't be clicked. Strangely, the Open toolbar icon/button still works, and so whilst I can manually open the file from there, I wonder if it's because it's impossible to call this action from VBA code and that's why they allowed it?
You don't have to "Set" a cell, It's part of the workbook class (as far as I know). Just use the following...
foo = wbk.Worksheets("Sheet1").Range("A1").Value
I would suggest that you open you the new workbook upon opening the calling workbook, in the worbook_open event.
You then store the new workbook reference in a global variable.
Then the function called by your cell uses the said global variable instead of trying to open a new workbook. This way you go around the limitations.
PS : Of course global variable are to be avoided, some sort of container would be better than a direct global variable.
You can check the error in a proper way by using the following code:
filelocation = c:\whatever\file.xlsx
On Error GoTo Handler 'this is key as if the next row returns an error while opening the file it will jump to the Handler down there.
Set wkb2 = Workbooks.Open(filelocation, ReadOnly)
Handler:
MsgBox "File " & filelocation & " does not exist or cannot be reached, please review and try again"
I know that this does not answer the question (that's why I also landed in this thread, as I cannot open the file and can't understand why is that so)
Cheers,
RV

Excel 2007 workbook locked after access from Access 2007

I've got a project where I'm reading data from an Excel worksheet and saving it in Access tables (not a direct import--see this question if you're interested). My current problem is that any time I run my "import" and then try to open the workbook in Excel, it's "locked for editing" unless/until I close Access. I don't think this should be the case. My process is
Open the workbook with Automation.
Build a collection of sheet names.
Release the Automation objects.
If there's more than one sheet, get user input on which to process.
Open an ADO recordset on a specific range & read some data.
Release the recordset & connection.
Open an ADO recordset on a different specific range & read a bunch o' data.
Release the recordset & connection.
Close the controling form.
Steps 1 - 4 and 9 live in the form file, the remainder in a module.
Am I missing something? I think I've released all the references to the workbook....
If your step #1 includes something like this:
Dim objExcel As New Excel.Application
And later releasing the object is this:
Set objExcel = Nothing
Trying including this line just before you set the object variable to Nothing:
objExcel.Quit
It also helps to make the Excel application instance visible after starting it so you're less likely to leave Excel running unseen:
objExcel.Visible = True

Resources