Jump to content

This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies. Find out more here. X
X


Photo

DISM console progress using StdoutRead


  • Please log in to reply
18 replies to this topic

#1 RvdH

RvdH

    Wayfarer

  • Active Members
  • Pip
  • 60 posts

Posted 07 January 2011 - 03:33 PM

Hello,
It has been a while last time i was here, nice to see everything is still up and running like it was in the time i joined here.

Anyone can help me out, i like to read DISM StdoutRead and display a custom progress bar using AutoIt
I have found some partial scripts here, but none seems to work with DISM

Posted Image

Posted Image

In the code below the idea was to read out the increasing '=' signs as shown in the pics above

Plain Text         
#RequireAdmin Opt("MustDeclareVars", 0) ; Script Start - Add your code below here ; Set the max number of = signs to expect $maxTicks = 52 ;26 = signs both left and right from the percentage indicator ; Run the child process, connecting to its STDOUT pipe $process = Run(@COMSPEC & ' /k dism /mount-wim /wimfile:' & @ScriptDir & '/boot.wim /index:1 /mountDir:C:\Mount', @ScriptDir, @SW_HIDE, 2) ; Show the progress bar ProgressOn("= Count", "Counting...") ; Read from the child's STDOUT While 1     $readTicks = StdoutRead($process)    ; if StdoutRead sets @error to -1 we're at EOF, so exit     If @error = -1 Then ExitLoop     StringReplace($readTicks, "=", "0")    ; StringReplace keeps a count of chars it replaces in @extended     $totalTicks += @extended    ; Adjust the progress bar     ProgressSet(($totalTicks / $maxTicks) * 100) WEnd ; Hide the progress bar ProgressOff() MsgBox(0, "Debug", "Done.") ; Finished


Anyone got an idea how to make this work?

RvdH







#2 Manadar

Manadar

         

  • MVPs
  • 10,878 posts

Posted 07 January 2011 - 03:44 PM

Hey,

I am getting a undeclared variable error from this line: $totalTicks += @extended. I added the $totalTicks = 0 at the beginning of the script but then I realized that it doesn't make sense to add the new number of "=" to the old number of "=". So I simply changed that to:

    StringReplace($readTicks, "=", "0")    ; StringReplace keeps a count of chars it replaces in @extended    ; Adjust the progress bar     ProgressSet((@extended / $maxTicks) * 100)


In the end, I wrote a "unit test" for your script since I can't test DISM like you can. And it shows that the code works:
AutoIt         
; Script Start - Add your code below here ; Set the max number of = signs to expect $maxTicks = 52 ;26 = signs both left and right from the percentage indicator ; Run the child process, connecting to its STDOUT pipe $process = 0;Run(@COMSPEC & ' /k dism /mount-wim /wimfile:' & @ScriptDir & '/boot.wim /index:1 /mountDir:C:\Mount', @ScriptDir, @SW_HIDE, 2) ; Show the progress bar ProgressOn("= Count", "Counting...") ; Read from the child's STDOUT While 1     $readTicks = _StdoutRead($process)    ; if StdoutRead sets @error to -1 we're at EOF, so exit     If @error = -1 Then ExitLoop     StringReplace($readTicks, "=", "0")    ; StringReplace keeps a count of chars it replaces in @extended    ; Adjust the progress bar     ProgressSet((@extended / $maxTicks) * 100) WEnd ; Hide the progress bar ProgressOff() MsgBox(0, "Debug", "Done.") ; Finished Func _StdoutRead($ignoreMe)     Static $i = 0     Switch $i         Case 0             Return "===="         Case 1             Return "==========="         Case 2             Return "=================="         Case 3             Return "============================="         Case 4             Return "===================================================="         Case Else             Return SetError(1)     EndSwitch     $i += 1 EndFunc



If this still doesn't fix your problem, then I don't think AutoIt is reading the output of the progress from console. ($readTicks is always an empty line)

#3 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 07 January 2011 - 03:56 PM

I think Manadar is right in that you can't read that progress bar all that easily... I think you need to use ReadConsoleOutput to read a specific block, and unfortunately it's one of the functions I haven't implemented you in my console udf.

Edit: Can't you just read the percentage value?

Edited by Mat, 07 January 2011 - 03:57 PM.


#4 RvdH

RvdH

    Wayfarer

  • Active Members
  • Pip
  • 60 posts

Posted 07 January 2011 - 04:03 PM

@Manadar
Thx for the prompt reply

Looks like you are right, progress indicator just hangs. So it seems like you said AutoIt is not reading the dynamic changing values in a line... damn, another way to accomplish that?

Edited by RvdH, 07 January 2011 - 04:07 PM.


#5 RvdH

RvdH

    Wayfarer

  • Active Members
  • Pip
  • 60 posts

Posted 07 January 2011 - 04:07 PM

@Mat
Reading percentage value, how do i accomplish that? Don't i have the exact same issue as above using that technique?

Edited by RvdH, 08 January 2011 - 10:21 AM.


#6 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 07 January 2011 - 04:13 PM

Read the start of my reply. I gave you the method I know of :x

Edit: Just to clarify, the reason I said to use the percentage is because I thought it might be easier to read a smaller block and end up with a more accurate number.

Edited by Mat, 07 January 2011 - 04:15 PM.


#7 Manadar

Manadar

         

  • MVPs
  • 10,878 posts

Posted 07 January 2011 - 07:21 PM

RvdH, unless someone else comes along, I think solving this problem at hand is going to be more work than it is worth.

#8 sdgsdgsdgsdg

sdgsdgsdgsdg

    Seeker

  • Validating
  • 1 posts

Posted 08 January 2011 - 12:10 AM

Hi,

I have the same problem, except I try to do it in .NET. I tried to send an email to the developers of gimagex and imagex/dism (Microsoft), but they didn't answered... There is a solution for sure, because gimagex have a progress bar... but what is the solution !?

Thanks !

#9 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 08 January 2011 - 09:45 AM

I did tell you. ReadConsoleOutput it allows you to copy a block of characters from one buffer to another. For an example look here

#10 RvdH

RvdH

    Wayfarer

  • Active Members
  • Pip
  • 60 posts

Posted 08 January 2011 - 10:21 AM

@Manadar
Thx, guess you are right

@Mat,
To be honest, your suggestion for me is way out of my (AutoIt) programming skills. With other words i have no clue of where to start from.
Maybe you could add it to your "TODO" list for your console udf? :x

Edited by RvdH, 08 January 2011 - 10:22 AM.


#11 MvGulik

MvGulik

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 2,816 posts

Posted 08 January 2011 - 11:27 AM

Mmm, any known alternative to using DISM to test on. (if DISM is not using some special MS-trick here of course.)

#12 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 08 January 2011 - 11:38 AM

I want to get the full list, the only problem is that it uses extensive structures... Such as needing an array of a particular structure. You should be ok making a workaround using just one CHAR_INFO struct and calling the function 4 times to get the percentage, or write it in C in which case it gets easier (but other bit's will get harder :x )

#13 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 08 January 2011 - 12:14 PM

Mmm, any known alternative to using DISM to test on. (if DISM is not using some special MS-trick here of course.)

Yes. Before you look at the code, this is NOT a good example, and I would never want it used for anything other than testing on. The correct would be making a second buffer and using WriteConsoleOutput, making the cursor jump everywhere is not the way to do this.

AutoIt         
#include <Console.au3> _Console_Alloc() ; The width of the dism progress is 60 chars, 2 chars are brackets so 58 possible = signs. ; The percentage starts at 27 chars, and is right aligned in 6 chars (Always to 1dp). Local $tScreenBufferInfo = _Console_GetScreenBufferInfo() Local $iWidth = DllStructGetData($tScreenBufferInfo, "SizeX") Local $iY = DllStructGetData($tScreenBufferInfo, "CursorPositionY") _Console_FillOutputCharacter(-1, " ", $iWidth, 0, $iY) _Console_FillOutputCharacter(-1, "[", 1, 0, $iY) _Console_FillOutputCharacter(-1, "]", 1, 59, $iY) _Console_SetCursorPosition(-1, 1, $iY) Local $iPercent For $i = 1 To 58     $sPercent = StringFormat("%.1f%%", Round(($i / 58) * 100, 1))     _Console_SetCursorPosition(-1, 33 - StringLen($sPercent), $iY)     _Console_Write($sPercent)     If $i < 33 - StringLen($sPercent) Or $i >= 33 Then         _Console_SetCursorPosition(-1, $i, $iY)         _Console_Write("=")     EndIf     _Console_SetCursorPosition(-1, 0, $iY + 1)     Sleep(100) Next Sleep(2000) _Console_Free()


#14 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 08 January 2011 - 04:08 PM

Ok, a few updates. You can use the ReadConsoleOutputCharacter function rather than the ReadConsoleOutput one. I don't see any reason why I can't implement it soon :x it looks like it's easy enough.

Also, another better example (in C++ as I haven't implemented the function in AutoIt yet):
Spoiler


Attached File  ProgressExample.exe   7KB   104 downloads

Edit: And finally the solution. It runs slightly behind, and eats a lot of cpu - but it works :P It needs the ProgressExample.exe I wrote from above.

AutoIt         
#include <Console.au3> $__gvKernel32 = DllOpen("kernel32.dll") Local $iPid = Run("ProgressExample.exe", @ScriptDir) ProcessWait($iPid) _Console_Attach($iPid) ; The width of the dism progress is 60 chars, 2 chars are brackets so 58 possible = signs. ; The percentage starts at 27 chars, and is right aligned in 6 chars (Always to 1dp). Local $hStdOut = _Console_GetStdHandle($STD_OUTPUT_HANDLE) Local $tScreenBufferInfo = _Console_GetScreenBufferInfo($hStdOut) Local $iY = DllStructGetData($tScreenBufferInfo, "CursorPositionY") ProgressOn("ProgressExample.exe", "...") While ProcessExists($iPid)     $s = _Console_ReadConsoleOutputCharacter($hStdOut, 5, 27, $iY)     ProgressSet(Execute(StringReplace($s, "=", ""))) WEnd ProgressOff() _Console_Free() Exit Func _Console_ReadConsoleOutputCharacter($hConsoleOutput, $nNumberOfCharsToRead, $iX, $iY, $fUnicode = Default, $hDll = -1)     Local $tCoord, $tBuffer, $aResult     If $fUnicode = Default Then $fUnicode = $__gfUnicode     If $hDll = -1 Then $hDll = $__gvKernel32     If $hConsoleOutput = -1 Then $hConsoleOutput = _Console_GetStdHandle($STD_OUTPUT_HANDLE, $hDll)     $tCoord = BitShift($iY, -16) + $iX     If $fUnicode Then         $tBuffer = DllStructCreate("wchar[" & ($nNumberOfCharsToRead + 1) & "]")         $aResult = DllCall($hDll, "bool", "ReadConsoleOutputCharacterW", _                 "handle", $hConsoleOutput, _                 "ptr", DllStructGetPtr($tBuffer), _                 "dword", $nNumberOfCharsToRead, _                 "dword", $tCoord, _                 "dword*", 0)     Else         $tBuffer = DllStructCreate("char[" & ($nNumberOfCharsToRead + 1) & "]")         $aResult = DllCall($hDll, "bool", "ReadConsoleOutputCharacterA", _                 "handle", $hConsoleOutput, _                 "ptr", DllStructGetPtr($tBuffer), _                 "dword", $nNumberOfCharsToRead, _                 "dword", $tCoord, _                 "dword*", 0)     EndIf     If @error Or (Not $aResult[0]) Then Return SetError(@error, @extended, "")     Return SetExtended($aResult[4], DllStructGetData($tBuffer, 1)) EndFunc   ;==>_Console_ReadConsoleOutputCharacter

Edited by Mat, 08 January 2011 - 05:42 PM.


#15 RvdH

RvdH

    Wayfarer

  • Active Members
  • Pip
  • 60 posts

Posted 10 January 2011 - 11:24 AM

Wow, Mat that's fantastic

Just tried to port it to the actual DISM console window, Local $iY = DllStructGetData($tScreenBufferInfo, "CursorPositionY") seems off, it doesn't display the progress. Once changed to '5' it functions correctly.

#16 Mat

Mat

    43 38 48 31 30 4E 34 4F 32

  • MVPs
  • 5,066 posts

Posted 10 January 2011 - 11:30 AM

Ah right ok, I was assuming the cursor would be on the same line as the progress, but that doesn't have to be the case with WriteConsoleOutputCharacter.

Thanks for reminding me as well, I've added those two functions to the library now. Up to 85 :x With the latest version:

#include <Console.au3> $__gvKernel32 = DllOpen("kernel32.dll") Local $iPid = Run("ProgressExample.exe", @ScriptDir) ProcessWait($iPid) _Console_Attach($iPid) ; The width of the dism progress is 60 chars, 2 chars are brackets so 58 possible = signs. ; The percentage starts at 27 chars, and is right aligned in 6 chars (Always to 1dp). ProgressOn("ProgressExample.exe", "...") While ProcessExists($iPid)     $s = _Console_ReadOutputCharacter(-1, 5, 27, 5)     ProgressSet(Execute(StringReplace($s, "=", ""))) WEnd ProgressOff() _Console_Free() Exit

Edited by Mat, 10 January 2011 - 11:31 AM.


#17 FreeBeing

FreeBeing

    Wayfarer

  • Active Members
  • Pip
  • 68 posts

Posted 07 November 2013 - 06:33 PM

Thank you for your script and Console UDF, it works perfectly with Windows PE 5 and DISM ;)



#18 SmokieBlahBlah

SmokieBlahBlah

    Seeker

  • Normal Members
  • 1 posts

Posted 15 February 2014 - 01:48 PM

ProgressExample.exe unavailable. Give me it please. Thanks :3


Edited by SmokieBlahBlah, 15 February 2014 - 01:48 PM.


#19 this-is-me

this-is-me

    Pursuer of obscure functionality

  • Active Members
  • PipPipPipPipPipPip
  • 2,466 posts

Posted 16 February 2014 - 03:33 AM

ProgressExample.exe unavailable. Give me it please. Thanks :3

!!!??? I need please document example code before give ProgressExample.exe. Do not delay or file deleted in few minutes!


Who else would I be?




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users