# A sample shell column provider
# Mainly ported from MSDN article:
#  Using Shell Column Handlers for Detailed File Information, 
#  Raymond Chen, Microsoft Corporation, February 2000
#
# To demostrate:
# * Execute this script to register the namespace.
# * Open Windows Explorer
# * Right-click an explorer column header - select "More"
# * Locate column 'pyc size' or 'pyo size', and add it to the view.
# This handler is providing that column data.
import sys, os, stat
import pythoncom
from win32com.shell import shell, shellcon
import commctrl
import winerror
from win32com.server.util import wrap
from pywintypes import IID

IPersist_Methods = ["GetClassID"]
IColumnProvider_Methods = IPersist_Methods + \
                          ["Initialize", "GetColumnInfo", "GetItemData"]

class ColumnProvider:
    _reg_progid_ = "Python.ShellExtension.ColumnProvider"
    _reg_desc_ = "Python Sample Shell Extension (Column Provider)"
    _reg_clsid_ = IID("{0F14101A-E05E-4070-BD54-83DFA58C3D68}")
    _com_interfaces_ = [pythoncom.IID_IPersist,
                        shell.IID_IColumnProvider,
                        ]
    _public_methods_ = IColumnProvider_Methods
    # IPersist
    def GetClassID(self):
        return self._reg_clsid_
    # IColumnProvider
    def Initialize(self, colInit):
        flags, reserved, name = colInit
        print("ColumnProvider initializing for file", name)
    def GetColumnInfo(self, index):
        # We support exactly 2 columns - 'pyc size' and 'pyo size'
        if index in [0,1]:
            # As per the MSDN sample, use our CLSID as the fmtid
            if index==0:
                ext = ".pyc"
            else:
                ext = ".pyo"
            title = ext + " size"
            description = "Size of compiled %s file" % ext
            col_id = (self._reg_clsid_, # fmtid
                     index)            # pid
            col_info = (
                    col_id, # scid
                    pythoncom.VT_I4, # vt
                    commctrl.LVCFMT_RIGHT, # fmt
                    20, #cChars
                    shellcon.SHCOLSTATE_TYPE_INT | \
                    shellcon.SHCOLSTATE_SECONDARYUI, # csFlags
                    title,
                    description)
            return col_info
        return None # Indicate no more columns.
    def GetItemData(self, colid, colData):
        fmt_id, pid = colid
        fmt_id==self._reg_clsid_
        flags, attr, reserved, ext, name = colData
        if ext.lower() not in [".py", ".pyw"]:
            return None
        if pid==0:
            ext = ".pyc"
        else:
            ext = ".pyo"
        check_file = os.path.splitext(name)[0] + ext
        try:
            st = os.stat(check_file)
            return st[stat.ST_SIZE]
        except OSError:
            # No file
            return None

def DllRegisterServer():
    import winreg
    # Special ColumnProvider key
    key = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT,
                        "Folder\\ShellEx\\ColumnHandlers\\" + \
                        str(ColumnProvider._reg_clsid_ ))
    winreg.SetValueEx(key, None, 0, winreg.REG_SZ, ColumnProvider._reg_desc_)
    print(ColumnProvider._reg_desc_, "registration complete.")

def DllUnregisterServer():
    import winreg
    try:
        key = winreg.DeleteKey(winreg.HKEY_CLASSES_ROOT,
                            "Folder\\ShellEx\\ColumnHandlers\\" + \
                            str(ColumnProvider._reg_clsid_) )
    except WindowsError as details:
        import errno
        if details.errno != errno.ENOENT:
            raise
    print(ColumnProvider._reg_desc_, "unregistration complete.")

if __name__=='__main__':
    from win32com.server import register
    register.UseCommandLine(ColumnProvider,
                   finalize_register = DllRegisterServer,
                   finalize_unregister = DllUnregisterServer)
