Jump to content
Sign in to follow this  
luckyluke

Dllcall - console attach to read output from CMD error

Recommended Posts

Hello,

Im trying to read the output from CMD using Dllcall, here is my code:

#include <WinAPI.au3>
#include <array.au3>
Global Const $STD_OUTPUT_HANDLE = -11
Global Const $_CONSOLE_SCREEN_BUFFER_INFO = _
             "struct;int dwSizeX;" & _
             "short dwSizeY;" & _
             "short dwCursorPositionX;" & _
             "short dwCursorPositionY;" & _
             "short wAttributes;" & _
             "short Left;" & _
             "short Top;" & _
             "short Right;" & _
             "short Bottom;" & _
             "short dwMaximumWindowSizeX;" & _
             "short dwMaximumWindowSizeY;endstruct"

$pCmd = Run( "cmd.exe" )
Sleep(1000)
$hCmd = WinGetHandle("")
ConsoleWrite('handle:' & $hCmd & @CRLF)

$aRet = DllCall("kernel32.dll", "int", "AttachConsole", "dword", $pCmd)
;_ArrayDisplay($aRet)
If $aRet[0] <> 0 Then
    $vHandle_data=''
    $vHandle=''

    $vHandle_data = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure

    $aRet1 = DllCall("kernel32.dll", "hwnd", "GetStdHandle", "dword", $STD_OUTPUT_HANDLE)
    if not @error Then $vHandle =  $aRet1[0]

    $aRet = DllCall("kernel32.dll", "int", "GetConsoleScreenBufferInfo", "hwnd", $vHandle, _
        "ptr", $vHandle_data)

    MsgBox(0, '1',DllStructGetData($vHandle_data, 'dwSizeX') & _WinAPI_GetLastErrorMessage())
EndIf

It did not work, i got the message 'The handle is invalid'. Please help?

Thank you in advance!

Share this post


Link to post
Share on other sites

Or you can also give Process UDF a try, you can get the output with a single line of code.


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites
8 hours ago, Jos said:

Why not simply use the standard supported StdoutRead() & StderrRead() in combination with Run()?

Jos 

Yes, that is the common way, i tried it, but it does not capture all output from the cmd. That why i want to try with console attach

 

7 hours ago, TheDcoder said:

Or you can also give Process UDF a try, you can get the output with a single line of code.

Your code is using the Stdreadout, i tried it before but it did not work. 

Share this post


Link to post
Share on other sites

Are you trying to read output directly from cmd.exe?


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites
49 minutes ago, TheDcoder said:

Are you trying to read output directly from cmd.exe?

Do you mean read from cmd.exe using StdoutRead, yes it can read output from cmd but not all things. I have an other program run using CMD, it will out the result to CMD, then i used StdoutRead to read from cmd, but can not get all result from there.

 

Share this post


Link to post
Share on other sites
1 hour ago, luckyluke said:

it can read output from cmd but not all things

I suspect that the program which outputs to the CMD is also using StdErr stream. You should try using the $STDERR_MERGED flag, the _Process_RunCommand function from Process UDF automatically does that for you by default :)

Edited by TheDcoder

A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites
6 minutes ago, TheDcoder said:

I suspect that the program which outputs to the CMD is also using StdErr stream. You should try using the $STDERR_MERGED flag, the _Process_RunCommand function from Process UDF automatically does that for you by default :)

yes, i tried, but not work. I see that if i close the program then it will show the message in the output. but if i run it from cmd, the message appears even when program is running.

Share this post


Link to post
Share on other sites
7 minutes ago, luckyluke said:

but if i run it from cmd, the message appears even when program is running.

If that is the case, then you can try calling the program from instead of directly calling it. You can do it like this in my UDF:

$sOutput = _Process_RunCommand($PROCESS_RUNWAIT, $PROCESS_COMMAND & 'path_to_your_program.exe') ; This will execute cmd.exe which will run your program

This way, cmd.exe acts like a proxy between the AutoIt script and the program. You should be able to read all output given to cmd.exe if you use the above code snippet

Edited by TheDcoder
Add $sOutput to the code snippet

A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites

I have a look at Process UDF, the code seems complicated.

Try this simple one:

Local $iCommand = "ping google.com"

_RunCmd($iCommand)
_RunCmd_GetStdOut($iCommand)


Func _RunCmd($sCommand)
    ConsoleWrite("+ Execute: " & $sCommand & @CRLF)
    Local $sOutput = '', $iPID = Run('"' & @ComSpec & '" /c ' & '"' & $sCommand & '"', '', @SW_HIDE, 0x6)
    If Not $iPID Then Return SetError(1, 0, '')
    Do
        $sOutput &= StdoutRead($iPID)
    Until @error
    Do
        $sOutput &= StderrRead($iPID)
    Until @error
    ConsoleWrite("" & $sOutput & @CRLF)
    ConsoleWrite("- -------------------------------------------------------------" & @CRLF)
    Return $sOutput
EndFunc   ;==>_RunCmd

Func _RunCmd_GetStdOut($sCommand, $sDir = '', $iType = 0x6, $bShow = False, $iDelay = 50)
    ConsoleWrite("+ Execute: " & $sCommand & @CRLF)
    Local $sTMP = '', $sOutput = ''
    Local $iPID = Run('"' & @ComSpec & '" /c ' & '"' & $sCommand & '"', $sDir, $bShow ? @SW_SHOW : @SW_HIDE, $iType)
    If Not $iPID Then Return SetError(1, 0, '')
    While 1
        $sTMP = StdoutRead($iPID, False, False)
        If @error Then ExitLoop 1
        If $sTMP <> "" Then
            $sTMP = StringReplace($sTMP, @CR & @CR, '')
            $sOutput &= $sTMP
            ConsoleWrite($sTMP)
            Sleep($iDelay)
        EndIf
    WEnd
    While 1
        $sTMP = StderrRead($iPID, 0, 0)
        If @error Then ExitLoop
        If $sTMP <> "" Then
            $sTMP = StringReplace($sTMP, @CR & @CR, '')
            $sOutput &= $sTMP
            ConsoleWrite($sTMP)
            Sleep($iDelay)
        EndIf
    WEnd
    ConsoleWrite("- -------------------------------------------------------------" & @CRLF)
    Return $sOutput
EndFunc   ;==>_RunCmd_GetStdOut

 


Regards,
 

Share this post


Link to post
Share on other sites
4 hours ago, luckyluke said:

yes, i tried, but not work. I see that if i close the program then it will show the message in the output. but if i run it from cmd, the message appears even when program is running.

Show your code and info on the program running so we can see what might be the issue.

Jos


SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
7 hours ago, TheDcoder said:

If that is the case, then you can try calling the program from instead of directly calling it. You can do it like this in my UDF:

$sOutput = _Process_RunCommand($PROCESS_RUNWAIT, $PROCESS_COMMAND & 'path_to_your_program.exe') ; This will execute cmd.exe which will run your program

This way, cmd.exe acts like a proxy between the AutoIt script and the program. You should be able to read all output given to cmd.exe if you use the above code snippet

This code will get the output when the program ends. But i want to get the status when the program is running.

 

3 hours ago, VIP said:

I have a look at Process UDF, the code seems complicated.

Try this simple one:

 

Yes, i found it and tried it before. But the code actually get the output after the program exit. I want to get the console while the program is running.

this is my code:

the code will open the CMD and run "python ui.py" then get the output from console.

#include 'array.au3'
;#include "UIAWrappers.au3"

Global $DOS, $timer, $whd

$live_file = IniRead(@ScriptDir & '\config.ini', 'py_run', 'live_file', '')
$prediction_file = IniRead(@ScriptDir & '\config.ini', 'py_run', 'prediction_file', '')
$training_file = IniRead(@ScriptDir & '\config.ini', 'py_run', 'training_file', '')
$wait_time = IniRead(@ScriptDir & '\config.ini', 'py_run', 'wait_time', 6)
FileDelete(@ScriptDir & '\pyConsole.txt')

startPY()
Sleep(1000)
$checker = 1
$i = 1
While 1
    $tmp = ControlGetText('python.exe', '', 'Button1')
    if StringInStr($tmp, 'check online for a solution') Then
        WinClose('python.exe')
        Sleep(3000)
        startPY()
    EndIf

;~  Sleep(50) ;; no need to go at full speed here.
;~  $sOutput=''
;~  While 1
;~         $sOutput &= StdoutRead($DOS, False, False)
;~         If @error Then
;~             ExitLoop
;~         EndIf
;~         Sleep(10)
;~      ConsoleWrite($sOutput)
;~     WEnd

    $Message = StdoutRead($DOS) ;; ditched peek parameter + changed "=" to "&=" ... No more endless loop.
    if @error Then
        restartPY()
        startPY()
    EndIf

    ;$sOutput = StderrRead($DOS)
    ;ConsoleWrite($i & ':' & $sOutput & ',' & StringLen($sOutput) & @CRLF)
    ConsoleWrite($i & ':' & $Message & ',' & StringLen($Message) & @CRLF)
    $i=$i+1
    if StringLen($Message)>2 and StringInStr($Message, @CRLF) Then
        ConsoleWrite('i:' & $i & ',' & $Message & @CRLF)
        ;$i=$i+1
        if StringInStr($Message, ',') Then
            $tmp = StringSplit($Message, @CRLF)
            ;_ArrayDisplay($tmp)
            if not @error Then
                for $j = 1 to UBound($tmp)-1
                    if StringInStr($tmp[$j], ',') Then
                        $file = FileOpen(@ScriptDir & '\pyConsole.txt', 1)
                        FileWrite($file, $tmp[$j] & @CRLF)
                        FileClose($file)
                    EndIf
                Next
            EndIf
        EndIf
        $checker=1
    Else
        $checker = $checker+1
        ;ConsoleWrite('checker:' & $checker & @CRLF)
        if $checker=10 Then
            $timer = TimerInit()
        EndIf
    EndIf

    if $checker>=10000 Then
        $atime = TimerDiff($timer)/1000
        if not @error Then
            if $atime>Number($wait_time) Then
                restartPY()
                startPY()
            EndIf
        EndIf
    EndIf
    if @error then exitloop
WEnd

Func restartPY()
    Do
        if WinExists('C:\Windows\system32\cmd.exe') then
            WinClose('C:\Windows\system32\cmd.exe')
        Else
            ExitLoop
        EndIf
    Until WinExists('C:\Windows\system32\cmd.exe')=0

    WinActivate('Predictive model 1.0')
    Sleep(500)
    WinClose('Predictive model 1.0')
    WinWait('Confirm Exit', '', 3)
    WinActivate('Confirm Exit')
    WinMove('Confirm Exit', '', 0, 0)
    Sleep(500)
    if WinExists('Confirm Exit') then MouseClick('left', 109,94)
    Sleep(4000)
EndFunc

Func startPY()

    $CMD = 'cd ' & @DesktopDir & '\Predictive_model && ' & _
        'python ui.py'
    $DOS = Run(@ComSpec & ' /C ' & $CMD, @ScriptDir, @SW_SHOW, $STDOUT_CHILD+$RUN_CREATE_NEW_CONSOLE)
    ;$DOS = Run(@ComSpec & ' /C ' & $CMD, @ScriptDir, @SW_SHOW, $STDIN_CHILD + $STDERR_MERGED)
    ConsoleWrite($DOS & @CRLF)

    $mtitle = 'Predictive model 1.0'
    WinWait($mtitle, '', 5000)
    ;Sleep(5000)


    WinMove($mtitle, '', 0, 0)
    Sleep(1000)

    ;=====================================set value to GUI=================================================
    ;live file
    ;_UIA_Action("Title:=;controltype:=UIA_EditControlTypeId;class:=","setfocus")
    ;_UIA_Action("Title:=;controltype:=UIA_EditControlTypeId;class:=","setValue using keys", "C:\Users\Administrator\Desktop\Sabrina Betting\LV1.txt")
    WinActivate($mtitle)
    Sleep(1000)
    MouseClick('left', 345,87)
    Send("^a")
    Sleep(500)
    Send($live_file  & '11')

    ;prediction file
    WinActivate($mtitle)
    Sleep(1000)
    MouseClick('left', 345,200)
    Send("^a")
    Sleep(500)
    Send($prediction_file)
    ;use control click
    WinActivate($mtitle)
    Sleep(1000)
    MouseClick('left', 345,234)
    Send("^a")
    Sleep(500)
    Send($training_file)

    ;click start button
;~  Local $oP1=_UIA_getObjectByFindAll($UIA_oDesktop, "Title:=Predictive model 1.0;controltype:=UIA_WindowControlTypeId;class:=QWidget", $treescope_children)
;~  Local $oP0=_UIA_getObjectByFindAll($oP1, "Title:=;controltype:=UIA_CustomControlTypeId;class:=", $treescope_children)
;~  Local $oUIElement=_UIA_getObjectByFindAll($oP0, "title:=Start;ControlType:=UIA_ButtonControlTypeId", $treescope_subtree)
;~  _UIA_action($oUIElement,"focus")
;~  _UIA_action($oUIElement,"click")
    WinActivate($mtitle)
    Sleep(1000)
    MouseClick('left', 593,301)
    Sleep(3000)
EndFunc

 

Share this post


Link to post
Share on other sites
1 minute ago, luckyluke said:

This code will get the output when the program ends. But i want to get the status when the program is running.

In that case you can use $PROCESS_RUN instead of $PROCESS_RUNWAIT. Refer to the Example.au3 script for more details :)


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites
4 hours ago, TheDcoder said:

In that case you can use $PROCESS_RUN instead of $PROCESS_RUNWAIT. Refer to the Example.au3 script for more details :)

ok, i will check it. thank you

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  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By cruisepandey
      Hi There ! 
      I have a script here : 
       
      ;Launch CMD
      Run("C:\Windows\System32\cmd.exe")
      sleep(2000)
      $cmdHandle = WinActivate("C:\Windows\System32\cmd.exe")
      Sleep(2000)
      ;Sending document
      ControlSend($cmdHandle, "", "", "ftp" & @CRLF)
      ControlSend($cmdHandle, "", "", "open" & @CRLF)
      Sleep(2000)
      ControlSend($cmdHandle, "", "", "first command" & @CRLF)
      Sleep(2000)
      ControlSend($cmdHandle, "", "", "second-coomand" & @CRLF)
       
      first-command and second-command I can't provide cause it's internal. I have complied this .au3 file into an exe and it does the work. But I need to invoke this with Java. Java code I have tried is : 
       
          ProcessBuilder pb = new ProcessBuilder("C:\\Users\\username\\eclipse-workspace\\Examples\\src\\com\\own\\examples\\etc.exe");
          pb.start();
          Thread.sleep(5000);
       
      Through java it just launches the cmd and nothing happens after that. Please help !!
    • By Chimp
      I'm trying to drive a command prompt by sending instructions via a NamedPipe.
      This way you can (should) be able to send commands to the command prompt and at the same time "view" the result in the same window.
      This is not allowed if you run a command prompt with "opt_flag" parameters (redirected streams) because this will disable StdOut on the cmd itself.
      This small (trivial) snippet works for the first command sent to the cmd, but further submissions will fail.
      Maybe the problem is in how I use the run () command to start a new cmd with the StdIn redirect from the NamedPipe. It seems that the generated cmd will close automatically after the first reception of the command via NamedPipe.
      suggestions on how to make it work are welcome
      thanks
      #include <NamedPipes.au3> #include <WinAPI.au3> ; Creates an instance of a named pipe Global $sPipeName = "\\.\pipe\pipename" Global $hPipe = _NamedPipes_CreateNamedPipe($sPipeName, 1, 1) MsgBox(0, "Debug", "Pipe created. Now open a CMD") ; run a cmd with only StdIn redirected (StdIn data incoming from a pipe) Global $hCMD = Run(@ComSpec & " /K cmd < " & $sPipeName & @CRLF, "c:\") ; ok? MsgBox(0, "Debug", "now Send a command to the cmd via a NamedPipe") _StdInPipeWrite("dir" & @CRLF) MsgBox(0, 'Debug', "further commands will fail" & @CRLF & "now send command 'dir c:\windows'") $sMessage = "Dir c:\windows" & @CRLF _StdInPipeWrite($sMessage) MsgBox(0, 'Debug', "send another command (will also fail)" & @CRLF & "now send command 'echo Hello'") _StdInPipeWrite("echo Hello" & @CRLF) MsgBox(0, "Debug", "end of test") ProcessClose($hCMD) Func _StdInPipeWrite($sMessage) ; =============================================================================================================================== ; This function writes a message to the pipe ; =============================================================================================================================== Local $iWritten, $iBuffer, $pBuffer, $tBuffer $iBuffer = StringLen($sMessage) + 1 $tBuffer = DllStructCreate("char Text[" & $iBuffer & "]") $pBuffer = DllStructGetPtr($tBuffer) DllStructSetData($tBuffer, "Text", $sMessage) If Not _WinAPI_WriteFile( _ $hPipe, _ ; ...... Handle to the file to be written $pBuffer, _ ; .... Pointer to the buffer containing the data to be written $iBuffer, _ ; .... Number of bytes to be written to the file $iWritten, _ ; ... The number of bytes written 0 _ ; ............ [optional] A $tagOVERLAPPED structure or a pointer to it ) Then ConsoleWrite("WriteMsg: _WinAPI_WriteFile failed" & @CRLF & _WinAPI_GetLastErrorMessage()) Else ConsoleWrite("WriteMsg: write OK" & @CRLF & _WinAPI_GetLastErrorMessage() & @CRLF) EndIf EndFunc ;==>_StdInPipeWrite  
    • By IndianSage
      Hi,
      My AutoIt script is as folllows:
      ;use for calling function add2NosA in dll ;Local $vNo1 = 33 ;Local $vNo2 = 11 ;use for calling function sortNos in dll Local $vNo1 = [11,7,9] Local $vNo2 = [1,3,2] ; _ArrayDisplay($vNo1, "vNo1 display") ; _ArrayDisplay($vNo2, "vNo2 display") ;Local $hWnd = DllOpen("E:\CV-Dell-1\autoit3\myComObj1.dll") Local $hWnd = ObjCreate("myComObj1.clsMath") if (@error) Then MsgBox (0, "Error", "Error1 = " & @error) Exit EndIf ;function call method - DllCall with function name ;Local $aRes = DllCall($hWnd, "int", "addNosA", "int", $vNo1, "int", $vNo2) ;Local $aRes = DllCall($hWnd, "Ptr", "sortNos", "Array", $vNo1, "Array", $vNo2) ;function call method - $hWnd.<function name> ;Local $aRes = $hWnd.add2NosA($vNo1, $vNo2) ; this works fine with ObjCreate Local $aRes = $hWnd.sortNos($vNo1, $vNo2) if (@error) Then MsgBox (0, "Error", "Error2 = " & @error) DllClose($hWnd) Exit EndIf ;use appropriate msgbox ;MsgBox(0,"Result", "Result = " & $vNo1[0]) MsgBox(0,"Result", "Result = " & $aRes) _ArrayDisplay($vNo1, "vNo1 display") _ArrayDisplay($aRes , "aRes display") DllClose($hWnd) My VB.Net - ClassLibrary - Dll - COM obj is as follows - has 2 functions - add2NosA and sortNos:
      <ComClass(clsMath.ClassId, clsMath.InterfaceId, clsMath.EventsId)> Public Class clsMath Public Const ClassId As String = "3A42F85E-24C8-4BAA-91B5-AE56C4683C13" Public Const InterfaceId As String = "D99D7C79-2BA7-4A33-B7BC-9B7F19FDF828" Public Const EventsId As String = "CA128AC4-580C-4112-9EAD-8D1599E3F37A" Public Sub New() MyBase.New() End Sub Public Function add2NosA(ByVal no1 As Integer, ByVal no2 As Integer) As Integer Return (no1 + no2) End Function Public Sub sortNos(ByRef no1 As Array, ByRef no2 As Array) Array.Sort(no1) no2 = no1 End Sub End Class  Over all I tried various 8 options mentioned in the attached Excel file - with only 1 combination working.
      Overall could not make Array returned capture in AutoIt script. 
      Can someone help please?
      Thanks in  advance.
      Options-Tried-Matrix-Results.xlsx
    • By IndianSage
      I have create a function in FreeBasic like below:
      Extern "Windows-MS" Type tA f1 As Integer f2 As Integer End Type Public Function _switchOrder(ByVal no1 As Integer, ByVal no2 As Integer) As tA Export Dim result As Integer Dim taa As tA taa.f1 = no2 taa.f2 = no1 Return taa End Function End Extern Caller AutoIt code is:
      #include <MsgBoxConstants.au3> Global Const $sTag_ftdi_version_info="struct; int no1a; int no2a; endstruct" Local $aRet=DllCall("Math1.dll","Ptr","_switchOrder", "Int", 10, "Int", 30) ;MsgBox (0,"",@error & "-" & $aRet[0] & "-" & $aRet[1]& "-" & $aRet[2]) Local $t_ftdi_version_info=DllStructCreate($sTag_ftdi_version_info,$aRet[0]) MsgBox (0,"msg1=",@error & "---" & $aRet[0] & "-" & $aRet[1]& "-" & $aRet[2]) ;Local $retData1 = DllStructGetData($t_ftdi_version_info,"",1) Local $retData1 = DllStructGetData($t_ftdi_version_info,"no1a") MsgBox (0,"msg2=",@error & "--" & $retData1) ;Local $retData1 = DllStructGetData($t_ftdi_version_info,"",2) Local $retData1 = DllStructGetData($t_ftdi_version_info,"no2a") MsgBox (0,"msg2=",@error & "--" & $retData1) ;ConsoleWrite(DllStructGetData($t_ftdi_version_info,"",2) & "--" & @error) ;ConsoleWrite(DllStructGetData($t_ftdi_version_info,"no2a") & @CRLF) ;ConsoleWrite(DllStructGetData($tversion_str,1) & @CRLF) Getting error 2 for DllStructGetData or it give Close Application AutoIt popup message. 
      Certainly DllCall is not returning pointer to the Structure in $aRet[0] hence issue.
      Can someone help me fix this please?
      Thanks in advance.
       
       
    • By xYuri
      This simple dllcall gives me error 5, access denied,
      Func _WinAPI_VkKeyScan($__key) _WinAPI_SetLastError(0) $res = DllCall('User32.dll', 'SHORT', 'VkKeyScan', 'CHAR', $__key) _xConsole('res: '&$res) $_LastErr = _WinAPI_GetLastError() If $_LastErr <> 0 Then _xConsole('Err: {' & $_LastErr & '}> ' & _WinAPI_GetLastErrorMessage()) Return $res EndFunc Am i doing something wrong?
      Also tried VkKeyScanA and W
      Edit:
      I want to send `:` via PostMessage() WM_KEYDOWN
×
×
  • Create New...