Recent

Author Topic: [Solved] Executing Applications with DOS Window  (Read 6145 times)

OLLI_S

  • Full Member
  • ***
  • Posts: 119
[Solved] Executing Applications with DOS Window
« on: October 01, 2018, 10:33:13 pm »
Hello,

In my Lazarus application I want to add two buttons that start an external app:
  • The first button should start the external application with a command window
  • The second button should start the same app without the command window

More Details:
I have an application (from a 3rd company) that is installed in C:\Program Files (x86)
This application also allows to start with parameters.
So I created a batch file that starts the following command:

Code: Diff  [Select][+][-]
  1. "C:\Program Files (x86)\Company\application.exe" --parameter

When I execute the batch file, then I see a lot of text in the command shell.

Execution showing a Command shell
My first button should start the application and also show a command shell (so users see the output).
Is it possible to leave the command shell opened (like the DOS command "pause" so users have to press a key to close the command shell.
And my button should be disabled until the command shell is opened (the process is running).
Edit: I do not want to deliver an additional batch file, just my EXE compiled with Lazarus.

Execution without  a Command shell
The second button should start the application with a second parameter (that suppresses all output).
Here no command shell should be shown but I need a feedback when the application is finished (so I can show a little animation and stop it when the process stops).

I really have no idea how to perform this.
So I hope you can help me.

Best regards

OLLI
« Last Edit: October 16, 2018, 11:01:43 pm by OLLI_S »

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Executing Applications with DOS Window
« Reply #1 on: October 01, 2018, 11:32:19 pm »
I believe what you are looking for is "TProcess" and maybe "TProcessUTF8"

 its on the system tab believe.

The only true wisdom is knowing you know nothing

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #2 on: October 01, 2018, 11:54:59 pm »
Hello Jamie,

thank you very much, I will play with the TProcess component!

Best regards

OLLI

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #3 on: October 03, 2018, 03:23:09 pm »
I believe what you are looking for is "TProcess" and maybe "TProcessUTF8"
 its on the system tab believe.

Thank you very much, the TProcess is exactly what I needed!

How can I mark here a topic as "Solved"?
« Last Edit: October 03, 2018, 03:24:51 pm by OLLI_S »

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Executing Applications with DOS Window
« Reply #4 on: October 03, 2018, 03:59:53 pm »
How can I mark here a topic as "Solved"?

When you are logged in, you can "Modify" the headline of your 1st post and insert [SOLVED] at the beginning.

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #5 on: October 03, 2018, 10:59:46 pm »
One last question:
The app that I am starting requires to be started as administrator.
Is there a way to start the app via TProcess as administrator?
So users can start my app as normal users and when they want to start the external app then the get the UAC window shown.

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #6 on: October 06, 2018, 11:12:26 am »
I found the solution here:
http://wiki.freepascal.org/Executing_External_Programs#Using_ShellExecuteEx_for_elevation.2Fadministrator_permissions

But now I have an other question:
When I start a process with the function RunAsAdmin how can I check if the process is still running?

I have a button that starts the process.
When I click the button, I disable it, start a timer (1 second interval) and execute the process.
In OnTimer I want to check if the process is still running and if not, I want to show a message, stop the timer and enable the button.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Executing Applications with DOS Window
« Reply #7 on: October 06, 2018, 04:46:46 pm »
You need to use a "WaitForSingleObject(processHandle, INFINITE)" in a thread if you don't want the
rest of your app to hang there.

 The ProcessHandle is return via the Shell Commands..
If you can translate this... This is the closes example I could find to..
I think you can handle it..  ;)
http://www.thescarms.com/VBasic/wait.aspx
The only true wisdom is knowing you know nothing

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #8 on: October 07, 2018, 11:06:57 am »
Hello jamie,

thank you for your answers.

If I read the VB code correctly then the application, that is calling an other application, is frozen until the called process is terminated.
This is not what I need, my application must be controllable while the other app is running.

I think I have to explain more details.
I am programming a little tool for a security application called VulnDetect (the upcoming replacement for Secunia PSI, the Personal Software Inspector).
VulnDetect scans your computer for installed applications and tells you when you have applications that have known vulnerabilities.
So users are encouraged to install the latest version without the vulnerabilities.

VulnDetect scans the PC automatically once per day, there is no GUI.
So users can start the manual scan only via a command and this process must be run in administrator mode.
Otherwise some information can not be gathered.

So I coded a little tool for users so they can start the scan with a single mouse click.
But I offer some other features (this is the reason why my tool needs to be controllable while the scan is running).

First I used the TProcess control and here everything seemed to be perfect:
I started the scan (the process) and disabled the "Scan" button, so users can not start a second scan (but use all other buttons and controls).
I also used a timer with the interval 1 second to check if the process is still running:

Code: Pascal  [Select][+][-]
  1. if prcFullScan.Running = false then begin
  2. // Process no more running, so here is some code like enable the buttons, stop the timer and play a beep sound
  3. end;

The only problem is that the process was started without Administrator rights.
So the perfect solution would be to start the scan with the TProcess with Administrator rights.
Is that possible?

I did not find a way so I used the RunAsAdmin function that is found here:
http://wiki.freepascal.org/Executing_External_Programs#Using_ShellExecuteEx_for_elevation.2Fadministrator_permissions

So the scan process is running in administrator mode but now I need a way to check if the process is still running.
And my application must be controllable while the process is running.

Thank you for your help!

Best regards

OLLI

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Executing Applications with DOS Window
« Reply #9 on: October 07, 2018, 04:37:20 pm »
understood...

 Which is why I said "IN A TRHEAD"

 Create a thread class to do all of this for  you and use a Wait object..
 
 Your main thread in your app will still be operating and you can use a Synchronize call
 in the thread to condition a LCL/Control the way you would like.

 Look for example on TThread, you need to create a Class based from that and the procedure
within that thread can do all of the file control you are using and then sit there using the
process handle to monitor the closing of the remote EXE using the Wait object without stalling your
main app.
The only true wisdom is knowing you know nothing

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #10 on: October 08, 2018, 08:41:42 pm »
Hello jamie,

at the moment I start the scan as administrator and if users click the button a second time it is their fault.

I am really not good enough to code what you suggested...
I am a beginner...

OLLI
« Last Edit: October 09, 2018, 08:17:36 pm by OLLI_S »

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Executing Applications with DOS Window
« Reply #11 on: October 10, 2018, 05:13:10 pm »
I have no knowledge about threads. But if I understand your problem right, you only want to check if a certain process is now running or not. In http://wiki.lazarus.freepascal.org/Windows_Programming_Tips#Showing.2Ffinding_processes you find how to detect whether your EXE is running or not. Hope that helps you.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Executing Applications with DOS Window
« Reply #12 on: October 11, 2018, 12:36:28 am »
I typed up something for you to study.
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Windows,shellapi,Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  9.   StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     procedure Button1Click(Sender: TObject);
  19.     procedure Button2Click(Sender: TObject);
  20.   private
  21.  
  22.   public
  23.  
  24.   end;
  25. TMyThread = Class(TThread)
  26.   Private
  27.    fFileName :WideString;
  28.    Sh:ShellExecuteInfoW;
  29.   Public
  30.   procedure Execute Override;
  31.   Procedure CleanUp;
  32.   constructor Create(FileName:WideString);
  33.   End;
  34. var
  35.   Form1: TForm1;
  36.   MyThread:TMyThread;
  37. implementation
  38.  
  39. {$R *.lfm}
  40.  
  41. { TForm1 }
  42. Procedure TMyThread.Execute;
  43.  Begin
  44.    FillChar(Sh, SizeOf(Sh),0);
  45.    Sh.cbSize:= SizeOf(Sh);
  46.    Sh.fMask := SEE_MASK_NOCLOSEPROCESS;
  47.    Sh.lpVerb := WideString('RunAs');
  48.    Sh.LpFile := pWideChar(fFileName);
  49.    Sh.nShow := SW_SHOWNORMAL;
  50.    Form1.Caption := PWideChar(Sh.LpFile);
  51.    If ShellExecuteExW(@Sh)= True Then
  52.    Begin
  53.      While (WaitForSingleObject(Sh.hProcess, 1000) = WAIT_TIMEOUT)and(Not Terminated) Do;
  54.      if Terminated Then TerminateProcess(Sh.HProcess, 0);
  55.    End;
  56.    Synchronize(@CleanUp);
  57.  end;
  58. Procedure TMyThread.Cleanup;
  59. Begin
  60.   Form1.Button2.OnClick(Self);
  61. end;
  62.  
  63. Constructor TMyThread.Create(FileName:WideString);
  64. Begin
  65.   fFileName := FileName;
  66.   Inherited Create(True); //Suspend Thread, don't start yet.
  67. end;
  68.  
  69. procedure TForm1.Button1Click(Sender: TObject);
  70. begin
  71.   Button1.Enabled := false;
  72.   MyThread := TMyThread.Create('c:\Windows\System32\notepad.exe');
  73.   MyThread.FreeOnTerminate := True;
  74.   MyThread.Start;
  75. end;
  76.  
  77. procedure TForm1.Button2Click(Sender: TObject);
  78. begin
  79.   if (Assigned(MyThread))and(MyThread.Terminated= False) Then MyThread.Terminate;
  80.   MyThread := Nil;
  81.   Button1.Enabled := True;
  82. end;
  83.  
  84. end.
  85.  
  86. There are other things you can add but this does work for me. for you, you'll need to change the code a bit to pass the correct file name you need.
  87. I may have missed some other details in the ShellExecute setup but this is a good start for you.
  88.  
  89.  
The only true wisdom is knowing you know nothing

OLLI_S

  • Full Member
  • ***
  • Posts: 119
Re: Executing Applications with DOS Window
« Reply #13 on: October 11, 2018, 10:51:07 pm »
I have no knowledge about threads. But if I understand your problem right, you only want to check if a certain process is now running or not. In http://wiki.lazarus.freepascal.org/Windows_Programming_Tips#Showing.2Ffinding_processes you find how to detect whether your EXE is running or not. Hope that helps you.

Hello Hartmut,

yesterday evening I added your code and this is working perfectly.
In my timer I check if the process is existing and if not, the scan was finished.
Works perfectly!

Just one question about the code shown in http://wiki.lazarus.freepascal.org/Windows_Programming_Tips#Showing.2Ffinding_processes

I used everything except this line:
Code: Pascal  [Select][+][-]
  1. function QueryFullProcessImageNameW(hProcess: HANDLE; dwFlags: DWORD; lpExeName: LPTSTR; var lpdwSize: DWORD): BOOL; stdcall; external 'KERNEL32';

What is this line for?


Hello jamie,

I really feel bad that I did not post already yesterday that I found a solution (but I was busy with coding and then my wife told me to stop).
This would have saved you much work (and this is the reason why I feel bad).

But I keep the link to this posting in my source code so when I need something with processes then I will come back.
And other users benefit from this code too.

Sorry again!

Best regards

OLLI

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Executing Applications with DOS Window
« Reply #14 on: October 12, 2018, 08:03:22 pm »
I used everything except this line:
Code: [Select]
function QueryFullProcessImageNameW(hProcess: HANDLE; dwFlags: DWORD; lpExeName: LPTSTR; var lpdwSize: DWORD): BOOL; stdcall; external 'KERNEL32';What is this line for?

Sorry, I don't know. This is not my code, I only used it in one of my programs and skipped this line too. I suppose this is a relict from the developer which is not needed.

 

TinyPortal © 2005-2018