Jump to content



Photo

Console.au3 UDF


  • Please log in to reply
47 replies to this topic

#1 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 15 March 2011 - 06:40 PM

Sup,

This isn't really an advanced UDF, but implements a couple of functions and features, with the idea of substituting the original functions like ConsoleWrite() and ConsoleWriteError() and the seriously sketchy ConsoleRead() lol.

Public functions:
  • Cout()
  • Cin()
  • Getch()
  • Cerr()
  • system()
  • RegisterConsoleEvent()
The motive for writing this was the missing ability to read user input from consoles in AutoIt, known as std::cin >> in C++. The UDF's design allows quick and simple access to the functions, without startup / shutdown and handle passing - all this is automatically taken care of. Some users may have know, that you cannot open a console if the script is running from SciTE - this UDF handles that problem, so you can open an console while running scripts through SciTE.

Features:
  • Dynamically opens and closes consoles
  • Use the STDOUT, STDERR and STDIN streams like in other languages.
  • Print coloured/styled text
  • Access the command interpreter through the console.
  • Uses unicode.
  • Register console events.
  • The UDF is designed to work standalone and to have minimal overhead (> 0.1 ms for writing a coloured string)
The UDF supports my style of scripting. I hate long names so standard UDF naming like _Console_WriteConsoleW() is abbreviated to Cout() for now. I also hate having to start up certain UDF's by calling funcs etc., so this is handled first time you call a function. Handles are controlled globally and closed when needed, so you don't need to pass them around lol.

Why would anyone need this?
Good question. I guess this mainly goes out to people with a bit of nostalgia in them. I personally like the feel of a console.

Picture:
Posted Image

Changelog:

  • 25-06-2012
    • Fixed system() to allow case sensitive text.
  • 25-06-2012
    • Fixed typo's.
    • Changed frequent dllcalls to use dllcalladdress for speed.
    • Added RegisterConsoleEvent - functions can be registrered to be called on certain events, like closure of console. This can be used to mimic OnAutoItExit behaviour, that wont be called in case of bad closure.
    • Various optimizations.
  • 09-07-2011
    • Added Getch() function.
    • Better error handling all around.
    • Put back color attribute constants as they are more symbolic imo.
    • Decreased the standard size of Cin allocation (bit harsh to allocate 2 kb memory each time) - it's now changed to 128 chars.
  • 05-06-2011
    • Added color constants thanks to Warmonger.
  • 16-03-2011
    • Fixed Cin() bug.
    • Cin() isn't returning a trailing CRLF anymore.
    • Fixed startup function, so it should run from SciTE now.
  • 15-03-2011 - Initial release.
Notes
I know Matt Diesel was/is working on large, similar UDF, however i wanted something simpler and easier to use. This is the result. Thoughts? Posted Image
Attached File  Console.au3   28.72K   636 downloads

Edited by Shaggi, 06 August 2012 - 03:14 PM.

  • arqstaad likes this
Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG







#2 UEZ

UEZ

    Never say never

  • MVPs
  • 3,614 posts

Posted 15 March 2011 - 09:51 PM

Looks very interesting. Any example available?

Br,
UEZ

 
The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯


#3 ProgAndy

ProgAndy

    You need AutoItObject

  • MVPs
  • 2,508 posts

Posted 15 March 2011 - 10:17 PM

Not bad. I think I'll have to improve my Console UDFs, too :)
*GERMAN* Posted Image [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

#4 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 15 March 2011 - 11:17 PM

Looks very interesting. Any example available?

Br,
UEZ

Thanks and yes, well this is a pretty common example:
AutoIt         
#include <Console.au3> Main() Func Main()     Local $Name     Local $Age     Local $Answer     Local $Continue = True     While $Continue         Cout("Enter your name: ")         Cin($Name)         Cout("Enter your age: ")         Cin($Age)         Cout("Do you want your answers printed in red? y/n: ")         Cin($Answer)         If StringInStr($Answer,"y") Then             Cout(@LF & "Your name is ")             Cout($Name & @LF,$FOREGROUND_RED)             Cout("You were born in ")             Cout(@Year - $Age & @LF,$FOREGROUND_RED)         Else             Cout(@LF & "Your name is ")             Cout($Name & @LF)             Cout("You were born in ")             Cout(@Year - $Age & @LF)         EndIf         $Answer = ""         Cout(@LF & "Do you want to try again? y/n: ")         Cin($Answer)         If StringInStr($Answer,"n") Then             $Continue = False         EndIf     WEnd     system("pause") EndFunc

Not bad. I think I'll have to improve my Console UDFs, too :)

Thanks. :)

Edited by Shaggi, 15 March 2011 - 11:19 PM.

Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

#5 taietel

taietel

    I'm the third from the left...

  • Active Members
  • PipPipPipPipPipPip
  • 722 posts

Posted 16 March 2011 - 03:44 AM

Thanks for sharing Shaggi.

One suggestion: I had an error regarding writting memory, but when I modified it (see below), it worked.
In your Cin function, add this (see the <<<<<<<<<<< sign):
Local $aResult = DllCall($__Dll_Kernel32, "BOOL", "ReadConsoleW", _             "handle", $__ConsoleHandle__Input, _             "ptr", DllStructGetPtr($lpBuffer), _             "dword", DllStructGetSize($lpBuffer), _             "dword*", $lpNumberOfCharsRead, _             "ptr", 0) ;<<<<<<<<<<< ADD THIS


taietel

#6 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 4,042 posts

Posted 16 March 2011 - 08:25 AM

You are right that it is a lot easier to use than mine, as mine is a direct wrapper around the WinAPI. Maybe I'll implement similar functions when I finish my UDF.

It still doesn't work running from SciTE (mine has the same problem). Any idea how to fix that?

I don't know where I'm going, but I'm on my way.


#7 UEZ

UEZ

    Never say never

  • MVPs
  • 3,614 posts

Posted 16 March 2011 - 08:35 AM

Thanks for the example. As taietel said it is crashing but working when I add the line mentioned by him.

Br,
UEZ

 
The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯


#8 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 16 March 2011 - 01:46 PM

You are right that it is a lot easier to use than mine, as mine is a direct wrapper around the WinAPI. Maybe I'll implement similar functions when I finish my UDF.

It still doesn't work running from SciTE (mine has the same problem). Any idea how to fix that?

Well currently mine does (by me, anyway - anyone having trouble with new version?). It opens a new instance of the script around SciTE but still does the checking etc.

As for that last parameter, it should be optional (according to MSDN):
BOOL WINAPI ReadConsole(   __in      HANDLE hConsoleInput,   __out     LPVOID lpBuffer,   __in      DWORD nNumberOfCharsToRead,   __out     LPDWORD lpNumberOfCharsRead,   __in_opt  LPVOID pInputControl );
But i added it anyway in the new release...
Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

#9 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 4,042 posts

Posted 16 March 2011 - 01:59 PM

You should do the command line properly. ShellExecuteWait is not a good solution because (as is the case with me) it doesn't always work.


Edit: It works when I use:
Local $iReturnCode = RunWait(@AutoItExe & ' ' & StringStripWS(StringTrimLeft($CmdLineRaw, StringLen("/ErrorStdOut")), 0x1 + 0x2))

Edited by Mat, 16 March 2011 - 02:00 PM.

I don't know where I'm going, but I'm on my way.


#10 ProgAndy

ProgAndy

    You need AutoItObject

  • MVPs
  • 2,508 posts

Posted 16 March 2011 - 02:15 PM

As for that last parameter, it should be optional (according to MSDN):

Optional means, that it is allowed to be NULL. AFAIK, this parameter has a default value of NULL in the C-headers, so it is not required to add it to the actual function call, but in AutoIt you have to use the complete call.
*GERMAN* Posted Image [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

#11 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 16 March 2011 - 02:44 PM

Optional means, that it is allowed to be NULL. AFAIK, this parameter has a default value of NULL in the C-headers, so it is not required to add it to the actual function call, but in AutoIt you have to use the complete call.

I see :) I haven't experienced a crash yet though... Maybe it depends on os, or length of the input string?

You should do the command line properly. ShellExecuteWait is not a good solution because (as is the case with me) it doesn't always work.


Edit: It works when I use:

Local $iReturnCode = RunWait(@AutoItExe & ' ' & StringStripWS(StringTrimLeft($CmdLineRaw, StringLen("/ErrorStdOut")), 0x1 + 0x2))

Isn't this fixed in the new version? Try redownloading.
Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

#12 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 4,042 posts

Posted 16 March 2011 - 03:57 PM

Yes sorry, it is fixed. There must be a better way to do it than to spawn a new process though...

I don't know where I'm going, but I'm on my way.


#13 hezi

hezi

    Seeker

  • Active Members
  • 34 posts

Posted 16 March 2011 - 05:01 PM

Looks very nice,

can it be used for "expect like" scripting?
running commands in console and wait for output.
it can save me using TKL and use only autoit.

Thanks.

#14 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 16 March 2011 - 11:00 PM

Yes sorry, it is fixed. There must be a better way to do it than to spawn a new process though...

Apparently not.. hm.

Looks very nice,

can it be used for "expect like" scripting?
running commands in console and wait for output.
it can save me using TKL and use only autoit.

Thanks.

Well, something like this?
#include <Console.au3> _Main() Func _Main()     Local $CommandString, $Answer, $Continue = True     While $Continue         Cin($CommandString)         Cout(Execute($CommandString) & @CRLF,$BACKGROUND_GREEN)         Cout(@LF & "Do you want to try again? y/n: ")         Cin($answer)         If $Answer == "n" Then             $Continue = False         EndIf     WEnd     system("pause") EndFunc

Please elaborate, i'm not quite sure i understand you.
Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

#15 ProgAndy

ProgAndy

    You need AutoItObject

  • MVPs
  • 2,508 posts

Posted 17 March 2011 - 09:15 AM

Here is some code I use in the development-version of my console.au3 :) With this, the console should be displayed when running from scite.
If Not @Compiled And StringRegExp($CMDLINERAW, "(?i)(\A|\s)/ErrorStdOut(\s|\Z)") Then         Local $aTmp[3][2] = [["CONIN$", 2],["CONOUT$", 4],["CONERR$", 4]]         For $i = 0 To 2             $GLOBAL_hConsole[$i] = _WinAPI_CreateFile($aTmp[$i][0], 2, $aTmp[$i][1], $aTmp[$i][1])             If $GLOBAL_hConsole[$i] = 0 Then                 If $ExitOnFatal Then _WinAPI_FatalAppExit("GetStdHandle for " & $msg[$i] & " failed")                 Return SetError(2 + $i, 0, 0)             EndIf         Next     Else         For $i = 0 To 2             $GLOBAL_hConsole[$i] = _WinAPI_GetStdHandle($i)             If $GLOBAL_hConsole[$i] <= 0 Then                 If $ExitOnFatal Then _WinAPI_FatalAppExit("GetStdHandle for " & $msg[$i] & " failed")                 Return SetError(2 + $i, 0, 0)             EndIf         Next     EndIf

*GERMAN* Posted Image [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

#16 hezi

hezi

    Seeker

  • Active Members
  • 34 posts

Posted 17 March 2011 - 03:28 PM

Apparently not.. hm.

Well, something like this?

#include <Console.au3> _Main() Func _Main()     Local $CommandString, $Answer, $Continue = True     While $Continue         Cin($CommandString)         Cout(Execute($CommandString) & @CRLF,$BACKGROUND_GREEN)         Cout(@LF & "Do you want to try again? y/n: ")         Cin($answer)         If $Answer == "n" Then             $Continue = False         EndIf     WEnd     system("pause") EndFunc

Please elaborate, i'm not quite sure i understand you.


Thanks, but i think its not what im looking for,

i will try to explain:
my goal is to open cmd window and run command into it, wait for the output and then run the next command, and so on.


the flow should look something like:

run cmd ->
send to console - format x:
wait for output - "Proceed with Format (Y/N)?"
send to console - "N"
wait for output - "c:\" (the prompt)

I want to use it to automate ssh connections, the format is just example... :)

#17 Shaggi

Shaggi

    Universalist

  • Active Members
  • PipPipPipPipPip
  • 296 posts

Posted 17 March 2011 - 04:38 PM

Thanks, but i think its not what im looking for,

i will try to explain:
my goal is to open cmd window and run command into it, wait for the output and then run the next command, and so on.


the flow should look something like:

run cmd ->
send to console - format x:
wait for output - "Proceed with Format (Y/N)?"
send to console - "N"
wait for output - "c:\" (the prompt)

I want to use it to automate ssh connections, the format is just example... :)

Yes, that is possible. However since the system() command blocks, you can't use it like you probably would...
#include <Console.au3> __main() Func __Main()     Local $CommandString, $Answer, $Continue = True, $iReturn     While $Continue         Cout(@CRLF & "Enter your command: " & @CRLF,$FOREGROUND_RED)         Cin($CommandString)         $iReturn = system($commandstring)         Cout(@LF & "Return from system: ")         Cout(" " & $iReturn & @CRLF,$BACKGROUND_GREEN)         Cout(@LF & "Do you want to try again? y/n: ")         Cin($answer)         If $Answer == "n" Then             $Continue = False         EndIf     WEnd     system("pause") EndFunc

Try something like this instead:
AutoIt         
$iHandle = Run("cmd.exe",@ScriptDIr,@SW_HIDE,0x1 + 0x8) Global $lastErr While 1     $Command = GetCommand()     If $LastErr THen ExitLoop     Dispatch($Command)     PrintOutput() Wend StdIoClose($iHandle) Func GetCommand()     Local $ans = InputBox("Command Interpreter","Please enter a command...")     $LastErr = @Error     Return $Ans EndFunc Func Dispatch($szCommand)     StdinWrite($iHandle,$szCommand & @CRLF) EndFunc Func PrintOutput()     $nMsg = StdoutRead($iHandle)     Local $hasBeenRead = False, $Count = 0     While NOT @error         IF $hasBeenRead AND $nMsg == "" Then             $Count += 1             Sleep(100)             If $Count > 10 Then ExitLoop         EndIf         ConsoleWrite($nMsg)         $nMsg = StdoutRead($iHandle)         If $nMsg <> "" Then $hasBeenRead = True         If @Error Then ExitLoop     WEnd EndFunc

Ever wanted to call functions in another process? ProcessCall UDFConsole stuff: Console UDFC Preprocessor for AutoIt OMG

#18 hezi

hezi

    Seeker

  • Active Members
  • 34 posts

Posted 21 March 2011 - 08:15 AM

I think it can work with some modifications,
it will take me some time to try, but you gave me good start.

Thanks!

#19 MvGulik

MvGulik

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 2,795 posts

Posted 23 March 2011 - 09:09 AM

Plugging in your console UDF seemed like a easy way to get colored output in the console I'm using ... but that was a short exercise.

(My exe being a CUI thats using the real windows-dos console. Oops, small communication mismatch on the word 'Console'.)

Still a nice UDF though.
Don't Fall in Love With Ideas"If you fall in love with an idea, you won't see the merits of alternative approaches -- and will probably miss an opportunity or two. One of life's great pleasures is letting go of a previously cherished idea. Then you're free to look for new ones. What part of your idea are you in love with? What would happen if you kissed it goodbye?"

#20 Warmonger

Warmonger

    Wayfarer

  • Banned (NOT IN USE)
  • 63 posts

Posted 18 May 2011 - 08:13 AM

Here's a update to this UDF (Shaggi I hope you don't mind just minor things). You can now use all 255 color combinations in a console, however you cannot Obfuscate your source no longer (bug).

Removed:
$FOREGROUND_X $BACKGROUND_X


Added:
$COLOR_X (1-255)


Posted Image

#include <Console.au3> Dim $COLOR_ For $i = 1 to 255     Cout($i & ' ', $COLOR_ & $i)     Sleep(10) Next While 1 = 1     Sleep(1000) WEnd

Attached Files


Edited by Warmonger, 18 May 2011 - 11:52 AM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users