Cannot close open workbook object - vba

I have a macro that opens an Excel file with test data, performs some simple formatting to the data, and then saves the data as a new file (keeping the file that was opened originally unchanged). I got everything to work up until the very last line, where I try to close the workbook I originally opened. There is some code just prior to attempting to close the original workbook, that sets a different workbook variable as the first one, then opens and closes it? I am a bit confused as to what the code is doing, but it closes the new file that the user just saved, and leaves the original data file that was opened at the beginning open. Here is my code below; can someone explain a little better what is happening when it saves and closes the workbook?
Sub Main()
'
'
'
'Define variables
Dim wBook As Workbook
Dim sBook As String
Dim ActSheet As Worksheet
Dim ActBook As Workbook
Dim CurrentFile As String
Dim NewFileType As String
Dim NewFile As String
'Get workbook filepath
sBook = Application.GetOpenFilename()
If sBook = "False" Then
End
End If
'Open Workbook
Set wBook = Workbooks.Open(sBook)
'Unrelated formatting occurs
'Save workbook as new file
Application.ScreenUpdating = False ' Prevents screen refreshing.
CurrentFile = wBook.FullName
NewFileType = "Excel Files 2007 (*.xlsx), *.xlsx,"
NewFile = Application.GetSaveAsFilename( _
InitialFileName:=NewFileName, _
fileFilter:=NewFileType)
If NewFile <> "" And NewFile <> "False" Then
wBook.SaveAs Filename:=NewFile, _
FileFormat:=xlOpenXMLWorkbook, _
Password:="", _
WriteResPassword:="", _
ReadOnlyRecommended:=False, _
CreateBackup:=False
Set ActBook = wBook
Workbooks.Open CurrentFile
ActBook.Close
End If
Application.ScreenUpdating = True
wBook.Close
End Sub

When you .SaveAs the wBook object becomes the "new file." You can just close that and be fine. If you wanted to create a new object leaving the original object unchanged you would use Workbook.SaveAsCopy instead.
So, what is happening in your code:
wBook.SaveAs
causes wBook to be the "new file" and the "old file is automatically closed"
Set ActBook = wBook
is basically creating two "new file" objects.
The old file is then opened using
Workbooks.Open CurrentFile
And then,
ActBook.Close
closes both wBook AND ActBook.
wBook.Close
tries to close an already closed workbook and throws an error. (Because it was the same as ActBook.)
I believe your intention is the following:
Sub Main()
'
'
'
'Define variables
Dim wBook As Workbook
Dim sBook As String
Dim ActSheet As Worksheet
Dim ActBook As Workbook
Dim CurrentFile As String
Dim NewFileType As String
Dim NewFile As String
'Get workbook filepath
sBook = Application.GetOpenFilename()
If sBook = "False" Then
End
End If
'Open Workbook
Set wBook = Workbooks.Open(sBook)
'Unrelated formatting occurs
'Save workbook as new file
Application.ScreenUpdating = False ' Prevents screen refreshing.
CurrentFile = wBook.FullName
NewFileType = "Excel Files 2007 (*.xlsx), *.xlsx,"
NewFile = Application.GetSaveAsFilename( _
InitialFileName:=NewFileName, _
fileFilter:=NewFileType)
If NewFile <> "" And NewFile <> "False" Then
wBook.SaveAs Filename:=NewFile, _
FileFormat:=xlOpenXMLWorkbook, _
Password:="", _
WriteResPassword:="", _
ReadOnlyRecommended:=False, _
CreateBackup:=False
' wBook is now the "new file" at this point and the "old file" has been closed.
End If
Application.ScreenUpdating = True
wBook.Close ' Close the new file.
End Sub

Related

VBA Canceling SaveAs

I've got part of the code:
Workbooks.Add
ActiveWorkbook.SaveAs filename:=Application.GetSaveAsFilename(fileFilter:="Excel Workbook (*.xlsx), *.xlsx")
So the user selects where and what name the workbook should have. However, if he clicks "Cancel" or tries to close the window, the workbook still saves under the name "False". How to stop that? The best solution would be to exit sub if the user clicks "Cancel" or closes the window
I recommend not to use ActiveWorkbook at all. Instead reference the newly added workbook directly.
Option Explicit
Public Sub SaveEample()
Dim NewWb As Workbook
Set NewWb = Workbooks.Add 'set the new added workbook to a variable so we can access it later
Dim FileLocation As Variant
FileLocation = Application.GetSaveAsFilename(fileFilter:="Excel Workbook (*.xlsx), *.xlsx")
If Not FileLocation = False Then
NewWb.SaveAs FileName:=FileLocation
End If
End Sub
Dim s as Variant
s = Application.GetSaveAsFilename(fileFilter:="Excel Workbook (*.xlsx), *.xlsx")
if s = False then
else
ActiveWorkbook.SaveAs filename:=s
end if
The method returns false when the user clicks Cancel, so you have to check for this case. Something like this should work for you:
fileSaveName = Application.GetSaveAsFilename(fileFilter:="Text Files (*.txt), *.txt")
If fileSaveName <> False Then
ActiveWorkbook.SaveAs filename := fileSaveName
End If
Using #Pᴇʜ code I modified my to work like I want to:
Set NewWb = Workbooks.Add
genpath = Application.GetSaveAsFilename(fileFilter:="Excel Workbook (*.xlsx), *.xlsx")
If Not genpath = False Then
NewWb.SaveAs filename:=genpath
Else
NewWb.Close
Exit Sub
End If

VBA Copy Method keeps failing?

I could have sworn that this was working before - but for some reason, this doesn't appear to be working anymore. I'm trying to take the active worksheet (also, this may not be very pretty or clean, but I am still really new to VBA), copy it to a new worksheet, in the new worksheet I want to open the Excel save as dialog, and when the worksheet is saved (in CSV) format, I want the workbook to close (or even if it doesn't close) at least return the user to the original workbook and end the sub
Sub saveExportAs()
Application.CutCopyMode = False
Sheets("load").Select
ActiveWorkbook.Activate
Sheets("load").Copy
Dim varResult As Variant
Dim ActBook As Workbook
'display the save as dialog
varResult = Application.GetSaveAsFilename(InitialFileName:="\\network\folder\upload_" & Format(Date, "yyyy-mm-dd") & ".csv", FileFilter:= _
"Comma Delimited / Upload Files (*.csv),*.csv", Title:="Save Upload File")
'check to make sure the user didn't cancel
If varResult <> False Then
ActiveWorkbook.saveAs Filename:=varResult, _
FileFormat:=xlCSV
Exit Sub
End If
End Sub
you can use the sheets defined as workbook/worksheet to avoid issues... may be like this :
Sub saveExportAs()
Dim wb1, wb2 As Workbook
Dim ws As Worksheet
Dim varResult As Variant
Set wb1 = ThisWorkbook
Set ws = ThisWorkbook.Worksheets("load")
ws.Copy
Set wb2 = ActiveWorkbook
varResult = Application.GetSaveAsFilename(InitialFileName:="\\network\folder\upload_" & Format(Date, "yyyy-mm-dd") & ".csv", FileFilter:= _
"Comma Delimited / Upload Files (*.csv),*.csv", Title:="Save Upload File")
If varResult <> False Then
wb2.SaveAs Filename:=varResult, FileFormat:=xlCSV
wb2.Close Savechanges:=True
Exit Sub
End If
wb1.Activate
End Sub
Try this...
Sub exportAsCSV()
Dim wb As Workbook
Set wb = ActiveWorkbook
SaveCopyAsCSV ("Sheet1") ' replace Sheet1 with whatever sheet name you need
wb.Activate
End Sub
Private Function SaveCopyAsCSV(SourceSheet As String)
Application.DisplayAlerts = False
ThisWorkbook.Sheets(SourceSheet).copy
ActiveWorkbook.SaveAs fileName:=SourceSheet, FileFormat:=xlCSV, CreateBackup:=True
ActiveWorkbook.Close
Application.DisplayAlerts = True
End Function

VBA code has Runtime Error with XLSM documents but not XLS

This VBA code is working for me in copying and moving XLS files but when I try to run it on an XLSM file it is telling me runtime error and is highlighting;
"CurrentWB.Sheets(SheetNumber).Select 'Selects All Worksheets in Workbook"
Run-Time Error 1004: Select Method of Worksheet Class Failed
Does anyone know what the issue might be?
Sub AutoUpdate()
On Error Resume Next
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.PrintCommunication = False
Dim SystemPath As String
Dim FilePath As String
Dim FileName As String
Dim UtilityType As String
Dim ThisName As String
Dim FlattenedFilePath As String
Dim FlattenedFileFolder As String
Dim CurrentWB As Workbook 'Workbook Stores Workbook
SystemPath = Range("Sys.Path")
UtilityType = Range("Utility.Type")
FlattenedFileFolder = Range("Flattened.Files")
FilePath = SystemPath & UtilityType
FileName = Dir(FilePath & "\*.xls")
FlattenedFilePath = FilePath & "\" & FlattenedFileFolder
Do While FileName <> ""
Set CurrentWB = Workbooks.Open(FileName:=FilePath & "\" & FileName, UpdateLinks:=3) 'Sets CurrentWB = to that long name. This becomes the name of the workbook.
CurrentWB.RunAutoMacros Which:=xlAutoOpen 'Enables Macros in Workbook
CurrentWB.Save
ThisName = CurrentWB.Name
For SheetNumber = 1 To CurrentWB.Sheets.Count 'Counts Worksheets in Workbook
If (CurrentWB.Sheets(SheetNumber).Name <> "What If") Then
CurrentWB.Sheets(SheetNumber).Unprotect ("UMC626") 'Unprotects Workbook
With CurrentWB.Sheets(SheetNumber).UsedRange
.Value = .Value
End With
CurrentWB.Sheets(SheetNumber).Protect Password:="UMC626", DrawingObjects:=True, Contents:=True, Scenarios:=True 'Protects Workbook
End If
Next SheetNumber 'Runs Through Iteration
CurrentWB.Cells(1, 1).Select 'Saves each workbook at the top of the page
CurrentWB.SaveAs FileName:=FlattenedFilePath & "\" & ThisName
CurrentWB.Close 'Closes Workbook
FileName = Dir
Loop
End Sub

Combining macros in Excel

I'm trying to combine/nest 3 different functions in Excel VBE: open, loop, and click. I have them written out separately, but am unsure of how to combine them. I've tried the "call macro" function but got a compile error returned to me.
The goal is to open a bunch of files within a certain folder and click on the URL in all of them (the URL will not always be the same, so I need a click function that targets any unknown URL within a sheet).
Open macro:
Sub openMyfile()
Dim Source As String
Dim StrFile As String
Source = "/users/kmogilevsky/Desktop/IC_new/"
StrFile = Dir("/users/kmogilevsky/Desktop/IC_new/")
Do While Len(StrFile) > 0
Workbooks.Open Filename:=Source & StrFile
StrFile = Dir("/users/kmogilevsky/Desktop/IC_new/")
Loop
End Sub
Loop macro:
Sub LoopThroughFiles()
Dim MyObj As Object, MySource As Object, file As Variant
Set MySource = MyObj.GetFolder("/users/kmogilevsky/Desktop/IC_new/")
For Each file In MySource.Files
If InStr(file.Name, "test") > 0 Then
End If
Next file
End Sub
Click macro (this needs some work):
Private Sub CommandButton1_Click()
Call NewSub
End Sub
Sub ReadWorkbooksInCurrentFolder()
Dim wbDst As Workbook
Dim wbSrc As Workbook
Dim MyPath As String
Dim strFilename As String
'Stop annoying popups while macro is running
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
'When working with many open workbooks its good to explicitly reference all workbooks, makes sure your code works and easier to read, understand and remember which workbook is which.
Set wbDst = ThisWorkbook
srcSheetName = "Data"
dstSheetName = "Results"
'I want to loop through all .xlsx files in the folder
MyPath = ThisWorkbook.Path
strFilename = Dir(MyPath & "\*.xlsx", vbNormal)
If Len(strFilename) = 0 Then
MsgBox "No workbooks found ending in .xlsx in current folder"
Exit Sub
End If
Do Until strFilename = ""
Set wbSrc = Workbooks.Open(Filename:=MyPath & "\" & strFilename)
Call CollectData(wbDst, wbSrc, dstSheetName, srcSheetName)
wbSrc.Close
strFilename = Dir()
Loop
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Sub CollectData(ByRef wbDst as Workbook, ByRef wbSrc as Workbook, dstSheetName as String, srcSheetName as String)
'Copy cell A1 contents in source workbook to destination workbook cell A1
wbDst.Sheets(dstSheetName).Range("A1") = wbSrc.Sheets(srcSheetName).Range("A1")
End Sub
Please edit the subroutine CollectData() so that it suits your needs, i.e. performs the click / url open. (I am not familiar with opening urls from excel, but I loop through workbooks often)
This code will open all Excel files in the IC_New folder on the desktop.
It will then look at each sheet and follow any hyperlinks that are on the sheet.
Sub Open_ClickHyperlinks()
Dim sPath As String
Dim vFiles As Variant
Dim vFile As Variant
Dim wrkBk As Workbook
Dim wrkSht As Worksheet
Dim HLink As Hyperlink
sPath = CreateObject("WScript.Shell").SpecialFolders("Desktop") & Application.PathSeparator & _
"IC_New" & Application.PathSeparator
'Return all files that have an extension starting with xls.
vFiles = EnumerateFiles(sPath, "xls*")
'Loop through each file.
For Each vFile In vFiles
'Open the file
Set wrkBk = Workbooks.Open(Filename:=vFile, UpdateLinks:=False)
With wrkBk
'Loop through each worksheet in the file.
For Each wrkSht In .Worksheets
'Loop through each hyperlink on the worksheet.
For Each HLink In wrkSht.Hyperlinks
HLink.Follow
Next HLink
Next wrkSht
.Close SaveChanges:=False
End With
Next vFile
End Sub
'Get all files in the specified folder, default to include all subfolders as well.
Public Function EnumerateFiles(sDirectory As String, _
Optional sFileSpec As String = "*", _
Optional InclSubFolders As Boolean = True) As Variant
EnumerateFiles = Filter(Split(CreateObject("WScript.Shell").Exec _
("CMD /C DIR """ & sDirectory & "*." & sFileSpec & """ " & _
IIf(InclSubFolders, "/S ", "") & "/B /A:-D").StdOut.ReadAll, vbCrLf), ".")
End Function

Clear copy of current file from data

There is workflow to fill in a sheet and mail it when you're done. The method to mail will send the current sheet as attachment, but it should directly create a new copy of the sheet where all your data is removed from.
I can clear the current sheet, but that's wrong, as I need to clear the new sheet. I have read about running macros on other workbooks, but it fails to run the macro. What's the best solution?
Sub SendData_Click()
If MsgBox("Sure to send?", vbYesNo, "Confirm") = vbYes Then
' Save current sheet
ActiveWorkbook.Save
' Send the current file
Mail_ActiveSheet
' Mark this sheet as sent
Worksheets("Data").Range("B6").Value = True
' Create a new emptied version
Create_New_Copy
MsgBox "Your data is sent"
End If
End Sub
Sub Create_New_Copy()
Dim Wb As Workbook
Dim NewFileName As String
Dim FileExtStr As String
Dim FilePath As String
Set Wb = ActiveWorkbook
NewFileName = "FileNameHere " & Format(DateAdd("d", 1, Now), "yyyy-mm-dd")
FileExtStr = "." & LCase(Right(Wb.Name, Len(Wb.Name) - InStrRev(Wb.Name, ".", , 1)))
FilePath = ActiveWorkbook.Path & "\" & NewFileName & FileExtStr
' # This is the problem, how to clear only the new file??
' Clear_Sheet_Invoices
' Save this sheet as the new file
Wb.SaveCopyAs FilePath
End Sub
Sub Clear_Sheet_Invoices()
Dim Ws As Worksheet
Set Ws = Worksheets("MyDataSheet")
' Remove all contents
Ws.Range("B2:F999").ClearContents
' Mark the "sent" flag for the new sheet to False
Worksheets("Data").Range("B6").Value = False
End Sub
As you might note, I am using ActiveWorkbook.SaveCopyAs to create a copy, and I have a Sub Clear_Sheet_Invoices which can clear all required data. How to run this sub on the new file?
I have thought to copy the MyDataSheet to a new sheet, clear the data sheet, save the new file and copy the sheet back. On opening a file, I check if a copy of the sheet is present and I will remove the sheet. Yeah, damn ugly, there should be a better way right? ;)
You can change the definition of Clear_Sheet_Invoices() in that way that it requires a parameter of Workbook type and it would clear worksheet "MyDataSheet" in this workbook.
Then you can invoke this sub and pass the newly created workbook as a parameter.
Below is the code you need to change to implement it:
Sub Clear_Sheet_Invoices(Wb As Workbook)
Dim Ws As Worksheet
Set Ws = Wb.Worksheets("MyDataSheet")
' Remove all contents
Ws.Range("B2:F999").ClearContents
' Mark the "sent" flag for the new sheet to False
Wb.Worksheets("Data").Range("B6").Value = False
End Sub
Sub Create_New_Copy()
Dim Wb As Workbook
Dim NewWb As Workbook
Dim NewFileName As String
Dim FileExtStr As String
Dim FilePath As String
Set Wb = ActiveWorkbook
NewFileName = "FileNameHere " & Format(DateAdd("d", 1, Now), "yyyy-mm-dd")
FileExtStr = "." & LCase(Right(Wb.Name, Len(Wb.Name) - InStrRev(Wb.Name, ".", , 1)))
FilePath = ActiveWorkbook.Path & "\" & NewFileName & FileExtStr
' Save this sheet as the new file
Wb.SaveCopyAs FilePath
Set NewWb = Excel.Workbooks.Open(FilePath)
' # This is the problem, how to clear only the new file??
Call Clear_Sheet_Invoices(NewWb)
Call NewWb.Close(True)
End Sub
Method SendData_Click doesn't require any changes.