What I have is a macro that is designed to open other workbooks and refresh the contents within those workbooks. All of these work except one of them is intermittent, and by that I mean most times it works exactly as required, but randomly it will bring up an error stating the macro cannot be found. I haven't found so far a point which I can pinpoint where it does this so it has been difficult to debug.
below is the code:
Call Shell("K:\ASA_Reporting\Audits\MDA\ListCompletedAudits.bat")
' This wait has been added to allow the command to run in Console
Application.Wait (Now() + TimeValue("00:00:10"))
ThisWorkbook.Worksheets("Bits n Pieces").Range("G14").Value = "True"
Dim wb1 As Workbook
'This is to update the 5S Audit Dashboard
Set wb1 = Workbooks.Open("K:\ASA_Reporting\Audits\Audit Dashboard v002.xlsb", True, False, , , "password")
Application.Run "'Audit Dashboard v002.xlsb'!Refresh5S"
wb1.Close savechanges:=True
Stop
The point which has a commented out section "This is to update the 5S Audit Dashboard" is the code which is where the issue is occurring. The section above that in regards to the waiting 10 seconds is to correct a different issue which is unrelated to the 5S.
I know that the Macro is correct as it works on the 5S workbook, and it does work most times through my updater, but as I've said on occasion is brings up an error stating the macro does not exist.
I have checked the code what is being called (shown below) but I cannot any errors in this.
Sub Refresh5S()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim datasheet As Worksheet
Set datasheet = ThisWorkbook.Worksheets("Data Sheet")
Dim wb As Workbook
Dim ws As Worksheet
Set wb=Workbooks.Open("\\bosch.com\dfsrb\dfsuk\loc\wo\dept\service\ASA_Reporting\Audits
\5S Audit Master v2.xlsx", True, True)
Set ws = wb.Worksheets("Counts")
datasheet.Range("W6:Z21").Value = ws.Range("B5:E20").Value
datasheet.Range("AB6:AC400").Value = ws.Range("H5:I399").Value
datasheet.Range("AD6:AG400").Value = ws.Range("K5:N399").Value
datasheet.Range("AH6:AH400").Value = ws.Range("O5:O399").Value
wb.Close False
MsgBox "Thank you for your patience." & vbNewLine & vbNewLine & "The figures
should update in a few seconds.", vbInformation
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I thought I had found the answer on a Microsoft help page titled "Macro in Excel Stops After A Workbook.Open Command" However that was for when you press the shift key, and that is not happening in this instance, it is being left to it's on devices.
https://support.microsoft.com/en-us/help/555263
Does anyone have any idea why it randomly decides the Macro in the 5S workbook doesn't exist?
Edit:
Tried the below and it worked for the day without issue, then today the problem came back with the following error:
The code has not been changed except for the suggestions below, which worked for a day.
The issue was in the end with Excel, as the latest updates of Office have now resolved this issue.
Related
I will try to be as clear as possible in the description, so here goes nothing:
I have created a code in which the user selects his excel file and then the macro copies the Sheet from that file into my macro Workbook.
MyFile = Application.GetOpenFilename()
Workbooks.Open (MyFile)
ActiveSheet.Copy After:=wbook.Sheets(1)
ActiveSheet.Name = "Selected file"
Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False
This is working, but what I realized is, that there might be cases where the selected file has multiple Sheets.
Is there a way to write the macro in which if my selected file has 1 sheet it runs the above code and if it has more than one sheet to let me select the sheet I want and then run the rest of the code?
Edit:
I thought of another way to handle this — perhaps closer to what you were looking for . . .
It's just an expansion of the basic pause routine that I use occasionally.
This is my "regular" Pause routine (using the Timer function):
Sub Pause(seconds As Single)
Dim startTime As Single
startTime = Timer 'get current timer count
Do
DoEvents 'let Windows "catch up"
Loop Until Timer > startTime + seconds 'repeat until time's up
End Sub
...so, it gave me an idea.
Honestly, I was a little surprised to discover that this works, since it's basically running two sections of code simultaneously.
Code for WaitForUserActivity :
Here's the code I used in the demo above:
Option Explicit
Public isPaused As Boolean
Sub WaitForUserActivity() 'THE 'RUN DEMO' BUTTON runs this sub.
Dim origSheet As String
isPaused = True 'flag "pause mode" as "on"
origSheet = ActiveSheet.Name 'remember current worksheet name
MsgBox "This will 'pause' code execution until you" & vbLf & _
"click the 'Continue' button, or select a different a worksheet."
Application.StatusBar = "PAUSED: Click ""Continue"", or select a worksheet."
Do 'wait for button click or ws change
DoEvents 'yield execution so that the OS can process other events
Loop Until (Not isPaused) Or (ActiveSheet.Name <> origSheet)
If isPaused Then 'the active worksheet was changed
MsgBox "Worksheet '" & ActiveSheet.Name & "' was selected." _
& vbLf & vbLf & "Now the program can continue..."
Else 'the button was clicked
MsgBox "The 'Continue' button was clicked." _
& vbLf & vbLf & "Now the program can continue..."
End If
Application.StatusBar = "Ready"
End Sub
Sub btnContinue() 'THE 'CONTINUE' BUTTON runs this sub.
isPaused = False 'flag "pause mode" as "off"
End Sub
To run the demo:
place the above code in a regular module
make sure the workbook has at least two worksheets
create two command buttons:
one for the "Run Demo" button, assign macro: WaitForUserActivity
one for the "Continue" button, assign macro: btnContinue
click the "Run Demo" button
The key command in the code is the DoEvents Function, which "yields execution so that the operating system can process other events."
DoEvents passes control to the operating system. Control is returned after the operating system has finished processing the events in its queue and all keys in the SendKeys queue have been sent.
DoEvents is most useful for simple things like allowing a user to cancel a process after it has started, for example a search for a file. For long-running processes, yielding the processor is better accomplished by using a Timer or delegating the task to an ActiveX EXE component - and the operating system takes care of multitasking and time slicing.
Any time you temporarily yield the processor within an event procedure, make sure the procedure is not executed again from a different part of your code before the first call returns; this could cause unpredictable results.
Further details (and warnings) at the source.
Original Answer:
Some suggested solutions:
Instead of "stopping" the code you could prompt the user to specify which worksheet.
The easiest way would be with an InputBox where the user would enter an ID number or otherwise identify the worksheet.
More complicated but more robust and professional-looking would be a custom dialog box with the help of a userform. There are several examples and tutorials online such as this one.
You could "pause" execution to give the user a set amount of time to select a worksheet, with a simple timer loop, ad you could even check the worksheet name to see if the user picked a new one, something like this:
Dim startTime As Single, shtName As String
If ThisWorkbook.Worksheets.Count = 1 Then
MsgBox "There is only one worksheet in this workbook."
Else
shtName = ActiveSheet.Name 'get name of active sheet
MsgBox "You have 5 seconds to select a worksheet after clicking OK.", _
vbOKOnly + vbInformation, "Select a worksheet... fast!"
startTime = Timer
Do
DoEvents
Loop Until Timer > startTime + 5
'check if user picked a new worksheet
If ActiveSheet.Name = shtName Then
MsgBox "You didn't select a new worksheet!"
Else
MsgBox "Thanks for selecting a new worksheet!"
End If
End If
It's a little hoakey but could work, especially if proper checks to make sure you've got the correct worksheet now.
I suppose you could create an worksheet event procedure that would run when a worksheet is activated, and checked a global variable to see if your "import procedure" was running, and if so, resume your code... but that would be messy and confusing and would require the code to exist in the workbook you're "importing".
Or, better than any of those would be to programmatically/logically determine which worksheet you need based on the contents of the worksheet. Is there a title? A certain date? Maybe the newest worksheet? Something in a certain cell? There must be something that differentiates it from the others.
Hopefully this gives you some ideas towards a non-linear solution. 😉
As in whole, I would recommend ashleedawg's solution, but if you
insisted on maintaining your code structure, your code could look
something like this:
You can distinguish between amount of Sheets a Workbook has using .Count property of the Sheets object (or Worksheets if you do not want to include Charts) and use InputBox to check for the sheet you want to look for.
MyFile = Application.GetOpenFilename()
Workbooks.Open (MyFile)
If ThisWorkbook.Sheets.Count = 1 Then
ThisWorkbook.ActiveSheet.Copy After:=wbook.Sheets(1)
ThisWorkbook.ActiveSheet.Name = "Selected File"
Else
Dim checkfor As String
checkfor = InputBox("What Sheet should I execute the code for?")
Dim i As Integer
For i = 0 To ThisWorkbook.Sheets.Count
If Trim(LCase(checkfor)) = Trim(LCase(Sheets(i).Name))) Then
ThisWorkbook.Sheets(i).Copy After := wbook.Sheets(1)
ThisWorkbook.Sheets(i).Name = "Selected file"
End If
Next i
End If
Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False
Might need some further tweaking, because I was unsure what exactly you wanted to achieve.
I know I've seen references to this issue before, but I have tried several of the suggestions and I am still getting the error. I have a workbook that assembles data from another book and generates a report. I then want to make a new workbook, copy the report information into the new book, save the new book and close it, and then move on to the next report. It should do this around 10 times. In the part of my code where I am copying and pasting the sheets, I am getting an error
Error -2147417848 Automation error The object invoked has
disconnected from its clients
I have checked other postings about this error, and tried the suggested solutions without any results. the interesting thing is that sometimes it will make it through 5 cycles of code before breaking, sometimes only 2. The only consistency is that it always breaks in the same place
fromBook.Sheets("Report").Copy Before:=newBook.Sheets("Sheet1")
I have option Explicit at the top of the module, and I have checked to make sure that there are not any globals inside of the sub it is breaking in. That being said, It's entirely possible I have overlooked something. I also put a "timer" in at one point to make sure that the excel sheets were not walking over each other.
I could really use the help!
Here is my sub's code:
Sub CreateAndSave(ByRef Reg As Integer, ByVal j As Integer)
Dim fromBook As Workbook
Dim fromSheet As Worksheet
Dim newBook As Workbook
Dim fileExists As Boolean
Dim i As Integer
Dim Holder As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set fromBook = Application.Workbooks("Region_Audit_Report")
Set newBook = Workbooks.Add
With newBook
.SaveAs Filename:="G:\DataTeam\ExcelDev\Audit Report\Region Workbooks\Region" & Reg & " " & Month(Date) & "-" & Day(Date) & "-" & Year(Date) & ".xlsx" _
, FileFormat:=xlOpenXMLWorkbook
End With
Set newBook = Application.Workbooks("Region" & Reg & " " & Month(Date) & "-" & Day(Date) & "-" & Year(Date) & ".xlsx")
fromBook.Sheets("Report").Copy Before:=newBook.Sheets("Sheet1")
fromBook.Sheets("MonthData").Copy After:=newBook.Sheets("Report")
newBook.Sheets("MonthData").Range("A1") = "Month"
newBook.Sheets("MonthData").Range("B1") = "Store#"
newBook.Sheets("MonthData").Range("C1") = "District"
newBook.Sheets("MonthData").Range("D1") = "Region"
newBook.Sheets("MonthData").Range("E1") = "Due Date"
newBook.Sheets("MonthData").Range("F1") = "Comp Date"
newBook.Sheets("MonthData").Range("G1") = "# of Errors"
newBook.Sheets("MonthData").Range("H1") = "Late?"
newBook.Sheets("MonthData").Range("I1") = "Complete?"
newBook.Sheets("MonthData").Range("A1:I1").Interior.ColorIndex = 43
newBook.Save
newBook.Close
Application.DisplayAlerts = True
End Sub
I have had this problem on multiple projects converting Excel 2000 to 2010. Here is what I found which seems to be working. I made two changes, but not sure which caused the success:
1) I changed how I closed and saved the file (from close & save = true to save as the same file name and close the file:
...
Dim oFile As Object ' File being processed
...
[Where the error happens - where aArray(i) is just the name of an Excel.xlsb file]
Set oFile = GetObject(aArray(i))
...
'oFile.Close SaveChanges:=True - OLD CODE WHICH ERROR'D
'New Code
oFile.SaveAs Filename:=oFile.Name
oFile.Close SaveChanges:=False
2) I went back and looked for all of the .range in the code and made sure it was the full construct..
Application.Workbooks("workbook name").Worksheets("worksheet name").Range("G19").Value
or (not 100% sure if this is correct syntax, but this is the 'effort' i made)
ActiveSheet.Range("A1").Select
I have just met this problem today: I migrated my Excel project from Office 2007 to 2010. At a certain point, when my macro tried to Insert a new line (e.g. Range("5:5").Insert ), the same error message came. It happens only when previously another sheet has been edited (my macro switches to another sheet).
Thanks to Google, and your discussion, I found the following solution (based on the answer given by "red" at answered Jul 30 '13 at 0:27): after switching to the sheet a Cell has to be edited before inserting a new row. I have added the following code:
'=== Excel bugfix workaround - 2014.08.17
Range("B1").Activate
vCellValue = Range("B1").Value
Range("B1").ClearContents
Range("B1").Value = vCellValue
"B1" can be replaced by any cell on the sheet.
You must have used the object, released it ("disconnect"), and used it again. Release object only after you're finished with it, or when calling Form_Closing.
I had this same problem in a large Excel 2000 spreadsheet with hundreds of lines of code. My solution was to make the Worksheet active at the beginning of the Class. I.E. ThisWorkbook.Worksheets("WorkSheetName").Activate
This was finally discovered when I noticed that if "WorkSheetName" was active when starting the operation (the code) the error didn't occur. Drove me crazy for quite awhile.
Couple of things to try...
Comment out the second "Set NewBook" line of code...
You already have an object reference to the workbook.
Do your SaveAs after copying the sheets.
The error in the below line of code (as mentioned by the requestor-William) is due to the following reason:
fromBook.Sheets("Report").Copy Before:=newBook.Sheets("Sheet1")
The destination sheet you are trying to copy to is closed. (Here newbook.Sheets("Sheet1")).
Add the below statement just before copying to destination.
Application.Workbooks.Open ("YOUR SHEET NAME")
This will solve the problem!!
I have a workbook that contains a Macro that checks the workbook out from our SharePoint server, updates it, and then should check it back in. Afterwards, it should remain open for the user review and possibly execute other updates. The main problem I have is that the ".checkin" method closes out the Workbook, terminating the macro before it can re-open the workbook. I had found a proposed solution here: https://stackoverflow.com/a/22380886/8858822 , however I have encountered a problem with how Application.OnTime operates.
If I attempt to use the Application.Workbook.Open procedure as an argument for the Application.OnTime method, as suggested by the link above, the .Open procedure gets called immediately, without waiting the desired delay. In this scenario, the workbook has not been checked-in and closed yet, causing an error:
Sub TestSub()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim FPath As String
FPath = wb.FullName
Workbooks.CheckOut (FPath)
'''''''''''''''''''''''''
'execute workbook updates
'''''''''''''''''''''''''
Application.DisplayAlerts = False
On Error Resume Next
Application.OnTime Now + TimeValue("00:00:10"), Application.Workbooks.Open(FPath)
wb.CheckIn
Application.DisplayAlerts = True
End Sub
Is there a reason that Application.Workbooks.Open(FPath) executes immediately, instead of waiting the specified 10 seconds? If I can delay that execution by 10 seconds, the code would execute correctly.
I noticed that if instead of directly opening the file, I call one the macros in the file, it does wait the desired 10 seconds. This allows for the file to first be checked in and closed, then re-opens it and executes the specified macro.
Sub TestSub()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim FPath As String
FPath = wb.FullName
Workbooks.CheckOut (FPath)
'''''''''''''''''''''''''
'execute workbook updates
'''''''''''''''''''''''''
Application.DisplayAlerts = False
On Error Resume Next
Application.OnTime Now + TimeValue("00:00:10"), " ' file address & name '!OtherMacroName "
wb.CheckIn
Application.DisplayAlerts = True
End Sub
With this code, the file is checked in, closes, and then after 10 seconds reopens the file and runs the macro. Unfortunately, due to trust center settings I believe, I cannot directly call macros from workbooks saved on our SharePoint server, and this code generates an permissions error. If I relocate the file to my personal or our network drive, it executes without error. I have not been able to resolve the SharePoint permissions issue, even after following: https://stackoverflow.com/a/21175812/8858822 .
If I can understand why the Application.Workbooks.Open procedure operates immediately, while the macro call procedure waits the desired 10 seconds, when each is an argument used by Application.OnTime, I believe the code would work as desired. If there is a way to call the macro within the closed workbook after 10 seconds, I presume there must be some way of just opening the workbook after the 10 seconds? Thank you for your time and assistance.
OnTime takes the name of a subroutine as its argument. You need to create a new routine for OnTime to call (it doesn't actually have to do anything if all you need is the workbook reopened).
Is there a reason that Application.Workbooks.Open(FPath) executes
immediately, instead of waiting the specified 10 seconds? If I can
delay that execution by 10 seconds, the code would execute correctly.
Yes. The answer you linked is incorrect.
Application.OnTime Now + TimeValue("00:00:10"), SecondArgument
The SecondArgument is the name of a subroutine to call.
What you're doing when you put Application.Workbooks.Open(FPath) in SecondArgument is opening the workbook, then returning a reference to the workbook, in the same way you would go:
Set wb = Application.Workbooks.Open(FPath)
Put differently, when you do this...
Application.OnTime Now + TimeValue("00:00:10"), Application.Workbooks.Open(FPath)
... you're actually doing this:
Set wb = Application.Workbooks.Open(FPath)
Application.OnTime Now + TimeValue("00:00:10"), wb
So that answers your question, but to solve your problem...
From this link, there's some sort of dirty workaround where the key is apparently to call the Application.OnTime method a moment before you close the workbook (check in the workbook in your case):
Sub CloseMe()
Application.OnTime Now + TimeValue("00:00:02"), "OpenMe"
ThisWorkbook.Close ' check in
End Sub
Sub OpenMe()
' literally does nothing
End Sub
So Excel knows to run the OpenMe method in 2 seconds' time, and it is that act of attempting to run the OpenMe method that actually re-opens the workbook.
You can test this by having two workbooks:
E:\Documents\Book3.xlsm has the following code:
Sub TestMe()
MsgBox "test"
End Sub
E:\Documents\Book2.xlsm has the following code:
Sub OpenAnotherWorkbook()
Application.Run "'E:\Documents\Book3.xlsm'!TestMe"
End Sub
Making sure that E:\Documents\Book3.xlsm is currently closed, we run OpenAnotherWorkbook from E:\Documents\Book2.xlsm.
It will open E:\Documents\Book3.xlsm and run TestMe.
I'm working on a protected Excel workbook and am trying to eliminate or understand why the follow message occurs AFTER my .MsgBox popup:
The cell or chart you're trying to change is on a protected sheet. To
make changes, click Unprotect Sheet in the Review tab (you might need
a password).
I only have one input field in the workbook (date field), and I've set that cell style to "Input", as well as modified the cell format to "unprotected" so it stays editable even if the workbook is locked.
My VBA/Macro:
Sub WeeklyReport()
Dim Week As String
Set WeekValue = ThisWorkbook.Sheets("Report_Weekly").Range("PRM_weekvalue")
Week = WeekValue
Application.ScreenUpdating = False
Call unprotectmacro
With ActiveWorkbook.Connections("SQLDBConnection").OLEDBConnection
.CommandText = "EXEC dbo.usp_WeeklyReport '" & Week & "'"
ActiveWorkbook.Connections("SQLDBConnection").Refresh
Sheets("Report_Weekly").Select
Range("A13").Select
MsgBox "The workbook is now refreshed."
End With
ActiveSheet.Protect "passwordgoeshere", DrawingObjects:=True, Contents:=True, Scenarios:=True
ActiveWorkbook.Protect "passwordgoeshere", Structure:=True, Windows:=False
'Application.ScreenUpdating = True
End Sub
I would like this message not to appear to my end users, but I don't understand why it is occurring. My only thought is the table isn't done being refreshed after the protect sheet is turned back on. If that is the case, is there a way to wait for the background query to finish running before protecting the sheet again?
To resolve my issue, I went into the Data tab and unchecked "Enable background refresh". I believe this only resolves my issue because I am using an OLEDB connection type.
I have the following issue:
I have a macro script for excel which is running through more then 300 excel workbooks,with several sheets.
The problem is that some of this sheets have faulty hyperlinks and each time I run the macro,the pop-up message informing me that the hyperlink found in the sheet is not working and I have to click each time , : ,,cancel'' . Is there a way (code) that I can write that will automatically ,,cancel'' the pop up question ,if it appears?
You should be able to bypass this by wrapping your code in:
Application.DisplayAlerts = False
-- your code --
Application.DisplayAlerts = True
Maybe the privacy options are related?
http://office.microsoft.com/en-001/excel-help/enable-or-disable-security-alerts-about-links-to-and-files-from-suspicious-web-sites-HA010039898.aspx
Let's say your hyperlinks were pointing to a worksheet's cells, and that worksheet may no longer exist, the best thing to do may be to simply remove those hyperlinks.
This is how you'd do this :
Sub RemoveDeadHyperlinks()
For Each hyperL In ActiveSheet.Hyperlinks
'Extract name of the sheet from the subaddress
toSheet = Left(hyperL.SubAddress, InStr(hyperL.SubAddress, "!") - 1)
If WorksheetExists(toSheet) Then
'Most likely a valid hyperlink!
Else
'Most likely a dead one!
hyperL.Delete
End If
Next
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String) As Boolean
On Error Resume Next
WorksheetExists = (Sheets(WorksheetName).Name <> "")
On Error GoTo 0
End Function