зеркало из https://github.com/mozilla/pjs.git
Add interface flattening to Python XPCOM bindings.
Not part of the build, but a=drivers@mozilla.org anyway!
This commit is contained in:
Родитель
703c17b979
Коммит
6da17cde8e
|
@ -17,9 +17,11 @@
|
|||
|
||||
import os
|
||||
import new
|
||||
from xpcom import xpt, _xpcom, COMException, nsError
|
||||
from xpcom import xpt, COMException, nsError
|
||||
|
||||
XPTC_InvokeByIndex = _xpcom.XPTC_InvokeByIndex
|
||||
# Suck in stuff from _xpcom we use regularly to prevent a module lookup
|
||||
from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, IID_nsISupportsString, IID_nsISupportsWeakReference, \
|
||||
IID_nsIWeakReference, XPTI_GetInterfaceInfoManager, NS_GetGlobalComponentManager, XPTC_InvokeByIndex
|
||||
|
||||
_just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"]
|
||||
_just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"]
|
||||
|
@ -31,9 +33,7 @@ _float_interfaces = _just_float_interfaces + _just_long_interfaces + _just_int_i
|
|||
|
||||
method_template = """
|
||||
def %s(self, %s):
|
||||
return XPTC_InvokeByIndex(self._comobj_, %d,
|
||||
(%s,
|
||||
(%s)))
|
||||
return XPTC_InvokeByIndex(self._comobj_, %d, (%s, (%s)))
|
||||
"""
|
||||
def _MakeMethodCode(method):
|
||||
# Build a declaration
|
||||
|
@ -66,8 +66,43 @@ def _MakeMethodCode(method):
|
|||
|
||||
# Keyed by IID, each item is a tuple of (methods, getters, setters)
|
||||
interface_cache = {}
|
||||
# Keyed by [iid][name], each item is an unbound method.
|
||||
interface_method_cache = {}
|
||||
|
||||
# Fully process the interface - generate method code, etc.
|
||||
def _shutdown():
|
||||
interface_cache.clear()
|
||||
interface_method_cache.clear()
|
||||
|
||||
# Fully process the named method, generating method code etc.
|
||||
def BuildMethod(method_info, iid):
|
||||
name = method_info.name
|
||||
try:
|
||||
return interface_method_cache[iid][name]
|
||||
except KeyError:
|
||||
pass
|
||||
# Generate it.
|
||||
assert not (method_info.IsSetter() or method_info.IsGetter()), "getters and setters should have been weeded out by now"
|
||||
method_code = _MakeMethodCode(method_info)
|
||||
# Build the method - We only build a function object here
|
||||
# - they are bound to each instance as needed.
|
||||
|
||||
## print "Method Code for %s (%s):" % (name, iid)
|
||||
## print method_code
|
||||
codeObject = compile(method_code, "<XPCOMObject method '%s'>" % (name,), "exec")
|
||||
# Exec the code object
|
||||
tempNameSpace = {}
|
||||
exec codeObject in globals(), tempNameSpace
|
||||
ret = tempNameSpace[name]
|
||||
if not interface_method_cache.has_key(iid):
|
||||
interface_method_cache[iid] = {}
|
||||
interface_method_cache[iid][name] = ret
|
||||
return ret
|
||||
|
||||
from xpcom.xpcom_consts import XPT_MD_GETTER, XPT_MD_SETTER, XPT_MD_NOTXPCOM, XPT_MD_CTOR, XPT_MD_HIDDEN
|
||||
FLAGS_TO_IGNORE = XPT_MD_NOTXPCOM | XPT_MD_CTOR | XPT_MD_HIDDEN
|
||||
|
||||
# Pre-process the interface - generate a list of methods, constants etc,
|
||||
# but don't actually generate the method code.
|
||||
def BuildInterfaceInfo(iid):
|
||||
ret = interface_cache.get(iid, None)
|
||||
if ret is None:
|
||||
|
@ -75,72 +110,30 @@ def BuildInterfaceInfo(iid):
|
|||
method_code_blocks = []
|
||||
getters = {}
|
||||
setters = {}
|
||||
method_names = []
|
||||
method_infos = {}
|
||||
|
||||
interface = xpt.Interface(iid)
|
||||
for m in interface.methods:
|
||||
if not m.IsNotXPCOM() and \
|
||||
not m.IsHidden() and \
|
||||
not m.IsConstructor():
|
||||
# Yay - a method we can use!
|
||||
if m.IsSetter():
|
||||
flags = m.flags
|
||||
if flags & FLAGS_TO_IGNORE == 0:
|
||||
if flags & XPT_MD_SETTER:
|
||||
param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params)
|
||||
setters[m.name] = m.method_index, param_flags
|
||||
elif m.IsGetter():
|
||||
elif flags & XPT_MD_GETTER:
|
||||
param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params)
|
||||
getters[m.name] = m.method_index, param_flags
|
||||
else:
|
||||
method_names.append(m.name)
|
||||
method_code_blocks.append(_MakeMethodCode(m))
|
||||
method_infos[m.name] = m
|
||||
|
||||
# Build the constants.
|
||||
constants = {}
|
||||
for c in interface.constants:
|
||||
constants[c.name] = c.value
|
||||
# Build the methods - We only build function objects here
|
||||
# - they are bound to each instance at instance creation.
|
||||
methods = {}
|
||||
if len(method_code_blocks)!=0:
|
||||
method_code = "\n".join(method_code_blocks)
|
||||
## print "Method Code:"
|
||||
## print method_code
|
||||
codeObject = compile(method_code, "<XPCOMObject method>","exec")
|
||||
# Exec the code object
|
||||
tempNameSpace = {}
|
||||
exec codeObject in globals(), tempNameSpace # self.__dict__, self.__dict__
|
||||
for name in method_names:
|
||||
methods[name] = tempNameSpace[name]
|
||||
ret = methods, getters, setters, constants
|
||||
ret = method_infos, getters, setters, constants
|
||||
interface_cache[iid] = ret
|
||||
return ret
|
||||
|
||||
def Component(ob, iid):
|
||||
ob_name = None
|
||||
if not hasattr(ob, "IID"):
|
||||
ob_name = ob
|
||||
cm = _xpcom.NS_GetGlobalComponentManager()
|
||||
ob = cm.CreateInstanceByContractID(ob)
|
||||
return Interface(ob, iid)
|
||||
|
||||
class Interface:
|
||||
"""Implements a dynamic interface using xpcom reflection.
|
||||
"""
|
||||
def __init__(self, ob, iid, object_name = None):
|
||||
ob = ob.QueryInterface(iid, 0) # zero means "no auto-wrap"
|
||||
self.__dict__['_comobj_'] = ob
|
||||
# Hack - the last interface only!
|
||||
methods, getters, setters, constants = BuildInterfaceInfo(iid)
|
||||
self.__dict__['_interface_infos_'] = getters, setters
|
||||
self.__dict__['_interface_methods_'] = methods # Unbound methods.
|
||||
|
||||
self.__dict__.update(constants)
|
||||
# We remember the constant names to prevent the user trying to assign to them!
|
||||
self.__dict__['_constant_names_'] = constants.keys()
|
||||
|
||||
if object_name is None:
|
||||
object_name = "object with interface '%s'" % (iid.name,)
|
||||
self.__dict__['_object_name_'] = object_name
|
||||
|
||||
class _XPCOMBase:
|
||||
def __cmp__(self, other):
|
||||
try:
|
||||
other = other._comobj_
|
||||
|
@ -152,19 +145,19 @@ class Interface:
|
|||
return hash(self._comobj_)
|
||||
|
||||
def __repr__(self):
|
||||
return "<XPCOM interface '%s'>" % (self._comobj_.IID.name,)
|
||||
return "<XPCOM object '%s'>" % (self._object_name_,)
|
||||
|
||||
# See if the object support strings.
|
||||
def __str__(self):
|
||||
try:
|
||||
self._comobj_.QueryInterface(_xpcom.IID_nsISupportsString)
|
||||
self._comobj_.QueryInterface(IID_nsISupportsString, 0)
|
||||
return str(self._comobj_)
|
||||
except COMException:
|
||||
return self.__repr__()
|
||||
|
||||
# Try the numeric support.
|
||||
def _do_conversion(self, interface_names, cvt):
|
||||
iim = _xpcom.XPTI_GetInterfaceInfoManager()
|
||||
iim = XPTI_GetInterfaceInfoManager()
|
||||
for interface_name in interface_names:
|
||||
iid = iim.GetInfoForName(interface_name).GetIID()
|
||||
try:
|
||||
|
@ -182,6 +175,139 @@ class Interface:
|
|||
|
||||
def __float__(self):
|
||||
return self._do_conversion(_float_interfaces, float)
|
||||
|
||||
class Component(_XPCOMBase):
|
||||
def __init__(self, ob, iid):
|
||||
assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one"
|
||||
ob_name = None
|
||||
if not hasattr(ob, "IID"):
|
||||
ob_name = ob
|
||||
cm = NS_GetGlobalComponentManager()
|
||||
ob = cm.CreateInstanceByContractID(ob)
|
||||
assert not hasattr(ob, "_comobj_"), "The created object should be a raw nsIWhatever, not a wrapped one"
|
||||
# Keep a reference to the object in the component too
|
||||
self.__dict__['_comobj_'] = ob
|
||||
# hit __dict__ directly to avoid __setattr__()
|
||||
self.__dict__['_interfaces_'] = {} # keyed by IID
|
||||
self.__dict__['_interface_names_'] = {} # keyed by IID name
|
||||
self.__dict__['_interface_infos_'] = {} # keyed by IID
|
||||
self.__dict__['_name_to_interface_name_'] = {}
|
||||
self.__dict__['_tried_classinfo_'] = 0
|
||||
|
||||
if ob_name is None:
|
||||
ob_name = "<unknown>"
|
||||
self.__dict__['_object_name_'] = ob_name
|
||||
self.QueryInterface(iid)
|
||||
|
||||
def _build_all_supported_interfaces_(self):
|
||||
# Use nsIClassInfo, but don't do it at object construction to keep perf up.
|
||||
# Only pay the penalty when we really need it.
|
||||
assert not self._tried_classinfo_, "already tried to get the class info."
|
||||
self.__dict__['_tried_classinfo_'] = 1
|
||||
# See if nsIClassInfo is supported.
|
||||
try:
|
||||
classinfo = self._comobj_.QueryInterface(IID_nsIClassInfo, 0)
|
||||
except COMException:
|
||||
classinfo = None
|
||||
if classinfo is not None:
|
||||
# print "YAY - have class info!!", classinfo
|
||||
real_cid = classinfo.contractID
|
||||
if real_cid is not None:
|
||||
self.__dict__['_object_name_'] = real_cid
|
||||
for nominated_iid in classinfo.getInterfaces():
|
||||
self._remember_interface_info(nominated_iid)
|
||||
self.__dict__['_com_classinfo_'] = classinfo
|
||||
|
||||
def _remember_interface_info(self, iid):
|
||||
method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
|
||||
# Remember all the names so we can delegate
|
||||
assert not self.__dict__['_interface_infos_'].has_key(iid), "Already remembered this interface!"
|
||||
self.__dict__['_interface_infos_'][iid] = method_infos, getters, setters, constants
|
||||
interface_name = iid.name
|
||||
names = self.__dict__['_name_to_interface_name_']
|
||||
for name in method_infos.keys(): names[name] = interface_name
|
||||
for name in getters.keys(): names[name] = interface_name
|
||||
for name in setters.keys(): names[name] = interface_name
|
||||
for name in constants.keys(): names[name] = interface_name
|
||||
|
||||
def _make_interface_info(self, ob, iid):
|
||||
interface_infos = self._interface_infos_
|
||||
assert not self._interfaces_.has_key(iid), "Already have made this interface"
|
||||
method_infos, getters, setters, constants = interface_infos[iid]
|
||||
new_interface = _Interface(ob, iid, method_infos, getters, setters, constants)
|
||||
self._interfaces_[iid] = new_interface
|
||||
self._interface_names_[iid.name] = new_interface
|
||||
# No point remembering these.
|
||||
del interface_infos[iid]
|
||||
|
||||
def QueryInterface(self, iid):
|
||||
if self._interfaces_.has_key(iid):
|
||||
assert self._interface_names_.has_key(iid.name), "_interfaces_ has the key, but _interface_names_ does not!"
|
||||
return self
|
||||
# Haven't seen this before - do a real QI.
|
||||
if not self._interface_infos_.has_key(iid):
|
||||
self._remember_interface_info(iid)
|
||||
ret = self._comobj_.QueryInterface(iid, 0)
|
||||
# print "Component QI for", iid, "yielded", ret
|
||||
self._make_interface_info(ret, iid)
|
||||
assert self._interfaces_.has_key(iid) and self._interface_names_.has_key(iid.name), "Making the interface didn't update the maps"
|
||||
return self
|
||||
|
||||
queryInterface = QueryInterface # Alternate name.
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# First allow the interface name to return the "raw" interface
|
||||
interface = self.__dict__['_interface_names_'].get(attr, None)
|
||||
if interface is not None:
|
||||
return interface
|
||||
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
|
||||
# This may be first time trying this interface - get the nsIClassInfo
|
||||
if interface_name is None and not self._tried_classinfo_:
|
||||
self._build_all_supported_interfaces_()
|
||||
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
|
||||
|
||||
if interface_name is not None:
|
||||
interface = self.__dict__['_interface_names_'].get(interface_name, None)
|
||||
if interface is None:
|
||||
iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID()
|
||||
self.QueryInterface(iid)
|
||||
interface = self.__dict__['_interface_names_'][interface_name]
|
||||
return getattr(interface, attr)
|
||||
# Some interfaces may provide this name via "native" support.
|
||||
# Loop over all interfaces, and if found, cache it for next time.
|
||||
for interface in self.__dict__['_interfaces_'].values():
|
||||
try:
|
||||
ret = getattr(interface, attr)
|
||||
self.__dict__['_name_to_interface_name_'][attr] = interface._iid_.name
|
||||
return ret
|
||||
except AttributeError:
|
||||
pass
|
||||
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
interface_name = self._name_to_interface_name_.get(attr, None)
|
||||
# This may be first time trying this interface - get the nsIClassInfo
|
||||
if interface_name is None and not self._tried_classinfo_:
|
||||
self._build_all_supported_interfaces_()
|
||||
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
|
||||
if interface_name is not None:
|
||||
interface = self._interface_names_[interface_name]
|
||||
setattr(interface, attr, val)
|
||||
return
|
||||
raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)
|
||||
|
||||
class _Interface(_XPCOMBase):
|
||||
def __init__(self, comobj, iid, method_infos, getters, setters, constants):
|
||||
self.__dict__['_comobj_'] = comobj
|
||||
self.__dict__['_iid_'] = iid
|
||||
self.__dict__['_property_getters_'] = getters
|
||||
self.__dict__['_property_setters_'] = setters
|
||||
self.__dict__['_method_infos_'] = method_infos # method infos waiting to be turned into real methods.
|
||||
self.__dict__['_methods_'] = {} # unbound methods
|
||||
self.__dict__['_object_name_'] = iid.name
|
||||
self.__dict__.update(constants)
|
||||
# We remember the constant names to prevent the user trying to assign to them!
|
||||
self.__dict__['_constant_names_'] = constants.keys()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# Allow the underlying interface to provide a better implementation if desired.
|
||||
|
@ -189,19 +315,29 @@ class Interface:
|
|||
if ret is not None:
|
||||
return ret
|
||||
# Do the function thing first.
|
||||
unbound_method = self.__dict__['_interface_methods_'].get(attr)
|
||||
unbound_method = self.__dict__['_methods_'].get(attr, None)
|
||||
if unbound_method is not None:
|
||||
return new.instancemethod(unbound_method, self, self.__class__)
|
||||
|
||||
getters, setters = self.__dict__['_interface_infos_']
|
||||
getters = self.__dict__['_property_getters_']
|
||||
info = getters.get(attr)
|
||||
if info is None:
|
||||
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
|
||||
method_index, param_infos = info
|
||||
if len(param_infos)!=1: # Only expecting a retval
|
||||
raise RuntimeError, "Can't get properties with this many args!"
|
||||
args = ( param_infos, () )
|
||||
return XPTC_InvokeByIndex(self._comobj_, method_index, args)
|
||||
if info is not None:
|
||||
method_index, param_infos = info
|
||||
if len(param_infos)!=1: # Only expecting a retval
|
||||
raise RuntimeError, "Can't get properties with this many args!"
|
||||
args = ( param_infos, () )
|
||||
return XPTC_InvokeByIndex(self, method_index, args)
|
||||
|
||||
# See if we have a method info waiting to be turned into a method.
|
||||
# Do this last as it is a one-off hit.
|
||||
method_info = self.__dict__['_method_infos_'].get(attr, None)
|
||||
if method_info is not None:
|
||||
unbound_method = BuildMethod(method_info, self._iid_)
|
||||
# Cache it locally
|
||||
self.__dict__['_methods_'][attr] = unbound_method
|
||||
return new.instancemethod(unbound_method, self, self.__class__)
|
||||
|
||||
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
# If we already have a __dict__ item of that name, and its not one of
|
||||
|
@ -210,7 +346,7 @@ class Interface:
|
|||
self.__dict__[attr] = val
|
||||
return
|
||||
# Start sniffing for what sort of attribute this might be?
|
||||
getters, setters = self.__dict__['_interface_infos_']
|
||||
setters = self.__dict__['_property_setters_']
|
||||
info = setters.get(attr)
|
||||
if info is None:
|
||||
raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)
|
||||
|
@ -218,12 +354,13 @@ class Interface:
|
|||
if len(param_infos)!=1: # Only expecting a single input val
|
||||
raise RuntimeError, "Can't set properties with this many args!"
|
||||
real_param_infos = ( param_infos, (val,) )
|
||||
return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos)
|
||||
return XPTC_InvokeByIndex(self, method_index, real_param_infos)
|
||||
|
||||
|
||||
# Called by the _xpcom C++ framework to wrap interfaces up just
|
||||
# before they are returned.
|
||||
def MakeInterfaceResult(ob, iid):
|
||||
return Interface(ob, iid)
|
||||
return Component(ob, iid)
|
||||
|
||||
class WeakReference:
|
||||
"""A weak-reference object. You construct a weak reference by passing
|
||||
|
@ -233,7 +370,7 @@ class WeakReference:
|
|||
Once you have a weak-reference, you can "call" the object to get
|
||||
back a strong reference. Eg:
|
||||
|
||||
>>> some_ob = components.classes['...]
|
||||
>>> some_ob = components.classes['...']
|
||||
>>> weak_ref = WeakReference(some_ob)
|
||||
>>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point
|
||||
>>> # EXCEPT: new_ob may be None of some_ob has already died - a
|
||||
|
@ -243,18 +380,18 @@ class WeakReference:
|
|||
or else you defeat the purpose of the weak-reference.
|
||||
"""
|
||||
def __init__(self, ob, iid = None):
|
||||
swr = Interface(ob, _xpcom.IID_nsISupportsWeakReference)
|
||||
self._comobj_ = Interface(swr.GetWeakReference(), _xpcom.IID_nsIWeakReference)
|
||||
swr = Component(ob._comobj_, IID_nsISupportsWeakReference)
|
||||
self._comobj_ = Component(swr.GetWeakReference()._comobj_, IID_nsIWeakReference)
|
||||
if iid is None:
|
||||
try:
|
||||
iid = ob.IID
|
||||
except AttributeError:
|
||||
iid = _xpcom.IID_nsISupports
|
||||
iid = IID_nsISupports
|
||||
self._iid_ = iid
|
||||
def __call__(self, iid = None):
|
||||
if iid is None: iid = self._iid_
|
||||
try:
|
||||
return Interface(self._comobj_.QueryReferent(iid), iid)
|
||||
return Component(self._comobj_.QueryReferent(iid)._comobj_, iid)
|
||||
except COMException, details:
|
||||
if details.errno != nsError.NS_ERROR_NULL_POINTER:
|
||||
raise
|
||||
|
|
|
@ -32,7 +32,7 @@ def _get_good_iid(iid):
|
|||
return iid
|
||||
|
||||
# The "manager" object.
|
||||
manager = xpcom.client.Interface(_xpcom.NS_GetGlobalComponentManager(), _xpcom.IID_nsIComponentManager)
|
||||
manager = xpcom.client.Component(_xpcom.NS_GetGlobalComponentManager(), _xpcom.IID_nsIComponentManager)
|
||||
|
||||
# The "interfaceInfoManager" object - JS doesnt have this.
|
||||
interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager()
|
||||
|
@ -190,6 +190,7 @@ class _ShutdownObserver:
|
|||
global interfaceInfoManager
|
||||
global _shutdownObserver
|
||||
manager = interfaceInfoManager = _shutdownObserver = None
|
||||
xpcom.client._shutdown()
|
||||
|
||||
svc = _xpcom.GetGlobalServiceManager().GetService("@mozilla.org/observer-service;1", interfaces.nsIObserverService)
|
||||
# Observers will be QI'd for a weak-reference, so we must keep the
|
||||
|
|
|
@ -74,7 +74,7 @@ and implements the <i>nsISample</i> interface.</p>
|
|||
<p>Thus, a complete Python program that uses this component is shown below.</p>
|
||||
<pre>from xpcom import components
|
||||
cls = components.classes["@mozilla.org/sample;1"]
|
||||
ob = cls.createInstance(components.interfaces.nsISample)
|
||||
ob = cls.createInstance() # no need to specify an IID for most components
|
||||
# nsISample defines a "value" property - let's use it!
|
||||
ob.value = "new value"
|
||||
if ob.value != "new value":
|
||||
|
@ -233,6 +233,20 @@ any given XPCOM method, there is only one possible type for a given parameter.</
|
|||
these parameters; in contrast, JavaScript requires these redundant parameters.</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Interface Flattening</h2>
|
||||
<p>Most people can ignore this information - Python XPCOM objects just
|
||||
work. However, if you are familiar with xpcom from C++ and the concept of <i>QueryInterface</i>,
|
||||
you may like to read this.</p>
|
||||
<p>Most components support the concept of "interface
|
||||
flattening". Such objects can report the interfaces they support,
|
||||
allowing languages such as Python and Javascript avoid using <i>QueryInterface</i>.
|
||||
When you are using an XPCOM object from Python, you can just call methods and
|
||||
reference properties without regard for the interface that implements it.</p>
|
||||
<p>When multiple interfaces share the same method or property name, you can use
|
||||
the name of the interface as a differentiator. Thus, <i>ob.nsIFoo.close()</i>
|
||||
will call close on <i>ob</i>'s <i>nsIFoo</i> interface, while <i>ob.nsIBar.close()</i>
|
||||
will use the <i>nsIBar</i> interface. <i>ob.close()</i> is not defined.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -117,6 +117,7 @@ XPCOM_SRC_OBJECTS = \
|
|||
src/PyGStub.o \
|
||||
src/PyGInputStream.o \
|
||||
src/PyGWeakReference.o \
|
||||
src/PyIClassInfo.o \
|
||||
src/PyIComponentManager.o \
|
||||
src/PyIInputStream.o \
|
||||
src/PyIEnumerator.o \
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<h1>Python XPCOM Package</h1>
|
||||
|
||||
<p>Mozilla CVS Version - Last updated April 2001</p>
|
||||
<p>Mozilla CVS Version - Last updated May 2001</p>
|
||||
<p>This is the readme for the Python interface to <b>XPCOM</b>.</p>
|
||||
<p><b>XPCOM </b>is an acronym for "Cross Platform COM". It has
|
||||
come out of the <a href="http://www.mozilla.org">Mozilla</a> project, which
|
||||
|
@ -37,7 +37,7 @@ is, then none of this probably interests you at all!</p>
|
|||
</ul>
|
||||
<p>Note: <b>This package requires Python 1.6 or later</b>; we recommend using
|
||||
the latest
|
||||
official Python version (currently 2.0). This package works
|
||||
official Python version (currently 2.1). This package works
|
||||
very well with the latest <a href="http://www.ActiveState.com/Products/ActivePython">ActivePython</a>,
|
||||
and does not require any external modules or packages beyond what is provided in
|
||||
the core Python release for each platform.</p>
|
||||
|
@ -86,6 +86,11 @@ documented here just in case!</li>
|
|||
<li>Changes to allow building with stand-alone XPCOM.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Version 0.92 - May 2001</h3>
|
||||
<p>Implement interface flattening. You should (almost) never need to use <i>QueryInterface()</i>!
|
||||
We are still 100% backwards compatible, so usage of QI still works - just is
|
||||
generally not necessary.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -29,7 +29,7 @@ from xpcom import _xpcom
|
|||
tracer = None
|
||||
|
||||
# Wrap an instance in an interface (via a policy)
|
||||
def WrapObject(ob, iid, policy = None):
|
||||
def WrapObject(ob, iid, policy = None, bWrapClient = 1):
|
||||
"""Called by the framework to attempt to wrap
|
||||
an object in a policy.
|
||||
If iid is None, it will use the first interface the object indicates it supports.
|
||||
|
@ -38,7 +38,7 @@ def WrapObject(ob, iid, policy = None):
|
|||
policy = DefaultPolicy
|
||||
if tracer is not None:
|
||||
ob = tracer(ob)
|
||||
return _xpcom.WrapObject(policy( ob, iid ), iid)
|
||||
return _xpcom.WrapObject(policy( ob, iid ), iid, bWrapClient)
|
||||
|
||||
# Create the main module for the Python loader.
|
||||
# This is a once only init process, and the returned object
|
||||
|
|
|
@ -20,33 +20,67 @@ import xpcom
|
|||
import traceback
|
||||
import xpcom.server
|
||||
import operator
|
||||
import types
|
||||
|
||||
IID_nsISupports = _xpcom.IID_nsISupports
|
||||
XPT_MD_IS_GETTER = xpcom_consts.XPT_MD_IS_GETTER
|
||||
XPT_MD_IS_SETTER = xpcom_consts.XPT_MD_IS_SETTER
|
||||
|
||||
_supports_primitives_map_ = {} # Filled on first use.
|
||||
|
||||
_interface_sequence_types_ = types.TupleType, types.ListType
|
||||
_string_types_ = types.StringType, types.UnicodeType
|
||||
XPTI_GetInterfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager
|
||||
|
||||
def _GetNominatedInterfaces(obj):
|
||||
ret = getattr(obj, "_com_interfaces_", None)
|
||||
if ret is None: return None
|
||||
# See if the user only gave one.
|
||||
try:
|
||||
ret[0]
|
||||
except TypeError:
|
||||
if type(ret) not in _interface_sequence_types_:
|
||||
ret = [ret]
|
||||
real_ret = []
|
||||
# For each interface, walk to the root of the interface tree.
|
||||
iim = _xpcom.XPTI_GetInterfaceInfoManager()
|
||||
iim = XPTI_GetInterfaceInfoManager()
|
||||
for interface in ret:
|
||||
try:
|
||||
# Allow interface name or IID.
|
||||
interface_info = None
|
||||
if type(interface) in _string_types_:
|
||||
try:
|
||||
interface_info = iim.GetInfoForName(interface)
|
||||
except COMException:
|
||||
pass
|
||||
if interface_info is None:
|
||||
# Allow a real IID
|
||||
interface_info = iim.GetInfoForIID(interface)
|
||||
except COMException:
|
||||
# Allow an interface name.
|
||||
interface_info = iim.GetInfoForName(interface)
|
||||
real_ret.append(interface_info.GetIID())
|
||||
parent = interface_info.GetParent()
|
||||
while parent is not None:
|
||||
real_ret.append(parent.GetIID())
|
||||
parent_iid = parent.GetIID()
|
||||
if parent_iid == IID_nsISupports:
|
||||
break
|
||||
real_ret.append(parent_iid)
|
||||
parent = parent.GetParent()
|
||||
return real_ret
|
||||
|
||||
class DefaultClassInfo:
|
||||
_com_interfaces_ = _xpcom.IID_nsIClassInfo
|
||||
def __init__(self, klass):
|
||||
self.klass = klass
|
||||
self.contractID = getattr(klass, "_reg_contractid_", None)
|
||||
self.classDescription = getattr(klass, "_reg_desc_", None)
|
||||
self.classID = getattr(klass, "_reg_clsid_", None)
|
||||
self.implementationLanguage = 3 # Python - avoid lookups just for this
|
||||
self.flags = 0 # what to do here??
|
||||
self.interfaces = None
|
||||
|
||||
def getInterfaces(self):
|
||||
if self.interfaces is None:
|
||||
self.interfaces = _GetNominatedInterfaces(self.klass)
|
||||
return self.interfaces
|
||||
|
||||
def getHelperForLanguage(self, language):
|
||||
return None # Not sure what to do here.
|
||||
|
||||
class DefaultPolicy:
|
||||
def __init__(self, instance, iid):
|
||||
self._obj_ = instance
|
||||
|
@ -54,16 +88,15 @@ class DefaultPolicy:
|
|||
self._iid_ = iid
|
||||
if ni is None:
|
||||
raise ValueError, "The object '%r' can not be used as a COM object" % (instance,)
|
||||
if iid not in ni:
|
||||
# The object may delegate QI.
|
||||
try:
|
||||
delegate_qi = instance._query_interface_
|
||||
except AttributeError:
|
||||
delegate_qi = None
|
||||
# Perform the actual QI and throw away the result - the _real_
|
||||
# QI performed by the framework will set things right!
|
||||
if delegate_qi is None or not delegate_qi(iid):
|
||||
raise ServerException(nsError.NS_ERROR_NO_INTERFACE)
|
||||
# This is really only a check for the user
|
||||
if __debug__:
|
||||
if iid != IID_nsISupports and iid not in ni:
|
||||
# The object may delegate QI.
|
||||
delegate_qi = getattr(instance, "_query_interface_", None)
|
||||
# Perform the actual QI and throw away the result - the _real_
|
||||
# QI performed by the framework will set things right!
|
||||
if delegate_qi is None or not delegate_qi(iid):
|
||||
raise ServerException(nsError.NS_ERROR_NO_INTERFACE)
|
||||
# Stuff for the magic interface conversion.
|
||||
self._interface_info_ = None
|
||||
self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index)
|
||||
|
@ -80,7 +113,11 @@ class DefaultPolicy:
|
|||
# NOTE: We could have simply returned the instance and let the framework
|
||||
# do the auto-wrap for us - but this way we prevent a round-trip back into Python
|
||||
# code just for the autowrap.
|
||||
return xpcom.server.WrapObject(self._obj_, iid)
|
||||
return xpcom.server.WrapObject(self._obj_, iid, bWrapClient = 0)
|
||||
|
||||
# Always support nsIClassInfo
|
||||
if iid == _xpcom.IID_nsIClassInfo:
|
||||
return xpcom.server.WrapObject(DefaultClassInfo(self._obj_.__class__), iid, bWrapClient = 0)
|
||||
|
||||
# See if the instance has a QI
|
||||
# use lower-case "_query_interface_" as win32com does, and it doesnt really matter.
|
||||
|
@ -100,7 +137,7 @@ class DefaultPolicy:
|
|||
_supports_primitives_map_[special_iid] = (attr, cvt)
|
||||
attr, cvt = _supports_primitives_map_.get(iid, (None,None))
|
||||
if attr is not None and hasattr(self._obj_, attr):
|
||||
return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid)
|
||||
return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid, bWrapClient = 0)
|
||||
# Out of clever things to try!
|
||||
return None # We dont support this IID.
|
||||
|
||||
|
@ -117,13 +154,13 @@ class DefaultPolicy:
|
|||
iid = self._interface_info_.GetIIDForParam(method_index, param_index)
|
||||
self._interface_iid_map_[(method_index, param_index)] = iid
|
||||
# iid = _xpcom.IID_nsISupports
|
||||
return client.Interface(interface, iid)
|
||||
return client.Component(interface, iid)
|
||||
|
||||
def _CallMethod_(self, com_object, index, info, params):
|
||||
# print "_CallMethod_", index, info, params
|
||||
flags, name, param_descs, ret = info
|
||||
assert ret[1][0] == xpcom_consts.TD_UINT32, "Expected an nsresult (%s)" % (ret,)
|
||||
if xpcom_consts.XPT_MD_IS_GETTER(flags):
|
||||
if XPT_MD_IS_GETTER(flags):
|
||||
# Look for a function of that name
|
||||
func = getattr(self._obj_, "get_" + name, None)
|
||||
if func is None:
|
||||
|
@ -132,7 +169,7 @@ class DefaultPolicy:
|
|||
else:
|
||||
ret = func(*params)
|
||||
return 0, ret
|
||||
elif xpcom_consts.XPT_MD_IS_SETTER(flags):
|
||||
elif XPT_MD_IS_SETTER(flags):
|
||||
# Look for a function of that name
|
||||
func = getattr(self._obj_, "set_" + name, None)
|
||||
if func is None:
|
||||
|
|
|
@ -171,7 +171,7 @@ PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **p
|
|||
|
||||
obIID = Py_nsIID::PyObjectFromIID(iid);
|
||||
if (obIID==NULL) goto done;
|
||||
args = Py_BuildValue("OO", ob, obIID);
|
||||
args = Py_BuildValue("OOzi", ob, obIID, NULL, 0);
|
||||
if (args==NULL) goto done;
|
||||
wrap_ret = PyEval_CallObject(func, args);
|
||||
if (wrap_ret==NULL) goto done;
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
* the specific language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Python XPCOM language bindings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is ActiveState Tool Corp.
|
||||
* Portions created by ActiveState Tool Corp. are Copyright (C) 2001
|
||||
* ActiveState Tool Corp. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Mark Hammond <MarkH@ActiveState.com> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// This code is part of the XPCOM extensions for Python.
|
||||
//
|
||||
// Written May 2001 by Mark Hammond.
|
||||
//
|
||||
// Based heavily on the Python COM support, which is
|
||||
// (c) Mark Hammond and Greg Stein.
|
||||
//
|
||||
// (c) 2001, ActiveState corp.
|
||||
|
||||
#include "PyXPCOM_std.h"
|
||||
#include "nsIClassInfo.h"
|
||||
|
||||
static nsIClassInfo *_GetI(PyObject *self) {
|
||||
nsIID iid = NS_GET_IID(nsIClassInfo);
|
||||
|
||||
if (!Py_nsISupports::Check(self, iid)) {
|
||||
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
|
||||
return NULL;
|
||||
}
|
||||
return (nsIClassInfo *)Py_nsISupports::GetI(self);
|
||||
}
|
||||
|
||||
static PyObject *PyGetInterfaces(PyObject *self, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
nsIClassInfo *pI = _GetI(self);
|
||||
if (pI==NULL)
|
||||
return NULL;
|
||||
|
||||
nsIID** iidArray = nsnull;
|
||||
PRUint32 iidCount = 0;
|
||||
nsresult r;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
r = pI->GetInterfaces(&iidCount, &iidArray);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if ( NS_FAILED(r) )
|
||||
return PyXPCOM_BuildPyException(r);
|
||||
|
||||
PyObject *ret = PyTuple_New(iidCount);
|
||||
if (ret==NULL)
|
||||
return NULL;
|
||||
for (PRUint32 i=0;i<iidCount;i++)
|
||||
PyTuple_SET_ITEM( ret, i, Py_nsIID::PyObjectFromIID(*(iidArray[i])) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *PyGetHelperForLanguage(PyObject *self, PyObject *args)
|
||||
{
|
||||
PRUint32 language = nsIProgrammingLanguage::PYTHON;
|
||||
if (!PyArg_ParseTuple(args, "|i", &language))
|
||||
return NULL;
|
||||
nsIClassInfo *pI = _GetI(self);
|
||||
if (pI==NULL)
|
||||
return NULL;
|
||||
|
||||
nsresult r;
|
||||
nsISupports *pi;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
r = pI->GetHelperForLanguage(language, &pi);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if ( NS_FAILED(r) )
|
||||
return PyXPCOM_BuildPyException(r);
|
||||
|
||||
return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports), PR_FALSE);
|
||||
}
|
||||
|
||||
static PyObject *MakeStringOrNone(char *v)
|
||||
{
|
||||
if (v)
|
||||
return PyString_FromString(v);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
#define GETATTR_CHECK_RESULT(nr) if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr)
|
||||
|
||||
PyObject *
|
||||
Py_nsIClassInfo::getattr(const char *name)
|
||||
{
|
||||
nsIClassInfo *pI = _GetI(this);
|
||||
if (pI==NULL)
|
||||
return NULL;
|
||||
|
||||
nsresult nr;
|
||||
PyObject *ret = NULL;
|
||||
if (strcmp(name, "contractID")==0) {
|
||||
char *str_ret;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
nr = pI->GetContractID(&str_ret);
|
||||
Py_END_ALLOW_THREADS;
|
||||
GETATTR_CHECK_RESULT(nr);
|
||||
ret = MakeStringOrNone(str_ret);
|
||||
nsAllocator::Free(str_ret);
|
||||
} else if (strcmp(name, "classDescription")==0) {
|
||||
char *str_ret;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
nr = pI->GetClassDescription(&str_ret);
|
||||
Py_END_ALLOW_THREADS;
|
||||
GETATTR_CHECK_RESULT(nr);
|
||||
ret = MakeStringOrNone(str_ret);
|
||||
nsAllocator::Free(str_ret);
|
||||
} else if (strcmp(name, "classID")==0) {
|
||||
nsIID *iid;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
nr = pI->GetClassID(&iid);
|
||||
Py_END_ALLOW_THREADS;
|
||||
GETATTR_CHECK_RESULT(nr);
|
||||
ret = Py_nsIID::PyObjectFromIID(*iid);
|
||||
nsAllocator::Free(iid);
|
||||
} else if (strcmp(name, "implementationLanguage")==0) {
|
||||
PRUint32 i;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
nr = pI->GetImplementationLanguage(&i);
|
||||
Py_END_ALLOW_THREADS;
|
||||
GETATTR_CHECK_RESULT(nr);
|
||||
ret = PyInt_FromLong(i);
|
||||
} else {
|
||||
ret = Py_nsISupports::getattr(name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
Py_nsIClassInfo::setattr(const char *name, PyObject *v)
|
||||
{
|
||||
return Py_nsISupports::setattr(name, v);
|
||||
|
||||
}
|
||||
|
||||
struct PyMethodDef
|
||||
PyMethods_IClassInfo[] =
|
||||
{
|
||||
{ "getInterfaces", PyGetInterfaces, 1},
|
||||
{ "GetInterfaces", PyGetInterfaces, 1},
|
||||
{ "getHelperForLanguage", PyGetHelperForLanguage, 1},
|
||||
{ "GetHelperForLanguage", PyGetHelperForLanguage, 1},
|
||||
{NULL}
|
||||
};
|
|
@ -70,7 +70,7 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
|
|||
return PyXPCOM_BuildPyException(r);
|
||||
|
||||
/* Return a type based on the IID (with no extra ref) */
|
||||
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
|
||||
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args)
|
||||
|
|
|
@ -117,7 +117,7 @@ static PyObject *PyGetParent(PyObject *self, PyObject *args)
|
|||
Py_END_ALLOW_THREADS;
|
||||
if ( NS_FAILED(r) )
|
||||
return PyXPCOM_BuildPyException(r);
|
||||
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
|
||||
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
static PyObject *PyGetMethodCount(PyObject *self, PyObject *args)
|
||||
|
|
|
@ -93,6 +93,25 @@ Py_nsISupports::SafeRelease(Py_nsISupports *ob)
|
|||
}
|
||||
}
|
||||
|
||||
/* virtual */ PyObject *
|
||||
Py_nsISupports::getattr(const char *name)
|
||||
{
|
||||
if (strcmp(name, "IID")==0)
|
||||
return Py_nsIID::PyObjectFromIID( m_iid );
|
||||
|
||||
PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type;
|
||||
return Py_FindMethodInChain(&this_type->chain, this, (char *)name);
|
||||
}
|
||||
|
||||
/* virtual */ int
|
||||
Py_nsISupports::setattr(const char *name, PyObject *v)
|
||||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "%s has read-only attributes", ob_type->tp_name );
|
||||
PyErr_SetString(PyExc_TypeError, buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*static*/ Py_nsISupports *
|
||||
Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid)
|
||||
{
|
||||
|
@ -287,7 +306,7 @@ Py_nsISupports::MakeInterfaceResult(PyObject *pyis,
|
|||
done:
|
||||
if (PyErr_Occurred()) {
|
||||
NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
|
||||
PyXPCOM_LogError("Creating an interface object to be used as a parameter failed\n");
|
||||
PyXPCOM_LogError("Creating an interface object to be used as a result failed\n");
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_XDECREF(mod);
|
||||
|
|
|
@ -206,7 +206,9 @@ public:
|
|||
static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
|
||||
static void InitType();
|
||||
|
||||
~Py_nsISupports();
|
||||
virtual ~Py_nsISupports();
|
||||
virtual PyObject *getattr(const char *name);
|
||||
virtual int setattr(const char *name, PyObject *val);
|
||||
protected:
|
||||
// ctor is protected - must create objects via
|
||||
// PyObjectFromInterface()
|
||||
|
@ -398,7 +400,7 @@ protected:
|
|||
private:
|
||||
};
|
||||
|
||||
// For the Gateways me manually implement.
|
||||
// For the Gateways we manually implement.
|
||||
#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
|
||||
{return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
|
||||
|
@ -570,4 +572,91 @@ private:
|
|||
PRBool created;
|
||||
};
|
||||
|
||||
// Our classes.
|
||||
// Hrm - So we can't have templates, eh??
|
||||
// preprocessor to the rescue, I guess.
|
||||
#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \
|
||||
\
|
||||
extern struct PyMethodDef Methods[]; \
|
||||
\
|
||||
class ClassName : public Py_nsISupports \
|
||||
{ \
|
||||
public: \
|
||||
static PyXPCOM_TypeObject *type; \
|
||||
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
|
||||
return new ClassName(pInitObj, iid); \
|
||||
} \
|
||||
static void InitType(PyObject *iidNameDict) { \
|
||||
type = new PyXPCOM_TypeObject( \
|
||||
#InterfaceName, \
|
||||
Py_nsISupports::type, \
|
||||
sizeof(ClassName), \
|
||||
Methods, \
|
||||
Constructor); \
|
||||
const nsIID &iid = NS_GET_IID(InterfaceName); \
|
||||
RegisterInterface(iid, type); \
|
||||
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
|
||||
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
|
||||
Py_DECREF(iid_ob); \
|
||||
} \
|
||||
protected: \
|
||||
ClassName(nsISupports *p, const nsIID &iid) : \
|
||||
Py_nsISupports(p, iid, type) { \
|
||||
/* The IID _must_ be the IID of the interface we are wrapping! */ \
|
||||
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
// End of PyXPCOM_INTERFACE_DECLARE macro
|
||||
|
||||
#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\
|
||||
\
|
||||
extern struct PyMethodDef Methods[]; \
|
||||
\
|
||||
class ClassName : public Py_nsISupports \
|
||||
{ \
|
||||
public: \
|
||||
static PyXPCOM_TypeObject *type; \
|
||||
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
|
||||
return new ClassName(pInitObj, iid); \
|
||||
} \
|
||||
static void InitType(PyObject *iidNameDict) { \
|
||||
type = new PyXPCOM_TypeObject( \
|
||||
#InterfaceName, \
|
||||
Py_nsISupports::type, \
|
||||
sizeof(ClassName), \
|
||||
Methods, \
|
||||
Constructor); \
|
||||
const nsIID &iid = NS_GET_IID(InterfaceName); \
|
||||
RegisterInterface(iid, type); \
|
||||
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
|
||||
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
|
||||
Py_DECREF(iid_ob); \
|
||||
} \
|
||||
virtual PyObject *getattr(const char *name); \
|
||||
virtual int setattr(const char *name, PyObject *val); \
|
||||
protected: \
|
||||
ClassName(nsISupports *p, const nsIID &iid) : \
|
||||
Py_nsISupports(p, iid, type) { \
|
||||
/* The IID _must_ be the IID of the interface we are wrapping! */ \
|
||||
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro
|
||||
|
||||
#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
|
||||
PyXPCOM_TypeObject *ClassName::type = NULL;
|
||||
|
||||
|
||||
// And the classes
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
|
||||
PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
|
||||
PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
|
||||
|
||||
#endif // __PYXPCOM_H__
|
||||
|
|
|
@ -34,12 +34,19 @@
|
|||
// Main Mozilla cross-platform declarations.
|
||||
#include "xp_core.h"
|
||||
|
||||
#include <nsIAllocator.h>
|
||||
#include <nsIWeakReference.h>
|
||||
#include <nsXPIDLString.h>
|
||||
#include <nsCRT.h>
|
||||
#include <xptcall.h>
|
||||
#include <xpt_xdr.h>
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIInterfaceInfoManager.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsCRT.h"
|
||||
#include "xptcall.h"
|
||||
#include "xpt_xdr.h"
|
||||
|
||||
// This header is considered internal - hence
|
||||
// we can use it to trigger "exports"
|
||||
|
|
|
@ -70,20 +70,13 @@ PyXPCOM_TypeObject::IsType(PyTypeObject *t)
|
|||
/*static*/PyObject *
|
||||
PyXPCOM_TypeObject::Py_getattr(PyObject *self, char *name)
|
||||
{
|
||||
if (strcmp(name, "IID")==0)
|
||||
return Py_nsIID::PyObjectFromIID( ((Py_nsISupports *)self)->m_iid );
|
||||
|
||||
PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)self->ob_type;
|
||||
return Py_FindMethodInChain(&this_type->chain, self, name);
|
||||
return ((Py_nsISupports *)self)->getattr(name);
|
||||
}
|
||||
|
||||
/*static*/int
|
||||
PyXPCOM_TypeObject::Py_setattr(PyObject *op, char *name, PyObject *v)
|
||||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "%s has read-only attributes", op->ob_type->tp_name );
|
||||
PyErr_SetString(PyExc_TypeError, buf);
|
||||
return -1;
|
||||
return ((Py_nsISupports *)op)->setattr(name, v);
|
||||
}
|
||||
|
||||
// @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity.
|
||||
|
|
|
@ -129,6 +129,9 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
|
|||
LogError("Python initialization failed!\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#ifndef NS_DEBUG
|
||||
Py_OptimizeFlag = 1;
|
||||
#endif
|
||||
AddStandardPaths();
|
||||
PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
|
||||
if (mod==NULL) {
|
||||
|
|
|
@ -40,6 +40,7 @@ CPP_OBJS= \
|
|||
.\$(OBJDIR)\PyGStub.obj \
|
||||
.\$(OBJDIR)\PyGInputStream.obj \
|
||||
.\$(OBJDIR)\PyGWeakReference.obj \
|
||||
.\$(OBJDIR)\PyIClassInfo.obj \
|
||||
.\$(OBJDIR)\PyIComponentManager.obj \
|
||||
.\$(OBJDIR)\PyIInputStream.obj \
|
||||
.\$(OBJDIR)\PyIEnumerator.obj \
|
||||
|
@ -64,6 +65,7 @@ CPPSRCS = \
|
|||
PyGStub.cpp \
|
||||
PyGInputStream.cpp \
|
||||
PyGWeakReference.cpp \
|
||||
PyIClassInfo.cpp \
|
||||
PyIComponentManager.cpp \
|
||||
PyIInputStream.cpp \
|
||||
PyIEnumerator.cpp \
|
||||
|
|
|
@ -28,21 +28,19 @@
|
|||
// (c) 2000, ActiveState corp.
|
||||
|
||||
#include "PyXPCOM_std.h"
|
||||
#include <nsIInterfaceInfoManager.h>
|
||||
#include <nsIFileSpec.h>
|
||||
#include <nsSpecialSystemDirectory.h>
|
||||
#include <nsIThread.h>
|
||||
#include <nsISupportsPrimitives.h>
|
||||
#include <nsIModule.h>
|
||||
#include <nsIInputStream.h>
|
||||
#include "nsIFileSpec.h"
|
||||
#include "nsSpecialSystemDirectory.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIModule.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
#include <nsIEventQueue.h>
|
||||
#include <nsIProxyObjectManager.h>
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
|
||||
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
|
||||
extern void PyXPCOM_InterpreterState_Ensure();
|
||||
|
@ -58,6 +56,15 @@ extern void PyXPCOM_InterpreterState_Ensure();
|
|||
|
||||
#endif // XP_WIN
|
||||
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// This is the main entry point called by the Python component
|
||||
// loader.
|
||||
|
@ -114,53 +121,6 @@ done:
|
|||
return nr;
|
||||
}
|
||||
|
||||
// Hrm - So we can't have templates, eh??
|
||||
// preprocessor to the rescue, I guess.
|
||||
#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \
|
||||
\
|
||||
extern struct PyMethodDef Methods[]; \
|
||||
\
|
||||
class ClassName : public Py_nsISupports \
|
||||
{ \
|
||||
public: \
|
||||
static PyXPCOM_TypeObject *type; \
|
||||
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
|
||||
return new ClassName(pInitObj, iid); \
|
||||
} \
|
||||
static void InitType(PyObject *iidNameDict) { \
|
||||
type = new PyXPCOM_TypeObject( \
|
||||
#InterfaceName, \
|
||||
Py_nsISupports::type, \
|
||||
sizeof(ClassName), \
|
||||
Methods, \
|
||||
Constructor); \
|
||||
const nsIID &iid = NS_GET_IID(InterfaceName); \
|
||||
RegisterInterface(iid, type); \
|
||||
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
|
||||
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
|
||||
Py_DECREF(iid_ob); \
|
||||
} \
|
||||
protected: \
|
||||
ClassName(nsISupports *p, const nsIID &iid) : \
|
||||
Py_nsISupports(p, iid, type) { \
|
||||
/* The IID _must_ be the IID of the interface we are wrapping! */ \
|
||||
NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
PyXPCOM_TypeObject *ClassName::type = NULL; \
|
||||
\
|
||||
// End of PyXPCOM_INTERFACE_DEFINE macro
|
||||
|
||||
// And the classes
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager)
|
||||
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
|
||||
|
||||
// "boot-strap" methods - interfaces we need to get the base
|
||||
// interface support!
|
||||
|
||||
|
@ -302,7 +262,8 @@ static PyObject *
|
|||
PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *ob, *obIID;
|
||||
if (!PyArg_ParseTuple(args, "OO", &ob, &obIID))
|
||||
int bWrapClient = 1;
|
||||
if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient))
|
||||
return NULL;
|
||||
|
||||
nsIID iid;
|
||||
|
@ -319,7 +280,7 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
|
|||
AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance.
|
||||
|
||||
// Now wrap it in an interface.
|
||||
return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE);
|
||||
return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE, bWrapClient);
|
||||
}
|
||||
|
||||
// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance
|
||||
|
@ -600,6 +561,7 @@ init_xpcom() {
|
|||
REGISTER_IID(nsIFactory);
|
||||
REGISTER_IID(nsIWeakReference);
|
||||
REGISTER_IID(nsISupportsWeakReference);
|
||||
REGISTER_IID(nsIClassInfo);
|
||||
// Register our custom interfaces.
|
||||
|
||||
Py_nsISupports::InitType();
|
||||
|
@ -610,6 +572,7 @@ init_xpcom() {
|
|||
Py_nsIInterfaceInfo::InitType(dict);
|
||||
Py_nsIServiceManager::InitType(dict);
|
||||
Py_nsIInputStream::InitType(dict);
|
||||
Py_nsIClassInfo::InitType(dict);
|
||||
|
||||
// We have special support for proxies - may as well add their constants!
|
||||
REGISTER_INT(PROXY_SYNC);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
test_misc
|
||||
Running all tests - use '-h' to see command-line options...
|
||||
The netscape sample worked!
|
||||
Dumping every interface I can find - please wait
|
||||
(verbosity is turned off, so I'm not actually going to print them)
|
||||
Finished dumping all the interfaces.
|
||||
Enumerated all the ContractIDs
|
||||
xpcom object hashing tests seemed to work
|
||||
Dumping every interface I can find - please wait
|
||||
(verbosity is turned off, so Im not actually going to print them)
|
||||
Finished dumping all the interfaces.
|
||||
The IID tests seemed to work
|
||||
The netscape sample worked!
|
||||
The netscape sample worked with interface flattening!
|
||||
|
|
|
@ -49,8 +49,8 @@ def test_interfaces():
|
|||
|
||||
def test_classes():
|
||||
# Need a well-known contractID here?
|
||||
prog_id = "@mozilla.org/filelocator;1"
|
||||
clsid = xpcom.components.ID("{78043e01-e603-11d2-915f-f08a208628fc}")
|
||||
prog_id = "@mozilla.org/supports-array;1"
|
||||
clsid = xpcom.components.ID("{bda17d50-0d6b-11d3-9331-00104ba0fd40}")
|
||||
|
||||
# Check we can create the instance (dont check we can do anything with it tho!)
|
||||
klass = xpcom.components.classes[prog_id]
|
||||
|
|
|
@ -73,7 +73,7 @@ class ImplicitSupportsFloat:
|
|||
def test():
|
||||
import xpcom.server, xpcom.client
|
||||
ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports)
|
||||
if not str(ob).startswith("<XPCOM interface"):
|
||||
if not str(ob).startswith("<XPCOM "):
|
||||
raise RuntimeError, "Wrong str() value: %s" % (ob,)
|
||||
|
||||
ob = xpcom.server.WrapObject( ImplicitSupportsString(), components.interfaces.nsISupports)
|
||||
|
|
|
@ -32,7 +32,7 @@ def DumpEveryInterfaceUnderTheSun():
|
|||
|
||||
print "Dumping every interface I can find - please wait"
|
||||
if verbose_level == 0:
|
||||
print "(verbosity is turned off, so Im not actually going to print them)"
|
||||
print "(verbosity is turned off, so I'm not actually going to print them)"
|
||||
enum = iim.EnumerateInterfaces()
|
||||
rc = enum.First()
|
||||
num = 0
|
||||
|
@ -70,19 +70,27 @@ def EnumContractIDs():
|
|||
print "Only found", n, "ContractIDs - this seems unusually low!"
|
||||
print "Enumerated all the ContractIDs"
|
||||
|
||||
def TestSampleComponent():
|
||||
def TestSampleComponent(test_flat = 0):
|
||||
"""Test the standard Netscape 'sample' sample"""
|
||||
# contractid = "mozilla.jssample.1" # the JS version
|
||||
contractid = "@mozilla.org/sample;1" # The C++ version.
|
||||
c = xpcom.components.classes[contractid].createInstance() \
|
||||
.queryInterface(xpcom.components.interfaces.nsISample)
|
||||
c = xpcom.components.classes[contractid].createInstance()
|
||||
if not test_flat:
|
||||
c = c.queryInterface(xpcom.components.interfaces.nsISample)
|
||||
assert c.value == "initial value"
|
||||
c.value = "new value"
|
||||
assert c.value == "new value"
|
||||
c.poke("poked value")
|
||||
assert c.value == "poked value"
|
||||
c.writeValue("Python just poked:")
|
||||
print "The netscape sample worked!"
|
||||
if test_flat:
|
||||
print "The netscape sample worked with interface flattening!"
|
||||
else:
|
||||
print "The netscape sample worked!"
|
||||
|
||||
def TestSampleComponentFlat():
|
||||
"""Test the standard Netscape 'sample' sample using interface flattening"""
|
||||
TestSampleComponent(1)
|
||||
|
||||
def TestHash():
|
||||
"Test that hashing COM objects works"
|
||||
|
@ -140,6 +148,8 @@ def main():
|
|||
for ob in globals().values():
|
||||
if type(ob)==type(main) and ob.__doc__:
|
||||
tests.append(ob)
|
||||
# Ensure consistent test order.
|
||||
tests.sort(lambda a,b:cmp(a.__name__, b.__name__))
|
||||
if __name__ == '__main__': # Only process args when not running under the test suite!
|
||||
opts, args = getopt.getopt(sys.argv[1:], "hv")
|
||||
for opt, val in opts:
|
||||
|
|
|
@ -264,7 +264,7 @@ def test_base_interface(c):
|
|||
test_constant(i, "BigLong", 0x7FFFFFFF)
|
||||
test_constant(i, "BigULong", 0xFFFFFFFF)
|
||||
|
||||
def test_derived_interface(c):
|
||||
def test_derived_interface(c, test_flat = 0):
|
||||
val = "Hello\0there"
|
||||
expected = val * 2
|
||||
|
||||
|
@ -329,7 +329,8 @@ def test_derived_interface(c):
|
|||
test_method(c.AppendArray, ([1,2,3],), [1,2,3])
|
||||
test_method(c.AppendArray, ([1,2,3],[4,5,6]), [1,2,3,4,5,6])
|
||||
|
||||
c = c.queryInterface(xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings)
|
||||
if not test_flat:
|
||||
c = c.queryInterface(xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings)
|
||||
# NULL DOM strings don't work yet.
|
||||
# test_method(c.GetDOMStringResult, (-1,), None)
|
||||
test_method(c.GetDOMStringResult, (3,), "PPP")
|
||||
|
@ -374,6 +375,13 @@ def test_all():
|
|||
c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterfaceExtra)
|
||||
test_base_interface(c)
|
||||
test_derived_interface(c)
|
||||
# Now create an instance and test interface flattening.
|
||||
c = xpcom.components.classes[contractid].createInstance()
|
||||
test_base_interface(c)
|
||||
test_derived_interface(c, test_flat=1)
|
||||
# This name is used in exceptions etc - make sure we got it from nsIClassInfo OK.
|
||||
assert c._object_name_ == "Python.TestComponent"
|
||||
|
||||
test_failures()
|
||||
|
||||
try:
|
||||
|
|
|
@ -40,6 +40,7 @@ Revision:
|
|||
of the new xpcom interfaces that provide this info.
|
||||
|
||||
May 2000 - Moved into Perforce - track the log there!
|
||||
Early 2001 - Moved into the Mozilla CVS tree - track the log there!
|
||||
|
||||
Todo:
|
||||
Fill out this todo list.
|
||||
|
|
Загрузка…
Ссылка в новой задаче