Not sure why but the following code has begun to throw an unknown error. When the macro is run Excel stops responding.
Why is this error occuring?
What is an alternative route with the same functionality?
This code is located within an Excel 2010 xlsm file on a Windows 7 machine.
Sub CopyFolderToCasinoDirectory()
'reference Microsoft Scripting Runtime
On Error Resume Next
Dim fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
fso.CopyFolder _
"\\xxxfileserve\department$\DBA\Opers\All Operators\yyy", _
"\\xxxfileserve\department$\DBA\Cas\yyy", _
True
On Error GoTo 0
Set fso = Nothing
End Sub
ok - I've changed the pathways so that it is attempting to move less files - and it hesitates but does eventually run through. I suspect that the above is failing because there are too many files in the directory specified? Currently there are 753 files - maybe too much?
RonDeBruin has given me lots of ideas of how to test or alter the logic. One possibility might be to use DeleteFolder first on the destination folder, and then CopyFolder the target folder over?
Sorry for replying so late. I was not able to get hold of network directories and I wanted to test the code before posting it :)
Try this. Run the Sub Sample() Does it still hang? You will also see the Files getting transferred in a Windows Dialog Box.
Private Declare Function SHFileOperation _
Lib "shell32.dll" Alias "SHFileOperationA" _
(lpFileOp As SHFILEOPSTRUCT) As Long
Private Type SHFILEOPSTRUCT
hWnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAborted As Boolean
hNameMaps As Long
sProgress As String
End Type
Private Const FO_COPY = &H2
Sub Sample()
Dim path1 As String, path2 As String
path1 = "\\xxxfileserve\department$\DBA\Opers\All Operators\yyy"
path2 = "\\xxxfileserve\department$\DBA\Opers\All Operators\yyy"
If CopyFolder(path1, path2) Then
MsgBox "Copied"
Else
MsgBox "Not copied"
End If
End Sub
Private Function CopyFolder(ByVal sFrom As String, _
ByVal sTo As String) As Boolean
Dim SHFileOp As SHFILEOPSTRUCT
On Error GoTo Whoa
CopyFolder = False
With SHFileOp
.wFunc = FO_COPY
.pFrom = sFrom
.pTo = sTo
End With
SHFileOperation SHFileOp
CopyFolder = True
Exit Function
Whoa:
MsgBox "Following error occurred while copying folder " & sFrom & vbCrLf & _
Err.Description, vbExclamation, "Error message"
End Function
There are some points regarding the fso.CopyFolder method:
If destination does not exist, the source folder and all its contents gets copied. This is the usual case.
If destination is an existing file, an error occurs.
If destination is a directory, an attempt is made to copy the folder and all its contents.
If a file contained in source already exists in destination, an error occurs if overwrite is False. Otherwise, it will attempt to copy the file over the existing file.
If destination is a read-only directory, an error occurs if an attempt is made to copy an existing read-only file into that directory and overwrite is False.
Make sure not any of these are becoming hindrance for your sub.
But test it another way like this
fso.CopyFolder _
"\\xxxfileserve\department$\DBA\Opers\All Operators\yyy\*", _
"\\xxxfileserve\department$\DBA\Cas\yyy", _
True
Hope this helps.
Related
My goal is to read the FileNames of all png files in a given folder.
I've Windows VBA code which uses the ActiveX FileSystemObject.
On a MAC This code results in
"runtime error 429 activex component can't create object"
Function ReadFileNames(ByVal sPath As String) As Integer
Dim oFSO, oFolder, oFile As Object
Dim sFileName As String
Set oFSO = CreateObject("scripting.FileSystemObject")
Set oFolder = oFSO.getfolder(sPath)
For Each oFile In oFolder.Files
If Not oFile Is Nothing And Right(LCase(oFile.Name), 4) = ".png" Then ' read only PNG-Files
sFileName = oFile.Name
' do something with the FileName ...
End If
Next oFile
End Function
Here is a sub, using the native VBA DIR command, listing EXCEL workbooks in a folder by printing their names on the debug window:
Public Sub DirXlList()
Const cstrPath As String = "c:\users\xxxx\misc\"
Dim strDirItem As String
strDirItem = Dir(cstrPath & "*.xlsx")
While strDirItem <> ""
Debug.Print "FileName: " & strDirItem, "FullPath: " & cstrPath & strDirItem
strDirItem = Dir()
DoEvents
Wend
End Sub
Does this help? In
Update: doevents command allows Excel to process other pending user interface activities, such as window refreshes, mouse-clicks. If you have lots of files (thousands) in a folder, Excel may appear unresponsive/frozen in a loop like this. It is not necessary, as it will become responsive again, once it completes the loop. If you have only a few hundred files then it is an overkill. Remove and try.
VBA for Mac can link to the entire c standard library, like this example:
Private Declare PtrSafe Function CopyMemory_byPtr Lib "libc.dylib" Alias "memmove" (ByVal dest As LongPtr, ByVal src As LongPtr, ByVal size As Long) As LongPtr
I'm too lazy to write out relevant examples for you, but if, by chance, you are familiar with using the c standard library for file manipulation, you can just do it that way.
I'm using these two functions to create project folders on startup. In the beginning I'm creating only one folder named ProjectName but now there's other folders on the same level with ProjectName named ProjectName_Inputs, ProjectName_Files, ProjectName_Outputs. I want to create them with my below code.
I wonder how can I adapt this to my code. I mean, is it possible to use an array or for loop etc.? path = [/ProjectName, ProjectName_Inputs, ProjectName_Files, ProjectName_Outputs] I don't know if it's possible?
Or can you suggest a more logical way to create them?
Sub CreateFolders()
Dim fso As New FileSystemObject
If Functions.FolderExists(path) Then
Exit Sub
Else
On Error GoTo FolderNotBuilt
fso.CreateFolder path ' could there be any error with this, like if the path is really screwed up?
Exit Sub
End If
FolderNotBuilt:
MsgBox "A folder could not be created for the following path: " & path & ". Check the path name and try again."
FolderCreate = False
Exit Sub
End Sub
This is the function that controls whether or not the directory created before
Function FolderExists(ByVal path As String) As Boolean
FolderExists = False
Dim fso As New FileSystemObject
If fso.FolderExists(path) Then FolderExists = True
End Function
Edited to amend a typo (End With missing) and change Resume to Resume Nextand skip the possibly screwed up path
I’d go like follows
Sub CreateFolders()
Dim path As Variant
With CreateObject("Scripting.FileSystemObject") 'create and reference a FileSystemObject object
For Each path In Array("path1*\", "path2", "path3")
If Not .FolderExists(path) Then 'loop through paths in array
On Error GoTo FolderNotBuilt
.CreateFolder path ' could there be any error with this, like if the path is really screwed up?
End If
Next
End With
Exit Sub
FolderNotBuilt:
MsgBox "A folder could not be created for the following path: " & vbCrLf & vbCrLf & path & vbCrLf & "Check the path name and try again."
Resume Next
End Sub
I'm mapping to the company's sharepoint drive using VBA. The intention is to save local file to sharepoint, and delete local file and unmapped the drive after success.
On my machine(Windows 10 64bits), the code works perfectly fine, successfully mapped the drive, created folder and file, successfully uploaded to sharepoint and unmap the drive.
However, when I run the same excel workbook that contains the same code on my colleague's computer(Window 7), it failed. There's no error being shown, except that it keeps on loading and loading until Excel Not Responsive. I tried manually mapping the drive, it success.
I tried to debug and found out that the code stops (keeps on loading) at MsgBox "Hello" but could not figure out what's missing.
Both are using Excel 2016
Any help and suggestions are appreciated. let me know if more info is needed. Thanks in advance.
This is my vba code
Sub imgClicked()
Dim fileName As String
Dim SharePointLib As String
Dim MyPath As String
Dim folderPath As String
Dim objNet As Object
Dim copyPath As String
Dim copyFilePath As String
folderPath = Application.ThisWorkbook.path
MyPath = Application.ThisWorkbook.FullName
Dim objFSO As Object
Dim strMappedDriveLetter As String
Dim strPath As String
Dim spPath As String
strPath = "https://company.com/sites/test/test 123/" 'example path
spPath = AvailableDriveLetter + ":\test.xlsm" 'example path
copyPath = folderPath + "\copyPath\"
'Add reference if missing
Call AddReference
Set objFSO = CreateObject("Scripting.FileSystemObject")
With objFSO
strMappedDriveLetter = IsAlreadyMapped(.GetParentFolderName(strPath))
If Not Len(strMappedDriveLetter) > 0 Then
strMappedDriveLetter = AvailableDriveLetter
If Not MapDrive(strMappedDriveLetter, .GetParentFolderName(strPath)) Then
MsgBox "Failed to map SharePoint directory", vbInformation, "Drive Mapping Failure"
Exit Sub
End If
End If
' Check file/folder path If statement here
End With
Set objFSO = Nothing
End Sub
Code for getting available drive
' Returns the available drive letter starting from Z
Public Function AvailableDriveLetter() As String
' Returns the last available (unmapped) drive letter, working backwards from Z:
Dim objFSO As Object
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
For i = Asc("Z") To Asc("A") Step -1
Select Case objFSO.DriveExists(Chr(i))
Case True
Case False
Select Case Chr(i)
Case "C", "D" ' Not actually necessary - .DriveExists should return True anyway...
Case Else
AvailableDriveLetter = Chr(i)
Exit For
End Select
End Select
Next i
Set objFSO = Nothing
MsgBox "This is the next available drive: " + AvailableDriveLetter ' returns Z drive
MsgBox "Hello" ' After this msgBox, starts loading until Not Responsive
End Function
Function to Map drive
Public Function MapDrive(strDriveLetter As String, strDrivePath As String) As Boolean
Dim objNetwork As Object
If Len(IsAlreadyMapped(strDrivePath)) > 0 Then Exit Function
Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive strDriveLetter & ":", strDrivePath, False
MapDrive = True
MsgBox "Successfully Created the Drive!"
Set objNetwork = Nothing
End Function
Code for MappedDrive
Public Function GetMappedDrives() As Variant
' Returns a 2-D array of (1) drive letters and (2) network paths of all mapped drives on the users machine
Dim objFSO As Object
Dim objDrive As Object
Dim arrMappedDrives() As Variant
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
ReDim arrMappedDrives(1 To 2, 1 To 1)
For i = Asc("A") To Asc("Z")
If objFSO.DriveExists(Chr(i)) Then
Set objDrive = objFSO.GetDrive(Chr(i))
If Not IsEmpty(arrMappedDrives(1, UBound(arrMappedDrives, 2))) Then
ReDim Preserve arrMappedDrives(1 To 2, 1 To UBound(arrMappedDrives, 2) + 1)
End If
arrMappedDrives(1, UBound(arrMappedDrives, 2)) = Chr(i) ' Could also use objDrive.DriveLetter...
arrMappedDrives(2, UBound(arrMappedDrives, 2)) = objDrive.ShareName
End If
Next i
GetMappedDrives = arrMappedDrives
Set objDrive = Nothing
Set objFSO = Nothing
End Function
Public Function IsAlreadyMapped(strPath As String) As String
' Tests if a given network path is already mapped on the users machine
' (Returns corresponding drive letter or ZLS if not found)
Dim strMappedDrives() As Variant
Dim i As Long
strMappedDrives = GetMappedDrives
For i = LBound(strMappedDrives, 2) To UBound(strMappedDrives, 2)
If LCase(strMappedDrives(2, i)) Like LCase(strPath) Then
IsAlreadyMapped = strMappedDrives(1, i)
Exit For
End If
Next i
Set objNetwork = Nothing
End Function
Add Reference
Sub AddReference()
'Macro purpose: To add a reference to the project using the GUID for the
'reference library
Dim strGUID As String, theRef As Variant, i As Long
'Update the GUID you need below.
strGUID = "{420B2830-E718-11CF-893D-00A0C9054228}"
'Set to continue in case of error
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID, Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Procedure imgClicked is calling function AvailableDriveLetter multiple times. Remember that the function has to execute each time you refer to it.
I ran imgClicked (assuming that's the procedure you start with) and I was told, twice, "Next available letter = Z" and "Hello" and then it crashed Excel (perhaps getting stuck in a loop of creating FileSystem objects to look for an available drive letter?)
Try assigning AvailableDriveLetter to a variable (string) at the beginning of the procedure and referring to the variable each time you need the value, and see if you still have the issue.
(Remember to save before execution -- I get frustrated when troubleshooting "application hanging" issues because I keep forgetting to save my changes and then lose them on the crash!)
If this doesn't work, add a breakpoint (F9) on the End Function line after your "Hello" box and see if the code stops there. (I have trouble believing the MsgBox or End Function are the culprit.) If not, which procedure runs after that?
One more thing whether the issue is resolved or not:
Add Option Explicit at the very beginning of your module and then Compile the project and fix your missing variable declaration(s).
This is recommended whenever troubleshooting an issue as a means to eliminate variable declaration issues as a possible cause.
UPDATE 2 (3/21/17)
I have discovered that trying to open an Excel book after hitting the Submit button once happens only when one (or all) of the imported sheets from the module are deleted. (The process removes the old sheets before re-submitting to clear out the workbook to start over). For a manual test, I hit the submit button, delete any of the imported worksheets then try to open any excel file and it crashes. I have also ensured all defunct named ranges are removed when the sheet is deleted. I also tested this on a file that just imports a blank sheet. Then I delete it and am able to open workbook just fine. I'd like to avoid having to create my module (since it's a kind of a drag).
Original Question
I have an Excel Workbook Tool that opens other Excel Workbooks and imports worksheets from those workbook after processing some information.
In total there are 5 module workbooks. At a high level these workbooks are the same - sheet structure, general code structure, etc. There are differing formulas and some named ranges are different, etc.
In the main tool, there is the ability to re-run the code that pulls the information from the different workbooks. It essentially resets the original workbook and then runs the code again. This is done without closing the original workbook. (A user can refresh web-service data and re-run the tool).
The problem I am facing is that when I re-run the process for two of the modules workbooks Excel crashes during the re-run at that point where the code attempts to open the module workbook. The other 3 module workbooks work great. I can run and re-run and re-run ... The other 2 crash every time.
I have done a ton a research on the files to see why this could happen, but have not found out why. There are no links left in the main workbook after the process runs, no data connections, no bad links etc.
Also, the interesting thing is that the files I store in the UAT environment folder work fine all the time. The files in the production folder fail. I even copied the files directly from the UAT environment folder to the production environment folder and it still fails. I have also ruled out permission and security at the folder level.
I can also open the file manually after submitting the code the first time.
I realize this may be slightly out of scope for SO and a little vague but was hoping someone may have had a similar experience and could shed some light.
Update
The relevant code is below. Based on the comments by #Ralph I forced a memory wipe by adding the line Set wbLOB = Nothing, but unfortunately, issue still happens.
Function LoadLOB(sLOB As String, sXMLFile As String) As Boolean
Dim sLOBFile As String
sLOBFile = wsReference.Range("ModuleFolder").Value2 & sLOB & "\" & sLOB & ".xlsb"
Dim wbLOB As Workbook
Set wbLOB = Workbooks.Open(sLOBFile) '--> 2nd run crashes on this line.
If TieXMLToExcel(wbLOB, sXMLFile, sLOB) Then
MapXMLFieldsToExcelCells wbLOB, sLOB
Select Case sLOB
Case Is = "Property"
SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tCommonLocationProperty", "Location_ID"
SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tLocationByCoverageTypeProperty", "Location_ID"
Case Is = "GeneralLiability": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tClassCodesByLocationGeneralLiability", "Location_ID"
Case Is = "CommercialAuto": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tVehicleSummaryCommercialAuto", "AuVehicleNo"
Case Is = "Crime": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tCommonLocationCrime", "Location_ID"
End Select
Application.Run wbLOB.Name & "!PrepareSheetForMasterFile", ThisWorkbook
wbLOB.Close False
LoadLOB = True
End If
Set wbLOB = Nothing
End Function
I doubt this is the answer, but I figured this is a better forum for exchanging the ideas I had on this issue. What I did is I grabbed some windows APIs to check to see if that file is open before trying to open it again. I also added a method to close the file, and I made the SaveChanges parameter more explicit. I also added a few DoEvents in there, in case something is waiting to finish.
Hopefully this is a launching pad for other ideas. I hope some of this helps.
'Determine whether a file is already open or not
#If VBA7 And Win64 Then
Private Declare PtrSafe Function lOpen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long
Private Declare PtrSafe Function lClose Lib "kernel32" Alias "_lclose" (ByVal hFile As Long) As Long
#Else
Private Declare Function lOpen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long
Private Declare Function lClose Lib "kernel32" Alias "_lclose" (ByVal hFile As Long) As Long
#End If
Function LoadLOB(ByVal sLOB As String, _
ByVal sXMLFile As String) As Boolean
Dim sLOBFile As String
Dim wbLOB As Workbook
sLOBFile = wsReference.Range("ModuleFolder").Value2 & sLOB & "\" & sLOB & ".xlsb"
'Make sure the file is closed before processing
If Not isFileOpen(sLOBFile) Then
Set wbLOB = Workbooks.Open(sLOBFile, 0, False)
Else
'Close it if it is open
closeWB sLOBFile
Set wbLOB = Workbooks.Open(sLOBFile, 0, False)
End If
If TieXMLToExcel(wbLOB, sXMLFile, sLOB) Then
MapXMLFieldsToExcelCells wbLOB, sLOB
Select Case sLOB
Case Is = "Property"
SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tCommonLocationProperty", "Location_ID"
SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tLocationByCoverageTypeProperty", "Location_ID"
Case Is = "GeneralLiability": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tClassCodesByLocationGeneralLiability", "Location_ID"
Case Is = "CommercialAuto": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tVehicleSummaryCommercialAuto", "AuVehicleNo"
Case Is = "Crime": SortTableByAscendingColumn wbLOB, "xml" & sLOB, "tCommonLocationCrime", "Location_ID"
End Select
Application.Run wbLOB.Name & "!PrepareSheetForMasterFile", ThisWorkbook
DoEvents
wbLOB.Close SaveChanges:=False
LoadLOB = True
End If
Set wbLOB = Nothing
End Function
Sub closeWB(ByVal FilePath As String)
Dim wb As Workbook
For Each wb In Application.Workbooks
If wb.FullName = FilePath Then
wb.Close SaveChanges:=False
Set wb = Nothing
DoEvents
Exit For
End If
Next
End Sub
Function isFileOpen(ByVal FileName As String) As Boolean
Dim FileNumb As Long: FileNumb = -1
Dim lastErr As Long
FileNumb = lOpen(FileName, &H10)
'Determine if we can open the file
If FileNumb = -1 Then
lastErr = Err.LastDllError
Else
lClose (FileNumb)
End If
' Check if there is a sharing violation and report back status
isFileOpen = (FileNumb = -1) And (lastErr = 32)
End Function
Not sure how helpful this answer will be, but I re-created the module files from scratch and they worked in all environments. Most likely a small corruption in the file that I could not find.
Simple Version:
Module A has a Public variable X
I want to be able to get the value of X from Module B, without hardcoding the name 'Module A', i.e. (obviously this is not the right code):
MsgBox Modules("Module A").X
More Advanced Version:
I have an Add-In/XLSM (it can toggle itself) called TAAA.xlsm. I use Rob Bovey's error handling system, and want to improve/expand it.
A lot of my modules create new workbooks. If the user receives an error, I want to give them the option of sending me the error to examine myself. I'd like it to prompt the user, and if they say 'yes', the error handler would use Outlook to e-mail me:
Error Log
TAAA.xlsm
Any child workbooks related to the error
My plan was to have a Public Workbook Array for each module where it would store any workbooks created/used by the code that caused the error. That way when the error handler processes, it can access that public array in order to attach the workbooks.
I suppose a "simpler" solution would be to store this data on worksheet in TAAA, though it's not as elegant.
Any thoughts would be much appreciated!
EDIT
I solved my own problem in an Answer below. However, I'm still curious if there is a good answer to my original question or if that's impossible.
So in retrospect, the answer seems pretty obvious to me.
How does the central error handler know which module the error came from? By the private module name string being passed to the central error handler.
Likewise, I can just pass the workbook array as another parameter to the central error handler!
So instead of the central error handler looking like this:
Public Function bCentralErrorHandler( _
ByVal sModule As String, _
ByVal sProc As String, _
Optional ByVal sFile As String, _
Optional ByVal bEntryPoint As Boolean) As Boolean
Static sErrMsg As String
Dim iFile As Integer
Dim lErrNum As Long
Dim sFullSource As String
Dim sPath As String
Dim sLogText As String
' Grab the error info before it's cleared by
' On Error Resume Next below.
lErrNum = Err.Number
' If this is a user cancel, set the silent error flag
' message. This will cause the error to be ignored.
If lErrNum = glUSER_CANCEL Then sErrMsg = msSILENT_ERROR
' If this is the originating error, the static error
' message variable will be empty. In that case, store
' the originating error message in the static variable.
If Len(sErrMsg) = 0 Then sErrMsg = Err.Description
' We cannot allow errors in the central error handler.
On Error Resume Next
' Load the default filename if required.
If Len(sFile) = 0 Then sFile = ThisWorkbook.Name
' Get the application directory.
sPath = ThisWorkbook.Path
If Right$(sPath, 1) <> "\" Then sPath = sPath & "\"
' Construct the fully-qualified error source name.
sFullSource = "[" & sFile & "]" & sModule & "." & sProc
' Create the error text to be logged.
sLogText = " " & Application.UserName & sFullSource & ", Error " & _
CStr(lErrNum) & ": " & sErrMsg
' Open the log file, write out the error information and
' close the log file.
iFile = FreeFile()
Open sPath & msFILE_ERROR_LOG For Append As #iFile
Print #iFile, Format$(Now(), "mm/dd/yy hh:mm:ss"); sLogText
If bEntryPoint Then Print #iFile,
Close #iFile
' Do not display or debug silent errors.
If sErrMsg <> msSILENT_ERROR Then
' Show the error message when we reach the entry point
' procedure or immediately if we are in debug mode.
If bEntryPoint Or gbDEBUG_MODE Then
Application.ScreenUpdating = True
MsgBox sErrMsg, vbCritical, gsAPP_NAME
' Clear the static error message variable once
' we've reached the entry point so that we're ready
' to handle the next error.
sErrMsg = vbNullString
End If
' The return vale is the debug mode status.
bCentralErrorHandler = gbDEBUG_MODE
Else
' If this is a silent error, clear the static error
' message variable when we reach the entry point.
If bEntryPoint Then sErrMsg = vbNullString
bCentralErrorHandler = False
End If
End Function
I would change the definition to:
Public Function bCentralErrorHandler( _
ByVal sModule As String, _
ByVal sProc As String, _
Optional ByVal wbChildWorkbooks() As Workbook, _
Optional ByVal sFile As String, _
Optional ByVal bEntryPoint As Boolean) As Boolean
Fairly obvious in retrospect. Sorry for the wasted question.