I was attempting to loop through every worksheet in every workbook in a folder and make sure only the cells containing formulas were locked. I have already been using code to lock all cells in every worksheet, and code to lock every formula in a worksheet, successfully for a few months, so I basically mashed the two pieces of code together to get this:
Sub LockAllFormulas()
Dim myOldPassword As String
Dim myNewPassword As String
Dim ws As Worksheet
Dim FileName As String
Dim rng As Range
myOldPassword = InputBox(Prompt:="Please enter the previously used password.", Title:="Old password input")
myNewPassword = InputBox(Prompt:="Please enter the new password, if any.", Title:="New password input")
FileName = Dir(CurDir() & "\" & "*.xls")
Do While FileName <> ""
Application.DisplayAlerts = False
If FileName <> "ProtectionMacro.xlsm" Then
MsgBox FileName
Workbooks.Open (CurDir & "\" & FileName)
For Each ws In ActiveWorkbook.Worksheets
If Not Cells.SpecialCells(xlCellTypeFormulas) Is Nothing Then
ActiveWorkbook.ActiveSheet.Unprotect Password:=myOldPassword
ActiveWorkbook.ActiveSheet.Cells.Locked = False
For Each rng In ws.Cells.SpecialCells(xlCellTypeFormulas)
rng.Locked = True
Next rng
ActiveWorkbook.ActiveSheet.Protect Password:=myPassword
End If
Next ws
ActiveWorkbook.Save
ActiveWorkbook.Close
End If
FileName = Dir()
Loop
Application.DisplayAlerts = True
End Sub
Every time I run it it shows a 400 error. The error matches one I got whenever the code runs into a sheet that doesn't have any code in it, but I thought I fixed that problem when I added:
If Not Cells.SpecialCells(xlCellTypeFormulas) Is Nothing Then
Any ideas what else could be going wrong?
When working with SpecialCells, you have to be very careful. What I do is I store them in a range sandwiched between OERN and then check of they are not nothing. Here is an example
Dim rng As Range
On Error Resume Next
Set rng = ws.Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not rng Is Nothing Then
'
'~~> Rest of the code
'
End If
Applying that to your code will be like this (UNTESTED)
Dim LockedRange As Range
For Each ws In ActiveWorkbook.Worksheets
With ws
On Error Resume Next
Set LockedRange = .Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not LockedRange Is Nothing Then
.Unprotect Password:=myOldPassword
.Cells.Locked = False
LockedRange.Locked = True
.Protect Password:=myPassword
End If
Set LockedRange = Nothing
End With
Next ws
Related
I'm adding a new worksheet to my workbook with
Application.ScreenUpdating = False
SheetExists = False
For Each WS In Worksheets
If WS.Name = "BLANK" Then
SheetExists = True
End If
Next WS
If Not SheetExists Then
Sheets.Add
ActiveSheet.Name = "BLANK"
End If
Is there any way to sheets.add silently without bringing focus to or activating the new added sheet? I just want to stay on the sheet (ie. Sheet1) that is currently active and add the new sheet in the background.
Thanks
At first, things look simple but there are a few things to consider:
There could be more sheets selected before running the code
The selected sheet(s) could be Chart sheet(s)
The Workbook can be protected
You might not want to set Application.ScreenUpdating = True at the end of the method because you might be running this from within another method that still needs it off
Restoring selection can only happen if the proper window is activated
You could use this method:
Sub AddWorksheet(ByVal targetBook As Workbook, ByVal sheetname As String)
Const methodName As String = "AddWorksheet"
'Do input checks
If targetBook Is Nothing Then
Err.Raise 91, methodName, "Target Book not set"
ElseIf sheetname = vbNullString Then
Err.Raise 5, methodName, "Sheet name cannot be blank"
ElseIf Len(sheetname) > 31 Then
Err.Raise 5, methodName, "Sheet name cannot exceed 31 characters"
Else
Dim arrForbiddenChars() As Variant
Dim forbiddenChar As Variant
arrForbiddenChars = Array(":", "\", "/", "?", "*", "[", "]")
For Each forbiddenChar In arrForbiddenChars
If InStr(1, sheetname, forbiddenChar) > 0 Then
Err.Raise 5, methodName, "Sheet name cannot contain characters: : \ / ? * [ or ]"
End If
Next forbiddenChar
End If
Dim alreadyExists As Boolean
'Check if a sheet already exists with the desired name
On Error Resume Next
alreadyExists = Not (targetBook.Sheets(sheetname) Is Nothing)
On Error GoTo 0
If alreadyExists Then
MsgBox "A sheet named <" & sheetname & "> already exists!", vbInformation, "Cancelled" 'Can remove
Exit Sub
End If
'Check if Workbook is protected
If targetBook.ProtectStructure Then
'Maybe write code to ask for password and then unprotect
'
'
'Or simply exit
MsgBox "Workbook is protected. Cannot add sheet", vbInformation, "Cancelled"
Exit Sub
End If
Dim bookActiveWindow As Window
Dim appActiveWindow As Window
Dim selectedSheets As Sheets
Dim screenUpdate As Boolean
Dim newWSheet As Worksheet
'Store state
Set bookActiveWindow = targetBook.Windows(1)
Set appActiveWindow = Application.ActiveWindow 'Can be different from the target book window
Set selectedSheets = bookActiveWindow.selectedSheets
screenUpdate = Application.ScreenUpdating
'Do main logic
screenUpdate = False
If bookActiveWindow.Hwnd <> Application.ActiveWindow.Hwnd Then
bookActiveWindow.Activate
End If
If selectedSheets.Count > 1 Then selectedSheets(1).Select Replace:=True
Set newWSheet = targetBook.Worksheets.Add
newWSheet.Name = sheetname
'Restore state
selectedSheets.Select Replace:=True
If appActiveWindow.Hwnd <> Application.ActiveWindow.Hwnd Then
appActiveWindow.Activate
End If
Application.ScreenUpdating = screenUpdate
End Sub
If you want the book containing the code then you can call with:
Sub Test()
AddWorksheet ThisWorkbook, "BLANK"
End Sub
or, if you want the currently active book (assuming you are running this from an add-in) then you can call with:
Sub Test()
AddWorksheet ActiveWorkbook, "BLANK"
End Sub
or any other book depending on your needs.
Just remember who was active:
Sub ytrewq()
Dim wsh As Worksheet, SheetsExist As Boolean
Set wsh = ActiveSheet
Application.ScreenUpdating = False
SheetExists = False
For Each ws In Worksheets
If ws.Name = "BLANK" Then
SheetExists = True
End If
Next ws
If Not SheetExists Then
Sheets.Add
ActiveSheet.Name = "BLANK"
End If
wsh.Activate
Application.ScreenUpdating = False
End Sub
I have a client who is hand holding a bunch of worksheets that should be standardized. They are created from importing CSV files. Basically, I need to replace the current manual sheets while they are being referenced from another tab without breaking the current references.
I've reduced the problem to a single workbook with 2 sheets. Sheet1 cell A1 references Sheet2 cell A1 which holds the string "Sheet2A1CellData"
Everything commented out below has been tried including Application.Volatile and Application.Calculation.
Option Explicit
Sub TestSheet2Delete()
Dim TmpSheet2 As Worksheet: Set TmpSheet2 = Sheets("Sheet2")
'Application.Volatile
If TmpSheet2 Is Nothing Then
Exit Sub
End If
'Application.Calculation = False
Application.DisplayAlerts = False
TmpSheet2.Delete
Application.DisplayAlerts = True
Set TmpSheet2 = Worksheets.Add(After:=Sheets("Sheet1"))
If TmpSheet2 Is Nothing Then
Exit Sub
End If
TmpSheet2.Name = "Sheet2"
TmpSheet2.Range("A1").Value = "Sheet2A1CellData"
'Application.Calculation = True
End Sub
Sheet1 A1 was originally =Sheet2!A1. When I run the function above from the VBE, Sheet1 cell A1 is set to =#REF!A1.
How can I keep the reference valid after the sheet has been replaced?
Obviously, the real world problem is much larger and re-importing CSV data requires updating 132,000 cells. 6000 rows x 22 Columns.
Thanks for any help.
Thank you presenting a real good question.
First of all disclaimer: This is not an direct solution but and workaround we had to adopt years back.
Exactly similar problem problem had been encountered in my workplace (literally made us to pull out our hairs), and we also tried to go for iNDIRECT. But since the formulas in the working sheets are complex we failed to replace them with INDIRECT. So instead of lengthy manual replacement of the hundreds of Formulas in the working sheet, we used to insert a temp Sheet and change the formulas reference to that sheet. After importing new sheet and renaming it as old sheet's name, formulas were reverted back to original.
I tried to reproduce the code used (since I don't have access to same files now). We only used the Sub ChangeFormulas, Here I used the same in line with your code.
Option Explicit
Sub TestSheet2Delete()
Dim Wb As Workbook
Dim Ws As Worksheet, Ws1 As Worksheet, Ws2 As Worksheet
Dim Xstr As String, Ystr As String
Set Wb = ThisWorkbook
Set Ws = Wb.Sheets("Sheet1")
Xstr = "Sheet2"
Ystr = "TempSheetX"
Set Ws1 = Wb.Sheets(Xstr)
Set Ws2 = Worksheets.Add(After:=Ws)
Ws2.Name = Ystr
DoEvents
ChangeFormulas Ws, Xstr, Ystr
Application.DisplayAlerts = False
Ws1.Delete
' Now again add another sheet with Old name and change formulas back to Original
Set Ws1 = Worksheets.Add(After:=Ws)
Ws1.Name = Xstr
DoEvents
ChangeFormulas Ws, Ystr, Xstr
Ws2.Delete
Application.DisplayAlerts = True
End Sub
Sub ChangeFormulas(Ws As Worksheet, Xstr As String, Ystr As String)
Dim Rng As Range, C As Range, FirstAddress As String
Set Rng = Ws.UsedRange
With Rng
Set C = .Find(What:=Xstr, LookIn:=xlFormulas)
If Not C Is Nothing Then
FirstAddress = C.Address
Do
C.Formula = Replace(C.Formula, Xstr, Ystr)
Set C = .FindNext(C)
If C Is Nothing Then Exit Do
If C.Address = FirstAddress Then Exit Do
Loop
End If
End With
End Sub
Another simplest workaround is not to delete the Sheet at all and import the CSV and copy the full sheet onto the sheet in question. However This fully depends on actual working conditions involving CSV and all.
AFTER I posted (of course :-)), this link came up on the right: Preserve references that recommends using INDIRECT. I have now changed Sheet1 A1 to =INDIRECT("Sheet2!"&"A1").
I am not certain why the named ranges suggested in the link are needed. The indirect call above seems to work without a named range.
If this works in the larger project, I will mark this as complete.
My original answer did not work for non-contiguous cells. However, I really like the Range to Variants and then back to Range pattern. Very fast. So I rewrote my original answer into more reusable code that tests using non-contiguous cells.
Function PreserveFormulaeInVariantArr(ByVal aWorksheet As Worksheet, _
ByVal aIsNoFormulaErr As Boolean, _
ByRef aErrStr As String) As Variant
Dim TmpRange As Range
Dim TmpAreaCnt As Long
Dim TmpVarArr As Variant
Dim TmpAreaVarArr As Variant
PreserveFormulaeInVariantArr = Empty
If aWorksheet Is Nothing Then
aErrStr = "PreserveFormulaeInVariantArr: Worksheet is Nothing."
Exit Function
End If
Err.Clear
On Error Resume Next
Set TmpRange = aWorksheet.Cells.SpecialCells(xlCellTypeFormulas)
If Err.Number <> 0 Then 'No Formulae.
PreserveFormulaeInVariantArr = Empty
If aIsNoFormulaErr Then
aErrStr = "PreserveFormulaeInVariantArr: No cells with formulae."
End If
Exit Function
End If
TmpAreaVarArr = Empty
On Error GoTo ErrLabel
ReDim TmpVarArr(1 To TmpRange.Areas.Count, 1 To 2)
For TmpAreaCnt = LBound(TmpVarArr) To UBound(TmpVarArr)
TmpVarArr(TmpAreaCnt, 1) = TmpRange.Areas(TmpAreaCnt).Address 'Set 1st Element to Range
TmpAreaVarArr = TmpRange.Areas(TmpAreaCnt).Formula 'Left TmpArrVarArr for Debugging
TmpVarArr(TmpAreaCnt, 2) = TmpAreaVarArr 'Creates Jagged Array
Next TmpAreaCnt
PreserveFormulaeInVariantArr = TmpVarArr
Exit Function
ErrLabel:
aErrStr = "PreserveFormulaeInVariantArr - Error Number: " + CStr(Err.Number) + " Error Description: " + Err.Description
End Function
Function RestoreFormulaeFromVariantArr(ByVal aWorksheet As Worksheet, _
ByVal aIsEmptyAreaVarArrError As Boolean, _
ByVal aAreaVarArr As Variant, _
ByRef aErrStr As String) As Boolean
Dim TmpVarArrCnt As Long
Dim TmpRange As Range
Dim TmpDim1Var As Variant
Dim TmpDim2Var As Variant
Dim TmpDim2Cnt As Long
Dim TmpDim2UBound As Long
RestoreFormulaeFromVariantArr = False
On Error GoTo ErrLabel
If aWorksheet Is Nothing Then
Exit Function
End If
If IsEmpty(aAreaVarArr) Then
If aIsEmptyAreaVarArrError Then
aErrStr = "RestoreFormulaeFromVariantArr: Empty array passed."
Else
RestoreFormulaeFromVariantArr = True
End If
Exit Function
End If
For TmpVarArrCnt = 1 To UBound(aAreaVarArr)
TmpDim1Var = aAreaVarArr(TmpVarArrCnt, 1) 'This is always the range.
TmpDim2Var = aAreaVarArr(TmpVarArrCnt, 2) 'This can be a Variant or Variant Array
aWorksheet.Range(TmpDim1Var).Formula = TmpDim2Var
Next TmpVarArrCnt
RestoreFormulaeFromVariantArr = True
Exit Function
ErrLabel:
aErrStr = "PreserveFormulaeInVariantArr - Error Number: " + CStr(Err.Number) + " Error Description: " + Err.Description
End Function
Sub TestPreserveFormulaeInVariantArr()
Dim TmpPreserveFormulaeArr As Variant
Dim TmpErrStr As String
Dim TmpIsNoFormulaErr As Boolean: TmpIsNoFormulaErr = True 'Change If Desired
Dim TmpEmptySheet1 As Boolean: TmpEmptySheet1 = False 'Change If Desired
Dim TmpSheet1 As Worksheet: Set TmpSheet1 = Sheets("Sheet1")
Dim TmpSheet2 As Worksheet
Err.Clear
On Error Resume Next
Set TmpSheet2 = Sheets("Sheet2")
On Error GoTo 0
'Always Delete Sheet2
If (TmpSheet2 Is Nothing) = False Then
Application.DisplayAlerts = False
TmpSheet2.Delete
Application.DisplayAlerts = True
Set TmpSheet2 = Nothing
End If
If TmpSheet2 Is Nothing Then
Set TmpSheet2 = Worksheets.Add(After:=Sheets("Sheet1"))
TmpSheet2.Name = "Sheet2"
TmpSheet2.Range("A1") = "Sheet2A1"
TmpSheet2.Range("B1") = "Sheet2A1"
TmpSheet2.Range("C4") = "Sheet2C4"
If TmpEmptySheet1 Then
TmpSheet1.Cells.ClearContents
Else
TmpSheet1.Range("A1").Formula = "=Sheet2!A1"
TmpSheet1.Range("B1").Formula = "=Sheet2!B1"
TmpSheet1.Range("C4").Formula = "=Sheet2!C4"
End If
End If
TmpPreserveFormulaeArr = PreserveFormulaeInVariantArr(TmpSheet1, TmpIsNoFormulaErr, TmpErrStr)
If TmpErrStr <> "" Then
MsgBox TmpErrStr
Exit Sub
End If
'Break Formulae and Cause #Ref Violation
Application.DisplayAlerts = False
TmpSheet2.Delete
Application.DisplayAlerts = True
'Add Sheet2 Back
Set TmpSheet2 = Worksheets.Add(After:=Sheets("Sheet1"))
TmpSheet2.Name = "Sheet2"
TmpSheet2.Range("A1") = "Sheet2A1"
TmpSheet2.Range("B1") = "Sheet2A1"
TmpSheet2.Range("C4") = "Sheet2C4"
'Restore Formulas Back to Sheet1
If RestoreFormulaeFromVariantArr(TmpSheet1, TmpIsNoFormulaErr, TmpPreserveFormulaeArr, TmpErrStr) = False Then
MsgBox TmpErrStr
Exit Sub
End If
End Sub
The TestPreserveFormulaeInVariantArr can be run in the VBE with options to set empty values. Any comments appreciated.
My macro is going through a folder and picking each Excel file and deleting the first tab which is named some_Accounts and then copy pasting data to the master workbook where the worksheet names match.
Getting the following error Method 'Name' of object '_Worksheet' on the following line of code
Set wsDst = wbDst.Worksheets(wsSrc.Name)
I made sure that the worksheet names are equal.
Sub ProjectMacro()
Dim wbDst As Workbook
Dim wsDst As Worksheet
Dim wbSrc As Workbook
Dim wsSrc As Worksheet
Dim MyPath As String
Dim strFilename As String
Dim lLastRow As Long
Dim LC As Long
Dim s As Worksheet, t As String
Dim i As Long, K As Long
K = Sheets.Count
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
Set wbDst = ThisWorkbook
MyPath = "C:\Users\Adam\Desktop\some files\"
strFilename = Dir(MyPath & "*.xls*", vbNormal)
Do While strFilename <> ""
Set wbSrc = Workbooks.Open(MyPath & strFilename)
'loop through each worksheet in the source file
For Each wsSrc In wbSrc.Worksheets
'Find the corresponding worksheet in the destination with the same
name as the source
For i = K To 1 Step -1
t = Sheets(i).Name
If t = "some_Accounts" Then
Application.DisplayAlerts = False
Sheets(i).Delete
Application.DisplayAlerts = True
End If
Next i
Set wsDst = wbDst.Worksheets(wsSrc.Name)
On Error GoTo 0
If wsDst.Name = wsSrc.Name Then
lLastRow = wsDst.UsedRange.Rows(wsDst.UsedRange.Rows.Count).Row + 1
wsSrc.UsedRange.Copy
wsDst.Range("A" & lLastRow).PasteSpecial xlPasteValues
End If
Next wsSrc
wbSrc.Close False
strFilename = Dir()
Loop
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Right now, you are looping through all the Worksheets in wbSrc. When wsSrc is the "some_Accounts" sheet, right after you've deleted it within For i = K to 1... End For, it no longer exists, and thus wsSrc has no Name and will throw an error later on. If you're deleting a sheet, do so before you loop through all the sheets in a workbook.
But since you are closing wbSrc without saving changes, I assume that you don't really need to delete that sheet; you can just skip it as you're looping.
That would look something like this:
For Each wsSrc In wbSrc.Worksheets
If wsSrc.Name <> "some_Accounts" Then
'... copy and pasting code here
End If
Next wsSrc
Note that you can incorporate a WorksheetExists function into your code to make sure that there is a matching sheet in wbDst. That's already been provided in another answer.
Try to put this in your code to see if the worksheet exists:
If worksheetExists(wbDst, wsDst.Name) = true then
MsgBox "Exists!"
else
MsgBox "Does not exist!"
end if
Public Function worksheetExists(ByVal wb As Workbook, ByVal sheetNameStr As String) As Boolean
On Error Resume Next
worksheetExists = (wb.Worksheets(sheetNameStr).Name <> "")
Err.Clear: On Error GoTo 0
End Function
[table - worksheet "output - flat"][1]
I have code below that checks to see if column "NamedRange" in the table attached appears as a named range in the (dstRng) template and if it does exist it returns the value to the right ("report balance"). How can I add a condition where when the user chooses a template it will only return values based on the Ted ID - in the table attached. I have 2 templates and it loops through the two templates however I want the first template to only return values for Ted ID 10004 and template 2 it will only return values for Ted ID 11372 and etc. etc. Hope that makes sense... let me know if u have any questions
Option Explicit
Sub Button4_Click()
Dim Desktop As Variant
Dim Files As Object
Dim Folder As Variant
Dim oShell As Object
Dim Tmplts As Variant ' Templates folder
Dim wsLocal As Worksheet
Dim wsGroup As Worksheet
Dim wb As Object
' Check Box 2 "Select All" must be checked to run the macro.
If ActiveSheet.Shapes("Check Box 2").ControlFormat.Value = xlOff Then Exit Sub
Application.ScreenUpdating = False
Application.EnableEvents = False
' Prompt user to locate the Templates folder.
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = True Then
Tmplts = .SelectedItems(1)
Else
Exit Sub
End If
End With
Set oShell = CreateObject("Shell.Application")
Set Desktop = oShell.Namespace(0)
' Create the Output folder on the User's Desktop if it does not exist.
Set Folder = Desktop.ParseName("Output")
If Folder Is Nothing Then
Desktop.NewFolder "Output"
Set Folder = Desktop.ParseName("Output")
End If
Set Files = oShell.Namespace(Tmplts).Items
Files.Filter 64, "*.xlsm"
For Each wb In Files
Set wb = Workbooks.Open(Filename:=wb.Path, UpdateLinks:=False)
Call BreakLinks(wb)
On Error Resume Next
Set wsLocal = wb.Worksheets("RVP Local GAAP")
Set wsGroup = wb.Worksheets("RVP Group GAAP")
'unprotect workbook
wsLocal.Unprotect Password:="KqtgH5rn9v"
wsGroup.Unprotect Password:="KqtgH5rn9v"
On Error GoTo 0
' Check that both worksheets exist before updating.
If Not wsLocal Is Nothing And Not wsGroup Is Nothing Then
Call ProcessNamedRanges(wb)
'lock the workbook
wsLocal.Protect Password:="KqtgH5rn9v"
wsGroup.Protect Password:="KqtgH5rn9v"
''MsgBox "Ranges have been updated sucessfully."
' Save the workbook to the folder and close.
On Error Resume Next
wb.SaveAs Filename:=Folder.Path & "\" & wb.Name
ActiveWorkbook.Close True
On Error GoTo 0
End If
Next wb
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Sub ProcessNamedRanges(ByRef wb As Workbook)
Dim dstRng As Range
Dim rng As Range
Dim rngName As Range
Dim rngNames As Range
Dim wks As Worksheet
Set wks = ThisWorkbook.Sheets("Output - Flat")
' Exit if there are no named ranges listed.
If wks.Range("D4") = "" Then Exit Sub
Set rngNames = wks.Range("D4").CurrentRegion
Set rngNames = Intersect(rngNames.Offset(1, 0), rngNames.Columns(2))
'Loop through all the values in NamedRange
For Each rngName In rngNames
' Verify the Named Range exists.
On Error Resume Next
Set dstRng = wb.Names(rngName.Text).RefersToRange
If Err = 0 Then
'Copy the report balance to the Template worksheet in column "G".
dstRng.Value = rngName.Offset(0, 1).Value
Else
'answer = MsgBox("The Named Range """ & rngName.Value & """ Does Not Exist" & vbLf & vbLf & "Continue?", vbYesNo + vbExclamation)
'If answer = vbNo Then Exit Sub
End If
On Error GoTo 0
Next rngName
End Sub
Sub BreakLinks(ByRef wb As Workbook)
Dim i As Long
Dim wbLinks As Variant
wbLinks = wb.LinkSources(xlExcelLinks)
If Not IsEmpty(wbLinks) Then
For i = 1 To UBound(wbLinks)
ActiveWorkbook.BreakLink wbLinks(i), xlLinkTypeExcelLinks
Next i
End If
End Sub
I have an existing worksheet "StudentSheet1" which I need to add as many times as a user needs.
For eg, if a user enters 3 in cell "A1", saves it and closes the workbook.
I want to have three sheets: "StudentSheet1" , "StudentSheet2" and "StudentSheet3" when the workbook is opened next time.
So I will have the Code in "Workbook_Open" event. I know how to insert new sheets, but cant insert this particular sheet "StudentSheet1" three times
Here is my code:
Private Sub Workbook_Open()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets.Add(Type:=xlWorksheet, After:=Worksheets(1))
Application.ScreenUpdating = True
End Sub
EDIT
Sorry I misread the question, try this:
Private Sub Workbook_Open()
Dim iLoop As Integer
Dim wbTemp As Workbook
If Not Sheet1.Range("A1").value > 0 Then Exit Sub
Application.ScreenUpdating = False
Set wbTemp = Workbooks.Open(Filename:="//Ndrive/Student/Student.xlsm")
wbTemp.Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
wbTemp.Close
Set wbTemp = Nothing
With Sheet1.Range("A1")
For iLoop = 2 To .Value
Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
ActiveSheet.Name = "StudentSheet" & iLoop
Next iLoop
.Value = 0
End With
Application.ScreenUpdating = True
End Sub
Why are you wanting to add sheets on the workbook open? If the user disables macros then no sheets will be added. As Tony mentioned, why not add the sheets when called by the user?
EDIT
As per #Sidd's comments, if you need to check if the sheet exists first use this function:
Function SheetExists(sName As String) As Boolean
On Error Resume Next
SheetExists = (Sheets(sName).Name = sName)
End Function
user793468, I would recommend a different approach. :)
wbTemp.Sheets("StudentSheet1").Copy After:=ThisWorkbook.Sheets(Sheets.Count)
is not reliable. Please see this link.
EDIT: The above code will fail if the workbook has defined names. Otherwise it is absolutely reliable. Thanks to Reafidy for catching that.
I just noticed OP's comment about the shared drive. Adding amended code to incorporate OP's request.
Tried and Tested
Option Explicit
Const FilePath As String = "//Ndrive/Student/Student.xlsm"
Private Sub Workbook_Open()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim TempName As String, NewName As String
Dim ShtNo As Long, i As Long
On Error GoTo Whoa
Application.ScreenUpdating = False
Set wb1 = ActiveWorkbook
Set ws1 = wb1.Sheets("Sheet1")
ShtNo = ws1.Range("A1")
If Not ShtNo > 0 Then Exit Sub
Set wb2 = Workbooks.Open(FilePath)
Set ws2 = wb2.Sheets("StudentSheet1")
For i = 1 To ShtNo
TempName = ActiveSheet.Name
NewName = "StudentSheet" & i
If Not SheetExists(NewName) Then
ws2.Copy After:=wb1.Sheets(Sheets.Count)
ActiveSheet.Name = NewName
End If
Next i
'~~> I leave this at your discretion.
ws1.Range("A1").ClearContents
LetsContinue:
Application.ScreenUpdating = True
On Error Resume Next
wb2.Close savechanges:=False
Set ws1 = Nothing
Set ws2 = Nothing
Set wb2 = Nothing
Set wb1 = Nothing
On Error GoTo 0
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
'~~> Function to check if sheet exists
Function SheetExists(wst As String) As Boolean
Dim oSheet As Worksheet
On Error Resume Next
Set oSheet = Sheets(wst)
On Error GoTo 0
If Not oSheet Is Nothing Then SheetExists = True
End Function