1 #Copyright (c) 2009 Vincent Povirk
3 #Permission is hereby granted, free of charge, to any person
4 #obtaining a copy of this software and associated documentation
5 #files (the "Software"), to deal in the Software without
6 #restriction, including without limitation the rights to use,
7 #copy, modify, merge, publish, distribute, sublicense, and/or sell
8 #copies of the Software, and to permit persons to whom the
9 #Software is furnished to do so, subject to the following
12 #The above copyright notice and this permission notice shall be
13 #included in all copies or substantial portions of the Software.
15 #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 #OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 #WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 #OTHER DEALINGS IN THE SOFTWARE.
26 from ctypes
import POINTER
, c_void_p
, Structure
, WINFUNCTYPE
, cast
, byref
, addressof
27 from windef
import HRESULT
, GUID
, REFIID
, ULONG
29 class _COMMethod(object):
30 __slots__
= ['p', 'name']
31 def __init__(self
, obj
, name
):
35 def __call__(self
, *args
):
36 return getattr(self
.p
.contents
.contents
, self
.name
)(self
.p
, *args
)
38 class _COMMethodGetter(object):
40 def __init__(self
, name
):
43 def __get__(self
, instance
, owner
):
44 return _COMMethod(instance
, self
.name
)
46 def _translate_methods(methods
, vtable
):
47 # translates a com method list into a vtable
49 objtype
= POINTER(POINTER(vtable
))
50 for method
in methods
:
52 functype
= WINFUNCTYPE(method
[1], objtype
, *method
[2:])
53 result
.append((name
, functype
))
56 class _interface_outparam(object):
57 __slots__
= ['p', '_as_parameter_']
60 self
._as
_parameter
_ = addressof(self
.p
)
63 def from_param(cls
, arg
):
66 elif isinstance(arg
, cls
) or (isinstance(arg
, _interface_outparam
) and issubclass(cls
.cls
, arg
.cls
)):
73 result
= self
.cls(self
.p
.value
)
77 raise ValueError("NULL interface pointer")
83 class _InterfaceClass(type):
84 def __init__(self
, name
, bases
, dict):
85 type.__init
__(self
, name
, bases
, dict)
87 # create the vtable type
88 class vtable(Structure
):
90 vtable
.__name
__ = '_%s_vtable' % name
93 if 'com_methods' in dict:
94 self
.set_methods(self
.com_methods
)
95 #else the creator of the class must call set_methods
97 # a COM object is a pointer to a pointer to a vtable
98 self
.objtype
= POINTER(POINTER(vtable
))
100 self
.outparam
= type('_%s_outparam' % name
, (_interface_outparam
,), {'cls': self
})
102 def set_methods(self
, methods
):
103 # add the base class methods to our list of methods
104 for base
in self
.__bases
__:
106 self
.com_methods
= base
.com_methods
+ methods
108 except AttributeError:
111 self
.com_methods
= methods
113 self
._vtable
._fields
_ = _translate_methods(self
.com_methods
, self
._vtable
)
115 # add an attribute for each method
116 for method
in self
.com_methods
:
117 setattr(self
, method
[0], _COMMethodGetter(method
[0]))
119 class _BaseInterface(object):
122 def __init__(self
, p
):
123 self
.p
= cast(c_void_p(p
), self
.objtype
)
125 def _get_parameter(self
):
128 _as_parameter_
= property(_get_parameter
)
131 def from_param(cls
, arg
):
134 elif isinstance(arg
, cls
):
139 # Needed because 3.0 added new syntax for metaclasses and removed the old syntax.
140 _InterfaceClassInstanceBase
= _InterfaceClass('_InterfaceClassInstanceBase', (_BaseInterface
,), {})
142 class IUnknown(_InterfaceClassInstanceBase
):
144 ('QueryInterface', HRESULT
, REFIID
, POINTER(c_void_p
)),
149 iid
= GUID("00000000-0000-0000-C000-000000000046")
151 def __init__(self
, obj
):
154 obj
.QueryInterface(byref(self
.iid
), byref(p
))
155 self
.p
= cast(p
, self
.objtype
)
156 except AttributeError:
157 _InterfaceClassInstanceBase
.__init
__(self
, obj
)