emendelson Posted December 29, 2011 Share Posted December 29, 2011 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. Link to comment Share on other sites More sharing options...
Beege Posted December 29, 2011 Share Posted December 29, 2011 (edited) You could define a variable in the scripts that are CUI. Then check if that variable exists using IsDeclared() function. Edited December 29, 2011 by Beege Assembly Code: fasmg . fasm . BmpSearch . Au3 Syntax Highlighter . Bounce Multithreading Example . IDispatchASMUDFs: Explorer Frame . ITaskBarList . Scrolling Line Graph . Tray Icon Bar Graph . Explorer Listview . Wiimote . WinSnap . Flicker Free Labels . iTunesPrograms: Ftp Explorer . Snipster . Network Meter . Resistance Calculator Link to comment Share on other sites More sharing options...
kylomas Posted December 29, 2011 Share Posted December 29, 2011 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 Link to comment Share on other sites More sharing options...
GerrOrneq Posted December 29, 2011 Share Posted December 29, 2011 @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 Link to comment Share on other sites More sharing options...
emendelson Posted December 29, 2011 Author Share Posted December 29, 2011 (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 December 29, 2011 by emendelson Link to comment Share on other sites More sharing options...
Valik Posted December 29, 2011 Share Posted December 29, 2011 Even if you compile as a CUI AutoIt will still create an internal window. Link to comment Share on other sites More sharing options...
UEZ Posted December 29, 2011 Share Posted December 29, 2011 (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 December 29, 2011 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
emendelson Posted December 29, 2011 Author Share Posted December 29, 2011 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. Link to comment Share on other sites More sharing options...
emendelson Posted December 29, 2011 Author Share Posted December 29, 2011 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. Link to comment Share on other sites More sharing options...
Valik Posted December 29, 2011 Share Posted December 29, 2011 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. Skysnake 1 Link to comment Share on other sites More sharing options...
emendelson Posted December 29, 2011 Author Share Posted December 29, 2011 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. Link to comment Share on other sites More sharing options...
ljcorsa Posted September 26, 2012 Share Posted September 26, 2012 (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.expandcollapse popup;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 September 26, 2012 by ljcorsa Link to comment Share on other sites More sharing options...
Simpel Posted January 18, 2018 Share Posted January 18, 2018 Hi. Sorry for necroposting but I exactly was looking for this. I tried it out and I put my compiled scripts in a hex editor. Value at position 0x154 is always 0x0. I think there will be a lot of changes since that AutoIt version. I guess the $magicPosition in version 3.3.14.2 is 0x16C. Can someone verifiy this? Regards, Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
AspirinJunkie Posted January 18, 2018 Share Posted January 18, 2018 Offset does not mean that it counts from the beginning of the file, but from the beginning of the PE header. At offset 60 (0x3C) is a pointer where the PE header starts in the file. Follow this pointer and from there, the offset should be +92 (+5C) for x86 files. I have just tested this with a file and got the correct result 0x02. Here you can research more about the structure of PE files: https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files Link to comment Share on other sites More sharing options...
Simpel Posted January 18, 2018 Share Posted January 18, 2018 Very interesting I read your link. But in my scripts with v 3.3.14.2 PE header starts at offset 272 (0x110). When I follow this pointer +92 (+5C) then I exactly found the correct result 0x02 for GUI and 0x03 for CUI. Complete offset is 364 (0x16C) as I found out earlier. But why is the offset to PE header larger than it should? Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
AspirinJunkie Posted January 18, 2018 Share Posted January 18, 2018 3 minutes ago, Simpel said: But why is the offset to PE header larger than it should? What do you mean with "should"? The offset depends on the the length of the dos-header. So there doesn't exist a fixed offset. Link to comment Share on other sites More sharing options...
Simpel Posted January 18, 2018 Share Posted January 18, 2018 Ok. So I understood your post and the text following your link wrong: "At offset 60 (0x3C) from the beginning of the DOS header is a pointer to the Portable Executable (PE) File header." I thought DOS header is fixed. Ok, so I have first to search the offset of PE header in my script and then add offset to cui/gui byte +92 (+5C). I'll will try it. Til now I didn't search inside a file in hex but I will find out. Thanks, Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
jguinch Posted January 18, 2018 Share Posted January 18, 2018 Maybe you can just use this : #include <WinAPI.au3> If _IsAutoItGUIMode() Then MsgBox(0, "", "GUI Mode") Else ConsoleWrite("CUI Mode") EndIf Func _IsAutoItGUIMode() Local $iStdHandle = _WinAPI_GetStdHandle ( 2 ) Return ($iStdHandle And @Compiled) ? 0 : 1 EndFunc Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF Link to comment Share on other sites More sharing options...
Simpel Posted January 18, 2018 Share Posted January 18, 2018 Got it. As it should work from shell:sendto I worked only with $CmdLine: expandcollapse popup#include <Constants.au3> If $CmdLine[0] < 1 Then Exit Local $sScriptFullPath = $CmdLine[1] Local $sCompileStyle = _isCUIorGUI($sScriptFullPath) If @error Then MsgBox(0, 'CUI_or_GUI', "There is no valid result." & @CRLF & @CRLF & "Error: " & @error & @CRLF & "Extended: " & @extended) Else MsgBox(0, 'CUI_or_GUI', $sScriptFullPath & @CRLF & "is compiled as: " & $sCompileStyle) EndIf Exit Func _isCUIorGUI($sScriptFullPath) ; parts by ljcorsa Local $result = False SetError(0, 1) Local Const $magicValueGUI = 0x2 Local Const $magicValueCUI = 0x3 Local Const $iOffsetDecPEtoCuiGuiByte = 92 Local $magicPosition If StringInStr($sScriptFullPath, ".exe") Then ; is compiled? Local $exeFileHandle = FileOpen($sScriptFullPath, 16) Local $HeaderSearch = FileRead($exeFileHandle) $HeaderSearch = StringTrimLeft($HeaderSearch, 2) Local $iOffsetDecPEHeader = (StringInStr($HeaderSearch, "50450000") - 1) / 2 ; 50450000 is HEX-Code for PE.. (. means NULL) Local $magicPositionDecimal = $iOffsetDecPEHeader + $iOffsetDecPEtoCuiGuiByte $magicPositionDecimal = Int($magicPositionDecimal) $magicPosition = "0x" & Hex($magicPositionDecimal) If (-1) <> $exeFileHandle Then ; - if can't open, read, or fileseek the executable file in which I'm running, fail If FileSetPos($exeFileHandle, $magicPosition, $FILE_BEGIN) Then Local $byte = FileRead($exeFileHandle, 1) If 0 = @error Then If $magicValueGUI = $byte Then ; - if the value at the magic position is 0x2, succeed! SetError(0, 0) $result = "GUI" ElseIf $magicValueCUI = $byte Then ; - if the value at the magic position is 0x3, succeed! SetError(0, 0) $result = "CUI" 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 Return $result EndFunc Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now