lcSystem = Thisform.oUtility.GetSystemDirectory()(GetSystemDirectory is a utility method that returns the location of the Windows System folder; I'll show the code for that later.)
try
run /n1 &lcSystem..odbcad32.exe
catch
endtry
This worked great until I tried it on Vista; it fails there because the ODBC Administrator requires admin privileges and the RUN command doesn't support requesting elevation. Fortunately, there's an easy solution to that: use ShellExecute instead. I changed the code to:
lcSystem = oUtility.GetSystemDirectory()(Like GetSystemDirectory, ShellExecute is another utility function. It runs the specified command. The cool thing about ShellExecute is that it'll launch the appropriate program. In the case of an EXE, it runs it. In the case of an HTML file, it launches the default browser. In the case of a DOC file, it launches Word.)
try
oUtility.ShellExecute(lcSystem + 'odbcad32.exe', 'RunAs')
catch
endtry
Now when the user clicks the button, they're requested to elevate to administrator before the ODBC Administrator appears. To make it obvious that this will happen, I've followed the Vista convention of adding a shield image to the button to alert the user that elevation will be requested. To do that, I set PicturePosition to 1-Left of Caption, Picture to VistaShield.BMP (an image I created using SnagIt to grab the shield icon displayed in the User Accounts control panel applet), and shortened Caption to just "ODBC" so it all fits. Here's what the button looks like:
Here's the code for GetSystemDirectory:
#define cnMAX_PATH 260Here's the code for ShellExecute:
#define ccNULL chr(0)
local lcBuffer
lcBuffer = space(cnMAX_PATH)
declare integer GetSystemDirectory in Win32API ;
string @szBuffer, integer nLength
GetSystemDirectory(@lcBuffer, cnMAX_PATH)
return addbs(alltrim(left(lcBuffer, at(ccNULL, lcBuffer) - 1)))
lparameters tcFileName, ;
tcOperation, ;
tcWorkDir, ;
tcParameters
local lcFileName, ;
lcWorkDir, ;
lcOperation, ;
lcParameters, ;
lnShow
if empty(tcFileName)
return -1
endif empty(tcFileName)
lcFileName = alltrim(tcFileName)
lcWorkDir = iif(vartype(tcWorkDir) = 'C', alltrim(tcWorkDir), '')
lcOperation = iif(vartype(tcOperation) = 'C' and not empty(tcOperation), ;
alltrim(tcOperation), 'Open')
lcParameters = iif(vartype(tcParameters) = 'C', alltrim(tcParameters), '')
lnShow = iif(upper(lcOperation) = 'Print', 0, 1)
declare integer ShellExecute in SHELL32.DLL ;
integer nWinHandle, ; && handle of parent window
string cOperation, ; && operation to perform
string cFileName, ; && filename
string cParameters, ; && parameters for the executable
string cDirectory, ; && default directory
integer nShowWindow && window state
return ShellExecute(0, lcOperation, lcFilename, lcParameters, lcWorkDir, ;
lnShow)
Hi Doug,
ReplyDeletei had to make a few minor modifications to make your code running in my environment, so here you are:
LOCAL lcBuffer, liPathLength, lcNull
liPathLength = 250
lcBuffer = SPACE(liPathLength)
lcNull = CHR(0)
DECLARE integer GetSystemDirectory in Win32API string @szBuffer, integer nLength
GetSystemDirectory(@lcBuffer, liPathlength)
RETURN ADDBS(ALLTRIM(LEFT(lcBuffer, AT(lcNULL, lcBuffer) - 1)))
In 'shellexecute' were two letters missing for 'if empty(tcfilename)'
after these changes everything works fine. A really neat function which is already implemented within my config-app.
Thanks, Tom
Tom, I don't see the fix you needed for the filename; it does appear as tcFileName in the code I posted. However, you reminded me that the GetSystemDirectory method uses a couple of constants which I hadn't specified in the code, so I edited the blog entry to include them. Thanks!
ReplyDeleteHi Doug,
ReplyDeleteFirst I want to say thanks for all the help you've given us VFP folks for the transition to Vista. I would be totally lost if it weren't for you!
Could I use WScript.Shell to RUN a file? i.e.:
oWscript = CREATEOBJECT("WScript.Shell")
lcSetupFile = path to setup.exe
oWscript.Run(lcSetupFile)
The code works, and the user is prompted to "Cancel" or "Allow" which is fine with me. I was just wondering if there was some security reason (or something) for using ShellExecute over WScript.Shell.
Thanks!
Hi Beth.
ReplyDeleteYes, WScript works fine too. The only thing to consider is that I believe it may be disabled on some locked down systems.
Doug