VBA Can't close read-only workbook after updating from file - excel

I want to update a read-only workbook from the file "Data.xlsx".
I change the file in another application in a read-write workbook.
When I try to close the read-only workbook after updating it, an error accours.
This is my code:
Option Explicit
Public xlApp As New Application
Public wb_readWrite As Workbook
Public wb_readOnly As Workbook
Sub main()
Dim path As String
path = ThisWorkbook.path & "\Data.xlsx"
Set wb_readOnly = Workbooks.Open(path, readOnly:=True)
Set wb_readWrite = xlApp.Workbooks.Open(path, readOnly:=False)
wb_readWrite.Sheets(1).Cells(1, 1) = InputBox("Input your data")
wb_readWrite.Save
MsgBox "Update Now"
wb_readOnly.UpdateFromFile
wb_readWrite.Close
wb_readOnly.Close 'Error is here
Set wb_readWrite = Nothing
Set wb_readOnly = Nothing
End Sub

Looks like calling UpdateFromFile reloads the workbook and breaks any existing VBA references to the workbook - you need to re-establish any references after the update.
So you could use a wrapper like this for example:
Sub ReloadWorkbook(wb As Workbook)
Dim app As Application, nm As String
Set app = wb.Application 'in case in a different instance of Excel
nm = wb.Name
wb.UpdateFromFile
Set wb = app.Workbooks(nm)
End Sub
and call
ReloadWorkbook wb_readOnly
instead of wb_readOnly.UpdateFromFile

Related

How to Close Excel application and workbook that is open and running in the background? [duplicate]

I have some code for exporting subform results to Excel workbook. Code works fine, only one small issue. If I do export, excel file opens If user wants I open. When this Excel file is opened and user wants to do Export again, I receive error 1004.
This error is produced because file is open, and new Excel object want to save a file with same name. What I want is when this happens, just cancel everything and let user know that he must first close this previously created workbook. Here is what I tried:
If Err.Number = 1004 Then
MsgBox "Error. You have opened Excel file, that has same name as this file name should be. Please close that file first !", vbCritical
Cancel = True
Set wb = Nothing ' wb is wb=XcelFile.Workbooks.Add
Set XcelFile = Nothing ' Xcelfile is Xcelfile= New Excel.Application
End If
This code works, when user closes that file, export can be performed - old file is just overwritted. Problem is that Excel application is still opened in Windows Task Manager, so Excel object is not properly closed.
Does anybody have a better solution ?
P.S.: I tried including numbers in file name of Excel, so that It wouldn't be same name, but I can't get It fixed.
EDIT: Here is how I tried changing filename
Dim i as Integer
ExcelFilename = "RESULTS_" & Format(Date, "dd/mm/yyyy") & "_" & i & "_" & ".xlsx"
i = i + 1
"i" doesn't change It's value when I run code once again. How can I make it increment ? This would solve my problem...
I suggest a simple solution: add the time to the file name to prevent conflicts.
ExcelFilename = "RESULTS_" & Format(Now(), "yyyy-mm-dd_hh-nn-ss") & ".xlsx"
For a number that will increment as long as the application is running, try
Static i As Integer
Static variables
You must be very strict in opening the Excel objects and closing them in reverse order - as done in this example:
Public Sub RenameWorkSheet()
Dim xls As Excel.Application
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set xls = New Excel.Application
Set wkb = xls.Workbooks.Open("c:\test\workbook1.xlsx")
Set wks = wkb.Worksheets(1)
wks.Name = "My New Name"
wkb.Close True
Set wks = Nothing
Set wkb = Nothing
xls.Quit
Set xls = Nothing
End Sub

Copying worksheets between different instance of Excel.Application

I am working on a VSTO Excel add-in where at some point, it will open a template workbook from Resources and copy a sheet from it to the running instance of Excel. I want to avoid the short white window flash when copying from the template so I created a hidden instance of Excel.Application and call it from there. This part works but when copying, I keep getting "System.Runtime.InteropServices.COMException: 'Copy method of Worksheet class failed'"
Dim tempFileName As String = "DesignWorks1_Template"
Dim tempName As String = Path.GetTempPath() & "\" & tempFileName & ".xlsx"
Dim ResMgr = New Resources.ResourceManager("MyUtilities.Resources", System.Reflection.Assembly.GetExecutingAssembly)
Dim fstream As New FileStream(tempName, FileMode.Create, FileAccess.Write)
Dim filestreamWrite As New BinaryWriter(fstream)
filestreamWrite.Write(My.Resources.DesignWorks1, 0, My.Resources.DesignWorks1.Length)
fstream.Close()
filestreamWrite.Close()
Dim currentWorkbook As Excel.Workbook = Globals.ThisAddIn.Application.ActiveWorkbook
Dim newHiddenApp As New Excel.Application
newHiddenApp.Visible = False
Dim oTemplate As Excel.Workbook = newHiddenApp.Workbooks.Add(tempName)
oTemplate.Worksheets(compareName).Copy(currentWorkbook.Worksheets(1)) 'error here
oTemplate.Close()
My.Computer.FileSystem.DeleteFile(tempName)
ResMgr.ReleaseAllResources()
Thanks in advance.
Is it possible to specify a particular sheet from the template? I tried Sheets.Add but it seems to import all worksheets from the specified path. – Virtual Underscore
This is the major pain point in exporting each sheet in a workbook to a WorkSheet template file. When you perform the save-as Worksheet template, the subject Worksheet must be the only Worksheet in the Workbook. If more than one Worksheet exists in the Workbook, you will be exporting a Workbook template.
You can copy the following VBA code to the ThisWorkbook code file of the Workbook you want to export templates from. Make sure you modify the templateFolder = "F:\Temp\Templates" line in the code. Run it and it will export each Worksheet in the Workbook.
Sub ExportWorksheetTemplates()
Excel.Application.DisplayAlerts = False
Excel.Application.ScreenUpdating = False
Dim templateFolder As String
templateFolder = "F:\Temp\Templates" ' set this to an existing folder on you system
Dim tmpWb As Excel.Workbook
Dim old_numsheets As Integer
old_numsheets = Excel.Application.SheetsInNewWorkbook
Excel.Application.SheetsInNewWorkbook = 1
Dim ws As Excel.Worksheet
Dim newWBFirstSheet As Excel.Worksheet
Dim templatePath As String
On Error GoTo Finalize
For Each ws In ThisWorkbook.Worksheets
Set tmpWb = Excel.Application.Workbooks.Add()
Set newWBFirstSheet = tmpWb.Worksheets(1)
newWBFirstSheet.Name = "."
ws.Copy after:=newWBFirstSheet
newWBFirstSheet.Delete
templatePath = templateFolder & "\" & tmpWb.Worksheets(1).Name & ".xltx"
tmpWb.Worksheets(1).SaveAs templatePath, Excel.XlFileFormat.xlOpenXMLTemplate
tmpWb.Close
Next
Finalize:
Excel.Application.DisplayAlerts = True
Excel.Application.ScreenUpdating = True
Excel.Application.SheetsInNewWorkbook = old_numsheets
End Sub
Now you can add each of those files to your VSTO project's resources.
Then you would export the resource templates to a temporary file as you are currently doing.
When you use the Sheets.Add method and specify Type:="path to template", you will now only get the single Worksheet added to the Workbook.
When running Excel on the desktop, you cannot copy sheets between instances. Therefore I doubt that it can be done when the Excel instances are initiated with VB.
In order to copy sheets between workbooks, these need to run in the same instance.

How to remedy Workbooks not closing properly

I'm currently writing a macro that will allow you to select a folder, set bounds, and then loop through some numbers to read in all of a certain file type. (Excel in this instance.)
You can see that right here
Dim StringP1 As String
Dim iterator As Integer
Dim StringP2 As String
Dim i As Integer
Dim final As Integer
'number of files
final = 5
'main folder
StringP1 = " FOLDER NAME "
StringP2 = ".xls"
i = 1
While i < final
iterator = 1
FileName = StringP1 & iterator & StringP2
Call attempt1(FileName)
Call attempt2(FileName)
i = (i + 1)
iterator = (iterator + 1)
Wend
when it loads into my subs it uses this code
Sub attempt1(FN As String)
Dim Excel As New Excel.Application
Dim FileName As String
Set XL = CreateObject("Excel.Application")
Set MyRec = CurrentDb.OpenRecordset("Infor")
Excel.Workbooks.Open (FN)
Then it goes through some code, and eventually ends up exiting the subroutine.
Everything I've tried seems to fail.
I've been messing with this for a few hours, using various things I've found from Stackoverflow and other VBA sites, but nothing seems to work.
I've tried using
excel.workbooks.close savechanges:=false
workbook.close
workbooks.close
.
.
.
I'm curious if anyone knows a good way to exit all of these EXCEL.EXE that open?
If I understand correctly you are trying to close all workbooks (Excel files).
Proper way to close single workbook by its name:
XL.Workbooks("filename.xls").Close Savechanges:=False
If you have many workbooks to close you may use a cycle like this:
Public Sub WorkWithExcel()
Dim XL As New Excel.Application, WB As Excel.Workbook
' Open Excel file:
XL.Workbooks.Open ("my_file.xls")
' Open another Excel file
XL.Workbooks.Open ("another my file.xls")
' do some work with this files
' ...
' For every file in our application:
For Each WB In XL.Workbooks
' Close file without saving changes:
WB.Close savechanges:=False
Next WB
' Close Excel applicatioin:
XL.Quit
' Clear object:
Set XL = Nothing
End Sub

Access VBA - close Excel object

I have some code for exporting subform results to Excel workbook. Code works fine, only one small issue. If I do export, excel file opens If user wants I open. When this Excel file is opened and user wants to do Export again, I receive error 1004.
This error is produced because file is open, and new Excel object want to save a file with same name. What I want is when this happens, just cancel everything and let user know that he must first close this previously created workbook. Here is what I tried:
If Err.Number = 1004 Then
MsgBox "Error. You have opened Excel file, that has same name as this file name should be. Please close that file first !", vbCritical
Cancel = True
Set wb = Nothing ' wb is wb=XcelFile.Workbooks.Add
Set XcelFile = Nothing ' Xcelfile is Xcelfile= New Excel.Application
End If
This code works, when user closes that file, export can be performed - old file is just overwritted. Problem is that Excel application is still opened in Windows Task Manager, so Excel object is not properly closed.
Does anybody have a better solution ?
P.S.: I tried including numbers in file name of Excel, so that It wouldn't be same name, but I can't get It fixed.
EDIT: Here is how I tried changing filename
Dim i as Integer
ExcelFilename = "RESULTS_" & Format(Date, "dd/mm/yyyy") & "_" & i & "_" & ".xlsx"
i = i + 1
"i" doesn't change It's value when I run code once again. How can I make it increment ? This would solve my problem...
I suggest a simple solution: add the time to the file name to prevent conflicts.
ExcelFilename = "RESULTS_" & Format(Now(), "yyyy-mm-dd_hh-nn-ss") & ".xlsx"
For a number that will increment as long as the application is running, try
Static i As Integer
Static variables
You must be very strict in opening the Excel objects and closing them in reverse order - as done in this example:
Public Sub RenameWorkSheet()
Dim xls As Excel.Application
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set xls = New Excel.Application
Set wkb = xls.Workbooks.Open("c:\test\workbook1.xlsx")
Set wks = wkb.Worksheets(1)
wks.Name = "My New Name"
wkb.Close True
Set wks = Nothing
Set wkb = Nothing
xls.Quit
Set xls = Nothing
End Sub

How to open a Workbook with a password, disable events

How to open a Workbook with a password, disable events,
and then copy a sheet in background to the second file and save.
I need in VBA, working in a MS-Access and Excel files
I have done this until now, is working.
Private Sub TestFunction()
'strPath = CurrentDb.Properties(0)
'strPath = Left(strPath, Len(strPath) - Len(Dir(strPath, vbNormal))) & "Temp\"
Dim CopyFrom As Object
Dim CopyTo As Object ''Early binding: Workbook
Dim CopyThis As Object
Dim xl As Object ''Early binding: New Excel.Application
Set xl = CreateObject("Excel.Application")
xl.Visible = True
Set CopyFrom = xl.Workbooks.Open("D:\A01.xls")
'CopyFrom.EnableEvents = False
Set CopyThis = CopyFrom.Sheets(1) ''Sheet number 1
Set CopyTo = xl.Workbooks.Open("D:\PM1.xls")
CopyThis.Copy After:=CopyTo.Sheets(CopyTo.Sheets.Count)
CopyFrom.Close
End Sub
This opens the Excel, I enter the pass copy's the sheet to second File.
But I need to pass the password in background, delete the sheet and save the second file, all in background.
Also I need to delete a sheet, without asking me, like :
CopyTo.Sheets("Sheet1").Delete
Thank you
Password issue
Be careful to check wether it is an "open file" password (password parameter) or a "modify file" password (WriteResPassword parameter).
Something like:
Sub OpenMyFile()
Workbooks.Open Filename:="Path", Password:="OpenFile", WriteResPassword:="WriteFile"
End Sub
Delete without alert
For your second question, here is what you can do:
Application.DisplayAlerts=False
CopyTo.Sheets("Sheet1").Delete
Application.DisplayAlerts=True

Resources