1004 Read-Only Error when Opening Closed Workbooks in VBA - vba

To give context to the problem that I'm facing - keep in mind I'm a relative novice - I am attempting to write a code that will open and then close a series of workbooks all contained within a folder, ultimately in order to update a number of VLookups on the master data sheet (since to update them, I believe the dependents need to be open).
Right now, I'm simply attempting to do this for one of the files which I can then go through and do for the rest of the folder. When I do attempt to open the file though, I get the "Run-Time Error 1004" with the message "Excel cannot access 'FolderName'. The document may be read-only or encrypted"
The code I'm using is:
sub openevery_v2()
' openevery_v2 Macro
' Keyboard Shortcut: Ctrl+Shift+O
' Dim diaFolder As FileDialog <-- Ideally the user would use a dialog box to select the folder
' Dim Fname As String
' Dim originalWB As Workbook
' Set originalWB = ThisWorkbook
' originalWB.Save
' Set diaFolder = Application.FileDialog(msoFileDialogFolderPicker)
' diaFolder.AllowMultiSelect = False
' diaFolder.Show
' Fname = diaFolder.SelectedItems(1)
Fname = "C:\FolderPath"
Openr = Dir(Fname + "Filename.xlsm")
Workbooks.Open (Fname)
End Sub
I've tried to change the settings of the folder from non-read only, but I don't think that is the issue at hand.
Has anyone run through a similar issue or can think of a solution to this particular issue? Alternatively, if there is a better way to think through this challenge, that would be much appreciated.

Your code is trying to open a file named c:\FolderPathFilename.xlsm. Unless that file exists in the root of your C: drive, you'll get errors.
This may be more of what you're after:
Fname = "C:\FolderPath\"
Openr = Dir(Fname & "Filename.xlsm")
Workbooks.Open (Fname)
Notice:
the \ added to the end of Fname.
The + is replaced with a &. VBA uses & for concatenation.
Of course, your code sample does seem to be a very cut-down version of what you're really executing, so that may not be the problem in your real code.

Related

How to open and activate another workbook in VBA?

I'm creating a macro where I will need to run it in 1 file (called "Masterfile"), it will open and execute the macro on another file ("SurveyReport") and then give me a message box saying "done!".
The code I have to execute on the SurveyReport file works fine when I open that file manually and execute it. The code I need to open SurveyReport from MasterFile is also working it seems, I ran the below with no issues:
Sub PivotTable()
'
' PivotTable Macro
Dim MasterFile As String
MasterFile = ActiveWorkbook.Name
Dim SurveyReport As String
SurveyReport = Application.GetOpenFilename("Excel files (*.xlsx), *xlsx", 1, "Please select the Survey Create Report file", , False)
Workbooks.Open (SurveyReport)
End Sub
But, when I try to activate the SurveyReport file so I can begin executing the macro in it, I get a "Subscript out of range" error. I've tried using the following code after the above block and before the code to execute in the SurveyReport file:
Windows(SurveyReport).Activate
This didn't work, not did:
ThisWorkbook.Activate
...which only had the effect of activating the MasterFile.
SurveyReport file is a .xlsx file. I tried saving it as a .xls file and amending the code, but no joy.
I also tried passing it the file name directly (i.e. Windows("filename.xlsx").Activate), same issue.
ActiveWorkbook is as it says on the tin - whichever workbook happens to be active when the code runs.
ThisWorkbook is always the workbook that the code is sitting in.
You can SET references to specific workbooks rather than just using their names each time. A name can change, or reference the wrong object.... imagine you have a friend called Darren. Each time you mention him you mention him by name. Someone that doesn't know Darren hasn't a clue which Darren out of all the ones available in the world you're talking about. Now imagine you have a little replica of Darren in your pocket... nah, that's a terrible anology - it wouldn't be a replica, it would be a reference to the real Darren... anyway, I digress.
This code sets a reference to the workbook, you can then use that reference any time you want to refer to the correct workbook:
Sub PivotTable()
Dim MasterFile As Workbook
Dim SurveyRptName As String
Dim SurveyReport As Workbook
Set MasterFile = ThisWorkbook '
SurveyRptName = Application.GetOpenFilename("Excel files (*.xlsx), *xlsx", 1, _
"Please select the Survey Create Report file", , False)
If SurveyRptName <> "False" Then
Set SurveyReport = Workbooks.Open(SurveyRptName)
End If
SurveyReport.Activate 'You don't need this line. It doesn't matter if
'the workbook is active, the code knows which one
'you're talking about in the next line.
MsgBox "This is " & SurveyReport.Name & _
" containing " & SurveyReport.Worksheets.Count & " sheets." & vbCr & _
"The value in cell A1 of the first sheet is " & _
SurveyReport.Worksheets(1).Range("A1")
End Sub
Edit: Of course, if you press Cancel when selecting a file then the lines following the IF...THEN code won't have a reference to work on and you'll get a Object Variable or With block variable not set - best not to run the bottom bit of code if you haven't successfully opened the Survey Report file.
The part of the answer that is missing - is that he tried to call a method of an object when his variable was STRING - the open command and subsequent commands will give you an OBJECT - which has properties and methods like .Activate. The STRING type has no such method or property (to be sure - it may have others).
the solution provided by Darren solves this by declaring his SurveyReport as type Workbook - an object of Excel.

Method 'SaveAs' of object '_Workbook' failed VBA

I have a workbook that is connected to a database and when you refresh the workbook, it refreshes your data in the workbook. Afterwards a macro is ran to save the new (raw) data in two different locations, then the macro will do analysis on that raw data, and save the same workbook later on in 4 other locations.
When I am trying to do the first save of the raw data, I am able to save to the first location, but when it moves to the second location I am getting the error: Run-time error '1004': Method 'SaveAs' of object '_Workbook' failed. Both of the locations are valid locations.
Here is one sub in the macro that does the first file save:
Sub saveraw()
Dim rdate As String
Dim rawfilename As String, rawfilename1 As String
Dim mywb As Workbook
Set mywb = ActiveWorkbook
rdate = Format(Now(), "mm-dd-yy")
rawfilename = "\\sw\mes\PS\SC\SCM_Supply_Execution\Spares\This Weeks Number Database\This Weeks Numbers(raw) " & rdate & ".xlsm"
rawfilename1 = "\\sw\mes\PS\SC\SCM_Shared\Spares Reports\This Weeks Numbers(raw) " & rdate & ".xlsm"
mywb.Save
Worksheets("Sheet2").Range("A2") = Null
Application.DisplayAlerts = False
mywb.SaveAs Filename:=rawfilename
mywb.SaveAs Filename:=rawfilename1
Application.DisplayAlerts = True
End Sub
I have also tried using the method of
ActiveWorkbook.SaveAs
in place of both of the mywb.SaveAs, but that did not work either.
As a test, run the code against file locations only YOU have access to. I'm noticing a reference to shared drive on the second command so maybe someone is already in it and it can't be saved over.
Set display alerts to true for now.
Also, When you run the test macro, make sure you don't have any windows explorer windows open and feed back here with results and I'll assist if it debugs again.
On the face of it, the code looks good to me.
Try this
ActiveWorkbook.SaveAs Filename:="\\sw\mes\PS\SC\SCM_Supply_Execution\Spares\This Weeks Number Database\This Weeks Numbers(raw) " & rdate & ".xlsm" _
, FileFormat:=xlOpenXMLWorkbookMacroEnabled
This might have issues if the file already exists because then a pop-up will ask you if you want to overwrite it or not
Though I think the error is due to an issue with privileges in that specific location or connection issues

Excel VBA: SaveAs, then killing old file has permission error

I have Excel VBA code, which I have distributed, to produce some reports. The code has errors, and I have now fixed them. I want to update the end users.
Assume that the code is in a macro workbook "software.xlsm", as is any data that they have entered.
What I have done is to create "software v1.0.1.xlsm". It checks for the presence of "software.xlsm" and copies all the data and parameters from it to itself. It then renames "software.xlsm" as "software v1.0.0.xlsm.old", and saves itself as "software.xlsm". At this point, Excel is quite happy that this is the new name for the workbook.
All that remains is to delete the "updater". But this is where I run into permission errors - Excel won't let me kill it. It is not in use anywhere else, and it seems as if Excel isn't letting go of the original file name.
This is my code:
set newWb = ActiveWorkbook
thisName = newWb.FullName ' get full name of updater
newWb.SaveAs newWb.Path & "\software.xlsm" ' save updater as code file
Kill thisName ' delete updater <!! FAILS
I'm tearing my hair out here. I have checked here an online, and what I am doing should work - but it doesn't!
Thanks.
EDIT: I should mention that I have also tried SetAttr on the file, which also has no effect.
EDIT2: I am not sure I am being clear about what I want to do. I want to get rid of the updater once it has run, so as to not confuse the users. So I used "SaveAs" to save the updater with a new name, which left TWO files on the disk, and ONE file open in Excel. I am then trying to kill / delete the file that IS NO LONGER open in Excel (i.e. the updater before I saved it with a new name).
newWb.Close (you have to close it before you can delete it)
You can also try setting the variable to nothing.
Set newWb = Nothing
The error you are encountering is because you are trying to access the FullName of the workbook which has since changed after the SaveAs. For example. If I have a workbook with the FullName "SomeFilePath.foo" and I do a SaveAs with FullName & ".old" the FullName is now "SomeFilePath.foo.old".
This makes sense, but the part you are getting tripped up on is your thisname variable. For example:
Dim thisName as String
thisName = ActiveWorkbook.FullName
Debug.Print thisName ' E.G "SomeFilePath.Foo"
ActiveWorkbook.SaveAs ActiveWorkbook.FullName & ".old"
Debug.Print thisname ' Still "SomeFilePath.Foo"
The workbook by the old name simply doesn't exist anymore. It has been changed to the new name.
How do we fix this? You could find the new name and still Kill it, but you dont see Kill often for a reason, it is a bad practice.
The ideal would be to properly host, and reference, your workbook. For example:
thisName = thisWorkbook.FullName
thisWorkbook.SaveAs thisWorkbook.FullName & ".old"
thisWorkbook.Close(False)
We are almost there. We are saving the workbook and closing the current workbook, but this isnt actually what we want. What we need instead is:
thisWorkbook.SaveCopyAs thisWorkbook.FullName & ".old"
thisWorkbook.Close(False)
Instead of changing the FilePath of the updating workbook, just make a copy of it. Not only is it cleaner, but it allows us to not have to worry about the funky things that can happen when we mess with a file when it has code currently running.
Note though, you will want to chance the output file path to the path you actually intend. The ".old" is purely for example. Likewise, ThisWorkbook.Close(False) isn't ideal, but if you must close immediately after finishing then this will work best.
TLDR: The permission denied error is caused by referencing a workbook, by name, that no longer exists within the processes.

Extracting certain cells from excel files in a specified directory

I am a VBA novice and I am trying to write a code that will copy the following data from multiple csv files all stored in the same directory.
I need it to open each csv file
Check IF Row 8 in columns H through CA for any cells that have the value ="TotalLMP" (Sample: Cell H8="TotalLMP")
THEN copy the value from both Row 7 and Row 19 of any columns that have that value ="TotalLMP" in Row 8 in two new columns (Sample: SINCE H8="TotalLMP", COPY H7="100" AS COLUMN A, COPY H19 = "26.437" AS COLUMN B)
THEN copy the value from cell $A$9 in a third column (Sample: COPY A9="20100101" AS COLUMN C")
after finishing loop through each csv file close and go to next
Then in the new active worksheet in the blank excel file would store each value as follows:
.......A .............. B ................ C
1 .. 100 .... 26.437 .... 20100101
2 .. 200 .... 26.585 .... 20100101
Let me help you with the CSV looping for now since this is rather hard for a beginner. I'm sure you will figure out how to test for a value in row 8. If not, you can always ask for more help!
In order to do so, you will have to use the Microsoft Scripting Runtime.
I suggest placing all of the csv file you want to open in the same directory, and only those to avoid potential problems.
Open a new workbook and go to the VBE (ALT + F11). Create a new module. Click in this new module, then go to Tools > References> Microsoft Scripting Runtime. This will let it know it will have to use that module and its objects.
Save the workbook as an macro-enabled workbook (.xls or .xslm for newer versions) in the same directory as your CSV (or somewhere else...)
Then start coding:
Sub Import_all_Csv()
' Reference Needed: Microsoft Scripting Runtime
' Dim some pointers to know what objects you will be manipulating thereafter
Dim MyWs, CSV As Worksheet
Set MyWs = ActiveSheet ' Meaning you will have to run the macro from the spreadsheet you want to export to. Feel free to replace that
Dim wbCSV As Workbook
' Those are the objects that belong to the reference Microsoft Scripting Runtime
Dim oFSO As FileSystemObject
Dim oFld As Folder
Dim oFile As File
Dim File As String
' Initialize the FileSystemObject
Set oFSO = New FileSystemObject
' That will only work on windows so I'm adding an error handler to ignore it if need be
On Error Resume Next
ChDir ThisWorkbook.Path
On Error GoTo 0 ' I'm asking VBA to throw an error now
' Dialog box to select the first csv file (this will let you choose another directory everytime)
File = Application.GetOpenFilename("Comma Separated Values File (*.csv*), *.csv*")
If File = "False" Then
Exit Sub ' Quit the macro if user canceled
Else
' Else get the path of the parent folder of that file
Set oFld = oFSO.GetFolder(oFSO.GetParentFolderName(File))
End If
' Go through each file in that folder
For Each oFile In oFld.Files
' Only open the CSV files
If oFile.Type = "Microsoft Excel Comma Separated Values File" Then
' Open it and set the first sheet (There is only one anyway)
Set wbCSV = Workbooks.Open(oFile)
Set CSV = wbCSV.Sheets(1)
' ============================
' Do what you want to do Here
' THIS IS A PLACEHOLDER
' Example to copy value of H8 in the CSV file to A2 the destination worksheet so you can see how to point to the correct cells in both files
MyWs.cells(1,2).value = wCSV.cells(8,8).value
' End of what you want to do
' ============================
' Close the CSV file without savings changes before going through the next one
wbCSV.Close False
End If
Next oFile
End Sub
I hope this helps! Good luck learning more VBA!
Best,
Julien

VBA - Copy as Path

I need help with a coding requirement that I've not previously experienced. I just browsed a similar issue raised here a couple of years ago - VBA to Copy files using complete path and file names listed in Excel Object.
My issue is similar but somewhat simpler than the OP.
I have a number of folders that each contain about 100 small .csv files; for each folder I need to copy the path for each file to an open worksheet. Each folder of .csv files has its own associated workbook.
As one example, the open workbook is F:\SM\M400AD.xlsm and the active worksheet is CSV_List. The folder containing the .csv files is F:\SM\M400AD.
Doing it manually, my sequence is then:
Open folder F:\SM\M400AD
Select all
Copy path
Paste to Range("B11") of worksheet CSV_List
When I do it manually, as described above, I get a list that looks like:
"F:\SM\M400AD\AC1.csv"
"F:\SM\M400AD\AC2.csv"
"F:\SM\M400AD\AE.csv"
"F:\SM\M400AD\AF.csv"
"F:\SM\M400AD\AG.csv"
"F:\SM\M400AD\AH1.csv"
"F:\SM\M400AD\AH2.csv"
"F:\SM\M400AD\AJ.csv"
and on down the page until I have a list of 100 paths. This single column list is then pasted into worksheet CSV_List, starting at Range("B11").
I need to automate this and would be grateful if a VBA guru could kindly code this for me.
Such of question has been asked before, for example:
Loop through files in a folder using VBA?
List files in folder and subfolder with path to .txt file
The difference is you want to "automate" it, which means you want to execute code on workbook Open event.
How to achieve that?
Open F:\SM\M400AD.xlsm file.
Go to Code pane (ALT+F11)
Insert new module and copy below code
Option Explicit
Sub EnumCsVFilesInCurrentFolder()
Dim sPath As String, sFileName As String
Dim i As Integer
sPath = ThisWorkbook.Path & "\"
i = 11
Do
If Len(sFileName) = 0 Then GoTo SkipNext
If LCase(Right(sFileName, 4)) = ".csv" Then
'replcae 1 with proper sheet name!
ThisWorkbook.Worksheets(1).Range("B" & i) = sPath & sFileName
i = i + 1
End If
SkipNext:
sFileName = Dir(sPath)
Loop While sFileName <> ""
End Sub
Now, go to ThisWorkbook module and insert below procedure:
Private Sub Workbook_Open()
EnumCsVFilesInCurrentFolder
End Sub
Save and close workbook
The workbook is ready to use. Whenever you open it, EnumCsVFilesInCurrentFolder macro will be executed.
Note: you have to change above code to restrict the number of records.