remove excel macros from multiple closed files - excel

I have +500 Excel files (*.xls) having macros, all located in same folder.
I want to remove all macros from these files. Removing macros manually one by one from all files will take too much time.
Is it possible to create a new macro in a separate excel file which will remove all macros from these closed files?
Thanks for your guidance in advance.

I have coded routines around macro ListComponentsSingleWbk to meet your requirement. I have tested then with a variety of workbooks and I believe they provide the functionality you seek.
Both ListComponentsCtrl and DeleteLinesCtrl contain the statement Path = .... You will need to amend these statements to match the path of your folder.
I use macro ListComponentsSingleWbk to provide daily backups of the macros I am developing. I have coded ListComponentsCtrl to call ListComponentsSingleWbk for every XLS files in a folder.
I suggest you run ListComponentsCtrl before you do anything else. It will create a file with the name “BkUp yymmdd hhmm.txt” where “yymmdd hhmm” represent the current date and time. Following the run, “BkUp yymmdd hhmm.txt” will contain:
The name of every workbook it has found.
The name of every component within a workbook that might contain code.
If there is code within a component, a list of that code.
Running ListComponentsCtrl will ensure you have a complete backup if you discover in a month’s time that you have deleted macros from the wrong workbooks.
DeleteCodeCtrl calls DeleteCodeSingleWbk for every XLS files in a folder.
DeleteCodeSingleWbk:
Removes all standard and class modules from a workbook.
Clears any code from the code modules of the worksheets.
Clears any code from the code module of ThisWorkbook.
Option Explicit
' This module was built from information scattered across many sites. The
' most useful were:
' http://vbadud.blogspot.co.uk/2007/05/insert-procedure-to-module-using.html
' http://support.microsoft.com/kb/282830
' http://msdn.microsoft.com/en-us/library/aa443716(v=vs.60).aspx
' http://www.ozgrid.com/forum/showthread.php?t=32709
' This module needs a reference to:
' "Microsoft Visual Basic for Applications Extensibility n.n"
' The security system will probably prevent access to VBComponents unless you:
' For Excel 2003, from Excel (not VB Editor)
' Click Tools
' Click Macro
' Click Security
' Click Trusted Publishers
' Tick Trust access to Visual Basic Project
' For other versions of Excel search for "programmatic access to Visual Basic project not trusted"
Sub DeleteCodeCtrl()
Dim FileObj As Object
Dim FileSysObj As Object
Dim FolderObj As Object
Dim Path As String
Application.ScreenUpdating = False
Application.EnableEvents = False
' ### Change to directory containing your Excel workbooks
' Note: trailing "\" is assumed by later code
Path = ThisWorkbook.Path & "\TestFiles\"
Set FileSysObj = CreateObject("Scripting.FileSystemObject")
Set FolderObj = FileSysObj.GetFolder(Path)
For Each FileObj In FolderObj.Files
If LCase(Right(FileObj.Name, 4)) = ".xls" Then
Call DeleteCodeSingleWbk(Path & FileObj.Name)
End If
Next
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Sub DeleteCodeSingleWbk(ByVal WbkName As String)
Dim CodeLineCrnt As Long
Dim InxC As Long
Dim NumCodeLines As Long
Dim VBC As VBComponent
Dim VBCType As Long
Dim VBP As VBProject
Dim VBMod As CodeModule
Dim Wbk As Workbook
Err.Clear
' Switch off normal error handling in case attempt to open workbook fails
On Error Resume Next
' Second parameter = False means links will not be updated since not interested in data
' Third parameter = False mean open for updating
Set Wbk = Workbooks.Open(WbkName, False, False)
' Restore normal error handling.
On Error GoTo 0
If Err.Number <> 0 Then
On Error Resume Next
' In case partially open
Wbk.Close SaveChanges:=False
On Error GoTo 0
Else
Set VBP = Wbk.VBProject
' Process components in reverse sequence because deleting a component
' will change the index numbers of components below it.
For Each VBC In VBP.VBComponents
VBCType = VBC.Type
If VBCType = vbext_ct_StdModule Or VBCType = vbext_ct_ClassModule Then
' Component is a module and can be removed
VBP.VBComponents.Remove VBC
ElseIf VBCType = vbext_ct_Document Then
' Component can have a code module which can be cleared
Set VBMod = VBC.CodeModule
NumCodeLines = VBMod.CountOfLines
If NumCodeLines > 0 Then
Call VBMod.DeleteLines(1, NumCodeLines)
End If
End If
Next
Wbk.Close SaveChanges:=True
End If
End Sub
Sub ListComponentsCtrl()
Dim BkUpFileObj As Object
Dim FileObj As Object
Dim FileSysObj As Object
Dim FolderObj As Object
Dim Path As String
Application.ScreenUpdating = False
Application.EnableEvents = False
' ### Change to directory containing your Excel workbooks
' Note: trailing "\" is assumed by later code
Path = ThisWorkbook.Path & "\TestFiles\"
Set FileSysObj = CreateObject("Scripting.FileSystemObject")
Set FolderObj = FileSysObj.GetFolder(Path)
' Second parameter = False means existing file will not be overwritten
' Third parameter = False means ASCII file will be created.
Set BkUpFileObj = FileSysObj.CreateTextFile(Path & "BkUp " & Format(Now(), "yymmyy hhmm") & ".txt", _
False, False)
For Each FileObj In FolderObj.Files
If LCase(Right(FileObj.Name, 4)) = ".xls" Then
Call ListComponentsSingleWbk(Path & FileObj.Name, BkUpFileObj)
End If
Next
BkUpFileObj.Close
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Sub ListComponentsSingleWbk(ByVal WbkName As String, ByRef BkUpFileObj As Object)
Dim CodeLineCrnt As Long
Dim InxC As Long
Dim NumCodeLines As Long
Dim VBC As VBComponent
Dim VBCType As Long
Dim VBP As VBProject
Dim VBMod As CodeModule
Dim Wbk As Workbook
Call BkUpFileObj.WriteLine("Workbook " & WbkName)
Err.Clear
' Switch off normal error handling in case attempt to open workbook fails
On Error Resume Next
' Second parameter = False means links will not be updated since not interested in data
' Third parameter = True mean open read only
Set Wbk = Workbooks.Open(WbkName, False, True)
' Restore normal error handling.
On Error GoTo 0
If Err.Number <> 0 Then
Call BkUpFileObj.WriteLine(" Unable to open workbook: " & Err.desc)
Else
Set VBP = Wbk.VBProject
For InxC = 1 To VBP.VBComponents.Count
Set VBC = VBP.VBComponents(InxC)
VBCType = VBC.Type
If VBCType = vbext_ct_StdModule Or VBCType = vbext_ct_ClassModule Or _
VBCType = vbext_ct_Document Then
' Component can have a code module
Set VBMod = VBC.CodeModule
NumCodeLines = VBMod.CountOfLines
If NumCodeLines = 0 Then
Call BkUpFileObj.WriteLine(" No code associated with " & _
VBCTypeNumToName(VBCType) & " " & VBC.Name)
Else
Call BkUpFileObj.WriteLine(" Code within " & _
VBCTypeNumToName(VBCType) & " " & VBC.Name)
For CodeLineCrnt = 1 To NumCodeLines
Call BkUpFileObj.WriteLine(" " & VBMod.Lines(CodeLineCrnt, 1))
Next
End If
End If
Next
End If
Wbk.Close SaveChanges:=False
End Sub
Function VBCTypeNumToName(ByVal VBCType As Long) As String
Select Case VBCType
Case vbext_ct_StdModule ' 1
VBCTypeNumToName = "Module"
Case vbext_ct_ClassModule ' 2
VBCTypeNumToName = "Class Module"
Case vbext_ct_MSForm ' 3
VBCTypeNumToName = "Form"
Case vbext_ct_ActiveXDesigner ' 11
VBCTypeNumToName = "ActiveX Designer"
Case vbext_ct_Document ' 100
VBCTypeNumToName = "Document Module"
End Select
End Function

Given you couldnt get Tony's code to work try this version:
Change "C:\temp" to the path of your choice
All xls files will be opened, saved as "orginalfilename_no_code.xlsx" and the prior version will be removed
Sub CullCode()
Dim StrFile As String
Dim strPath As String
Dim WB As Workbook
strPath = "c:\temp\"
StrFile = Dir(strPath & "*.xls*")
With Application
.DisplayAlerts = False
.ScreenUpdating = False
.EnableEvents = False
End With
Do While Len(StrFile) > 0
Set WB = Workbooks.Open(strPath & StrFile)
WB.SaveAs strPath & StrFile & "_no_code.xlsx", 51
WB.Close False
Kill strPath & StrFile
StrFile = Dir
Loop
With Application
.DisplayAlerts = True
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub

Related

I'm trying to change event procedure s for multiple workbooks?

Please help as I stuck in error saying
"object variable or with block variable not set.
Error #91
It stucked in wb.close line
Please help as need to change the event procedure for multiple workbooks
Any idea
Sub CopyCode()
Dim wb As Workbook
Dim strInput
Dim VBP As Object, VBC As Object, CM As Object
Dim strpath As String, strCurrentFile As String
strpath = "C:\Users\Basem Lap\Desktop\test\"
strCurrentFile = Dir(strpath & "*.xls"*)
Do While strCurrentFile <> ""
Set wb = Workbooks.Open(strpath & strCurrentFile)
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(wb.CodeName)
Set CM = VBC.CodeModule
Application.DisplayAlerts = False
Application.DisplayAlerts = False
With wb.VBProject.VBComponents("ThisWorkbook").CodeModule
.ReplaceLine 1, "Private Sub Workbook_BeforeClose(Cancel As Boolean)"
End With
wb.Close savechanges:=True
Application.DisplayAlerts = False
Set wb = Nothing
strCurrentFile = Dir
Loop
MsgBox "Done"
End Sub
Please, change:
strCurrentFile = Dir(strpath & "*.xls"*)
with:
strCurrentFile = Dir(strpath & "*.xls*")
Wild character must be inside the string.
But I cannot understand how your code could pass over this. The error should (firstly) be raised on the above mentioned line...
Please, try adding this code line immediately after the line in discussion:
Debug.Print strCurrentFile: Stop
What does it return when the code stops? Is it a real workbook full name?
I would recommend that, when trying to modify something in a code module, to add a reference to "Microsoft Visual Basic for Applications Extensibility xx" library and appropriately declare the used variables. You will benefit of the intellisense suggestions, which may help a lot.
Edited:
If the code line to be replaced is the first one, your existing code should replace it with what you want. If it is not, please use the next code which will firstly search for the code to be replaces string, and make the replacement there where it is:
Function ReplaceCodeLine(wb As Workbook, strModule As String, strSearch As String, strReplace As String) As Boolean
Dim VBProj As Object, VBComp As Object, CodeMod As Object
Dim startL As Long, endL As Long
Dim strCLine As String, boolFound As Boolean
Set VBProj = wb.VBProject
Set VBComp = VBProj.VBComponents(strModule)
Set CodeMod = VBComp.CodeModule
startL = 1
With CodeMod
endL = .CountOfLines
boolFound = .Find(Target:=strSearch, StartLine:=startL, StartColumn:=1, _
EndLine:=endL, EndColumn:=255, wholeword:=True, MatchCase:=False, _
patternsearch:=False)
If boolFound Then
strCLine = Replace(CodeMod.Lines(startL, 1), strSearch, _
strReplace, Compare:=vbTextCompare)
.ReplaceLine startL, strCLine
ReplaceCodeLine = True
Else
ReplaceCodeLine = False
End If
End With
End Function
It can be called from your code by copying the above function in a standard module and replacing the next part:
With wb.VBProject.VBComponents("ThisWorkbook").CodeModule
.ReplaceLine 1, "Private Sub Workbook_BeforeClose(Cancel As Boolean)"
End With
with this one:
Dim strExist as String, strToReplace as String
strExist = "Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)"
strToReplace = "Private Sub Workbook_BeforeClose(Cancel As Boolean)"
Debug.Print ReplaceCodeLine(wb, "ThisWorkbook", strExist, strToReplace)
It will return in Immediate Window True if the line to be replaced has been found and the replacement took place.
Please, test it and send some feedback.
Edited second time:
The following solution will use a workbook having a correct "ThisWorkbook" code module, which will be copied to all the workbooks in the strPathfolder. You must take care of the strCurrentFile value. It may allow .xlsx documents, which cannot be saved with VBA inside...
The following solution needs a reference to 'Microsoft Visual for Applications Extensibility 5.3'. In order to add it programmatically, please copy the next code in a standard module and run it:
Sub addExtenssibilityReference()
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:="{0002E157-0000-0000-C000-000000000046}", _
Major:=5, Minor:=3
End Sub
Your existing code should be replaced by the next one:
Sub CopyThisWorkbookCode()
'It needs a reference to 'Microsoft Visual for Applications Extensibility 5.3'.
Dim VBProjSource As VBIDE.VBProject, VBCompSource As VBIDE.VBComponent
Dim VBProjTarget As VBIDE.VBProject, wb As Workbook, strCode As String
Set VBProjSource = ThisWorkbook.VBProject 'or another (open) workbook keeping
'the ThisWorkbook code to be copyed from
Set VBCompSource = VBProjSource.VBComponents("ThisWorkbook")
'all ThisWorkbook module code copied as string:
strCode = VBCompSource.CodeModule.Lines(1, VBCompSource.CodeModule.CountOfLines)
Dim strPath As String, strCurrentFile As String
strPath = "C:\Users\Basem Lap\Desktop\test\"
strCurrentFile = Dir(strPath & "*.xls*")
Application.EnableEvents = False: Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Do While strCurrentFile <> ""
Set wb = Workbooks.Open(strPath & strCurrentFile)
Set VBProjTarget = wb.VBProject
impThisWorkbookModule VBProjTarget, strCode
wb.Close savechanges:=True
strCurrentFile = Dir
Loop
Application.EnableEvents = True: Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
MsgBox "Done"
End Sub
Please, take care of VBProjSource choosing. In the above code, I used the workbook keeping this code. You may use another one: Set VBProjSource = Workbooks("Model Workbook").VBProject.
Copy the next function below the above code:
Function impThisWorkbookModule(VBProjT As VBIDE.VBProject, strCode As String)
Dim VBCompTarget As VBIDE.VBComponent
Set VBCompTarget = VBProjT.VBComponents("ThisWorkbook")
With VBCompTarget.CodeModule
.DeleteLines 1, .CountOfLines
.InsertLines 1, strCode
End With
End Function
Run CopyThisWorkbookCode Sub and send some feedback.
Change Type of Event Procedure
Something like this could be a solution. Hopefully the event procedures start in the first line.
The Code
Option Explicit
Sub CopyCode()
Const ReplaceString As String = _
"Private Sub Workbook_BeforeClose(Cancel As Boolean)"
Dim wb As Workbook
Dim VBP As Object, VBC As Object, CM As Object
Dim strpath As String, strCurrentFile As String
strpath = "C:\Users\Basem Lap\Desktop\test\"
strCurrentFile = Dir(strpath & "*.xls*")
Do While strCurrentFile <> ""
Set wb = Workbooks.Open(strpath & strCurrentFile)
' Debug.Print wb.FullName
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(wb.CodeName)
Set CM = VBC.CodeModule
Application.DisplayAlerts = False
CM.ReplaceLine 1, ReplaceString
wb.Close SaveChanges:=True
Application.DisplayAlerts = False
strCurrentFile = Dir
Loop
MsgBox "Done"
End Sub

Trying to go through all XLSX files within a folder, unprotect them, change value, and protect them

From MS Access, I am attempting to open every XLSX file within a folder and edit a specific cell within the excel document. However some of these files are protected and some are not. Therefore I am trying to add an IF statement to check for this potential roadblock (I know the password for the protected workbooks and it is consistent across all of them).
I have tried the below code but it keeps returning various errors after every time I alter some of it to work (current error is "Wrong Number of arguments or invalid property):
Private Sub Command0_Click()
Dim xl As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim fso As FileSystemObject
Dim objFolder As Folder
Dim objFile As File
Dim strPath As String
Dim strFile As String
Dim errnum As Long
Dim errtxt As String
'Specify the path to the folder.
strPath = CurrentProject.Path & "\originals"
'***** Set a reference to "Microsoft Scripting Runtime" by using
'***** Tools > References in the Visual Basic Editor (Alt+F11)
'Create an instance of the FileSystemObject.
Set fso = New Scripting.FileSystemObject
'Alternatively, without the reference mentioned above:
'Set fso = CreateObject("Scripting.FileSystemObject")
'Get the folder.
Set objFolder = fso.GetFolder(strPath)
'If the folder does not contain files, exit the sub.
If objFolder.Files.Count = 0 Then
MsgBox "No files found in the specified folder.", vbApplicationModal + _
vbExclamation + vbOKOnly, "Runtime Error"
Exit Sub
End If
'Turn off screen updating. It may run quicker if updating is disabled, but
'if the work to be done is minimal, it may not be necessary.
Set xl = Excel.Application
xl.ScreenUpdating = False
DoCmd.SetWarnings False
'Loop through each file in the folder
For Each objFile In objFolder.Files
strFile = objFile.Path
'Open each file and perform actions on it.
Set wb = xl.Workbooks.Open(objFile.Path)
'Set inline error trap in case PLOG tab does not exist.
On Error Resume Next
Set ws = wb.Worksheets("Whole Foods Market PLOG")
wb.Application.DisplayAlerts = False
errnum = Err.Number
errtxt = Err.Description
On Error GoTo -1
Select Case errnum
Case 0 'Zero = no error.
If ws.ProtectContents = True Then
ws.Unprotect "550" 'enter password
End If
ws.Cells(11, 20).Value = Date
ws.Protect "550", True, True
wb.Save
Case 9 'Subscript out of range; most likely the tab does not exist.
MsgBox "The workbook '" & objFile.Name & "' does not have a 'PLOG' tab."
Case 58
MsgBox "Fix This"
Case 91
Resume Next
Case Else 'All other errors.
MsgBox "Runtime error #" & CStr(errnum) & ": " & IIf(Right(errtxt, 1) = ".", errtxt, errtxt & ".")
End Select
wb.Application.DisplayAlerts = True
wb.Close False
Set wb = Nothing
Next objFile
'Turn screen updating back on
xl.ScreenUpdating = True
'IMPORTANT: Clean up & quit Excel. If this is not done, Excel will stay in memory
'after the macro ends. If this is done repeatedly, many individual instances of Excel
'will build up in memory, and will stay there until killed with an task app such as
'Windows Task Manager or SysInternals ProcessExplorer, or until the system is rebooted,
'and it may even prevent Windows from shutting down properly because all those instances
'of Excel are waiting for user input at the "Save workbook? Yes/No/Cancel" dialog.
xl.Quit
Set xl = Nothing
End Sub
I simply want the code to go through each excel file within the folder and do this:
if the workbook is protected then
unprotect it,
edit cell,
reprotect it,
save/close
if the workbook is not protected then
edit cell,
reprotect it,
save/close
Edit1: fixed a typo I saw in the original code
ws.Unprotect "550", True, True
This would be the "wrong number of arguments". Worksheet.Unprotect takes a single, optional, Password parameter - VBA doesn't know what to do with these two True arguments.
Option Compare Database
Option Explicit
Public Sub SO56995486()
'Declare the variables
Dim xl As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim fso As Scripting.FileSystemObject
Dim objFolder As Scripting.Folder
Dim objFile As Scripting.file
Dim fileList As VBA.Collection
Dim fldrPath As String
Dim fullpath As String
Dim filename As String
Dim errnum As Long
Dim c As Long
Dim i As Long
'Specify the path to the folder.
fldrPath = "C:\Temp\"
'Set up a log file.
Open fldrPath & "_logfile.txt" For Output As #1
'***** Set a reference to "Microsoft Scripting Runtime" by using
'***** Tools > References in the Visual Basic Editor (Alt+F11)
'Set up the major object variables.
Set xl = Excel.Application
Set fso = New Scripting.FileSystemObject
Set fileList = New VBA.Collection
'Get the folder.
Set objFolder = fso.GetFolder(fldrPath)
'If the folder does not contain files, exit the sub.
If objFolder.Files.Count = 0 Then
MsgBox "No files found in the specified folder.", vbApplicationModal + _
vbExclamation + vbOKOnly, "Runtime Error"
Exit Sub
End If
'Create a list of all XLSX files in the folder.
For Each objFile In objFolder.Files
filename = objFile.Name
If UCase(fso.GetExtensionName(filename)) = "XLSX" Then
fileList.Add objFile
End If
Next
'Remove any Excel temp files. Tricky loop since items may be deleted.
i = 1
Do
Set objFile = fileList.ITEM(i)
filename = Left(objFile.Name, 2)
If filename = "~$" Then
fileList.Remove (i)
Else
i = i + 1
End If
Loop Until i >= fileList.Count
'Remove any open files. Tricky loop again.
i = 1
Do
Set objFile = fileList.ITEM(i)
fullpath = objFile.Path
If IsFileOpen(fullpath) Then
fileList.Remove (i)
Else
i = i + 1
End If
Loop Until i >= fileList.Count
'Turn off screen updating. It may run quicker if updating is disabled, but
'if the work to be done is minimal, it may not be necessary.
xl.ScreenUpdating = False
DoCmd.SetWarnings False
'Loop through each file in the folder
For Each objFile In fileList
fullpath = objFile.Path
'Open the file. Use inline error trap in case it can't be opened.
On Error Resume Next
Set wb = xl.Workbooks.Open(fullpath)
errnum = Err.Number
On Error GoTo 0
Select Case errnum
Case 0 'File opened ok.
'Use inline error trap in case PLOG tab does not exist.
On Error Resume Next
Set ws = wb.Worksheets("PLOG")
errnum = Err.Number
On Error GoTo 0
Select Case errnum
Case 0 'Tab reference grabbed ok.
If ws.ProtectContents = True Then
ws.Unprotect "550" 'enter password
End If
ws.Cells(11, 20).value = Date
ws.Protect "550", True, True
On Error Resume Next
wb.Save
errnum = Err.Number
On Error GoTo 0
Select Case errnum
Case 0 'Saved ok.
Print #1, "OK: " & objFile.Name
Case Else
Print #1, "Couldn't save: " & objFile.Name
End Select
Case 9 'Subscript out of range; probably tab does not exist.
Print #1, "Tab does not exist: " & objFile.Name
Case Else 'Other errors.
Print #1, "Other error (" & CStr(errnum) & "): " & objFile.Name
End Select
Case Else
Print #1, "Can't open file: "; Tab(20); objFile.Name
End Select
wb.Close True
Set wb = Nothing
Next
'Turn screen updating back on
xl.ScreenUpdating = True
DoCmd.SetWarnings True
'IMPORTANT: Clean up & quit Excel. If this is not done, Excel will stay in memory
'after the macro ends. If this is done repeatedly, many individual instances of Excel
'will build up in memory, and will stay there until killed with an task app such as
'Windows Task Manager or SysInternals ProcessExplorer, or until the system is rebooted,
'and it may even prevent Windows from shutting down properly because all those instances
'of Excel are waiting for user input at the "Save workbook? Yes/No/Cancel" dialog.
xl.Quit
Set xl = Nothing
Close #1
End Sub
Public Function IsFileOpen(filename As String) As Boolean
Dim filenum As Integer
Dim errnum As Integer
On Error Resume Next
filenum = FreeFile()
' Attempt to open the file and lock it.
Open filename For Input Lock Read As #filenum
Close filenum
errnum = Err
On Error GoTo 0
Select Case errnum
Case 0
'No error.
IsFileOpen = False
Case 55, 70
'File already open.
IsFileOpen = True
Case Else
'Other error.
'IsFileOpen = ?
End Select
End Function

Access - open Excel file, do some coding with It and close

I'm trying to open an Excel file from Access and do some stuff with It, but code is not stable. Sometimes It works, other times not. Here's how I do this:
Dim FilePath As String
Dim ExcelApp As Excel.Application
FilePath = "C:\Users\Lucky\Desktop\Test.xls"
Set ExcelApp = CreateObject("Excel.Application")
ExcelApp.Workbooks.Open (FilePath)
With ExcelApp
'do some stuff here
End With
ExcelApp.Workbooks.Close
Set ExcelApp = Nothing
I've also noticed that once I run code, Excel starts proccess under Task Manager, that has to be killed manually in order to get code working again. Otherwise I get two types of error with Excel file:
one is that If I click Excel file, It doesn't open, It just flashes for a second and dissapears
and other is that Excel file opens in "read-only" mode...
So I reckon there is some flaw when file is closed in my code. How can I fix this ?
I can't see what's wrong with your code - maybe the path to the desktop?
This is the code I usually use - I've added another function to help choose the file. It uses late binding, so no need to set a reference to Excel - you don't get the IntelliSense and can't use Excel constants such as xlUp - you have to use the numerical equivalent.
Public Sub Test()
Dim oXLApp As Object
Dim oXLWrkBk As Object
Dim oXLWrkSht As Object
Dim vFile As Variant
Dim lLastRow As Long
vFile = GetFile()
Set oXLApp = CreateXL
Set oXLWrkBk = oXLApp.WorkBooks.Open(vFile, False)
Set oXLWrkSht = oXLWrkBk.WorkSheets(1) 'First sheet. Can also use "Sheet1", etc...
lLastRow = oXLWrkSht.Cells(oXLWrkSht.Rows.Count, "A").End(-4162).Row '-4162 = xlUp
MsgBox "Last row in column A is " & lLastRow
oXLWrkBk.Close False
oXLApp.Quit
Set oXLWrkBk = Nothing
Set oXLApp = Nothing
End Sub
Public Function CreateXL(Optional bVisible As Boolean = True) As Object
Dim oTmpXL As Object
'''''''''''''''''''''''''''''''''''''''''''''''''''''
'Defer error trapping in case Excel is not running. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
Set oTmpXL = GetObject(, "Excel.Application")
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
'If an error occurs then create an instance of Excel. '
'Reinstate error handling. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
If Err.Number <> 0 Then
Err.Clear
On Error GoTo ERROR_HANDLER
Set oTmpXL = CreateObject("Excel.Application")
End If
oTmpXL.Visible = bVisible
Set CreateXL = oTmpXL
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateXL."
Err.Clear
End Select
End Function
Function GetFile(Optional startFolder As Variant = -1, Optional sFilterName As String = "") As Variant
Dim fle As Object
Dim vItem As Variant
'''''''''''''''''''''''''''''''''''''''''''
'Clear the file filter and add a new one. '
'''''''''''''''''''''''''''''''''''''''''''
Application.FileDialog(3).Filters.Clear
Application.FileDialog(3).Filters.Add "'Some File Description' Excel Files", "*.xls, *.xlsx, *.xlsm"
Set fle = Application.FileDialog(3)
With fle
.Title = "Select a file"
.AllowMultiSelect = False
If startFolder = -1 Then
.InitialFileName = CurrentProject.Path
Else
If Right(startFolder, 1) <> "\" Then
.InitialFileName = startFolder & "\"
Else
.InitialFileName = startFolder
End If
End If
If .Show <> -1 Then GoTo NextCode
vItem = .SelectedItems(1)
End With
NextCode:
GetFile = vItem
Set fle = Nothing
End Function
I have managed to solve my problem. There is nothing wrong with code in my question, except that instead of declaring
Dim ExcelApp As Excel.Application
It's better to use
Dim ExcelApp As Object
But much bigger problem is with code that does changes in Excel, such as this line:
x = Range(Cells(1, i), Cells(Rows.Count, i).End(xlUp)).Value
And correct synthax is:
x = ExcelApp.Range(ExcelApp.Cells(1, i), ExcelApp.Cells(ExcelApp.Rows.Count, i).End(xlUp)).Value 'maybe also better to replace xlUp with -4162
So, whenever you use some code for Excel file from Access, DON'T FORGET to reference everything to Excel object. And ofcourse, before everything, a proper reference must be set in VBA console, in my case Microsoft Office 15.0 library.

Iterate through spreadsheets in a folder and collect a value from each

I'm trying to write code that on Commandbutton2_Click searches through the folder that the file is in, takes a value from the same cell in each file and adds these together.
I have this:
Private Sub CommandButton2_Click()
Dim lCount As Long
Dim wbResults As Workbook
Dim wbCodeBook As Workbook
Dim strFolderPath As String
Dim strToolNumber As String
Dim RingCount As Integer
RingCount = 0
strToolNumber = CStr(Sheets("Sheet1").Range("B9").Value)
strFolderPath = "T:\Engineering\Tooling\Tooling Control Engineering\Press Tool Inspection Records\" & strToolNumber & "\"
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.EnableEvents = False
On Error Resume Next
Set wbCodeBook = ThisWorkbook
With Application.FileSearch
.NewSearch
'Change path to suit
.LookIn = strFolderPath
.FileType = msoFileTypeExcelWorkbooks
If .Execute > 0 Then 'Workbooks in folder
For lCount = 1 To .FoundFiles.Count 'Loop through all
'Open Workbook x and Set a Workbook variable to it
Set wbResults = Workbooks.Open(FileName:=.FoundFiles(lCount), UpdateLinks:=0)
'DO YOUR CODE HERE
RingCount = Val(RingCount) + ActiveWorkbook.Sheets("Sheet1").Range("F11").Value
wbResults.Close SaveChanges:=False
Next lCount
End If
End With
On Error GoTo 0
ActiveSheet.Unprotect Password:=""
ActiveWorkbook.Sheets("Sheet1").Range("F13").Value = (RingCount + ActiveWorkbook.Sheets("Sheet1").Range("F11").Value)
ActiveSheet.Protect Password:=""
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.EnableEvents = True
End Sub
whose main body was pieced together from different google searches - but it continually returns a value of 0 (despite the cells in the other sheets having values).
I read somewhere that Application.Filesearch does not work for versions of Excel later than 2003, could this be the source of the problem?
Its possible to pull that value youre interested in without opening each workbook. Its much more efficient and reliable.
This code iterates through all files in the path variable and pulls values without opening the Excel files. It then prints the values starting at F20. You can then make another wrapper function to sum them up and delete or whatever you want. Hope this helps
Private Sub CommandButton2_Click()
Dim tool As String
tool = CStr(Sheets("Sheet1").range("B9").Value)
Dim path As String
path = "T:\Engineering\Tooling\Tooling Control Engineering\Press Tool Inspection Records\" & strToolNumber & "\"
Dim fname
fname = Dir(CStr(path)) ' gets the filename of each file in each folder
Do While fname <> ""
If fname <> ThisWorkbook.Name Then
PullValue path, fname ' add values
End If
fname = Dir ' get next filename
Loop
End Sub
Private Sub PullValue(path As String, ByVal fname As String)
With range("F" & (range("F" & Rows.Count).End(xlUp).Row + 1))
.Formula = "='" & path & "[" & fname & "]Sheet1'!F11"
.Value = .Value
End With
End Sub

I'm trying to merge all the excel spreadsheet into one Master spreadsheet

I'm trying to write an Excel Macro that will traverse through all the folders in the directory, and merge multiple excel spreadsheet into one. All the excel spreadsheet have the same format.
I'm able to traverse through all the folders in the directory but I keep getting errors when I try to merge the excel spreadsheet together.
This is the error message I got:
Run-time error '1004':
Excel cannot insert the sheets into the destination workbook, because
it contains fewer rows and columns than the source workbook. To move
or copy the data to the destination workbook, you can select the data,
and then use the Copy and Paste commands to insert it into the sheets
of another workbook.
This is what I have done so far:
Option Explicit
Sub FileListingAllFolder()
Dim pPath As String
Dim FlNm As Variant
Dim ListFNm As New Collection ' create a collection of filenames
Dim OWb As Workbook
Dim ShtCnt As Integer
Dim Sht As Integer
Dim MWb As Workbook
Dim MWs As Worksheet
Dim i As Integer
' Open folder selection
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select a Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
pPath = .SelectedItems(1)
End With
Application.WindowState = xlMinimized
Application.ScreenUpdating = False
' Create master workbook with single sheets
Set MWb = Workbooks.Add(1)
MWb.Sheets(1).Name = "Result"
Set MWs = MWb.Sheets("Result")
' Filling a collection of filenames (search Excel files including subdirectories)
Call FlSrch(ListFNm, pPath, "*Issues.xls*", True)
' Print list to immediate debug window and as a message window
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
Sheets(Sht).Copy After:=ThisWorkbook.Sheets(1)
Next Sht
OWb.Close False
Next FlNm
' Print to immediate debug window and message if no file was found
If ListFNm.Count = 0 Then
Debug.Print "No file was found !"
MsgBox "No file was found !"
MWb.Close False
End
End If
MWb.Activate
MWs.Activate
Cells.Select
Selection.EntireColumn.AutoFit
Range("A1").Select
Application.ScreenUpdating = True
Application.WindowState = xlMaximized
End
NextCode:
MsgBox "You Click Cancel, and no folder selected!"
End Sub
Private Sub FlSrch(pFnd As Collection, pPath As String, pMask As String, pSbDir As Boolean)
Dim flDir As String
Dim CldItm As Variant
Dim sCldItm As New Collection
' Add backslash at the end of path if not present
pPath = Trim(pPath)
If Right(pPath, 1) <> "\" Then pPath = pPath & "\"
' Searching files accordant with mask
flDir = Dir(pPath & pMask)
Do While flDir <> ""
pFnd.Add pPath & flDir 'add file name to list(collection)
flDir = Dir ' next file
Loop
' Procedure exiting if searching in subdirectories isn't enabled
If Not pSbDir Then Exit Sub
' Searching for subdirectories in path
flDir = Dir(pPath & "*", vbDirectory)
Do While flDir <> ""
' Do not search Scheduling folder
If flDir <> "Scheduling" Then
' Add subdirectory to local list(collection) of subdirectories in path
If flDir <> "." And flDir <> ".." Then If ((GetAttr(pPath & flDir) And _
vbDirectory) = 16) Then sCldItm.Add pPath & flDir
End If
flDir = Dir 'next file
Loop
' Subdirectories list(collection) processing
For Each CldItm In sCldItm
Call FlSrch(pFnd, CStr(CldItm), pMask, pSbDir) ' Recursive procedure call
Next
End Sub
I think this is the part that causes the problem.
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
Sheets(Sht).Copy After:=ThisWorkbook.Sheets(1)
Next Sht
OWb.Close False
Next FlNm
I have been trying to mess with this code for two days now. I'm not too sure where I did it wrong. :(
If you have acess to vb.net I would urge you to use that in combination with Excel-Interop.
I have tried the same thing as you do know - basically, it never worked 100% satisfactory with pure VBA. The combination of Vb.net and interop worked like a charm.

Resources