Solved

Launching an external executable.

Posted on 1999-01-17
5
824 Views
Last Modified: 2010-04-06
Hi experts,

there are several ways to start an external executable from the main program.
I created a 32 Bit main program from which I want to launch another 32 Bit
application. I need a solution which works both under WIN95 and WIN98 and WIN NT.


For this purpose, several FAQ's recommend the usage of:


ShellExecute(Application.MainForm.Handle, 'print', , '', '',
             SW_SHOWNORMAL);


I wanted to try it out, but I don't understand the parameter

"Application.Mainform.Handle".

Does it represent the external executable to be launched?


Moreover I don't know which unit I will have to include in the
uses clause of my demo program, so that my own unit can find
ShellExecute.

I simply want to do something like:

procedure TfrmMain.Button1Click(Sender: TObject);
begin
  ShellExecute('notepad.exe c:\autoexec.bat');
end;


What is the correct syntax of this ShellExecute statement with all parameters?
Unfortunately, my collection of FAQ's don't provide me with concrete examples,
so I don't understand how I can use this function.

Do you agree that ShellExecute is really the best way to launch another program?
Or should I rather use alternatives like WinExec,ExecAndWait, ShellExecute, CreateProcess.
What is the correct syntax of WinExec,ExecAndWait, ShellExecute, CreateProcess, if I want
to load my autoexec.bat into notepad.exe with the help of these functions.

BTW: I am meanwhile using Delpi 4.0 , standard edition, if that counts.

With kind regards

Mathes

0
Comment
Question by:mathes
  • 2
  • 2
5 Comments
 
LVL 5

Accepted Solution

by:
JimBob091197 earned 30 total points
ID: 1362240
Hi

ShellExecute is the best method in Win 95/98/NT to execute any file.  The benefit is that it doesn't have to be an EXE file.  It can be DOC, BMP, etc.

The syntax is:

(To answer your question: you have to include the "ShellApi" unit.)

ShellExecute(Self.Handle, 'open', PChar('C:\Windows\Notepad.exe'), PChar('C:\autoexec.bat'), nil, SW_NORMAL);

I use Self.Handle, where Self is the main form, so this is the same as "Application.MainForm.Handle".  This parameter is the window handle of the calling app that can receive error messages if ShellExecute fails, etc.  You can also use GetDesktopWindow.

Another useful way of starting an app is CreateProcess:

var
  ProcessInfo: TProcessInformation;
  StartUpInfo: TStartUpInfo;
begin
  ZeroMemory(@StartUpInfo, SizeOf(TStartUpInfo));
  with StartUpInfo do
    begin
      cb := SizeOf(TStartUpInfo);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_SHOWNORMAL;;
    end;
  CreateProcess(nil, PChar('C:\Windows\Notepad.exe C:\autoexec.bat'), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo);
end;

The benefits of CreateProcess are as follows:

(1)  You can close Notepad politely:

function ThreadWndProc(hWnd: HWND; lParam: LParam): Bool; stdcall;
begin
  // lParam is WM_CLOSE, because that's what we send in when
  // we call EnumThreadWindows (below).
  // Thus, the following will send WM_CLOSE to the window.
  SendMessage(hWnd, lParam, 0, 0);

  // Return True to continue enumeration.
  Result := True;
end;

if not (EnumThreadWindows(ProcessInfo.dwThreadId, @ThreadWndProc, WM_CLOSE)) then
  ShowMessage('EnumThreadWindows failed!');
 

(2)  You can force Notepad to close (unsaved changes in Notepad are lost):

  TerminateProcess(ProcessInfo.hProcess, 0);


(3)  You can execute Notepad & wait for it to terminate:

  ZeroMemory(@StartUpInfo, SizeOf(TStartUpInfo));
  with StartUpInfo do
    begin
      cb := SizeOf(TStartUpInfo);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_SHOWNORMAL;;
    end;
  if (CreateProcess(nil, PChar('C:\Windows\Notepad.exe C:\autoexec.bat'), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo)) then
    begin
      WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
      ShowMessage('Finished');
    end;


I usually use ShellExecute because it's pretty simple & can be used on any file (if the file extension is registered).  You can use WinExec, but it's maintained only for compatibility with older versions of Windows.  WinExec will call CreateProcess anyway.

Cheers,
JB
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1362241
JimBob is completely right. Just one addition. "TerminateProcess" is a quite unclean method of terminating another process. Better would be sending a WM_CLOSE message (like JimBob suggested) if the user may save a changed file or a WM_QUIT message, if the user must not save a changed file.

Regards, Madshi.
0
 

Author Comment

by:mathes
ID: 1362242
Dear JimBob,

thank you so far for your help.

Can you please tell me, how I can check the returncode of ShellExecute?
If the returncode is not 0, it is better to display an error message and tell the user what was wrong,
instead of a black screen and leaving the user alone with this problem. Which else values except 0
can ShellExecute return?

And can you please the following lines so that they are accepted  by Delphi 4.0 as
syntactically correct:


WinExec,ExecAndWait, ShellExecute, CreateProcess,

I want to learn the usage of these functions, too. Maybe they are valuable and the best
solution in other situations.

uses ;

.

WinExec ('notepad.exe c:\autoexec.bat');

uses ;

..

ExecAndWait ('notepad.exe c:\autoexec.bat');

uses ;

.

ShellExecute('notepad.exe c:\autoexec.bat');

uses ;

...

CreateProcess('notepad.exe c:\autoexec.bat');



With kind regards


Mathes
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1362243
Hi again

The return values from ShellExecute (as per the Win32 help file) are as follows:

ERROR_FILE_NOT_FOUND      The specified file was not found.
ERROR_PATH_NOT_FOUND      The specified path was not found.
ERROR_BAD_FORMAT          The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
SE_ERR_ACCESSDENIED       The operating system denied access to the specified file.
SE_ERR_ASSOCINCOMPLETE    The filename association is incomplete or invalid.
SE_ERR_DDEBUSY            The DDE transaction could not be completed because other DDE transactions were being processed.
SE_ERR_DDEFAIL            The DDE transaction failed.
SE_ERR_DDETIMEOUT         The DDE transaction could not be completed because the request timed out.
SE_ERR_DLLNOTFOUND        The specified dynamic-link library was not found.
SE_ERR_FNF                The specified file was not found.
SE_ERR_NOASSOC            There is no application associated with the given filename extension.
SE_ERR_OOM                There was not enough memory to complete the operation.
SE_ERR_PNF                The specified path was not found.
SE_ERR_SHARE              A sharing violation occurred.

As for your other questions, I have already given examples of ShellExecute (which "uses ShellApi") and CreateProcess (which "uses Windows), but here is an example for WinExec:

uses
  Windows;
 
WinExec('C:\Windows\Notepad.exe C:\autoexec.bat', SW_NORMAL);

According to the help file, WinExec returns the following values:
  If the function succeeds, the return value is greater than 31.
  If the function fails, the return value is one of the following error values:
    0 = The system is out of memory or resources.
    ERROR_BAD_FORMAT = The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
    ERROR_FILE_NOT_FOUND = The specified file was not found.
    ERROR_PATH_NOT_FOUND = The specified path was not found.

(I have never used ExecAndWait, but I suspect it is the Windows 3.1 equivalent to the CreateProcess sample I gave previously - the one where you wait for Notepad to terminate.
Similarly, WinExec is (according to the Help file) "provided for compatibility with earlier versions of Windows. For Win32-based applications, use the CreateProcess function".)

As I said before, I nearly always use ShellExecute.  I sometimes use CreateProcess if I want a little more control over the process.

Cheers,
Dave

0
 

Author Comment

by:mathes
ID: 1362244
Thank you for your help. This is exactly what I was looking for.

With kind regards

Mathes
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now