none
How to get a hWnd of Windows Upgrade percentage progress

    Question

  • Hi all!

    I know this may be a weird question, but this is my situation:

    My customer asked me to create an application in VB.NET to show the progress of the Windows 10 Upgrade Setup.
    I am able to get hwnd of the upgrade windows progress bar, but I need to run the upgrade in silent mode, so no Window will appear.
    How could I get hwnd of the progress of the hidden process?


    Friday, February 8, 2019 11:02 PM

Answers

  • Ok I solved the problem:

    Dim MainForm As IntPtr = FindWindow(Nothing, "Easy Deployment Tool") 'Find Application
            UpgradeWindowInPanel = FindWindowExW(MainForm, IntPtr.Zero, "windowsforms10.window.8.app.0.141b42a_r10_ad1", Nothing) 'This is the panel
            UpgradeWindowInPanelChild = FindWindowExW(UpgradeWindowInPanel, IntPtr.Zero, "#32770", Nothing) 'This is the Upgrade Window into the panel
            hlabel = FindWindowExW(UpgradeWindowInPanelChild, IntPtr.Zero, "Static", Nothing) 'This is the Static element I need
    

    After that I used your code and everything works fine.
    Thanks a lot IronRazerz.

    • Marked as answer by Simone Termine Tuesday, February 12, 2019 3:25 AM
    Tuesday, February 12, 2019 3:25 AM

All replies

  • Hello,

    Been here long enough nothing this doesn't sound weird but I doubt that the setup runs with a progressbar in this case, only when there is a visible window would there be a progressbar, granted I could be wrong but I were to build a setup that runs in silent mode there would be no progress bar. 

    Only sure way to know is to run the setup with Spy++ or similar tool to see if there is a handle/hWnd in the window list for the setup.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites


    Friday, February 8, 2019 11:24 PM
    Moderator
  •  I would agree with Karen,  in silent mode I would doubt the updater/installer would create the ProgressBar or keep it's value updated with a percent since there is no window to view.  However,  I could be wrong but, to me  it wouldn't make much sense to consume more memory or processor time to create a window and update a progress bar if it is not visible to the user.

    If you say it can`t be done then i`ll try it

    Saturday, February 9, 2019 5:07 PM
  •  I would agree with Karen,  in silent mode I would doubt the updater/installer would create the ProgressBar or keep it's value updated with a percent since there is no window to view.  However,  I could be wrong but, to me  it wouldn't make much sense to consume more memory or processor time to create a window and update a progress bar if it is not visible to the user.

    If you say it can`t be done then i`ll try it

    The problem is that the Windows Upgrade Window could be closed by the end user, I created this application just for manage this problem. The end user could potentially reboot the pc during the upgrade because the silent mode does not show anything.

    I could incorporate the Upgrade window in my form in a panel and then resize my form to let it be hidden.

    But which class should I use in my code?

    If I open 001E06F2:

    Saturday, February 9, 2019 5:29 PM
  •  I would agree with Karen,  in silent mode I would doubt the updater/installer would create the ProgressBar or keep it's value updated with a percent since there is no window to view.  However,  I could be wrong but, to me  it wouldn't make much sense to consume more memory or processor time to create a window and update a progress bar if it is not visible to the user.


    If you say it can`t be done then i`ll try it

    The problem is that the Windows Upgrade Window could be closed by the end user, I created this application just for manage this problem. The end user could potentially reboot the pc during the upgrade because the silent mode does not show anything.

    I could incorporate the Upgrade window in my form in a panel and then resize my form to let it be hidden.

    But which class should I use in my code?

    If I open 001E06F2:

    I have to disagree with this thought process. What if you prevent this and then user presses the power button?

    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Saturday, February 9, 2019 7:05 PM
    Moderator
  •  I would recommend not setting the dialog window as a child of your vb.net app's form as that can cause unwanted behavior.  I would try just getting the handle of the dialog window which will be different every time the window is created,  and try using the ShowWindow api function to hide the window.

     Below is an untested example I threw together that should help get you going if it does not work as is.  It is set up to find the Dialog window,  then find the Label control that displays the percentage.  If both are successfully found,  then it will hide the dialog window and start a Timer which should keep a label on your vb.net form updated with the current progress percentage.

     You can test it in a new Form with 1 Button,  1 Label,  and 1 Timer added to the Form.

    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
        <DllImport("user32.dll")>
        Public Shared Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
    
        <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
        Private Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="GetWindowTextW")>
        Private Shared Function GetWindowTextW(ByVal hWnd As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpString As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
        End Function
    
        Private Const SW_HIDE As Integer = &H0
        Private Const SW_SHOW As Integer = &H5
    
        Private hDialog As IntPtr = IntPtr.Zero
        Private hLabel As IntPtr = IntPtr.Zero
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            'find the dialog window using its Class Name '#32770' and window title 'Installazione di Windows 10'.
            hDialog = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "#32770", "Installazione di Windows 10")
    
            If hDialog <> IntPtr.Zero Then 'check if the dialog window was found
    
                hLabel = FindWindowExW(hDialog, IntPtr.Zero, "Static", Nothing) 'find the first child Label control in the Dialog window
    
                While hLabel <> IntPtr.Zero 'enter while loop if the first child label was found
                    Dim sb As New System.Text.StringBuilder(256)
                    GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
    
                    If sb.ToString.ToLower.StartsWith("completamento operazione:") Then
                        Label1.Text = sb.ToString 'set the label on your form to the text retrieved from the label on the dialog
                        Exit While 'if this is the label that shows the percentage, then exit the loop
                    End If
    
                    hLabel = FindWindowExW(hDialog, hLabel, "Static", Nothing) 'if the correct label was not found yet, then get the next child label in the Dialog window
                End While
    
                'if the dialog window and the correct label was found, then hide the Window and start a timer which will keep your vb.net Label updated to the current %
                If hDialog <> IntPtr.Zero AndAlso hLabel <> IntPtr.Zero Then
                    ShowWindow(hDialog, SW_HIDE) 'hide the dialog window
                    Timer1.Interval = 500
                    Timer1.Start()
                End If
            End If
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Dim sb As New System.Text.StringBuilder(256)
            GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
            Label1.Text = sb.ToString
        End Sub
    End Class
    


    If you say it can`t be done then i`ll try it

    Saturday, February 9, 2019 7:29 PM
  •  I would recommend not setting the dialog window as a child of your vb.net app's form as that can cause unwanted behavior.  I would try just getting the handle of the dialog window which will be different every time the window is created,  and try using the ShowWindow api function to hide the window.

     Below is an untested example I threw together that should help get you going if it does not work as is.  It is set up to find the Dialog window,  then find the Label control that displays the percentage.  If both are successfully found,  then it will hide the dialog window and start a Timer which should keep a label on your vb.net form updated with the current progress percentage.

     You can test it in a new Form with 1 Button,  1 Label,  and 1 Timer added to the Form.

    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
        <DllImport("user32.dll")>
        Public Shared Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
    
        <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
        Private Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="GetWindowTextW")>
        Private Shared Function GetWindowTextW(ByVal hWnd As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpString As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
        End Function
    
        Private Const SW_HIDE As Integer = &H0
        Private Const SW_SHOW As Integer = &H5
    
        Private hDialog As IntPtr = IntPtr.Zero
        Private hLabel As IntPtr = IntPtr.Zero
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            'find the dialog window using its Class Name '#32770' and window title 'Installazione di Windows 10'.
            hDialog = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "#32770", "Installazione di Windows 10")
    
            If hDialog <> IntPtr.Zero Then 'check if the dialog window was found
    
                hLabel = FindWindowExW(hDialog, IntPtr.Zero, "Static", Nothing) 'find the first child Label control in the Dialog window
    
                While hLabel <> IntPtr.Zero 'enter while loop if the first child label was found
                    Dim sb As New System.Text.StringBuilder(256)
                    GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
    
                    If sb.ToString.ToLower.StartsWith("completamento operazione:") Then
                        Label1.Text = sb.ToString 'set the label on your form to the text retrieved from the label on the dialog
                        Exit While 'if this is the label that shows the percentage, then exit the loop
                    End If
    
                    hLabel = FindWindowExW(hDialog, hLabel, "Static", Nothing) 'if the correct label was not found yet, then get the next child label in the Dialog window
                End While
    
                'if the dialog window and the correct label was found, then hide the Window and start a timer which will keep your vb.net Label updated to the current %
                If hDialog <> IntPtr.Zero AndAlso hLabel <> IntPtr.Zero Then
                    ShowWindow(hDialog, SW_HIDE) 'hide the dialog window
                    Timer1.Interval = 500
                    Timer1.Start()
                End If
            End If
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Dim sb As New System.Text.StringBuilder(256)
            GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
            Label1.Text = sb.ToString
        End Sub
    End Class


    If you say it can`t be done then i`ll try it

    Your code works great, but it seems that my situation is a little bit diferent.
    Here some images:

    As you can see I have used the SetParent function to put the upgrade window into a panel that will be hidden when I'll be sure that my code works.

    When I use SetParent, the hDialog function returns IntPtr.Zero again because it has been integrated in another form. How can I access the label again?


    Tuesday, February 12, 2019 12:43 AM
  •  Well,  with a slight modification to use the SetParent api instead of just hiding the dialog window,  this seems to work on my end.  However,  I tested it with a dialog window that belonged to Notepad,  not the same dialog that you are using.

    Imports System.Runtime.InteropServices
    
    Public Class Form1
        <DllImport("user32.dll")>
        Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
        Private Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="GetWindowTextW")>
        Private Shared Function GetWindowTextW(ByVal hWnd As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpString As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
        End Function
    
        Private hDialog As IntPtr = IntPtr.Zero
        Private hLabel As IntPtr = IntPtr.Zero
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            'find the dialog window using its Class Name '#32770' and window title 'Installazione di Windows 10'.
            hDialog = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "#32770", "Installazione di Windows 10")
    
            If hDialog <> IntPtr.Zero Then 'check if the dialog window was found
    
                hLabel = FindWindowExW(hDialog, IntPtr.Zero, "Static", Nothing) 'find the first child Label control in the Dialog window
    
                While hLabel <> IntPtr.Zero 'enter while loop if the first child label was found
                    Dim sb As New System.Text.StringBuilder(256)
                    GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
    
                    If sb.ToString.ToLower.StartsWith("completamento operazione:") Then
                        Label1.Text = sb.ToString 'set the label on your form to the text retrieved from the label on the dialog
                        Exit While 'if this is the label that shows the percentage, then exit the loop
                    End If
    
                    hLabel = FindWindowExW(hDialog, hLabel, "Static", Nothing) 'if the correct label was not found yet, then get the next child label in the Dialog window
                End While
    
                'if the dialog window and the correct label was found, then hide the Window and start a timer which will keep your vb.net Label updated to the current %
                If hDialog <> IntPtr.Zero AndAlso hLabel <> IntPtr.Zero Then
                    SetParent(hDialog, Panel1.Handle)
                    'you can use the MoveWindow or SetWindowPos api function here if you want to move the dialog window to a specific location in the Panel.
                    'however, if you won't see it, there is no need.
                    Timer1.Interval = 500
                    Timer1.Start()
                End If
            End If
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Dim sb As New System.Text.StringBuilder(256)
            GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
            Label1.Text = sb.ToString
        End Sub
    End Class
     

     I have no idea what all you are doing so,  you may want to reset the parent of the dialog back to the original parent of the dialog when your app is about to close.  Otherwise the dialog window will be closed and disposed of when your application is closed.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Tuesday, February 12, 2019 1:54 AM
    Tuesday, February 12, 2019 1:49 AM
  •  Well,  with a slight modification to use the SetParent api instead of just hiding the dialog window,  this seems to work on my end.  However,  I tested it with a dialog window that belonged to Notepad,  not the same dialog that you are using.

    Imports System.Runtime.InteropServices
    
    Public Class Form1
        <DllImport("user32.dll")>
        Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
        Private Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
        End Function
    
        <DllImport("user32.dll", EntryPoint:="GetWindowTextW")>
        Private Shared Function GetWindowTextW(ByVal hWnd As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpString As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
        End Function
    
        Private hDialog As IntPtr = IntPtr.Zero
        Private hLabel As IntPtr = IntPtr.Zero
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            'find the dialog window using its Class Name '#32770' and window title 'Installazione di Windows 10'.
            hDialog = FindWindowExW(IntPtr.Zero, IntPtr.Zero, "#32770", "Installazione di Windows 10")
    
            If hDialog <> IntPtr.Zero Then 'check if the dialog window was found
    
                hLabel = FindWindowExW(hDialog, IntPtr.Zero, "Static", Nothing) 'find the first child Label control in the Dialog window
    
                While hLabel <> IntPtr.Zero 'enter while loop if the first child label was found
                    Dim sb As New System.Text.StringBuilder(256)
                    GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
    
                    If sb.ToString.ToLower.StartsWith("completamento operazione:") Then
                        Label1.Text = sb.ToString 'set the label on your form to the text retrieved from the label on the dialog
                        Exit While 'if this is the label that shows the percentage, then exit the loop
                    End If
    
                    hLabel = FindWindowExW(hDialog, hLabel, "Static", Nothing) 'if the correct label was not found yet, then get the next child label in the Dialog window
                End While
    
                'if the dialog window and the correct label was found, then hide the Window and start a timer which will keep your vb.net Label updated to the current %
                If hDialog <> IntPtr.Zero AndAlso hLabel <> IntPtr.Zero Then
                    SetParent(hDialog, Panel1.Handle)
                    'you can use the MoveWindow or SetWindowPos api function here if you want to move the dialog window to a specific location in the Panel.
                    'however, if you won't see it, there is no need.
                    Timer1.Interval = 500
                    Timer1.Start()
                End If
            End If
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Dim sb As New System.Text.StringBuilder(256)
            GetWindowTextW(hLabel, sb, sb.Capacity) 'get the Label's Text
            Label1.Text = sb.ToString
        End Sub
    End Class
     

     I have no idea what all you are doing so,  you may want to reset the parent of the dialog back to the original parent of the dialog when your app is about to close.  Otherwise the dialog window will be closed and disposed of when your application is closed.


    If you say it can`t be done then i`ll try it

    First of all thank you for the support!
    Anyway sorry, maybe it came out wrong.

    When I press "Aggiorna" button, my application launches the setup and put its window into the panel in my form. At this point, if I run Spy++ I see that the setup form has been put into my form, this is the situation:

    The code you posted could work, but I need to get the value with this scheme.

    Tuesday, February 12, 2019 2:12 AM
  • Ok I solved the problem:

    Dim MainForm As IntPtr = FindWindow(Nothing, "Easy Deployment Tool") 'Find Application
            UpgradeWindowInPanel = FindWindowExW(MainForm, IntPtr.Zero, "windowsforms10.window.8.app.0.141b42a_r10_ad1", Nothing) 'This is the panel
            UpgradeWindowInPanelChild = FindWindowExW(UpgradeWindowInPanel, IntPtr.Zero, "#32770", Nothing) 'This is the Upgrade Window into the panel
            hlabel = FindWindowExW(UpgradeWindowInPanelChild, IntPtr.Zero, "Static", Nothing) 'This is the Static element I need
    

    After that I used your code and everything works fine.
    Thanks a lot IronRazerz.

    • Marked as answer by Simone Termine Tuesday, February 12, 2019 3:25 AM
    Tuesday, February 12, 2019 3:25 AM