Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8056153
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 5, 20262026-06-05T08:37:13+00:00 2026-06-05T08:37:13+00:00

I’m trying add some shell extensions using python with icons and a sub menu

  • 0

I’m trying add some shell extensions using python with icons and a sub menu but I’m struggling to get much further than the demo in pywin32. I can’t seem to come up with anything by searching google, either.

I believe I need to register a com server to be able to change the options in submenu depending on where the right clicked file/folder is and the type of file etc.

# A sample context menu handler.
# Adds a 'Hello from Python' menu entry to .py files.  When clicked, a
# simple message box is displayed.
#
# To demostrate:
# * Execute this script to register the context menu.
# * Open Windows Explorer, and browse to a directory with a .py file.
# * Right-Click on a .py file - locate and click on 'Hello from Python' on
#   the context menu.

import pythoncom
from win32com.shell import shell, shellcon
import win32gui
import win32con

class ShellExtension:
    _reg_progid_ = "Python.ShellExtension.ContextMenu"
    _reg_desc_ = "Python Sample Shell Extension (context menu)"
    _reg_clsid_ = "{CED0336C-C9EE-4a7f-8D7F-C660393C381F}"
    _com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
    _public_methods_ = shellcon.IContextMenu_Methods + shellcon.IShellExtInit_Methods

    def Initialize(self, folder, dataobj, hkey):
        print "Init", folder, dataobj, hkey
        self.dataobj = dataobj

    def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
        print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags
        # Query the items clicked on
        format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
        sm = self.dataobj.GetData(format_etc)
        num_files = shell.DragQueryFile(sm.data_handle, -1)
        if num_files>1:
            msg = "&Hello from Python (with %d files selected)" % num_files
        else:
            fname = shell.DragQueryFile(sm.data_handle, 0)
            msg = "&Hello from Python (with '%s' selected)" % fname
        idCmd = idCmdFirst
        items = ['First Python content menu item!']
        if (uFlags & 0x000F) == shellcon.CMF_NORMAL: # Check == here, since CMF_NORMAL=0
            print "CMF_NORMAL..."
            items.append(msg)
        elif uFlags & shellcon.CMF_VERBSONLY:
            print "CMF_VERBSONLY..."
            items.append(msg + " - shortcut")
        elif uFlags & shellcon.CMF_EXPLORE:
            print "CMF_EXPLORE..."
            items.append(msg + " - normal file, right-click in Explorer")
        elif uFlags & CMF_DEFAULTONLY:
            print "CMF_DEFAULTONLY...\r\n"
        else:
            print "** unknown flags", uFlags
        win32gui.InsertMenu(hMenu, indexMenu,
                            win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                            0, None)
        indexMenu += 1
        for item in items:
            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_STRING|win32con.MF_BYPOSITION,
                                idCmd, item)
            indexMenu += 1
            idCmd += 1

        win32gui.InsertMenu(hMenu, indexMenu,
                            win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                            0, None)
        indexMenu += 1
        return idCmd-idCmdFirst # Must return number of menu items we added.

    def InvokeCommand(self, ci):
        mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci
        win32gui.MessageBox(hwnd, "Hello", "Wow", win32con.MB_OK)

    def GetCommandString(self, cmd, typ):
        # If GetCommandString returns the same string for all items then
        # the shell seems to ignore all but one.  This is even true in
        # Win7 etc where there is no status bar (and hence this string seems
        # ignored)
        return "Hello from Python (cmd=%d)!!" % (cmd,)

def DllRegisterServer():
    import _winreg
    folder_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
    "Folder\\shellex")
    folder_subkey = _winreg.CreateKey(folder_key, "ContextMenuHandlers")
    folder_subkey2 = _winreg.CreateKey(folder_subkey, "PythonSample")
    _winreg.SetValueEx(folder_subkey2, None, 0, _winreg.REG_SZ,
    ShellExtension._reg_clsid_)

    file_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
    "*\\shellex")
    file_subkey = _winreg.CreateKey(file_key, "ContextMenuHandlers")
    file_subkey2 = _winreg.CreateKey(file_subkey, "PythonSample")
    _winreg.SetValueEx(file_subkey2, None, 0, _winreg.REG_SZ,
    ShellExtension._reg_clsid_)

    print ShellExtension._reg_desc_, "registration complete."

def DllUnregisterServer():
    import _winreg
    try:
        folder_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,

        "Folder\\shellex\\ContextMenuHandlers\\PythonSample")
        file_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,

        "*\\shellex\\ContextMenuHandlers\\PythonSample ")
    except WindowsError, details:
        import errno
        if details.errno != errno.ENOENT:
            raise
    print ShellExtension._reg_desc_, "unregistration complete."

if __name__=='__main__':
    from win32com.server import register
    register.UseCommandLine(ShellExtension,
                   finalize_register = DllRegisterServer,
                   finalize_unregister = DllUnregisterServer)
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-05T08:37:14+00:00Added an answer on June 5, 2026 at 8:37 am

    I found out how to do this after a lot of trial and error and googling.

    The example below shows a menu with a submenu and icons.

    # A sample context menu handler.
    # Adds a menu item with sub menu to all files and folders, different options inside specified folder. 
    # When clicked a list of selected items is displayed.
    #
    # To demostrate:
    # * Execute this script to register the context menu. `python context_menu.py --register`
    # * Restart explorer.exe- in the task manager end process on explorer.exe. Then file > new task, then type explorer.exe
    # * Open Windows Explorer, and browse to a file/directory.
    # * Right-Click file/folder - locate and click on an option under 'Menu options'.
    
    import os
    import pythoncom
    from win32com.shell import shell, shellcon
    import win32gui
    import win32con
    import win32api
    
    class ShellExtension:
        _reg_progid_ = "Python.ShellExtension.ContextMenu"
        _reg_desc_ = "Python Sample Shell Extension (context menu)"
        _reg_clsid_ = "{CED0336C-C9EE-4a7f-8D7F-C660393C381F}"
        _com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
        _public_methods_ = shellcon.IContextMenu_Methods + shellcon.IShellExtInit_Methods
    
        def Initialize(self, folder, dataobj, hkey):
            print "Init", folder, dataobj, hkey
            win32gui.InitCommonControls()
            self.brand= "Menu options"
            self.folder= "C:\\Users\\Paul\\"
            self.dataobj = dataobj
            self.hicon= self.prep_menu_icon(r"C:\path\to\icon.ico")
    
    
        def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
            print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags
    
            # Query the items clicked on
            files= self.getFilesSelected()
    
            fname = files[0]
            idCmd = idCmdFirst
    
            isdir= os.path.isdir(fname)
            in_folder= all([f_path.startswith(self.folder) for f_path in files])
    
            win32gui.InsertMenu(hMenu, indexMenu,
                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                0, None)
            indexMenu += 1
    
            menu= win32gui.CreatePopupMenu()
            win32gui.InsertMenu(hMenu,indexMenu,win32con.MF_STRING|win32con.MF_BYPOSITION|win32con.MF_POPUP,menu,self.brand)
            win32gui.SetMenuItemBitmaps(hMenu,menu,0,self.hicon,self.hicon)
    #        idCmd+=1
            indexMenu+=1
    
            if in_folder:
                if len(files) == 1:
                    if isdir:
                        win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 1"); idCmd+=1
                    else:
                        win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 2")
                        win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
                        idCmd+=1
            else:
                win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 3")
                win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
                idCmd+=1
    
            if idCmd > idCmdFirst:
                win32gui.InsertMenu(menu,1,win32con.MF_SEPARATOR,0,None)
    
            win32gui.InsertMenu(menu,2,win32con.MF_STRING,idCmd,"Item 4")
            win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
            idCmd+=1
            win32gui.InsertMenu(menu,3,win32con.MF_STRING,idCmd,"Item 5")
            win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
            idCmd+=1
    
            win32gui.InsertMenu(menu,4,win32con.MF_SEPARATOR,0,None)
    
            win32gui.InsertMenu(menu,5,win32con.MF_STRING|win32con.MF_DISABLED,idCmd,"Item 6")
            win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
            idCmd+=1
    
            win32gui.InsertMenu(hMenu, indexMenu,
                                win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
                                0, None)
            indexMenu += 1
            return idCmd-idCmdFirst # Must return number of menu items we added.
    
        def getFilesSelected(self):
            format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
            sm = self.dataobj.GetData(format_etc)
            num_files = shell.DragQueryFile(sm.data_handle, -1)
            files= []
            for i in xrange(num_files):
                fpath= shell.DragQueryFile(sm.data_handle,i)
                files.append(fpath)
            return files
    
        def prep_menu_icon(self, icon): #Couldn't get this to work with pngs, only ico
            # First load the icon.
            ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON)
            ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON)
            hicon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE)
    
            hdcBitmap = win32gui.CreateCompatibleDC(0)
            hdcScreen = win32gui.GetDC(0)
            hbm = win32gui.CreateCompatibleBitmap(hdcScreen, ico_x, ico_y)
            hbmOld = win32gui.SelectObject(hdcBitmap, hbm)
            # Fill the background.
            brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)
            win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush)
            # unclear if brush needs to be feed.  Best clue I can find is:
            # "GetSysColorBrush returns a cached brush instead of allocating a new
            # one." - implies no DeleteObject
            # draw the icon
            win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)
            win32gui.SelectObject(hdcBitmap, hbmOld)
            win32gui.DeleteDC(hdcBitmap)
    
            return hbm
    
        def InvokeCommand(self, ci):
            mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci
            win32gui.MessageBox(hwnd, str(self.getFilesSelected()), "Wow", win32con.MB_OK)
    
        def GetCommandString(self, cmd, typ):
            # If GetCommandString returns the same string for all items then
            # the shell seems to ignore all but one.  This is even true in
            # Win7 etc where there is no status bar (and hence this string seems
            # ignored)
            return "Hello from Python (cmd=%d)!!" % (cmd,)
    
    def DllRegisterServer():
        import _winreg
        folder_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
        "Folder\\shellex")
        folder_subkey = _winreg.CreateKey(folder_key, "ContextMenuHandlers")
        folder_subkey2 = _winreg.CreateKey(folder_subkey, "PythonSample")
        _winreg.SetValueEx(folder_subkey2, None, 0, _winreg.REG_SZ,
        ShellExtension._reg_clsid_)
    
        file_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
        "*\\shellex")
        file_subkey = _winreg.CreateKey(file_key, "ContextMenuHandlers")
        file_subkey2 = _winreg.CreateKey(file_subkey, "PythonSample")
        _winreg.SetValueEx(file_subkey2, None, 0, _winreg.REG_SZ,
        ShellExtension._reg_clsid_)
    
        print ShellExtension._reg_desc_, "registration complete."
    
    def DllUnregisterServer():
        import _winreg
        try:
            folder_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
    
            "Folder\\shellex\\ContextMenuHandlers\\PythonSample")
            file_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
    
            "*\\shellex\\ContextMenuHandlers\\PythonSample")
        except WindowsError, details:
            import errno
            if details.errno != errno.ENOENT:
                raise
        print ShellExtension._reg_desc_, "unregistration complete."
    
    if __name__=='__main__':
        from win32com.server import register
        register.UseCommandLine(ShellExtension,
                       finalize_register = DllRegisterServer,
                       finalize_unregister = DllUnregisterServer)
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

That's pretty much it. I'm using Nokogiri to scrape a web page what has
I am trying to understand how to use SyndicationItem to display feed which is
Basically, what I'm trying to create is a page of div tags, each has
I'm new to using the Perl treebuilder module for HTML parsing and can't figure
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have just tried to save a simple *.rtf file with some websites and
I want to count how many characters a certain string has in PHP, but
For some reason, after submitting a string like this Jack’s Spindle from a text
I have a string like this: La Torre Eiffel paragonata all’Everest What PHP function
I am reading a book about Javascript and jQuery and using one of the

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.