title: How to get system image list icon index of an IShellItem?
body: <p>Given a Windows Vista or newer <strong><code>IShellItem</code></strong>, how do i get the system image list icon index associated with that item?</p>
  
  <p>For example <em>(pseudo-code)</em>:</p>
  
  <pre><code>IShellItem networkFolder = SHGetKnownFolderItem(FOLDERID_NetworkFolder, 0, 0, IShellItem);
  Int32 iconIndex = GetSmallSysIconIndex(networkFolder);
  
  
  Int32 GetSmallSysIconIndex(IShellItem item)
  {
     //TODO: Ask Stackoverflow
  }
  </code></pre>
  
  <h2>Background</h2>
  
  <p>In the olden days (Windows 95 and newer), we could ask the shell to give us the system imagelist index for an item's icon. We did it using <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179%28v=vs.85%29.aspx?f=255&amp;MSPPError=-2147217396" rel="nofollow noreferrer"><code>SHGetFileInfo</code></a>.  The SHGet­File­Info function <a href="https://blogs.msdn.microsoft.com/oldnewthing/20110127-00/?p=11653" rel="nofollow noreferrer">gets the icon by asking the shell namespace for the icon index in the system imagelist</a>:</p>
  
  <pre><code>HICON GetIconIndex(PCTSTR pszFile)
  {
      SHFILEINFO sfi;
      HIMAGELIST himl = SHGetFileInfo(pszFile, 0, &amp;sfi, sizeof(sfi), SHGFI_SYSICONINDEX));
      if (himl) {
         return sfi.iIcon;
      } else {
         return -1;
      }
  }
  </code></pre>
  
  <p>That works when you are using an item in the shell namespace that corresponds to a file. But the shell supports things besides files and folders in the filesystem.</p>
  
  <p><strong>Icon Index from IShellFolder</strong></p>
  
  <p>The general solution for getting information about an object in the shell namespace comes from using the way you represent an <em>item</em> in the shell namespace:</p>
  
  <ul>
  <li><strong><code>IShellFolder</code></strong>: the folder that the <em>thing</em> sits in, along with</li>
  <li><strong>child <code>PIDL</code></strong>: the id of the <em>thing</em> in that folder</li>
  </ul>
  
  <p>From that there are <a href="https://stackoverflow.com/questions/25353059/how-to-get-the-shell-image-index-of-an-object-in-the-shell-namespace">ways to get the system image list index</a>:</p>
  
  <pre><code>Int32 GetIconIndex(IShellFolder folder, PITEMID_CHILD childPidl)
  {
     //Note: I actually have no idea how to do this.
  }
  </code></pre>
  
  <p><strong>But IShellFolder is out; we're using IShellItem now</strong></p>
  
  <p>Starting with Windows Vista, <code>IShellItem</code> became <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb761144(v=vs.85).aspx" rel="nofollow noreferrer">the preferred AP</a>I for navigating the shell. The Windows 95 era API of having to keep an <code>IShellFolder</code>+<code>pidl</code> pair around <a href="https://blogs.msdn.microsoft.com/oldnewthing/20110831-00/?p=9763/" rel="nofollow noreferrer">was cumbersome, and error prone</a>. </p>
  
  <p>The question becomes: How to do stuff with it? In particular, how do i get the image index in the system image list of the item? Looking at its methods, there isn't even a way to get its absolute pidl:</p>
  
  <ul>
  <li><strong>BindToHandler</strong>: Binds to a handler for an item as specified by the handler ID value (BHID).</li>
  <li><strong>Compare</strong>: Compares two IShellItem objects.</li>
  <li><strong>GetAttributes</strong>: Gets a requested set of attributes of the IShellItem object.</li>
  <li><strong>GetDisplayName</strong>: Gets the display name of the IShellItem object.</li>
  <li><strong>GetParent</strong>: Gets the parent of an IShellItem object.</li>
  </ul>
  
  <p>I was hoping that the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd561977(v=vs.85).aspx" rel="nofollow noreferrer"><strong>Windows Property System</strong></a>, accessible through <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb761130(v=vs.85).aspx" rel="nofollow noreferrer"><code>IShellItem2</code></a>, would have a property associated with the shell imagelist icon index. Unfortunately, i don't see any:</p>
  
  <ul>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb760159(v=vs.85).aspx" rel="nofollow noreferrer">System.DescriptionID</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd391574(v=vs.85).aspx" rel="nofollow noreferrer">System.InfoTipText</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb892886(v=vs.85).aspx" rel="nofollow noreferrer">System.InternalName</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb760160(v=vs.85).aspx" rel="nofollow noreferrer">System.Link.TargetSFGAOFlagsStrings</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb760161(v=vs.85).aspx" rel="nofollow noreferrer">System.Link.TargetUrl</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd391575(v=vs.85).aspx" rel="nofollow noreferrer">System.NamespaceCLSID</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb760162(v=vs.85).aspx" rel="nofollow noreferrer">System.Shell.SFGAOFlagsStrings</a></li>
  </ul>
  
  <p><strong>Ways of extracting icons</strong></p>
  
  <p>There <a href="https://xkcd.com/927/" rel="nofollow noreferrer">are many standard ways</a> of getting the picture that goes with a <em>thing</em> in the Windows Shell Namespace: </p>
  
  <ul>
  <li><a href="https://msdn.microsoft.com/en-us/library/bb761854(v=vs.85).aspx" rel="nofollow noreferrer"><code>IExtractIcon</code></a>. Returns an <code>HICON</code>. Requires <code>IShellFolder</code>+pidl. If it fails <a href="https://blogs.msdn.microsoft.com/oldnewthing/20140501-00/?p=1103" rel="nofollow noreferrer">you can use SHDefExtractIcon</a></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb762149(v=vs.85).aspx" rel="nofollow noreferrer"><code>SHDefExtractIcon</code></a>. Returns an <code>HICON</code>. Requires full path to icon file</li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb774628(v=vs.85).aspx" rel="nofollow noreferrer"><code>IThumbnailCache</code></a>. Requires <code>IShellItem</code>. Returns thumbnail, not icon</li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb761084(v=vs.85).aspx" rel="nofollow noreferrer"><code>IShellImageFactory</code></a>. Gets a bitmap that represents an <code>IShellItem</code></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb774614%28v=vs.85%29.aspx?f=255&amp;MSPPError=-2147217396" rel="nofollow noreferrer"><code>IThumbnailProvider</code></a>. Windows Vista replacement for <code>IExtractImage</code></li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb761848(v=vs.85).aspx" rel="nofollow noreferrer"><code>IExtractImage</code></a>. Requires <code>IShellFolder</code>+<code>pidl</code>.</li>
  <li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx" rel="nofollow noreferrer"><code>SHGetFileInfo</code></a>. Requires full file path, or an absolute pidl</li>
  </ul>
  
  <p>None of them:</p>
  
  <ul>
  <li>take an IShellItem</li>
  <li>return an index</li>
  </ul>