[pywin32-checkins] pywin32/com/win32comext/shell/demos/servers shell_view.py,1.2,1.3
OLD project page for the Python extensions for Windows
Brought to you by:
mhammond
|
From: <mha...@us...> - 2003-11-24 09:25:20
|
Update of /cvsroot/pywin32/pywin32/com/win32comext/shell/demos/servers
In directory sc8-pr-cvs1:/tmp/cvs-serv10424
Modified Files:
shell_view.py
Log Message:
A shell folder and shell view implementation - adds a new top-level
namespace for Python's sys.path, and uses scintilla to display the file.
Index: shell_view.py
===================================================================
RCS file: /cvsroot/pywin32/pywin32/com/win32comext/shell/demos/servers/shell_view.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** shell_view.py 6 Nov 2003 06:11:51 -0000 1.2
--- shell_view.py 24 Nov 2003 09:25:17 -0000 1.3
***************
*** 3,23 ****
# To demostrate:
# * Execute this script to register the namespace.
! # * Open Windows Explorer
! # * Note the new folder hanging off "My Computer"
! # This is still incomplete - but we *do* create a view window - we just do
! # nothing with it.
import sys, os
import pythoncom
from win32com.shell import shell, shellcon
! import win32gui
! import win32con
! import winerror
! from win32com.server.util import wrap
! debug=1
! if debug:
! import win32com.server.dispatcher
! defaultDispatcher = win32com.server.dispatcher.DefaultDebugDispatcher
IOleWindow_Methods = "GetWindow ContextSensitiveHelp".split()
IShellView_Methods = IOleWindow_Methods + \
--- 3,55 ----
# To demostrate:
# * Execute this script to register the namespace.
! # * Open Windows Explorer, and locate the new "Python Path Shell Browser"
! # folder off "My Computer"
! # * Browse this tree - .py files are shown expandable, with classes and
! # methods selectable. Selecting a Python file, or a class/method, will
! # display the file using Scintilla.
! # Known problems:
! # * Classes and methods don't have icons
!
import sys, os
+ import thread
+ import pyclbr
import pythoncom
+ import win32gui, win32api, win32con, winerror
from win32com.shell import shell, shellcon
! from win32com.server.util import wrap, NewEnum
! from win32com.server.exception import COMException
! from win32com.util import IIDToInterfaceName
! from pywin.scintilla import scintillacon
! debug=0
!
! # Helper function to get a system IShellFolder interface, and the PIDL within
! # that folder for an existing file/directory.
! def GetFolderAndPIDLForPath(filename):
! desktop = shell.SHGetDesktopFolder()
! info = desktop.ParseDisplayName(0, None, os.path.abspath(filename))
! cchEaten, pidl, attr = info
! # We must walk the ID list, looking for one child at a time.
! folder = desktop
! while len(pidl) > 1:
! this = pidl.pop(0)
! folder = folder.BindToObject([this], None, shell.IID_IShellFolder)
! # We are left with the pidl for the specific item. Leave it as
! # a list, so it remains a valid PIDL.
! return folder, pidl
+ # A cache of pyclbr module objects, so we only parse a given filename once.
+ clbr_modules = {} # Indexed by path, item is dict as returned from pyclbr
+ def get_clbr_for_file(path):
+ try:
+ objects = clbr_modules[path]
+ except KeyError:
+ dir, filename = os.path.split(path)
+ base, ext = os.path.splitext(filename)
+ objects = pyclbr.readmodule_ex(base, [dir])
+ clbr_modules[path] = objects
+ return objects
+
+ # Our COM interfaces.
IOleWindow_Methods = "GetWindow ContextSensitiveHelp".split()
IShellView_Methods = IOleWindow_Methods + \
***************
*** 26,29 ****
--- 58,62 ----
GetCurrentInfo AddPropertySheetPages SaveViewState
SelectItem GetItemObject""".split()
+
IShellFolder_Methods = """ParseDisplayName EnumObjects BindToObject
BindToStorage CompareIDs CreateViewObject
***************
*** 36,65 ****
IPersistFolder_Methods = IPersist_Methods + ["Initialize"]
! # Our shell extension.
! class ShellView:
! # _reg_progid_ = "Python.ShellExtension.View"
! # _reg_desc_ = "Python Sample Shell Extension (View)"
! _public_methods_ = IShellView_Methods
! _com_interfaces_ = [pythoncom.IID_IOleWindow,
! shell.IID_IShellView,
! ]
! def __init__(self, hwnd):
! self.hwnd_parent = hwnd
! # IShellView
! def CreateViewWindow(self, prev, settings, browser, rect):
! print "CreateViewWindow", prev, settings, browser, rect
! import win32ui
! style = win32con.WS_VISIBLE|win32con.WS_CHILD
! l = win32ui.CreateListCtrl()
! l.CreateWindow(style, rect, self.hwnd_parent, 1)
! l.InsertItem(0, "Hello")
! return l.GetSafeHwnd()
! def TranslateAccelerator(self, msg):
! return winerror.S_FALSE
!
! class ShellFolder:
! _reg_progid_ = "Python.ShellExtension.Folder"
! _reg_desc_ = "Python Sample Shell Extension (Folder)"
! _reg_clsid_ = "{f6287035-3074-4cb5-a8a6-d3c80e206944}"
_com_interfaces_ = [shell.IID_IBrowserFrameOptions,
pythoncom.IID_IPersist,
--- 69,76 ----
IPersistFolder_Methods = IPersist_Methods + ["Initialize"]
! # Base class for a shell folder.
! # All child classes use a simple PIDL of the form:
! # "object_type\0object_name[\0extra ...]"
! class ShellFolderBase:
_com_interfaces_ = [shell.IID_IBrowserFrameOptions,
pythoncom.IID_IPersist,
***************
*** 71,87 ****
IPersistFolder_Methods + \
IShellFolder_Methods
! # IPersistFolder
def GetFrameOptions(self, mask):
return 0
def GetClassID(self):
return self._reg_clsid_
- # IPersist
def Initialize(self, pidl):
! print "Got pidl", repr(pidl)
! # IShellFolder
def CreateViewObject(self, hwnd, iid):
! print "CreateViewObject", hwnd, iid
! return wrap(ShellView(hwnd), useDispatcher=defaultDispatcher)
!
def DllRegisterServer():
import _winreg
--- 82,368 ----
IPersistFolder_Methods + \
IShellFolder_Methods
!
def GetFrameOptions(self, mask):
+ #print "GetFrameOptions", self, mask
return 0
+ def ParseDisplayName(self, hwnd, reserved, displayName):
+ print "ParseDisplayName", displayName
+ # return cchEaten, pidl, attr
+ def BindToStorage(self, pidl, bc, iid):
+ print "BTS", iid, IIDToInterfaceName(iid)
+ def BindToObject(self, pidl, bc, iid):
+ # We may be passed a set of relative PIDLs here - ie
+ # [pidl_of_dir, pidl_of_child_dir, pidl_of_file, pidl_of_function]
+ # But each of our PIDLs keeps the fully qualified name anyway - so
+ # just jump directly to the last.
+ final_pidl = pidl[-1]
+ typ, extra = final_pidl.split('\0', 1)
+ if typ == "directory":
+ klass = ShellFolderDirectory
+ elif typ == "file":
+ klass = ShellFolderFile
+ elif typ == "object":
+ klass = ShellFolderObject
+ else:
+ raise RuntimeError, "What is " + repr(typ)
+ ret = wrap(klass(extra), iid, useDispatcher = (debug>0))
+ return ret
+
+ # A ShellFolder for an object with CHILDREN on the file system
+ # Note that this means our "File" folder is *not* a 'FileSystem' folder,
+ # as it's children (functions and classes) are not on the file system.
+ #
+ class ShellFolderFileSystem(ShellFolderBase):
+ def _GetFolderAndPIDLForPIDL(self, my_idl):
+ typ, name = my_idl[0].split('\0')
+ return GetFolderAndPIDLForPath(name)
+ # Interface methods
+ def CompareIDs(self, param, id1, id2):
+ return cmp(id1, id2)
+ def GetUIObjectOf(self, hwndOwner, pidls, iid, inout):
+ # delegate to the shell.
+ assert len(pidls)==1, "oops - arent expecting more than one!)"
+ pidl = pidls[0]
+ folder, child_pidl = self._GetFolderAndPIDLForPIDL(pidl)
+ try:
+ inout, ret = folder.GetUIObjectOf(hwndOwner, [child_pidl], iid,
+ inout, pythoncom.IID_IUnknown)
+ except pythoncom.com_error, (hr, desc, exc, arg):
+ raise COMException(hresult=hr)
+ return inout, ret
+ # return object of IID
+ def GetDisplayNameOf(self, pidl, flags):
+ # delegate to the shell.
+ folder, child_pidl = self._GetFolderAndPIDLForPIDL(pidl)
+ ret = folder.GetDisplayNameOf(child_pidl, flags)
+ return ret
+ def GetAttributesOf(self, pidls, attrFlags):
+ ret_flags = -1
+ for pidl in pidls:
+ pidl = pidl[0] # ??
+ typ, name = pidl.split('\0')
+ flags = shellcon.SHGFI_ATTRIBUTES
+ info = shell.SHGetFileInfo(name, 0, flags)
+ hIcon, iIcon, dwAttr, name, typeName = info
+ # All our items, even files, have sub-items
+ extras = shellcon.SFGAO_HASSUBFOLDER | \
+ shellcon.SFGAO_FOLDER | \
+ shellcon.SFGAO_FILESYSANCESTOR
+ ret_flags &= (dwAttr | extras)
+ return ret_flags
+
+ class ShellFolderDirectory(ShellFolderFileSystem):
+ def __init__(self, path):
+ self.path = os.path.abspath(path)
+ def CreateViewObject(self, hwnd, iid):
+ # delegate to the shell.
+ folder, child_pidl = GetFolderAndPIDLForPath(self.path)
+ return folder.CreateViewObject(hwnd, iid)
+ def EnumObjects(self, hwndOwner, flags):
+ pidls = []
+ for fname in os.listdir(self.path):
+ fqn = os.path.join(self.path, fname)
+ if os.path.isdir(fqn):
+ type_name = "directory"
+ type_class = ShellFolderDirectory
+ else:
+ base, ext = os.path.splitext(fname)
+ if ext in [".py", ".pyw"]:
+ type_class = ShellFolderFile
+ type_name = "file"
+ else:
+ type_class = None
+ if type_class is not None:
+ pidls.append( [type_name + "\0" + fqn] )
+ return NewEnum(pidls, iid=shell.IID_IEnumIDList,
+ useDispatcher=(debug>0))
+
+ # As per comments above, even though this manages a file, it is *not* a
+ # ShellFolderFileSystem, as the children are not on the file system.
+ class ShellFolderFile(ShellFolderBase):
+ def __init__(self, path):
+ self.path = os.path.abspath(path)
+ def EnumObjects(self, hwndOwner, flags):
+ objects = get_clbr_for_file(self.path)
+ pidls = []
+ for name, ob in objects.items():
+ pidls.append( ["object\0" + self.path + "\0" + name] )
+ return NewEnum(pidls, iid=shell.IID_IEnumIDList,
+ useDispatcher=(debug>0))
+
+ def GetAttributesOf(self, pidls, attrFlags):
+ ret_flags = -1
+ for pidl in pidls:
+ assert len(pidl)==1, "Expecting relative pidls"
+ pidl = pidl[0]
+ typ, filename, obname = pidl.split('\0')
+ obs = get_clbr_for_file(filename)
+ ob = obs[obname]
+ flags = shellcon.SFGAO_BROWSABLE | shellcon.SFGAO_FOLDER | \
+ shellcon.SFGAO_FILESYSANCESTOR
+ if hasattr(ob, "methods"):
+ flags |= shellcon.SFGAO_HASSUBFOLDER
+ ret_flags &= flags
+ return ret_flags
+
+ def GetDisplayNameOf(self, pidl, flags):
+ assert len(pidl)==1, "Expecting relative PIDL"
+ typ, fname, obname = pidl[0].split('\0')
+ return obname
+
+ def CreateViewObject(self, hwnd, iid):
+ return wrap(ScintillaShellView(hwnd, self.path), useDispatcher=debug>0)
+
+ # A ShellFolder for our Python objects
+ class ShellFolderObject(ShellFolderBase):
+ def __init__(self, details):
+ self.path, details = details.split('\0')
+ if details.find(".")>0:
+ self.class_name, self.method_name = details.split(".")
+ else:
+ self.class_name = details
+ self.method_name = None
+ def CreateViewObject(self, hwnd, iid):
+ mod_objects = get_clbr_for_file(self.path)
+ object = mod_objects[self.class_name]
+ if self.method_name is None:
+ lineno = object.lineno
+ else:
+ lineno = object.methods[self.method_name]
+ return wrap(ScintillaShellView(hwnd, self.path, lineno),
+ useDispatcher=debug>0)
+ def EnumObjects(self, hwndOwner, flags):
+ assert self.method_name is None, "Should not be enuming methods!"
+ mod_objects = get_clbr_for_file(self.path)
+ my_objects = mod_objects[self.class_name]
+ pidls = []
+ for func_name, lineno in my_objects.methods.items():
+ pidl = ["object\0" + self.path + "\0" +
+ self.class_name + "." + func_name]
+ pidls.append(pidl)
+ return NewEnum(pidls, iid=shell.IID_IEnumIDList,
+ useDispatcher=(debug>0))
+ def GetDisplayNameOf(self, pidl, flags):
+ assert len(pidl)==1, "Expecting relative PIDL"
+ typ, fname, obname = pidl[0].split('\0')
+ class_name, method_name = obname.split('.')
+ return method_name
+ def GetAttributesOf(self, pidls, attrFlags):
+ ret_flags = -1
+ for pidl in pidls:
+ assert len(pidl)==1, "Expecting relative pidls"
+ flags = shellcon.SFGAO_BROWSABLE | shellcon.SFGAO_FOLDER | \
+ shellcon.SFGAO_FILESYSANCESTOR
+ ret_flags &= flags
+ return ret_flags
+
+ # The "Root" folder of our namespace. As all children are directories,
+ # it is derived from ShellFolderFileSystem
+ class ShellFolderRoot(ShellFolderFileSystem):
+ _reg_progid_ = "Python.ShellExtension.Folder"
+ _reg_desc_ = "Python Path Shell Browser"
+ _reg_clsid_ = "{f6287035-3074-4cb5-a8a6-d3c80e206944}"
def GetClassID(self):
return self._reg_clsid_
def Initialize(self, pidl):
! #print "Initialize called with pidl", repr(pidl)
! pass
def CreateViewObject(self, hwnd, iid):
! raise COMException(hresult=winerror.E_NOTIMPL)
! def EnumObjects(self, hwndOwner, flags):
! items = [ ["directory\0" + p] for p in sys.path if os.path.isdir(p)]
! return NewEnum(items, iid=shell.IID_IEnumIDList,
! useDispatcher=(debug>0))
!
! # A Simple shell view implementation
! # Our shell extension.
! class ScintillaShellView:
! _public_methods_ = IShellView_Methods
! _com_interfaces_ = [pythoncom.IID_IOleWindow,
! shell.IID_IShellView,
! ]
! def __init__(self, hwnd, filename, lineno = None):
! self.filename = filename
! self.lineno = lineno
! self.hwnd_parent = hwnd
! self.hwnd = None
! def _SendSci(self, msg, wparam=0, lparam=0):
! return win32gui.SendMessage(self.hwnd, msg, wparam, lparam)
!
! # IShellView
! def CreateViewWindow(self, prev, settings, browser, rect):
! print "CreateViewWindow", prev, settings, browser, rect
! # Make sure scintilla.dll is loaded. If not, find it on sys.path
! # (which it generally is for Pythonwin)
! try:
! win32api.GetModuleHandle("Scintilla.dll")
! except win32api.error:
! for p in sys.path:
! fname = os.path.join(p, "Scintilla.dll")
! if not os.path.isfile(fname):
! fname = os.path.join(p, "Build", "Scintilla.dll")
! if os.path.isfile(fname):
! win32api.LoadLibrary(fname)
! break
! else:
! raise RuntimeError, "Can't find scintilla!"
!
! style = win32con.WS_CHILD | win32con.WS_VSCROLL | \
! win32con.WS_HSCROLL | win32con.WS_CLIPCHILDREN | \
! win32con.WS_VISIBLE
! self.hwnd = win32gui.CreateWindow("Scintilla", "Scintilla", style,
! rect[0], rect[1], rect[2]-rect[0], rect[3]-rect[1],
! self.hwnd_parent, 1000, 0, None)
! file_data = file(self.filename, "U").read()
!
! self._SetupLexer()
! self._SendSci(scintillacon.SCI_SETTEXT, 0, file_data)
! self._SendSci(scintillacon.SCI_COLOURISE, 0, -1)
! if self.lineno != None:
! self._SendSci(scintillacon.SCI_GOTOLINE, self.lineno)
! print "Made scintilla", self.hwnd
!
! def _SetupLexer(self):
! h = self.hwnd
! styles = [
! ((0, 0, 200, 0, 0x808080), None, scintillacon.SCE_P_DEFAULT ),
! ((0, 2, 200, 0, 0x008000), None, scintillacon.SCE_P_COMMENTLINE ),
! ((0, 2, 200, 0, 0x808080), None, scintillacon.SCE_P_COMMENTBLOCK ),
! ((0, 0, 200, 0, 0x808000), None, scintillacon.SCE_P_NUMBER ),
! ((0, 0, 200, 0, 0x008080), None, scintillacon.SCE_P_STRING ),
! ((0, 0, 200, 0, 0x008080), None, scintillacon.SCE_P_CHARACTER ),
! ((0, 0, 200, 0, 0x008080), None, scintillacon.SCE_P_TRIPLE ),
! ((0, 0, 200, 0, 0x008080), None, scintillacon.SCE_P_TRIPLEDOUBLE),
! ((0, 0, 200, 0, 0x000000), 0x008080, scintillacon.SCE_P_STRINGEOL),
! ((0, 1, 200, 0, 0x800000), None, scintillacon.SCE_P_WORD),
! ((0, 1, 200, 0, 0xFF0000), None, scintillacon.SCE_P_CLASSNAME ),
! ((0, 1, 200, 0, 0x808000), None, scintillacon.SCE_P_DEFNAME),
! ((0, 0, 200, 0, 0x000000), None, scintillacon.SCE_P_OPERATOR),
! ((0, 0, 200, 0, 0x000000), None, scintillacon.SCE_P_IDENTIFIER ),
! ]
! self._SendSci(scintillacon.SCI_SETLEXER, scintillacon.SCLEX_PYTHON, 0)
! self._SendSci(scintillacon.SCI_SETSTYLEBITS, 5)
! print "Got back lexer", win32gui.SendMessage(self.hwnd, scintillacon.SCI_GETLEXER)
! baseFormat = (-402653169, 0, 200, 0, 0, 0, 49, 'Courier New')
! for f, bg, stylenum in styles:
! self._SendSci(scintillacon.SCI_STYLESETFORE, stylenum, f[4])
! self._SendSci(scintillacon.SCI_STYLESETFONT, stylenum, baseFormat[7])
! if f[1] & 1: self._SendSci(scintillacon.SCI_STYLESETBOLD, stylenum, 1)
! else: self._SendSci(scintillacon.SCI_STYLESETBOLD, stylenum, 0)
! if f[1] & 2: self._SendSci(scintillacon.SCI_STYLESETITALIC, stylenum, 1)
! else: self._SendSci(scintillacon.SCI_STYLESETITALIC, stylenum, 0)
! self._SendSci(scintillacon.SCI_STYLESETSIZE, stylenum, int(baseFormat[2]/20))
! if bg is not None:
! self._SendSci(scintillacon.SCI_STYLESETBACK, stylenum, bg)
! self._SendSci(scintillacon.SCI_STYLESETEOLFILLED, stylenum, 1) # Only needed for unclosed strings.
!
! def DestroyViewWindow(self):
! win32gui.DestroyWindow(self.hwnd)
! self.hwnd = None
! print "Destroyed scintilla window"
!
! def TranslateAccelerator(self, msg):
! return winerror.S_FALSE
!
def DllRegisterServer():
import _winreg
***************
*** 89,104 ****
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" \
"Explorer\\Desktop\\Namespace\\" + \
! ShellFolder._reg_clsid_)
! _winreg.SetValueEx(key, None, 0, _winreg.REG_SZ, ShellFolder._reg_desc_)
# And special shell keys under our CLSID
key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
! "CLSID\\" + ShellFolder._reg_clsid_ + "\\ShellFolder")
# 'Attributes' is an int stored as a binary! use struct
attr = shellcon.SFGAO_FOLDER | shellcon.SFGAO_HASSUBFOLDER | \
shellcon.SFGAO_BROWSABLE
import struct
! s = struct.pack("I", attr)
_winreg.SetValueEx(key, "Attributes", 0, _winreg.REG_BINARY, s)
! print ShellFolder._reg_desc_, "registration complete."
def DllUnregisterServer():
--- 370,385 ----
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" \
"Explorer\\Desktop\\Namespace\\" + \
! ShellFolderRoot._reg_clsid_)
! _winreg.SetValueEx(key, None, 0, _winreg.REG_SZ, ShellFolderRoot._reg_desc_)
# And special shell keys under our CLSID
key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
! "CLSID\\" + ShellFolderRoot._reg_clsid_ + "\\ShellFolder")
# 'Attributes' is an int stored as a binary! use struct
attr = shellcon.SFGAO_FOLDER | shellcon.SFGAO_HASSUBFOLDER | \
shellcon.SFGAO_BROWSABLE
import struct
! s = struct.pack("i", attr)
_winreg.SetValueEx(key, "Attributes", 0, _winreg.REG_BINARY, s)
! print ShellFolderRoot._reg_desc_, "registration complete."
def DllUnregisterServer():
***************
*** 108,121 ****
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" \
"Explorer\\Desktop\\Namespace\\" + \
! ShellFolder._reg_clsid_)
except WindowsError, details:
import errno
if details.errno != errno.ENOENT:
raise
! print ShellFolder._reg_desc_, "unregistration complete."
if __name__=='__main__':
from win32com.server import register
! register.UseCommandLine(ShellFolder,
finalize_register = DllRegisterServer,
finalize_unregister = DllUnregisterServer)
--- 389,403 ----
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" \
"Explorer\\Desktop\\Namespace\\" + \
! ShellFolderRoot._reg_clsid_)
except WindowsError, details:
import errno
if details.errno != errno.ENOENT:
raise
! print ShellFolderRoot._reg_desc_, "unregistration complete."
if __name__=='__main__':
from win32com.server import register
! register.UseCommandLine(ShellFolderRoot,
! debug = debug,
finalize_register = DllRegisterServer,
finalize_unregister = DllUnregisterServer)
|