Copy New Access client to users - database

I use a very simple version control whereby I use the "tag" property on the Switchboard to record the version of the database.
On a linked "mastertable" I have a master record that shows the current version. If this is out of sync, then there is code in the switchboard to initiate a simple file copy of the new client version to the user's desktop.
I can't use any EXE type auto-installers to do this, so had to come up with an all Access solution, but having some issues with shell commands and timing that is causing the "auto" part of the installer to be inconsistent.
Below are my codes for the Client and my standalone "Installer" database (which only has one form that opens on startup and initiates the copy code). I use lookup tables for all file locations, but will use strings in my example.
Client.mdb:
strInstaller = "c:\Installer\Installer.mdb"
set obj = CreateObject("access.application") 'previously tried SHELL command
with obj
.visible = true
.userControl = true
.openCurrentDatabase (strInstaller)
end with
application.quit
Simple enough. So the above code just opens my Installer mdb which opens a form and executes the following on open.
Installer.mdb:
strFileName = "ClientDB"
strMaster = "D:\" & strFileName
strClient= dlookup("DBPath", "UserTbl", "LanID = '" & MyID & "'") & "\" & strFileName
if len(dir(strClient)) <> 0 then
kill strClient
end if
filecopy strMaster, strClient
The dlookup in the strClient simply looks up the path where the user opened up the instance of the client mdb. (I record this on every instance).
My issues is that I am not getting consistent results. Sometimes it will copy the file, and sometimes it won't. I've changed it to run from a button on the Installer Form, and it works every time, so I'm guessing it has something to do with timing.
I've tried putting a pause function before the kill command, and that seems to help if I set the pause to 3 or 4 seconds. I originally used Shell to open the Installer, but got rid of it as I heard that it was running concurrently with the installer.mdb code.
I'm thinking it's something obvious, but I've been staring at this for about an hour and can't figure it out. Ideally, I don't want the user to interact with this form using an "Install" button, but would like it to happen in the background. i.e. I want to set the .visible = false at some point.
Can anyone see an issue with this method, or suggest a better method to push out new copies of the client - and I can't use any EXE install programs.

You likely want to use the shell() command. You can use CreateObject, but that feature is NOT available in the runtime. (and worse, it will not work).
The simple trick is ONCE you shell out to the upgrade program, you want to QUIT the main program (since you can’t copy over it while it is running).
The code I use is thus:
strCurrentDir = CurrentProject.Path & "\"
' path to msaccess.exe is determined here
strShellProg = q & SysCmd(acSysCmdAccessDir) & "msaccess.exe" & q & " "
' path to current dir...assume upgrade program in same folder
strShellProg = strShellProg & q & strCurrentDir & "UpGrade.accDE" & q
If Shell(strShellProg, vbNormalFocus) > 0 Then
Application.Quit
Else
MsgBox "Un able to run upgrade", vbCritical, AppName
Application.Quit
End If
In above “q” is = """" (a single double quote).
So you shell out, and then immediate do a application.Quit. The upgrade program should have a “prompt” like “about to upgrade – ok”. That “prompt the user has to hit gives the main application time to quit. I also useally write out the locations to a text file in the above code - but the above steps to shell() is the main takeaway solution here.
As noted, you can use create object, but THEN if you quit the main application, then that variable holding the upgrade program will also go out of scope (or worse, the main application cannot shut down because it is “hosting” an automated copy of the upgrade application by CreateObject.
So you in practical terms don’t want to use createObject, since this means the main program is “hosting” or “holding” a copy of the upgrade program and the main program really can’t quit.

Related

Run batch silently by hotkey (permissions issue?)

I am trying to control Spotify volume from inside a game without switching windows. To do this I did the following:
A. Found nircmd.exe from NirSoft that can control individual program volumes in Windows
B. Wrote a batch to execute the command
C. Wrote this .vbs script to hook into the batch silently:
Set WshShell = CreateObject("WScript.Shell" )
WshShell.Run chr(34) & "Spotify App Volume Up.bat" & Chr(34), 0
Set WshShell = Nothing
^
Using this .vbs snippet to accomplish silent run is really popular. This works when I click the .vbs myself. The problem I have is I need a way to execute this from another program. When I try to execute from any hotkey program or something like AutoHotKey it gives me this error:
ActiveX Component cannot create object 'WScript.Shell' Code: 800a01ad
I tried setting security of all involved files to everyone, full control. It did not help. It seems to me that Windows is trying to protect me by preventing scripts from initializing by other programs. Any suggestions? Otherwise does someone know how to execute this silently with another method?
EDIT:
AutoHotKey's run command will do this:
run "mybat.bat",, Hide
However, does anyone know how to get around this behavior with .vbs? I am curious.
I believe all your scripts, vbscript and your batch file can potentially be written natively in Ahk, but here's how I'd launch your vb script.
x:: ; press x
sc := ComObjCreate("ScriptControl")
sc.Language := "VBScript"
script =
(
Set WshShell = CreateObject("WScript.Shell" )
WshShell.Run chr(34) & "Spotify App Volume Up.bat" & Chr(34), 0
Set WshShell = Nothing
)
sc.ExecuteStatement(script)
return

Creating a Message Box that runs a Specified Program (vbs)

Take the following script that I have:
x=msgbox ("Do you want to recycle the Premiere Pro Media Cache?" ,4, "Recycle Premiere Pro Media Cache")
If box =6 Then
CreateObject("wscript.shell").run "C:\Expedited\Scripts\PrMCRecycler1"
End If
My goal is to get this VBS file (which brings up a message box) to run the batch file (the same way it would run when double-clicking it) when the yes button is pressed. I'm not sure what I'm doing wrong above. When I click No, nothing needs to happen, so I didn't specify anything for it.
Basically, since it brings up a yes/no message box, I just need to make the yes button execute the specified batch file. I could really use some assistance in figuring out what's wrong. When I try the code listed above, nothing happens upon choosing yes (besides the dialogue box going away).
Try this example and change the path of your batch file.
Option Explicit
Dim ws,Question,PathProgram
Set ws = CreateObject("wscript.shell")
'change the path of your batch file
PathProgram = "C:\Program Files\Internet Explorer\iexplore.exe"
Question = Msgbox("Do you want to recycle the Premiere Pro Media Cache?",VbYesNO + VbQuestion, "Recycle Premiere Pro Media Cache")
If Question = VbYes Then
ws.run DblQuote(PathProgram)
End If
'***************************************
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'***************************************

Passing an argument into a VBS script which passes into a batch file

I have a legacy application which doesn't support utilizing the default applications defined in windows which requires that I specify a specific an executable for a file format to be opened within the application. Since Microsoft no longer includes MODI with Office by default I have been looking at using launching Windows Picture Viewer for .TIF, .TIFF, & .BMP files since it is built into Windows; however Microsoft does not have a direct executable for Windows Picture Viewer which can be called forcing me to create a script which executes the command which calls for Windows Picture Viewer to execute. After research the only way I have been able to call the application to open a specific file is by creating a batch file such as below:
GIFTS.BAT
rundll32.exe C:\WINDOWS\system32\shimgvw.dll,ImageView_Fullscreen %~1
If I execute the above code such as GIFTS.BAT "C:\Example Directory\Sample File.tif" from a command prompt or from the application launches and the Sample File.tif opens without a problem; however a command prompt opens along with the file when launching from the application.
Upon which I tried to create a vbscript to hide the batch file from executing however I can't seem to pass my argument if the argument has a "space" within the argument.
GIFTS.VBS
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run """C:\GIFTS.BAT"" " & WScript.Arguments.Item(0), 0
Set WshShell = Nothing
If I try to execute the VBScript from a command prompt such as GIFTS.VBS "C:\Example Directory\Sample File.tif" the application never launches and the command prompt returns no message or error. If I simplify the execute command (removing spaces to GIFTS.VBS "C:\Sample_File.tif" the application launches as well as the file Sample_File.tif is displayed and there is no command prompt displayed when the application executes the VBScript.
My question is how can I pass an argument into the VBS script that in return passes the the batch file when the argument contains spaces (which there is always going to be spaces since the argument will be a file name and path)?
There might be an easier approach to what I want to accomplish; however I am looking for a solution that Windows 7 - 8.1 can utilize with no additional software to install or manage on each workstation. The batch files works great I just need to be able to hide the command prompt that opens along with the application as my end users won't know what to do with it.
Thanks!
Sometimes, nested levels of escaping characters requires intimate knowledge of the undocumented behavior of CMD or some voodoo. Another way to attack the problem is to guarantee that you won't have any spaces in the name of the file. Windows has a concept of a short path (no spaces or special chars) for which every existing file has a unique one.
Here's a modified version of your program for which invoked subcommand doesn't need quotes around the file name.
Set WshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set fsoFile = fso.GetFile(WScript.Arguments.Item(0))
WshShell.Run """c:\GIFTS.BAT"" " & fsoFile.ShortPath, 0
Set WshShell = Nothing
You may wish to add your own error checking. The specified file must exist in order for the GetFile() command to succeed.

.PIF With ? Allowed for a Variable Request

Up until now I have been using the .PIF shortcut with "?" to call for a variable that is then used in a batch file to produce specific results. We have over project 10,000 folders, and the JobFind.PIF tool really satisfied a quick search. It is like a moving or floating Shortcut.LNK to any one folder in the larger directory.
Program Line Call Inside JobFind.PIF
S:\YoursTruly\JobFind\JobFind.bat ?
JobFind.bat Contents Where %1 = ?
explorer "P:\SDIT_L~1\Projects\000030%1"
Is there a simple replacement for my olde fashion JobFind.pif tool?
Thank you,
GPB
You could replace it with either a command-line or GUI VBScript. Here's an example:
strJob = InputBox("Enter the job number:")
With CreateObject("WScript.Shell")
.Run "explorer.exe P:\SDIT_L~1\Projects\000030" & strJob
End With

Why does Applescript run in Script Editor, but error when saved as Application?

My applescript needs to detect its own filename, and the following runs fine on Snow Leopard (10.6)
set my_name to name of me as string
display dialog "Name: " & my_name
It displays "Name: AppleScript Editor" when I run it from AppleScript Editor, and it displays "Name: NewTest" when I save it as an application called NewTest.
When I run it on a Leopare (10.5) machine, it complains "Can't make name of <> into type string." When I remove the "as string" portion, it runs under Script Editor, returning "Name: Script Editor", but when saved as an application, it errors and says, "Can't get name."
What is different about running in script editor and saving as application under 10.5?
Here's another thought although I haven't checked. One thing that can cause problems is the command "get". In general when you run a command like "name of me" the command get is implied so you're really running "get name of me". The problem is that the implied "get" is not always the case. So sometimes you have to explicitly say "get". Whenever I have a problem like yours the first thing I try is to add "get" to the command... it's become habit because you just never know. Note that you can always use the word get and never have that issue. As such, try changing your command to "set my_name to (get name of me)". I'd be interested to know if that fixes your 10.5 problem. Also note that a name is already a string so there's no need to coerce the result to a string.
EDIT:
I looked through some of my older scripts. I used the following code to get the name. In my notes I have these comments...
-- this will get the name of the application or script without any file extension
-- it is done using the path because when a script is run from the script menu, and you write set myName to name of me, then the result is "applescript runner" instead of the actual name
-- also it assures that you're getting the name as it appears in the Finder because sometimes the system events process name is different than the Finder name
on getMyName()
set myPath to path to me as text
if myPath ends with ":" then
set n to -2
else
set n to -1
end if
set AppleScript's text item delimiters to ":"
set myName to text item n of myPath
if (myName contains ".") then
set AppleScript's text item delimiters to "."
set myName to text 1 thru text item -2 of myName
end if
set AppleScript's text item delimiters to ""
return myName
end getMyName
An Applescript application isn't an "application" in the truest sense of the word. A lot of contexts change, like "get path to me" will be different when run as a script or as an application, because they are still good ol' wonky Applescript as opposed to a Carbon or Cocoa-based application. Running similar code against the Finder...
tell application "Finder"
set my_name to name as string
display dialog "Finder: " & my_name
end tell
...behaves as expected because the Finder is a Carbon/Cocoa-based application.
I don't have a real answer other than to say it sounds like there was a change made to the OS relative to the Applescript framework in 10.6 that makes the call to "me" behave more as expected.
I would recommend reading the section in the Applescript guide about the me and it keywords to gain more insight into how me works.

Resources