How to SaveAs with OneDrive while offline? - excel

I use VBA to create copies (Excel and PDF) of an Excel document.
I save in the OneDrive folder (C:\Users\XXX\OneDrive) so I can access the document from every device later. I use this folder so I can save while I am connected to internet or not.
When I am connected to internet and OneDrive everything works.
When I am not connected to internet I get
error 1004 method saveas of object _workbook failed
My macro stops but when I go to the folder the files are there.
I get the error on:
ActiveWorkbook.SaveAs Filename:=Fname, FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
(Fname="C:\Users\XXX\OneDrive\YYY\ZZZ.xlsm")
I couldn't find anything related to this function not working on OneDrive while not connected to internet.

If your file is in OneDrive, I would first make sure to deactivate the AutoSave feature. I've personally had some bugs with it in the past, so it might help.
I'm not aware of this particular bug that you are experiencing, but since you are saying that the file is actually saved properly even if an error is triggered, there is a way to ignore the error and check if the file was actually saved. It would look a little like this:
Const RETRY_LIMIT = 2
Dim DoesFileExist As Boolean
dim RetryCounter as Integer
Do While RetryCounter < RETRY_LIMIT And DoesFileExist = False
On Error Resume Next
ActiveWorkbook.SaveAs Filename:=Fname, FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
On Error GoTo 0
DoesFileExist = FileExists(Fname)
RetryCounter = RetryCounter + 1
Loop
If DoesFileExist = False Then
MsgBox "Error: File couldn't be saved."
Exit Sub
End If
Note that I've added a retry limit of 2 to make sure that we don't go into an infinite loop.
Also make sure to add the following function in the module you are working on to make sure the code above works.
Function FileExists(ByVal FullFileName As String) As Boolean
If Dir(FullFileName) <> vbNullString Then FileExists = True
End Function
Some explanations and caveats
If you have never used error handling statements such as : On Error Resume Next or On Error GoTo 0, I would strongly advise you to have a look at C. Pearson's Error Handling In VBA article.
To summarize, what On Error Resume Next does is simply ignore the error and let the code handle the error. In our case, the DoesFileExist does the job of making sure that the code ran without error and the if statement after the loop will make sure to stop the code if all tentative to save the file failed. This does the job, but you could also check Err.Number to handle different type of error as well.
Regarding On Error GoTo 0, to put it simply, it resets the VBA error handling to its normal state where any error will launch the usual run-time error dialog box

I ended up saving the file on my desktop and then using FileSystemObject to move the file. It works fine except that if I try to open the file right away (using VBA or directly in windows explorer) I get a network error. If I wait about 1 min I don't get that error anymore. So I decided to live with it for now.
here is an example:
Dim FSO as Object
Set FSO = CreateObject("Scripting.Filesystemobject")
FSO.MoveFile("SourceFileName", "TargetFileName")
Thank you very much for your help

Related

Bypassing/ignoring corrupt Excel files

I have to loop through Excel files stored in a folder and process them using VBA. I want to only process those Excel files that open without any questions being asked (questions like unreadable content, corrupted file, unknown source etc).
Is there some way to do this? I have tried On Error go to Label, but the problem still persists with some files.
That sounds weird. You didn't post any sample code, but you can try it like this.
Sub t()
Application.ErrorCheckingOptions.BackgroundChecking = False
On Error Resume Next
'other code here
On Error GoTo 0
Application.ErrorCheckingOptions.BackgroundChecking = True
End Sub
Normally, 'On Error Resume Next' is not recommended, because it will hide all kinds of errors from your view, which can be quite helpful for debugging issues, but in this case it may be appropriate.

Macro gives error when updating connections - but only sometimes

My macro opens up a couple of files, then updates Connections in one of those files. These connections are all pulls from website html tables. The macro worked just fine for a while. Now, when I run the macro, I get this error:
Run-time error '1004':
Application-defined or object-defined error
When debugging, the error points to the first connection update line of the macro (Advanced2). Here's the code:
Workbooks.Open (ThisWorkbook.Path & "\TheFormulaFinal V5.xlsm")
Workbooks.Open (ThisWorkbook.Path & "\WebScraper.xlsx")
Windows("WebScraper.xlsx").Activate
ActiveWorkbook.Connections("Advanced2").Refresh
ActiveWorkbook.Connections("DVP").Refresh
ActiveWorkbook.Connections("PrSolu").Refresh
ActiveWorkbook.Connections("Misc").Refresh
ActiveWorkbook.Connections("NF Project").Refresh
ActiveWorkbook.Connections("OppTot").Refresh
ActiveWorkbook.Connections("PlrTot2").Refresh
ActiveWorkbook.Connections("TeamTot").Refresh
ActiveWorkbook.Connections("RotoGuru").Refresh
Sheets("PlrTot2").Select
However, the very odd thing is that if I close the two files my code opened (WebScraper and TheFormula V5) without saving, then run the exact same macro, the next time it works! I suspect it has to be some kind of time-related error. I have turned off all background connection refresh as well as any kind of refresh upon file open, so none of these connections should ever update unless they are manually called to do so. I tried using Application Wait to add some time after the WebScraper file opened, and/or after the first refresh, but no avail. I also tried adding some dummy activities after the WebScraper file is activated to see if the file needed some time to load the connections, but also no luck.
Any help is appreciated, thanks!
Workbooks.Open function returns reference to opened workbook. You can use this reference instead ActiveWorkbook.
Dim wb As Workbook
Set wb = Workbooks.Open(ThisWorkbook.Path & "\WebScraper.xlsx")
wb.Connetions("Advanced2").Refresh
...

VBA Excel code stops execution after adding a worksheet

I seem to have stumbled upon a problem I can't seem to figure out how to solve. I'm currently working with 2 separate workbooks, one of them is the active workbook the code is run from, the other one is a separate workbook I need to open:
On Error GoTo ErrorHandler:
Set manWb = ActiveWorkbook
Application.AutomationSecurity = msoAutomationSecurityForceDisable
Set conWb = Workbooks.Open(PARDirOTC & PARFileOTC, ReadOnly:=False)
Application.AutomationSecurity = msoAutomationSecurityByUI
ActiveWindow.Visible = False
On Error GoTo 0
I set the AutomationSecurity to msoAutomationSecurityForceDisable to prevent that second workbook from running its Workbook_Open event, which has code in it I don't need in this situation. That error handling event never seems to activate, and the code keeps going without issues.
Everything works nicely from this point on, I gather and exchange data between these 2 workbooks and nothing seems to go wrong. That is, until it gets to the point where I need to create a worksheet on the second workbook, the one called "conWb".
Set conOT = conWb.Sheets.Add(After:=conWb.Sheets(conWb.Sheets.Count))
This is the troubling line. The worksheet is created, but the code suddenly stops executing at this point. No error message at all, nothing pops up, it simply stops. I've noticed that the code apparently stops executing, and switches to the code in the newly created sheet, which is blank and has nothing in it. I can't understand why.
I've looked around, other people seem to have found similar issues, but none of their solutions worked for me. I've tried playing around with several Application settings, like EnableEvents, ScreenUpdating, AutomationSecurity, etc, but nothing works. Along the code, I've also tried to remove or comment out all of the "On Error" events, fearing that they could be hiding an error that could explain this behaviour, but it doesn't seem to be the case.
I'll highly appreciate if someone with more experience than me could help figure out what could be the reason for this behaviour. Thanks in advance.
Kind regards
Using Application.EnableEvents instead of Application.AutomationSecurity when opening the second workbook, like one of you suggested, ended up solving the entire issue. Like so:
On Error GoTo ErrorHandler:
Set manWb = ActiveWorkbook
Application.EnableEvents = False
Set conWb = Workbooks.Open(PARDirOTC & PARFileOTC, ReadOnly:=False)
Application.EnableEvents = True
ActiveWindow.Visible = False
On Error GoTo 0
As far as I know, AutomationSecurity can be used to disable all macros when opening a workbook programatically, and I thought that would be enough to prevent the Workbook_Open event, but I'm assuming that either there's some other event I wasn't aware of, or the AutomationSecurity setting works in a different way than what I initially thought.
Either way, the problem seems to be solved, so thank you.
Kind regards

VBA Error 1004 - ChangeFileAccess Method Failed - File on Sharepoint

I'm fixing some code written by a colleague and I've come across this hurdle where an Excel document is opened from a Sharepoint and the ChangeFileAccess method is run to change it to Read/Write. The method fails with error code 1004. The file opens so everything up to that point is working.
I can't see why it won't work, I'm hoping someone more knowledgeable than I can!
I've removed the file path and document name for the sake of anonymity.
I'm using Office 365, code in question below:
Dim ObjFileA, ObjfileB As File
FilePathA = "filepath" & fileName
Set FSO = CreateObject("Scripting.FileSystemObject")
Set App = CreateObject("Excel.Application")
Set ObjFileA = FSO.GetFile(FilePathA)
Set wbA = Workbooks.Open(ObjFileA, False, False)
wbA.Activate
wbA.ChangeFileAccess (xlReadWrite)
Set wbA = Workbooks(fileName)
Is your file already being opened as Read-Write?
I just encountered a similar problem to what you describe (Err 1004 when changing the access method, though in my case I was attempting to change the access to Read-Only on a file that was already Read-Only.)
After some testing, I get the error every time if I try to invoke wkbk.ChangeFileAccess to "change" the access type to be the same as the current access type.
If you find that the workbook might already be Read-Write, then I suggest a change to :
If wbA.ReadOnly then wbA.ChangeFileAccess (xlReadWrite)

Outlook 2010 - strange item.Attachments error

I have the following code, that should save a specific Excel file attached to an email. The code is combined with a rule, that trigger this script when an emai lwith a specific subject is received.
The code is triggered, but here comes the strangest error I saw lately: itm.Attachments.Count appear to be zero and obviously the file is not saved! But... if I put a breakpoint on "For each..." line and add itm.Attachments.Count to watch window, it is shown as zero. If I add itm only, then browse to Attachments property, then to Count property it shows 1 for Count (as it should) and the code is executed fine. I spent half a day trying to understand what's going on, but I can't figure it out.
The behaviour is the same both on a Outlook 2010 x64 on a Windows 7 x64 and on a Outlook 2010 x86 on a Windows 7 x86. Macros are enabled in Trust Center. I have attached some screenshot with the code and rule settings and also a movie showing the watch windows strangeness.
The script was built some time ago and it worked well on a couple of PCs and it was based on the steps from here: iterrors.com/outlook-automatically-save-an-outlook-attachment-to-disk/.
Any ideas?
Rule screen here
1 min. movie here
Public Sub Kona(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
saveFolder = "C:\test"
For Each objAtt In itm.Attachments
If InStr(objAtt.DisplayName, "Kona Preferred Fixed Price Matrix (ALL)") Then
objAtt.SaveAsFile saveFolder & "\" & objAtt.DisplayName
End If
Set objAtt = Nothing
Next
End Sub
In case if you have an IMAP account configured in Outlook: your Offline Settings might be set to only store up to 1 month, 3 months, 12 month worth of emails on your local disk.
If you’ve got enough space on your disk and want to cache more emails locally, you can set the sync slider in the following way:
File-> Account Settings-> Account Settings…-> double click on your IMAP account.
Try to increase the offline storage in Outlook. See Empty Inbox and other IMAP synching issues in Outlook 2013 for more information.
My best understanding of this behavior is that Microsoft Outlook (at least the versions of 2010 that I tested) has a bug. There may be other factors that I'm not aware of contributing to this, but I was able to reproduce the error using different service pack levels / builds of Outlook 2010 on Windows Vista. Office 2013 does not appear to be affected.
I managed to create a workaround.
I found that by displaying the message while stepping through the code in debug mode using
objMailItem.GetInspector.Activate
the number of attachments was subsequently correctly detected (without having to do strange things like setting up a watch for the object variable and then clicking on it in the IDE).
However, this only worked while stepping through the code, not during normal execution.
For this reason, I suspected the message might not be displaying long enough during normal code execution for Outlook to get the twist out of its knickers. I reasoned that it might be possible to insert a delay to allow sufficient time for this.
I tried out several methods of inserting a delay. Here is the one that worked for me. I created a form called
frmTimer
and added the freeware RSTimer OCX control (http://www.softpedia.com/get/Programming/Components-Libraries/RS-Timer.shtml) to it.
I set the
Interval
property of the OCX to 1000 ms.
The form is loaded right after displaying the message like this:
objMailItem.GetInspector.Activate
frmTimer.Show ' <-- form is loaded and displayed (it is not sufficient to just 'load' it)
objMailItem.Close OlInspectorClose.olDiscard
The form has one single event handler:
Private Sub RSTimer1_Timer()
Unload frmTimer
End Sub
When the event fires, the form is unloaded and code execution continues with
objMailItem.GetInspector.Activate
frmTimer.Show
objMailItem.Close OlInspectorClose.olDiscard ' <-- code execution continues here
Here is a complete function that allows the attachment to be detected correctly.
Function EmailHasAttachments(ByVal objMailItem As Outlook.MailItem) As Boolean
On Error GoTo ErrHandler
objMailItem.GetInspector.Activate
frmTimer.Show
objMailItem.Close OlInspectorClose.olDiscard
If objMailItem.Attachments.Count > 0 Then
EmailHasAttachments = True
Else
EmailHasAttachments = False
End If
ExitHere:
Exit Function
ErrHandler:
Debug.Print Err.Number, Err.Description
Select Case Err.Number
Case 12345
' handle the error
Case Else
MsgBox "An unknown error has occurred."
Exit Function
End Select
End Function

Resources