I want my Access application to run an external program (in this case a R script) after the user clicks a button. I use this code:
Dim RetVal
RetVal = Shell("""C:\Program Files\R\R-2.10.1\bin\R.exe"" CMD BATCH --no-environ --silent --no-restore --no-save ""c:\test.R"" ""c:\test-result.txt""", vbHide)
MsgBox RetVal
This works fine, but the VBA code keeps on running while my script is executed. How can I make Access waiting for the script to be finished? Has anybody suggestions about how to give an error message of the script back to Access?
The OpenProcess and WaitForSingleObject combo that #Remou links to, is probably your best bet for doing this. You should take a look at this, it's a nice drop in module for shell and wait.
For returning a message back from the script, you could mess around with redirecting the scripts input and output. This is not for the faint of heart. As an alternative I would redirect the output of the script to a text file, then read in that file after it exits.
Related
I would like to know if there is an easy workaround for my following question. I have an access database that have different modules in vba (and of course each module with different subroutines). How can I do to create an icon or an executable file that by clicking on it it runs one of the subroutines of one of the modules without opening access?
The reason of this is because when I am away people need to run some of these subroutines and these users don't have any experience with Access.
You can start Access with a command line option to run a named Access macro. (That means an Access macro object. Some people also call VBA procedures macros, but an Access macro object is different.)
An Access macro has a RunCode method which you can use to run a VBA function. Since the code you want to run is a subroutine, create a new function which calls that subroutine and shuts down Access afterward, and use the function with the macro's RunCode method.
After you have the macro working correctly, test it from a Windows Command Prompt session following this pattern:
"<path to MSACCESS.EXE>" "<path to db file>" -X <macro name>
After working out those details, you can create a desktop shortcut to do the same thing.
However, if your Access operation must be run by you or another user on a regularly scheduled basis (daily, weekdays only, etc.), you could create a Windows Scheduled Task to do it and forget about other users and desktop shortcuts.
Note this suggestion isn't exactly what you requested because it does open Access. But it could close Access after the operation is finished, so perhaps it will be acceptable.
I have an MS Access form, and on a button click it runs VBA code to run the Shell Command.
private sub cmdOpen_click()
dim vValue as String
vValue = Listbox.column(1) 'Retrieving a path name from a list
shell "C:\Adobe's Path\Arco.exe " & vValue
end sub
When I first run this script the first time I open this database, it stops running, opens the script editor, and highlights the shell line. There is no error code, in fact if I just hit the Run button it finishes just fine. If run it a second time there is no issue. Only when I close it down and reopen it.
No there is no Breakpoints/stops in the code. Would anyone have any idea why this is happening? I can't seem to fine anyone else with a similar issue.
I have had issues with this in Access 2010. I found that there was a breakpoint on that line, and for some reason Access seemed to remember it even after closing the application. For me, it usually happened when I fixed code and someone else ran it.
The only thing I found that seemed to fix it was to set a breakpoint on that line, save the project, then clear it and save it again. Sometimes I had to open and close the project once or twice to get it to completely forget the breakpoint was there.
It seems to me that it's a random, esoteric bug in the Access IDE. It would be fantastic if they would actually make this a feature, but it's not even a bug that can be relied on.
I've had similar experiences with Access and what always helped for me is to copy the text into a Notepad .txt file (or other basic text processing program). Then select it all in the .txt and copy it back.
Decompiling the Access application will solve this too.
Previous SO question: How does one decompile and recompile a database application?
I followed the suggestion by Cody Gray about halfway down the page in this thread but I'm having no luck.
Unless I'm missing something, this is supposed to allow me to navigate from Access, using the Windows API Dialog Box, to the relevant folder and open a file, no? I'm trying to open a Word doc which has a Mail Merge coming back to the same Access Db. I needed the dialog because there are multiple files that may be selected at different times.
I added all the suggested code and while the process runs without error, when I get to the final step, the selected file doesn't open. Nothing happens.
I realize this is not much help without an error message. Any thoughts nonetheless?
As I understand the situation, you have code which uses a string variable named strFileToOpen to hold the path to a Ms Word document. And now you want to open that file in Word.
You can use the FollowHyperlink method.
Application.FollowHyperlink strFileToOpen
Look at the Access help topic for that method. It offers other options you may wish to use.
Also I suggest you look at the help topic for FileDialog Object. It is simpler than the Windows APi method in the code you linked.
I am seeking comments on how to schedule auto updates of a database (.accdb) since I am not very comfortable with the process I have set up.
Currently, it works as follow:
Task Scheduler calls a .bat
.bat calls a .vbs
.vbs opens the database and calls a macro
The macro calls a function (VBA Level)
The function calls the update Subroutine
I consider there are too many steps and the fact that it requires 2 external files (.Bat and .vbs) related to the database and stored on the system increase the risk that the procedure would break.
Apparently (but please tell me that I am wrong and how I can change it) .vbs cannot call a subroutine but only a macro. Identically, an access macro cannot call a subroutine but only a function if the user is expecting to enter the VB environment of the database. This is the reason why I called a function (VBA Level) that then calls the subroutine.
Hope some of you know how to shorten the steps and eventually get ride of the .bat and .vbs
To the best of my knowledge the shortest path for a Windows Scheduled Task to "do something useful in Access VBA" is:
Create a Public Function (not Sub) in the database. For example:
Option Compare Database
Option Explicit
Public Function WriteToTable1()
Dim cdb As DAO.Database
Set cdb = CurrentDb
cdb.Execute "INSERT INTO Table1 (textCol) VALUES ('sched test')", dbFailOnError
Set cdb = Nothing
Application.Quit
End Function
Create a Macro in the database to invoke the function:
Create a Windows Scheduled Task to invoke MSACCESS.EXE with the appropriate parameters
In the above dialog box the values are:
Program/script:
"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"
Add arguments (optional):
C:\Users\Public\schedTest.accdb /x DoSomething
A VBS script can call any standard VBA SUBROUTINE with the following:
dim accessApp
set accessApp = createObject("Access.Application")
accessApp.OpenCurrentDataBase("C:\MyApp\MultiSelect.mdb")
accessApp.Run "TimeUpDate"
accessApp.Quit
set accessApp = nothing
Note that the sub TimeUpDate is a standard VBA subroutine. This means no Autoexec macros, and no macros at all - only pure VBA sub calls + this VBS script.
There is a little known trick dating back to the earliest years of access to allow it to run as a process which still works. Access will always on startup look for a macro called "Autoexec". If it finds it it will immediately start executing this macro. I find this is extremely useful if I need to initialise the program before opening forms or, as in the case of the original questioner, run access as a scheduled process with no user I/O.
After beating my head against the wall for about four hours, I finally got this to work:
1) Create a DOS batch file with one line it. The line is composed of three parts a) the full path to Microsoft Access (msaccess.exe), b) the full path of the Microsoft Access database with the code in it, and c) the Access command line argument "/x MacroName". The first two items should be surrounded with quotes. Mine looks like this:
"C:\Program Files (x86)\Microsoft Office\Office14\MSACCESS.EXE" "C:\MyPrograms\ProdDB Reports\ProdDB Reports.accdb" /X DailyTestReportsRun
2) Create a macro inside of Access with the name you used in your batch file. It has one command, RunCode, with an argument of the name of a VBA function you want to call. This should be followed by open/close parenthesis "()". I didn't try passing any parameters to the function; I think this would be problematic.
4) Make sure the VBA function you call has a Docmd.Quit command at the end, or that you add this as a second line to your macro. These will make sure that Access doesn't stay open after your process runs.
5) In Windows Task Scheduler, select "create a basic task" (which invokes a wizard). Set the program name to the name of your DOS batch file. There's a helpful check box labeled something like "Open the properties window when I'm finished." Check that so you that go to the properties window.
6) Set the task to run regardless of whether the user is logged on or not. Also check on the "Run with highest privileges" box, which one friend on here suggested.
You can now test everything by right-clicking the scheduled task and selecting the Run command.
I liked Albert Kallal's script and tried it. Everything worked great until I tried to schedule it. Then, for some mysterious reason the scheduler would not kick it off.
none of the above work
ms access DB with task scheduler will not work as to open the db run code and quit the application
the solution I found is to avoid task scheduler and have the ms access db open all time and have a timer in msaccess do the job
I have a kind of complex scenario
The Access-Application we are developing calls a VBA Function in another Access-Application which then triggers an Install Routine by calling the "calling" Access-Application.
Both Applications are either accda (for Access-AddIn) or compiled accde files.
Admin.accda -> PlugIn.accda (InstallPlugIn) -> Admin.accda (RegisterPlugIn)
The corresponding line in Admin.accda looks like:
Application.Run("\\Path\To\PlugIn\PlugIn.InstallPlugin", "Parameters")
Everything works as expected except for one thing. Access keeps the file handle on the PlugIn.accda open until I close the Admin.accda.
When I debug my Code I can see that after calling Application.Run() in Admin.accda the VBA-Code of PlugIn.accda gets loaded into Admin.accda and a Lockfile for PlugIn.accda (PlugIn.laccda) gets created. When my code finishes the Lockfile has 0 Bytes but still exists.
By using the ProcessExplorer from Sysinternals I can see that the Process in which the Admin.accda is running still has a Filehandle open to the PlugIn.accda.
I want to close that file handle because there is nothing more to do with the PlugIn.accda and the open Filehandle could interfere with Process in the Clients Client/Server deployment like copying the PlugIn to the Client Computer.
Until now I have tried two different approaches but without success:
First:
I tried to call the Run on Access-Application-Object and close that Object afterwards
Dim oApplication As Object
Set oApplication = CreateObject("Access.Application")
oApplication.OpenCurrentDatabase Me.txtPathPlugIn
If oApplication.Run("\\Path\To\PlugIn\PlugIn.InstallPlugin", "Params") Then
'Do something
End If
oApplication.CloseCurrentDatabase
Set oApplicaton = Nothing
With that approach the PlugIn was unable to call the RegisterPlugIn Function in the Admin.accda because it was exclusivly opened in another Process.
Second:
I tried to close the PlugIn Database after the call to RegisterPlugIn in the Admin.accda by using:
CodeProject.CloseCurrentDatabase
But that had no effect what so ever :-(
Is there a way to close File handles by using some Windows-API functions? Or does anyone has an better approach to dynamically register additional Access files?
Maybe this is a dumb solution but just throwing it out there, you could use the taskkill command ?
http://technet.microsoft.com/en-us/library/bb491009.aspx