19

I need to mention a 3rd party program, or better said the source-code of WinThumbsPreloader 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:

enter image description here

The problem is that what I need to preload is the icon of a folder, but the IThumbnailCache::GetThumbnail method does not allow to pass a folder item, and it will return error code 0x8004B200 (WTS_E_FAILEDEXTRACTION):

The Shell item does not support thumbnail extraction. For example, .exe or .lnk items.

In other words, I need to do the same thing WinThumbsPreloader program does, but for folder icons instead of folder/icon thumbnails.

So, what I mean is that I have a folder with a desktop.ini file inside, which as you probably know it can serve to replace the default icon/thumbnail for the folder that stores that desktop.ini file. An example of desktop.ini file content:

[.ShellClassInfo]
IconResource=FolderPreview.ico,0

The reason why I need to preload folders is to avoid the icon cache generation every time that I navigate through a folder.

To clear doubts, I would like to avoid this slow folder icon generation:

before

And instead, get this improved speed:

after

My question is: In C# or VB.NET, how can I programmatically preload the icon of a specific folder in Windows icon cache?.

It seems that IThumbnailCache interface is not the way to go for this problem...


UPDATE 1

Following @Jimi's commentary suggestions, this is the approach I'm trying:

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

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 iconcache_256.db 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 iconcache_256.db doubles its file size to around 500 MB, and this is a evidence that iconcache_256.db 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...

What I'm doing wrong?.

UPDATE 2

Using WindowsAPICodePack v1.1 library (from Nuget manager) I'm having the same problem as described in the code of the UPDATE 1 using IShellItemImageFactory.GetImage: I can extract the icons and the icons are cached in iconcache_256.db 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...

Full code sample:

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

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 iconcache_256.db (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 iconcache_256.db (and in the other *.db files).

I don't know how to read the database format of iconcache_256.db 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...

UPDATE 3

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...

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.

I really don't know what more can I try... and what is differing in the "duplicated" references inside the *.db icon cache files.

ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • 2
    See the notes in Remarks section of [IShellItemImageFactory::GetImage](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishellitemimagefactory-getimage) – Jimi May 24 '20 at 14:18
  • @Jimi thanks for comment, but not sure what I must see there, can you explain me in more detail?. Theoretically **ShellItemImageFactory::GetImage** would serve to extract the icon (or get the cached icon if exists) but not to force the operating system to extract it and then cache it in the system's icon/thumbnails cache, is this not right?. – ElektroStudios May 24 '20 at 14:29
  • Btw, IIRC, [SHGetImageList](https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetimagelist) returns an [`IImageList`](https://learn.microsoft.com/en-us/windows/win32/api/commoncontrols/nn-commoncontrols-iimagelist) and its [IImageList::GetIcon](https://learn.microsoft.com/en-us/windows/win32/api/commoncontrols/nf-commoncontrols-iimagelist-geticon) method can return the thumbnails of Directories. -- It's related to this kind of processing and the UI thread. You may need a thread that caches, one that reads and rock-solid garbage collection handling. – Jimi May 24 '20 at 14:35
  • @Jimi I tried IShellItemImageFactory.GetImage with different flag combinations and it does not seem to cache the extracted icon. I yet didn't had time to implement and try the other possible solution (SHGetImageList). – ElektroStudios May 28 '20 at 06:40
  • @Jimi In fact I noticed it caches the icon, but for some strange reason the cached icon is not used by the operating system, instead when I manually navigate to the directory the operating system creates/extracts a new icon and uses that, why can happen this?. So lets say If I use GetImage with 1000 folders I got a ~250 MB iconcache_256.db file, then If I navigate to that directory the file size doubles because the O.S extracts again each icon for each folder. – ElektroStudios May 28 '20 at 06:51
  • GetThumbnail works fine for folders. WTS_E_FAILEDEXTRACTION is reported when no thumbnail can be created (for example if it's empty). In this case, you can use the standard folder icon (not thumbnail). Note the ThumbnailPreloader.cs code has issues. For example ISharedBitmap is buggy (methods are not in the right order) – Simon Mourier May 28 '20 at 13:34
  • @Simon Mourier It is not working for me, GetThumbnail is throwing WTS_E_FAILEDEXTRACTION error for folders that are not empty and it is not extracting/caching the folder icon. I uploaded a sample folder for testing (note the hidden desktop.ini and folder.ico files inside): https://www.mediafire.com/file/pcomizv46ewrtf6/sample.zip/file – ElektroStudios May 28 '20 at 15:39
  • 1
    In your sample folder, there's no thumbnail, since you force it to be an icon (folder.ico) with the desktop.ini. – Simon Mourier May 28 '20 at 18:34
  • That's it, from the start I'm saying that I want to preload the folder icon into the operating system's icon cache!. thanks for comment Simon Mourier – ElektroStudios May 28 '20 at 19:32
  • I just found the CLSID of Local Icon Cache: **{2155fee3-2419-4373-b102-6843707eb41f}** that points to **C:\Windows\System32\thumbcache.dll** file, but I'm not sure if this can be a hint for something of interest or just junk info from my side, because I didn't found any related win32 interface related to iconCache (I was trying to search something equivalent to **IThumbnailCache** interface for icons), and the **thumbcache.dll** file has no exported functions of interest (I used "DLL Export Viewer" from NirSoft). – ElektroStudios May 28 '20 at 20:08
  • Have you thought about writing an IThumbnailProvider (A COM object that needs to be registered) to replace desktop.ini+folder.ico, coupled with the same GetThumbnail approach? – Simon Mourier May 29 '20 at 06:55
  • @Simon Mourier I appreciate the alternative idea, and please correct me if I'm wrong but I think developing a kind of shell-ext could be an overkill for what I really pretend to do. My need is to found a way to force windows to extract and cache the icon for a specific set of subfolders in a directory, so the next time I navigate to that directory using Explorer.exe windows gets the preloaded icons from the cache and I don't need to wait for folder icons to be extracted. I just would like to do the same thing **WinThumbsPreloader** program does, but for folder icons instead of file thumbnails. – ElektroStudios May 29 '20 at 07:41
  • If you read the UPDATES in my main post,I'm stuck at a point at which using **IShellItemImageFactory.GetImage** or using **WindowsAPICodePack** wrappers I can extract and cache the folder icons inside IconCache_*.db files,but those icons seems are not properly recognized by Windows because the O.S will create new additional "duplicated" references in IconCache_*.db files when I navigate to the directory using Explorer.exe (the O.S will extract and cache again the folder icons).I suspect this approach could be the easiest way to go but I'm just missing something to finally do this properly. – ElektroStudios May 29 '20 at 07:58
  • Shell extension could make perfectly sense if you already install something on the user's PC. It's not too difficult to develop and allowed using .NET (thanks to process isolation for that type of extension). – Simon Mourier May 29 '20 at 08:42
  • @Simon Mourier I think that the proposal of a shell extension does not fit what I really need. The problem is not unexperience with SharpShell (I published a kind of file properties dialog shell-extension on GitHub), but I think that approach can't help me. See, I need to be able to specify a directory, programmatically and arbitrarily (eg. in a line of code to call some magical method) to preload the icons for that directory and its subdirectories. – ElektroStudios Jun 01 '20 at 17:08
  • @Simon Mourier I would like to have a solution provided in that way because it is the more comfortable way for me and by the moment the only one I can see it can have beneffits. It would be a thing to perform once, for example when changing a directory name, a letter drive, or after a drive formatting... things that will make "invalid" the current folder icon cache references, things that I would like to solve in a simple way (calling on-the-fly a method) as I explained. – ElektroStudios Jun 01 '20 at 17:09
  • @Simon Mourier However, with a shell extension I think I should use always Explorer to navigate to "X" folder to let the shell-ext first detect the folder I'm in to begin perform the "magic" thumbnail provider logic with the current folder I'm in. Anyways I recognize that I don't get at all what exactly the **IThumbnailProvider** can do and how can do it but I think is not what I'm looking for. – ElektroStudios Jun 01 '20 at 17:11
  • The problem comes from the use of icons. My point is just that with a thumbnail provider ext installed (that would use cover.jpg as the thumbnail internally w/o any desktop.ini nor folder.ico), you could then use the IThumnailCache API to preload the cache as you planned to, for example with the WinThumbsPreloader code. (it will hit your thumbnail provider code indirectly) – Simon Mourier Jun 01 '20 at 17:40
  • @Simon Mourier And by using **IThumnailCache** I would not have the problem on which the shell-ext generates one thumbnail for "X" directory, but then Windows does not "recognize" and does not load that thumbnail and instead it generates a second, different "duplicated" thumbnail for same folder and then it adds that "duplicated" thumbnail in thumbnail cache file?. That is the problem I'm facing with folder icons when using **IShellItemImageFactory.GetImage** and **WindowsAPICodePack**, I don't know why. – ElektroStudios Jun 01 '20 at 17:48
  • 1
    I can't guarantee anything, but it's not too difficult to test. Icons are kinda obsolete somehow. IShellItemImageFactory (note the "Image" generic term) looks 1) for thumbnail and 2) for icon (BTW when it looks for thumbnail it uses IThumbnailCache). It's not really a caching mechanism. – Simon Mourier Jun 01 '20 at 18:10
  • Well ... if a better option isn't known, I'll try with **IThumnailCache** at least to see if it works as an alternative. Later I will look for some examples already made, but if you want to suggest a particular example then it will be very welcome. Thanks for your time! – ElektroStudios Jun 01 '20 at 18:52
  • Just throwing a crazy idea but maybe **IshellItem.BindToHandler()** could do the trick If I bind it to **IThumbnailProvider** (E357FCCD-A995-4576-B01F-234630154E96) or IExtraction or related interface guids?, I don't know how to do so, in fact I don't know exactly the meaning context and purpose of binding an **IShellItem** interface. – ElektroStudios Jun 07 '20 at 00:39
  • IShellItem (and methods) is just the new and cleaner way of binding to various interfaces. But undercover, you'll end up using the same piece of code in the Shell. But that will not change the fact your folder has no thumbnail, because you force it to be an icon. – Simon Mourier Jun 09 '20 at 13:52
  • 1
    Have you tried to use [ThumbCache Viewer](https://thumbcacheviewer.github.io/) to check the db content pre and post your code ? – Max Jun 12 '20 at 14:43
  • @Max I really needed a tool like that, thanks!. Now I can confirm there are two differences: filenames are different, and file size of the cached icon (a png image) differs by two bytes (the Icon I cache with my code is two bytes smaller). https://i.imgur.com/uDP1PRu.png (the first row is the icon I cache with my code, the second row is the one cached by the O.S) this info is useful to verify what are the differences, but I don't know how to cache a identical icon like windows does, matching same filename and file size. – ElektroStudios Jun 13 '20 at 11:04
  • Try to change the options on your code starting from this `folder.Thumbnail.FormatOption = ShellThumbnailFormatOption.IconOnly` and see if something change – Max Jun 13 '20 at 23:15
  • @Max it was one of the first things I've tried, that and doing different flags combination on GetImage method. Filename and filesize is always the same regardless of what flags I use to extract the icon. :( – ElektroStudios Jun 14 '20 at 06:46
  • I found two deterministic things when using 'ThumbCache Viewer': 1. My generated icon and the one generated by Windows has the same size (I was wrong when I said they file size differ by 2 bytes) because 'data size' and 'data checksum' colums are equals. 2. The filename column displays a CRC64 string, I found it by analyzing 'ThumbCache Viewer' source code, but my C/C++ skills are not that good to figure out how to retrieve the real file path to determine whether my generated icon and the one generated by Windows could differ in the path. I still dont understand why the OS duplicates my icons. – ElektroStudios Feb 27 '21 at 04:55
  • https://stackoverflow.com/questions/19523599/how-to-get-thumbnail-of-file-using-the-windows-api – Nadeem Taj Mar 05 '21 at 18:13
  • Why the bounty? What has changed since my last remark "But that will not change the fact your folder has no thumbnail, because you force it to be an icon". You can't go around that. – Simon Mourier Mar 21 '21 at 19:20
  • @Simon Mourier nothing has changed, the title of the thread is clear: "Preload folder icon for...". I just had a word mistake saying thumbnail instead of icon when talking to you and in my very first text editions. The O.S generates an icon for these folders (the icon path is specified in the 'desktop.ini' file), and that is what I would like to preload, and stopping the O.S from duplicating the same icon that I preloaded, in the icon cache files. I would accept the solution you proposed via shell extension in case of no easier and less intrusive solution. – ElektroStudios Mar 22 '21 at 00:12
  • AFAIK, the icon/thumb hash for a path is computed using the size (doesn't exist for a folder), last modified date, and the file identifier which is https://learn.microsoft.com/en-us/windows/win32/properties/props-system-filefrn you can read it with a (C#) code like this https://pastebin.com/raw/nkRNmc5k if you delete a folder, it's id changes. – Simon Mourier Mar 22 '21 at 09:30
  • @Simon Mourier that is too good info, thank you, although I don't know how / where you got that information, that demonstrates how internally the O.S. creates an entry in the icon cache files and reference it by a unique hash, that's right?. So maybe the hash of the icons that I try to preload and are added to the icon cache file could differ with those hashes generated by the O.S?, this is good to know, however I have no idea what can I do with this info since I can't programaticaly modify hashes of the entries in the icon cache files, or I don't know how to do so. – ElektroStudios Mar 22 '21 at 21:28
  • Using your code example I checked folder ids and last modified time before and after caching their icons (adding their icons to the icon cache file), and it didn't changed, but the O.S still duplicate all the icons in the icon cache files for the folders that I already cached. This is a nightmare. The icons I add are equal image size and file size (I see are the same when using thumbcache_viewer.exe), file id and last modified time are equal, but the O.S. always generate an additional/duplicated icon for some strange reason, it does not want to use my cached icon, instead it creates a new one. – ElektroStudios Mar 22 '21 at 22:15
  • I didn't get your comment (your @ call didn't work for some reason). I got the info from here: https://i.imgur.com/nHfAy3F.png if you checked ids and time, I don't know why the hashes are different. There must be something that's different... – Simon Mourier Mar 23 '21 at 18:51
  • Just speculating but maybe the thing that is different could be the process?.I mean,Maybe icons generated are per process and that is causing Explorer/the O.S to create new icons instead of use the icons that I generated with my .NET assembly?.Do u know if its possible to inject a .NET assembly into explorer.exe to run it remotely with the purpose to generate the icons as if explorer.exe is the process who is creating them?.I only find programs like "Donut" that serve to inject shellcode into a native process,but I don't find how to inject .NET code or an assembly into a native (explorer.exe). – ElektroStudios Mar 23 '21 at 23:27
  • The code approach that I shared using WindowsAPICodePack, use this class to generate the icon / thumbnail (with 'IconOnly' flag set like in the code I shared): https://github.com/aybe/Windows-API-Code-Pack-1.1/blob/ae73c1294fe9d47c5052d090b945f69a6364e3a8/source/WindowsAPICodePack/Shell/Common/ShellThumbnail.cs#L16 – ElektroStudios Mar 23 '21 at 23:45
  • And I think it calls this other function which I think is the one responsible of generating the icon in the icon cache file: https://github.com/aybe/Windows-API-Code-Pack-1.1/blob/ae73c1294fe9d47c5052d090b945f69a6364e3a8/source/WindowsAPICodePack/Shell/Interop/ShellExtensions/HandlerNativeMethods.cs#L37 all these things are just windows API calls to let Windows do his things in his way, I don't know in which manner hashes could differ when using windows API calls and opening a folder in explorer to generate the folder icons... does not have sense for me, maybe hashes could be per process?. – ElektroStudios Mar 23 '21 at 23:54
  • Yeeeeeeeeeeees, damn at least I found the difference!!!!. I don't know if exists documentaton about it but I can confirm icons generated are PER PROCESS!! (or per app domains, I'm not sure). If I use the same process to try generate the icon of a folder, all works fine, I mean it only creates a unique icon regardless of how many times I compile and run that process, but If I change the GUID of the process in the project settings then it generates a new additional duplicated icon!!!. – ElektroStudios Mar 24 '21 at 00:04
  • Now,knowing this,what can I do?.What are my options?.Since I discovered entry hashes in the icon cache files are per process,I think is reasonable to think that folder icons should be generated only by the explorer.exe process in order to avoid duplicated entries in the cache files that only differ in their hash,because if I use other process (my own .NET app) to generate the folder icons, the O.S ignore these icons and generate new ones.So I need to "lie" the system to "imporsonate" my process as explorer.exe?,or inject my code into explorer.exe,or what?. what can I do now and how to do it? – ElektroStudios Mar 24 '21 at 00:09
  • Wait, is not only the assembly GUID. Now I'm unsure of the exact changes, I can't tell are per process because only changing the guid it does not generate a duplicate, I needed to create a new empty project and paste the code to generate the icon, and then it created a new duplicated entry icon in the icon cache file, but now I CAN'T reproduce again this behavior... damn. What a pain. – ElektroStudios Mar 24 '21 at 00:18
  • The difference is somewhat per architecture!!, compiling the same code / process for x86 and x64 to generate a folder icon, each of both processes will generate its own icon entry in the icon cache file, although both a x86 and x64 process generate the same icons, but their entry hash differs. That is the difference. – ElektroStudios Mar 24 '21 at 00:38
  • And now having discovered this (the only) difference Its easy to figure out the solution... so easy from the beginning, oh my god. I will publish an answer soon. – ElektroStudios Mar 24 '21 at 00:45

1 Answers1

3

Let me summarize everything starting from the scratch, since perhaps with so much text and comments in the comments box the question and the bounty could had been very confusing for users:

The Objective

My main goal was and is to preload the folder icon from a bunch of specific folders. The icon is specified in the "desktop.ini" file inside each of these folders, this is an O.S feature on which the O.S visually represents the folder as an icon, it literally replaces the common yellow default folder icon with the file contents preview, for the icon of your choose that is specified in the "desktop.ini" file. It's a beautiful preview feature for example for folders containing videogames, music albums or movies, on which you can use the game, movie or music cover as the icon for that folder.

The code approach

Using some code to call the IShellItemImageFactory.GetImage() function, or same thing using WindowsAPICodePack library I was able to get the operating system to generate the icons and add their respective entries to the Iconcache_nnn.db file.

The problem

The problem I found was that the O.S ignored these icons, it did not wanted to use my cached icons to preview the folder icons, but instead the O.S created new entries with different hashes but being the same icon, in other words, the O.S re-caches the icons that I already cached.

The root of the problem

By trial and error I discovered that the process architecture (x86 / x64) on which my code was ran to call IShellItemImageFactory.GetImage() function, it matters a lot.

So having a 64-bit Windows I was always running my code in x86 mode, and this was causing, without me being aware of the problem, that my x86 process generated icon entries with a different hash than the entries that the O.S was creating in the Iconcache_nnn.db file, and this is the reason why icons were cached again by the O.S, because the O.S didn't recognized the hashes of my cached icons from my x86 process.

I really don't know why this happens in this way, but it is like that, so rescuing this comment from @Simon Mourier:

AFAIK, the icon/thumb hash for a path is computed using the size (doesn't exist for a folder), last modified date, and the file identifier

To that computation we need to add another factor: process architecture differentiation ?

The solution

The solution in my 64-Bit O.S is simply to make sure compile the process (that programmatically gets the folder icons) in x64 to match the same architecture of the O.S / Explorer.exe. In case of having a 32-Bit Windows there is not much to say about, run your x86 process.

And this is a simple code to preload the icon of a folder using WindowsAPICodePack library:

    ''' ----------------------------------------------------------------------------------------------------
    ''' <summary>
    ''' Preloads the icon of a directory into Windows Icon Cache system files (IconCache_xxx.db).
    ''' <para></para>
    ''' The folder must contain a "desktop.ini" file with the icon specified.
    ''' </summary>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <remarks>
    ''' Because the Windows Icon Cache system creates icon's entry hashes 
    ''' with some kind of process architecture differentiation, 
    ''' the user must make sure to call <see cref="PreloadInIconCache"/> function from
    ''' a process that matches the same architecture of the running operating system. 
    ''' <para></para>
    ''' In short, <see cref="PreloadInIconCache"/> function should be called 
    ''' from a x64 process if running under Windows x64, and  
    ''' from a x86 process if running under Windows x86.
    ''' <para></para>
    ''' Otherwise, if for example <see cref="PreloadInIconCache"/> function is called  
    ''' from a x86 process if running under Windows x64, it will happen that 
    ''' when accesing the specified folder via Explorer.exe, the operating system 
    ''' will ignore the icon cached using <see cref="PreloadInIconCache"/> function,
    ''' and it will cache again the folder, generating a new additional entry 
    ''' in the Icon Cache system.
    ''' <para></para>
    ''' Read more about this problem at: <see href="https://stackoverflow.com/a/66773765/1248295"/>
    ''' </remarks>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <example> This is a code example.
    ''' <code language="VB.NET">
    ''' Dim directoryPath As String = "C:\Movies\"
    ''' Dim searchPattern As String = "*"
    ''' Dim searchOption As SearchOption = SearchOption.TopDirectoryOnly
    ''' Dim iconSize As IconSizes = IconSizes._256x256
    ''' 
    ''' For Each dir As DirectoryInfo In New DirectoryInfo(directoryPath).EnumerateDirectories(searchPattern, searchOption)
    '''     Console.WriteLine($"Preloading icon ({CStr(iconSize)}x{CStr(iconSize)}) for directory: '{dir.FullName}'")
    '''     DirectoryUtil.PreloadInIconCache(dir.FullName, iconSize)
    ''' Next file
    ''' </code>
    ''' </example>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <param name="dirPath">
    ''' The directory path.
    ''' </param>
    ''' 
    ''' <param name="iconSize">
    ''' The requested icon size, in pixels. 
    ''' <para></para>
    ''' Default value is 256.
    ''' </param>
    ''' ----------------------------------------------------------------------------------------------------
    <DebuggerStepThrough>
    Public Shared Sub PreloadInIconCache(directory As DirectoryInfo, Optional iconSize As Integer = 256)
        PreloadInIconCache(directory.FullName, iconSize)
    End Sub

    <DebuggerStepThrough>
Public Shared Sub PreloadInIconCache(path As String, Optional iconSize As Integer = 256)
    Using folder As ShellFileSystemFolder = DirectCast(ShellObject.FromParsingName(path), ShellFileSystemFolder)
        folder.Thumbnail.FormatOption = ShellThumbnailFormatOption.IconOnly
        folder.Thumbnail.RetrievalOption = ShellThumbnailRetrievalOption.Default
        folder.Thumbnail.AllowBiggerSize = True
        folder.Thumbnail.CurrentSize = New System.Windows.Size(iconSize, iconSize)

        Using thumbnail As Bitmap = folder.Thumbnail.Bitmap
        End Using
    End Using
End Sub

Example usage:

Dim folders As DirectoryInfo() = New DirectoryInfo("C:\").GetDirectories("*", SearchOption.AllDirectories)
For Each folder As DirectoryInfo In folders
    PreloadFolderIcon(folder, 256)
Next folder

Remember, a .NET assembly containing that code must be run in x64 mode if operating under a 64-Bit Windows, otherwise that code will generate the icon entries in the Iconcache_nnn.db file but when accessing the folders via Explorer.exe the O.S will simply ignore those entries and instead re-cache again the folder icons generating new additional entries.

Lastly, don't forget that you can check and preview the icon entries in the Iconcache_nnn.db file using the tool thumbcacheviewer mentioned by @Max.

ElektroStudios
  • 19,105
  • 33
  • 200
  • 417