123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- """Utilities for selecting and enumerating the Type Libraries installed on the system
- """
-
- import pythoncom
- import win32api
- import win32con
-
-
- class TypelibSpec:
- def __init__(self, clsid, lcid, major, minor, flags=0):
- self.clsid = str(clsid)
- self.lcid = int(lcid)
- # We avoid assuming 'major' or 'minor' are integers - when
- # read from the registry there is some confusion about if
- # they are base 10 or base 16 (they *should* be base 16, but
- # how they are written is beyond our control.)
- self.major = major
- self.minor = minor
- self.dll = None
- self.desc = None
- self.ver_desc = None
- self.flags = flags
-
- # For the SelectList
- def __getitem__(self, item):
- if item == 0:
- return self.ver_desc
- raise IndexError("Cant index me!")
-
- def __lt__(self, other): # rich-cmp/py3k-friendly version
- me = (
- (self.ver_desc or "").lower(),
- (self.desc or "").lower(),
- self.major,
- self.minor,
- )
- them = (
- (other.ver_desc or "").lower(),
- (other.desc or "").lower(),
- other.major,
- other.minor,
- )
- return me < them
-
- def __eq__(self, other): # rich-cmp/py3k-friendly version
- return (
- (self.ver_desc or "").lower() == (other.ver_desc or "").lower()
- and (self.desc or "").lower() == (other.desc or "").lower()
- and self.major == other.major
- and self.minor == other.minor
- )
-
- def Resolve(self):
- if self.dll is None:
- return 0
- tlb = pythoncom.LoadTypeLib(self.dll)
- self.FromTypelib(tlb, None)
- return 1
-
- def FromTypelib(self, typelib, dllName=None):
- la = typelib.GetLibAttr()
- self.clsid = str(la[0])
- self.lcid = la[1]
- self.major = la[3]
- self.minor = la[4]
- if dllName:
- self.dll = dllName
-
-
- def EnumKeys(root):
- index = 0
- ret = []
- while 1:
- try:
- item = win32api.RegEnumKey(root, index)
- except win32api.error:
- break
- try:
- # Note this doesn't handle REG_EXPAND_SZ, but the implementation
- # here doesn't need to - that is handled as the data is read.
- val = win32api.RegQueryValue(root, item)
- except win32api.error:
- val = "" # code using this assumes a string.
-
- ret.append((item, val))
- index = index + 1
- return ret
-
-
- FLAG_RESTRICTED = 1
- FLAG_CONTROL = 2
- FLAG_HIDDEN = 4
-
-
- def EnumTlbs(excludeFlags=0):
- """Return a list of TypelibSpec objects, one for each registered library."""
- key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "Typelib")
- iids = EnumKeys(key)
- results = []
- for iid, crap in iids:
- try:
- key2 = win32api.RegOpenKey(key, str(iid))
- except win32api.error:
- # A few good reasons for this, including "access denied".
- continue
- for version, tlbdesc in EnumKeys(key2):
- major_minor = version.split(".", 1)
- if len(major_minor) < 2:
- major_minor.append("0")
- # For some reason, this code used to assume the values were hex.
- # This seems to not be true - particularly for CDO 1.21
- # *sigh* - it appears there are no rules here at all, so when we need
- # to know the info, we must load the tlb by filename and request it.
- # The Resolve() method on the TypelibSpec does this.
- # For this reason, keep the version numbers as strings - that
- # way we can't be wrong! Let code that really needs an int to work
- # out what to do. FWIW, http://support.microsoft.com/kb/816970 is
- # pretty clear that they *should* be hex.
- major = major_minor[0]
- minor = major_minor[1]
- key3 = win32api.RegOpenKey(key2, str(version))
- try:
- # The "FLAGS" are at this point
- flags = int(win32api.RegQueryValue(key3, "FLAGS"))
- except (win32api.error, ValueError):
- flags = 0
- if flags & excludeFlags == 0:
- for lcid, crap in EnumKeys(key3):
- try:
- lcid = int(lcid)
- except ValueError: # not an LCID entry
- continue
- # Check for both "{lcid}\win32" and "{lcid}\win64" keys.
- try:
- key4 = win32api.RegOpenKey(key3, "%s\\win32" % (lcid,))
- except win32api.error:
- try:
- key4 = win32api.RegOpenKey(key3, "%s\\win64" % (lcid,))
- except win32api.error:
- continue
- try:
- dll, typ = win32api.RegQueryValueEx(key4, None)
- if typ == win32con.REG_EXPAND_SZ:
- dll = win32api.ExpandEnvironmentStrings(dll)
- except win32api.error:
- dll = None
- spec = TypelibSpec(iid, lcid, major, minor, flags)
- spec.dll = dll
- spec.desc = tlbdesc
- spec.ver_desc = tlbdesc + " (" + version + ")"
- results.append(spec)
- return results
-
-
- def FindTlbsWithDescription(desc):
- """Find all installed type libraries with the specified description"""
- ret = []
- items = EnumTlbs()
- for item in items:
- if item.desc == desc:
- ret.append(item)
- return ret
-
-
- def SelectTlb(title="Select Library", excludeFlags=0):
- """Display a list of all the type libraries, and select one. Returns None if cancelled"""
- import pywin.dialogs.list
-
- items = EnumTlbs(excludeFlags)
- # fixup versions - we assume hex (see __init__ above)
- for i in items:
- i.major = int(i.major, 16)
- i.minor = int(i.minor, 16)
- items.sort()
- rc = pywin.dialogs.list.SelectFromLists(title, items, ["Type Library"])
- if rc is None:
- return None
- return items[rc]
-
-
- # Test code.
- if __name__ == "__main__":
- print(SelectTlb().__dict__)
|