Close another workbook upon closing the workbook - vba

I have a code that opens another workbook (source.xlsx) when I open (triggers on Workbook_Open event) a template workbook (template.xlsm).
The code:
Private Sub Workbook_Open()
Application.Screenupdating= False
Set w = workbooks
w.open filename:="link", Updatelinks:=true , readonly:=true
activewindow.visible=false
thisworkbook.activate
application.screenupdating=True
end sub
However, I want the source workbook to just run on background upon opening and close it when I close the template file.
Private sub workbook_aftersave()
Workbook("source.xlsx").Close SaveChanges:=False
End Sub

You want to use the Workbooks collection (Workbooks("source.xlsx")), rather than a Workbook object (Workbook("source.xlsx"), which will throw an error). Also, rather than trying to close it on the Workbook_AfterSave event, you could try using the Workbook_BeforeClose event:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next 'In case the Workbook is already closed
Workbooks("source.xlsx").Close SaveChanges:=False
End Sub
{EDIT} And, because I can, here's a tidier version of your Workbook_Open code too:
Private Sub Workbook_Open()
Application.ScreenUpdating = False
Dim wsSource As Workbook
Set wsSource = Workbooks.Open(Filename:="SomeDirectory\source.xlsx", UpdateLinks:=True, ReadOnly:=True) 'Change the filename to where your "source.xlsx" is stored
DoEvents 'Wait for it to finish opening
wsSource.Windows(1).Visible = False
ThisWorkbook.Activate
Application.ScreenUpdating = True
End Sub

Try using
Application.Visible = False
Place this in your Workbook_Open code on the workbook you want to hide, and then use True to bring it back to close.

Related

Hiding worksheet completely in favour of userform

I have a userform and would like this to be the first thing that is shown to the user when opening the workbook, and the sheet behind this form to be hidden.
I understand the below is the code to do this:
Private Sub Workbook_Open()
Application.Visible = False
UserForm1.Show vbModeless
End Sub
This performs the operation successfully, but my worksheet flashes up for a second or two before it is hidden and the userform appears.
This is long enough for someone to take a screenshot or see valuable information behind the userform.
It also doesn't look very tidy!
Is there a way to alter anything within the VBA to accomplish this?
I have discovered that it is possible with batch scripts or something similar but I have no experience of this and would prefer not to add another dimension to an already complex form.
I'd opt for a Workbook_BeforeClose event that hides all of the sensitive sheets. That way your data remains hidden to people opening your file without macros enabled.
This goes in a new standard module
Option Explicit
Option Private Module
Public Sub SheetsHidden(ByRef hidden As Boolean)
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.name <> "Home" And hidden Then 'your *safe* sheet name
ws.Visible = xlSheetVeryHidden
Else
ws.Visible = xlSheetVisible
End If
Next ws
End Sub
And then you can call it from your ThisWorkbook module
Private Sub Workbook_BeforeClose(Cancel As Boolean)
SheetsHidden True
End Sub
Once you have authenticated the user you can unhide the sheets with the parameter as False.
I would also recommend exploring UserForms, particularly:
With New UserForm1
.Show vbModeless
'do more with your form
End With
By design, opening Excel file without Excel showing up is not possible without external script or tool.
Easier way to hide all sheets is to save the file as .xla(m) (or using ThisWorkbook.IsAddin = True)
Private Sub Workbook_Open()
ThisWorkbook.IsAddin = True ' True by default for .xla(m) Excel Add-In files
Application.Visible = Workbooks.Count
UserForm1.Show vbModeless
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not ThisWorkbook.IsAddin Then ThisWorkbook.IsAddin = True
If Not ThisWorkbook.Saved Then ThisWorkbook.Save
If Workbooks.Count Then Application.Visible = True Else Application.Quit
End Sub
and in the form close event:
Private Sub UserForm_Terminate()
If Workbooks.Count Then ThisWorkbook.Close True Else Application.Quit
End Sub

vba Macro to open other WB and execute Macro fails when other WB have userform show on opening

As topic implies I have a problem I cannot find any solution to.
I have a Workbook (1) with the purpose to open other WBs and run macros in them.
Everything works like a charm except when the other WB has Workbook_Open() event to open a Userform (typically it asks if the WB should be updated). Then I get error code 1004 and my code fails.
How could I supress the Workbook_Open event from triggering when I open another WB?
I have tried the setting Application.EnableEvents = False but it´s not related.
Thank you very much for any help on this topic!
Here is the code for opening the WB
Public Function wbTargetOpen(sTargetPath As String, SPassword As String) As Workbook
Dim sWBName As String
sWBName = Mid(sTargetPath, InStrRev(sTargetPath, "\") + 1, Len(sTargetPath) - InStrRev(sTargetPath, "\") + 1)
If WorkbookIsOpen(sWBName) Then
Set wbTargetOpen = Workbooks(sWBName)
If wbTargetOpen.ReadOnly = True Then
wbTargetOpen.Close
Set wbTargetOpen = Workbooks.Open(FileName:=sTargetPath, UpdateLinks:=0, ReadOnly:=False, WriteResPassword:=SPassword)
End If
Else
Set wbTargetOpen = Workbooks.Open(FileName:=sTargetPath, UpdateLinks:=0, ReadOnly:=False, WriteResPassword:=SPassword)
End If
If wbTargetOpen.ReadOnly Then sErrorCode = "ReadOnly"
End Function
All you have to do is add one word VbModeless to the other workbook which launches the userform.
Private Sub Workbook_Open()
UserForm1.Show vbModeless
End Sub
The vbModeless will launch the form but will also allow your macro to run.
Close the other userforms before you run the macros.
Sub CloseOtherUserForms()
Dim frm As UserForm
For Each frm In UserForms
If Not TypeName(frm) = "MacroForm" Then
Unload frm
End If
Next
End Sub

How to apply workbook_open to multiple sheets

I have a excel workbook that a number of users interact with daily and on multiple montiors with different resolutions, screen zooms etc.. I need all worksheets to adjust to the ranges on each sheet I want the user to see each time.
Below works for 1 worksheet, but how would I get it to apply to all worksheets (Sheet1,Sheet2,etc.)
Private Sub Workbook_Open()
With Sheets("Sheet1")
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
End With
End Sub
You can use the Worksheet_Activate event, and place code such as
Private Sub Worksheet_Activate()
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
End Sub
on each sheet, editing the range as required.
That code will execute every time the sheet is activated, which may or may not be what you would like, so you may need to use something a bit more complicated and use:
Private AlreadyRun As Boolean
Private Sub Worksheet_Activate()
If Not AlreadyRun Then
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
AlreadyRun = True
End If
End Sub
which will only do something the first time the sheet is activated (as the AlreadyRun variable will originally be False, but will be changed to True once it is run once), or
Private AlreadyRun As Boolean
Private Sub Worksheet_Activate()
Dim CurRng as Range
Set CurRng = Selection
Columns("A:P").Select
ActiveWindow.Zoom = True
CurRng.Select
If Not AlreadyRun Then
Range("A1").Select
AlreadyRun = True
End If
End Sub
which will resize the sheet every time it is activated, but only move the selected cell to A1 the first time.
To avoid the issue caused by the sheet which is current when the Workbook is saved not going through the Worksheet_Activate event when the workbook is reopened, you can include a Workbook_Open event that says
Private Sub Workbook_Open()
Application.Screenupdating = False
Dim ws As Worksheet
Set ws = Activesheet
'For the next two lines, just pick any two of your worksheets
'All it is trying to do is to ensure whichever sheet was active at open
'is deactivated before being activated again in the "ws.Activate" command
Worksheets("Sheet1").Activate
Worksheets("Sheet2").Activate
ws.Activate
Application.Screenupdating = True
End Sub
(Disabling Screenupdating while the event is run will avoid the users seeing any "flickering" of worksheets.)

Unshare workbook everyday

I want to unshare a excel workbook everyday at 11:00pm.
First I use windows task scheduler to open the file at 10:59:45pm, and then run the following code.
Would the following code work?
Sub Unshare()
Application.DisplayAlerts = False
If ThisWorkbook.MultiUserEditing Then
ThisWorkbook.ExclusiveAccess
Application.DisplayAlerts = True
ThisWorkbook.Close
Else
Application.DisplayAlerts = True
ThisWorkbook.Close
End Sub
Sub Workbook Open()
Application.OnTime TimeValue("23:00:00"), "Unshare"
End Sub
Also, all of the code is located in Thisworkbook.
Thanks!
Try using Workbook_Open event in the private module of the Workbook object.
Private Sub Workbook_Open( )
Application.OnTime TimeValue("23:00:00"), "Unshare"
End Sub

how can I have every excel workbook I open to have columns.autofit property?

I would like to write a macro or adjust Excel properties, so that whenever I open a new excel workbook all values are autofited to the columns.
I tried using the following code, which works if I save the code for a specific workbook, however if I save the code in the PERSONAL workbook, the code produces an error. "Method 'Columns' of object '_Global' failed"
Sub auto_open()
Columns().AutoFit
End Sub
The way I do this is to create a simple add-in that handles Application events I want to intercept. The reason that it doesn't work in the auto_open() is because you are trying to work with the Columns object before it gets instantiated. Much better to use the SheetActivate event. This also avoids the possibility of opening a Workbook with 20 pages and having to wait for all of them to AutoFit. You only see the active sheet, right?
The concept is to grab a reference WithEvents to the application and set up handlers to whatever events you care about. To do this, you'll have to put the code into a class. I called mine "AppHolder".
Class code:
Option Explicit
Private WithEvents app As Application
Private Sub Class_Initialize()
Set app = Application
End Sub
Private Sub app_SheetActivate(ByVal Sh As Object)
Sh.Columns().AutoFit
End Sub
Private Sub app_WorkbookActivate(ByVal Wb As Workbook)
Wb.ActiveSheet.Columns().AutoFit
End Sub
Private Sub app_WorkbookNewSheet(ByVal Wb As Workbook, ByVal Sh As Object)
Sh.Columns().AutoFit
End Sub
Then, create an instance of your class in and set it in auto_open (or Workbook_Open as the case may be) in the ThisWorkbook module:
Option Explicit
Private hook As AppHolder
Private Sub Workbook_Open()
Set hook = New AppHolder
End Sub
Save it as an Excel add-in file (.xlam) in the default location - should be in Users[You]\AppData\Roaming\Microsoft\AddIns. Close Excel and re-open it, then go to Developer...Add-Ins and enable it. All there is to it.
EDIT: Almost forgot - that doesn't cover all situations in which you'll be presented with a Worksheet. You need WorkbookActivate and WorkbookNewSheet too...
You could use something like this: (untested)
Sub auto_open()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.DisplayAlerts = False
Dim wb As Workbook
Dim ws As Worksheet
For Each wb In Workbooks
For Each ws In wb.Worksheets
ws.Columns.AutoFit
Next ws
Next wb
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Its important to identify the Objects you are working on (in this case workbooks and worksheets) because it helps you to know which method you could apply to them (see)
This might work :
Sub auto_open()
For i = 1 To Application.Workbooks.Count
For j = 1 To Application.Workbooks(i).Sheets.Count
For k = 1 To Application.Workbooks(i).Sheets(j).Cells(1, Columns.Count).End(xlToLeft).Column
Application.Workbooks(i).Sheets(j).Columns(k).EntireColumn.AutoFit
Next k
Next j
Application.Workbooks(i).Save
Next i
End Sub