Sign in to follow this  
Followers 0
emendelson

Can a compiled script detect if it was made for CUI or GUI?

12 posts in this topic

I am working on a script that will perform differently if it has been compiled for CUI or for GUI. I would like to use the same script for both versions, and simply compile it twice, once for CUI, once for GUI.

Is it possible for a compiled script to detect whether it has been compiled for the CUI or GUI? Right now I have set the script to detect its own name (whether or not "CUI" is in the filename) and use its CUI-only behavior if it finds "CUI" in its name, but of course this method isn't foolproof. Is there any better method?

Thanks for any help.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

You could define a variable in the scripts that are CUI. Then check if that variable exists using IsDeclared() function.

Edited by Beege

Share this post


Link to post
Share on other sites

emendleson,

Curious as to why this matters?

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

@emendelson

The way I see it you have a couple of options:

a. You could set an appropriate Environment variable in the AutoExec and check that from you script (Look up EnvSet, EnvGet, EnvUpdate in the help file.)

b. Run you app whilst specifying a commandline parameter and have you app check for the parameter and take action accordingly. e.g. MyApp.exe /CUI or MyApp.exe /GUI.

(see $CmdLine and $CmdLineRaw in the help file.)

Regards

DeMo.


Quote of the week:"BASIC programmers never die, they GOSUB and don't RETURN." -- UnknownWisdom of the ages:

  

  • I'd be unstoppable... if not for law enforcement and physics.
  • Marriage, the number 1 cause of divorce.
  • Don't steal... the government hates competition.
  • Irish Government Motto: We’ve got what it takes to take what you’ve got.
  • Birthdays are good for you. Statistics show that the people who have the most live the longest.
  • Failure is not an option. It comes bundled with your Microsoft product.-- Ferenc Mantfeld
  • If you learn from your mistakes, then why ain't I a genius?! -- Anonymous
  • Remember, live every day as if it was your last day! one day you will be right.
  • How is it one careless match can start a forest fire, but it takes a whole box to start a campfire?
  • Sure my system is secure, it just locked up again.
  • I haven't lost my mind; I have a tape back-up somewhere.  ~Author Unknown

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

The way I see it you have a couple of options:

a. You could set an appropriate Environment variable in the AutoExec and check that from you script (Look up EnvSet, EnvGet, EnvUpdate in the help file.)

b. Run you app whilst specifying a commandline parameter and have you app check for the parameter and take action accordingly. e.g. MyApp.exe /CUI or MyApp.exe /GUI.

(see $CmdLine and $CmdLineRaw in the help file.)

Thank you - the second one (command-line switch) is what I'm using now.

As for the reason for doing this: The program (which converts a PCL printfile into PDF format and then prints the PDF) will be used in two different ways - as a program that can be run by a user (or a batch file launched by a user), or as a program that is launched by a Windows service that is owned by the "system", not by an individual user. A program run from a service that is owned by the system cannot interact with any user, so it can't display message boxes and wait for an OK, and it can't use any GUI elements at all, or it will never shut down. So I want the CUI version to write error messages to a log file, while the GUI version will display error messages in message boxes for user interaction.

Edited by emendelson

Share this post


Link to post
Share on other sites

Even if you compile as a CUI AutoIt will still create an internal window.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

As far as I know the value of the PE header at position 0x0154 will become 0x03 if it is a CUI, otherwise 0x02.

Read out the value at the position and you should know whether it is a CUI compiled exe.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Even if you compile as a CUI AutoIt will still create an internal window.

The internal window is perfectly all right for the program that is launched by a service, as long as it doesn't require the user to interact with it, and as long as it closes when the macro exits - which it seems to do.

Share this post


Link to post
Share on other sites

As far as I know the value of the PE header at position 0x0154 will become 0x03 if it is a CUI, otherwise 0x02.

Read out the value at the position and you should know whether it is a CUI compiled exe.

That could be very useful. Can an AutoIt exe read its own file while that file is in use because it the program is running? (I know the answer is that I should try it and see, and will do so as soon as I get back to my development machine. Thank you for this - it sounds like the only foolproof method.

Share this post


Link to post
Share on other sites

The internal window is perfectly all right for the program that is launched by a service, as long as it doesn't require the user to interact with it, and as long as it closes when the macro exits - which it seems to do.

You seem to be failing to see the forest for the trees or you have failed to provide a crucial piece of information. Why do you compile the script as CUI? Why not compile it as GUI and write it correctly so that a single flag is checked before any interactive GUI's are shown? Services can be invoked with command line parameters so it is trivial to setup the service invocation with a /service flag which is processed and sets an internal flag which causes all GUI code to be skipped. No reading the PE header. No separate compilation for special circumstances, et cetera.

Share this post


Link to post
Share on other sites

You seem to be failing to see the forest for the trees or you have failed to provide a crucial piece of information. Why do you compile the script as CUI? Why not compile it as GUI and write it correctly so that a single flag is checked before any interactive GUI's are shown? Services can be invoked with command line parameters so it is trivial to setup the service invocation with a /service flag which is processed and sets an internal flag which causes all GUI code to be skipped. No reading the PE header. No separate compilation for special circumstances, et cetera.

Ah - thank you. I have now done exactly what you suggest, and it works perfectly. Thank you again.

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I liked UEZ's reply for my purpose. I coded up a function "isCompiledGUI.au3" which returns True/False based on the value at position 0x154 of the executable.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Func isCompiledGUI()
;  Detect if running in a compiled GUI
;  returns True and sets @error = 0 if it completely succeeded
;  returns False  and sets @error = 1 if not (@extended gives more insight to a dev)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  Based on a post "Can a compiled script detect if it was made for CUI or GUI?"
; in the AutoIt Forums:
;  UEZ, on 29 December 2011 - 09:29 AM, said:
;  As far as I know the value of the PE header at position 0x0154 will become 0x03 if it is a CUI, otherwise 0x02.
;  Read out the value at the position and you should know whether it is a CUI compiled exe.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#include-once
#include <Constants.au3>
Func isCompiledGUI()
; use (experimental) Static Local vars to allow quicker response on subsequent calls
Static Local $beenrun = False
Static Local $result = False
SetError(0, 1)
If $beenrun Then Return $result
; Check:
; - are we running v3 of AutoIt?  if not, the magic number 0x154 may be wrong
; - if not compiled, don't care
; - if running within AutoIt, bail
; - if can't open, read, or fileseek the executable file in which I'm running, fail
;  - if the value at the magic position is 0x2, succeed!
Local Const $magicPosition = 0x154
Local Const $magicValue = 0x2
If 3 = Floor(@AutoItVersion) Then
  If @Compiled Then
   If 0 = StringInStr(@AutoItExe, "autoit.exe", 0) Then
    Local $exeFileHandle = FileOpen(@AutoItExe, 16)
    If (-1) <> $exeFileHandle Then
     If FileSetPos($exeFileHandle, $magicPosition, $FILE_BEGIN) Then
      Local $byte = FileRead($exeFileHandle, 1)
      If 0 = @error Then
       If $magicValue = $byte Then
        SetError(0, 0)
        $result = True
       Else
        SetError(1, 7)
       EndIf
      Else
       SetError(1, 6)
      EndIf
     Else
      SetError(1, 5)
     EndIf
    Else
     SetError(1, 4)
    EndIf
   Else
    SetError(1, 3)
   EndIf
  Else
   SetError(1, 2)
  EndIf
Else
  SetError(1, 1)
EndIf
$beenrun = True
Return $result
EndFunc   ;==>isCompiledGUI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  test code for function isCompiledGUI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
If 0 < StringInStr(@ScriptFullPath, "\isCompiledGUI.") Then
Local $i
For $i = 1 To 2
  Local $isgui = isCompiledGUI()
  Local $err = @error
  Local $ext = @extended
  Local $msg = @ScriptName
  If $isgui Then
   $msg &= " returned TRUE."
   If $ext > 0 Then $msg &= " (not re-evaluated)"
   SplashTextOn(@ScriptName, $msg)
   Sleep(2000)
  Else
   $msg &= " returned False. "
   If $err > 0 Then
    $msg &= "("
    Switch $ext
     Case 1
      $msg &= "only tested on AutoIT version 3"
     Case 2
      $msg &= "not compiled"
     Case 3
      $msg &= "running within AutoIt.EXE"
     Case 4
      $msg &= "FileOpen failed"
     Case 5
      $msg &= "FileSetPos failed"
     Case 6
      $msg &= "FileRead failed"
     Case 7
      $msg &= "CONSOLE (CUI) app"
     Case Else
      $msg &= "@extended = " & $ext
     EndSwitch
     $msg &= ")"
   EndIf
  EndIf
  ConsoleWrite($msg & @CRLF)
Next
EndIf
Edited by ljcorsa

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0