PureBasic Forum
http://forums.purebasic.com/english/

Get the Shell Thumbnail for files
http://forums.purebasic.com/english/viewtopic.php?f=12&t=20838
Page 1 of 2

Author:  freak [ Wed Mar 29, 2006 10:14 pm ]
Post subject:  Get the Shell Thumbnail for files

This is just a little something i played around with. Maybe it is usefull to somebody.
It allows to easily get a preview image from the shell like the ones explorer displays.
This requires PB4 beta8 to run.

It behaves just like CreateImage(). Supports #PB_Any as well as static numbers.
The function fails (returns 0) if there is no preview supported for the file type.

Here is the procedure:
Code:
Procedure GetShellThumbnail(FileName$, Image, Width, Height, Depth = #PB_Image_DisplayFormat)
  Protected Result = 0, ImageResult
  Protected Desktop.IShellFolder, Folder.IShellFolder
  Protected Extract.IExtractImage
  Protected *pidlFolder.ITEMIDLIST, *pidlFile.ITEMIDLIST 
  Protected Priority, Flags, Bitmap = 0, size.SIZE

  If SHGetDesktopFolder_(@Desktop) >= 0
    If Desktop\ParseDisplayName(#Null, #Null, GetPathPart(FileName$), #Null, @*pidlFolder, #Null) = #S_OK
      If Desktop\BindToObject(*pidlFolder, #Null, ?IID_IShellFolder, @Folder) = #S_OK
        If Folder\ParseDisplayName(#Null, #Null, GetFilePart(FileName$) , #Null, @*pidlFile, #Null) = #S_OK
          If Folder\GetUIObjectOf(#Null, 1, @*pidlFile, ?IID_IExtractImage, 0, @Extract) = #S_OK

            ImageResult = CreateImage(Image, Width, Height, Depth)
            If ImageResult
              If Image = #PB_Any
                Image = ImageResult
              EndIf   
              If Depth = #PB_Image_DisplayFormat
                Depth = ImageDepth(Image)
              EndIf
                                 
              size\cx = Width
              size\cy = Height
             
              If Extract\GetLocation(Space(#MAX_PATH), #MAX_PATH, @Priority, @size, Depth, @Flags) >= 0               
                If Extract\Extract(@Bitmap) >= 0 And Bitmap
                                 
                  If StartDrawing(ImageOutput(Image))
                    DrawImage(Bitmap, 0, 0)
                    StopDrawing()                   
                    Result = ImageResult
                  EndIf
                 
                  DeleteObject_(Bitmap)
                EndIf
              EndIf               
              Extract\Release()
            EndIf
           
            If Result = 0
              FreeImage(Image)
            EndIf           
          EndIf
                   
          CoTaskMemFree_(*pidlFile)
        EndIf                       
        Folder\Release()
      EndIf     
      CoTaskMemFree_(*pidlFolder)     
    EndIf   
    Desktop\Release()
  EndIf

  ProcedureReturn Result
 
  DataSection 
    IID_IShellFolder: ; {000214E6-0000-0000-C000-000000000046}
      Data.l $000214E6
      Data.w $0000, $0000
      Data.b $C0, $00, $00, $00, $00, $00, $00, $46
 
    IID_IExtractImage: ; {BB2E617C-0920-11D1-9A0B-00C04FC2D6C1}
      Data.l $BB2E617C
      Data.w $0920, $11D1
      Data.b $9A, $0B, $00, $C0, $4F, $C2, $D6, $C1
  EndDataSection 
EndProcedure


A simple example:
Code:
#ExplorerGadget = 0
#ImageGadget    = 1
#Image = 0

If OpenWindow(0, 0, 0, 500, 400, "Shell Thumbnails", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  CreateGadgetList(WindowID(0))
  ExplorerTreeGadget(#ExplorerGadget, 5, 5, 190, 390, "C:\")
  ImageGadget(#ImageGadget, 225, 100, 250, 200, 0, #PB_Image_Border)

  Repeat
    Event = WaitWindowEvent()
   
    If Event = #PB_Event_Gadget And EventGadget() = #ExplorerGadget And EventType() = #PB_EventType_Change     
   
      If GetShellThumbnail(GetGadgetText(#ExplorerGadget), #Image, 250, 200)
        SetGadgetState(#ImageGadget, ImageID(#Image))
      Else
        SetGadgetState(#ImageGadget, 0)
      EndIf
     
    EndIf
   
  Until Event = #PB_Event_CloseWindow
EndIf
End


Here is a more complex example. It uses SHGetFileInfo_() to get an Icon for the file
if no preview is available to create a nice folder preview:

Code:
#ExplorerGadget = 0
#ScrollGadget   = 1
#ProgressGadget = 2

Structure File
  FileName$
  Text$
  Image.l 
  Gadget.l ; Its a ContainerGadget, so the others inside are freed as well
EndStructure

NewList File.File()

If OpenWindow(0, 0, 0, 800, 600, "Shell Thumbnails", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  CreateGadgetList(WindowID(0))
  ExplorerTreeGadget(#ExplorerGadget, 5, 5, 240, 590, "C:\", #PB_Explorer_NoFiles)
  ScrollAreaGadget(#ScrollGadget, 250, 5, 545, 570, 520, 10, 10)
  CloseGadgetList()
  ProgressBarGadget(#ProgressGadget, 250, 580, 545, 15, 0, 100)

  Repeat
    Event = WaitWindowEvent()
   
    If Event = #PB_Event_Gadget And EventGadget() = #ExplorerGadget And EventType() = #PB_EventType_Change     
   
      ; Clear the old content of the display
      ;
      ForEach File()
        FreeGadget(File()\Gadget)
        FreeImage(File()\Image)
      Next File()
      ClearList(File())
     
      ; Creating the thumbnail may take a little time for certain file types
      ; (for example big PowerPoint presentations), especially when there are lots
      ; of files in a folder. So the text information is read first (which is quite fast)
      ; and the images are created later with a progressbar to indicate the progress
      ;     
      Count = 0
      If ExamineDirectory(0, GetGadgetText(#ExplorerGadget), "*.*")
        While NextDirectoryEntry(0)
          If DirectoryEntryType(0) = #PB_DirectoryEntry_File
            AddElement(File())
            File()\FileName$ = GetGadgetText(#ExplorerGadget) + DirectoryEntryName(0)
            File()\Text$ = "Name: " + File()\FileName$ + Chr(13)
            File()\Text$ + "Size: " + Str(DirectoryEntrySize(0)) + " Bytes" + Chr(13)
            File()\Text$ + FormatDate("Created: %mm/%dd/%yyyy", DirectoryEntryDate(0, #PB_Date_Created)) + Chr(13)
            File()\Text$ + FormatDate("Modified: %mm/%dd/%yyyy", DirectoryEntryDate(0, #PB_Date_Modified)) + Chr(13)
            File()\Text$ + FormatDate("Accessed: %mm/%dd/%yyyy", DirectoryEntryDate(0, #PB_Date_Accessed))           
            Count + 1
          EndIf
        Wend
      EndIf 
     
      If Count > 0
             
        OpenGadgetList(#ScrollGadget)
        SetGadgetState(#ProgressGadget, 0)
        While WindowEvent(): Wend ; Refresh the display so it looks better
       
        ForEach File()
          index = ListIndex(File())
         
          ; Create the thumbnail
          File()\Image = GetShellThumbnail(File()\FileName$, #PB_Any, 100, 80)           
         
          ; If no image could be created, we try to read the Icon for the file type and
          ; show that
          ;
          If File()\Image = 0
            File()\Image = CreateImage(#PB_Any, 100, 80)
            If File()\Image And StartDrawing(ImageOutput(File()\Image))               
              Box(0, 0, 100, 80, $FFFFFF)
              If SHGetFileInfo_(@File()\FileName$, 0, @info.SHFILEINFO, SizeOf(SHFILEINFO), #SHGFI_ICON|#SHGFI_LARGEICON)
                DrawImage(info\hIcon, 34, 24)
                DestroyIcon_(info\hIcon)
              EndIf               
              StopDrawing()
            EndIf                           
          EndIf
         
          File()\Gadget = ContainerGadget(#PB_Any, 5, 5+index*90, 510, 80, #PB_Container_Flat)
            ImageGadget(#PB_Any, 0, 0, 100, 80, ImageID(File()\Image))         
            TextGadget(#PB_Any, 105, 5, 400, 70, File()\Text$)
          CloseGadgetList()
       
          ; Update the Gadget states and refresh the display
          ;
          SetGadgetState(#ProgressGadget, (index * 100)/Count)
          SetGadgetAttribute(#ScrollGadget, #PB_ScrollArea_InnerHeight, (index+1)*90 + 10) 
          While WindowEvent(): Wend
        Next File()
       
        CloseGadgetList()       
      EndIf   
 
      SetGadgetState(#ProgressGadget, 100)   
      SetGadgetAttribute(#ScrollGadget, #PB_ScrollArea_InnerHeight, Count*90 + 10)     
     
    EndIf
   
  Until Event = #PB_Event_CloseWindow
EndIf
End

Author:  dell_jockey [ Wed Mar 29, 2006 10:34 pm ]
Post subject: 

Danke Timo!

Author:  dige [ Thu Mar 30, 2006 7:45 am ]
Post subject: 

Wow!! That rocks. Thank you fr34k!

Author:  Dare2 [ Thu Mar 30, 2006 10:10 am ]
Post subject: 

Awesome. Thank you!

Author:  Trond [ Thu Mar 30, 2006 4:25 pm ]
Post subject: 

I think there is an error somewhere, because no preview is shown for my deneba canvas files when I use the simple example, but the preview is shown in windows explorer and in the complex example.

Author:  techjunkie [ Thu Mar 30, 2006 4:32 pm ]
Post subject: 

Wow! Really nice! Thanks! :D

Author:  va!n [ Thu Mar 30, 2006 6:55 pm ]
Post subject: 

fantastic *10/10 points*
great work fr34k!

Author:  freak [ Thu Mar 30, 2006 8:53 pm ]
Post subject: 

Trond: Are you sure its not just the file icon you see in the complex example ?
It works fine here for all file types.

Author:  Trond [ Fri Mar 31, 2006 4:36 pm ]
Post subject: 

freak wrote:
Trond: Are you sure its not just the file icon you see in the complex example ?
It works fine here for all file types.
Of course I am sure.
Simple example (file icon show in file list): http://img92.imageshack.us/my.php?image=blur2560mz.png
Advanced example (preview shows): http://img483.imageshack.us/my.php?image=blur2569ic.png
Windows explorer: http://img394.imageshack.us/my.php?image=blur2567yd.png

Author:  Sparkie [ Sat Apr 01, 2006 9:10 pm ]
Post subject: 

Very useful! Thank you freak. :)

Author:  freak [ Wed Jul 05, 2006 1:23 pm ]
Post subject: 

Just a quick note that this code needs a CoInitialize_(0) call (and a CoUninitialize_() at the end)
to work properly.

The ExplorerTreeGadget() does these calls automatically, thats why it works as it is,
but does not work if you take the gadget out of the code.

Author:  TheMaster [ Tue Oct 07, 2008 4:58 pm ]
Post subject: 

Real great work!!!

However, could anyone please give me a short hint, how can I select a thumbnail within the gadget. The idea is to pass the selected thumbnail image file name which is in the gadget list to another programme (image editor paint.net). Paint.net is missing the preview or browser function but with this snipplet I could very easy preview the files and pass them to paint.net by using the run command.


Many thanks

Author:  Hi-Toro [ Wed Oct 08, 2008 5:45 pm ]
Post subject: 

Excellent piece of work.

Author:  c4s [ Tue Nov 30, 2010 12:06 am ]
Post subject:  Re: Get the Shell Thumbnail for files

Great work!

A small tip: PureBasic now supports alpha channels, so do the following to maintain it:
  • Use "32" as Depth
  • Put "| #PB_Image_Transparent" at the end of "CreateImage(Image, Width, Height, Depth)" (to create a fully transparent image)
  • Set "DrawImage()" to "DrawAlphaImage()"


I still have a small question:
How is it possible to find out the real thumbnail dimension (or the original one) using this interface stuff?

Author:  TomS [ Tue Nov 30, 2010 1:02 pm ]
Post subject:  Re: Get the Shell Thumbnail for files

Looks nice. Thanks for sharing.
But images are up-side-down (bmp and jpeg).
Thumbnails of Videos and OpenOffice Docs look fine. (second Example)

-PB 4.51 - Win7 Home Premium 32bit

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/