Consultancy and Programming
Advice, tips, techniques and downloads for Visual Foxpro developers.
Have you ever needed to run an external program from within your VFP application? Or pop up an email message window? Or play a sound file? Or display a web page in the user's browser? Or open a file folder? Or launch the Find File dialogue? Or print an RTF document? Or do just about anything else that involves running another process or application on the user's computer?
You can perform all these tasks - and many more - by courtesy of a versatile API function called ShellExecute(). The function has dozens of uses, and, if you have not yet made its acquaintance, we strongly recommend that you do so now.
At its simplest, ShellExecute() lets you programmatically launch any application which is installed on the user's computer. So, let's say you want to run Winzip from within your Visual FoxPro program, this is how you would go about it with ShellExecute():
DECLARE INTEGER ShellExecute IN shell32.dll ; INTEGER hndWin, ; STRING cAction, ; STRING cFileName, ; STRING cParams, ; STRING cDir, ; INTEGER nShowWin cFileName = "c:\Program Files\Winzip\Winzip32.Exe" cAction = "open" ShellExecute(0,cAction,cFileName,"","",1)
Because ShellExecute() is an API function, you need to declare it before you can call it. FoxPro's DECLARE statement establishes the number and data types of the parameters, and also the data type of the returned value. You only need to execute the DECLARE statement once, but you must do so before the first time you call ShellExecute().
As you can see in the above code, ShellExecute() takes six parameters. These are as follows:
|hndWin||The handle of the program's parent window. In VFP, you will usually set this to 0.|
|cAction||The action which is to be performed (see below).|
|cfileName||The file (or other 'object') on which the action is to be performed (see below).|
|cParams||If the file is an executable program, these are the parameters (if any) which are passed to it in the command line.|
|cDir||If the file is an executable program, this is the program's default or start-up directory.|
|nShowWindow||The program's initial window state (1 = normal, 2 = minimised, 3 = maximised).|
Note that the parameter names shown here are for illustration only. Within the DECLARE statement, you can give the parameters any names you like, or you can omit the names completely. But you must specify the data types. Note also that the function name, ShellExecute, is case-sensitive within the DECLARE statement.
The most important parameters are the action and the filename. If you want to use ShellExecute() to launch a specific program, the action is the word 'open' and the filename is the fully-qualified filename of the EXE file, as in the above example.
Although the above code works fine on our system, it might not work on yours. That's because the code assumes that Winzip is located in the c:\Program Files\Winzip folder, which is not necessarily the case. For that matter, it also assumes that Winzip is installed on the user's computer and that its executable filename is Winzip32.Exe.
A more generic approach would be to specify, not the name of the Winzip program, but that of the zip file that you want to open. In that case, the call to ShellExecute() would look something like this:
cFileName = "f:\Data\Archive.Zip" cAction = "open" ShellExecute(0,cAction,cFileName,"","",1)
The advantage of this approach is that it will work regardless of where Winzip is located. It will even work if the user has installed a different utility to process zip files - provided that the utility in question is associated with the ZIP file extension.
Similarly, if you wanted to let the user edit a DOC file, you could do so like this:
cFileName = "d:\MyDocs\Chase.Doc" cAction = "open" ShellExecute(0,cAction,cFileName,"","",1)
Again, not only don't you have to know the path and filename of the Microsoft Word executable program, you don't even need to know if Word is installed. If it is not, the above code will open Wordpad or whatever other word processor is associated with DOC files on the user's system.
Nor are you limited to opening the file. ShellExecute() can perform any action which is registered for the relevant document type. In the case of a DOC file, you could just as easily print the file. To do so, simply change the action parameter from 'open' to 'print', like so:
cFileName = "d:\MyDocs\Chase.Doc cAction = "print" ShellExecute(0,cAction,cFileName,"","",1)
Here are some more ideas for putting ShellExecute() to work:
cFileName = "www.ml-consult.co.uk" cAction = "open" ShellExecute(0,cAction,cFileName,"","",1)
This will display the specified web page in the user's default web browser.
cFileName = "mailto:firstname.lastname@example.org" cAction = "open" ShellExecute(0,cAction,cFileName,"","",1)
Here, we are launching a message composing window in the user's default mail client, with the specified email address already entered in the To line. Going further, you can also fill in the CC and BCC lines, as well as the actual message text. For more details of this technique, see the Foxstuff article, An easy way to send email from a Visual FoxPro application.
cFileName = "c:\data" cAction ="open" ShellExecute(0,cAction,cFileName,"","",1)
This simply opens the specified folder window. If you change the action to 'explore', it will open Windows Explorer with the specified folder in focus. Or you could specify 'find' as the action. That would launch the Windows Find File dialogue, with the folder name entered in the Look In box.
cFileName = "quikview.exe" cAction = "open" ShellExecute(0,cAction,cFileName,"d:\MyDocs\Chase.doc","",1)
This opens the specified document in the Word QuickView window, which is handy if you want to let the user see the document but not edit it. Of course, this assumes that Quikview.exe is installed on the user's computer (but you don't have to specify its path as it is usually held in the System folder).
In that last example, the document name is passed as a command-line parameter, that is, as the fourth parameter to ShellExecute(). Note that you have to provide the full path to the document, even if the file is in the VFP search path. ShellExecute() doesn't know anything about VFP's DEFAULT or PATH settings. However, if the file in question is in the VFP search path, you can always use FULLPATH() to establish the fully-qualified filename.
Here are two final examples:
cFileName = "c:\music\Mozart.Wav" cAction = "play" ShellExecute(0,cAction,cFileName,"","",1)
This will play the specified wave file. Your program doesn't need to know which wave-playing utility is installed on the user's system.
And finally, this opens the property sheet for a given shortcut:
cFileName = "c:\Windows\Desktop\Word.Lnk" cAction = "properties" ShellExecute(0,cAction,cFileName,"","",1)
Remember, in all these examples, you must already have executed the DECLARE statement. If you plan to call ShellExecute() from different parts of your application, you will probably run the DECLARE near the top of your main program.
How do you know what actions are available for a given file or document?
One way to find out is to look in the Folder Options window. You get to this window from the Tools menu in Windows Explorer or in any folder window. Go to the File Types tab (Figure 1) and scroll down until you see the file type that you are interested in. Select it, then click the Edit button (this is labelled Advanced in some versions of Windows). The Edit File Type dialogue (Figure 2) will show you all the registered actions - New, Open, Print and Printto in this example.
Another method is to look in the Registry. The actions are specified as sub-keys of HKEY_CLASSES_ROOT\<object name>\Shell. For Word 2000 documents, for example, there is a key named HKEY_CLASSES_ROOT\Word.Document.9\Shell, which contains sub-keys named New, Open, Print and Printto. You could therefore programmatically search the Registry to determine the available actions (the method of doing that is beyond the scope of this article).
Most file types have a default action, which is also specified in the Registry. If you omit the action parameter, the default action will be executed. If there is no default action, it is assumed to be 'open' (this behaviour varies slightly with different versions of Windows).
If ShellExecute() succeeds, it returns an integer greater than 32. The integer is in fact the handle of the main window of the application which has been launched. This could be useful if you want to use other API functions to manipulate the window in some way.
A returned value of 32 or lower indicates an error. The commonest error values are 2 (invalid path or filename) and 31 (invalid action, or no application associated with the specified file). You might also come across a value of 8 (insufficient memory) and 11 (invalid EXE file).
By now, we hope you agree that ShellExecute() opens up many interesting possibilities. We have used it dozens of times in our own applications, and we are sure that you will find it equally useful in yours.
Mike Lewis Consultants Ltd. July 2002
FoxStuff is maintained by Mike Lewis Consultants Ltd. as a service to the VFP community. Feel free to download and use any code or components, and to pass around copies of the articles (but please do not remove our copyright notices or disclaimers).
The information given on this site has been carefully checked and is believed to be correct, but no legal liability can be accepted for its use. Do not use code, components or techniques unless you are satisfied that they will work correctly in your applications.
© Copyright Mike Lewis Consultants Ltd.