visitor (0 QPoints)
  • FR
  • EN
  • NL
  • DE
  • ES
315 experts, 1193 registered users, 1659 questions already answered
European Experts Exchange, the very best site for high-quality IT solutions

New Improved Search!

 


05/10/2011 1h30 : Steve Jobs is dead, the father of Apple ][ is gone, we are all orphaned.

Languages :: Delphi :: How to run another app, wait till it's done and go on.


By: JackNaif U.S.A.  Date: 15/06/2003 00:00:00  English French  Points: 300 Status: Answered
Quality : Excellent
Hi,
I'm trying to do in Delphi 5.0 some of the stuff you would do in C with the spawnXX familly of functions (available in C++ Builder, but, to my best knowledge, not in Delphi).
Basically what I want to do is to have my app start another programme, stay put while this other programme does it's thing, and then (but only then) go on with it's execution.
I have found a couple of clues here and there and ShellExecute seems to be a good way of launching the other app, but I don't know how to have my app realise when the other is done.
The programme I would be launching in this ocassion is a console programme whichs source code is not available for modification.
Also, the output from this console programme normally goes to the standard output (ie: the screen). By calling it with >log.txt I can send it to a file where my app can read it once the console programme is done, but if you know about a tidier way of getting that output into a buffer in my programme, without having to write it to, and retrieve it from, disk, I would also apreciate that.
Thank's a lot:

Jack.
By: VGR Date: 15/06/2003 16:39:00 English  Type : Answer
ok

1) without input&output redirection :

Function ExecNewProcess(ProgramName : String; doWait : Boolean = False) : Boolean;
var
StartInfo : TStartupInfo;
ProcInfo : TProcessInformation;
CreateOK : Boolean;
begin

//AddLigne('calling '+ProgramName);

{ fill with known state }
FillChar(StartInfo,SizeOf(TStartupInfo),#0);
FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
StartInfo.cb := SizeOf(TStartupInfo);

CreateOK := CreateProcess(nil, PChar(ProgramName), nil, nil,False,
CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS,
nil, nil, StartInfo, ProcInfo);

{ check to see if successful }
if CreateOK then
//may or may not be needed. Usually wait for child processes
if doWait then WaitForSingleObject(ProcInfo.hProcess, INFINITE);
ExecNewProcess:=CreateOK;
end;



2) with redirections :
{----------------------------CreateDOSProcessRedirected---------------------------
Description : executes a (DOS!) app defined in the CommandLine parameter redirected
to take input from InputFile and give output to OutputFile
Result : True on success
Parameters :
CommandLine : the command line for the app, including its full path
InputFile : the ascii file where from the app takes input
OutputFile : the ascii file to which the app's output is redirected
ErrMsg : additional error message string. Can be empty
Error checking : YES
Target : Delphi 2, 3, 4
Author : Theodoros Bebekis, email bebekis@otenet.gr
Notes :
Example call : CreateDOSProcessRedirected('C:\MyDOSApp.exe',
'C:\InputPut.txt',
'C:\OutPut.txt',
'Please, record this message')
-----------------------------------------------------------------------------------}
function CreateDOSProcessRedirected(const CommandLine, InputFile, OutputFile, ErrMsg :string):boolean;
const
ROUTINE_ID = '[function: CreateDOSProcessRedirected ]';
var
OldCursor : TCursor;
pCommandLine : array[0..MAX_PATH] of char;
pInputFile,
pOutPutFile : array[0..MAX_PATH] of char;
StartupInfo : TStartupInfo;
ProcessInfo : TProcessInformation;
SecAtrrs : TSecurityAttributes;
hAppProcess,
hAppThread,
hInputFile,
hOutputFile : THandle;
begin

Result := False;

{ check for InputFile existence }
if not FileExists(InputFile)
then
raise Exception.CreateFmt(ROUTINE_ID + #10 + #10 +
'Input file * %s *' + #10 +
'does not exist' + #10 + #10 +
ErrMsg, [InputFile]);

{ save the cursor }
OldCursor := Screen.Cursor;
Screen.Cursor := crHourglass;

{ copy the parameter Pascal strings to null terminated strings }
StrPCopy(pCommandLine, CommandLine);
StrPCopy(pInputFile, InputFile);
StrPCopy(pOutPutFile, OutputFile);

TRY

{ prepare SecAtrrs structure for the CreateFile calls
This SecAttrs structure is needed in this case because
we want the returned handle can be inherited by child process
This is true when running under WinNT.
As for Win95 the documentation is quite ambiguous }
FillChar(SecAtrrs, SizeOf(SecAtrrs), #0);
SecAtrrs.nLength := SizeOf(SecAtrrs);
SecAtrrs.lpSecurityDescriptor := nil;
SecAtrrs.bInheritHandle := True;

{ create the appropriate handle for the input file }
hInputFile := CreateFile(
pInputFile, { pointer to name of the file }
GENERIC_READ or GENERIC_WRITE, { access (read-write) mode }
FILE_SHARE_READ or FILE_SHARE_WRITE, { share mode }
@SecAtrrs, { pointer to security attributes }
OPEN_ALWAYS, { how to create }
FILE_ATTRIBUTE_TEMPORARY, { file attributes }
0 ); { handle to file with attributes to copy }


{ is hInputFile a valid handle? }
if hInputFile = INVALID_HANDLE_VALUE
then
raise Exception.CreateFmt(ROUTINE_ID + #10 + #10 +
'WinApi function CreateFile returned an invalid handle value' + #10 +
'for the input file * %s *' + #10 + #10 +
ErrMsg, [InputFile]);

{ create the appropriate handle for the output file }
hOutputFile := CreateFile(
pOutPutFile, { pointer to name of the file }
GENERIC_READ or GENERIC_WRITE, { access (read-write) mode }
FILE_SHARE_READ or FILE_SHARE_WRITE, { share mode }
@SecAtrrs, { pointer to security attributes }
CREATE_ALWAYS, { how to create }
FILE_ATTRIBUTE_TEMPORARY, { file attributes }
0 ); { handle to file with attributes to copy }

{ is hOutputFile a valid handle? }
if hOutputFile = INVALID_HANDLE_VALUE
then
raise Exception.CreateFmt(ROUTINE_ID + #10 + #10 +
'WinApi function CreateFile returned an invalid handle value' + #10 +
'for the output file * %s *' + #10 + #10 +
ErrMsg, [OutputFile]);

{ prepare StartupInfo structure }
FillChar(StartupInfo, SizeOf(StartupInfo), #0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.hStdOutput := hOutputFile;
StartupInfo.hStdInput := hInputFile;

{ create the app }
Result := CreateProcess(nil, { pointer to name of executable module }
pCommandLine, { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
True, { handle inheritance flag }
CREATE_NEW_CONSOLE or
REALTIME_PRIORITY_CLASS, { creation flags }
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
ProcessInfo); { pointer to PROCESS_INF }

{ wait for the app to finish its job and take the handles to free them later }
if Result
then
begin
WaitforSingleObject(ProcessInfo.hProcess, INFINITE);
hAppProcess := ProcessInfo.hProcess;
hAppThread := ProcessInfo.hThread;
end
else
raise Exception.Create(ROUTINE_ID + #10 + #10 +
'Function failure' + #10 + #10 +
ErrMsg);

FINALLY
{ close the handles
Kernel objects, like the process and the files we created in this case,
are maintained by a usage count.
So, for cleaning up purposes we have to close the handles
to inform the system that we don't need the objects anymore }
if hOutputFile <> 0 then CloseHandle(hOutputFile);
if hInputFile <> 0 then CloseHandle(hInputFile);
if hAppThread <> 0 then CloseHandle(hAppThread);
if hAppProcess <> 0 then CloseHandle(hAppProcess);
{ restore the old cursor }
Screen.Cursor:= OldCursor;
END;

end;


By: anAKiN Date: 16/06/2003 22:19:00 English  Type : Assist
lol
By: VGR Date: 16/06/2003 23:53:00 English  Type : Comment
yes : it's your code. Isn't it ? You should have commented it :D
By: VGR Date: 16/06/2003 23:54:00 English  Type : Comment
the second one, of course
By: JackNaif Date: 18/06/2003 02:18:00 English French  Type : Comment
Wow, VGR! That was fast.

anAKIN:
since the code for the second function is, to my best knowledge, yours and VGR agrees you also deserve recognition.



Hence, here is what I'm doing:

I'm adding 20 points to the question to award them to anAKIN without diminishing VGR's points because after all, he was extraordinarilly fast and accurate in answering.

Only problem is: I'll only have those 20 points tomorrow :( so you'll have to wait (I'm sorry).


Back to technicalities:

I've been reading SDK helps for quite a few hours, and I believe I have understood all of the code, but just to check: if I use version 2 and want to do something with the output from the DOS program, say, for instance: load it in a memo, then I should not do close it with CloseHandle(hOutputFile); but rather I should first use ReadFile to get the data from it, only then CloseHandle it and then DeleteFile it (by name, not by handle). And as it had FILE_ATTRIBUTE_TEMPORARY it won't even reach the disk (unless it's too big a file or the system is too low in memory or...).
Did I get all that right?

Of course, even before reading your confirmation on this subject (which would of course be greatly appreciated): your first answer is accepted, with an A grade and 20 extra points to anAKIN (all of it tomorrow).
Merci beaucoup:


Jack
By: VGR Date: 18/06/2003 02:23:00 French  Type : Comment
le premier code est le mien, marche très très bien, et n'a pas besoin des complications de l'autre. Il peut même être facilement modifié (deux lignes) pour rediriger entrée et sortie, ce qu'il ne fait pas actuellement.

à++
By: anAKiN Date: 18/06/2003 02:32:00 French  Type : Comment
VGR :-)
pourquoi avez-vous écrit cela en français?
By: VGR Date: 18/06/2003 02:45:00 French  Type : Comment
parce que quand quelqu'un utilise un language que je comprends, j'ai la politesse de l'employer pour lui répondre :D

On me dit "merci", je répond :D :D
By: JackNaif Date: 18/06/2003 17:26:00 English French  Type : Comment
English version below (just in case and for all those who don't know Victor Hugo's language):

Trés bien, on parle français touts le trois mais est ce que quelqu'un d'entre nous est vraiment francophone? (Pas moi). :-)
(J'ai trouvé des mots en français dans les fonctions que VGR a envoyé , et j'ai mis mes propres mots en français "Pour n'être pas moins").
C'est un plaisir quand même pratiquer un peu...
C'est vrai ça: La premiere fonction marche très bien, dont, vous avez touts les points. Les points extra sont une reconnaisance pour anAKIN.
Je n'accept encore la solution parce que j'ai besoin de attendre jusqu' à demain. Maintenant je n'ai que 15 points.
La deuxième fonction aussi marche bien, et la maniere de saisir la sortie du logiciel DOS a beaucoup m'interessé, parce que c'est completement nouvelle pour moi. C' est pour ça que je cherche de la confirmation de l'avoir bien compris.
Je suis ici pour apprendre (même le français) :-)


All right, so all three of us speak French, but is any one of us truly francophone? (Not me) :-)
(I found french words in the functions VGR sent me so I put in my own french words just because I "didn't want to be less").
It's a pleasure to practice a bit anyway...
It's true, the first function works all right, thus, you've got all the points. The extra points are in recognition to anAKIN.
I haven't accepted the solution yet because I need to wait till tomorrow. Right now, I've only got 15 points.
The second function also works all right, and I found very interesting the way of getting the output from the DOS programme, because it's completely new to me. That's why I wanted to confirm I had it right.
I'm here to learn. (even French) :-)




By: anAKiN Date: 18/06/2003 17:30:00 English  Type : Comment
thank you ;-)
By: VGR Date: 18/06/2003 17:44:00 English  Type : Comment
I like your attitude :-)
By: JackNaif Date: 19/06/2003 17:01:00 English  Type : Comment
Promises are debts.
I'm accepting VGR's answer and adding 20 points for anAKIN.

By: JackNaif Date: 19/06/2003 17:03:00 English  Type : Comment
Oh! And I also like your attitudes (both of you) :-)
See you around.

Do register to be able to answer

EContact
browser fav
page generated in 393.931870 milliseconds

Why Google AdSense ads ?

compteur
 Ranking-Hits PageRank for this page