#Warn: get StdOut from another script

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

#Warn: get StdOut from another script

10 Nov 2018, 18:08

- Has anybody set #Warn to StdOut mode, and been able to retrieve that output from another script?
- Can this be done via AttachConsole and GetStdHandle? As in this scipt. (I couldn't get it to work.) Thanks.
GitHub - joedf/LibCon.ahk: LibCon - AutoHotkey Library For Console Support
https://github.com/joedf/LibCon.ahk
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
burque505
Posts: 1736
Joined: 22 Jan 2017, 19:37

Re: #Warn: get StdOut from another script

10 Nov 2018, 18:52

Hi jeeswg, some small success, still working at it.
Needs stdout2var.ahk, included.
1) warntest.ahk

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

#Include stdout2var.ahk

msgbox % StdOutStream("autohotkey.exe warn.ahk")
2) warn.ahk (this is basically ripped off from the docs for #warn)

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn, All, StdOut  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

g := 1
ShowG() {       ; The warning is displayed even if the function is never called.
    ;global g   ; <-- This is required to access the global variable.
    MsgBox % g  ; Without the declaration, "g" is an empty local variable.
}
3) stdout2var.ahk (from here, I think :?: )
Spoiler
Regards,
burque505
lexikos
Posts: 9599
Joined: 30 Sep 2013, 04:07
Contact:

Re: #Warn: get StdOut from another script

10 Nov 2018, 19:57

A console is used to display output or get input from the user, not to direct output from one process to another. An application can be associated with a console and yet have stdout directed elsewhere. Scripts and other GUI (not console) applications do not have a console by default. You cannot attach to the console of a process that does not have a console.

Even if you were to attach both scripts to the same console, I do not think you can read console output as a stream. Console output buffers are designed to be written into, with that data being displayed in the console window. If you read from the console (CON), you get the user's input, not the program's output. To get the contents of a console, you need to use a function like ReadConsoleOutput, providing the character position to read from.

There is no difference between retrieving stdout from a script with #Warn and retrieving stdout from any other process. There are numerous examples on the forums, and even some in the documentation:

Code: Select all

; Using ExecScript from the docs/Run examples:
MsgBox % ExecScript("#Warn All, StdOut`na:=b+1")

; Using RunWaitOne from the docs/Run examples:
FileAppend % "#Warn All, StdOut`na:=b+1", temp.ahk
MsgBox % RunWaitOne("""" A_AhkPath """ temp.ahk")
FileDelete temp.ahk
These examples rely on WScript.Shell, which does not support Unicode output. If that's not an issue, I would suggest using WScript.Shell directly rather than using these functions as-is. Otherwise, I would suggest using one of the functions found on the forum, or rolling your own with CreateProcess, CreatePipe, etc.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: #Warn: get StdOut from another script

11 Nov 2018, 00:30

- Thanks for the ideas.
- I had thought of ExecScript and RunWaitOne, however, those require that the script that monitors another script, also launches that script.
- So, if it's possible, a monitor script that can retrieve the StdOut from a pre-existing script, would be useful.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
CyL0N
Posts: 211
Joined: 27 Sep 2018, 09:58

Re: #Warn: get StdOut from another script

11 Nov 2018, 01:49

Why not have a script 'monitor' itself...

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn All, Stdout  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

a := b+1

If !InStr(ScriptArg(), "ErrorStdOut"){	;reload script if run without ErrorStdOut...
	rP = "%A_AhkPath%" /ErrorStdOut "%A_ScriptFullPath%"
	StdOutStream( rP, "StdOutStream_Callback" )
	MsgBox, The Original Instance, Now the Monitoring Instance will only exit once Monitored instance is dead...
	ExitApp
}

x := y+1
FileAppend, `n Sth... Else, *

StdOutStream_Callback( data, n ) {		;example func
	Static D
	If n
		ToolTip % D .= data
	Else
		Return "DONE" . ( D := "" )
}

ScriptArg(){
	wmi := ComObjGet("winmgmts:")
	,queryEnum := wmi.ExecQuery("" . "Select * from Win32_Process where ProcessId=" . DllCall("GetCurrentProcessId"))._NewEnum()		;	query to retrieve matching process(es).
	return ( queryEnum[process] ? process.CommandLine : "" )	; return first matching process.
}


StdOutStream( sCmd, Callback := "", WorkingDir:=0, ByRef ProcessID:=0) { ; Modified : maz-1 https://gist.github.com/maz-1/768bf7938e533907d54bff276db80904
	Static StrGet := "StrGet" ; Modified : SKAN 31-Aug-2013 http://goo.gl/j8XJXY
	; Thanks to : HotKeyIt http://goo.gl/IsH1zs
	; Original : Sean 20-Feb-2007 http://goo.gl/mxCdn
	tcWrk := WorkingDir=0 ? "Int" : "Str"
	DllCall( "CreatePipe", UIntP,hPipeRead, UIntP,hPipeWrite, UInt,0, UInt,0 )
	DllCall( "SetHandleInformation", UInt,hPipeWrite, UInt,1, UInt,1 )
	If A_PtrSize = 8
	{
		VarSetCapacity( STARTUPINFO, 104, 0 ) ; STARTUPINFO ; http://goo.gl/fZf24
		NumPut( 68, STARTUPINFO, 0 ) ; cbSize
		NumPut( 0x100, STARTUPINFO, 60 ) ; dwFlags => STARTF_USESTDHANDLES = 0x100
		NumPut( hPipeWrite, STARTUPINFO, 88 ) ; hStdOutput
		NumPut( hPipeWrite, STARTUPINFO, 96 ) ; hStdError
		VarSetCapacity( PROCESS_INFORMATION, 24 ) ; PROCESS_INFORMATION ; http://goo.gl/b9BaI
	}
	Else
	{
		VarSetCapacity( STARTUPINFO, 68, 0 )
		NumPut( 68, STARTUPINFO, 0 )
		NumPut( 0x100, STARTUPINFO, 44 )
		NumPut( hPipeWrite, STARTUPINFO, 60 )
		NumPut( hPipeWrite, STARTUPINFO, 64 )
		VarSetCapacity( PROCESS_INFORMATION, 16 )
	}
	;Tip for struct calculation
	; Any member should be aligned to multiples of its size
	; Full size of structure should be multiples of the largest member size
	;============================================================================
	;
	; x64
	; STARTUPINFO
	; offset size comment
	;DWORD cb; 0 4
	;LPTSTR lpReserved; 8 8(A_PtrSize) aligned to 8-byte boundary (4 + 4)
	;LPTSTR lpDesktop; 16 8(A_PtrSize)
	;LPTSTR lpTitle; 24 8(A_PtrSize)
	;DWORD dwX; 32 4
	;DWORD dwY; 36 4
	;DWORD dwXSize; 40 4
	;DWORD dwYSize; 44 4
	;DWORD dwXCountChars; 48 4
	;DWORD dwYCountChars; 52 4
	;DWORD dwFillAttribute; 56 4
	;DWORD dwFlags; 60 4
	;WORD wShowWindow; 64 2
	;WORD cbReserved2; 66 2
	;LPBYTE lpReserved2; 72 8(A_PtrSize) aligned to 8-byte boundary (2 + 4)
	;HANDLE hStdInput; 80 8(A_PtrSize)
	;HANDLE hStdOutput; 88 8(A_PtrSize)
	;HANDLE hStdError; 96 8(A_PtrSize)
	;
	;ALL : 96+8=104=8*13
	;
	; PROCESS_INFORMATION
	;
	;HANDLE hProcess 0 8(A_PtrSize)
	;HANDLE hThread 8 8(A_PtrSize)
	;DWORD dwProcessId 16 4
	;DWORD dwThreadId 20 4
	;
	;ALL : 20+4=24=8*3
	;============================================================================
	; x86
	; STARTUPINFO
	; offset size
	;DWORD cb; 0 4
	;LPTSTR lpReserved; 4 4(A_PtrSize)
	;LPTSTR lpDesktop; 8 4(A_PtrSize)
	;LPTSTR lpTitle; 12 4(A_PtrSize)
	;DWORD dwX; 16 4
	;DWORD dwY; 20 4
	;DWORD dwXSize; 24 4
	;DWORD dwYSize; 28 4
	;DWORD dwXCountChars; 32 4
	;DWORD dwYCountChars; 36 4
	;DWORD dwFillAttribute; 40 4
	;DWORD dwFlags; 44 4
	;WORD wShowWindow; 48 2
	;WORD cbReserved2; 50 2
	;LPBYTE lpReserved2; 52 4(A_PtrSize)
	;HANDLE hStdInput; 56 4(A_PtrSize)
	;HANDLE hStdOutput; 60  4(A_PtrSize)
	;HANDLE hStdError; 64 4(A_PtrSize)
	;
	;ALL : 64+4=68=4*17
	;
	; PROCESS_INFORMATION
	;
	;HANDLE hProcess 0 4(A_PtrSize)
	;HANDLE hThread 4 4(A_PtrSize)
	;DWORD dwProcessId 8 4
	;DWORD dwThreadId 12 4
	;
	;ALL : 12+4=16=4*4
	If ! DllCall( "CreateProcess", UInt,0, UInt,&sCmd, UInt,0, UInt,0 ; http://goo.gl/USC5a
		, UInt,1, UInt,0x08000000, UInt,0, tcWrk, WorkingDir
		, UInt,&STARTUPINFO, UInt,&PROCESS_INFORMATION )
	{
		DllCall( "CloseHandle", UInt,hPipeWrite )
		DllCall( "CloseHandle", UInt,hPipeRead )
		DllCall( "SetLastError", Int,-1 )
		Return ""
	}
	hProcess := NumGet( PROCESS_INFORMATION, 0 )
	hThread := NumGet( PROCESS_INFORMATION, A_PtrSize )
	ProcessID:= NumGet( PROCESS_INFORMATION, A_PtrSize*2 )
	DllCall( "CloseHandle", UInt,hPipeWrite )
	AIC := ( SubStr( A_AhkVersion, 1, 3 ) = "1.0" ) ; A_IsClassic
	VarSetCapacity( Buffer, 4096, 0 ), nSz := 0
	While DllCall( "ReadFile", UInt,hPipeRead, UInt,&Buffer, UInt,4094, UIntP,nSz, Int,0 ) {
		tOutput := ( AIC && NumPut( 0, Buffer, nSz, "Char" ) && VarSetCapacity( Buffer,-1 ) )
		? Buffer : %StrGet%( &Buffer, nSz, "CP0" ) ; formerly CP850, but I guess CP0 is suitable for different locales
		Isfunc( Callback ) ? %Callback%( tOutput, A_Index ) : sOutput .= tOutput
	}
	DllCall( "GetExitCodeProcess", UInt,hProcess, UIntP,ExitCode )
	DllCall( "CloseHandle", UInt,hProcess )
	DllCall( "CloseHandle", UInt,hThread )
	DllCall( "CloseHandle", UInt,hPipeRead )
	DllCall( "SetLastError", UInt,ExitCode )
	VarSetCapacity(STARTUPINFO, 0)
	VarSetCapacity(PROCESS_INFORMATION, 0)
	Return Isfunc( Callback ) ? %Callback%( "", 0 ) : sOutput
}

live ? long & prosper : regards
lexikos
Posts: 9599
Joined: 30 Sep 2013, 04:07
Contact:

Re: #Warn: get StdOut from another script

11 Nov 2018, 02:13

A "pre-existing" script has already sent all of its load-time warnings to stdout, probably discarding them since stdout hasn't been directed anywhere.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: #Warn: get StdOut from another script

11 Nov 2018, 02:32

- Thanks CyL0N, I'll take a look.
- Thanks lexikos.

- It looks like OutputDebug will be the way to go, so that one script can handle all errors.
- I'm currently using DebugView, (it gathers text in a listview control,) but I'd like to remove the dependency on it. This script is almost complete:
retrieve OutputDebug text - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=58069

- I've found it difficult to find good info for StdIn/StdOut, as evidenced by the 3 queries here: Maxima CAS (wxMaxima): run via the command line - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=56032
- It would be a good subject for a mini-tutorial, to get a fuller understanding.

- Does anyone use StdOut with #Warn? The approach seems to have some limitations, at least for what I'm trying to do, maybe I missed something.
- Although /ErrorStdOut has been very useful e.g.:
numbers/strings in expressions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 37&t=55905
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
burque505
Posts: 1736
Joined: 22 Jan 2017, 19:37

Re: #Warn: get StdOut from another script

11 Nov 2018, 14:02

jeeswg said:
- I had thought of ExecScript and RunWaitOne, however, those require that the script that monitors another script, also launches that script.
- So, if it's possible, a monitor script that can retrieve the StdOut from a pre-existing script, would be useful.
The example below, although I don't believe it meets your needs exactly, might still be useful. It's referencing libraries by FanaticGuru ("GuiVar.ahk"), Relayer ("GuiVar_Class.ahk"), and modified slightly from the example scripts given. Script_1 does NOT retrieve StdOut from a "pre-existing" script, but it does send and receive information from Script_2, manually launched within 10 seconds AFTER Script_1 (and not BY Script_1, although the original script "Script#1) did launch Script#2).

(I still think StdOut2Var as used in my example above and CyLON's as well might prove useful for your purposes.)

The needed files should be in the ZIP attached.
FooBar2.gif
FooBar2.gif (228.71 KiB) Viewed 1611 times
Pass variables.zip
(7.07 KiB) Downloaded 50 times
Regards,
burque505

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Joey5, mikeyww, Proxima, Rohwedder, ziru and 321 guests