Access VBA: SUB designed to refresh an Excel Spreadsheet giving an error - vba

Relative VBA newbie here. I created a new Module "QCDataRefresh" with a Public Sub "RefreshExcel" that is designed to open an Excel spreadsheet (housed on my network drive) in the background and refresh it. This is done in order to refresh the many data links contained within said spreadsheet.
Here is the code for this Sub:
Public Sub RefreshExcel()
Dim appExcel As Object
Set appExcel = CreateObject("Excel.Application")
appExcel.workbooks.Open ("\\renssfile2\shares\Supply Chain Project Management\QCData.xlsx")
appExcel.activeworkbook.refreshall
Set appExcel = Nothing
End Function
Running this gives a run-time error '1004': "Application Defined or object-defined error. Debugging seems to highlight the line of code "appExcel.activeworkbook.refreshall". Not sure why though?
Additionally, I am also attempting to create a button in Access to run this from my dashboard. To do this, I created a new button, and created a new Event Procedure for this entitled, "Command101_Click".
The following is the code for that Event, which attempts to run my RefreshExcel Sub upon clicking the button:
Private Sub Command101_Click()
QCDataRefresh.RefreshExcel
End Sub
When I run this Event, I would expect it to give me the same error from my refresh Function above. However, instead it opens a window asking me to select a Macro. I'm unsure what my mistake is here, but I'm sure that it must be a simple oversight. Thoughts on this as well?
Thanks all!

I think the problem is that the workbooks.open method returns a workbook.
Try this:
Public Sub RefreshExcel()
Dim appExcel As Object
Dim excelwb As Excel.Workbook
Set appExcel = CreateObject("Excel.Application")
Set excelwb = appExcel.workbooks.Open ("\\renssfile2\shares\Supply Chain Project Management\QCData.xlsx")
excelwb.refreshall
Set excelwb = Nothing
Set appExcel = Nothing
End Sub

Whenever I have unexpected and unusual issue\error for using excel to output to or read from I allways try the following, especially when the code breaks in the middle and doesn't get to the line where you close the spreadsheet and close the Excel object from memory.
So close your spreadsheet and any Excel instances and objects you may have as follow:
Close all Excel files and excel program if you have any open
Go to the Task Manager (by doing Alt+Ctrl+Del) then select Task Manager
Go to processes tab
Sort by process name
Look for any Excel.exe in the list and force close them all one by one
Let us know.

Related

Is it possible to run a VBA macro in a READ-ONLY protected PowerPoint?

My colleague and I have been on a six month quest for a VBA macro that can run in a Read-Only, password protected PowerPoint.
Is it possible or will PowerPoint always block the VBA macro from running in the presentation, because of the read-only status?
Private Sub CheckBox1_Click()
Dim ppShp As Shape
Dim eff1 As Effect
Dim ani1 As AnimationBehavior
With ActivePresentation.Slides(1)
Set ppShp = .Shapes("Oval 4")
Set eff1 = .TimeLine.MainSequence.AddEffect(Shape:=ppShp, effectId:=msoAnimEffectAppear)
End With
End Sub
I tried using If ReadOnly = True Then conditions.
I want the user to use the macros and save, but not edit beyond that, or to open and 'look under the hood'.
(It's all for an educational program)
We get
Run-time error '-2147467259 (80004005)'
Presentation (unknown member) : Invalid request. Presentation cannot be modified.
Perhaps as a work around you could save a copy of the original read only presentation, run your macro on the new version and then save the new version as read only?
Hello this might be too late but if I understand you correctly, you want that other users can read, execute macros but not able to read the code behind it. Saving should be okay.
The macro that you used should be password protected. First go to the editor, select the macro and view the properties/protection and set up a password
Then after you are done, close the file. Right Click on the file/properties and check readonly. Users will then have access to the macro, not being able to see what code is behind it and can save it.

VBScript/VBA quitting an Excel application is affected by standard Excel events

I use Task Scheduler to manage a VBScript which starts a vba sub procedure in Workbook X. This procedure opens two other Workbooks and move data to Workbook X and closes them again. The procedure outcome is an updated Workbook X which I need to save. The VBA procedure works fine and is triggered by the VBScript as expected. However, the part of the VBScript which should save the file doesn't work. The VBScript is based on code I have found on Stackoverflow.com and other sites.
When I open the file X I tried to save with the VBScript, It asks me to decide whether I want to save the file. If I do, I can see the data the above procedure has created has worked.
I can see in the Task Manager that the Excel instance I have created with the VBScript is never closed although I tried to do it in the VBScript. I have also tried the Save method, but with no luck. I have tried different parameters for the methods with no luck. I have search on this site and other sites for how the issue could be solved. However, they suggest Save and SaveAs methods and I tried them with the different suggested parameter configurations without success.
I have now found the root cause but not the solution. It has nothing to do with the script itself. In the open workbook event.
I have code which activate a userform (StartUpForm.Show). In the workbook before close and open events I call procedure RemoveFilter which remove a filter on a set of filtered data. If I mark UserForm.Show and the RemoveFilter in the before close workbook event as notation it works. It is not enough to avoid call StartUpForm.Show. StartUpForm.Show needs to be marked as notation or deleted. How can that be? And is there a workaround?
This doesn't work:
Private Sub Workbook_Open()
Dim batRun As Boolean
RemoveFilter
ResolveStartUp (batRun)
If Not batRun Then
StartUpForm.Show vbModal
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
RemoveFilter
End Sub
This works:
Private Sub Workbook_Open()
Dim batRun As Boolean
RemoveFilter
ResolveStartUp (batRun)
If Not batRun Then
' StartUpForm.Show vbModal
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
' RemoveFilter
End Sub
VBScript:
On Error Resume Next
ImportAccesFilesToHolidaysAndWorkshops
Sub ImportAccesFilesToHolidaysAndWorkshops()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
xlApp.DisplayAlerts = False
Set xlBook = xlApp.Workbooks.Open ("Z:\ResourceManagement\Holiday and workshops input.xlsm", 0, False,,,,,,,,True)
xlApp.Run "ImportResourcesAndProjects"
xlApp.ActiveWorkbook.Close
xlBook.SaveAs "Z:\ResourceManagement\Holiday and workshops input.xlsm",,,,,,xlExclusive, xlLocalSessionChanges
xlBook.Close
Set xlBook = Nothing
xlApp.Quit
Set xlApp = Nothing
WScript.Echo "Finished."
WScript.Quit
End Sub
Try saving to your C: drive. If that works you are probably running into a scheduled task problem. If the task runs whether or not a user is logged in or it is set to use highest privileges, you aren't running under the security context you think you are. In either of those cases job scheduler will use S4U authentication which will prevent you from accessing network resources. I'm guessing that Z: drive is a mapped network drive. Mapped drives belong to the user who mapped the drive so it won't be available unless you are running as the user that mapped the drive and that user is logged in.
If you use "run with highest privileges", you are actually running under the built in Administrator account. That is a separate account and it won't have your drive mappings.
Task Security Context
Some Programs Cannot Access Network Locations When UAC Is Enabled
windows 7 scheduled tasks run with highest privileges

How To Call a Subroutine From Another Object

I am not entirely sure if this is possible, but assuming with us being able to set object references I don't see why not.
To start off, the object that contains the subroutine in question is Excel itself. I am wanting to call one of Excel's VBA subroutines using a different program's VB6 script editor.
I have tried the following without success, but hopefully you can see what I am trying to accomplish here:
Sub Excel_Test()
Dim appXL As Object
Set appXL = GetObject(, "Excel.Application")
Call appXL.Project1.Module1.Test()
End Sub
Obviously this code is not working - but what would be the proper Syntax (if one exists) to call the Macro Test, located in Module1 contained in Excel's object?
You can automate other instances of excel if you identify them by some criteria like the workbook name,
try like
Code:
set otherinstance = getobject(,"fullpath\filename.xls")
otherinstance.application.run "macroname"

Export data from excel to word using VBA

I want to export data from a spreadsheet such as name, date of birth, address etc to a letter that I'm writing in word.
I've been following this tutorial:
I've had success in populating the information in word using a command button, but i don't want the ugly grey button in word so i tried making a macro and pasted the same script into a macro vba.
here is the script I'm using when trying to make the macro:
Sub Macro1()
Dim objExcel As Object
Set objExcel = CreateObject("Excel.Application")
Set exWb = objExcel.Workbooks.Open("C:\Users\Admin\Desktop\Case Log.xlsx")
ThisDocument.solicitor.Caption = exWb.Sheets("Sheet1").Cells(4, 3)
exWb.Close
Set exWb = Nothing
End Sub
when i run the macro it highlights the word "solicitor" and displays the message "Compile error: Method or data member not found"
I've checked and rechecked and the label name is correct, it works with the command button, i don't understand why it shouldn't work as a macro.
Any helps would be much appreciated.
I found a native solution for doing this.
Mail Merge!
I set one up and saved it, now everytime I open the document, it loads all the info from the spreadsheet which it is already pointing to.
Thanks for all the suggestions

Cancel External Query in Excel VBA

I have created an Excel Spreadsheet which helps with data analysis from an Oracle database.
The user enters then clicks the "Refresh Query" button which generates a query for Oracle to execute. The query takes a minute or so to complete. Although the VBA code does not hang on ".Refresh", all Excel windows remain frozen until the query completes.
Sub refreshQuery_click()
Dim queryStr as String
' Validate parameters and generate query
' ** Code not included **
'
' Refresh Query
With ActiveWorkbook.Connections("Connection").OLEDBConnection
.CommandText = queryStr
.Refresh
End With
End Sub
Is there a way for the user to manually cancel the query (calling .CancelRefresh) while the Excel user-interface is frozen?
EDIT I don't know if the following is worth noting or regular behavior. While the query is executing, all open Excel windows (including the VBA Editor) become "Not Responding" in Task Manager. Neither pressing Esc nor Ctrl+Break will cancel the script. Also, calling DoEvents (either before or after .Refresh) does not change this behavior.
Here's a method that I know will work. However, there are some complications.
Here's how it's done:
Put the spreadsheet with the data in a separate workbook. This worksheet should execute the refresh query when it's opened and then close once the data is updated.
Create a batch file to call the "Data" Excel file.
Within a different workbook, create a procedure (macro) for the user to call. This procedure will call the batch file, which subsequently calls the Excel file. Since you are calling a batch file and not Excel directly, the Excel procedure will continue because the command shell is released so quickly and opens the other Excel file in a different thread. This allows you to continue working within the main Excel file.
Here are some complications:
I included a method to alert the user that the data has been udpated. There are timing issues where it's possible to try to check if the data has been update when the workbook is not accessible, which forces the user to try to update values. I included a method called my time which pauses the execution of the code so it only checks every so many seconds.
The updated worksheet will pop up in a new window, so the user will need to click on their original worksheet and keep working. You could learn to hide this if you're comfortable with Windows scripting (I haven't learned that yet).
Here are some files and code. Be sure to read the comments in the code for why some things are there.
FILE: C:\DataUpdate.xls
We'll make a workbook called "DataUpdate.xls" and put it in our C:\ folder. In cell A1 of Sheet1, we'll add our QueryTable which grabs external data.
Option Explicit
Sub UpdateTable()
Dim ws As Worksheet
Dim qt As QueryTable
Set ws = Worksheets("Sheet1")
Set qt = ws.Range("A1").QueryTable
qt.Refresh BackgroundQuery:=False
End Sub
Sub OnWorkbookOpen()
Dim wb As Workbook
Set wb = ActiveWorkbook
'I put this If statement in so I can change the file's
'name and then edit the file without code
'running. You may find a better way to do this.
If ActiveWorkbook.Name = "DataUpdate.xls" Then
UpdateTable
'I update a cell in a different sheet once the update is completed.
'I'll check this cell from the "user workbook" to see when the data's been updated.
Sheets("Sheet2").Range("A1").Value = "Update Table Completed " & Now()
wb.Save
Application.Quit
End If
End Sub
In the ThisWorkbook object in Excel, there's a procedure called Workbook_Open(). It should look like the following so it executes the update code when it is opened.
Private Sub Workbook_Open()
OnWorkbookOpen
End Sub
NOTE: I found a bug when this file closed if 1) you accessed the file from the command line or shell and 2) you have the Office Live Add-in installed. If you have the Office Live Add-in installed, it will throw an exception on exit.
FILE: C:\RunExcel.bat
Next, we're going to create a batch file that will open the Excel file we just made. The reason that call the Excel file from within the batch file and not directly from the other Excel file using Shell is because Shell will not continue until the other application closes (at least when using Excel.exe "c:\File.xls"). The batch file, however, runs its code and then immediately closes, thus allowing the original code that called it to continue. This is what will let your uses continue working in Excel.
All this file needs is:
cd "C:\Program Files\Microsoft Office\Office10\"
Excel.exe "C:\DataUpdate.xls"
If you're handy with Windows Scripting, you do fancy things like open the window in a hidden mode or pass a parameter of the file name or Excel location. I kept it simple with a batch file.
FILE: C:\UserWorkbook.xls
This is the file that the user will open to "do their work in." They'll call the code to update the other workbook from within this workbook and they'll still be able to work in this workbook while this one is updating.
You need a cell in this workbook where you'll check the "Update Table Completed" cell from the DataUpdate workbook. I chose cell G1 in Sheet1 for my example.
Add the following code to a VBA module in this workbook:
Option Explicit
Sub UpdateOtherWorkbook()
Dim strFilePath As String
Dim intOpenMode As Integer
Dim strCallPath As String
Dim strCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
'This makes sure the formula has the most recent "Updated" value
'from the data file.
rng.Formula = strCellFormula
strFilePath = "C:\RunExcel.bat"
intOpenMode = vbHide
'This will call the batch file that calls the Excel file.
'Since the batch file executes it's code and then closes,
'the Excel file will be able to keep running.
Shell strFilePath, intOpenMode
'This method, defined below, will alert the user with a
'message box once the update is complete. We know that
'the update is complete because the "Updated" value will
'have changed in the Data workbook.
AlertWhenChanged
End Sub
'
Sub AlertWhenChanged()
Dim strCellValue As String
Dim strUpdatedCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
strCellValue = rng.Value
strUpdatedCellValue = strCellValue
'This will check every 4 seconds to see if the Update value of the
'Data workbook has been changed. MyWait is included to make sure
'we don't try to access the Data file while it is inaccessible.
'During this entire process, the user is still able to work.
Do While strCellValue = strUpdatedCellValue
MyWait 2
rng.Formula = strCellFormula
MyWait 2
strUpdatedCellValue = rng.Value
DoEvents
Loop
MsgBox "Data Has Been Updated!"
End Sub
'
Sub MyWait(lngSeconds As Long)
Dim dtmNewTime As Date
dtmNewTime = DateAdd("s", lngSeconds, Now)
Do While Now < dtmNewTime
DoEvents
Loop
End Sub
As you can see, I constantly updated the formula in the "Listening Cell" to see when the other cell was updated. Once the data workbook has been updated, I'm not sure how you'd force an update in code without rewriting all the cells. Closing the workbook and reopening it should refresh the values, but I'm not sure of the best way to do it in code.
This whole process works because you're using a batch file to call Excel into a different thread from the original file. This allows you to work in the original file and still be alerted when the other file has been updated.
Good luck!
EDIT: Rather than include a more complete answer in this same answer, I've created a separate answer dedicated entirely to that solution. Check it out below (or above if it gets voted up)
Your users can break the VBA function by pressing Ctrl+Break on the keyboard. However, I've found that this can cause your functions to randomly break until each time any function is run. It goes away when the computer is restarted.
If you open this file in a new instance of Excel (meaning, go to Start > Programs and open Excel from there), I think that the only workbook that will be frozen will be the one executing the code. Other intances of Excel shouldn't be affected.
Lastly, you might research the DoEvents functions, which yields execution back to the Operating System so that it can process other events. I'm not sure if it would work in your case, but you could look into it. That way you can do other things while the process is being completed (It's kind of dangerous because the user can then change the state of your application while the process is working).
I believe I know a way that actually will work, but it's complicated and I don't have the code in front of me. It involves creating a separate instance of the Excel application in code and attaching a handler to the execution of that instance. You include the DoEvents part of the code in a loop that releases once the application closes. The other instantiated Excel application has the sole purpose of opening a file to execute a script and then close itself. I've done something like this before so I know that it works. I'll see if I can find the code tomorrow and add it.
Well, you could consider the old-fashion way -- split the query into smaller batches and use Do Events in between batches.
You could try XLLoop. This lets you write excel functions (UDfs) on an external server. It includes server implementations in many languages (eg. Java, Ruby, Python, PHP).
You could then connect to your oracle database (and potentially add a caching layer) and serve up the data to your spreadsheet that way.
The XLL also has a feature to popup a "busy" GUI that lets the user cancel the function call (which disconnects from the server).
BTW, I work on the project so let me know if you have any questions.