I have three pieces of code that i\'m working with at the moment:
What I did to access Free Download Manager's type library was the following:
import pythoncom, win32com.client
fdm = pythoncom.LoadTypeLib('fdm.tlb')
downloads_stat = None
for index in xrange(0, fdm.GetTypeInfoCount()):
type_name = fdm.GetDocumentation(index)[0]
if type_name == 'FDMDownloadsStat':
type_iid = fdm.GetTypeInfo(index).GetTypeAttr().iid
downloads_stat = win32com.client.Dispatch(type_iid)
break
downloads_stat.BuildListOfDownloads(True, True)
print downloads_stat.Download(0).Url
The code above will print the URL of the first download.
Here is a method I devised to load a COM object from a DLL. It was based on a lot of reading about COM, etc. I'm not 100% sure about the last lines, specifically d=. I think that only works if IID_Dispatch is passed in (which you can see if the default param).
In addition, I believe this code leaks - for one, the DLL is never unloaded (use ctypes.windll.kernel32.FreeLibraryW) and I believe the COM ref counts for the initial class factory are off by one, and thus never get released. But still, this works for my application.
import pythoncom
import win32com.client
def CreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None, dwClsContext=pythoncom.CLSCTX_SERVER):
from uuid import UUID
from ctypes import OleDLL, c_long, byref
e = OleDLL(dll)
clsid_class = UUID(clsid_class).bytes_le
iclassfactory = UUID(str(pythoncom.IID_IClassFactory)).bytes_le
com_classfactory = c_long(0)
hr = e.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
MyFactory = pythoncom.ObjectFromAddress(com_classfactory.value, pythoncom.IID_IClassFactory)
i = MyFactory.CreateInstance(pUnkOuter, iid_interface)
d = win32com.client.__WrapDispatch(i)
return d
For a useful utility module that wraps the object-from-DLL case, as well as others, see https://gist.github.com/4219140
__all__ = (
####### Class Objects
#CoGetClassObject - Normal, not wrapped
'CoDllGetClassObject', #Get ClassObject from a DLL file
####### ClassFactory::CreateInstance Wrappers
'CoCreateInstanceFromFactory', #Create an object via IClassFactory::CreateInstance
'CoCreateInstanceFromFactoryLicenced', #Create a licenced object via IClassFactory2::CreateInstanceLic
###### Util
'CoReleaseObject', #Calls Release() on a COM object
###### Main Utility Methods
#'CoCreateInstance', #Not wrapped, normal call
'CoCreateInstanceLicenced', #CoCreateInstance, but with a licence key
###### Hacky DLL methods for reg-free COM without Activation Contexts, manifests, etc
'CoCreateInstanceFromDll', #Given a dll, a clsid, and an iid, create an object
'CoCreateInstanceFromDllLicenced', #Given a dll, a clsid, an iid, and a license key, create an object
)
IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"
from uuid import UUID
from ctypes import OleDLL, WinDLL, c_ulong, byref, WINFUNCTYPE, POINTER, c_char_p, c_void_p
from ctypes.wintypes import HRESULT
import pythoncom
import win32com.client
import logging
log = logging.getLogger(__name__)
def _raw_guid(guid):
"""Given a string GUID, or a pythoncom IID, return the GUID laid out in memory suitable for passing to ctypes"""
return UUID(str(guid)).bytes_le
proto_icf2_base = WINFUNCTYPE(HRESULT,
c_ulong,
c_ulong,
c_char_p,
c_ulong,
POINTER(c_ulong),
)
IClassFactory2__CreateInstanceLic = proto_icf2_base(7, 'CreateInstanceLic', (
(1, 'pUnkOuter'),
(1 | 4, 'pUnkReserved'),
(1, 'riid'),
(1, 'bstrKey'),
(2, 'ppvObj'),
), _raw_guid(IID_IClassFactory2))
#--------------------------------
#--------------------------------
def _pc_wrap(iptr, resultCLSID=None):
#return win32com.client.__WrapDispatch(iptr)
log.debug("_pc_wrap: %s, %s"%(iptr, resultCLSID))
disp = win32com.client.Dispatch(iptr, resultCLSID=resultCLSID)
log.debug("_pc_wrap: %s (%s)", disp.__class__.__name__, disp)
return disp
def CoCreateInstanceFromFactory(factory_ptr, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
"""Given a factory_ptr whose interface is IClassFactory, create the instance of clsid_class with the specified interface"""
ClassFactory = pythoncom.ObjectFromAddress(factory_ptr.value, pythoncom.IID_IClassFactory)
i = ClassFactory.CreateInstance(pUnkOuter, iid_interface)
return i
def CoCreateInstanceFromFactoryLicenced(factory_ptr, key, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
"""Given a factory_ptr whose interface is IClassFactory2, create the instance of clsid_class with the specified interface"""
requested_iid = _raw_guid(iid_interface)
ole_aut = WinDLL("OleAut32.dll")
key_bstr = ole_aut.SysAllocString(unicode(key))
try:
obj = IClassFactory2__CreateInstanceLic(factory_ptr, pUnkOuter or 0, c_char_p(requested_iid), key_bstr)
disp_obj = pythoncom.ObjectFromAddress(obj, iid_interface)
return disp_obj
finally:
if key_bstr:
ole_aut.SysFreeString(key_bstr)
#----------------------------------
def CoReleaseObject(obj_ptr):
"""Calls Release() on a COM object. obj_ptr should be a c_void_p"""
if not obj_ptr:
return
IUnknown__Release = WINFUNCTYPE(HRESULT)(2, 'Release', (), pythoncom.IID_IUnknown)
IUnknown__Release(obj_ptr)
#-----------------------------------
def CoCreateInstanceLicenced(clsid_class, key, pythoncom_iid_interface=pythoncom.IID_IDispatch, dwClsContext=pythoncom.CLSCTX_SERVER, pythoncom_wrapdisp=True, wrapas=None):
"""Uses IClassFactory2::CreateInstanceLic to create a COM object given a licence key."""
IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"
ole = OleDLL("Ole32.dll")
clsid_class_raw = _raw_guid(clsid_class)
iclassfactory2 = _raw_guid(IID_IClassFactory2)
com_classfactory = c_void_p(0)
ole.CoGetClassObject(clsid_class_raw, dwClsContext, None, iclassfactory2, byref(com_classfactory))
try:
iptr = CoCreateInstanceFromFactoryLicenced(
factory_ptr = com_classfactory,
key=key,
iid_interface=pythoncom_iid_interface,
pUnkOuter=None,
)
if pythoncom_wrapdisp:
return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
return iptr
finally:
if com_classfactory:
CoReleaseObject(com_classfactory)
#-----------------------------------------------------------
#DLLs
def CoDllGetClassObject(dll_filename, clsid_class, iid_factory=pythoncom.IID_IClassFactory):
"""Given a DLL filename and a desired class, return the factory for that class (as a c_void_p)"""
dll = OleDLL(dll_filename)
clsid_class = _raw_guid(clsid_class)
iclassfactory = _raw_guid(iid_factory)
com_classfactory = c_void_p(0)
dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
return com_classfactory
def CoCreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
iclassfactory_ptr = CoDllGetClassObject(dll, clsid_class)
try:
iptr = CoCreateInstanceFromFactory(iclassfactory_ptr, iid_interface)
if pythoncom_wrapdisp:
return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
return iptr
finally:
CoReleaseObject(iclassfactory_ptr)
def CoCreateInstanceFromDllLicenced(dll, clsid_class, key, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
iclassfactory2_ptr = CoDllGetClassObject(dll, clsid_class, iid_factory=IID_IClassFactory2)
try:
iptr = CoCreateInstanceFromFactoryLicenced(iclassfactory2_ptr, key, iid_interface)
if pythoncom_wrapdisp:
return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
return iptr
finally:
CoReleaseObject(iclassfactory2_ptr)