Hi all,

I am working on a Windows Explorer context menu handler; Windows 10, Python 3.4 (both 64 bit), pywin32 version 219 installed (no virtual environment).

The handler is working fine when running it as a Python source file. However, I would like to create an executable containing all the dependencies, so it can be run on PCs that don't have Python installed. I can't get this to work. I have tried using py2exe and pyinstaller, with various setup.py and spec file examples, and nothing seems to work.

I've attached a stripped-down version of my code; when registered, it adds a context menu entry that, when clicked, pops up a message box showing the item clicked.

Can anyone help me find a way to convert this to an executable that still works? Thanks!

Regards,
Gertjan.

#!/usr/bin/env python3.4

import sys, os

from os.path import dirname, join, exists

import pythoncom
from win32com.shell import shell, shellcon

import win32gui
import win32gui_struct

import win32con
import win32process
import win32api


IContextMenu_Methods = ["QueryContextMenu", "InvokeCommand", "GetCommandString"]
IShellExtInit_Methods = ["Initialize"]

class ShellExtension:
    name = 'ContextMenuTest'
    _reg_progid_ = "Python.ShellExtension.ContextMenuTest" 
    _reg_desc_ = "Contextmenu test"
    _reg_clsid_ = "{1055EB80-4862-11E6-8607-101F7414C0D3}"
    _com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
    _public_methods_ = IContextMenu_Methods + IShellExtInit_Methods
    
    def Initialize(self, folder, dataobj, hkey):
        print("Initialize")
        self.dataobj = dataobj
        self.folder = folder
    
    def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
        print("QueryContextMenu")
        flags = win32con.MF_BYPOSITION | win32con.MF_STRING
        win32gui.InsertMenu(hMenu, indexMenu, flags, idCmdFirst, "Context menu 
test")
        return 1
    
    def InvokeCommand(self, ci):
        print("InvokeCommand")
        mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci
        if dir:
            mb_flags = win32con.MB_ICONEXCLAMATION | win32con.MB_OK
            win32gui.MessageBox(hwnd, dir, "Item clicked", 0)
        return
    
    def GetCommandString(self, cmd, typ):
        print("GetCommandString:", (cmd, typ))
        return ""
    
    def __del__(self):
        # Automatically unload the module if and only if a file __debug__ is
        # present in the same directory as this file.
        path = dirname(__file__)
        flagfile = join(path, '__debug__')
        if not exists(flagfile):
            return
        # Flag file exists: unload module
        if self.__module__ in sys.modules:
            print("Deleting", self.__module__, "module.")
            del sys.modules[self.__module__]
        

# ========== ========== ========== ========== ==========

# Paths in HKCR to register / unregister
REGPATHS = (
    r"*\shellex\ContextMenuHandlers\%s",
)

def DllRegisterServer():
    import winreg
    
    classid = ShellExtension._reg_clsid_
    for path in REGPATHS:
        path = path % ShellExtension.name
        key = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, path)
        winreg.SetValueEx(key, None, 0, winreg.REG_SZ, classid)
    
    print(ShellExtension._reg_desc_, "registration complete.")


def DllUnregisterServer():
    for path in REGPATHS:
        path = path % ShellExtension.name
        del_key(path)
    
    print(ShellExtension._reg_desc_, "unregistration complete.")


def del_key(path):
    import winreg
    try:
        key = winreg.DeleteKey(winreg.HKEY_CLASSES_ROOT, path)
    except WindowsError as details:
        import errno
        if details.errno != errno.ENOENT:
            raise
    

# ========== ========== ========== ========== ==========

if __name__ == '__main__':
    # Loaded as program: register as shell extension
    # Register:
    #   py -3.4 ctxm.py --register
    # Unregister:
    #   py -3.4 ctxm.py --unregister
    
    # No implicit registration
    if len(sys.argv) < 2:
        print("Use --register or --unregister.")
        sys.exit(1)
    
    # 
    if sys.argv[1] == "/Automate":
        from win32com.server import localserver
        localserver.serve([ShellExtension._reg_clsid_])
        sys.exit(0)
    
    from win32com.server import register
    register.UseCommandLine(
        ShellExtension,
        finalize_register = DllRegisterServer,
        finalize_unregister = DllUnregisterServer)
    
else:
    # Loaded as module: use win32traceutil for debugging
    # To view output, use:
    # py -3.4 -mwin32traceutil
    
    import win32traceutil
    print("\n=====\nLoading ctmx module.")
    
    

_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32

Reply via email to