title: Preload folder icon for a specific folder in Windows Icon cache, in C# or VB.NET
body: <p>I need to mention a 3rd party program, or better said the source-code of <a href="https://github.com/bruhov/WinThumbsPreloader/blob/master/WinThumbsPreloader/WinThumbsPreloader/ThumbnailPreloader.cs" rel="noreferrer">WinThumbsPreloader</a> program, which contains all the necessary code written in C# to preload the thumbnail of a file in Windows thumbnails cache as you can see in this demo:</p>
  
  <p><a href="https://i.stack.imgur.com/qIEiZ.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/qIEiZ.gif" alt="enter image description here"></a></p>
  
  <p>The problem is that what I need to preload is the icon of a folder, but the <a href="https://docs.microsoft.com/en-us/windows/win32/api/thumbcache/nf-thumbcache-ithumbnailcache-getthumbnail" rel="noreferrer">IThumbnailCache::GetThumbnail</a> method does not allow to pass a folder item, and it will return error code <code>0x8004B200</code> (<a href="https://docs.microsoft.com/en-us/windows/win32/api/thumbcache/nf-thumbcache-ithumbnailcache-getthumbnail" rel="noreferrer">WTS_E_FAILEDEXTRACTION</a>):</p>
  
  <blockquote>
    <p>The Shell item does not support thumbnail extraction. For example, .exe or .lnk items.</p>
  </blockquote>
  
  <p>In other words, I need to do the same thing <strong>WinThumbsPreloader</strong> program does, but for folder icons instead of folder/icon thumbnails.</p>
  
  <p>So, what I mean is that I have a folder with a <strong>desktop.ini</strong> file inside, which as you probably know it can serve to replace the default icon/thumbnail for the folder that stores that <strong>desktop.ini</strong> file. An example of <strong>desktop.ini</strong> file content:</p>
  
  <pre><code>[.ShellClassInfo]
  IconResource=FolderPreview.ico,0
  </code></pre>
  
  <p>The reason why I need to preload folders is to avoid the icon cache generation every time that I navigate through a folder.</p>
  
  <p>To clear doubts, I would like to avoid this slow folder icon generation:</p>
  
  <p><a href="https://i.stack.imgur.com/U3BYI.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/U3BYI.gif" alt="before"></a></p>
  
  <p>And instead, get this improved speed:</p>
  
  <p><a href="https://i.stack.imgur.com/cJNIy.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/cJNIy.gif" alt="after"></a></p>
  
  <p>My question is: In C# or VB.NET, how can I programmatically preload the icon of a specific folder in Windows icon cache?.</p>
  
  <p>It seems that <strong>IThumbnailCache</strong> interface is not the way to go for this problem...</p>
  
  <hr>
  
  <blockquote>
    <p>UPDATE 1</p>
  </blockquote>
  
  <p>Following @Jimi's commentary suggestions, this is the approach I'm trying:</p>
  
  <pre><code>Public Shared Sub PreloadInIconCache(path As String, 
                                       Optional iconSize As Integer = 256)
  
      Dim iIdIShellItem As New Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")
      Dim shellItem As IShellItem = Nothing
      Dim shellItemIF As IShellItemImageFactory
      Dim iconFlags As IShellItemImageFactoryGetImageFlags = 
                       IShellItemImageFactoryGetImageFlags.IconOnly
  
      SHCreateItemFromParsingName(path, IntPtr.Zero, iIdIShellItem, shellItem)
      shellItemIF = DirectCast(shellItem, IShellItemImageFactory)
      shellItemIF.GetImage(New NativeSize(iconSize, iconSize), iconFlags, Nothing)
  
      Marshal.ReleaseComObject(shellItemIF)
      Marshal.ReleaseComObject(shellItem)
      shellItemIF = Nothing
      shellItem = Nothing
  
  End Sub
  </code></pre>
  
  <p>It caches the icons. If I call this method for lets say a directory that contains 1000 subfolders with custom icons, then the size of <strong>iconcache_256.db</strong> increases like around 250 MB, so its a clear evidence that icons are being cached, however I'm doing something wrong because those cached icons are not used by the operating system. I mean, if after I call that method and then I manually use Explorer.exe to navigate to that directory, the operating system starts again extracting and caching the icons for all the 1000 subfolders creating NEW icon references, so <strong>iconcache_256.db</strong> doubles its file size to around 500 MB, and this is a evidence that <strong>iconcache_256.db</strong> contains both the icons I cached using the method above, and the icons cached by the operating system itself, so the icon cache references that I generate calling the method above differ in some way from the icon cache references generated by the operating system itself, and that is what I'm doing wrong...</p>
  
  <p>What I'm doing wrong?.</p>
  
  <blockquote>
    <p>UPDATE 2</p>
  </blockquote>
  
  <p>Using <strong>WindowsAPICodePack</strong> v1.1 library (from Nuget manager) I'm having the same problem as described in the code of the <strong>UPDATE 1</strong> using <code>IShellItemImageFactory.GetImage</code>: I can extract the icons and the icons are cached in <strong>iconcache_256.db</strong> file (and other *.db files too of less con cache size), but If I navigate to the directory through Explorer.exe then the operating system starts extracting and caching again the icon for the same folders I already cached...</p>
  
  <p>Full code sample:</p>
  
  <pre><code>Imports Microsoft.WindowsAPICodePack.Shell
  ...
  
  Dim directoryPath As String = "C:\Directory"
  Dim searchPattern As String = "*"
  Dim searchOption As SearchOption = SearchOption.AllDirectories
  
  For Each dir As DirectoryInfo In New DirectoryInfo(directoryPath).EnumerateDirectories(searchPattern, searchOption)
  
      Console.WriteLine($"Extracting icon for directory: '{dir.FullName}'")
  
      Using folder As ShellFolder = DirectCast(ShellFolder.FromParsingName(dir.FullName), ShellFolder)
          folder.Thumbnail.FormatOption = ShellThumbnailFormatOption.IconOnly
          folder.Thumbnail.RetrievalOption = ShellThumbnailRetrievalOption.Default
  
          Using ico As Bitmap = folder.Thumbnail.Bitmap ' Or: folder.Thumbnail.Icon
              ' PictureBox1.Image = ico
              ' PictureBox1.Update()
              ' Thread.Sleep(50)
          End Using
  
      End Using
  
  Next dir
  </code></pre>
  
  <p>I'm not sure why the operating system insists to extract new icons and cache them when I already cached them, this multiplies x2 the cached icon references in <strong>iconcache_256.db</strong> (and in the other *.db files), because if I iterate 1000 subfolders from a directory to extract and cache their icons, if after I do that I navigate to that folder through Explorer.exe then the O.S. will extract and cache again those 1.000 subfolder icons creating NEW entries in <strong>iconcache_256.db</strong> (and in the other *.db files). </p>
  
  <p>I don't know how to read the database format of <strong>iconcache_256.db</strong> file, so I don't know the structure format, but if the structure takes a directory path as one of its fields then I suspect the code approaches I used maybe forces to add a directory path field that differs from what the operating system adds in the icon cache field when I navigate to the folder to cache icons through Explorer.exe, and maybe for that reason the icon cache references are multiplied x2... just I'm speculating...</p>
  
  <blockquote>
    <p>UPDATE 3</p>
  </blockquote>
  
  <p>I thought that maybe the real problem could be that the references added in icon cache *.db files maybe are per-process and for that reason when I navigate to the directory with Explorer.exe it starts extracting and caching again the icons that I already extracted and cached when debugging my executable in Visual Studio...</p>
  
  <p>So I did a test running the same code to extract/cache folder icons from two different processes just by building the same project to two executable with different names and different assembly guids. I discovered that the icon cache references in *.db files are NOT multiplied/duplicated when I run the second executable, so the per-process idea is discarded.</p>
  
  <p>I really don't know what more can I try... and what is differing in the "duplicated" references inside the *.db icon cache files.</p>