cmd execution in delphi without freezing - delphi

I have been trying to execute some cmd dos commands within Delphi project with the help of cmd execution function which works well but when the execution is in process the application seems to be like freeze and like blocked till the process is over .. I need help is there any tricks to bypass the process so the application behave normal when execution is in process .
Update from comments:
the function which i am using creates pipe:
if CreatePipe(read_stdout, newstdout, #sa, 0) then begin
GetStartupInfo(si);
with si do begin
dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
wShowWindow := SW_HIDE;
hStdOutput := newstdout;
hStdError := newstdout;
hStdInput := newstdin;
end;
After Google I found a Function here http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_25050763.html
Approach 1: (Author: Marco Pipino) ......
Can anybody help me to modify this function so that enduser not think the application is hanging while performing the command?

Your problem is that you are blocking the main thread. The main thread of an application must process messages in a timely fashion in order to remain responsive.
The right way to tackle this is to start the external process, and then wait for it, from a thread. Doing this ensures that you don't block the main thread. You may well wish to use some inter thread communication to provide user feedback.

As a quick-fix, I'd START the batch, then have it signal completion by creating or deleting a file, eg:
#echo off
setlocal
echo.>"c:\some\filename"
start "title if you want one" yourrealbatch anditsparameters
yourrealbatch should then delete "c:\some\filename" after its finished processing
Then have delphi simply monitor the presence of "c:\some\filename". When it disappears, the batch process is complete.

Related

unelevated program starts an elevated updater, updater should wait for finishing of program

I have 2 apps, program.exe and updater.exe, both written in Delphi5.
Program runs without admin-rights (and without manifest), updater has a manifest with "requireAdministrator" because he must be able to write at Program-Folder to update program.exe.
The problem is to launch updater and let him wait until program is closed.
I've found different ways at the web, but none works (in most cases the 1st app starts 2nd app and wait for ending of 2nd app, in my case 2nd app should wait for ending of 1nd app).
Updater should wait, thats easy
updater.exe
{$R manifest.res}
label.caption:='Wait for program.exe closing';
repeat
sleep(1000);
until File is not open
ProgramHandle := Read Handle from File
WaitForSingleObject(ProgramHandle,INFINITE);
label.caption:='program.exe CLOSED';
Do updates
Way 1
Starting updater with CreateProcess:
program.exe
FillChar(siInfo, SizeOf(siInfo), 0);
siInfo.cb := SizeOf(siInfo);
saProcessAttributes.nLength := SizeOf(saProcessAttributes);
saProcessAttributes.lpSecurityDescriptor := nil;
saProcessAttributes.bInheritHandle := TRUE;
saThreadAttributes.nLength := SizeOf(saThreadAttributes);
saThreadAttributes.lpSecurityDescriptor := nil;
saThreadAttributes.bInheritHandle := True;
if CreateProcess(nil,
PChar('updater.exe'),
#saProcessAttributes,
#saThreadAttributes,
TRUE, NORMAL_PRIORITY_CLASS, nil,
PChar(ExtractFilePath(Application.ExeName)),
siInfo, piInfo) then
begin
DuplicateHandle(GetCurrentProcess, GetCurrentProcess,
piInfo.hProcess, #MyHandle,
PROCESS_QUERY_INFORMATION, TRUE,
DUPLICATE_SAME_ACCESS) then
Write MyHandle in a File
end;
Close program
Doesn't do anything, works only when updater has no manifest with requireAdministrator into.
If i run program with explizit admin-rights, it works too.
Way 2
Starting updater with ShellExecuteEx:
program.exe
FillChar(Info, SizeOf(Info), Chr(0));
Info.cbSize := SizeOf(Info);
Info.fMask := SEE_MASK_NOCLOSEPROCESS;
Info.lpVerb := PChar('runas');
Info.lpFile := PChar('update.exe');
Info.lpDirectory := nil;
Info.nShow := SW_RESTORE;
ShellExecuteEx(#Info);
MyHandle:=OpenProcess(PROCESS_ALL_ACCESS, False, GetCurrentProcessId())));
Write MyHandle in a File
Close program
Doesnt' work, MyHandle has a different value each time i run this procedure (without restarting the program), so updater can't work with it.
So i have no idea how to start updater.exe and write the handle of program.exe in the file.
Im not very familiar with these parts of programing ... does somebody has an idea for my proplem?
Your code is not working because the handle table is per process, which means that the second process could have the same handle pointing to another kernel object. Below, there is one of many possible solutions:
When creating the process 2, pass the PID of the process 1 as parameter:
procedure CreateUpdater;
var
Info: TShellExecuteInfo;
begin
FillChar(Info, SizeOf(TShellExecuteInfo), 0);
Info.cbSize := SizeOf(TShellExecuteInfo);
Info.fMask := SEE_MASK_NOCLOSEPROCESS;
Info.lpVerb := PChar('runas');
Info.lpFile := PChar('Update.exe');
Info.lpParameters := PChar(IntToStr(GetCurrentProcessId));
Info.lpDirectory := nil;
Info.nShow := SW_RESTORE;
ShellExecuteEx(#Info);
//NOTE: MISSING ERROR CHECKING!
end;
Inside the Updater, wait for the process1 to terminate:
procedure WaitForAndClose;
var
PID: String;
AHandle: Cardinal;
Ret: longbool;
ExitNumber: DWORD;
begin
PID:= ParamStr(1);
if PID <> '' then
begin
AHandle:= OpenProcess(PROCESS_QUERY_INFORMATION, False, StrToInt(PID));
//NOTE: MISSING ERROR CHECKING!
try
repeat
Ret:= GetExitCodeProcess(AHandle, ExitNumber);
//NOTE: MISSING ERROR CHECKING!
Sleep(1000); //define a time to poolling
until (ExitNumber <> STILL_ACTIVE);
finally
CloseHandle(AHandle);
end;
//Terminate the process;
Application.Terminate;
end;
end;
You can also use WaitForSingleObject to avoid polling:
WaitForSingleObject(AHandle, INFINITE);
//NOTE: MISSING ERROR CHECKING!
But you need the SYNCHRONIZE access to open the process:
AHandle:= OpenProcess(SYNCHRONIZE, False, StrToInt(PID));
//NOTE: MISSING ERROR CHECKING!
Note: There is no error checking here. You should read the docs and properly check for errors.
Note 2: I would like to get your attention to the fact you are leaking a handle.
When you use SEE_MASK_NOCLOSEPROCESS the caller is responsible to close the handle of the calee. In your case I think you don't need that mask at all. I would remove it.
Here is a basic example of how to achieve this using events:
program.exe:
// manual-reset event, non-signaled
Event := CreateEvent(nil, True, False, 'MyUniqueName');
ExecuteUpdater; // via ShellExecuteEx with runas
// synchronize - wait for the event to be signaled
WaitForSingleObject(Event, INFINITE);
// WAIT_OBJECT_0 = The state of the specified object is signaled.
CloseHandle(Event);
updater.exe:
Event := CreateEvent(nil, True, False, 'MyUniqueName');
if Event = 0 then RaiseLastWin32Error;
SetEvent(Event); // sets the event object to the signaled state
CloseHandle(Event);
You should also add a manifest to program.exe (requestedExecutionLevel should be level="asInvoker") to avoid virtualization.
I see the main problem there in indeterminate order of two events: closing of the program and starting of the updater main code.
One possible way to fix it would be using Events - https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686670(v=vs.85).aspx
The program creates the Event (with an option for the children to inherit it), then launches the updater (passing handles of both the Event and the program's process as integers via the command line to it !), then freezes in WaitForSingleObject on the Event.
This ensures the program would not exit before the updater would be ready to monitor it, so PID would not get invalid.
The updater then calls OpenProcess on the program's PID gained from the command line, then calls SignalAndWait both knocking the Event (gained from the command line) and freezing upon the handle (gained from OpenProcess) - https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686293(v=vs.85).aspx
The program, now being released from waiting upon Event, terminates.
The termination of the process is signalling it, so now the updater gets released in turn and can start doing the main work.
Another approach suggested at C++, How to determine if a Windows Process is running? is querying the exit code of the program ProcessID - it is said that while the program is still running there would be a specific error code and you can Sleep(100) then try again. Any other result means the program already had finished.
The program exits immediately after launching the updater without waiting for it to starting monitoring.
This seems nice approach except that I do not now any warranty that PID values would not be reused. Chances are infinitesimal, but still not zero.
Personally I would probably use a flag file. The CreateFile API has a very interesting flag - the temporary-file mode. It means, Windows would automatically delete the file after process ends. So then
The program creates a new GUID using Windows API (or a new Random Value using Crypto API).
The program creates in the temporary files folder the temporary-mode file with the name based upon the GUID or the Random value. If by any wild luck such a file already exist - you just obtain a new GUID or Random value.
The program launches the updater and passes the filename to it via the command line
The program exits immediately after launching the updater without waiting for it to starting monitoring.
The updater keeps checking if the file exists (making pauses between attempts). When the file does not more exist - that means the program had finished and Windows auto-deleted it.
Again, there is an infinitesimal chance that some other process would create the flag file with exactly the same name in-between the program terminates and the updater checks again, but that is next to impossible in practice

Which is the proper way to terminate a delphi application?

I would like to terminate a Delphi application without executing any other code line and I'm wondering about which is the proper way to do this. Furthermore, I would like to know if there's something wrong in what I'm actually doing at the moment.
Basically, my code looks like this:
//Freeing all objects (Obj1.Free, etc..)
Application.Terminate;
Halt;
Is this the right way to stop a Delphi application or should it be done in another way?
Application.Terminate() breaks the message loops in TApplication.Run() and TForm.ShowModal(), allowing the main thread to exit normally, perform necessary cleanups, etc.
Vcl.Forms.TApplication.Terminate
Ends application execution.
Call Terminate to end the application programmatically. By calling Terminate rather than freeing the application object, you allow the application to shut down in an orderly fashion.
Terminate calls the Windows API PostQuitMessage function to perform an orderly shutdown of the application. Terminate is not immediate.
Terminate is called automatically on a WM_QUIT message and when the main form closes.
Halt(), on the other hand, is an immediate abnormal termination. Basically, ripping the process out of memory. Use it only in extreme situations where no other option is available.
System.Halt
Initiates the abnormal termination of a program.
Halt performs an abnormal termination of a program and returns to the operating system.
To perform a normal termination of a Delphi application, call the Terminate method on the global Application object. If the application does not use a unit that provides an Application object, call the Exit procedure from the main Program block.
I would like to terminate a Delphi application without executing any other code.
Neither Application.Terminate nor Halt will achieve that. The former performs an orderly termination. Lots of code will execute. Calling Halt is more hopeful. That is an abnormal termination. But unit finalization code is executed.
If you wish to exit as quickly as possible, executing the minimum amount of code along the way, call ExitProcess. That's the final step of Halt and by calling ExitProcess directly you avoid all the steps that Halt takes before it calls ExitProcess.
I had some problems with Application.Terminate, because I had to start the Form Close procedure, so I did only:
Form1.Close;
I found a new solution inside .dproj
begin
ReportMemoryLeaksOnShutdown := True;
Application.Initialize;
Application.CreateForm(TFormMain, FormMain);
if Not(VerifyCode()) then
begin
ShowMessage('Software unregistered!');
Application.Terminate;
end
else
Application.Run;
end.
Just to leave a point on a extra problem if code must be on main form OnCreate.
Try such code on the Main Form OnCreate event. It does not work as expected, main form is shown, then the application is finished.
To be able to see it, add another form and put on its creation a long loop.
It seems like all the Application.CreateForm on the main project source are executed.
Sample code:
procedure TMyMainForm.FormCreate(Sender: TObject);
begin
ShowMessage('[1] This must allways be shown');
if mrOK=MessageDlg('Exit?',mtConfirmation,[mbOK,mbCancel],0)
then begin
Application.Terminate;
Exit;
end;
ShowMessage('[2] This must not allways be shown');
end;
procedure TMyOtherForm.FormCreate(Sender: TObject);
begin
ShowMessage('[3] This must not allways be shown');
end;
With that code messages [1] and [3] are allways shown.
Only way to not show [3] is to call Halt.
Note: Why such code on MainForm OnCreate? Simple answer could be, the exe checks conditions to be run and see they are not meet (missing files, etc), rude one (sorry for that), just because i want/need to.
I know this is an old thread, but would appreciate comments on this addition to the thread if anyone is still listening.
For quite some time I have called Application.Terminate followed by ExitProcess(0). My theory is that Application.Terminate does the graceful cleanup, but ExitProcess prevents any other code from executing. It seems to work, and I don't get reports of memory leaks or other ill effects. Code would be something like:
Procedure (KillTheApp);
begin
Application.Terminate;
Application.ProcessMessages;
ExitProcess(0);
end;

How to keep a program responsive while executing Anydac Query?

With sdac I can let the program responsive for user input as :
while Query.Executing do
begin
Application.ProcessMessages;
Sleep(1);
end;
How do I implement the same code with anydac query (there is no similar function)?
I'm using delphi xe2 and anydac v6.
AnyDAC supports different execution modes. To check the current operation status use ADQuery1.Command.State. This is pseudo-code (I don't have Delphi here):
ADQuery1.ResourceOptions.CmdExecMode := amAsync;
ADQuery1.Open;
while ADQuery1.Command.State = csExecuting do
begin
// This is NOT RECOMMENDED
Application.ProcessMessages;
Sleep(1);
end;
However, since the only thing you are doing in your while block is processing GUI messages, I think your best bet is using amNonBlocking mode, which will wait for the query to finish (thus avoiding the while block) but doesn't block the GUI (it does ignore keyboard and mouse events, thought.)
ADQuery1.ResourceOptions.CmdExecMode := amNonBlocking;
ADQuery1.Open;
For more information, see the documentation in the developer's website: Asynchronous Execution.

delphi - terminate all the threads (TThread) on closing application

My application is a tcp/ip server, with main thread created only once & listening all the time. When new client connects, the main thread creates the new thread of TClientThread type. There is however no list of running Client threads, as that would make my app a bit complicated... is there any way to execute "terminate" method on all the threads, even if the thread is busy (in my case "busy" means it's waiting for the data, where the timeout set is about 30 sec ... so I have to kill it anyway, without waiting.)?
The simple closing application seems not to run "terminate" method on the threads, which ends up with memory leaks reported by FastMM...
Memory leaks on shutdown are nothing to worry about - going to the trouble of freeing memory before returning control to the operating system is a waste of time and needlessly slows down application exit. All you really need to do is ensure that all data has been saved, and all interprocess handles (such as semaphores and mutexes) correctly released, and exit away.
For notifying clients, the best you can do would be a strategy somewhat like this:
Add all client-handling threads to some list somewhere (with suitable locking on creation, destruction and iteration)
Make client threads remove themselves from the list upon termination, and have the last item removed from the list set an event (manual reset event, e.g. TEvent in SyncObjs) if the server is shutting down
Introduce polling (e.g. select or equivalent with a timeout) or other kind of interruption (e.g. SO_RCVTIMEO / SO_SNDTIMEO) in what would otherwise be long-running blocking routines, monitoring the Terminated property
On shutdown, lock the list and iterate through it, calling Terminate, and then wait for the event to be signaled; of course, the listening socket which adds items to the list should be closed and known to be closed before iterating through the list
Sounds like this article may help
What you'll see if you click that link:
Using Semaphores in Delphi, Part 2:
The Connection Pool
By: Cary Jensen
Abstract: Semaphores are used to
coordinate multiple threads and
processes. That semaphores provide
multiple threads with simultaneous
access to a shared resource is
highlighted by the
TFixedConnectionPool class described
in this article.
I use a KillThreadList: TList global.
I monitor it in my thread as:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
I also test for the KillThreadList in my processes to let me opt out of them before completion, where safe to do so.
I pass the OnTerminate event out to the Main thread and remove the ThreadID from the KillList there. I use this model extensively and it has not failed me yet.
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
In the case above, I am also removing some GUI stuff.
Hope that helps.
SpringerRider

Added the {APPTYPE CONSOLE} directive and now my application runs very slowly. Moving the mouse makes it run faster

I am trying to extend a 3rd party application so that it can be invoked via command line in addition to using the windows form GUI (mixed mode is desired). It's a fairly simple program which basically loads a file and then you click a button it starts sending UDP network packets.
I need to invoke the application from another and would like to pass in an argument and need to be able to return the ExitCode to the calling app. From what i've read, in order to do so you need to add the compiler directive {APPTYPE CONSOLE}.
I did this and my application worked as I wanted it to except sending the network packets slowed down to a crawl. I found that whenever I moved my mouse around on the form. That the network transfer rate increased significantly. I suspect there is some type of Windows Message queue problem and moving mouse is causing interrupts which in turn is causing the message queue to be processed?
I have googled around and tried calling Application.ProcessMessages and PeekMessages in a Timer with a 1ms interval and that didn't help at all. I found in this user manual for some other application it says that Indy 10 is supported in both APPTYPE CONSOLE and GUI types. Quite frankly this just confuses me as I would have assumed that all network library would work in both modes... but like I said I'm not familiar with Delphi.
I am positive that the issue is isolated to a single line in my application and that is whether or not {APPTYPE CONSOLE} is included or not.
Anyone have any ideas?
Version Info:
Delphi 7 Personal (Build 4.453)
Indy 9.0.4
If you add {APPTYPE CONSOLE} to your application even though you desire mixed mode execution, then you will have to live with a console even when the application is in GUI mode. You can of course close the console, but this will cause some flicker and feels a bit hackish to me.
You should be able to do what you want without a console program. A small test program proves that the exit code can be read from a GUI program:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ExitCode := 42;
Timer1.Interval := 1000;
Timer1.Enabled := TRUE;
end;
If this is executed with the following cmd file:
#echo off
start /WAIT project1.exe
echo %ERRORLEVEL%
the program shows its main form for 1 second, closes, and the script prints 42 to the console window.
Now for capturing the output - doing this from a GUI program is actually easier than doing it from a console program, if you allow for the use of a temporary file. You need to start the program with a command line parameter anyway, so why not give it the name of a temporary file, wait for the application to finish, read in the file and delete it afterwards?
If you want an application to return an "error" code there is no need to make it a console application. You only need to set the ExitCode, e.g.
ExitCode := 10;
in a batch file
#Echo off
project1
echo %errorlevel%
Will display the application, then display 10 when.
Note: It is also possible to create a console window dynamically from the windows API using AllocConsole or to attach using AttachConsole.
I created an object wrapper for this once, but no longer have the code available. From memory it didn't support redirection (because I didn't need it).
If I understand you correctly, then you want your app to have two modes:
If no argument is passed, run in GUI mode
Run in non-GUI mode otherwise
The easiest is if you can centralize your logic so it can be called from one method (CoreLogic in my example).
The below app then should work fine.
Two tricks:
Application.ShowMainForm := False; that will not make the MainForm show at all.
ExitCode := 327; which will set your return code (like mghie and Gerry already mentioned).
A few notes:
because the CoreLogic does not process any windows messages, anything in your application that depends on Windows messages being processed will stall.
if you need windows message processing, then just all Application.ProcessMessages() inside your CoreLogic
if you need your form to be visible, then you change the logic inside your MainForm to test for the commandline parameters, and exit when it's work as been done (by calling Application.Terminate()). The best place to put that logic in is the event method for the MainForm.OnShow event.
Hope this helps :-)
program VCLAppThatDoesNotShowMainForm;
uses
Forms,
MainFormUnit in 'MainFormUnit.pas' {MainForm},
Windows;
{$R *.res}
procedure CoreLogic;
begin
Sleep(1000);
ExitCode := 327;
end;
procedure TestParams;
begin
if ParamCount > 0 then
begin
MessageBox(0, CmdLine, PChar(Application.Title), MB_ICONINFORMATION or MB_OK);
CoreLogic();
Application.ShowMainForm := False;
end;
end;
begin
Application.Initialize();
Application.MainFormOnTaskbar := True;
TestParams();
Application.CreateForm(TMainForm, MainForm);
Application.Run();
end.
A timer with 1ms will only fire about every 40 ms (due to Windows limitations), so it won't help. I have seen effects like you describe with mixed console and GUI apps, another is that they don't minimize properly.
Instead of enabling the console in the project, you could probably use the CreateConsole API call (Not sure whether the name is correct) to create one after the programm was started. I have seen no adverse effects in the one (!) program I have done this.
But this is only necessary if you want to write to the console. If you only want to process command line parameters and return an exit code, you do not need a console. Just evaluate the ParamCount/ParamStr functions for the parameters and set ExitCode for the return value.
If some threads in your console application call Synchronize (and I guess the Indy stuff is actually doing that), you have to make some preparations:
Assign a method to the WakeMainThread variable. This method must have the signature of TNotifyEvent.
Inside this method call CheckSynchronize.
For additional information see the Delphi help for these two items.

Resources