ActiveState Code

Recipe 576821: Python to IProgressDialog interface


Easy method to use Windows Explorer's ProgressDialog COM object to show progress of processing, uploads, downloads, etc.

Python
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import win32gui

class COMprogressDialog(object):
    def __init__(self, title='Progress Dialog', animation_res=161):
        '''
        COMprogressDialog - Windows COM object that shows progress of task.
                            This dialog runs in a separate thread so it can be
                            run from virtually any program without adding
                            threading complexity to that program.

        title         - Dialog window title
        animation_res - animation resource .AVI for interesting progress display
                        animation_res=160 (move)
                        animation_res=161 (copy)

        COMprogressDialog.dialog class methods -

          StartProgressDialog(hwndParent, lEnableModeless, dwFlags, pvReserved)
          StopProgressDialog()
          SetTitle(sTitle)
          SetAnimation(hInstAnimation, idAnimation)
          HasUserCancelled()
          SetProgress(completed, total)
          SetProgress64(completed64, total64)
          SetLine(lineNum, sText, lCompactPath, pvReserved)
          SetCancelMsg(sCancelMsg, pvReserved)
          Timer() - Reset timer
          Release() - Close dialog, release resources

        Animation resource in shell32.dll that points to .AVIs

        Written by: Larry Bates (with substantial help from Thomas Heller and
                    Tim Golden on COM interfacing to IProgressDialog),
                    February 2008

        License: GPL
        Requires: ctypes, comtypes, win32gui
        '''
        #
        # Save title so I can update it with % completed as I progress
        #
        self.title = title
        #
        # Get a list of topWindows
        #
        topWindows = []
        win32gui.EnumWindows(self._windowEnumerationHandler, topWindows)
        #
        # Isolate Program Manager window from all the other topWindows,
        # this will be used as the parent window for the dialog.
        #
        hwndParent = [w[0] for w in topWindows if w[1] == 'Program Manager'][0]
        import comtypes.client
        try:
            import comtypes.gen.VBProgressDialog
            
        except ImportError:
            #
            # Create object from the progress tlb file for the COM Progress
            # Dialog
            #
            comtypes.client.GetModule('progdlg.tlb')
            
        vbpd = comtypes.gen.VBProgressDialog
        #
        # Create instance of progress dialog
        #
        self.dialog = comtypes.client.CreateObject(vbpd.ProgressDialog)
        #
        # Set the animation for the dialog (default=copy) from shell32.dll
        #
        import ctypes
        #
        # Pointer to shell32.dll
        #
        shell32 = ctypes.windll.shell32
        #
        # Get handle for this
        #
        m_hLibShell32 = shell32._handle
        #
        # Set the animation based on animation_res number (default animation
        # is copy animation).
        #
        self.dialog.SetAnimation(m_hLibShell32, animation_res)
        #
        # Insert title into top of dialog if present
        #
        if title:
            self.dialog.SetTitle(title)
        #
        # Start the dialog
        #
        self.dialog.StartProgressDialog(hwndParent, None, 0, 0)
        
    def _windowEnumerationHandler(self, hwnd, resultList):
        #
        # Get a list of the top level windows so I can find Program Manager
        #
        resultList.append((hwnd, win32gui.GetWindowText(hwnd)))

    def __del__(self):
        self.dialog.Release()
        del self.dialog
       
if __name__ == "__main__":
    import time
    compactPath = 1
    total = 100
    filenames=['C:/pagefile.sys',
               'C:/Documents and Settings/All Users/Start Menu/' \
               'Programs/Administrative Tools/Computer Management'
              ]

    for i in xrange(3):
        title="COMprogressDialot Unit Test %i" % (i+1)
        #
        # Create instance of the COMprogressDialog class
        #
        DLGobj = COMprogressDialog(title=title)
        #
        # Set the first line of the dialog to the filename
        #
        DLGobj.dialog.SetLine(1, filenames[0], compactPath, 0)
        for j in xrange(total):
            completed=int(100.0 / total * j)
            completed="%s (%i%%)" % (title, completed)
            #
            # Update title to include (xx%) completed
            #
            DLGobj.dialog.SetTitle(completed)
            #
            # Update the progress gauge
            #
            DLGobj.dialog.SetProgress(j, total)
            #
            # Set second line to ##### of ##### bytes uploaded
            #
            line2="%i of %i bytes uploaded" % (j, total)
            DLGobj.dialog.SetLine(2, line2, 0, 0)
            #
            # See if user pushed cancel button
            #
            if DLGobj.dialog.HasUserCancelled():
                break

            #
            # Simulate uploading two equal sized files
            #
            if j == 50:
                compactPath=1
                DLGobj.dialog.SetLine(1, filenames[1], compactPath, 0)
                
            time.sleep(0.1)

        #
        # Only necessary because of nested loops
        #
        if DLGobj.dialog.HasUserCancelled():
            break
        #
        # Destroy the object (note: this is important!)
        #
        del DLGobj

Discussion

Launches ProgressDialog in a separate thread for showing progress on long running tasks.

Comments

  1. 1. At 1:01 p.m. on 12 jul 2009, Gabriel Genellina said:

    I don't have progdlg.tlb anywhere, nor an VBProgressDialog object registered. Where do you get those?

Sign in to comment