none
VBS (or less preferably Powershell) - How to get list of icons in the file context menu? RRS feed

  • Question

  • Hi,

    It's easy enough to get the verbs listed on any file via VBS but I'm trying to to get a reference to any given icon that accompanies any specific verb.  Some verbs don't have an icon but, for example, "Always keep on this device" for OneDrive has a tick on it.  Is it possible to dynamically check the file to see if the "Tick" icon is set or not?  The OneDrive verb is just an example.

    As an aside does anyone know how you get the MUI verb strings from the verb numbers and vice versa?  For example 51201 is the number relating to "Pin to Start" in Shell32.dll (I think).  How can you retrieve the verbs from the dll from the known numbers in order to work on different locales?

    Stuart

    • Moved by Bill_Stewart Wednesday, September 4, 2019 6:19 PM This is not "research Windows Explorer API documentation for me" forum
    Monday, March 4, 2019 9:24 PM

All replies

  • The shell provides the "Verbs" property which lists all verbs available for that item.

    https://docs.microsoft.com/en-us/windows/desktop/shell/folderitem-verbs


    \_(ツ)_/


    • Edited by jrv Monday, March 4, 2019 10:04 PM
    Monday, March 4, 2019 10:02 PM
  • Hi,

    As I said, it's easy to get the verbs directly.  Ideally I would like to be able to query the strings from the dll.  If you look at this old AutoIt forum (about midway down the page where someone has posted a working example) it is possible in the AutoIT language by loading the shell32.dll and querying the string number...

    https://www.autoitscript.com/forum/topic/116641-how-can-i-create-any-shortcut-at-the-quicklaunch-for-windows-7/

    That's ultimately what I would like to in VBS along with being able to query what icon is displayed in the context menu alongside a specific verb.

    Stuart

    PS - Sorry, I realized I have two accounts on here, I am the OP'er
    • Edited by Stuart_P Tuesday, March 5, 2019 10:01 AM
    Tuesday, March 5, 2019 8:43 AM
  • What DLL are you referring to?  There is no DLL.  The "Shell" object is a COM object.  It has no icons.

    \_(ツ)_/

    Tuesday, March 5, 2019 10:53 AM
  • OK - there are two separate questions...

    The shell32.dll appears to be loadable to read the verb strings from to get different language versions of the same verb depending on the locale of Windows.  The AutoIt link shows a working version of an AutoIt script that can retrieve the localized verbs of a given number from the shell32.dll file (although it does so by loading a separate function).

    Retrieving the icons on the context menu is a different matter but linked to the same problem I am trying to overcome.  The icons are my main concern, the localized verb retrieval is a nice-to-have.  But appears not to be a native VBS thing...
    https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryexa

    So in AutoIt these commands let you get the localzed verbs for verb number 5386 from shell32.dll.  I basically want to do the same in VBS.

    ########################################################

    #include <WinAPI.au3>

    local $hInstance = _WinAPI_LoadLibraryEx("shell32.dll", $LOAD_LIBRARY_AS_DATAFILE)
    local $DoVerb = _WinAPI_LoadString($hInstance, 5386)

    ########################################################

    As far as the icons are concerned, my theory is that if you can read the verbs associated to a file's specific context menu then surely (maybe) you can read the associated icon in a similar fashion albeit probably not natively in VBS (more likely to find a solution in PowerShell I guess).

    Stuart



    • Edited by Stuart_P Tuesday, March 5, 2019 12:23 PM
    Tuesday, March 5, 2019 12:19 PM
  • They can only be easily loaded with a compiled program or a with Net code in PowerShell.  AutoIt may have a function that does this.  VBScript does not.

    You would have to use the LoadResource API call.

    The following works in PowerShell:

    $code = @'
    namespace Win32Utils{
    
         using System;
         using System.Drawing;
         using System.Runtime.InteropServices;
    
         /// <summary>
         /// Example using ExtractIconEx
         /// </summary>
         public class ExtractIcon
         {
         /* CONSTRUCTORS */
         static ExtractIcon(){
         }
    
         // HIDE INSTANCE CONSTRUCTOR
         private ExtractIcon(){
         }
    
         [DllImport("Shell32", CharSet=CharSet.Auto)]
         private static extern int ExtractIconEx (
             string lpszFile,
             int nIconIndex,
             IntPtr[] phIconLarge, 
             IntPtr[] phIconSmall,
             int nIcons);
    
         [DllImport("user32.dll", EntryPoint="DestroyIcon", SetLastError=true)]
         private static extern int DestroyIcon(IntPtr hIcon);
    
         public static Icon ExtractIconFromFile(string file, int index, bool large)
         {
             int readIconCount = 0;
             IntPtr[] hDummy  = new IntPtr[1] {IntPtr.Zero};
             IntPtr[] hIconEx = new IntPtr[1] {IntPtr.Zero};
    
             try
             {
                 if(large)
                 readIconCount = ExtractIconEx(file, index, hIconEx, hDummy, 1);
                 else
                 readIconCount = ExtractIconEx(file, index, hDummy, hIconEx, 1);
    
                 if(readIconCount > 0 && hIconEx[0] != IntPtr.Zero)
                 {
                 // GET FIRST EXTRACTED ICON
                 Icon extractedIcon = (Icon)Icon.FromHandle(hIconEx[0]).Clone();
    
                 return extractedIcon;
                 }
                 else // NO ICONS READ
                 return null;
             }
             catch(Exception ex)
             {
                 /* EXTRACT ICON ERROR */
    
                 // BUBBLE UP
                 throw new ApplicationException("Could not extract icon", ex);
             }
             finally
             {
                 // RELEASE RESOURCES
                 foreach(IntPtr ptr in hIconEx)
                 if(ptr != IntPtr.Zero)
                     DestroyIcon(ptr);
    
                 foreach(IntPtr ptr in hDummy)
                 if(ptr != IntPtr.Zero)
                     DestroyIcon(ptr);
             }
             }
         }
     }
    '@
    Add-Type $code -ReferencedAssemblies System.Drawing
    


    \_(ツ)_/

    Tuesday, March 5, 2019 12:54 PM
  • OK, that looks workable.  How would I use that to find icons listed in the context menu of a specific file?
    Tuesday, March 5, 2019 2:40 PM
  • You have to know the resource number.


    \_(ツ)_/

    Tuesday, March 5, 2019 2:44 PM