unit ShellApiEx;
(******************************************************************************)
(************* This code is released into the PUBLIC DOMAIN ***************)
(************* [url]http://assarbad.net[/url] | [url]http://assarbad.org[/url] ***************)
(******************************************************************************)
interface
uses
Windows;
{.$DEFINE UNICODE}// Defines wether the unicode or the ansi prototype is to be used!
function ShellExecuteAndWaitA(hWnd: HWND; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer; bWait: BOOL): HINST;
stdcall;
function ShellExecuteAndWaitW(hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer; bWait: BOOL): HINST;
stdcall;
type
TShellExecuteAndWait =
function(hWnd: Windows.HWND;
{$IFDEF UNICODE}
Operation, FileName, Parameters, Directory: PWideChar;
{$ELSE}
Operation, FileName, Parameters, Directory: PAnsiChar;
{$ENDIF}
ShowCmd: Integer; bWait: BOOL): HINST;
stdcall;
var
ShellExecuteAndWait: TShellExecuteAndWait =
{$IFDEF UNICODE}
ShellExecuteAndWaitW;
{$ELSE}
ShellExecuteAndWaitA;
{$ENDIF}
implementation
uses ShellApi;
(*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
GERMAN ABSTRACT (important informations below in English)
Meine Kommentare im Quelltext sind Englisch, hier beschränke ich mich aber auf
Deutsch:
ShellExecute() ist weithin bekannt. Komischerweise gilt dies scheinbar
(zumindest unter Delphianern nicht für ShellExecuteEx(). Man sieht oft
Beispiele auf die Frage: "wie führe ich ein Programm aus und warte, bis es
beendet ist?" - ich habe aber bisher nur Varianten mit CreateProcess gesehen,
es gehört aber IMHO zum guten Ton auch auf ShellExecuteEx zu verweisen.
Wieso? Nun, es ist eine erweiterte Version von ShellExecute und bietet die
selben Vorteile (i.e. Ausführen von "Dateien" die bei einer Anwendung
registriert sind, Benutzung von Verben ... EDIT, PRINT, OPEN ...). Außerdem
wird eben das Handle zum neu erzeugten Prozeß zurückgeliefert, so daß man auf
dessen Ende warten kann.
Ansonsten kann man ShellExecuteEx auch nehmen um Informationen über den Prozeß,
der erstellt wird, zu erhalten. Dazu möchte ich auf das Windows Platform SDK
verweisen, da es dort eine ausführliche Beschreibung gibt und es müßig ist
alle Varianten der Nutzung zu erklären. Die wichtigste Ist hier umgesetzt.
Assarbad AT gmx DOT info [2003-06-22]
PS: Ich arbeite mit den Records als Variablen, um die Abfrage ob eine
Allozierung erfolgreich war zu vermeiden.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*)
(*
There are 2(3) new functions declared in this unit:
- ShellExecuteAndWaitW(),
- ShellExecuteAndWaitA()
(ShellExecuteAndWait as either Unicode or Ansi version of the above functions!)
The functions share the syntax with the standard ShellExecute(A|W) API, with
one exception:
- There is an additional parameter. On Delphi 4 up you could define a default
value of "False" which would resemble the functionality of ShellExecute.
I did not define this value to keep compatibility with Delphi 3.
Description:
The value is a BOOL (LongBool) which determined wether the function
should wait for the new process to finish or not.
*)
function ShellExecuteAndWaitW(hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer; bWait: BOOL): HINST;
stdcall;
var
sei: TShellExecuteInfoW;
begin
// Delete any contents of this variable (undetermined for complex types)
ZeroMemory(@sei, sizeof(sei));
// Fill the information structure with all ShellExecute standard parameters
with sei
do
begin
cbSize := sizeof(sei);
fMask := SEE_MASK_NOCLOSEPROCESS;
// we want a process handle returned!
Wnd := hWnd;
lpVerb := Operation;
// Pre-defined: edit, explore, find, open, print, nil
lpFile := FileName;
lpParameters := Parameters;
lpDirectory := Directory;
nShow := ShowCmd;
end;
// Call ShellExecuteEx()
if ShellExecuteExW(@sei)
then
try
if bWait
then
WaitForSingleObject(sei.hProcess, INFINITE);
finally
// Close references to new process! THIS ALSO NEEDS TO BE DONE IF THE PROCESS
// IS ALREADY FINISHED WITH EXECUTION!!!
CloseHandle(sei.hProcess);
end;
// Return a value (not actually HINST, as with ShellExecute! ... see Platform SDK)
result := sei.hInstApp;
end;
function ShellExecuteAndWaitA(hWnd: HWND; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer; bWait: BOOL): HINST;
stdcall;
var
sei: TShellExecuteInfoA;
begin
// Delete any contents of this variable (undetermined for complex types)
ZeroMemory(@sei, sizeof(sei));
// Fill the information structure with all ShellExecute standard parameters
with sei
do
begin
cbSize := sizeof(sei);
fMask := SEE_MASK_NOCLOSEPROCESS;
// we want a process handle returned!
Wnd := hWnd;
lpVerb := Operation;
// Pre-defined: edit, explore, find, open, print, nil
lpFile := FileName;
lpParameters := Parameters;
lpDirectory := Directory;
nShow := ShowCmd;
end;
// Call ShellExecuteEx()
if ShellExecuteExA(@sei)
then
try
if bWait
then
WaitForSingleObject(sei.hProcess, INFINITE);
finally
// Close references to new process! THIS ALSO NEEDS TO BE DONE IF THE PROCESS
// IS ALREADY FINISHED WITH EXECUTION!!!
CloseHandle(sei.hProcess);
end;
// Return a value (not actually HINST, as with ShellExecute! ... see Platform SDK)
result := sei.hInstApp;
end;
end.