Excel VBA protect returning error - vba

I've seen many posts on here and elsewhere about using the following code in the ThisWorkbook Object in order to protect your workbook but still allow macros to run:
Private Sub Workbook_Open()
ActiveWorkbook.Protect UserInterfaceOnly:=True
End Sub
However, the protect function tooltip that pops up only offers three arguments Protect([password], [structure], [windows]). Therefore, when I open the document I get the following error
"Compile Error: Named argument not found"
in regard to UserInterfaceOnly:=True.
Am I using the wrong protect function, or is there something else I'm missing? I want to allow users to input data into the workbook using forms/macros, but I don't want them to be able to manually change any cells.
It almost seems as if the protect function that I'm running has different arguments than many of the other protect solutions I've found. Could this be a version issue or something else?

The suggestion provided by Tim Williams worked. Protect doesn't work the same way at the workbook level, therefore I needed to write individual code for each sheet I wanted to protect. I used the following code to protect the sheets but allow forms to populate:
Private Sub Workbook_Open()
Worksheets("Sheet1").Protect UserInterfaceOnly:=True
Worksheets("Sheet2").Protect UserInterfaceOnly:=True
Worksheets("Sheet3").Protect UserInterfaceOnly:=True
End Sub

Related

Maro to always copy and paste as formulas by default in Excel

I need help to check this macro that intends to copy and paste without formatting. It doesn't work fine.
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
On Error Resume Next
Target.PasteSpecial xlPasteFormulas
Application.CutCopyMode = True
End Sub
How do I make Ctrl-V to paste without any format? I want to keep the excel clean and tidy, so users can copy and paste values and formulas without formatting.
Thanks!
If you want to make your own, custom Ctrl-V, well, you can achieve it this way:
' Code Module ThisWorkbook
Private Sub Workbook_Open()
Application.OnKey "^v", "ThisWorkbook.PasteWithoutFormat"
End Sub
Private Sub PasteWithoutFormat()
If Application.CutCopyMode Then Application.Selection.PasteSpecial xlPasteFormulas
End Sub
Try this: Assigning Macros to Short-Cut Keys in Excel
You'll need to work out how users have access to the macro - there are a few ways to do this and I'm not so sure what will work in your environment, nor your access level to make these options work.
I suppose I'd build a very simple ADD-IN in which I'd embed the macro and there also, assign the macro shortcut to override CTRL + V. Then deploy the ADD-IN according to your company policies.
However, we need more details from you to fully implement the solution.
I went for the easiest way. I set up Ctr-v (in macro's options) to run the following code:
Sub Pstfrmul()
Selection.PasteSpecial xlPasteFormulas
End Sub
Many many thanks for all your answers and comments. Best,
GerĂ³nimo

Declare global variable for sheet password

I have a larger Excel file with multiple sheets and modules.
In the code for each of these I need to protect or unprotect a password protected sheet temporarily in order to update certain protected parts.
So far I use one of the following lines which works but this means that the password appears multiple times throughout the code.
Is there a way I can declare this password just once like a global variable and then just refer to this variable whenever needed so that it only has to be changed once if there is need for a change ?
Also, would this reduce security on the file ?
Current code:
To protect a sheet:
ActiveSheet.Protect Password:="MyPassword", UserInterfaceOnly:=True
To unprotect a sheet:
ActiveSheet.Unprotect Password:="MyPassword"
In your VB editor, right click on the project, and then Insert > Module
Call it something useful like 'Constants'
Insert the following statement:
Public Const strPwd as String = "MyPassword"
It is optional to type the constant, so the 'as String' part is down to taste. You can use this constant in any place in your project where you would previously have used your literal password string.
Regarding security, the best thing to do would be to make sure you have protected the VB project itself with a strong password. You can explore the options here in VB IDE > Tools > VBAProject Properties > Protection tab.
You can use this code as an example
Option Explicit
Public Const g_strPASSWARD As String = "MyPassword"
' To Protect
Sub ProtectSheet(ByRef shToProtect As Worksheet)
shToProtect.Protect Password:=g_strPASSWARD, UserInterfaceonly:=True
End Sub
'To Protect
Sub UnprotectSheet(ByRef shToUnprotect As Worksheet)
shToUnprotect.Unprotect Password:=g_strPASSWARD
End Sub
' To Use
Sub MyTest()
ProtectSheet ActiveSheet
UnprotectSheet ActiveSheet
End Sub
I hope this helps.

Hide specific sheets when closing workbook

I'm creating some VBA code which should do the following:
Users press a button a are required to input a code.
When the input the correct code the team relevant code they get access to certain sheets.
The sheets they get access to differs according to the team number and code they enter. So when they enter he password "banana": the sheets "Team_1" & Team_1_sub become visible.
I now created the following code to achieve this:
Sub filter_tabs()
Dim answer As String
answer = InputBox("Please enter your password")
If answer = "Password" Then
MsgBox "Correct, je krijgt nu de goede tabs te zien!"
Worksheets("Team_1").Visible = True
Worksheets("Team_1_sub").Visible = True
Else
MsgBox "Wrong password"
End If
End Sub
Two questions about the code above:
When the users close the document all sheet should "disappear" again. Does anybody know how to do this? So when opening the document sheets "Team_1" and "Team_1_sub" should be be standard
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
Could you guys give me some feedback on whether the procedure I follow above (different if statements where users are prompted for a password and then get to see certain tabs) is the most efficient one to reach my goal? End goal is to make sure certain team leader can only see certain sheets.
Here for setting visible false, you can use Workbook_BeforeClose method as follow:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
'must save, if not save, it is not effect.
Me.Save
End Sub
Reference for that method is here.
One thing is that this method must have in the ThisWorkBook module.
For next question, you should say more like, which sheets for which user and password. Because you code is enough for your question. It can use for your requirement.
As you aren't using passwords you should at least make the sheets VeryHidden rather than Hidden - much harder for the average user to unhide.
The Me.Save proposed by the other answer also isn't necessary.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Worksheets("Team_1").Visible = VeryHidden
Worksheets("Team_1_sub").Visible = VeryHidden
End Sub
ad 1)
you best use a Workbook_BeforeSave() routine to code the hiding of all sheets ... in the VBAProject view you find this under ThisWorkbook
ad 2)
The code you post looks very nice - my point of concern would be the hard coding of user names vs. sheet names. I would consider putting this in a sheet/table using headers /code/ /sheetname/ ... this way you can adapt your logic at any time without having to modify the code.
With such a table at hand (in an all time hidden sheet if need be) you traverse it (one single piece of code) and - upon code entering - you unhide If CodeInTable = CodeEntered ... in the other case you unconditionally hide that sheet ... because hiding/unhiding differs only by 2 simple conditions.

Running Macros from Toolbar/Running one macro from another

I am trying to develop a macro for a publisher document. This macro will, when run, show a pop-up allowing the user to select one of three types of clients, and add different bullet points to a text box depending on which option was selected. I'm having two different problems which I suspect are coming from the same source. Problem number one is that I can't get the button on my User Form to run a different macro when the button is clicked. Problem two is that I've added my macros to one of the toolbars, and nothing happens when I click on them. In both cases, it's simply not running the macro. What am I doing wrong?
UserForm1
Private Sub CommandButton1_Click()
Application.Run ("ShapeTest")
End Sub
Private Sub UserForm_Initialize()
With ListBox1
.AddItem ("Federal")
.AddItem ("State")
.AddItem ("Local")
End With
End Sub
ThisDocument
Private Sub GenerateStatement()
UserForm1.Show
End Sub
Private Sub ShapeTest()
MsgBox ("Hello!")
Application.ActiveDocument.Pages(1).Shapes(1).TextFrame.TextRange.InsertAfter`enter code here`(Chr(13) & "My Text")
End Sub
Why are you using Application.Run("ShapeTest") rather than simply ShapeTest?
I don't have enough information to be 100% sure, but the following should work: To make ShapeTest callable from the userform you do two things:
1) Move it from ThisDocument to a general code module (first Insert/Module in the editor).
2) Eliminate the word Private in front of Sub ShapeTest()-- you don't want this to be a private sub since you want code outside of the module to be able to use it.
On edit: Alternatively -- you could keep ShapeTest() where it is in ThisDocument, get rid of the Private qualifier and in the userform code refer to ShapeTest as ThisDocument.ShapeTest. I prefer using the first method since I tend to like to keep as much code as possible in general code modules (reserving things like ThisDocument for event handlers) but OTOH my VBA experience is mostly Excel with a smattering of Word and there might be reasons to keep the code in ThisDocument in Publisher. I don't know Publisher, but a problem that I have run into in Word at times is I have sometimes accidentally put code in the Normal template that I wanted to go in the document's project. If something similar is possible in Publisher you should double check where your code is living.

vba private scripts

I know that even private vba scripts can be called by the user, such that making it "private" in fact only hides its name.
However, is there a way to set up a macro so it is only runnable if you are inside that particular VBA project? Not from Excel and not from any VBScript or the likes.
If you want to lock down the code you could
make the code private so the macro names areen't exposed
lock the protect, and then test that the project is actually unlocked before letting the code run
The sample code below checks that the VBA in the host workbook is not protected before running
Does this meet your needs?
Private Sub TestMe()
Dim objVB As Object
Set objVB = ThisWorkbook.VBProject
If objVB.Protection = 0 Then
Call TestSub
Else
MsgBox "Sorry sport - unauthorised", vbCritical
End If
End Sub
Private Sub TestSub()
MsgBox "Project unprotected - i've been run", vbOK
End Sub
Honestly, there is no foolproof way around it. You can have certain checks but that's all you can do.
If you are sure that a user will not have access to VBA Code then what brettdj suggested is the best way to go ahead. Protect your project. One cannot run a macro from Excel or from outside Excel if one doesn't know the macro name ;)
The basic intention of making a macro Private is not to prevent it from running but making it invisible to the user. Mostly, the only macros that needs to be private in Excel are the inbuilt Worksheet or Workbook events or macros referred by other macros which necessarily don't need to be accessed by the user. A user can still access them from outside VBA if he or she wants to.
Having said that, you can restrict (But not STOP - Not referring to disabling your macro security) the macros from running. Pass an authorization FLAG. Only when it receives an "Authorization", will it run.
For Example
Option Explicit
Private Sub Sample(Auth As Boolean)
If Auth = True Then
'~~> Your macro code goes here
End If
End Sub
Now if you want this macro to be called from VBA then you have to call it like this
Sample True
or
Call Sample(True)
This will ensure that the above macro will only run when you allow it to.
Would this method prevent user from running this from VBS?
NO. It won't. However, it won't run till the time the user specifies or gives the "Authorization"
HTH