I have a VBA script in several workbook templates that unlocks the current (active) worksheet. I use the same hotkey so that the users who are permitted to use the macro don't have to remember which hotkey allows them to unlock the workbook.
This generally causes no headaches as most users don't have more than one workbook open at a time (and in all likelihood don't use the hotkeys anyway). The issue is if I have more than one workbook open and try to run the VBA script with the hotkey, I'm currently getting a random instance of the VBA script. This causes problems because the password does vary between the workbooks, so if the hotkey kicks off the VBA script in WB X and I'm in WB Y, I get an error.
Getting to the point, is there a way I can make it so that the VBA script from the active workbook on that hotkey is the one that's used?
Per Alter's request here's a sanitized version of my lock_unlock VBA script
Sub Lock_Unlock()
Dim CurrentUser As String 'holds the current users Windows login
Dim Approved As String
Approved = "|user1|user2|user3|"
'Give CurrentUser it's value
CurrentUser = Environ$("username")
'Check if the user is approved
If InStr(1, Approved, CurrentUser) > 0 Then
'The user can use this macro. Check if the sheet is currently locked
If ActiveSheet.ProtectContents = True Then
'It is, unlock
ActiveSheet.Unprotect Password:=PW()
Else
'It isn't, relock
ActiveSheet.Protect DrawingObjects:=False, Contents:=True, Scenarios:= _
False, Password:=PW()
End If
'Not a user approved to use this macro, don't do anything
End If
End Sub
Function PW() As String
PW = "password"
End Function
This is how I would do it, modularize the password to a getFunction.
ex.
Function getPassword()
getPassword = "password1"
End Function
Now, when you want the password call Application.Run(ActiveWorkbook.Name & "!getPassword") This will make sure the password is retrieved from the active workbook, regardless of the workbook your macro is being run from
Ex.
Sub test()
MsgBox Application.Run(ActiveWorkbook.Name & "!getPassword")
End Sub
Function getPassword()
getPassword = "hello"
End Function
Option 2: check if ThisWorkbook is the ActiveWorkbook, if it isn't then call the macro from the activeworkbook using the same method I used to get the password.
Related
I use Excel 2016. The file I am using runs some code in workbook Open event handler.
Depending on what the code does the workbook may never get opened (visible).
in Workbook_Open the event handler establishes a connection with a data base and load some data eventually warn the user if an error occurs for instance.
Establishing the connection with a data base and load some data works most of the time. Some times it does not and the Excel splash screen remains on the screen for ever. After closing the splash screen clicking on the close cross, the Excel process continues running in the background.
If an error occurs I don't see the pop up form which is opened to warn the user as long as the workbook is not visible.
when I kill the process an reopen Excel (not the workbook), Excel suggest to retrieve the file which was opened earlier proving somehow that it has in deed been opened.
The second process just does not work unless the workbook is visible. If I run Excel and then open the workbook it s ok (in case an error occurs the warning pop up form is opened).
If Excel is closed and i open the workbook it does not work (splash screen frozen).
what is the proper way to start a VBA application where It is necessary to manage some cosmetics tasks (show some sheets, hide some other) and run a connection to a data base?
Here is a simplified version of the code (can't provide it all - too complex - too long)
In this code the function bConnectToTheDatabase is forced to return False which make the bLogin function useless (the code is not provided for this reason).
Private mLoginForm As frmLgn ' a form to login the application (see image)
Private mCustomMsgBox As frmMsgBox ' a form to display custom messages (see image)
Public Const gsPFU_VBA_PWD as String = "my secret password"
Public Const gsBLANK_WKS_NAME As String = "Blank"
Private Sub Workbook_Open()
'
Call HidShowSomeSheets()
' start the application up
Call LoginIntoTheApplication()
End Sub
' hide all sheets but the one named gsBLANK_WKS_NAME
' protect/unprotect to chnage visibility
Sub HidShowSomeSheets()
With Application.Workbooks(ThisWorkbook.Name())
.Unprotect (gsPFU_VBA_PWD)
.Sheets(gsBLANK_WKS_NAME).Visible = xlSheetVisible
For Each wks In .Sheets
With wks
.Unprotect (gsPFU_VBA_PWD)
End With
Next wks
For Each wks In .Sheets
With wks
If (StrComp(gsBLANK_WKS_NAME, .Name) <> 0) Then
.Unprotect (gsPFU_VBA_PWD)
On Error Resume Next
.Visible = xlSheetVeryHidden
Else
.Protect (gsPFU_VBA_PWD)
.Activate
End If
End With
Next wks
.Protect (gsPFU_VBA_PWD)
End With
End Sub
Sub LoginIntoTheApplication()
if( bConnectToTheDatabase() ) then
call bLogin
else
'create a custom form (it has it own even handler - block the execution flow)
'set mCustomMsgBox= new frmMsgBox
'mCustomMsgBox.Show vbModeless 'this does not work
MsgBox "something went wrong" 'this works
end if
end Sub
Function bLogin() as Boolean
'login into the application
End Function
Function bConnectToTheDatabase() as Boolean
'do the connection
'get the data
'etc ....
bConnectToTheDatabase= False 'fore it to False for the purpose of the explanation
End Function
The login form
The custom message box
On its own workbook "A" starts with checking if there is a settings file saved locally, that stores the User's credentials for autologin.
If there is no such file, it will show a login form.
I would like to add now the functionality that if I open workbook"A" from workbook "B" it should try to fetch the logged in user of WorkBook"B" instead of starting with checking the local settings file first.
There is a variety of WB-s that could call "A", so i would not go for putting a code in A to check a cellvalue in B, instead I would like to have B modify something in A upon opening.
The problem is:
When i open "A" from "B", any modification is only implemented after every code executed from _Open macro, so it cannot recognize in time, that actually i would like to pass extra information to that process.
like this:
Sub Test 'In Wb"B"
Dim Wb as workbook
Set Wb = Workbooks.Open(path)
Wb.Sheets(1).Range("A1").Value = "NewValue"
End sub
'----
Private Sub workbook_open() ' In Wb"A"
MsgBox ThisWorkbook.Worksheets(1).Range("A1").Value
End Sub
MsgBox will show "OldValue", because the external change will take place after the _Open event.
I have also tried to pass a parameter like _Open(optional Modifier as variant), but as I suspected, Events cannot accept parameters like that, right?
So how to provide extra info to Wb"A" from Wb"B" upon opening, before anything else happens?
One possible, but not preferred method I can think of is via command line parameters, like discussed in here:
Passing a parameter to an Excel file when opening it
Is there any other solution to achieve the requied results?
you could use the last workbook opened before "A" as a "messenger"
for instance should "B" the last opened workbook, you would have the following Test() sub:
Sub Test() 'In Wb"B"
Dim Wb As Workbook
Sheets(1).Range("A1").Value = "NewValue" ' use a convenient sheet and cell in "B" workbook to store the value you want to "pass" to "to-be-opened-soon" workbook
Set Wb = Workbooks.Open(path)
End Sub
and in "A" ThisWorkbook code pane you would then place:
Private Sub workbook_open() ' In Wb"A"
ThisWorkbook.Worksheets(1).Range("A1").Value = Workbooks(Workbooks.Count - 1).Sheets(1).Range("A1").Value 'retrieve the value from the last opened workbook
MsgBox ThisWorkbook.Worksheets(1).Range("A1").Value
End Sub
I am new to Excel Add-ins and I am not sure how to write mi programm.
I would like to put in an add-in a code so that, when the workbook that uses the add-in is opened, it creates a sheet named "mainSheet".
I can use the event handler in the Workbook, but is it possible to put the code in the module of the add-in and still be able to run it?
I found this on the "Automate Excel" web site. Hope this helps
The following code works opening a workbook. It automatically adds a new sheet and labels it with the name. It also checks to see that the sheet doesn’t already exist – to allow for the possibility of it being opened more than once a day.
This code makes use of the Workbook Open Event and must be placed in the workbook module under the “Open work Book” event. The function Sheet_Exists must be placed in a module and this checks whether or not the sheet exists:
Private Sub Workbook_Open()
Dim New_Sheet_Name As String
New_Sheet_Name = "mainSheet"
If Sheet_Exists(New_Sheet_Name) = False Then
With Workbook
Worksheets.Add().Name = New_Sheet_Name
End With
End If
End Sub
==
Function Sheet_Exists(WorkSheet_Name As String) As Boolean
Dim Work_sheet As Worksheet
Sheet_Exists = False
For Each Work_sheet In ThisWorkbook.Worksheets
If Work_sheet.Name = WorkSheet_Name Then
Sheet_Exists = True
End If
Next
End Function
I'm working on a protected Excel workbook and am trying to eliminate or understand why the follow message occurs AFTER my .MsgBox popup:
The cell or chart you're trying to change is on a protected sheet. To
make changes, click Unprotect Sheet in the Review tab (you might need
a password).
I only have one input field in the workbook (date field), and I've set that cell style to "Input", as well as modified the cell format to "unprotected" so it stays editable even if the workbook is locked.
My VBA/Macro:
Sub WeeklyReport()
Dim Week As String
Set WeekValue = ThisWorkbook.Sheets("Report_Weekly").Range("PRM_weekvalue")
Week = WeekValue
Application.ScreenUpdating = False
Call unprotectmacro
With ActiveWorkbook.Connections("SQLDBConnection").OLEDBConnection
.CommandText = "EXEC dbo.usp_WeeklyReport '" & Week & "'"
ActiveWorkbook.Connections("SQLDBConnection").Refresh
Sheets("Report_Weekly").Select
Range("A13").Select
MsgBox "The workbook is now refreshed."
End With
ActiveSheet.Protect "passwordgoeshere", DrawingObjects:=True, Contents:=True, Scenarios:=True
ActiveWorkbook.Protect "passwordgoeshere", Structure:=True, Windows:=False
'Application.ScreenUpdating = True
End Sub
I would like this message not to appear to my end users, but I don't understand why it is occurring. My only thought is the table isn't done being refreshed after the protect sheet is turned back on. If that is the case, is there a way to wait for the background query to finish running before protecting the sheet again?
To resolve my issue, I went into the Data tab and unchecked "Enable background refresh". I believe this only resolves my issue because I am using an OLEDB connection type.
I am trying to come up with some vba code to open an input box automatically as soon as the workbook is opened and have the user enter a date and then have the date placed in the A1 cell. I have written the code below but the input box is not pulling up at all it just opens the workbook and moves on.. not sure what is happening. Any and all help is appreciated.
Thanks!
Option Explicit
Private Sub workbook_open()
Dim cellvalue As Variant
Dim ws As Worksheet
Set ws = Worksheets("Workbench Report")
ReShowInputBox: cellvalue = Application.InputBox("Please Enter Todays Date (dd/mm/yyyy)")
If cellvalue = False Then Exit Sub
If IsDate(cellvalue) And CDate(cellvalue) < Date Then
ws.Range("A1").Value = DateValue(cellvalue)
Else: MsgBox ("Invalid Date!")
GoTo ReShowInputBox
End If
End Sub
Your code triggers upon the Workbook opening for me. Try these steps.
Open up Excel and Save As, changing the extension to .XSLM
Open up the VBA Editor (ALT + F11)
In the left-hand window, locate your macro file (the one you just created and named - it's in brackets after "VBA Project"), drilldown to "This Workbook" and double-click it.
Paste your code into the right-hand window
Save the file and re-open.
See attached diagram.
By the way, "cellValue = false" should probably be cellValue = "" since InputBox is returning a string and not a boolean value.
For Workbook_Open events the script needs to reside in the private module (ThisWorkbook)
From Ozgrid:
the Workbook_Open event is a procedure of the Workbook Object and as
such, the Workbook_Open procedure MUST reside in the private module of
the Workbook Object (ThisWorkbook).