I have two separated workbooks with macroces: Book1 with Macro1 and Book2 with Macro2.
Macro1 is simple code to:
hidely open Book2 (has an open password: 1111);
write "test" in A1 Active Sheet of Book2;
run Macro2 from Book2, which is simple MsgBox "Hello! I am an msgbox
from Book2";
close Book2 with saving.
Sub Macro1()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Dim myWb As Workbook
Set myWb = Workbooks.Open(ThisWorkbook.Path & "/" & "Book2.xlsb", True, False, , "1111")
myWb.Unprotect ("1111")
Cells(1, 1) = "test"
myWb.IsAddin = True
Application.Run "'Book2.xlsb'!Macro2"
myWb.Close savechanges:=True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Sub Macro2()
MsgBox "Hello! I am an msgbox from Book2"
End Sub
I emphasize that everything should be done secretly and the user should not see neither Book2 nor any flashes, etc.
But when code comes to the saving step a window pops up on the screen, which, by the way, can be ignored and the code will continue to run/execute but anyway it's a PROBLEM I want get rid of:
password pop-up window
What I noticed:
If I remove the opening password from book2, the saving will be successfull and without pop-up dialogs. But I need Book2 opening protected.
I tried to modify code, but results are not unsatisfactory due to
screen blinking, screenshots below:
OK
V1-NOK
V2-NOK
V1: myWb.IsAddin = True is deleted/commented
Application.Run "'Book2.xlsb'!Macro2"
myWb.Close savechanges:=True
V2: ON/OFF IsAddin = True before/after Macro2 executing
myWb.IsAddin = True
Application.Run "'Book2.xlsb'!Macro2"
myWb.IsAddin = False
myWb.Close savechanges:=True
Please, try the next way. It will open the workbook in a new session, will write in its first sheet and run the macro. But a macro sending a message from a non visible session/window is not the best idea. In order to see the message, please move the cursor over the Excel workbooks icons on taskbar, select the MsgBox window and press OK. A better idea would be do avoid sending messages. The code should run as you need:
Sub HiddenWBOpenRunMacro()
Dim newEx As Excel.Application, myWb As Workbook
Set newEx = CreateObject("Excel.Application")
'Open the workbook in the newly created session:
Set myWb = newEx.Workbooks.Open(ThisWorkbook.Path & "/" & "Book2.xlsb", , , , "1111")
myWb.Sheets(1).cells(1, 1).Value = "Test" 'write in its first sheet
myWb.Application.Run "'Book2.xlsb'!Macro2" 'run the macro
myWb.Close True 'close the workbook, saving it
newEx.Quit 'quit the session
End Sub
If ThisWorkbook not in Excel Trusted Locations it must be added.
Related
I want to close the active macro workbook inside the Userform_Terminate event. The problem I am facing is that, a ghost window of excel application lingers on even after workbook has been closed.
Have tried most of the suggested ways, I could get my hands on (described in detail in the code snippet) but to no avail. If anybody can help, much grateful.
NOTE: Have released almost all excel related objects from memory by setting it to nothing.
Code :
Private Sub UserForm_Terminate()
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
'
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Saved = True
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
' Application.DisplayAlerts = False 'The excel ghost window lingers on.
' ThisWorkbook.Close , False
' Application.Quit
' Application.DisplayAlerts = True
Application.DisplayAlerts = False 'Ghost window is closed but also kills all instances of excel currently open
Application.Quit
Application.DisplayAlerts = True
'NOTE:
'Have released all excel related objects from memory by setting it to nothing, post use.
End Sub
Snap:
Well, your "gost" problem has the next explanation:
An Excel session/instance means the same Application handler. If you open a workbook from the Excel existing interface, it is open in the same instance. Pressing Ctrl + F6 will jump to the next workbook open in the same instance...
If there are open workbooks not seen in the Ctrl + F6 sequence, this only means that they are open in a different instance.
Another instance is open, for instance :), in this way:
Din ExApp as Object
Set ExApp = CreateObject("Excel.Application")
ExApp.Workbooks.add 'without this line, the instance is quit by itself...
Set ExApp = Nothing 'this only releases the memory
You can see more open Excel instances (if they exist) looking in TaskManager and seeing more the one such application (Excel.exe)...
When you close a workbook, and this specific workbook is the single one of the instance, the application Window, what you name a "gost" remains!. If there are some other workbooks open, the so named "gost" window disappears, too.
In order to handle both situations, please try the next approach:
Private Sub UserForm_Terminate()
If Workbooks.Count > OpenWb Then
ThisWorkbook.Close , False
Else
Application.Quit
End If
End Sub
Function OpenWb() As Long
Dim count As Long, wb As Workbook, arr
For Each wb In Workbooks
arr = Split(wb.Name, ".")
If UCase(arr(UBound(arr))) = "XLSB" Then count = count + 1
Next
OpenWb = count + 1
End Function
Quitting the application is done here only because you asked for it... When you try programmatically to open and close many workbooks, it is more efficient to keep the application open. To open a new instance takes time. To open a workbook in an existing instance takes less time... But to do that, your code must find that existing instance:
Sub testExcelInstance()
Dim Ex As Object
On Error Resume Next
Set Ex = GetObject(, "Excel.Application")
If Ex Is Nothing Then
Err.Clear: On Error GoTo 0
Set Ex = CreateObject("Excel.Application")
End If
On Error GoTo 0
Ex.Workbooks.Add 'just doing something after having the Excel instance object
End Sub
Releasing the objects from the memory does not do anything, in terms of the object itself existence. If physically disappears only if you quit it.
I have an unexpected display when closing a new workbook !
I launch my macro from the command line.
Application is made invisible from workbook_open :
Sub workbook_open()
Application.Visible = False
UserForm1.Show
Application.Visible = True
End Sub
UserForm1 contains a single button.
-> Only the userform is displayed.
Pressing the button starts the following code :
Sub UnexpectedDisplay()
Dim NewBook As Workbook
Debug.Print "_______________"
Application.Visible = False
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set NewBook = Workbooks.Add
With NewBook
.Title = "MyTitle"
.Subject = "Display"
.SaveAs Filename:="MyWorkbook"
End With
Debug.Print ActiveWorkbook.Name
MsgBox "New workbook added"
NewBook.Close SaveChanges:=True
Debug.Print ActiveWorkbook.Name
MsgBox "Workbook closed"
Application.DisplayAlerts = True
End Sub
The first msgbox is displayed : "New workbook added"
-> Only the msgbox is displayed.
Press "Ok"
The second msgbox is displayed : "Workbook closed"
Debug Trace :
_______________
MyWorkbook.xlsx
MyMacroFile.xlsm
-> A workbook becomes visible
( when MyMacroFile.xlsm is opened?).
-> Question : How to avoid this.
Please try this code.
Sub TestInVis()
Dim Wb As Workbook
Dim Fn As String
Fn = FileOpenName("Test")
Application.ScreenUpdating = False
Set Wb = Workbooks.Open(Fn)
Wb.Windows(1).Visible = False
Application.ScreenUpdating = True
End Sub
Before doing so, please set the variable Fn to contain a valid filename, complete with its path. (I used a function called FileOpenName which calls a FilePicker dialog.) The code will open the specified workbook and hide its window, leaving the previously displayed window on top.
In my test, the Open action didn't re-instate Screen Updating but I'm not sure that disabling it makes a difference. There is a short flicker while the workbook is being opened and I thought it was less pronounced while ScreenUpdating = False. It will be prolonged, however, if the file is large. One way or the other, the file opens invisibly and you can access it by the object variable to which it was assigned.
Next, I tested the same procedure with Workbooks.Add. All I said about about Open applies equally, except that the new workbook is very small, of course. Therefore it's even harder to tell whether ScreenUpdating really makes a difference.
I've encountered a strange thing: I've joined three workbooks: Personal Data Tracker, Global Tracker and the workbook with pivots and charts. The logic is as it follows: the user clicks on a button after the work is finished so the data is copied to the GL Tracker. Once the change event is triggered in the GL Tracker Table, the last workbook opens, the pivot is refreshed upon the open vent and the wb is closed.
Everything seems to be working fine, however when I run the macro live, at the very end I get an error message about
"Application-defined or object-defined error".
Only OK and Help button displayed, it doesn't make the VBE Open so I could debug it.
Would anyone know what it may be happening even if the whole chain works fine?
Thank you.
Code from the Personal Tracker:
Sub test()
Dim path As String
Dim wb As Workbook
path = ThisWorkbook.path & "\Dest.xlsm"
Application.ScreenUpdating = False
ThisWorkbook.Sheets("Total").Range("R1").Value = Date
Range("R1").Font.Color = VBA.ColorConstants.vbWhite
Worksheets("TOTAL").Range("B2:B13").Copy
On Error GoTo Handler
Workbooks.Open (path)
On Error GoTo 0
Set wb = Workbooks("Dest")
Worksheets("Sheet1").Range("B2").PasteSpecial Paste:=xlPasteValues
Exit Sub
Handler:
MsgBox "Someone else is saving their data at the moment." & vbNewLine & _
"Please try in a few seconds"
End Sub
Code from the GL Tracker:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim MRange As Range
Dim wbPivot As Workbook
Dim pt As PivotTable
Dim ws As Worksheet
Dim Name As String
Dim answer As VbMsgBoxResult
Set MRange = ThisWorkbook.Sheets(1).Range("Table1")
Name = Application.UserName
Application.ScreenUpdating = False
If Not Intersect(Target, MRange) Is Nothing Then
Application.EnableEvents = True
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Pivot.xlsm")
End If
'refresh
For Each ws In wbPivot.Worksheets
For Each pt In ws.PivotTables
pt.PivotCache.Refresh
pt.Update
pt.RefreshTable
Next
Next
'saving
Application.ScreenUpdating = True
If Application.UserName <> "Jakub Tracz" Then
MsgBox "User not authorised. Workbook will be closed."
wbPivot.Close True
ThisWorkbook.Close True
Else
answer = MsgBox(Prompt:="Do you want to save and close the workbook?", _
Buttons:=vbYesNo + vbQuestion)
Select Case answer
Case vbYes
wbPivot.Close True
ThisWorkbook.Close True
Case vbNo
MsgBox "Welcome, " & Application.UserName
End Select
End If
End Sub
I'm going to give you a proof of concept code as an example for you to use. This will not exactly answer your question with code you can just copy/paste, but you will be able to use this to put it together the way you want it to work instead of me making assumptions about many things and restructuring it myself.
This simply demonstrates how to use a workbook object variable in one routine that can reference another workbook, and how to make changes to that 2nd workbook and save/close it.
Sub Tracker_Update()
Dim wbPivot as Workbook
' open the workbook
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Test.xlsx")
' optionally make it hidden
wbPivot.Visible = False
With wbPivot
' pretend this code updates the pivot table
.Worksheets(1).Range("A1") = "hello world"
' Close and save it
.Close True
End With
' optionally clear the variable
' this is not really needed in VBA, but if you eventually
' start using VB.NET with Excel as a COM object,
' you will want to know how to do this part when you are done
Set wbPivot = Nothing
End Sub
I think you will like this approach in the end much better in the end anyway, as the code isn't scattered around so much in different places. Easier to debug later, and easier for someone else to understand what you are doing if and when you leave the company.
I have an Excel macro that creates another workbook for the user to modify. When I try to enter data in a cell in the new workbook, however, I get the error "The cell or chart you're trying to change is on a protected sheet." The sheet in the macro workbook is, in fact, protected, but that sheet is not visible at the time I get the error. When I try to close the visible, newly created workbook, it’s the macro workbook that closes. The last thing my macro does is activate the sheet in the new workbook. What do I have to do to make that work? Having the macro close its own workbook solves the problem, of course, but that’s not what I want to do, since the user needs another macro in the same workbook to process the changes on the new sheet.
The program has over 6000 lines of code (so far), but here is one of the routines that causes the problem.
Private Sub z3_BudgetPrepUpd()
'Build a new workbook initialized to let the user modify data
'for an existing fiscal-quarter budget.
'When this routine executes,
' UserForm1 is still active.
Dim strTracer As String 'error-handling tracer for this subroutine
Dim strFyrQtr As String
On Error GoTo abend
If blnAbort Then Exit Sub
If blnAbortGlobal Then Exit Sub
'Find out which ListBox item the user selected:
If UserForm1.ListBox1.ListCount < 1 Then GoTo aa9000 'ListBox is empty
If UserForm1.ListBox1.ListIndex < 0 Then 'No item selected
strMsgTitle = udtPrm.msgTtl
strMsgPrompt = "Please select a fiscal quarter to update."
Call z0_MsgBox
GoTo aa9000
End If
strFyrQtr = UserForm1.ListBox1.Value 'Selected item in ListBox
'Close UserForm1:
UserForm1.Hide
ThisWorkbook.Sheets(c_WKS_WELCOME).Activate
'Build the udtBgt() array with data for the specified quarter:
lngBgtHiNdx = -1
Call zz_GetBudgetForQtr(strFyrQtr)
If blnAbort Then GoTo aa9000
'Build a new workbook for the user to update budget amounts:
Workbooks.Add
Set wkbNewBook = ActiveWorkbook
'Save the names of the default worksheets
'so we can delete them later:
strDfltSheets() = z0_SheetNames(wkbNewBook)
'Build a worksheet with data from the udtBgt() array:
Call z3_BuildBudgetUpdSheet
If blnAbort Then GoTo aa9000
'Delete the default worksheets:
Call z0_DeleteSheets(wkbNewBook, strDfltSheets())
If blnAbort Then GoTo aa9000
wkbNewBook.Sheets(c_WKS_IPT_BUDGET).Activate
'Excel 2016 Bug:
'We need to close ThisWorkbook to allow the user
'to work with the book we just created:
Application.DisplayAlerts = False
ThisWorkbook.Close
aa9000:
Exit Sub
abend:
lngErr = Err.Number
strErr = Err.Description
blnAbort = True
Application.Cursor = xlDefault 'no more hourglass
strMsgTitle = "Program Error"
strMsgPrompt = "The following error occurred:" & Chr(10) & Chr(10) & _
"Error No. " & CStr(lngErr) & Chr(10) & _
"Error Description: " & strErr & Chr(10) & _
"Subroutine: z3_BudgetPrepUpd" & Chr(10) & _
"Tracer: " & strTracer
Call z0_MsgBox
Resume aa9000
End Sub
You use ThisWorkbook which I agree with. You use ActiveWorkbook which I hardly ever use.
I'd recommend using a variable to store reference to workbooks other than that which houses your code. So use
Dim wb As Excel.Workbook
Set wb = Application.Workbooks.Open("c:\test.xlsm") 'for opening
'* or
Set wb = Application.Workbooks.Add 'for creating a new one
'* or
Set wb = Application.Workbooks.Item("AlreadyOpen.xlsm") 'for referencing one already open
'* from hereon use wb instead of ActiveWorkbook
wb.Worksheets.Item(1).Visible = True
Thanks, everyone, for your interest and suggestions. I have solved the problem by redesigning the application without UserForms or external workbooks. Office 2016 has many issues, and perhaps this is one of them. In any case, I have no more time to research it.
I want to open a workbook (WB1) and then as it's opened, another workbook (WB2) is opened. I want WB2 hidden.
Private Sub Workbook_Open()
Application.ScreenUpdating = False
Workbooks.Open Filename:="C:\WB2.xlsm"
ActiveWindow.Visible = False
End Sub
This is what I have so far and what it does is hide BOTH workbooks. I want WB1 to remain on top and visible.
Thank you! Josh
Private Sub Workbook_Open()
Dim wb as workbook
Application.ScreenUpdating = False
set wb=Workbooks.Open(Filename:="C:\WB2.xlsm")
wb.Windows(1).Visible = False
End Sub
an important part would seem to be how to turn view back on again.
other post is the answer.. i just had to see it work before i commited it.
hope this is enough to explain it, may have been done in less space. thanks.
i would have to agree to post a couple words describing the key working line. i am just novice at vb & have to say that 99% of posts require some research to get a needed variable in there. i believe so enough to add some expletives as hours by many can be spent, trying to find the dang answer, but will refrain : ).
the consequence is: everyone on the planet has to spend 2 to infinite hours.
(thanks for having code, to put code in a box, needs some tweaking for lines to include / space lines interfere?).
what i found: changing out may not work: .Visible and .Hidden
- have no idea what the 1 in windows(1) is for.
sub TEST1() 'in a module
'if want to happen when you open a wb, place in: "ThisWorkbook" module as:
'Private Sub Workbook_Open()
Dim wb As Workbook
'Set wb = Workbooks("WB2.xlsm") 'YES
'Set wb = Workbooks(Filename:="C:\WB2.xlsm") 'untried should work for path eg
'Set wb = Workbooks.Open(Filename:="C:\WB2.xlsm") 'original, with a command added: open
Application.ScreenUpdating = False
If 0 = 0 Then 'set to: if 0 = 1 to skip test
If wb.WINDOWS(1).Visible = False Then 'TOGGLES: press F5 or run macro button
wb.WINDOWS(1).Visible = True
MsgBox "Workbook is NOT Hidden" & Space(10), vbQuestion 'a good test method
Else
wb.WINDOWS(1).Visible = False '<< line to use, to hide wb on open
MsgBox "Workbook is Hidden" & Space(10), vbQuestion 'a good test method
End If
Else
wb.WINDOWS(1).Visible = False '<< line to use, to hide wb on open
end if
End Sub
This seems to be an old post but I thought I'd add in my version of the answer,as I was working on something similar.
Set m_WB = Workbooks("WB2FilePath\WB2.xlsm")
Windows(m_WB.Name).Visible = False
'Do work
'Set WorkBook to visible
Windows(m_WB.Name).Visible = True
Keep in mind, it would be good practice to set WB2 to visible once completed. This would avoid any memory being eaten up in the background without you knowing!
Cheers.