Welcome to MSDN Blogs Sign in | Join | Help

Create your own Flip Task Bar with live thumbnails using Vista Desktop Window Manager DWM

 

The sample below uses Desktop Window Manager  under Windows Vista with Aero to get dynamic live thumbnails of running applications. If a movie is playing in Windows Media Player, it will play in the thumbnail too!

 

EnumChildWindows or EnumWindows is used to enumerate all running windows created by the various processes on your machine.

 

I extracted code from: How does EventHandler work? IConnectionPoint! to make the CAsmLib class to generate assembly code. The sample below uses the class to generate ASM code that gets called by EnumChildWindows and calls _VFP.DoCmd method to insert the Window handles found into a cursor.

 

On both XP and Vista, the code will generate a cursor with Window Handles and their titles.

 

A SQL statement executed in a timer routine determines if any new processes were added and if so, to refresh the display.

                   SELECT hWnd,Title FROM NewTopLevel WHERE hWnd NOT in (SELECT hWnd FROM TopLevel) UNION ;

                             SELECT hWnd,Title FROM TopLevel WHERE hWnd NOT in (SELECT hWnd FROM NewTopLevel) ;

                             INTO CURSOR temp

 

 

If you’re running on Vista and DwmIsCompositionEnabled, the code will then create a form and an array of live thumbnails on it. The form uses an array of invisible commandbuttons for each thumbnail. Using an Image control without an image displays a cross. All we’re doing is providing an hWnd and a rect for DWM to draw the thumbnail.

 

(Vista Aero can have DwmIsCompositionEnabled enabled or disabled. See Control Panel->System and Maintenance->System->Advanced System Settings->Advanced->Performance->Settings->Visual Effects->Enable desktop composition)

 

GetWindowThreadProcessId is called to get the Process Id of the window handle.

 

Play a movie: make it repeat if it’s short, do things in other windows, and you’ll see the thumbnails update on the form. Hit Alt-Tab (or Alt-Ctrl-Tab to keep the flip display on, or even WindowsKey-Tab), and you’ll see the thumbnail still live. Use the slider to changes the size of the thumbnails. You can even make the thumbs larger than the source application!

 

Click on a thumbnail to make it the foreground application. Resize the thumbnail form. Modify source windows by editing text, etc. Hit WindowKey->M to minimize all windows.

 

 

 

CLEAR ALL

CLEAR

MODIFY COMMAND PROGRAM() NOWAIT

SET SAFETY OFF

PUBLIC oForm

oForm=CREATEOBJECT("CThumbForm")

         

#define WS_VISIBLE 0x10000000

#define WS_BORDER 0x00800000

 

DEFINE CLASS CThumbForm as Form

          ShowWindow=2        && Top Level

          width=SYSMETRIC(1)  && entire width of display

          height=100

          MinButton=.f. && don't allow minimize for us

          nThumbs=0   && number of thumbs currently on form

          fDWM = .f.    && are we running under Vista Desktop Window Management?

          nThumbWidth=400    && size of thumb to draw

          nThumbHeight=this.nThumbWidth * SYSMETRIC(2)/SYSMETRIC(1)        && same aspect ratio as desktop

          ADD OBJECT cmdQuit as CommandButton WITH Caption="\<Quit",cancel=.t.

          ADD OBJECT cmdRefresh as CommandButton WITH Caption="\<Refresh",left=120

          ADD OBJECT oSlider as cSlider WITH left=250

          ADD OBJECT oTimer as Timer WITH interval=2000 && millisecs

          PROCEDURE oTimer.Timer

                   thisform.GetHWnds("NewTopLevel")

                   SELECT hWnd,Title FROM NewTopLevel WHERE hWnd NOT in (SELECT hWnd FROM TopLevel) UNION ;

                             SELECT hWnd,Title FROM TopLevel WHERE hWnd NOT in (SELECT hWnd FROM NewTopLevel) ;

                             INTO CURSOR temp

                   IF _Tally>0    && a new window was created or destroyed

                             thisform.GetThumbNails()    && ToDo: optimize for only the change

                   ENDIF

          PROCEDURE cmdRefresh.Click

                   thisform.GetThumbNails()

          PROCEDURE cmdQuit.Click

                   thisform.release

          PROCEDURE Init

                   SET TALK OFF

                   IF VAL(OS(3))>=6    && runnning under Vista. Check for Desktop Compostion enabled

                             DECLARE integer DwmIsCompositionEnabled IN dwmapi integer @ dwEnabled

                             dwEnabled=0

                             IF DwmIsCompositionEnabled(@dwEnabled) = 0 AND dwEnabled>0

                                      this.fDWM = .t.

                             ENDIF

                   ENDIF

                   IF this.fDWM

                             DECLARE integer DwmRegisterThumbnail IN dwmapi integer hwndDest, integer  hwndSrc, integer @ nThumbnailId

                             DECLARE integer DwmUnregisterThumbnail IN dwmapi integer nThumbnailId

                             DECLARE integer DwmQueryThumbnailSourceSize IN dwmapi integer nThumbnailId, string @pSize

                             DECLARE integer DwmUpdateThumbnailProperties IN dwmapi integer hThumbnailId, string  @ ptnProperties

                             DECLARE integer SetForegroundWindow IN WIN32API integer

                             DECLARE integer GetWindowPlacement IN WIN32API integer hWnd, string @ pPlacement

                             DECLARE integer SetWindowPlacement IN WIN32API integer hWnd, string @ pPlacement

                            

                             this.Visible=1

*                           this.GetThumbNails() && Resize will call GetThumbNails

                   ELSE

                             NEWOBJECT("CEnumWindows")      && call the class that creates the cursor of hWnds

                             LOCATE         && go to the top of the cursor

                             BROWSE LAST NOWAIT

                             RETURN .f.    && don't create form

                   ENDIF

          PROCEDURE Resize

                   this.GetThumbNails()

          PROCEDURE GetHWnds(DestCursor as string)

                   NEWOBJECT("CEnumWindows")      && call the class that creates the cursor of hWnds

                   SELECT * FROM hwnds WHERE BITAND(style,WS_VISIBLE+WS_BORDER) = WS_VISIBLE+WS_BORDER AND ;

                             hWnd != thisform.HWnd ;

                             INTO CURSOR (DestCursor)  && Only those hWnds which are visible and have a border

                   RETURN _tally

          PROCEDURE GetThumbNails

                   LOCAL cStr,oLbl,cName,x,y,oi

                   thisform.LockScreen= .T.

                   FOR indx = 1 TO thisform.nThumbs

                             cName="im"+PADL(indx,3,"0")       && im001, im002...

                             thisform.RemoveObject(cName)

                             IF TYPE("thisForm."+cName+"lbl")="O"

                                      thisform.RemoveObject(cName+"lbl")

                             ENDIF

                   ENDFOR

                   thisform.nThumbs=this.GetHWnds("TopLevel")

                   INDEX on hwnd TAG hwnd

                   nRatio = thisform.oSlider.Value/thisform.oSlider.max

                   x = 0

                   y = 20

                   indx=1

                   SCAN

                             cName="im"+PADL(indx,3,"0")       && im001, im002...

                             thisform.AddObject(cName,"CThumb")

                             cStr="Thisform."+cName

                             oi = EVALUATE(cStr)

                             oi.Height = this.nThumbHeight * nRatio

                             oi.Width = this.nThumbWidth * nRatio

                             oi.Left = x

                             oi.Top = y

                             oi.visible=1