Add interface flattening to Python XPCOM bindings.

Not part of the build, but a=drivers@mozilla.org anyway!
This commit is contained in:
markh%activestate.com 2001-05-27 02:51:18 +00:00
Родитель 703c17b979
Коммит 6da17cde8e
24 изменённых файлов: 649 добавлений и 199 удалений

Просмотреть файл

@ -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[&quot;@mozilla.org/sample;1&quot;]
ob = cls.createInstance(components.interfaces.nsISample)
ob = cls.createInstance() # no need to specify an IID for most components
# nsISample defines a &quot;value&quot; property - let's use it!
ob.value = &quot;new value&quot;
if ob.value != &quot;new value&quot;:
@ -233,6 +233,20 @@ any given XPCOM method, there is only one possible type for a given parameter.</
these parameters;&nbsp;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.&nbsp; 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 &quot;interface
flattening&quot;.&nbsp; Such objects can report the interfaces they support,
allowing languages such as Python and Javascript avoid using <i>QueryInterface</i>.&nbsp;
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.&nbsp; 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.&nbsp; <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 &quot;Cross Platform COM&quot;.&nbsp; 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).&nbsp; This package works
official Python version (currently 2.1).&nbsp; 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.&nbsp; You should (almost) never need to use <i>QueryInterface()</i>!&nbsp;
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.