I've seen some things in what I've been doing that makes me think that how I'm doing my CreateProcess calls could be flawed in some way. I'm not really looking for how to do it, but maybe some ideas on perfecting it. This is perhaps good since I see as many different examples of this online as there are examples posted. Basically no one does it the same way.
Here's what I do. I typically put this stuff into units and do library calls, but I figure putting it all into a program would allow easier testing with respect to making any major changes.
The primary concern I have is shepherding the called program after the fact. To that end, I have coded a boolean flag that is there if I want to wait on the program to complete in my main program. This is what I'm not 100% sure of.
If you notice what I try to do is to set a loop with a delay and try to determine if the program is completed. The problem is that I want to stay out of the way of the called program while I'm doing that.
My thought was the delay loop along with a ProcessMessage call. As the comments go, TApplication.ProcessMessages is the thought I had, but I wanted a VCL-free version of it, so I copied it and removed the VCL parts. The question is if there's a way to test it so I know that it really is working for the called program.
Then perhaps the biggest question that's making me revisit this is the idea of what to do with a hung program that is started by this code. I'm not sure of what would exactly cause the program to hang (or "not respond" in Task Manager speak).
It could be the issue in #1, it could be something else. Perhaps the question is if there's an idea on how best to detect that and deal with it? My first thought was a simple timer, but I'm thinking that there has to be some way that the Task Manager is determining relevant activity that would be more elegant (sending a certain message, looking for a response?).
Then there's the question of how to handle it once detected. The only thing I can think of is to forcibly terminate the process, but I'm not sure if that's best either (and whether it would take out the entire process tree or not, assuming this called program might call something else itself?). Maybe the question in general on this one is whether or not it would be possible to do a decent job of garbage collection in such a case?
And the last and probably best question: Is there another/better approach that could possibly be taken? I know there's some nitpicks in the code that I will likely fix, but beyond that, is there a better approach to take?
Measurement is not management.
Here's what I do. I typically put this stuff into units and do library calls, but I figure putting it all into a program would allow easier testing with respect to making any major changes.
Code:
program testnewcp; uses windows, messages;
type
DWord = Integer;
function ProcessAMsg: Boolean;
{ equivalent to TApplication.ProcessMessages }
var
Msg: TMsg;
msg_proc: boolean;
begin
msg_proc := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
msg_proc := True;
if Msg.Message <> WM_QUIT then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
ProcessAMsg := msg_proc;
end;
procedure ProcessMessage;
begin
while ProcessAMsg do;
end;
function execute_program(ExecuteFile, paramstring: string; var ProcID: DWord;
wait: boolean): DWord;
var
StartInfo : TStartupInfo;
ProcInfo : TProcessInformation;
CreateOK : Boolean;
ErrorCode : DWord;
AppDone : DWord;
begin
ErrorCode := 0;
FillChar(StartInfo,SizeOf(TStartupInfo),#0);
FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
StartInfo.cb := SizeOf(TStartupInfo);
CreateOK := Windows.CreateProcess(nil,
PChar(ExecuteFile + ' ' + paramstring),
nil, nil, False,
CREATE_NEW_PROCESS_GROUP+IDLE_PRIORITY_CLASS+SYNCHRONIZE,
nil, nil, StartInfo, ProcInfo);
WaitForInputIdle(ProcInfo.hProcess, INFINITE);
if CreateOK then
if wait then
begin
repeat
AppDone := WaitForSingleObject(ProcInfo.hProcess, 10);
ProcessMessage;
until AppDone <> WAIT_TIMEOUT;
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end
else
procid := ProcInfo.hProcess;
GetExitCodeProcess(ProcInfo.hProcess, ErrorCode);
Execute_Program := ErrorCode;
end;
var
procid: DWord;
begin
execute_program('C:\Windows\Notepad.EXE', '', procid, true);
end.
The primary concern I have is shepherding the called program after the fact. To that end, I have coded a boolean flag that is there if I want to wait on the program to complete in my main program. This is what I'm not 100% sure of.
If you notice what I try to do is to set a loop with a delay and try to determine if the program is completed. The problem is that I want to stay out of the way of the called program while I'm doing that.
My thought was the delay loop along with a ProcessMessage call. As the comments go, TApplication.ProcessMessages is the thought I had, but I wanted a VCL-free version of it, so I copied it and removed the VCL parts. The question is if there's a way to test it so I know that it really is working for the called program.
Then perhaps the biggest question that's making me revisit this is the idea of what to do with a hung program that is started by this code. I'm not sure of what would exactly cause the program to hang (or "not respond" in Task Manager speak).
It could be the issue in #1, it could be something else. Perhaps the question is if there's an idea on how best to detect that and deal with it? My first thought was a simple timer, but I'm thinking that there has to be some way that the Task Manager is determining relevant activity that would be more elegant (sending a certain message, looking for a response?).
Then there's the question of how to handle it once detected. The only thing I can think of is to forcibly terminate the process, but I'm not sure if that's best either (and whether it would take out the entire process tree or not, assuming this called program might call something else itself?). Maybe the question in general on this one is whether or not it would be possible to do a decent job of garbage collection in such a case?
And the last and probably best question: Is there another/better approach that could possibly be taken? I know there's some nitpicks in the code that I will likely fix, but beyond that, is there a better approach to take?
Measurement is not management.