Languages :: Delphi :: How to run another app, wait till it's done and go on. |
|||
| By: JackNaif |
Date: 15/06/2003 00:00:00 |
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 | 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 | Type : Assist |
|
| lol |
|||
| By: VGR | Date: 16/06/2003 23:53:00 | 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 | Type : Comment |
|
| the second one, of course |
|||
| By: JackNaif | Date: 18/06/2003 02:18:00 | 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 | 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 | Type : Comment |
|
| VGR :-) pourquoi avez-vous écrit cela en français? |
|||
| By: VGR | Date: 18/06/2003 02:45:00 | 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 | 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 | Type : Comment |
|
| thank you ;-) |
|||
| By: VGR | Date: 18/06/2003 17:44:00 | Type : Comment |
|
| I like your attitude :-) |
|||
| By: JackNaif | Date: 19/06/2003 17:01:00 | 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 | Type : Comment |
|
| Oh! And I also like your attitudes (both of you) :-) See you around. |
|||
|
Do register to be able to answer |
|||
©2010 These pages are served without commercial sponsorship. (No popup ads, etc...). Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE.
Please DO link to this page!








