Windows 7 (Vista?) Show a progress bar in taskbar button!

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by Rescator »

Kind of a pain to make so I posted this here to save others the headache.

This example just shows the taskbar button progressbar,
I leave it to others to toy around with taskbar thumbnail toolbar controls. (mini play/pause at bottom of thumb preview for example),
or changing the thumb tooltip and whatnot.
There is also a ITaskbarList4 but it only ads one method so it's not used in this code...

If anyone see any mistakes (I'm green when it comes to interfaces and COM!) by all means post corrections.

Introducing The Taskbar APIs
ITaskbarList3

Code: Select all

;Public Domain
EnableExplicit

#PB_Compiler_Exe=#True ;This does not exist (yet?)

;http://msdn.microsoft.com/en-us/library/dd464660%28VS.85%29.aspx
Global _ScaleDPI_X_.f=1.0,_ScaleDPI_Y_.f=1.0,_ScaleDPI_font_$
#DefaultDPIX=96.0 ;Different platforms might have different default DPI, Windows is 96 DPI.
#DefaultDPIY=96.0
Procedure InitScaleDPI() ;Windows 5.0 or higher needed for minimum functionality of this procedure.
 Protected dpiaware.l=#False,dc.i,lpx.i,lpy.i,dll.i,*SetProcessDPIAware,*IsProcessDPIAware,ncm.NONCLIENTMETRICS,font.i
 ;This part is Windows 6.x+ only (Vista etc.) and must be done before we use devcaps.
 ;http://msdn.microsoft.com/en-us/library/dd464660%28VS.85%29.aspx#declaring_dpi_awareness
 ;You really should use the DPI aware manifest instead of SetProcessDPIAware() when possible.
 ;On Windows 2000 and XP the manifest has no effect and set dpi aware is not available,
 ;however Devicecaps still returns usefull info that can be used.
 ;Note! If the dpi aware manifest is missing on Vista and Win7 then the OS will lie on devicecaps and will autoscale the entire app window.
 CompilerIf #PB_Compiler_Exe ;Only use this in exes, as dlls inherit DPI from the calling process.
  ;If the exe or the calling exe in case of this being a dll is allready dpi aware (like through a manifest),
  ;then we skip using the the set dpi aware function, a dll should never use the set function, but it should check if the process id dpi aware
  ;and apply the proper modifiers where appropriate obviously.
  dll=OpenLibrary(#PB_Any,"user32.dll")
  If dll
	  *IsProcessDPIAware=GetFunction(dll,"IsProcessDPIAware")
   If *IsProcessDPIAware
    dpiaware=CallFunctionFast(*IsProcessDPIAware)
   EndIf
   If Not dpiaware
	   *SetProcessDPIAware=GetFunction(dll,"SetProcessDPIAware")
	   If *SetProcessDPIAware
	    CallFunctionFast(*SetProcessDPIAware)
	   EndIf
   EndIf
  EndIf
 CompilerEndIf
 dc=GetDC_(#Null)
 If dc
	 lpx=GetDeviceCaps_(dc,#LOGPIXELSX)
	 lpy=GetDeviceCaps_(dc,#LOGPIXELSY)
	 If lpx>0
 	 _ScaleDPI_X_=lpx/#DefaultDPIX
 	EndIf
	 If lpy>0
 	 _ScaleDPI_Y_=lpy/#DefaultDPIY
 	EndIf
	 ReleaseDC_(#Null,dc)
 EndIf
 ;Get the system font for message boxes etc.
 ;We default to a size of 9, which is also the Vista and Win7 default size.
 ;The OS will automatically (Vista and Win7 at least) scale the font per the current user's DPI setting.
 ncm\cbSize=SizeOf(NONCLIENTMETRICS)
 If SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS,SizeOf(NONCLIENTMETRICS),ncm,#Null)
  _ScaleDPI_font_$=PeekS(@ncm\lfMessageFont\lfFaceName)
		font=LoadFont(#PB_Any,_ScaleDPI_font_$,9,#PB_Font_HighQuality)
		If font
		 SetGadgetFont(#PB_Default,FontID(font))
		EndIf
 EndIf
EndProcedure
InitScaleDPI()
Macro ScaleDPIx(x)
 (x)*_ScaleDPI_X_
EndMacro
Macro ScaleDPIy(y)
 (y)*_ScaleDPI_Y_
EndMacro
Macro ScaleDPIfont()
 _ScaleDPI_font_$
EndMacro

#CLSCTX_ALL = 0

#TBPF_NOPROGRESS    = $0
#TBPF_INDETERMINATE = $1
#TBPF_NORMAL        = $2
#TBPF_ERROR         = $4
#TBPF_PAUSED        = $8

#TBATF_USEMDITHUMBNAIL   = $1
#TBATF_USEMDILIVEPREVIEW = $2

#THB_BITMAP  = $1
#THB_ICON    = $2
#THB_TOOLTIP = $4
#THB_FLAGS   = $8

#STPF_NONE                      = $00000000
#STPF_USEAPPTHUMBNAILALWAYS     = $00000001
#STPF_USEAPPTHUMBNAILWHENACTIVE = $00000002
#STPF_USEAPPPEEKALWAYS          = $00000004
#STPF_USEAPPPEEKWHENACTIVE      = $00000008

Structure THUMBBUTTON
 dwMask.l
 iId.l
 iBitmap.l
 hIcon.i
 szTip.u[260]
 dwFlags.l
EndStructure

Interface ITaskbarList3 Extends ITaskbarList2
 SetProgressValue.i(hWnd.i,ullCompleted.q,ullTotal.q)
 SetProgressState.i(hWnd.i,tbpFlags.l)
 RegisterTab.i(hWndTab.i,hWndMDI.i)
 UnregisterTab.i(hWndTab.i)
 SetTabOrder.i(hWndTab.i,hWndInsertBefore.i)
 SetTabActive.i(hWndTab.i,hWndMDI.i,tbatFlags.l)
 ThumbBarAddButtons.i(hWnd.i,cButtons.l,*pButton)
 ThumbBarUpdateButtons.i(hWnd.i,cButtons.l,*pButton)
 ThumbBarSetImageList.i(hWnd.i,himl.i)
 SetOverlayIcon.i(hWnd.i,hIcon.i,pszDescription$)
 SetThumbnailTooltip.i(hWnd.i,pszTip$)
 SetThumbnailClip.i(hWnd.i,*prcClip)
EndInterface

Interface ITaskbarList4 Extends ITaskbarList3
 SetTabProperties.i(hwndTab.i,stpFlags.l)
EndInterface

DataSection
 CLSID_TaskBarList:
  Data.l $56FDF344
  Data.w $FD6D, $11D0
  Data.b $95, $8A, $00, $60, $97, $C9, $A0, $90
 IID_ITaskBarList3:
  Data.l $ea1afb91
  Data.w $9e28,$4b86
  Data.b $90,$E9,$9e,$9f,$8a,$5e,$ef,$af
EndDataSection

Enumeration 1
 #Window_Main
EndEnumeration

Enumeration 1
 #Gadget_Main_Text
 #Gadget_Main_Progress
EndEnumeration

Enumeration 1
 #Timer_Progress
EndEnumeration

InitScaleDPI()
Define ptl.ITaskbarList3,event,progress,progressmax,pp.ITaskbarList3

;Note1: It seems that CoInitialize, HrInit and CoUninitialize are not needed (does PB apply these?)
;Note2: Only tried this on Windows 7, does Vista display the taskbutton progress?
;Note3: You should wait to use the taskbar stuff until the taskbar button has been created.
; DWORD g_wmTBC = (DWORD)-1;
; 
; //In the window Procedure:
; switch (msg) {
; Case WM_CREATE:
;     g_wmTBC = RegisterWindowMessage(L"TaskbarButtonCreated");
;     //Proceed To create the window
; Case g_wmTBC:
;     //The taskbar button has been created
; }

If OpenWindow(#Window_Main,0,0,ScaleDPIx(320),ScaleDPIy(160),"ProgressBar",#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
 progress=0
 progressmax=100
 TextGadget(#Gadget_Main_Text,ScaleDPIx(10),ScaleDPIy(10),ScaleDPIx(250),ScaleDPIy(20),"Progress ("+Str(progress)+"/"+Str(progressmax)+")",#PB_Text_Center)
 ProgressBarGadget(#Gadget_Main_Progress,ScaleDPIx(10),ScaleDPIy(30),ScaleDPIx(250),ScaleDPIy(30),0,100)
 SetGadgetState(#Gadget_Main_Progress,progress)
 CoInitialize_(#Null)

 CoCreateInstance_(?CLSID_TaskBarList,#Null,1,?IID_ITaskBarList3,@ptl)

 If ptl
  ptl\HrInit()
  ptl\SetProgressValue(WindowID(#Window_Main),progressmax,progressmax)
  ptl\SetProgressState(WindowID(#Window_Main),#TBPF_INDETERMINATE)
 EndIf
 AddWindowTimer(#Window_Main,#Timer_Progress,1000)
 Repeat
  event=WaitWindowEvent()
  If event=#PB_Event_Timer
   progress+1;Random(progressmax)
   SetGadgetState(#Gadget_Main_Progress,progress)
   SetGadgetText(#Gadget_Main_Text,"Progress ("+Str(progress)+"/"+Str(progressmax)+")")
   If ptl
    If progress=5
     ptl\SetProgressState(WindowID(#Window_Main),#TBPF_NORMAL)
     RemoveWindowTimer(#Window_Main,#Timer_Progress)
     AddWindowTimer(#Window_Main,#Timer_Progress,100)
    ElseIf progress>5
     ptl\SetProgressValue(WindowID(#Window_Main),progress,progressmax)
    EndIf
   EndIf
   If progress=101
    RemoveWindowTimer(#Window_Main,#Timer_Progress)
    AddWindowTimer(#Window_Main,#Timer_Progress,1000)
    ptl\SetProgressState(WindowID(#Window_Main),#TBPF_PAUSED)
   ElseIf progress=102
    ptl\SetProgressState(WindowID(#Window_Main),#TBPF_NORMAL)
   ElseIf progress=103
    ptl\SetProgressState(WindowID(#Window_Main),#TBPF_ERROR)
   ElseIf progress=104
    ptl\SetProgressState(WindowID(#Window_Main),#TBPF_INDETERMINATE)
    progress=0
   EndIf
  EndIf
 Until event=#PB_Event_CloseWindow
EndIf
RemoveWindowTimer(#Window_Main,#Timer_Progress)
If ptl
 ptl\Release()
EndIf
CloseWindow(#Window_Main)
CoUninitialize_()
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by Foz »

Very cool. 8)

Unfortunately, it seems ridiculously complex for such a minor effect, you do have to ask the question... is it worth the effort? :?
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by rsts »

Damn slick effect.

Thanks for sharing this :)

cheers
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by SFSxOI »

Very Nice! Thank you very much! :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by Shardik »

Rescator,

thank you for your code example, especially your helpful comments and the MSDN links.

For those interested in yet another code example: DarkDragon already posted this example
in the German forum:
http://www.purebasic.fr/german/viewtopi ... 47&start=8
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by SFSxOI »

@Shardik

The code by Dragon doesn't take into account DPI Scaling.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Windows 7 (Vista?) Show a progress bar in taskbar button!

Post by Rescator »

DPI scaling, oh right, that was code in my test source, leftover from my ScaleDPI in another post here, but since it was fully functional I just left it in.
I've made it standard to always take DPI scaling into account on current and future software, and when PureBasic gets more support for DPI scaling it's very easy to just do a search and replace to remove the scale macros etc.

Didn't know of DarkDragon's code, then again I only frequent the international forum, so... Never hurts to have more examples though :)
rudz
User
User
Posts: 35
Joined: Sun Mar 21, 2010 6:59 am
Location: Denmark
Contact:

Re: Windows 7 (Vista?) Show a progress bar in taskbar button

Post by rudz »

Nice code!

Only adds ~1kb to my compiled+compressed .exe :)

Oh, and it works fine for me in win7/64
AMD FX-8350 @ ~4.8GHz | 8GB Corsair DDR3-SDRAM @ 1800Mhz | 7even Ult & Manjaro 0.8.7.1 | PB 5.3
Web: rudz.dk
Post Reply