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
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
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 barProgressSet((@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 barProgressOn("= Count","Counting..."); Read from the child's STDOUTWhile1$readTicks=_StdoutRead($process); if StdoutRead sets @error to -1 we're at EOF, so exitIf@error=-1ThenExitLoopStringReplace($readTicks,"=","0"); StringReplace keeps a count of chars it replaces in @extended; Adjust the progress barProgressSet((@extended/$maxTicks)*100)WEnd; Hide the progress barProgressOff()MsgBox(0,"Debug","Done."); FinishedFunc_StdoutRead($ignoreMe)Static$i=0Switch$iCase0Return"===="Case1Return"==========="Case2Return"=================="Case3Return"============================="Case4Return"===================================================="CaseElseReturnSetError(1)EndSwitch$i+=1EndFunc
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)
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.
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?
Read the start of my reply. I gave you the method I know of
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.
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 !?
@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?
Mmm, any known alternative to using DISM to test on. (if DISM is not using some special MS-trick here of course.)
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?"
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 )
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$iPercentFor$i=1To58$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>=33Then_Console_SetCursorPosition(-1,$i,$iY)_Console_Write("=")EndIf_Console_SetCursorPosition(-1,0,$iY+1)Sleep(100)NextSleep(2000)_Console_Free()
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 it looks like it's easy enough.
Also, another better example (in C++ as I haven't implemented the function in AutoIt yet):
Spoiler
Plain Text
#include "stdafx.h"
#include <windows.h>
// The width of the dism progress is 60 chars, 2 chars are brackets so 58 possible = signs.
// The percentage starts at char 27, and is right aligned in 6 chars (Always to 1dp).
int _tmain(int argc, _TCHAR* argv[])
{
char sBar[60];
FillMemory(sBar, 60, ' ');
float nPercent;
char sPercent[6];
HANDLE hConsole;
COORD dwTarget;
DWORD dwWritten;
CONSOLE_CURSOR_INFO tCCI;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
dwTarget.X = 0;
dwTarget.Y = 0;
GetConsoleCursorInfo(hConsole, &tCCI);
tCCI.bVisible = false;
SetConsoleCursorInfo(hConsole, &tCCI);
// Add knowns:
sBar[0] = '[';
sBar[59] = ']';
sBar[32] = '%';
for (int i = 1; i <= 58; i++)
{
nPercent = (float)i / 58 * 100;
sprintf(sPercent, "%5.1f", nPercent);
if (i < 30 || i > 32)
sBar[i] = '=';
for (int n = 0; n <= 4; n++)
{
if (sPercent[n] == ' ') continue;
sBar[27 + n] = sPercent[n];
}
WriteConsoleOutputCharacterA(hConsole, &sBar[0], 60, dwTarget, &dwWritten);
Sleep(100);
}
dwTarget.X = 0;
dwTarget.Y = 1;
SetConsoleCursorPosition(hConsole, dwTarget);
tCCI.bVisible = true;
SetConsoleCursorInfo(hConsole, &tCCI);
getchar();
return 0;
}
Edit: And finally the solution. It runs slightly behind, and eats a lot of cpu - but it works 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","...")WhileProcessExists($iPid)$s=_Console_ReadConsoleOutputCharacter($hStdOut,5,27,$iY)ProgressSet(Execute(StringReplace($s,"=","")))WEndProgressOff()_Console_Free()ExitFunc_Console_ReadConsoleOutputCharacter($hConsoleOutput,$nNumberOfCharsToRead,$iX,$iY,$fUnicode=Default,$hDll=-1)Local$tCoord,$tBuffer,$aResultIf$fUnicode=DefaultThen$fUnicode=$__gfUnicodeIf$hDll=-1Then$hDll=$__gvKernel32If$hConsoleOutput=-1Then$hConsoleOutput=_Console_GetStdHandle($STD_OUTPUT_HANDLE,$hDll)$tCoord=BitShift($iY,-16)+$iXIf$fUnicodeThen$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)EndIfIf@errorOr(Not$aResult[0])ThenReturnSetError(@error,@extended,"")ReturnSetExtended($aResult[4],DllStructGetData($tBuffer,1))EndFunc;==>_Console_ReadConsoleOutputCharacter
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.
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 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","...")WhileProcessExists($iPid)$s=_Console_ReadOutputCharacter(-1,5,27,5)ProgressSet(Execute(StringReplace($s,"=","")))WEndProgressOff()_Console_Free()Exit