|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Common Control API
Routines CreateWindowEx: Create the Common Control ProgressBar |
||
Posted: | Sunday June 29, 1997 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB4-32, Windows 95 | |
OS restrictions: | None | |
Author: | Brad Martinez | |
Related: |
SetParent: Add a VB Progress Bar to a VB StatusBar SendMessage: Change the Colour of a VB ProgressBar InitCommonControlsEx: Common Control Initialization Module Pure VB: Customizable PhotoShop-Style ProgressBar Pure VB: Customizable PhotoShop-Style ProgressBar in a MDI App CreateWindowEx: Creating a Common Control ProgressBar- Overview SetParent: Display Modal Form Activity on a Parent Form's 'PhotoShop-style' ProgressBar SetParent: Display Modal Form Activity in a Parent Form's VB ProgressBar |
|
Prerequisites |
None. For additional information on the progress bar members used, see Creating the Common Control ProgressBarvia the API - An Overview |
|
This
is based on the original article written for VBnet by Brad Martinez explaining the ins & outs of the Win32 / NT4 "comctl32.dll" common
control library, here showing how to implement a fully-functional API ProgressBarexposed by
comctl32.dll
without the use of either comctl32.ocx or mscomctl.ocx. The advantages of this implementation are obviously beneficial. First and foremost, the need to distribute an ocx control with your application is removed reducing distribution size. Also, an application's memory footprint is significantly reduced by not loading an ActiveX control. Finally, there is a noticeable improvement in performance. As long as you do not require your progress bar to handle and process mouse events, this demo is for you. (To work around this you can implement your own events via either a subclassing control or the AddressOf operator. This however is not shown here.) The dwIterations variable used in the Command1_Click code represents the number of items you are processing (e.g. the number of files if iterating through a folder, or the number of records if iterating through a database). The progress bar whose values are set via PBM_SETRANGE - as in this demo - is limited to a maximum of 32k items. For larger number of items the PBM_SETRANGE32 message is used instead, however this requires a different SendMessage calling syntax to pass the low and high points of the progress bar range. |
BAS Module Code |
None. |
|
Form Code |
Create a new form and add a text box (Text1), check box (Check1), command button (Command1), and two labels (Label1, Label2). The blue labels show in the illustration are not required for this demo. Add the following to the general declarations section of the form; the Load code will position and label the controls. Note that the code creates the progress bar along the bottom of the form, so don't size the demo form window too large for testing. |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'The progress bar's Form_Resize() module level variables Private hProgBar As Long 'hWnd Private dwPBPosLeft As Long 'static x position when vertical Private dwPBPosTop As Long 'static y position when horizontal 'SetWindowLong param Private Const GWL_STYLE As Long = (-16) 'Restricts input in the text box control to digits only Private Const ES_NUMBER As Long = &H2000 Private Const WS_VISIBLE As Long = &H10000000 Private Const WS_CHILD As Long = &H40000000 Private Const WM_USER = &H400 Private Const PBM_SETRANGE = (WM_USER + 1) Private Const PBM_SETPOS = (WM_USER + 2) Private Const PBM_SETSTEP = (WM_USER + 4) Private Const PBM_STEPIT = (WM_USER + 5) Private Const PBM_SETRANGE32 = (WM_USER + 6) Private Const PBM_GETRANGE = (WM_USER + 7) Private Const PROGRESS_CLASS = "msctls_progress32" Private Const PBS_VERTICAL = &H4 Private Const ICC_PROGRESS_CLASS = &H20 Private Type tagINITCOMMONCONTROLSEX dwSize As Long dwICC As Long End Type Private Declare Function InitCommonControlsEx Lib "comctl32.dll" _ (lpInitCtrls As tagINITCOMMONCONTROLSEX) As Boolean Private Declare Sub InitCommonControls Lib "comctl32.dll" () Private Declare Function CreateWindowEx Lib "user32" _ Alias "CreateWindowExA" _ (ByVal dwExStyle As Long, _ ByVal lpClassName As String, _ ByVal lpWindowName As String, _ ByVal dwStyle As Long, _ ByVal x As Long, ByVal y As Long, _ ByVal nWidth As Long, _ ByVal nHeight As Long, _ ByVal hWndParent As Long, _ ByVal hMenu As Long, _ ByVal hInstance As Long, _ lpParam As Any) As Long Private Declare Function DestroyWindow Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function IsWindow Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function MoveWindow Lib "user32" _ (ByVal hwnd As Long, _ ByVal x As Long, _ ByVal y As Long, _ ByVal nWidth As Long, _ ByVal nHeight As Long, _ ByVal bRepaint As Long) As Long Private Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" _ (ByVal hwnd As Long, _ ByVal wMsg As Long, _ ByVal wParam As Long, _ lParam As Any) As Long Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (Destination As Any, Source As Any, _ ByVal Length As Long) Private Sub Form_Load() Call IsNewComctl32 With Text1 .Text = 25000 .Move 1000, 300, 1000, 285 Call SetWindowLong(.hwnd, _ GWL_STYLE, _ GetWindowLong(Text1.hwnd, GWL_STYLE) _ Or ES_NUMBER) End With With Check1 .Caption = "Vertical" .Value = vbUnchecked .Move 2200, 300, 1200, 285 End With With Command1 .Caption = "Create && Run ProgressBar..." .Cancel = True .Move 1000, 700, 2500, 375 End With With Label1 .AutoSize = True .WordWrap = False .Caption = "" .Move 900, 1200 End With With Label2 .AutoSize = True .WordWrap = False .Caption = "n %" .Move 3700, 780 ', 2500, 375 End With Me.ScaleMode = vbPixels End Sub Private Sub Form_Resize() 'adjust the width & height w/the form If IsWindow(hProgBar) Then MoveWindow hProgBar, _ dwPBPosLeft, dwPBPosTop, _ Me.ScaleWidth - dwPBPosLeft, _ Me.ScaleHeight - dwPBPosTop, _ 1 'display the progress bar's current size Label1.Caption = "Width: " & Me.ScaleWidth - dwPBPosLeft & _ " Height: " & Me.ScaleHeight - dwPBPosTop & _ " (pixels)" Else Label1.Caption = "(click button to create a progress bar...)" End If End Sub Private Sub Command1_Click() 'Dynamically create a progress bar and place it at the 'bottom (or the right) of the form, do stuff that takes a 'while & show the progress, then destroy the progress bar. '(The progress bar could be hidden using ShowWindow() instead 'of it being destroyed, but the time it takes to create it is 'negligible & its resources are also freed with this method) Static bRunning As Boolean 'cancel flag Dim bIsIE3 As Boolean Dim dwIterations As Long Dim dwRange As Long Dim dwStyle As Long Dim cnt As Long On Local Error GoTo progbar_exit If bRunning Then bRunning = False: Exit Sub 'Set the default progress bar styles dwStyle = WS_CHILD Or WS_VISIBLE 'if vertical selected, make it so! If Check1.Value = vbChecked Then dwStyle = dwStyle Or PBS_VERTICAL End If 'Create and show the status bar. Additional standard 'or extended window styles can be specified to alter the 'default appearance of the progress bar. The progress 'bar can also be easily created as a child window of a 'status bar part (VB "Panel"). Substitute the status bar's 'hWnd and a part's bounding rectangle (via SB_GETRECT) in 'CreateWindowEx()'s respective params below. hProgBar = CreateWindowEx(0, PROGRESS_CLASS, _ vbNullString, _ dwStyle, _ 0, 0, 0, 0, _ hwnd, 0, _ App.hInstance, _ ByVal 0) If hProgBar = 0 Then MsgBox "CreateWindowEx failed.": Exit Sub 'Here we go... the progress bar's style can't 'be changed after its been created. bRunning = True Command1.Caption = "Stop" Text1.Enabled = False Check1.Enabled = False 'Set the progress bar's static x (or y) position 'so its initially 20 pixels wide (or high). The code 'in the form_resize event uses these values to position 'the progress bar If Check1.Value = vbChecked Then dwPBPosLeft = Me.ScaleWidth - 20 dwPBPosTop = 0 Else dwPBPosTop = Me.ScaleHeight - 20 dwPBPosLeft = 0 End If 'MoveWindow() in the Form_Resize event will set the 'progress bar's initial position & size. It will also 'display the prog bar's current size in the label. Call Form_Resize 'get the number of iterations entered into the textbox dwIterations = Val(Text1.Text) 'set the range and step interval of the progress bar dwRange = MAKELPARAM(0, dwIterations) Call SendMessage(hProgBar, PBM_SETRANGE, 0&, ByVal dwRange) Call SendMessage(hProgBar, PBM_SETSTEP, ByVal 1, 0&) 'Let's do some stuff... For cnt = 1 To dwIterations 'call DoEvents to allow the loop to 'respond to a cancel (stop) command DoEvents If Not bRunning Then Exit For '<your app-specific code goes here> 'advance the current position of the progress bar 'by the step increment. Call SendMessage(hProgBar, PBM_STEPIT, 0&, ByVal 0&) Label2.Caption = Int((cnt / dwIterations) * 100) & " %" Next progbar_exit: 'Free all resources associated with the progress bar. 'If not destroyed here, the progress bar will automatically 'be destroyed when the parent window - the window specified in 'hWndParent of CreateWindowEx() - is destroyed. If IsWindow(hProgBar) Then Call DestroyWindow(hProgBar) 're-initialize form's controls bRunning = False Command1.Caption = "Create && Run ProgressBar..." Text1.Enabled = True Check1.Enabled = True Label2.Caption = "n %" End Sub Private Function MAKELPARAM(wLow As Long, wHigh As Long) As Long 'Combines two integers into a long MAKELPARAM = MAKELONG(wLow, wHigh) End Function Private Function MAKELONG(wLow As Long, wHigh As Long) As Long MAKELONG = LoWord(wLow) Or (&H10000 * LoWord(wHigh)) End Function Private Function LoWord(dwValue As Long) As Integer CopyMemory LoWord, dwValue, 2 End Function Private Function IsNewComctl32() As Boolean 'ensures that the Comctl32.dll library is loaded Dim icc As tagINITCOMMONCONTROLSEX On Error GoTo Err_InitOldVersion icc.dwSize = Len(icc) icc.dwICC = ICC_PROGRESS_CLASS 'VB will generate error 453 "Specified DLL function not found" 'here if the new version isn't installed IsNewComctl32 = InitCommonControlsEx(icc) Exit Function Err_InitOldVersion: InitCommonControls End Function |
Comments |
Save then run the project, enter the number of iterations
to execute (maximum 32k) and click the command button. If, in testing just the progress bar, this code runs the bar too fast for you to debug, add a declaration for the Sleep API to the form and add a Sleep call in the loop to simulate the time taken to process your application data. When simulating 100 to 500 files 100 milliseconds should be enough for you to see the effect. If simulating less than 100 files up the delay to 200 or 250. If simulating more than 500 or so files, decrease it as low as 10 or you'll spend all day watching it. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |