Recent

Author Topic: How To get bin version from my own App?  (Read 373 times)

garlar27

  • Hero Member
  • *****
  • Posts: 593
How To get bin version from my own App?
« on: May 14, 2019, 11:59:07 pm »
Hi everybody!

I have a windowed app and I wish to get the version from console without showing a single form.

Execution from console example:
Quote
C:\MyProject\MyApp> MyFooApp.exe -v
My Foo App version 3.0.5
C:\MyProject\MyApp>

I tried this but I got no output on the console
Code: Pascal  [Select]
  1. var
  2.    ind: Integer;
  3.    AParam: String;
  4. begin
  5.    WriteLn('Does this appears on console?');// NO IT DOESN'T !!!
  6.    if Application.ParamCount > 0 then begin
  7.       WriteLn('ParĂ¡metros: ', Application.ParamCount);
  8.       for ind := 0 to Application.ParamCount -1 do begin
  9.          AParam := Application.Params[ind];
  10.          if SameText(AParam, 'v') then begin
  11.             WriteLn(ProjectVersionString);
  12.             Application.Terminate;
  13.             Exit;
  14.          end;
  15.       end;
  16.    end;
  17.  
  18.    RequireDerivedFormResource := True;
  19.    Application.Initialize;
  20.    Application.CreateForm(TForm1, Form1);
  21.    Application.Run;
  22. end.
  23.  

Does anyone knows how to do it?

ASerge

  • Hero Member
  • *****
  • Posts: 1230
Re: How To get bin version from my own App?
« Reply #1 on: May 15, 2019, 12:59:18 am »
Simple solution. I added lines to the standard project file with comments // <- Add this
Code: Pascal  [Select]
  1. program Project1;
  2. {$APPTYPE CONSOLE}                          // <- Add this
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Windows, SysUtils,                        // <- Add this
  11.   Forms, unit1
  12.   { you can add units after this };
  13.  
  14. {$R *.res}
  15.  
  16. begin
  17.   if FindCmdLineSwitch('v') then            // <- Add this
  18.     Writeln('Some version info')            // <- Add this
  19.   else                                      // <- Add this
  20.   begin                                     // <- Add this
  21.     ShowWindow(GetConsoleWindow, SW_HIDE);  // <- Add this
  22.     RequireDerivedFormResource := True;
  23.     Application.Scaled := True;
  24.     Application.Initialize;
  25.     Application.CreateForm(TForm1, Form1);
  26.     Application.Run;
  27.     ShowWindow(GetConsoleWindow, SW_SHOW);  // <- Add this
  28.   end;                                      // <- Add this
  29. end.
But there are drawbacks - the console window flashes at startup, if the application is not started from the console, and if it is started from the console, the original console is hidden until the program ends.

ASerge

  • Hero Member
  • *****
  • Posts: 1230
Re: How To get bin version from my own App?
« Reply #2 on: May 15, 2019, 01:21:11 am »
Improved version that does not hide the original console if the program is running from it:
Code: Pascal  [Select]
  1. program project1;
  2. {$APPTYPE CONSOLE}
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Windows, SysUtils,
  11.   Forms, Unit1;
  12.  
  13. {$R *.res}
  14.  
  15. function ConsoleOnlyForMe: Boolean;
  16. var
  17.   StorageOnlyForOneId: DWORD;
  18.   Cnt: DWORD;
  19. begin
  20.   Cnt := GetConsoleProcessList(@StorageOnlyForOneId, 1);
  21.   Result := (Cnt = 1);
  22. end;
  23.  
  24. begin
  25.   if FindCmdLineSwitch('v') then
  26.     Writeln('Some version info')
  27.   else
  28.   begin
  29.     if ConsoleOnlyForMe then
  30.       ShowWindow(GetConsoleWindow, SW_HIDE);
  31.     RequireDerivedFormResource := True;
  32.     Application.Scaled := True;
  33.     Application.Initialize;
  34.     Application.CreateForm(TForm1, Form1);
  35.     Application.Run;
  36.   end;
  37. end.

garlar27

  • Hero Member
  • *****
  • Posts: 593
Re: How To get bin version from my own App?
« Reply #3 on: May 15, 2019, 04:36:45 pm »
Thanks ASerge!!! I will try it later since suddenly my work load increased  %)


Is there a way to redirect Writeln to the console?

ASerge

  • Hero Member
  • *****
  • Posts: 1230
Re: How To get bin version from my own App?
« Reply #4 on: May 15, 2019, 07:09:39 pm »
Is there a way to redirect Writeln to the console?
By default, the Output (the default text file for writeln) is already redirected to the console.

440bx

  • Hero Member
  • *****
  • Posts: 795
Re: How To get bin version from my own App?
« Reply #5 on: May 15, 2019, 09:50:00 pm »
Hello Garlar,

Here is another way that doesn't require changing the APPTYPE to CONSOLE.  Do note that there are some disadvantages with it.   The advantage of keeping it as APPTYPE GUI is that the console isn't monopolized until the program ends.

the basic code goes like this:
Code: Pascal  [Select]
  1.   if AttachConsole(ATTACH_PARENT_PROCESS) then
  2.   begin
  3.     { we were started from a console                                          }
  4.  
  5.     ConsoleWindow := GetConsoleWindow();
  6.  
  7.     writeln(ProgramVersion);
  8.     writeln;
  9.  
  10.     // these are needed for the console's prompt to re-appear
  11.  
  12.     FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
  13.  
  14.       PostMessage(ConsoleWindow, WM_KEYDOWN, VK_RETURN, 1);
  15.       PostMessage(ConsoleWindow, WM_KEYUP,   VK_RETURN, 0);
  16.  
  17.     FreeConsole();  { release the console - CTRL-C will not affect the window }
  18.   end;
  19.  
That is a brutally abbreviated piece of code for a GUI app to control its parent's console for its purposes.  The one major problem it doesn't solve is that if multiple instances of the program are started and every instance writes to the console then the output on the console screen will be all jumbled.    It's somewhat rare for that situation to take place, the user has to make it happen.

The one thing that is a minor problem and the solution is not overly complicated is that the "version" string is displayed along with the console's prompt instead of in a line by itself, as it would be, if it were a real console app.   The solution is for the GUI app to write directly to the console's buffer instead of using writeln (which I used to keep the example simple.)

Running the program as a console app has one downside that is easily solved.  If the user presses CTRL-C then your "gui" app is gone.  A real GUI app is immune to CTRL-C.  The solution to that problem is easy, just put a CTRL-C handler that ignores the CTRL-C.  That might make the user unhappy though. :)

Attached is a complete sample of a program that can run as a GUI or a console.  Comment and uncomment the $define at the top to play with it.

Also attached is a screenshot showing what happens when multiple instances of the sample are started in quick succession, look at how the output is "jumbled".  That's because there are three programs writing to one window without any synchronization between them.  The easy but limiting solution is to ensure there can only be one instance of the program running at any time.  The other way is to make the first instance the manager of console window and have all output to the console window go through it so its properly synchronized.

HTH.

ETA:

I should have mentioned that this solution is totally Windows specific.

I should have also mentioned that if the loop start several hundred instances (instead of 3 as I showed), things get royally messed up. :)  If you want to see what happens to Windows when it's running a few _thousand_ processes, this is a way to do it.
« Last Edit: May 15, 2019, 09:57:19 pm by 440bx »
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

garlar27

  • Hero Member
  • *****
  • Posts: 593
Re: How To get bin version from my own App?
« Reply #6 on: May 15, 2019, 11:33:31 pm »
@440bx:

What you did looks like what I need. The plan is stop the app right after displaying de version so there won't be any problem if there are multiple instances (the app also is using UniqueInstance so it will not be more than one instance at the same time).

The idea is to know the binary version from console is mainly to use it for updaters. You can run the app on piped TProces to know the exact version to do the correct actions needed to upgrade. It also can help if you stumble with a binary and want a quick way to identify it.


lucamar

  • Hero Member
  • *****
  • Posts: 1485
Re: How To get bin version from my own App?
« Reply #7 on: May 16, 2019, 12:00:09 am »
The idea is to know the binary version from console is mainly to use it for updaters. You can run the app on piped TProces to know the exact version to do the correct actions needed to upgrade. It also can help if you stumble with a binary and want a quick way to identify it.

For updaters, wouldn't it be easier to just read the VersionInfo resource from the binary, w/out ever running it? And to identify it, the same: just write a specific tool, say VersionOf.exe which reads and shows the VersionInfo resource. It may even work for (Lazarus/FPC) Unix, etc. binaries.

Just saying ... :-[
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4 & 2.0.2 w/FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

garlar27

  • Hero Member
  • *****
  • Posts: 593
Re: How To get bin version from my own App?
« Reply #8 on: May 16, 2019, 01:10:02 am »
For updaters, wouldn't it be easier to just read the VersionInfo resource from the binary, w/out ever running it? And to identify it, the same: just write a specific tool, say VersionOf.exe which reads and shows the VersionInfo resource. It may even work for (Lazarus/FPC) Unix, etc. binaries.

Just saying ... :-[
We are not using the built in versioning system (the one in project options/Versioning).  :-[

440bx

  • Hero Member
  • *****
  • Posts: 795
Re: How To get bin version from my own App?
« Reply #9 on: May 16, 2019, 01:10:39 am »
You can run the app on piped TProces to know the exact version to do the correct actions needed to upgrade. It also can help if you stumble with a binary and want a quick way to identify it.
Redirection and piping don't work when starting a GUI app from a command line interpreter (CLI).  The CLI will create the necessary file(s) but Windows won't pass the handle(s) to the GUI app.  (GetStartupInfo will always give -1 to a GUI app for all the standard handles.) 

If you want piping and/or redirection, Serge's solution is the practical, reasonable, solution.  If you really want your app to be a GUI then Lucamar's suggestion is a reasonable way to go.

If you don't need redirection and/or piping, you could use the sample code I posted.

HTH.








using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.