Hi Mark, I followed your suggestion and the SO threads touching on this area. ( http://stackoverflow.com/questions/4619701/python-64-bit-dll-com-server-registration-problem-on-64-bit-windows-7 ) Using py2exe I generated a dist folder with an exe of my overlay script. Running this on a machine without Python installed shows all of the proper log messages being generated and registry entry created for my overlay handler, however there's no indication that explorer is loading and running the overlay handler.
Following the SO examples I instead generated a COM DLL from the same source. I can copy this dist directory and new DLL over to a machine without Python and use regsrv32 to register the DLL without errors, but it doesn't run the main method which is what sets the required registry entries and calls UseCommandLine so it doesn't look like it's being registered correctly at all. Sorry for the newb questions, but I seem to have a big gap in my understanding of the mechanism. So, the way that I'm using it at least, py2exe is either generating an EXE that will register correctly but not provide a COM object with the correct environment for explorer to run the overlay handler, or a DLL that should be self contained and functional but not provide the registration functionality. I've attached my primary script (Overlay Handler + logging and some helper objects) as well as 2 py2exe setup scripts I've tried. I'm hoping you can point out a huge flaw in my thinking, or an obvious step that I'm missing in the registration process. Thanks again for any help you can provide. On Fri, Jan 8, 2016 at 3:30 PM, Alexander Jewell <balexjew...@gmail.com> wrote: > I created a fresh Python 2.7 environment with pywin and py2exe and > stripped down my overlay handler to the basics to better troubleshoot. > > Running my script (command line or in PyCharm) registers everything > correctly, just like before, but running the py2exe generated EXE seems to > be registering but no overlays are appearing, which looks just like what > happens when I restarted explorer.exe in my previous attempt (logged > messages during registration, plus a manual check of the registry look good > but nothing generated by IsMemberOf. > > I'm going to try generating a DLL and manually registering following the > example here: > http://stackoverflow.com/questions/4619701/python-64-bit-dll-com-server-registration-problem-on-64-bit-windows-7 > > It looks like this example came out of a mail thread with you back in 2011 > so I'll try to follow the advice there and report back. > > Thanks again for the help Mark. > > On Wed, Jan 6, 2016 at 7:19 PM, Mark Hammond <mhamm...@skippinet.com.au> > wrote: > >> On 7/01/2016 6:21 AM, Alexander Jewell wrote: >> >>> Unfortunately my end goal was to bundle the entire application as an exe >>> with PyInstaller so that the end user does not actually have Python >>> installed. >>> >>> Do you think it would be possible to package the overlay handler in such >>> a way that explorer would not need access to an installed Python >>> interpreter? >>> Embedding(https://docs.python.org/3.4/extending/embedding.html) seems >>> to still require a Python interpreter but Cython sounds promising. >>> >> >> I've used py2exe for this in the past and it works fine - you need to end >> up with a stand-alone directory that functions independently of any >> installed Python - py2exe bundles Python itself, pywin32, etc in just this >> way. Last I tried though, it only worked with python 2.x >> >> Mark >> >> >>> -Alex >>> >>> On Wed, Jan 6, 2016 at 5:37 AM, Mark Hammond <skippy.hamm...@gmail.com >>> <mailto:skippy.hamm...@gmail.com>> wrote: >>> >>> My guess is that the environment (eg, PATH, PYTHONPATH etc) for the >>> new explorer instance isn't setup correctly - how is the >>> explorer.exe process started when it *does* work? It's hard to >>> answer without more info, but Python ends up inside explorer.exe, so >>> the environment that explorer.exe starts with is important. >>> >>> Mark >>> >>> On 6/01/2016 8:29 AM, Alexander Jewell wrote: >>> >>> So, thanks to the Tim Golden guide >>> < >>> http://timgolden.me.uk/python/win32_how_do_i/add-my-own-icon-overlays.html >>> > >>> ( >>> http://timgolden.me.uk/python/win32_how_do_i/add-my-own-icon-overlays.html >>> ) >>> and >>> other questions >>> < >>> http://stackoverflow.com/questions/4775020/icon-overlay-issue-with-python# >>> > >>> on >>> Stack Overflow I have a script that will show overlays on files >>> and >>> folders based on their "state" similar to Tortoise SVN or >>> Dropbox. Works >>> great. >>> >>> My problem is that once I restart the explorer.exe process or >>> the OS >>> itself and open explorer there are no longer any overlays. >>> >>> My first thought: >>> >>> * Have the service that actually manages file state detect >>> that no >>> requests have come in and just re-register the overlay >>> handler >>> >>> The problem here is that registration requires elevated >>> permissions >>> which is acceptable on initial install of the application by the >>> end >>> user but not every time they restart their machine. >>> >>> Can anyone suggest what I might be missing here? I have the class >>> BaseOverlay and its children in a single .py file and register >>> from my >>> main app by calling this script using subprocess. >>> >>> >>> |subprocess.check_call("C:\scripts\register_overlays.py",shell=True)| >>> >>> Is Explorer not able to re-load the script as it is Python? Do I >>> need to >>> compile into a DLL or EXE? Would that change the registration >>> process? >>> >>> Here's the registration call: >>> >>> |win32com.server.register.UseCommandLine(BaseOverlay)| >>> >>> Here's the class(simplified): >>> >>> |classBaseOverlay:_reg_clsid_ >>> ='{8D4B1C5D-F8AC-4FDA-961F-A0143CD97C41}'_reg_progid_ >>> ='someoverlays'_reg_desc_ ='Icon Overlay Handler'_public_methods_ >>> =['GetOverlayInfo','GetPriority','IsMemberOf']_com_interfaces_ >>> >>> =[shell.IID_IShellIconOverlayIdentifier]defGetOverlayInfo(self):returnicon_path,0,shellcon.ISIOI_ICONFILE >>> >>> defGetPriority(self):return50defIsMemberOf(self,fname,attributes):returnwinerror.S_OK| >>> >>> Thanks for any help you can provide, >>> >>> Alex Jewell >>> >>> >>> >>> >>> _______________________________________________ >>> python-win32 mailing list >>> python-win32@python.org <mailto:python-win32@python.org> >>> https://mail.python.org/mailman/listinfo/python-win32 >>> >>> >>> >> >
import logging import subprocess import _winreg as winreg from logging.handlers import RotatingFileHandler import winerror from win32com.shell import shell, shellcon import win32con import win32com.server.register class OSHelper(object): @staticmethod def restart_process(process_name): try: killed = subprocess.call(['taskkill', '/f', '/im', process_name]) except subprocess.TimeoutExpired as e: print(e) except Exception as e: print(e) return False if killed == 0: try: subprocess.Popen([process_name]) except Exception as e: print(e) return False return True class OverlayLogger(object): log_file_name = r"C:\overlay_handlers\overlays.log" max_bytes = 5242880 backup_count = 5 log_level = logging.DEBUG log_format = "%(asctime)s : %(levelname)s : %(threadName)s : %(message)s" log = None def __init__(self): logger = logging.getLogger() for h in logger.handlers: logger.removeHandler(h) logger.setLevel(self.log_level) handler = RotatingFileHandler(self.log_file_name, maxBytes=self.max_bytes, backupCount=self.backup_count) handler.setLevel(self.log_level) formatter = logging.Formatter(self.log_format) handler.setFormatter(formatter) logger.addHandler(handler) logger.info("Overlay Logging Started") type(self).log = logger class WindowsRegistry(object): def __init__(self, root, key): self._reg_root = root self._reg_key = key self.create_registry_key() def create_registry_key(self): try: winreg.CreateKey(self._reg_root, self._reg_key) except WindowsError as details: logging.getLogger(__name__).error(details) return False return True def set_registry_subkey(self, subkey, value): try: key = winreg.OpenKey(self._reg_root, self._reg_key, 0, winreg.KEY_WRITE) winreg.SetValueEx(key, subkey, 0, win32con.REG_SZ, value) winreg.CloseKey(key) return True except WindowsError as details: logging.getLogger(__name__).error(details) return False class BaseOverlay: _reg_clsid_ = '{b8c0f456-1041-45b8-aa49-e56085a8d9fe}' _reg_progid_ = 'demo.overlays' _reg_desc_ = 'Icon Overlay Handler Example' _public_methods_ = ['GetOverlayInfo', 'GetPriority', 'IsMemberOf'] _com_interfaces_ = [shell.IID_IShellIconOverlayIdentifier] handler_name = 'ExampleBaseOverlay' overlay_icon = r'C:\overlay_handlers\green_checkbox.ico' reg_base = winreg.HKEY_LOCAL_MACHINE reg_key_base = 'Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers' reg_key = "{0}\\{1}".format(reg_key_base, handler_name) def __init__(self): log = OverlayLogger().log log.debug("Initializing {0}".format(self.__class__.__name__)) # Override to set an overlay icon # This is only called on initialization, changing the icon path later (e.g. based on the filename) will not work def GetOverlayInfo(self): return self.overlay_icon, 0, shellcon.ISIOI_ICONFILE # Override this method to set a higher or lower priority on this icon # Experiments haven't shown any effect, Windows seems to rely solely on the name of the Handler in the registry def GetPriority(self): return 50 # Override this method in each handler to set the correct icon. In case of multiple overlays returning winerror.S_OK # Windows will pick the first handler in alphabetical order based on its name in the registry def IsMemberOf(self, fname, attributes): log = logging.getLogger(__name__).debug("Getting {0} overlay for file {1}".format(self.__class__.__name__, fname)) if "py" in fname: return winerror.S_OK return winerror.E_FAIL @classmethod def register(cls): reg = WindowsRegistry(cls.reg_base, cls.reg_key) log = OverlayLogger().log log.info("Updating Registry Key for {0}...".format(cls.__name__)) reg.set_registry_subkey(None, cls._reg_clsid_) log.info("Registering Overlay Handler {0}".format(cls.__name__)) win32com.server.register.UseCommandLine(cls) if __name__=='__main__': log = OverlayLogger().log log.info("Registration started") overlay_handlers = [BaseOverlay] for overlay_handler in overlay_handlers: overlay_handler.register() log.info("Registration complete") OSHelper.restart_process("explorer.exe") log.info("Finished restarting explorer")
from distutils.core import setup import py2exe import sys try: import py2exe.mf as modulefinder except ImportError: import modulefinder import win32com for p in win32com.__path__[1:]: modulefinder.AddPackagePath("win32com", p) for extra in ["win32com.shell"]: __import__(extra) m = sys.modules[extra] for p in m.__path__[1:]: modulefinder.AddPackagePath(extra, p) setup(console=['overlays.py'])
from distutils.core import setup import py2exe import sys try: import py2exe.mf as modulefinder except ImportError: import modulefinder import win32com for p in win32com.__path__[1:]: modulefinder.AddPackagePath("win32com", p) for extra in ["win32com.shell"]: __import__(extra) m = sys.modules[extra] for p in m.__path__[1:]: modulefinder.AddPackagePath(extra, p) class Target: def __init__(self, **kw): self.__dict__.update(kw) # for the version info resources (Properties -- Version) self.version = "1.0" self.company_name = "My name" self.copyright = "(C) 2011, My company" self.name = "heikki" heikki_target = Target( description="my com server desc", # use module name for win32com exe/dll server modules=["overlays"], # specify which type of com server you want (exe and/or dll) create_exe=True, create_dll=False ) setup( version="1.0", zipfile=None, description="my com server", name="heikki", author="Heikki", com_server=[heikki_target], )
_______________________________________________ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32