First checkin of the Python XPCOM bindings.

git-svn-id: svn://10.0.0.236/trunk@87331 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
markh%activestate.com
2001-02-19 05:24:45 +00:00
parent 0b610ca389
commit abe83923e1
70 changed files with 13648 additions and 0 deletions

View File

@@ -0,0 +1,567 @@
MOZILLA PUBLIC LICENSE
Version 1.1
---------------
1. Definitions.
1.0.1. "Commercial Use" means distribution or otherwise making the
Covered Code available to a third party.
1.1. "Contributor" means each entity that creates or contributes to
the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A -Mozilla Public License.
``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 Initial Developer of the Original Code is ________________________.
Portions created by ______________________ are Copyright (C) ______
_______________________. All Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the terms
of the _____ license (the "[___] License"), in which case the
provisions of [______] License are applicable instead of those
above. If you wish to allow use of your version of this file only
under the terms of the [____] License and not to allow others to use
your version of this file under the MPL, indicate your decision by
deleting the provisions above and replace them with the notice and
other provisions required by the [___] License. If you do not delete
the provisions above, a recipient may use your version of this file
under either the MPL or the [___] License."
[NOTE: The text of this Exhibit A may differ slightly from the text of
the notices in the Source Code files of the Original Code. You should
use the text of this Exhibit A rather than the text found in the
Original Code Source Code for Your Modifications.]
----------------------------------------------------------------------
AMENDMENTS
The Netscape Public License Version 1.1 ("NPL") consists of the
Mozilla Public License Version 1.1 with the following Amendments,
including Exhibit A-Netscape Public License. Files identified with
"Exhibit A-Netscape Public License" are governed by the Netscape
Public License Version 1.1.
Additional Terms applicable to the Netscape Public License.
I. Effect.
These additional terms described in this Netscape Public
License -- Amendments shall apply to the Mozilla Communicator
client code and to all Covered Code under this License.
II. "Netscape's Branded Code" means Covered Code that Netscape
distributes and/or permits others to distribute under one or more
trademark(s) which are controlled by Netscape but which are not
licensed for use under this License.
III. Netscape and logo.
This License does not grant any rights to use the trademarks
"Netscape", the "Netscape N and horizon" logo or the "Netscape
lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
"Smart Browsing" even if such marks are included in the Original
Code or Modifications.
IV. Inability to Comply Due to Contractual Obligation.
Prior to licensing the Original Code under this License, Netscape
has licensed third party code for use in Netscape's Branded Code.
To the extent that Netscape is limited contractually from making
such third party code available under this License, Netscape may
choose to reintegrate such code into Covered Code without being
required to distribute such code in Source Code form, even if
such code would otherwise be considered "Modifications" under
this License.
V. Use of Modifications and Covered Code by Initial Developer.
V.1. In General.
The obligations of Section 3 apply to Netscape, except to
the extent specified in this Amendment, Section V.2 and V.3.
V.2. Other Products.
Netscape may include Covered Code in products other than the
Netscape's Branded Code which are released by Netscape
during the two (2) years following the release date of the
Original Code, without such additional products becoming
subject to the terms of this License, and may license such
additional products on different terms from those contained
in this License.
V.3. Alternative Licensing.
Netscape may license the Source Code of Netscape's Branded
Code, including Modifications incorporated therein, without
such Netscape Branded Code becoming subject to the terms of
this License, and may license such Netscape Branded Code on
different terms from those contained in this License.
VI. Litigation.
Notwithstanding the limitations of Section 11 above, the
provisions regarding litigation in Section 11(a), (b) and (c) of
the License shall apply to all disputes relating to this License.
EXHIBIT A-Netscape Public License.
"The contents of this file are subject to the Netscape 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/NPL/
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 Mozilla Communicator client code, released
March 31, 1998.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998-1999 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the
terms of the _____ license (the "[___] License"), in which case
the provisions of [______] License are applicable instead of
those above. If you wish to allow use of your version of this
file only under the terms of the [____] License and not to allow
others to use your version of this file under the NPL, indicate
your decision by deleting the provisions above and replace them
with the notice and other provisions required by the [___]
License. If you do not delete the provisions above, a recipient
may use your version of this file under either the NPL or the
[___] License."

View File

@@ -0,0 +1,53 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# The XPCOM (Cross Platform COM) package.
import exceptions
#import sys
#sys.stdout = open("pystdout.log", "w")
# A global "verbose" flag - currently used by the
# server package to print trace messages
verbose = 0
hr_map = {}
# The standard XPCOM exception object.
# Instances of this class are raised by the XPCOM extension module.
class Exception(exceptions.Exception):
def __init__(self, errno, message = None):
assert int(errno) == errno, "The errno param must be an integer"
self.errno = errno
self.message = message
exceptions.Exception.__init__(self, errno)
def __str__(self):
if not hr_map:
import nsError
for name, val in nsError.__dict__.items():
if type(val)==type(0):
hr_map[val] = name
message = self.message
if message is None:
message = hr_map.get(self.errno)
if message is None:
message = ""
return "0x%x (%s)" % (self.errno, message)
# An alias for Exception - allows code to say "from xpcom import COMException"
# rather than "Exception" - thereby preventing clashes.
COMException = Exception
# Exceptions thrown by servers. It can be good for diagnostics to
# differentiate between a ServerException (which was presumably explicitly thrown)
# and a normal exception which may simply be propagating down.
# (When ServerException objects are thrown across the XPConnect
# gateway they will be converted back to normal client exceptions if
# subsequently re-caught by Python
class ServerException(Exception):
def __init__(self, errno=None, *args, **kw):
if errno is None:
import nsError
errno = nsError.NS_ERROR_FAILURE
Exception.__init__(self, errno, *args, **kw)
# Some global functions.

View File

@@ -0,0 +1,247 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import os
import new
from xpcom import xpt, _xpcom, COMException, nsError
XPTC_InvokeByIndex = _xpcom.XPTC_InvokeByIndex
_just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"]
_just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"]
_just_float_interfaces = ["nsISupportsDouble", "nsISupportsFloat"]
# When doing a specific conversion, the order we try the interfaces in.
_int_interfaces = _just_int_interfaces + _just_float_interfaces
_long_interfaces = _just_long_interfaces + _just_int_interfaces + _just_float_interfaces
_float_interfaces = _just_float_interfaces + _just_long_interfaces + _just_int_interfaces
method_template = """
def %s(self, %s):
return XPTC_InvokeByIndex(self._comobj_, %d,
(%s,
(%s)))
"""
def _MakeMethodCode(method):
# Build a declaration
param_no = 0
param_decls = []
param_flags = []
param_names = []
used_default = 0
for param in method.params:
param_no = param_no + 1
param_name = "Param%d" % (param_no,)
param_default = ""
if not param.hidden_indicator and param.IsIn() and not param.IsDipper():
if param.IsOut() or used_default: # If the param is "inout", provide a useful default for the "in" direction.
param_default = " = None"
used_default = 1 # Once we have used one once, we must for the rest!
param_decls.append(param_name + param_default)
param_names.append(param_name)
type_repr = xpt.MakeReprForInvoke(param)
param_flags.append( (param.param_flags,) + type_repr )
sep = ", "
param_decls = sep.join(param_decls)
if len(param_names)==1: # Damn tuple reprs.
param_names = param_names[0] + ","
else:
param_names = sep.join(param_names)
# A couple of extra newlines make them easier to read for debugging :-)
return method_template % (method.name, param_decls, method.method_index, tuple(param_flags), param_names)
# Keyed by IID, each item is a tuple of (methods, getters, setters)
interface_cache = {}
# Fully process the interface - generate method code, etc.
def BuildInterfaceInfo(iid):
ret = interface_cache.get(iid, None)
if ret is None:
# Build the data for the cache.
method_code_blocks = []
getters = {}
setters = {}
method_names = []
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():
param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params)
setters[m.name] = m.method_index, param_flags
elif m.IsGetter():
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))
# 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
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
def __cmp__(self, other):
try:
other = other._comobj_
except AttributeError:
pass
return cmp(self._comobj_, other)
def __hash__(self):
return hash(self._comobj_)
def __repr__(self):
return "<XPCOM interface '%s'>" % (self._comobj_.IID.name,)
# See if the object support strings.
def __str__(self):
try:
self._comobj_.QueryInterface(_xpcom.IID_nsISupportsString)
return str(self._comobj_)
except COMException:
return self.__repr__()
# Try the numeric support.
def _do_conversion(self, interface_names, cvt):
iim = _xpcom.XPTI_GetInterfaceInfoManager()
for interface_name in interface_names:
iid = iim.GetInfoForName(interface_name).GetIID()
try:
prim = self._comobj_.QueryInterface(iid)
return cvt(prim.data)
except COMException:
pass
raise ValueError, "This object does not support automatic numeric conversion to this type"
def __int__(self):
return self._do_conversion(_int_interfaces, int)
def __long__(self):
return self._do_conversion(_long_interfaces, long)
def __float__(self):
return self._do_conversion(_float_interfaces, float)
def __getattr__(self, attr):
# Allow the underlying interface to provide a better implementation if desired.
ret = getattr(self.__dict__['_comobj_'], attr, None)
if ret is not None:
return ret
# Do the function thing first.
unbound_method = self.__dict__['_interface_methods_'].get(attr)
if unbound_method is not None:
return new.instancemethod(unbound_method, self, self.__class__)
getters, setters = self.__dict__['_interface_infos_']
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)
def __setattr__(self, attr, val):
# If we already have a __dict__ item of that name, and its not one of
# our constants, we just directly set it, and leave.
if self.__dict__.has_key(attr) and attr not in self.__dict__['_constant_names_']:
self.__dict__[attr] = val
return
# Start sniffing for what sort of attribute this might be?
getters, setters = self.__dict__['_interface_infos_']
info = setters.get(attr)
if info is None:
raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)
method_index, param_infos = info
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)
# Called by the _xpcom C++ framework to wrap interfaces up just
# before they are returned.
def MakeInterfaceResult(ob, iid):
return Interface(ob, iid)
class WeakReference:
"""A weak-reference object. You construct a weak reference by passing
any COM object you like. If the object does not support weak
refs, you will get a standard NS_NOINTERFACE exception.
Once you have a weak-reference, you can "call" the object to get
back a strong reference. Eg:
>>> 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
>>> # weak reference does not keep the object alive (that is the point)
You should never hold onto this resulting strong object for a long time,
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)
if iid is None:
try:
iid = ob.IID
except AttributeError:
iid = _xpcom.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)
except COMException, details:
if details.errno != nsError.NS_ERROR_NULL_POINTER:
raise
return None

View File

@@ -0,0 +1,183 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# This module provides the JavaScript "components" interface
import xpt
import xpcom, _xpcom
import xpcom.client
import xpcom.server
import types
StringTypes = [types.StringType, types.UnicodeType]
# The "manager" object.
manager = xpcom.client.Interface(_xpcom.NS_GetGlobalComponentManager(), _xpcom.IID_nsIComponentManager)
# The "interfaceInfoManager" object - JS doesnt have this.
interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager()
# The "Exception" object
Exception = xpcom.Exception
# Base class for our collections.
# It appears that all objects supports "." and "[]" notation.
# eg, "interface.nsISupports" or interfaces["nsISupports"]
class _ComponentCollection:
# Bases are to over-ride 2 methods.
# _get_one(self, name) - to return one object by name
# _build_dict - to return a dictionary which provide access into
def __init__(self):
self._dict_data = None
def keys(self):
if self._dict_data is None:
self._dict_data = self._build_dict()
return self._dict_data.keys()
def items(self):
if self._dict_data is None:
self._dict_data = self._build_dict()
return self._dict_data.items()
def values(self):
if self._dict_data is None:
self._dict_data = self._build_dict()
return self._dict_data.values()
def has_key(self, key):
if self._dict_data is None:
self._dict_data = self._build_dict()
return self._dict_data.has_key(key)
def __len__(self):
if self._dict_data is None:
self._dict_data = self._build_dict()
return len(self._dict_data)
def __getattr__(self, attr):
if self._dict_data is not None and self._dict_data.has_key(attr):
return self._dict_data[attr]
return self._get_one(attr)
def __getitem__(self, item):
if self._dict_data is not None and self._dict_data.has_key(item):
return self._dict_data[item]
return self._get_one(item)
class _Interface:
# An interface object.
def __init__(self, name, iid):
# Bypass self.__setattr__ when initializing attributes.
d = self.__dict__
d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID.
d['name'] = name
d['constants'] = None # Built first time an attribute is asked for.
def __cmp__(self, other):
this_iid = self._iidobj_
other_iid = getattr(other, "_iidobj_", other)
return cmp(this_iid, other_iid)
def __hash__(self):
return hash(self._iidobj_)
def __str__(self):
return str(self._iidobj_)
def __getitem__(self, item):
raise TypeError, "components.interface objects are not subscriptable"
def __setitem__(self, item, value):
raise TypeError, "components.interface objects are not subscriptable"
def __setattr__(self, attr, value):
raise AttributeError, "Can not set attributes on components.Interface objects"
def __getattr__(self, attr):
# Support constants as attributes.
c = self.constants
if c is None:
c = {}
i = xpt.Interface(self._iidobj_)
for c_ob in i.constants:
c[c_ob.name] = c_ob.value
self.__dict__['constants'] = c
if c.has_key(attr):
return c[attr]
raise AttributeError, "'%s' interfaces do not define a constant '%s'" % (self.name, attr)
class _Interfaces(_ComponentCollection):
def _get_one(self, name):
item = interfaceInfoManager.GetInfoForName(name)
return _Interface(item.GetName(), item.GetIID())
def _build_dict(self):
ret = {}
enum = interfaceInfoManager.EnumerateInterfaces()
while not enum.IsDone():
# Call the Python-specific FetchBlock, to keep the loop in C.
items = enum.FetchBlock(500, _xpcom.IID_nsIInterfaceInfo)
# This shouldnt be necessary, but appears to be so!
for item in items:
ret[item.GetName()] = _Interface(item.GetName(), item.GetIID())
return ret
# And the actual object people use.
interfaces = _Interfaces()
del _Interfaces # Keep our namespace clean.
#################################################
class _Class:
def __init__(self, contractid):
self.contractid = contractid
def __getattr__(self, attr):
if attr == "clsid":
rc = manager.contractIDToClassID(self.contractid)
# stash it away - it can never change!
self.clsid = rc
return rc
raise AttributeError, "%s class has no attribute '%s'" % (self.contractid, attr)
def createInstance(self, iid = None):
import xpcom.client
if iid is None:
iid = _xpcom.IID_nsISupports
elif type(iid) in StringTypes and len(iid)>0 and iid[0] != "{":
iid = getattr(interfaces, iid)
return xpcom.client.Component(self.contractid, iid)
def getService(self, iid):
return _xpcom.GetGlobalServiceManager().getService(self.contractid, iid)
class _Classes(_ComponentCollection):
def __init__(self):
_ComponentCollection.__init__(self)
def _get_one(self, name):
# XXX - Need to check the contractid is valid!
return _Class(name)
def _build_dict(self):
ret = {}
enum = manager.EnumerateContractIDs()
while not enum.IsDone():
# Call the Python-specific FetchBlock, to keep the loop in C.
items = enum.FetchBlock(500)
for item in items:
name = str(item)
ret[name] = _Class(name)
return ret
classes = _Classes()
del _Classes
del _ComponentCollection
# The ID function
ID = _xpcom.IID
# A helper to cleanup our namespace as xpcom shuts down.
class _ShutdownObserver:
_com_interfaces_ = interfaces.nsIObserver
def Observe(self, service, topic, extra):
global manager
global interfaceInfoManager
global _shutdownObserver
manager = interfaceInfoManager = _shutdownObserver = None
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
# observer alive ourself, and must keep the COM object alive,
# _not_ just the Python instance!!!
_shutdownObserver = xpcom.server.WrapObject(_ShutdownObserver(), interfaces.nsIObserver)
svc.AddObserver(_shutdownObserver, "xpcom-shutdown")
del svc, _ShutdownObserver

View File

@@ -0,0 +1,135 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Python XPCOM Advanced Topics</title>
</head>
<body>
<h1>Python XPCOM Advanced Topics</h1>
<p>This document contains a series of tidbits that don't fit
anywhere else. As the Python XPCOM Package documentation matures, most of
these topics will have another home.</p>
<h2>XPCOM Services</h2>
<p>An XPCOM service is simply a singleton registered by name.&nbsp; Python has
full support for both using and implementing XPCOM services.&nbsp; To use a
service, use <i>xpcom.components.services</i> just like the JavaScript
counterpart.&nbsp; There is nothing special about implementing a service in
Python; see the standard XPCOM documentation on services for more information.</p>
<h2>nsISupports Primitives.</h2>
<p>There is a set of interfaces described in <i>nsISupportsPrimitives.idl</i>, which I
term collectively the <i>nsISupports Primitives Interfaces</i>.&nbsp; These
are a set of interfaces a component can support to allow automatic conversion to
and from many basic types.&nbsp; For example, an interface can define that it
supports the <i>nsISupportsString</i> interface, and this could be used by any
program that wishes to get a string representation of the object.&nbsp; If an
interface wishes to expose itself as a &quot;boolean value&quot;, it may choose
to support the <i>nsISupportsPRBool</i> interface.</p>
<p>When you call an XPCOM object (i.e., you have an XPCOM interface you are
calling), you can use
the builtin functions <i>str()</i>, <i>int()</i>, <i>long()</i> etc., on the
object<i>.</i>&nbsp; In the
case of <i>str()</i>, if the object does not support the <i>nsISupportsString</i>
or <i>nsISupportsWString</i> interfaces, the default string <i>str()</i> for the
object will be returned (i.e., what is normally returned for most XPCOM objects -
support for these interface is not very common!).&nbsp; In the case of the numeric functions, a <i>ValueError</i>
exception will be raised if the objects do not support any interface that can be
used for the conversion.&nbsp;<i>ValueError</i> is used instead of <i>TypeError</i>,
as the type itself (i.e., an XPCOM object) can sometimes be used in this context -
hence it is the specific <i>value</i> of the object that is the problem.</p>
<p>The use of <i>repr()</i> on an XPCOM interface object prevents support
attempts for these interfaces, and allows you to see the
&quot;real&quot; object, rather than what the object wants you to see!</p>
<p>When you implement an XPCOM object, you have two choices for implementation
of these interfaces:</p>
<ul>
<li>You can explicitly handle these interfaces like any other interface.&nbsp;
In this case, you have full control.&nbsp; However, if you
implement only one of these standard interfaces, then you are only
overriding the default behavior for that specific interface - all other
interfaces not explicitly listed in your class will still get the behavior
described below.<br>
</li>
<li>If your class does not define support for these interfaces, the framework
will use standard Python class semantics to implement them - i.e., if your
class provides a <i>__str__</i> method, it will be used to implement <i>nsISupportsString</i>
and <i>nsISupportsWString</i>, if you provide <i>__int__</i>, <i>__long__</i>,
<i>__float__</i> etc., methods, they will be used to implement the numeric
interfaces.&nbsp; If your class defines no such special methods, then the <i>
QueryInterface()</i> for those interfaces fails (rather than the QI succeeding
and the operation to fetch the data failing).</li>
</ul>
<blockquote>
<p>This allows for an interesting feature that would not normally be
possible.&nbsp; Consider Python code that does a <i>str()</i> on an&nbsp; XPCOM
interface, and where the XPCOM interface itself is implemented in Python and
provides a <i>__str__</i> method.&nbsp; The <i>str()</i> on the original
interface queries for the <i>nsISupportsString</i> interface.&nbsp; The
Python implemented object responds to this interface and delegates to the <i>__str__</i>
method. At the end of all this, <i>str()</i> returns the same result
as if the objects were native Python objects with no XPCOM layer in between.</p>
</blockquote>
<h2>Enumerators</h2>
<p>The primary enumerator used by XPCOM is <i>nsISimpleEnumerator</i>.
Although the Python XPCOM package has full support for <i>nsIEnumerator</i>,
since this interface is not &quot;scriptable&quot;, you should avoided using it in interfaces
you design.</p>
<p>When you use <i>nsISimpleEnumerator</i> from Python, the following enhancements
are available:</p>
<ul>
<li>The <i>GetNext()</i> method takes an optional IID as a parameter. If
this is specified, the returned object will be of this interface.&nbsp; This
prevents the manual <i>QueryInterface()</i> generally required from other
languages.</li>
<li>There is a <i>FetchBlock(num, [iid])</i> method, which fetches the
specified number of elements in one operation and returns a Python
list. This can be useful for large enumerator sets, so the loop
iterating the elements runs at full C++ speed.</li>
</ul>
<p><i>nsIEnumerator</i> has similar enhancements.</p>
<p>When implementing a Python XPCOM object, the Python class <i>xpcom.server.enumerator.SimpleEnumerator()</i>
can be used.&nbsp; You can pass a standard Python sequence (list, etc), and it
will be correctly wrapped in an <i>nsISimpleEnumerator</i> interface.</p>
<h2>Files</h2>
<p>The Python XPCOM package provides an <i> xpcom.file</i> module.&nbsp; This implements
a Python-like file object on top of the XPCOM/Mozilla stream interfaces.&nbsp;
When run from within the Mozilla environment, this allows you to open almost any
URL supported by Mozilla (including &quot;chrome://&quot; etc.,).</p>
<p>See this module for more information, including test code.</p>
<h2>XPCOM Object Identity</h2>
<p>XPCOM has defined rules for object identity and for how objects must behave
in their <i> QueryInterface()</i> implementations.&nbsp; The Python XPCOM framework
manages this for you; your code can return new Python instances etc., when
responding to new interfaces, and the framework itself will ensure the XPCOM
semantics are followed.&nbsp; Critically, the framework provides no mechanism
for breaking these rules.</p>
<h2>Policies</h2>
<p>The Python XPCOM framework has the concept of &quot;policies&quot; that
define how XPCOM semantics are mapped to Python objects.&nbsp; It is the policy
that implements delegation of <i> QueryInterface()</i>, translates property
references into direct property references, and failing that, &quot;get_name&quot;
and &quot;set_name&quot; calls, decides how to handle exceptions in the
component, and so on.</p>
<p>The default policy is very flexible and suitable for most purposes.
Indeed, the Komodo project has never had to implement a custom policy.
However, you should be aware the feature exists should you wish to do some
bizarre things, such as using Python as a bridge between XPCOM and some other
component technology.</p>
</body>
</html>

View File

@@ -0,0 +1,84 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Architecture</title>
</head>
<body>
<h1>Python XPCOM Package Architecture</h1>
<h2><a name="Architecture">Architecture</a></h2>
<p>Much of the design for the Python XPCOM Package has been borrowed from the Python MS-COM
extensions in <i>win32com</i>. Most of the major limitations and drawbacks in the <i>win32com</i>
design have been addressed, mainly &quot;auto-wrapping&quot; of
interface objects, which is not supported by <i>win32com</i>.</p>
<p>Like <i>win32com</i>, this architecture includes the concept of <i>client COM</i> and <i>server
COM.</i> </p>
<p>Client COM:</p>
<ul>
<li>calls other interfaces</li>
<li>is supported by <i>PyInterfaces</i> implemented in C++, which assists
in making the COM calls</li>
<li>is supported by <i>PyGateways</i>, which assists in receiving
external COM calls and dispatching them to the correct Python object</li>
<li> is supported in the <i>xpcom/client</i> package</li>
</ul>
<p>Server COM:</p>
<ul>
<li>implements interfaces for use by other XPCOM applications or components</li>
<li> is
supported in the <i>xpcom/server</i> package</li>
</ul>
<p>The XPConnect framework is very powerful, and far exceeds what COM's <i>
IDispatch</i> can offer.&nbsp; Thus, we are able to get by with far fewer interfaces
supported in the C++ level, and defer most things to the Python code that uses
XPConnect.&nbsp; As a result, the requirement for a huge number of interfaces to
exist in the <i>.pyd</i> does not exist.&nbsp; There are, however, a number of
interfaces that do require native C++ support: these are interfaces
required to &quot;boot&quot; the XPConnect support (i.e., the interfaces that are
used to get information about interfaces), and also two gateways that need to
work without interface information available. This last requirement is
due to the XPCOM shutdown-ordering - it may be a bug, but is not an unreasonable
amount of code anyway.</p>
<p><b>Auto-wrapping</b> of COM objects is supported by both client COM and
server COM.&nbsp;For client COM, auto-wrapping means that the
Python programmer always sees Python &quot;component&quot; objects, rather than
raw C++ interface objects; to the user, it all appears to &quot;just
work&quot;.&nbsp; This is a major source of frustration in the <i>win32com</i>
framework.</p>
<p>For server COM, auto-wrapping means that you can
pass Python instances wherever a COM object is expected. If the Python
instance supports COM interfaces, by virtue of having a <i>_com_interfaces_</i>
attribute that lists the interface requested, it will be automatically wrapped
in the correct COM object.&nbsp;</p>
<p><b>Error Handling:</b> The C++ framework has good error handling support,
and uses the XPCOM console service to log debug messages, Python exceptions and
tracebacks.&nbsp; <i>win32com</i> does not have good exception/traceback support
at the C++ level, mainly because COM does not define a service like
the console where debug messages can go.&nbsp; This does mean that in Mozilla
release builds, these debug messages are likely to be lost, but the <i>--console</i>
command line option to a release Mozilla will get them back.&nbsp; Therefore,
the other error-support utilities, such as the error callbacks made on the
policy object, may be used.</p>
<p><b>Component Loader, Modules and Factories:</b>&nbsp; XPCOM has the concept
of a component loader - a module used to load all components of a
particular type.&nbsp; For example, the <i>moz.jsloader.1</i> component loads all
the JavaScript components.&nbsp;Similarly, the <i>moz.pyloader.1</i>
component loads all Python components.&nbsp; However, unlike
JavaScript, the Python component loader is actually implemented in Python
itself!&nbsp;Since the Python component loader can not be used to load
itself, this component has some special code, <i>pyloader.dll,</i> to boot-strap itself.</p>
<p>This means is that all XPCOM components, including the Python loader itself and all
XPCOM module and factory interfaces, are implemented in
Python.&nbsp;<b>There are no components or interfaces implemented purely in C++
in this entire package!</b></p>
</body>
</html>

View File

@@ -0,0 +1,198 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Configuring your Environment</title>
</head>
<body>
<h1>Building, Configuring and Testing Python XPCOM Package</h1>
<p>This document attempts to explain how to build, configure and test the
Python XPCOM Package. This document assumes you have already successfully
built
Mozilla from source and your environment is currently set up for such a build -
see the <a href="http://www.mozilla.org/build/">Mozilla build documentation</a>
for more information.</p>
<p>This section covers:</p>
<ul>
<li>
<p align="left"><a href="#ConfigureTheEnvironment">Configuring your
Environment</a></li>
<li>
<p align="left"><a href="#BuildingTheExtensions">Building</a></li>
<li>
<p align="left"><a href="#RunningTheTests">Testing your Setup</a></li>
<li><a href="#Registration">Registering the Loader and Test
Component</a></li>
<li><a href="#RunningTheTests">Running the test suite</a></li>
</ul>
<h2><a name="ConfigureTheEnvironment">Configuring your Environment</a></h2>
<p>In addition to the existing environment requirements for building Mozilla itself, the
Python XPCOM package has the following requirements:</p>
<ul>
<li>
<a name="MozillaDirectory"><b>Mozilla Directory</b></a><b> - </b>Ensure the Mozilla
<i> bin</i> directory is on your PATH
(LD_LIBRARY_PATH
on Unix) so Python can locate the <i> xpcom.dll</i> module needed for
core XPCOM services.</li>
<li><a name="PYTHONPATH"><b>PYTHONPATH</b></a> - <tt>PYTHONPATH</tt> needs to be set appropriately.&nbsp;Ensure
the parent to this <i>xpcom</i> directory is on your path so &quot;import
xpcom&quot; locates this directory.&nbsp; Note that the Mozilla <i>components</i> directory does not need to be on the <tt>PYTHONPATH</tt>,
but any modules used by your components must be set correctly.&nbsp; If anything
is wrong here you should get a normal <tt>ImportError</tt>.</li>
</ul>
<blockquote>
<p>Note that on Windows, the PYTHONPATH is generally maintained in the
Registry; however, you can set this variable at a DOS prompt, and it will still be
added to the core PYTHONPATH.
</blockquote>
<h2><a name="BuildingTheExtensions">Building</a></h2>
<p>The initial release of the Python XPCOM package has a very simple, hard-coded
build process.&nbsp; The intention is to include this package in the Mozilla
source tree, and integrate the build with the Mozilla build.&nbsp; Until this
happens, perform the following steps:</p>
<ul>
<li>Ensure you can successfully build Mozilla itself from source-code.</li>
<li>Unpack this source code, and change to the <i>xpcom</i> directory under
the root <i>PyXPCOM</i> directory.</li>
<li>For Windows, edit <i>makefile.stupid.win</i>, while for Linux, edit <i>makefile.stupid.linux</i></li>
<li>As per the instructions at the top of the makefile, edit the MOZ_SRC,
INSTALLDIR and PYTHON_SRC definitions appropriately.</li>
</ul>
<h3>Build Example: Building on Windows</h3>
<p>For this example, we will assume that the source-code for Mozilla is in C:\src\mozilla,
the source-code for the PyXPCOM package is in <i>c:\src\pyxpcom</i>. Further, we assume
that you have Python 2.0 installed in <i>C:\Python20</i>, and wish to install
the built Python XPCOM package so it exists in <i>C:\Python20\xpcom</i>.</p>
<p>To build the package in this environment, you would perform the following
steps:</p>
<ul>
<li>Unpack the PyXPCOM package source-code into the appropriate directory</li>
<li>Edit makefile.stupid.win with the following changes:<br>
<i>MOZ_SRC=c:\src<br>
INSTALLDIR=C:\Python20<br>
PYTHON_SRC=C:\Python20</i></li>
<li>&nbsp;From the top-level Python xpcom source directory (i.e., the
directory with <i>makefile.stupid.win</i>), execute the command:<br>
<i>nmake -f makefile.stupid.win install</i></li>
</ul>
<p>NOTE: To build a Debug version of the Python XPCOM library, you can add <i>DEBUG=1</i>
to the nmake command-line.</p>
<p>If everything appears to work and you are brave, you may also like to execute
<i>make -f makefile.stupid.win test</i> to execute the test script.&nbsp;
Otherwise, continue to the following section where we confirm the installation
step-by-step.</p>
<h3>Build Example: Building on Linux</h3>
<p>For this example, we will assume that the source-code for Mozilla is in ~/src/mozilla,
the source-code for the PyXPCOM package is in ~/src/pyxpcom. Further, we assume
that you have ActivePython 2.0 installed in <i>/usr/local/ActivePython2.0</i>,
and wish to install the built Python XPCOM package so it exists in <i>/usr/local/ActivePython2.0/lib/python2.0/site-packages/xpcom</i>.</p>
<p>To build the package in this environment, you would perform the following
steps:</p>
<ul>
<li>Unpack the PyXPCOM package source-code into the appropriate directory</li>
<li>Edit makefile.stupid.linux with the following changes (substituting
username accordingly):<br>
<i>MOZ_SRC=/home/username/src<br>
INSTALLDIR=/usr/local/ActivePython-2.0/site-packages<br>
PYTHON_SRC=/usr/local/ActivePython-2.0</i></li>
<li>Build: As a regular user, from the top-level Python xpcom source
directory (i.e., the directory with <i>makefile.stupid.linux</i>), execute
the command:<br>
<i>make -f makefile.stupid.linux DEBUG=1</i></li>
<li>Install: Log in as a user with permissions to install into the relevant directories
(usually the root user).&nbsp; From the top-level Python xpcom source
directory (i.e., the directory with <i>makefile.stupid.linux</i>), execute
the command:<br>
<i>make -f makefile.stupid.linux DEBUG=1 install</i></li>
<li>Switch back to a regular user, ready for testing!</li>
</ul>
<p>NOTE: The instructions above are for a Debug build, as this is the default
Mozilla build type.&nbsp; If you have configured Mozilla to build a Release
version of Mozilla, you can drop the DEBUG=1 option.&nbsp; It is important that
PyXPCOM and Mozilla itself are consistent with respect to Release and Debug
builds.&nbsp; For more details, please consult the makefile.</p>
<p>If everything appears to work and you are brave, you may also like to execute
<i>make -f makefile.stupid.linux test</i> to execute the test script.&nbsp;
Otherwise, continue to the following section where we confirm the installation
step--by-step.</p>
<h2><a name="RunningTheTests">Testing your Setup</a></h2>
<p>The Python XPCOM Package has a complete test suite.&nbsp; If you are
impatient, you can simply execute <i>make -f makefile.stupid.linux test</i> (for
Linux) or <i>nmake -f makefile.stupid.linux test</i> (for Windows).&nbsp; If
this command indicates that the tests succeeded, then you can ignore the rest of
this section.</p>
<p>In the rest of this section, we walk through some simpler tests a step at a time,
to help diagnose any problems.</p>
<p><b>Note:</b> We recommend you do all your testing outside of <i> mozilla.exe</i>; it is far simpler to test all of
this using the PyXPCOM package stand-alone.</p>
<p><b>Note:</b> On Windows, if you use a debug build of Mozilla (i.e., in <i>dist\WIN32_D.OBJ\bin)</i>,
you <b>must</b> use <i>python_d.exe</i>; if you use a release build (i.e., in
a <i>dist\WIN32_O.OBJ\bin</i> directory), you must use <i>python.exe</i>.&nbsp;
<i>makefile.stupid.win</i> handles this automatically.</p>
<p>To test your setup:</p>
<ol>
<li>Start Python, and check<br>
&gt;&gt;&gt; <i>import xpcom</i><br>
works. If not, <a href="#PYTHONPATH">check your PYTHONPATH</a> - the
main PyXPCOM package can not be located..</li>
<li>Check<i><br>
&gt;&gt;&gt; import xpcom._xpcom</i><br>
works. If not, then most likely your <a href="#MozillaDirectory">Mozilla
directory is not on your path</a>, or something is wrong with <i>_xpcom(_d).pyd/_xpcommodule.so</i>.</li>
<li>Next run a simple test: <i>test/test_misc.py</i>.&nbsp;With a Windows debug build, the command may look like:<br>
<i>C:\Anywhere&gt; python_d \src\python\xpcom\test\test_misc.py<br>
</i>or on Linux<br>
<i>/home/user/src/mozilla/dist/bin$ python /home/user/src/python/xpcom/test/test_misc.py</i></li>
</ol>
<p>If you can't get this going, you won't get much further! If you do, the
next step is to register our test component and run our full test suite.</p>
<h2><a name="Registration">Registering the Loader and Test Component</a></h2>
<p>First register the generic Python loader. For instructions, see the <a href="file:///F:/src/as/Komodo/src/pyxpcom/xpcom/doc/architecture.html">architecture
document</a>.&nbsp;Do this only once, regardless of how many
Python components you have.&nbsp; Then install the test component itself, and
finally you can test it!</p>
<h3>Registering the Python Loader and Component</h3>
<p>To register the Python Loader and Component:</p>
<ol>
<li>Ensure the build process has put <i>pyloader.dll </i>(or <i>modpyloader.so</i>
for Unix), and the files <i> py_test_component.py </i> and <i> py_test_component.idl</i> into
the Mozilla <i>bin/components</i> directory.&nbsp; If not, copy the files
there manually.</li>
<li>Run <i>regxpcom</i>.&nbsp;<i>regxpcom</i> is a standard Mozilla
executable, found in the <i>bin</i> directory, that detects whether the DLL and .py
files have been added and registers them accordingly.&nbsp; You should
see a few messages that include the following:</li>
</ol>
<blockquote>
<pre>Registering: PythonComponentLoader
Registered 1 Python components in pyloader.dll
nsNativeComponentLoader: autoregistering succeeded
Auto-registering all Python components in F:\src\mozilla\dist\WIN32_D.OBJ\bin\components
Registering: PythonTestComponent
Registered 1 Python components in py_test_component.py</pre>
</blockquote>
<p>If so (or you see no message at all), you are ready to run the test suite.</p>
<p><b>Note</b>: If you execute this same step a second time, you will not
see any of the above mentioned messages.&nbsp;XPCOM knows that nothing has
changed since you last ran <i>regxpcom</i>, so nothing is registered.&nbsp; If
you do not see these messages the first time you run it, there is the
possibility that some other process, possibly the build process, has already
executed this step.</p>
<h2><b>Running the Test Suite</b></h2>
<p>To run the test suite, run <i>xpcom/test/regrtest.py.</i>&nbsp; This runs the
tests and ensures that the test output is as expected.&nbsp; If all tests
pass, you have a fully functioning Python XPCOM package.&nbsp; Enjoy!</p>
</body>
</html>

View File

@@ -0,0 +1,54 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Language" content="en-au">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Credits and Acknowledgements</title>
</head>
<body>
<h1>Credits and Acknowledgements</h1>
<h2>ActiveState Tool Corporation</h2>
<p>The Python XPCOM Package was developed primarily by <a href="mailto:markh@activestate.com">Mark
Hammond</a> of <a href="http://www.ActiveState.com">ActiveState Tool Corporation</a>.</p>
<p>The developers on the <a href="http://www.ActiveState.com/Products/Komodo">Komodo
project</a> deserve high praise for putting up with early versions when almost
nothing worked, and for believing in Python as a viable XPCOM language.&nbsp;
Their feedback and patience has allowed the first public release to be amazingly
functional and bug-free.</p>
<h3>Komodo Development Team (at December 2000)</h3>
<p><a href="mailto:davida@activestate.com">David Ascher</a>, <a href="mailto:aaronb@ActiveState.com">Aaron Bingham</a>,
<a href="mailto:bindu@activestate.com">Bin Du</a>, <a href="mailto:markh@activestate.com">Mark
Hammond</a>, <a href="mailto:trentm@activestate.com">Trent Mick (build god)</a>,&nbsp;
<a href="mailto:paulp@activestate.com">Paul Prescod</a>,&nbsp; <a href="mailto:ericp@ActiveState.com">Eric Promislow</a>,
<a href="mailto:kens@ActiveState.com">Ken Simpson</a>, <a href="mailto:neilw@ActiveState.com">Neil Watkiss</a>,
<a href="mailto:AudreyS@ActiveState.com">Audrey Schumacher</a>.</p>
<h2>Mozilla/Netscape</h2>
<p>The following people at <a href="http://www.netscape.com">Netscape</a> and <a href="http://www.mozilla.org">Mozilla</a>
(or not there but still heavily involved in the project) have provided enormous
help in getting things integrated with their build system, answering us on the
newsgroup, teaching us the finer points of XPCOM, gently slapping us for accidentally
referring to <i>jscript</i>, etc., and otherwise lending us a clue in the
Mozilla/Netscape/XPCOM world.</p>
<p><a href="mailto:jband@netscape.com">John Bandhauer</a>, <a href="mailto:brendan@meer.net">Brendan
Eich</a>, <a href="mailto:shaver@zeroknowledge.com">Mike Shaver</a>, <a href="mailto:evaughan@netscape.com">Eric Vaughan</a>,
<a href="mailto:hyatt@netscape.com">David Hyatt</a></p>
<h2>External Contributors</h2>
<p>The following people have made contributions to the project, simply because
they find it useful and enjoy supporting Open Source projects.</p>
<p><a href="mailto:cmeerw@web.de">Christof Meerwald</a></p>
<h2>Documentation Credits</h2>
<p>The following people have contributed to the Python XPCOM Package
documentation&nbsp;</p>
<p><a href="mailto:markh@activestate.com">Mark
Hammond</a>, <a href="mailto:AudreyS@ActiveState.com">Audrey Schumacher</a></p>
</body>
</html>

View File

@@ -0,0 +1,240 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Python XPCOM Package Tutorial</title>
</head>
<body>
<h1>Python XPCOM Package Tutorial</h1>
<p>This is a quick introduction to the Python XPCOM Package. We assume that you have a good understanding of Python and <a href="http://www.mozilla.org/projects/xpcom/">XPCOM</a>,
and have experience both using and implementing XPCOM objects in some other
language (e.g., C++ or JavaScript). We <b><i>do not</i></b> attempt to
provide a tutorial to XPCOM or Python itself, only to using Python <i>and</i>
XPCOM.</p>
<p>This tutorial contains the following sections:</p>
<ul>
<li><a href="#Using">Using XPCOM Objects and Interfaces</a> - when you wish to
<i>use</i> a component written by anyone else in any XPCOM supported
language.</li>
<li><a href="#Implementing">Implementing XPCOM Objects and Interfaces</a> -
when you wish to implement a component for use by anyone else in any xpcom
supported language.</li>
<li><a href="#Parameters">Parameters and Types</a> - useful information
regarding how Python translates XPCOM types, and handles byref parameters.</li>
</ul>
<p>For anything not covered here, try the <a href="advanced.html">advanced
documentation</a>, and if that fails, use the source, Luke!</p>
<h2><a name="Using">Using XPCOM object and interfaces.</a></h2>
<p>The techniques for using XPCOM in Python have been borrowed from JavaScript -
thus, the model described here should be quite familiar to existing JavaScript
XPCOM programmers.</p>
<h3>xpcom.components module</h3>
<p>When using an XPCOM object, the primary module used is the <u><i>xpcom.components</i></u>
module.&nbsp; Using this module, you can get a Python object that supports any
scriptable XPCOM interface. Once you have this Python object, you can
simply call XPCOM methods on the object, as normal.</p>
<p>The <u><i>xpcom.components</i></u> module defines the following public
members:</p>
<table border="1" width="100%">
<tr>
<td width="16%"><b>Name</b></td>
<td width="84%"><b>Description</b></td>
</tr>
<tr>
<td width="16%">classes</td>
<td width="84%">A mapping (dictionary-like object) used to get XPCOM
&quot;classes&quot;.&nbsp; These are indexed by XPCOM contract ID, just
like the JavaScript object of the same name.&nbsp;&nbsp;
<p>Example:</p>
<pre>cls = components.classes[&quot;@mozilla.org/sample;1&quot;]
ob = cls.createInstance() # Now have an nsISupports</pre>
</td>
</tr>
<tr>
<td width="16%">interfaces</td>
<td width="84%">An object that exposes all XPCOM interface IDs (IIDs).&nbsp;
Like the JavaScript object of the same name, this object uses
&quot;dot&quot; notation, as demonstrated below.
<p>Example:</p>
<pre>ob = cls.createInstance(components.interfaces.nsISample)
# Now have an nsISample</pre>
</td>
</tr>
</table>
<p>For many people, this is all you need to know. Consider the Mozilla Sample Component.&nbsp; The Mozilla Sample
Component has a contract ID of <i>@mozilla.org/sample;1</i>,
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)
# nsISample defines a &quot;value&quot; property - let's use it!
ob.value = &quot;new value&quot;
if ob.value != &quot;new value&quot;:
print &quot;Eeek - what happened?&quot;</pre>
<p>And that is it - a complete Python program that uses XPCOM.</p>
<h2><a name="Implementing">Implementing XPCOM Objects and Interfaces.</a></h2>
<p>Implementing XPCOM objects is almost as simple as using them. The
basic strategy is this:</p>
<ol>
<li>Create a standard Python source file, with a standard Python class.</li>
<li>Add some special <a href="#Attributes"> attributes</a> to your class for use by the Python XPCOM
framework. This controls the XPCOM behavior of your object.</li>
<li>Implement the XPCOM <a href="#Properties"> properties</a> and methods of your classes as normal.</li>
<li>Put the Python source file in the Mozilla <i> components</i> directory.</li>
<li>Run <i> regxpcom.</i></li>
</ol>
<p>Your component is now ready to be used.</p>
<h3><a name="Attributes">Attributes</a></h3>
<p>There are two classes of attributes: those used at runtime to define the object
behavior and those used at registration time to control object
registration.&nbsp; Not all objects require registration, thus not all
Python XPCOM objects will have registration-related attributes.</p>
<table border="1" width="100%">
<tr>
<td width="17%"><b>Attribute</b></td>
<td width="83%"><b>Description</b></td>
</tr>
<tr>
<td width="17%">_com_interfaces_</td>
<td width="83%">The interface IDs (IIDs) supported by the component.&nbsp;
For simplicity, this may be either a single IID, or a list of IIDs.&nbsp;
There is no need to specify base interfaces, as all parent interfaces are
automatically supported. Thus, it is never necessary to nominate <i>
nsISupports</i> in the list of interfaces.
<p>This attribute is required. Objects without such an attribute are
deemed unsuitable for use as a XPCOM object.</td>
</tr>
<tr>
<td width="17%">_reg_contractid_</td>
<td width="83%">The contract ID of the component.&nbsp; Required if the
component requires registration (i.e., exists in the components directory).</td>
</tr>
<tr>
<td width="17%">_reg_clsid_</td>
<td width="83%">The Class ID (CLSID) of the component, as a string in the
standard &quot;{XXX-XXX-XXX-XXX}&quot; format. Required if the
component requires registration (i.e., exists in the components directory).</td>
</tr>
<tr>
<td width="17%">_reg_registrar_</td>
<td width="83%">Nominates a function that is called at registration
time. The default is for no extra function to be called. This can
be useful if a component has special registration requirements and needs
to hook into the registration process.</td>
</tr>
<tr>
<td width="17%">_reg_desc_</td>
<td width="83%">The description of the XPCOM object. This may be used by
browsers or other such objects.&nbsp; If not specified, the contract ID
is used.</td>
</tr>
</table>
<h3><a name="Properties">Properties</a></h3>
<p>A Python class can support XPCOM properties in one of two ways.&nbsp; Either
a standard Python property of the same name can exist - our sample
component demonstrates this with the <i>boolean_value</i> property.&nbsp;
Alternatively, the class can provide the <i>get_propertyName(self)</i> and <i>set_propertyName(self,
value)</i> functions (with <i>propertyName</i> changed to the appropriate value for the
property), and these functions will be called instead.</p>
<h4>Example:&nbsp; The Python XPCOM Test Component</h4>
<p>As an example, examine the Python XPCOM Test Component.&nbsp; This
code can be found in <i>py_test_component.py</i>.</p>
<pre>from xpcom import components
class PythonTestComponent:
_com_interfaces_ = components.interfaces.nsIPythonTestInterface
_reg_clsid_ = &quot;{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}&quot;
_reg_contractid_ = &quot;Python.TestComponent&quot;
def __init__(self):
self.boolean_value = 1
...
def do_boolean(self, p1, p2):
ret = p1 ^ p2
return ret, not ret, ret
...</pre>
<p><b>Note:</b> This component only specifies the mandatory attributes - <i>_com_interfaces</i>,
<i>_reg_clsid_</i> and <i>_reg_contractid_</i>.</p>
<p>This sample code demonstrates supporting the <i>boolean_value</i> attribute,
supported implicitly, as it is defined in the IDL and exists as a real Python
attribute of that name, and a method called <i>do_boolean</i>.</p>
<h4>Tip: The xpcom/xpt.py Script</h4>
<p> The xpcom/xpt.py script is a useful script that can generate the skeleton of a class for
any XPCOM interface.&nbsp; Just specify the interface name on the command-line,
and paste the output into your source file.</p>
<p>This is the output of running this program over the <i>nsISample</i>
interface (i.e., assuming we wanted to implement a component that supported this
interface):</p>
<pre>class nsISample:
_com_interfaces_ = xpcom.components.interfaces.nsISample
# If this object needs to be registered, the following 2 are also needed.
# _reg_clsid_ = {a new clsid generated for this object}
# _reg_contractid_ = &quot;The.Object.Name&quot;
def get_value( self ):
# Result: string
pass
def set_value( self, param0 ):
# Result: void - None
# In: param0: string
pass
def writeValue( self, param0 ):
# Result: void - None
# In: param0: string
pass
def poke( self, param0 ):
# Result: void - None
# In: param0: string
pass</pre>
<p><b>Note:</b> The types of the parameters and the function itself are included in
the comments.&nbsp;You need to implement the functions
themselves.&nbsp; Another advantage of this script is that the <a href="#HiddenParams">hidden
parameters</a> are handled for you; the comments indicate when parameters
have been hidden.</p>
<h2><a name="Parameters">Parameters and Types</a></h2>
<p>This section briefly describes the XPCOM type support in
Python.</p>
<p>All XPCOM interfaces define parameters of a specific type.&nbsp; There is
currently no concept of a variant, or union of all types. Thus, the
conversion rules are very straightforward, and generally surprise free: for
any given XPCOM method, there is only one possible type for a given parameter.</p>
<h3>Type Conversion Rules:</h3>
<ul>
<li>All numeric types will attempt to be coerced to the correct type.&nbsp;
Thus, you can pass a Python float to an XPCOM method expecting an integer,
or vice-versa. Specifically, when an integer is required, you can pass
any Python object for which <i>int()</i> would succeed; for a Python float,
any object for which <i>float()</i> would succeed is acceptable.&nbsp; This
means that you can pass a Python string object as an integer, as long as the
string was holding a valid integer.</li>
<li>Strings and Unicode objects are interchangeable, but no other automatic
string conversions are performed.&nbsp; Thus, you can not pass an integer
where a string is expected, even though the reverse is true.</li>
<li>Any sequence object can be passed as an array.&nbsp; List objects are
always returned for arrays.</li>
<li>Any Python instance suitable for use as a XPCOM object (i.e., with the
<a href="#Implementing">necessary annotations</a>) can be
passed as a XPCOM object. No special wrapping step is needed to turn a
Python instance into a XPCOM object.&nbsp; Note you must pass a class <i>instance</i>,
not the class itself.</li>
<li><a name="HiddenParams">Many XPCOM <b> method signatures</b> specify
&quot;count&quot; or &quot;size&quot; parameters.&nbsp; For example, every
time an array is passed via XPCOM, the method signature will always specify
an integer that holds the count of the array.&nbsp; These parameters are
always hidden in Python.&nbsp; As the size param can be implied from the
length of the Python sequence passed, the Python programmer need never pass
these parameters;&nbsp;in contrast, JavaScript requires these redundant parameters.</a></li>
</ul>
</body>
</html>

View File

@@ -0,0 +1,298 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
"""Implementation of Python file objects for Mozilla/xpcom.
Introduction:
This module defines various class that are implemented using
Mozilla streams. This allows you to open Mozilla URI's, and
treat them as Python file object.
Example:
>>> file = URIFile("chrome://whatever")
>>> data = file.read(5) # Pass no arg to read everything.
Known Limitations:
* Not all URL schemes will work from "python.exe" - most notably
"chrome://" and "http://" URLs - this is because a simple initialization of
xpcom by Python does not load up the full set of Mozilla URL handlers.
If you can work out how to correctly initialize the chrome registry and
setup a message queue.
Known Bugs:
* Only read ("r") mode is supported. Although write ("w") mode doesnt make
sense for HTTP type URLs, it potentially does for file:// etc type ones.
* No concept of text mode vs binary mode. It appears Mozilla takes care of
this internally (ie, all "text/???" mime types are text, rest are binary)
"""
from xpcom import components, Exception, _xpcom
import os
import threading # for locks.
NS_RDONLY = components.interfaces.nsIFileChannel.NS_RDONLY
NS_WRONLY = components.interfaces.nsIFileChannel.NS_WRONLY
NS_RDWR = components.interfaces.nsIFileChannel.NS_RDWR
NS_CREATE_FILE = components.interfaces.nsIFileChannel.NS_CREATE_FILE
NS_APPEND = components.interfaces.nsIFileChannel.NS_APPEND
NS_TRUNCATE = components.interfaces.nsIFileChannel.NS_TRUNCATE
NS_SYNC = components.interfaces.nsIFileChannel.NS_SYNC
NS_EXCL = components.interfaces.nsIFileChannel.NS_EXCL
# A helper function - you pass a progID, an interface, plus optionally the
# name of the "constructor" and its args.
def _construct(progid, interface, ctor = None, *args):
assert (ctor is None and not args) or (ctor is not None and args), \
"no point having a ctor with no args, or if you provide args, there must be a ctor!"
instance = components.classes[progid] \
.createInstance(interface)
if ctor is not None:
ctor = getattr(instance, ctor)
apply(ctor, args)
return instance
# A helper function that may come in useful
def LocalFileToURL(localFileName):
"Convert a filename to an XPCOM nsIFileURL object."
# Create an nsILocalFile
localFile = components.classes["@mozilla.org/file/local;1"] \
.createInstance(components.interfaces.nsILocalFile)
localFile.initWithPath(localFileName)
# Create a standard URL, but we QI for the FileURL interface!
url = components.classes["@mozilla.org/network/standard-url;1"] \
.createInstance(components.interfaces.nsIFileURL)
# Setting the "file" attribute causes initialization...
url.file = localFile
return url
# A base class for file objects.
class _File:
def __init__(self, name_thingy = None, mode="r"):
self.lockob = threading.Lock()
self.inputStream = self.outputStream = None
if name_thingy is not None:
self.init(name_thingy, mode)
def __del__(self):
self.close()
# The Moz file streams are not thread safe.
def _lock(self):
self.lockob.acquire()
def _release(self):
self.lockob.release()
def read(self, n = -1):
assert self.inputStream is not None, "Not setup for read!"
self._lock()
try:
return str(self.inputStream.read(n))
finally:
self._release()
def readlines(self):
# Not part of the xpcom interface, but handy for direct Python users.
# Not 100% faithful, but near enough for now!
lines = self.read().split("\n")
if len(lines) and len(lines[-1]) == 0:
lines = lines[:-1]
return [s+"\n" for s in lines ]
def write(self, data):
assert self.outputStream is not None, "Not setup for write!"
self._lock()
try:
self.outputStream.write(data, len(data))
finally:
self._release()
def close(self):
self._lock()
try:
if self.inputStream is not None:
self.inputStream.close()
self.inputStream = None
if self.outputStream is not None:
self.outputStream.close()
self.outputStream = None
self.channel = None
# leave self.fileInst alone - it should be available after close.
finally:
self._release()
def flush(self):
self._lock()
try:
if self.outputStream is not None: self.outputStream.flush()
finally:
self._release()
# A synchronous "file object" used to open a URI.
class URIFile(_File):
def init(self, url, mode="r"):
self.close()
if mode != "r":
raise ValueError, "only 'r' mode supported'"
io_service = components.classes["@mozilla.org/network/io-service;1"] \
.createInstance("nsIIOService")
if hasattr(url, "queryInterface"):
url_ob = url
else:
url_ob = components.classes["@mozilla.org/network/standard-url;1"] \
.createInstance(components.interfaces.nsIURL)
url_ob.spec = url
# Mozilla asserts and starts saying "NULL POINTER" if this is wrong!
if not url_ob.scheme:
raise ValueError, ("The URI '%s' is invalid (no scheme)"
% (url_ob.spec,))
self.channel = io_service.newChannelFromURI(url_ob)
self.inputStream = self.channel.openInputStream()
# A "file object" implemented using Netscape's native file support.
# Based on io.js - http://lxr.mozilla.org/seamonkey/source/xpcom/tests/utils/io.js
# You open this file using a local file name (as a string) so it really is pointless -
# you may as well be using a standard Python file object!
class LocalFile(_File):
def init(self, name, mode = "r"):
name = os.path.abspath(name) # Moz libraries under Linux fail with relative paths.
self.close()
self.fileInst = _construct('@mozilla.org/file/local;1', "nsILocalFile", "initWithPath", name)
self.inputStream = None
self.channel = None
if mode in ["w","a"]:
if mode== "w":
if self.fileInst.exists():
self.fileInst.delete(0)
moz_mode = NS_CREATE_FILE | NS_WRONLY
elif mode=="a":
moz_mode = NS_APPEND
else:
assert 0, "Can't happen!"
perms = 0644
if not self.fileInst.exists():
self.fileInst.create(components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, 0644)
self.channel = _construct('@mozilla.org/network/local-file-channel;1', "nsIFileChannel", "init",
self.fileInst, moz_mode, perms)
self.outputStream = self.channel.openOutputStream()
self.fileInst.permissions = perms
elif mode == "r":
self.channel = _construct('@mozilla.org/network/local-file-channel;1', "nsIFileChannel", "init",
self.fileInst, NS_RDONLY, self.fileInst.permissions)
self.inputStream = self.channel.openInputStream()
else:
raise ValueError, "Unknown mode"
def read(self, n = -1):
if n == -1:
n = self.fileInst.fileSize
return _File.read(self, n)
##########################################################
##
## Test Code
##
##########################################################
def _DoTestRead(file, expected):
# read in a couple of chunks, just to test that our various arg combinations work.
got = file.read(3)
got = got + file.read(300)
got = got + file.read(0)
got = got + file.read()
if got != expected:
raise RuntimeError, "Reading '%s' failed - got %d bytes, but expected %d bytes" % (file, len(got), len(expected))
def _DoTestBufferRead(file, expected):
# read in a couple of chunks, just to test that our various arg combinations work.
buffer = _xpcom.AllocateBuffer(50)
got = ''
while 1:
# Note - we need to reach into the file object so we
# can get at the native buffer supported function.
num = file.inputStream.read(buffer)
if num == 0:
break
got = got + str(buffer[:num])
if got != expected:
raise RuntimeError, "Reading '%s' failed - got %d bytes, but expected %d bytes" % (file, len(got), len(expected))
def _TestLocalFile():
import tempfile, os
fname = tempfile.mktemp()
data = "Hello from Python"
test_file = LocalFile(fname, "w")
try:
test_file.write(data)
test_file.close()
# Make sure Python can read it OK.
f = open(fname, "r")
if f.read() != data:
print "Eeek - Python could not read the data back correctly!"
f.close()
# For the sake of the test, try a re-init.
test_file.init(fname, "r")
got = str(test_file.read())
if got != data:
print "Read the wrong data back - %r" % (got,)
else:
print "Read the correct data."
test_file.close()
# Try reading in chunks.
test_file = LocalFile(fname, "r")
got = test_file.read(10) + test_file.read()
if got != data:
print "Chunks the wrong data back - %r" % (got,)
else:
print "Chunks read the correct data."
test_file.close()
# XXX - todo - test "a" mode!
finally:
try:
os.unlink(fname)
except OSError, details:
print "Error removing temp test file:", details
def _TestAll():
# A mini test suite.
# Get a test file, and convert it to a file:// URI.
# check what we read is the same as when
# we read this file "normally"
fname = components.__file__
if fname[-1] in "cCoO": # fix .pyc/.pyo
fname = fname[:-1]
expected = open(fname, "rb").read()
# convert the fname to a URI.
url = LocalFileToURL(fname)
# First try passing a URL as a string.
_DoTestRead( URIFile( url.spec), expected)
print "Open as string test worked."
# Now with a URL object.
_DoTestRead( URIFile( url ), expected)
print "Open as URL test worked."
_DoTestBufferRead( URIFile( url ), expected)
print "File test using buffers worked."
# For the sake of testing, do our pointless, demo object!
_DoTestRead( LocalFile(fname), expected )
print "Local file read test worked."
# Now do the full test of our pointless, demo object!
_TestLocalFile()
def _TestURI(url):
test_file = URIFile(url)
print "Opened file is", test_file
got = test_file.read()
print "Read %d bytes of data from %r" % (len(got), url)
test_file.close()
if __name__=='__main__':
import sys
if len(sys.argv) < 2:
print "No URL specified on command line - performing self-test"
_TestAll()
else:
_TestURI(sys.argv[1])

View File

@@ -0,0 +1,217 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Dumb makefile to build PyXPCOM on linux
#
# The build is by no means clean. I just kept shoving in compiler and linker
# options until it worked. :)
#
# USAGE:
# 1. edit top section as appropriate
# 2. build, install, and test PyXPCOM
# > make -f makefile.stupid.linux DEBUG=1
# > make -f makefile.stupid.linux DEBUG=1 install
# > make -f makefile.stupid.linux DEBUG=1 test
# A debug build is suggested (DEBUG=1) by default because a default
# mozilla build is a debug build. Exclude the "DEBUG=1" to build for a
# release build of mozilla.
#
#-------------------------
# You must edit the variables in this section as appropriate for your machine
# The most common edits will just be:
# MOZ_SRC, INSTALLDIR, and PYTHON_SRC
# =========== START OF SECTION FOR COMMON EDITS =====================
# We expect a "mozilla" directory under this
MOZ_SRC=/home/skip/src
# this will have an "xpcom" subdir on install
INSTALLDIR=/usr/local/ActivePython-2.0/lib/python2.0/site-packages
PYTHON_SRC=/usr/local/ActivePython-2.0
# =========== START OF SECTION FOR COMMON EDITS =====================
MOZCOMPONENTSDIR=$(MOZ_SRC)/mozilla/dist/bin/components
MOZINCLUDES=-I$(MOZ_SRC)/mozilla/dist/include
MOZLIBDIR=$(MOZ_SRC)/mozilla/dist/lib
# this is setup to use the *installed* Python directory structure
# - To use the development Python dir structure some changes are
# necessary here *and* below (below, because there two lib dir
# to include in LDFLAGS for the dev dir structure)
PYTHON_SRC=/usr/local/ActivePython-2.0
PYTHONINCLUDES=-I$(PYTHON_SRC)/include/python2.0
PYTHONLIBDIR=$(PYTHON_SRC)/lib/python2.0/config
XPIDL=$(MOZ_SRC)/mozilla/dist/bin/xpidl
IDLINCLUDES=-I$(MOZ_SRC)/mozilla/dist/idl
#-------------------------
# You should not need to edit anything beyond this point.
#
# the main PyXPCOM engine library
ENGINE=src/_xpcommodule.so
# the PyXPCOM loader
LOADER=src/loader/libpyloader.so
all:: $(ENGINE) $(LOADER)
#---- build the PyXPCOM loader
LOADER_CFLAGS=-fpic -fno-rtti -fno-exceptions -Wconversion \
-Wpointer-arith -Wbad-function-cast -Wcast-align -Woverloaded-virtual \
-Wsynth -pedantic -Wno-long-long -pthread -DTRIMMED
ifdef DEBUG
LOADER_CFLAGS += -DDEBUG
endif
# NOTE: not sure if using -rpath is the best way to do this
LOADER_LDFLAGS=-Xlinker -rpath -Xlinker $(MOZLIBDIR) \
-Xlinker -rpath -Xlinker $(MOZLIBDIR)/components \
-Xlinker -rpath -Xlinker $(PYTHONLIBDIR) \
-L$(MOZLIBDIR) -L$(PYTHONLIBDIR)
# NOTE: can't remember if "-shared" is necessary here
LOADER_LIBS=-lpython2.0 -ldl -lpthread -ldb -lutil -shared -lxpcom
$(LOADER): src/loader/pyloader.cpp
c++ $(LOADER_CFLAGS) $(MOZINCLUDES) $(PYTHONINCLUDES) \
-c src/loader/pyloader.cpp \
-o src/loader/pyloader.o
c++ $(LOADER_CFLAGS) $(LOADER_LDFLAGS) $(LOADER_LIBS) \
-o $(LOADER) \
src/loader/pyloader.o
#---- build the PyXPCOM engine
ENGINE_CFLAGS=-fpic -fno-rtti -fno-exceptions -Wconversion \
-Wpointer-arith -Wbad-function-cast -Wcast-align -Woverloaded-virtual \
-Wsynth -pedantic -Wno-long-long -pthread -DTRIMMED -nostdlib
ifdef DEBUG
ENGINE_CFLAGS += -DDEBUG
endif
# -DXPCOM_EXPORTS
XPCOM_SRC_OBJECTS = \
src/ErrorUtils.o \
src/PyGBase.o \
src/PyGModule.o \
src/PyGStub.o \
src/PyGInputStream.o \
src/PyGWeakReference.o \
src/PyIComponentManager.o \
src/PyIInputStream.o \
src/PyIEnumerator.o \
src/PyIID.o \
src/PyIInterfaceInfo.o \
src/PyIInterfaceInfoManager.o \
src/PyIServiceManager.o \
src/PyISimpleEnumerator.o \
src/PyISupports.o \
src/Pyxpt_info.o \
src/TypeObject.o \
src/VariantUtils.o \
src/dllmain.o \
src/xpcom.o
%.o: %.cpp
c++ $(ENGINE_CFLAGS) $(MOZINCLUDES) $(PYTHONINCLUDES) \
-c $< -o $@
# NOTE: not sure if using -rpath is the best way to do this
# NOTE: can't remember if "-shared" is necessary here
ENGINE_LDFLAGS=-Xlinker -rpath -Xlinker $(MOZLIBDIR) \
-Xlinker -rpath -Xlinker $(MOZLIBDIR)/components \
-Xlinker -rpath -Xlinker $(PYTHONLIBDIR) \
-Xlinker -shared
ENGINE_LIBS=-lpython2.0 -ldl -lpthread -ldb -lutil -lxpcom \
-lnspr4 -lgtk -lgdk -rdynamic -lgmodule -lglib -lm -lplc4 \
-lpthread -lnsl -lresolv -lm -lc -lgcc
$(ENGINE): $(XPCOM_SRC_OBJECTS)
c++ $(ENGINE_CFLAGS) $(ENGINE_LDFLAGS) -o $(ENGINE) \
$(XPCOM_SRC_OBJECTS) -L$(MOZLIBDIR) -L$(PYTHONLIBDIR) $(ENGINE_LIBS)
#---- install PyXPCOM
XPCOM_PACKAGE_FILES = \
__init__.py \
components.py \
file.py \
nsError.py \
register.py \
xpcom_consts.py \
xpt.py \
client/__init__.py \
server/__init__.py \
server/enumerator.py \
server/factory.py \
server/loader.py \
server/module.py \
server/policy.py
# this is a cheasy install
# - no attention to permissions
# - doesn't explicitly use $(XPCOM_PACKAGE_FILES)
install:: all $(XPCOM_PACKAGE_FILES)
mkdir -p $(INSTALLDIR)/xpcom/client
mkdir -p $(INSTALLDIR)/xpcom/server
cp -f *.py $(INSTALLDIR)/xpcom
cp -f client/*.py $(INSTALLDIR)/xpcom/client
cp -f server/*.py $(INSTALLDIR)/xpcom/server
cp -f $(ENGINE) $(INSTALLDIR)/xpcom
mkdir -p $(MOZCOMPONENTSDIR)
cp -f $(LOADER) $(MOZCOMPONENTSDIR)
( \
export PYTHONPATH=$(INSTALLDIR):$(PYTHONPATH) ; \
export MOZILLA_FIVE_HOME=$(MOZ_SRC)/mozilla/dist/bin ; \
export LD_LIBRARY_PATH=$(MOZ_SRC)/mozilla/dist/bin ; \
$(MOZ_SRC)/mozilla/dist/bin/regxpcom \
)
#---- build and run the PyXPCOM test suite
all:: test/test_component/py_test_component.xpt
test/test_component/py_test_component.xpt: test/test_component/py_test_component.idl
$(XPIDL) -m typelib -w $(IDLINCLUDES) -o test/test_component/py_test_component $<
install::
mkdir -p $(MOZCOMPONENTSDIR)
cp -f test/test_component/py_test_component.xpt $(MOZCOMPONENTSDIR)
cp -f test/test_component/py_test_component.py $(MOZCOMPONENTSDIR)
( \
export PYTHONPATH=$(INSTALLDIR):$(PYTHONPATH) ; \
export MOZILLA_FIVE_HOME=$(MOZ_SRC)/mozilla/dist/bin ; \
export LD_LIBRARY_PATH=$(MOZ_SRC)/mozilla/dist/bin ; \
$(MOZ_SRC)/mozilla/dist/bin/regxpcom \
)
test:: install
( \
export PYTHONPATH=$(INSTALLDIR):$(PYTHONPATH) ; \
export MOZILLA_FIVE_HOME=$(MOZ_SRC)/mozilla/dist/bin ; \
export LD_LIBRARY_PATH=$(MOZ_SRC)/mozilla/dist/bin ; \
python test/regrtest.py \
)
runpython: install
( \
export PYTHONPATH=$(INSTALLDIR):$(PYTHONPATH) ; \
export MOZILLA_FIVE_HOME=$(MOZ_SRC)/mozilla/dist/bin ; \
export LD_LIBRARY_PATH=$(MOZ_SRC)/mozilla/dist/bin ; \
python \
)
clean:
find . -name "*~" | xargs rm -f
find . -name "*.o" | xargs rm -f
find . -name "*.pyc" | xargs rm -f
find . -name "*.so" | xargs rm -f

View File

@@ -0,0 +1,223 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Dumb makefile to build PyXPCOM on Windows
#
# The build is by no means clean. I just kept shoving in compiler and linker
# options until it worked. :)
#
# USAGE:
# 1. edit top section as appropriate
# 2. build, install, and test PyXPCOM
# > nmake -f makefile.stupid.win
# > nmake -f makefile.stupid.win install
# > nmake -f makefile.stupid.win test
#----------------------------------------------------------------------------
# You must edit the variables in this section as appropriate for your machine
# The most common edits will just be:
# MOZ_SRC, INSTALLDIR, and PYTHON_SRC
# ========= START OF SECTION FOR COMMON EDITS ==============
# We expect a "mozilla" directory under this
MOZ_SRC=c:\src
# this will have an "xpcom" subdir on install
INSTALLDIR=C:\Python20
# this is setup to use the *installed* Python directory structure
PYTHON_SRC=C:\Python20
# ========= END OF SECTION FOR COMMON EDITS ==============
!IF DEFINED(DEBUG)
MOZ_BUILD_DIR=$(MOZ_SRC)\mozilla\dist\WIN32_D.OBJ
PYTHON_EXE=python_d.exe
!ELSE
MOZ_BUILD_DIR=$(MOZ_SRC)\mozilla\dist\WIN32_O.OBJ
PYTHON_EXE=python.exe
!ENDIF
MOZCOMPONENTSDIR=$(MOZ_BUILD_DIR)\bin\components
MOZINCLUDES=/I$(MOZ_SRC)\mozilla\dist\include /I$(MOZ_BUILD_DIR)\include
MOZLIBS=/LIBPATH:$(MOZ_BUILD_DIR)\lib
# this is setup to use the *installed* Python directory structure
# - To use the development Python dir structure some changes are
# necessary here *and* below (below, because there two lib dir
# to include in LDFLAGS for the dev dir structure)
PYTHONINCLUDES=/I$(PYTHON_SRC)\include
PYTHONLIBS=/LIBPATH:$(PYTHON_SRC)\libs
MOZ_BIN=$(MOZ_BUILD_DIR)\bin
XPIDL=$(MOZ_BIN)\xpidl.exe
IDLINCLUDES=-I$(MOZ_SRC)\mozilla\dist\idl
REGXPCOM=$(MOZ_BIN)\regxpcom.exe
#----------------------------------------------------------------------------
# You should not need to edit anything beyond this point.
#
# the main PyXPCOM engine library
!IF DEFINED(DEBUG)
ENGINE=src\_xpcom_d.pyd
# the PyXPCOM loader
LOADER=src\loader\pyloader_d.dll
!ELSE
ENGINE=src\_xpcom.pyd
# the PyXPCOM loader
LOADER=src\loader\pyloader.dll
!ENDIF
all:: $(ENGINE) $(LOADER)
#---- build the PyXPCOM loader
!IF DEFINED(DEBUG)
LOADER_CFLAGS_THIS_BUILD=/ZI /MDd /Od /DDEBUG /D_DEBUG
LOADER_LDFLAGS_THIS_BUILD=/debug
!ELSE
LOADER_CFLAGS_THIS_BUILD=/MD /Ox /DNDEBUG /D_NDEBUG
LOADER_LDFLAGS_THIS_BUILD=
!ENDIF
LOADER_CFLAGS=/W3 /D WIN32 /D _WINDOWS /D XPCOM_EXPORTS $(LOADER_CFLAGS_THIS_BUILD)
LOADER_LDFLAGS=/dll $(LOADER_LDFLAGS_THIS_BUILD)
$(LOADER): src\loader\pyloader.cpp
cl /nologo $(LOADER_CFLAGS) $(MOZINCLUDES) $(PYTHONINCLUDES) \
/c src\loader\pyloader.cpp \
/Fosrc\loader\pyloader.obj
link $(LOADER_LDFLAGS) $(PYTHONLIBS) $(MOZLIBS) \
/out:$(LOADER) \
src\loader\pyloader.obj \
xpcom.lib
#---- build the PyXPCOM engine
!IF DEFINED(DEBUG)
ENGINE_CFLAGS_THIS_BUILD=/ZI /MDd /Od /DDEBUG /D_DEBUG
!ELSE
ENGINE_CFLAGS_THIS_BUILD=/MD /Ox /DNDEBUG /D_NDEBUG
!ENDIF
ENGINE_CFLAGS=/D _USRDLL /W3 /D WIN32 /D _WINDOWS /D XPCOM_EXPORTS $(ENGINE_CFLAGS_THIS_BUILD)
XPCOM_SRC_OBJECTS = \
src\ErrorUtils.obj \
src\PyGBase.obj \
src\PyGModule.obj \
src\PyGStub.obj \
src\PyGInputStream.obj \
src\PyGWeakReference.obj \
src\PyIComponentManager.obj \
src\PyIInputStream.obj \
src\PyIEnumerator.obj \
src\PyIID.obj \
src\PyIInterfaceInfo.obj \
src\PyIInterfaceInfoManager.obj \
src\PyIServiceManager.obj \
src\PyISimpleEnumerator.obj \
src\PyISupports.obj \
src\Pyxpt_info.obj \
src\TypeObject.obj \
src\VariantUtils.obj \
src\dllmain.obj \
src\xpcom.obj
.cpp.obj:
cl /nologo $(ENGINE_CFLAGS) $(MOZINCLUDES) $(PYTHONINCLUDES) -c $< -Fo$@
!IF DEFINED(DEBUG)
ENGINE_LDFLAGS_THIS_BUILD=/debug
!ELSE
ENGINE_LDFLAGS_THIS_BUILD=
!ENDIF
#XXX for debug: ENGINE_LDFLAGS_DEBUG=/DEBUG
ENGINE_LDFLAGS=/dll /export:init_xpcom $(ENGINE_LDFLAGS_THIS_BUILD)
$(ENGINE): $(XPCOM_SRC_OBJECTS)
link $(ENGINE_LDFLAGS) $(XPCOM_SRC_OBJECTS) $(MOZLIBS) $(PYTHONLIBS) /out:$(ENGINE)
#---- install PyXPCOM
XPCOM_PACKAGE_FILES = \
__init__.py \
components.py \
file.py \
nsError.py \
register.py \
xpcom_consts.py \
xpt.py \
client\__init__.py \
server\__init__.py \
server\enumerator.py \
server\factory.py \
server\loader.py \
server\module.py \
server\policy.py
# this is a cheasy install
# - no attention to permissions
# - doesn't explicitly use $(XPCOM_PACKAGE_FILES)
install:: all $(XPCOM_PACKAGE_FILES)
if not exist $(INSTALLDIR) mkdir $(INSTALLDIR)
if not exist $(INSTALLDIR)\xpcom mkdir $(INSTALLDIR)\xpcom
if not exist $(INSTALLDIR)\xpcom\client mkdir $(INSTALLDIR)\xpcom\client
if not exist $(INSTALLDIR)\xpcom\server mkdir $(INSTALLDIR)\xpcom\server
if not exist $(INSTALLDIR)\xpcom\test mkdir $(INSTALLDIR)\xpcom\test
if not exist $(INSTALLDIR)\xpcom\test\output mkdir $(INSTALLDIR)\xpcom\test\output
copy /v /y *.py $(INSTALLDIR)\xpcom
copy /v /y client\*.py $(INSTALLDIR)\xpcom\client
copy /v /y server\*.py $(INSTALLDIR)\xpcom\server
copy /v /y test\*.py $(INSTALLDIR)\xpcom\test
copy /v /y test\output\* $(INSTALLDIR)\xpcom\test\output
copy /v /y $(ENGINE) $(INSTALLDIR)\xpcom
if not exist $(MOZCOMPONENTSDIR) mkdir $(MOZCOMPONENTSDIR)
copy /v /y $(LOADER) $(MOZCOMPONENTSDIR)
set PYTHONPATH=$(INSTALLDIR);$(PYTHONPATH)
set PATH=$(MOZ_BIN);$(PATH)
$(REGXPCOM)
#---- build and run the PyXPCOM test suite
all:: test\test_component\py_test_component.xpt
test\test_component\py_test_component.xpt: test\test_component\py_test_component.idl
$(XPIDL) -m typelib -w $(IDLINCLUDES) -o test\test_component\py_test_component test\test_component\py_test_component.idl
install::
if not exist $(MOZCOMPONENTSDIR) mkdir $(MOZCOMPONENTSDIR)
copy /v /y test\test_component\py_test_component.xpt $(MOZCOMPONENTSDIR)
copy /v /y test\test_component\py_test_component.py $(MOZCOMPONENTSDIR)
set PYTHONPATH=$(INSTALLDIR);$(PYTHONPATH)
set PATH=$(MOZ_BIN);$(PATH)
$(REGXPCOM)
test:: install
set PATH=$(MOZ_BIN);$(PATH)
set PYTHONPATH=$(INSTALLDIR);$(PYTHONPATH)
$(PYTHON_EXE) test\regrtest.py
runpython:: install
set PATH=$(MOZ_BIN);$(PATH)
set PYTHONPATH=$(INSTALLDIR);$(PYTHONPATH)
$(PYTHON_EXE)
clean:
-del /f /q src\*.obj
-del /f /q src\loader\*.obj
-del /f /q *.pyc
-del /f /q client\*.pyc
-del /f /q server\*.pyc
-del /f /q test\*.pyc

View File

@@ -0,0 +1,115 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Generated by h2py from nsError.h
# CMD line: h2py.py -i (nsresult) nsError.h
# XXX - NOTE - some manual code at the end, and all literals moved back to ints
NS_ERROR_MODULE_XPCOM = 1
NS_ERROR_MODULE_BASE = 2
NS_ERROR_MODULE_GFX = 3
NS_ERROR_MODULE_WIDGET = 4
NS_ERROR_MODULE_CALENDAR = 5
NS_ERROR_MODULE_NETWORK = 6
NS_ERROR_MODULE_PLUGINS = 7
NS_ERROR_MODULE_LAYOUT = 8
NS_ERROR_MODULE_HTMLPARSER = 9
NS_ERROR_MODULE_RDF = 10
NS_ERROR_MODULE_UCONV = 11
NS_ERROR_MODULE_REG = 12
NS_ERROR_MODULE_FILES = 13
NS_ERROR_MODULE_DOM = 14
NS_ERROR_MODULE_IMGLIB = 15
NS_ERROR_MODULE_MAILNEWS = 16
NS_ERROR_MODULE_EDITOR = 17
NS_ERROR_MODULE_XPCONNECT = 18
NS_ERROR_MODULE_PROFILE = 19
def NS_FAILED(_nsresult): return ((_nsresult) & 0x80000000)
NS_ERROR_SEVERITY_SUCCESS = 0
NS_ERROR_SEVERITY_ERROR = 1
NS_ERROR_MODULE_BASE_OFFSET = 0x45
def NS_ERROR_GET_CODE(err): return ((err) & 0xffff)
def NS_ERROR_GET_MODULE(err): return (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
def NS_ERROR_GET_SEVERITY(err): return (((err) >> 31) & 0x1)
NS_OK = 0
NS_COMFALSE = 1
NS_ERROR_BASE = ( 0xC1F30000)
NS_ERROR_NOT_INITIALIZED = (NS_ERROR_BASE + 1)
NS_ERROR_ALREADY_INITIALIZED = (NS_ERROR_BASE + 2)
NS_ERROR_NOT_IMPLEMENTED = ( 0x80004001)
NS_NOINTERFACE = ( 0x80004002)
NS_ERROR_NO_INTERFACE = NS_NOINTERFACE
NS_ERROR_INVALID_POINTER = ( 0x80004003)
NS_ERROR_NULL_POINTER = NS_ERROR_INVALID_POINTER
NS_ERROR_ABORT = ( 0x80004004)
NS_ERROR_FAILURE = ( 0x80004005)
NS_ERROR_UNEXPECTED = ( 0x8000ffff)
NS_ERROR_OUT_OF_MEMORY = ( 0x8007000e)
NS_ERROR_ILLEGAL_VALUE = ( 0x80070057)
NS_ERROR_INVALID_ARG = NS_ERROR_ILLEGAL_VALUE
NS_ERROR_NO_AGGREGATION = ( 0x80040110)
NS_ERROR_NOT_AVAILABLE = ( 0x80040111)
NS_ERROR_FACTORY_NOT_REGISTERED = ( 0x80040154)
NS_ERROR_FACTORY_REGISTER_AGAIN = ( 0x80040155)
NS_ERROR_FACTORY_NOT_LOADED = ( 0x800401f8)
NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT = \
(NS_ERROR_BASE + 0x101)
NS_ERROR_FACTORY_EXISTS = (NS_ERROR_BASE + 0x100)
NS_ERROR_PROXY_INVALID_IN_PARAMETER = ( 0x80010010)
NS_ERROR_PROXY_INVALID_OUT_PARAMETER = ( 0x80010011)
##### END OF GENERATED CODE
#####
def NS_ERROR_GENERATE_FAILURE(module,code):
return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
NS_BASE_STREAM_CLOSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2)
NS_BASE_STREAM_OSERROR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3)
NS_BASE_STREAM_ILLEGAL_ARGS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 4)
NS_BASE_STREAM_NO_CONVERTER = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5)
NS_BASE_STREAM_BAD_CONVERSION = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6)
NS_BASE_STREAM_WOULD_BLOCK = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 7)
NS_ERROR_FILE_UNRECOGNIZED_PATH = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 1)
NS_ERROR_FILE_UNRESOLVABLE_SYMLINK = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 2)
NS_ERROR_FILE_EXECUTION_FAILED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 3)
NS_ERROR_FILE_UNKNOWN_TYPE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 4)
NS_ERROR_FILE_DESTINATION_NOT_DIR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 5)
NS_ERROR_FILE_TARGET_DOES_NOT_EXIST = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 6)
NS_ERROR_FILE_COPY_OR_MOVE_FAILED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 7)
NS_ERROR_FILE_ALREADY_EXISTS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 8)
NS_ERROR_FILE_INVALID_PATH = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 9)
NS_ERROR_FILE_DISK_FULL = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 10)
NS_ERROR_FILE_CORRUPTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 11)
NS_ERROR_FILE_NOT_DIRECTORY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 12)
NS_ERROR_FILE_IS_DIRECTORY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 13)
NS_ERROR_FILE_IS_LOCKED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 14)
NS_ERROR_FILE_TOO_BIG = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 15)
NS_ERROR_FILE_NO_DEVICE_SPACE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 16)
NS_ERROR_FILE_NAME_TOO_LONG = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 17)
NS_ERROR_FILE_NOT_FOUND = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 18)
NS_ERROR_FILE_READ_ONLY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 19)
NS_ERROR_FILE_DIR_NOT_EMPTY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 20)
NS_ERROR_FILE_ACCESS_DENIED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 21)
## from netCore.h
NS_ERROR_ALREADY_CONNECTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 11)
NS_ERROR_NOT_CONNECTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 12)
NS_ERROR_IN_PROGRESS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 15)
NS_ERROR_OFFLINE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 16)
## from nsISocketTransportService.idl
NS_ERROR_CONNECTION_REFUSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 13)
NS_ERROR_NET_TIMEOUT = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 14)
# Status nsresult codes: used with nsIProgressEventSink::OnStatus
NS_NET_STATUS_RESOLVING_HOST = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 3)
NS_NET_STATUS_CONNECTED_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 4)
NS_NET_STATUS_SENDING_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 5)
NS_NET_STATUS_RECEIVING_FROM = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 6)
NS_NET_STATUS_CONNECTING_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 7)

View File

@@ -0,0 +1,91 @@
<html>
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Python XPCOM module</title>
</head>
<body>
<h1>Python XPCOM Package</h1>
<p>Version 0.91 - January 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
maintains the <a href="http://www.mozilla.org/projects/xpcom/">main XPCOM
project pages.</a>&nbsp; The Python XPCOM package is a set of Python bindings to
XPCOM, allowing a Python programmer to both use and implement XPCOM
interfaces.&nbsp; If you don't know what <a href="http://www.python.org">Python</a>
is, then none of this probably interests you at all!</p>
<p>This readme has links to the following information:</p>
<ul>
<li><a href="doc/configure.html">Building, Configuring and
Testing the Python
XPCOM Package</a></li>
<li><a href="doc/tutorial.html">A tutorial for the Python XPCOM package</a></li>
<li>Some <a href="doc/advanced.html">advanced
topics and other miscellaneous information</a></li>
<li><a href="doc/architecture.html">Information on the architecture</a></li>
<li>A list of the <a href="#KnownBugs">known issues and bugs</a>, the <a href="#ReleaseHistory">release
history</a> and the <a href="doc/credits.html">PyXPCOM acknowledgements</a></li>
</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
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>
<h2>About the Python XPCOM Package</h2>
<p>The Python XPCOM Package was developed by <a href="http://www.ActiveState.com">ActiveState
Tool Corporation</a>, and came out of their <a href="http://www.ActiveState.com/Products/Komodo">Komodo
project</a>.&nbsp; The Python XPCOM package is released under the <a href="http://www.mozilla.org/MPL/">Mozilla
Public License (MPL)</a></p>
<p>Please see the <a href="doc/credits.html">credits file</a> for a list of
contributors. </p>
<h2><a name="KnownBugs">Known Bugs</a>/Issues</h2>
<ul>
<li>No attempt is made to recurse sub-directories of the main
&quot;components&quot; directory.&nbsp; This is because we may decide on some
smart scheme for recursion (similar to Python packages), and don't want people
to rely on simple recursive searches.</li>
<li>No management of the PythonPath is done by the package.&nbsp; You must
arrange for the Python <i>xpcom</i> package to be on your PythonPath.&nbsp;
Significantly, the XPCOM <i> components</i> directory is not on the PythonPath and
generally cannot be, as Python will often find other DLLs in this directory and
attempt to use them as Python modules.&nbsp; This means that Python module
files will not be found in the <i> components</i> directory, even when referenced by
another component - thus, a component can&nbsp; not import another component
source file as a regular module!&nbsp; It is thought that when we know what to
do with sub-directories of the <i> components</i> directory (as described above), some
automated PythonPath support will be provided, so Python components and regular
Python modules the component depends on can exist in the same directory
structure.</li>
<li>No unregistration support at all.&nbsp;The main Python Component Loader supports
unregistration, but the actual Python objects themselves do not support unregistration.&nbsp;It is unclear if the Component Loader
unregistration process needs to manually remove each component it is responsible
for.</li>
<li>All Python-implemented components unconditionally support
weak-references.&nbsp; There is no way to disable this feature for any or all
components.&nbsp; It is unclear if there is a need to prevent this, but it is
documented here just in case!</li>
</ul>
<h2><a name="ReleaseHistory">Release History</a></h2>
<h3>Version 0.90 - January 2001</h3>
<ul>
<li>First public release.</li>
</ul>
<h3>Version 0.91 - January 2001</h3>
<ul>
<li>Fix a seg fault on Linux when PYTHONPATH is not set.</li>
<li>Changes to allow building with stand-alone XPCOM.</li>
</ul>
</body>
</html>

View File

@@ -0,0 +1,37 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import os, sys
def addSelf(fname):
#XXX the path hardcoding and env var reliance limits the usefulness
#XXX I don't even know if this is used, or usable, at all anymore.
try:
mozSrc = os.environ['MOZ_SRC']
except KeyError:
print "register.py: need MOZ_SRC to be set"
sys.exit(-1)
try:
komododist = os.environ['KOMODO']
except KeyError:
print "Set KOMODO"
sys.exit(-1)
bindir = os.path.join(mozSrc, "dist", "WIN32_D.OBJ", "bin")
idldir = os.path.join(mozSrc, "dist", "idl")
idl2dir = os.path.join(komododist, "SciMoz")
componentdir = os.path.normpath(os.path.join(bindir, 'components'))
base, ext = os.path.splitext(fname)
idlfile = base+'.idl'
pyfile = base+'.py'
xptfile = base+'.xpt'
if os.path.exists(idlfile):
# IDL file of same name exists, assume it needs to be updated
print r'%(bindir)s\xpidl -I %(idldir)s -I %(idl2dir)s -m typelib %(idlfile)s' % vars()
os.system(r'%(bindir)s\xpidl -I %(idldir)s -I %(idl2dir)s -m typelib %(idlfile)s' % vars())
print r'cp %(xptfile)s %(componentdir)s' % vars()
os.system(r'cp %(xptfile)s %(componentdir)s' % vars())
print 'cp %(pyfile)s %(componentdir)s' % vars()
os.system('cp %(pyfile)s %(componentdir)s' % vars())

View File

@@ -0,0 +1,38 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# The xpcom.server package.
from policy import DefaultPolicy
from xpcom import _xpcom
# We define the concept of a single "tracer" object - similar to the single
# Python "trace hook" for debugging. Someone can set
# xpcom.server.tracer to some class/function, and it will be used in place
# of the real xpcom object. Presumably this "trace" object will delegate
# to the real object, but presumably also taking some other action, such
# as calling a profiler or debugger.
tracer = None
# Wrap an instance in an interface (via a policy)
def WrapObject(ob, iid, policy = None):
"""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.
"""
if policy is None:
policy = DefaultPolicy
if tracer is not None:
ob = tracer(ob)
return _xpcom.WrapObject(policy( ob, iid ), iid)
# Create the main module for the Python loader.
# This is a once only init process, and the returned object
# if used to load all other Python components.
# This means that we keep all factories, modules etc implemented in
# Python!
def NS_GetModule( serviceManager, nsIFile ):
import loader
iid = _xpcom.IID_nsIModule
return WrapObject(loader.MakePythonComponentLoaderModule(serviceManager, nsIFile), iid)

View File

@@ -0,0 +1,24 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
from xpcom import components
# This class is created by Python components when it
# needs to return an enumerator.
# For example, a component may implement a function:
# nsISimpleEnumerator enumSomething();
# This could could simply say:
# return SimpleEnumerator([something1, something2, something3])
class SimpleEnumerator:
_com_interfaces_ = [components.interfaces.nsISimpleEnumerator]
def __init__(self, data):
self._data = data
self._index = 0
def hasMoreElements(self):
return self._index < len(self._data)
def getNext(self):
self._index = self._index + 1
return self._data[self._index-1]

View File

@@ -0,0 +1,36 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Class factory
#
# Hardly worth its own source file!
import xpcom
from xpcom import components, nsError, _xpcom
class Factory:
_com_interfaces_ = components.interfaces.nsIFactory
# This will only ever be constructed via other Python code,
# so we can have ctor args.
def __init__(self, klass):
self.klass = klass
def createInstance(self, outer, iid):
if outer is not None:
raise xpcom.ServerException(nsError.NS_ERROR_NO_AGGREGATION)
if xpcom.verbose:
print "Python Factory creating", self.klass.__name__
try:
return self.klass()
except:
# An exception here may not be obvious to the user - none
# of their code has been called yet. It can be handy on
# failure to tell the user what class failed!
_xpcom.LogWarning("Creation of class '%r' failed!\nException details follow\n" % (self.klass,))
raise
def lockServer(self, lock):
if xpcom.verbose:
print "Python Factory LockServer called -", lock

View File

@@ -0,0 +1,208 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import xpcom
from xpcom import components
import factory
import module
import glob, os, types
from xpcom.client import Component
fileSizeValueName = "FileSize"
lastModValueName = "LastModTimeStamp"
xpcomKeyName = "software/mozilla/XPCOM/components"
# Until we get interface constants.
When_Startup = 0
When_Component = 1
When_Timer = 2
def _has_good_attr(object, attr):
# Actually allows "None" to be specified to disable inherited attributes.
return getattr(object, attr, None) is not None
def FindCOMComponents(py_module):
# For now, just run over all classes looking for likely candidates.
comps = []
for name, object in py_module.__dict__.items():
if type(object)==types.ClassType and \
_has_good_attr(object, "_com_interfaces_") and \
_has_good_attr(object, "_reg_clsid_") and \
_has_good_attr(object, "_reg_contractid_"):
comps.append(object)
return comps
def register_self(compMgr, location, registryLocation, componentType):
pcl = PythonComponentLoader
from xpcom import _xpcom
svc = _xpcom.GetGlobalServiceManager().GetService("@mozilla.org/categorymanager;1", components.interfaces.nsICategoryManager)
svc.addCategoryEntry("component-loader", pcl._reg_component_type_, pcl._reg_contractid_, 1, 1)
class PythonComponentLoader:
_com_interfaces_ = components.interfaces.nsIComponentLoader
_reg_clsid_ = "{63B68B1E-3E62-45f0-98E3-5E0B5797970C}" # Never copy these!
_reg_contractid_ = "moz.pyloader.1"
_reg_desc_ = "Python component loader"
# Optional function which performs additional special registration
# Appears that no special unregistration is needed for ComponentLoaders, hence no unregister function.
_reg_registrar_ = (register_self,None)
# Custom attributes for ComponentLoader registration.
_reg_component_type_ = "script/python"
def __init__(self):
self.com_modules = {} # Keyed by module's FQN as obtained from nsIFile.path
def _getCOMModuleForLocation(self, componentFile):
fqn = componentFile.path
mod = self.com_modules.get(fqn)
if mod is not None:
return mod
import ihooks, sys
base_name = os.path.splitext(os.path.basename(fqn))[0]
loader = ihooks.ModuleLoader()
module_name_in_sys = "component:%s" % (base_name,)
stuff = loader.find_module(base_name, [componentFile.parent.path])
assert stuff is not None, "Couldnt find the module '%s'" % (base_name,)
py_mod = loader.load_module( module_name_in_sys, stuff )
# Make and remember the COM module.
comps = FindCOMComponents(py_mod)
mod = module.Module(comps)
self.com_modules[fqn] = mod
return mod
def getFactory(self, clsid, location, type):
# return the factory
assert type == self._reg_component_type_, "Being asked to create an object not of my type:%s" % (type,)
file_interface = components.manager.specForRegistryLocation(location)
# delegate to the module.
m = self._getCOMModuleForLocation(file_interface)
return m.getClassObject(components.manager, clsid, components.interfaces.nsIFactory)
def init(self, comp_mgr, registry):
# void
registry = registry.QueryInterface(components.interfaces.nsIRegistry)
try:
self.xpcom_registry_key = registry.getSubtree(
components.interfaces.nsIRegistry.Common,
xpcomKeyName)
# If we worked, we can use the registry!
self.registry = registry
except xpcom.Exception, details:
print "Registry failed", details
self.registry = None # no registry ops allowed
self.comp_mgr = comp_mgr
if xpcom.verbose:
print "Python component loader init() called"
# Called when a component of the appropriate type is registered,
# to give the component loader an opportunity to do things like
# annotate the registry and such.
def onRegister (self, clsid, type, className, proId, location, replace, persist):
if xpcom.verbose:
print "Python component loader - onRegister() called"
def autoRegisterComponents (self, when, directory):
directory_path = directory.path
print "Auto-registering all Python components in", directory_path
import traceback
# ToDo - work out the right thing here
# eg - do we recurse?
# - do we support packages?
entries = directory.directoryEntries
while entries.HasMoreElements():
entry = entries.GetNext(components.interfaces.nsIFile)
if os.path.splitext(entry.path)[1]==".py":
try:
self.autoRegisterComponent(when, entry)
except:
print "** Registration of '%s' failed!" % (entry.path,)
traceback.print_exc()
def autoRegisterComponent (self, when, componentFile):
# bool return
reg_loc = components.manager.registryLocationForSpec(componentFile)
# Use the registry to see if we actually need to do anything
if not self._hasChanged(reg_loc, componentFile):
return 1
# Sheesh - it appears we should also use the observer service
# to let the system know of our auto-register progress.
# auto-register via the module.
m = self._getCOMModuleForLocation(componentFile)
m.registerSelf(components.manager, componentFile, reg_loc, self._reg_component_type_)
self._setRegistryInfo(reg_loc, componentFile)
return 1
def autoUnregisterComponent (self, when, componentFile):
# bool return
# auto-unregister via the module.
m = self._getCOMModuleForLocation(componentFile)
reg_loc = components.manager.registryLocationForSpec(componentFile)
try:
m.unregisterSelf(components.manager, componentFile, reg_loc)
finally:
self._removeRegistryInfo( reg_loc, componentFile)
return 1
def registerDeferredComponents (self, when):
# bool return
if xpcom.verbose:
print "Python component loader - registerDeferred() called"
return 0 # no more to register
def unloadAll (self, when):
if xpcom.verbose:
print "Python component loader being asked to unload all components!"
self.registry = None
self.comp_mgr = None
self.com_modules = {}
# Internal Helpers
def _setRegistryInfo(self, registry_location, nsIFile):
if self.registry is None:
return # No registry work allowed.
e_location = self.registry.escapeKey(registry_location, 1)
if e_location is None: # No escaped key needed.
e_location = registry_location
key = self.registry.addSubtreeRaw(self.xpcom_registry_key, e_location)
self.registry.setLongLong(key, lastModValueName, nsIFile.lastModificationDate)
self.registry.setLongLong(key, fileSizeValueName, nsIFile.fileSize)
def _hasChanged(self, registry_location, nsIFile):
if self.registry is None:
# Can't cache in registry - assume it has changed.
return 1
e_location = self.registry.escapeKey(registry_location, 1)
if e_location is None: # No escaped key needed.
e_location = registry_location
try:
key = self.registry.getSubtreeRaw(self.xpcom_registry_key, e_location)
if nsIFile.lastModificationDate != self.registry.getLongLong(key, lastModValueName):
return 1
if nsIFile.fileSize != self.registry.getLongLong(key, fileSizeValueName):
return 1
return 0
except xpcom.Exception, details:
return 1
def _removeRegistryInfo(self, registry_location, nsIFile):
if self.registry is None:
return # No registry work allowed.
e_location = self.registry.escapeKey(registry_location, 1)
if e_location is None: # No escaped key needed.
e_location = registry_location
try:
key = self.registry.removeSubtreeRaw(self.xpcom_registry_key, e_location)
except xpcom.Exception, details:
pass
def MakePythonComponentLoaderModule(serviceManager, nsIFile):
import module
return module.Module( [PythonComponentLoader] )

View File

@@ -0,0 +1,75 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
from xpcom import components
from xpcom import ServerException, Exception
from xpcom import nsError
import factory
import types
import os
class Module:
_com_interfaces_ = components.interfaces.nsIModule
def __init__(self, comps):
# Build a map of classes we can provide factories for.
c = self.components = {}
for klass in comps:
c[components.ID(klass._reg_clsid_)] = klass
def getClassObject(self, compMgr, clsid, iid):
# Single retval result.
try:
klass = self.components[clsid]
except KeyError:
raise ServerException(nsError.NS_ERROR_FACTORY_NOT_REGISTERED)
# We can ignore the IID - the auto-wrapp process will automatically QI us.
return factory.Factory(klass)
def registerSelf(self, compMgr, location, registryLocation, componentType):
# void function.
for klass in self.components.values():
print "Registering: %s" % (klass.__name__,)
reg_contractid = klass._reg_contractid_
reg_desc = getattr(klass, "_reg_desc_", reg_contractid)
compMgr.registerComponentWithType(klass._reg_clsid_,
reg_desc,
reg_contractid,
location,
registryLocation,
1,
1,
componentType)
# See if this class nominates custom register_self
extra_func = getattr(klass, "_reg_registrar_", (None,None))[0]
if extra_func is not None:
extra_func(compMgr, location, registryLocation, componentType)
print "Registered %d Python components in %s" % (len(self.components),os.path.basename(location.path))
def unregisterSelf(self, compMgr, location, registryLocation):
# void function.
for klass in self.components.values():
ok = 1
try:
compMgr.unregisterComponentSpec(klass._reg_clsid_, location)
except Exception:
ok = 0
# Give the class a bash even if we failed!
extra_func = getattr(klass, "_reg_registrar_", (None,None))[1]
if extra_func is not None:
try:
extra_func(compMgr, location, registryLocation)
except Exception:
ok = 0
if ok:
print "Successfully unregistered", klass.__name__
else:
print "Unregistration of", klass.__name__, "failed. (probably just not already registered)"
def canUnload(self, compMgr):
# single bool result
return 0 # we can never unload!

View File

@@ -0,0 +1,211 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
from xpcom import xpcom_consts, _xpcom, client, nsError, ServerException, COMException
import xpcom
import traceback
import xpcom.server
import operator
_supports_primitives_map_ = {} # Filled on first use.
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:
ret = [ret]
real_ret = []
# For each interface, walk to the root of the interface tree.
iim = _xpcom.XPTI_GetInterfaceInfoManager()
for interface in ret:
try:
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 = parent.GetParent()
return real_ret
class DefaultPolicy:
def __init__(self, instance, iid):
self._obj_ = instance
self._nominated_interfaces_ = ni = _GetNominatedInterfaces(instance)
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)
# Stuff for the magic interface conversion.
self._interface_info_ = None
self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index)
def _QueryInterface_(self, com_object, iid):
# Framework allows us to return a single boolean integer,
# or a COM object.
if iid in self._nominated_interfaces_:
# We return the underlying object re-wrapped
# in a new gateway - which is desirable, as one gateway should only support
# one interface (this wont affect the users of this policy - we can have as many
# gateways as we like pointing to the same Python objects - the users never
# see what object the call came in from.
# 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)
# See if the instance has a QI
# use lower-case "_query_interface_" as win32com does, and it doesnt really matter.
delegate = getattr(self._obj_, "_query_interface_", None)
if delegate is not None:
# The COM object itself doesnt get passed to the child
# (again, as win32com doesnt). It is rarely needed
# (in win32com, we dont even pass it to the policy, although we have identified
# one place where we should - for marshalling - so I figured I may as well pass it
# to the policy layer here, but no all the way down to the object.
return delegate(iid)
# Finally see if we are being queried for one of the "nsISupports primitives"
if not _supports_primitives_map_:
iim = _xpcom.XPTI_GetInterfaceInfoManager()
for (iid_name, attr, cvt) in _supports_primitives_data_:
special_iid = iim.GetInfoForName(iid_name).GetIID()
_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)
# Out of clever things to try!
return None # We dont support this IID.
def _MakeInterfaceParam_(self, interface, iid, method_index, mi, param_index):
# Wrap a "raw" interface object in a nice object. The result of this
# function will be passed to one of the gateway methods.
if iid is None:
# look up the interface info - this will be true for all xpcom called interfaces.
if self._interface_info_ is None:
import xpcom.xpt
self._interface_info_ = xpcom.xpt.Interface( self._iid_ )
iid = self._interface_iid_map_.get( (method_index, param_index))
if iid is None:
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)
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):
# Look for a function of that name
func = getattr(self._obj_, "get_" + name, None)
if func is None:
assert len(param_descs)==1 and len(params)==0, "Can only handle a single [out] arg for a default getter"
ret = getattr(self._obj_, name) # Let attribute error go here!
else:
ret = func(*params)
return 0, ret
elif xpcom_consts.XPT_MD_IS_SETTER(flags):
# Look for a function of that name
func = getattr(self._obj_, "set_" + name, None)
if func is None:
assert len(param_descs)==1 and len(params)==1, "Can only handle a single [in] arg for a default setter"
setattr(self._obj_, name, params[0]) # Let attribute error go here!
else:
func(*params)
return 0
else:
# A regular method.
func = getattr(self._obj_, name)
return 0, func(*params)
def _doHandleException(self, func_name, exc_info):
exc_val = exc_info[1]
is_server_exception = isinstance(exc_val, ServerException)
if is_server_exception:
if xpcom.verbose:
print "** Information: '%s' raised COM Exception %s" % (func_name, exc_val)
traceback.print_exception(exc_info[0], exc_val, exc_info[2])
print "** Returning nsresult from existing exception", exc_val
return exc_val.errno
# Unhandled exception - always print a warning.
print "** Unhandled exception calling '%s'" % (func_name,)
traceback.print_exception(exc_info[0], exc_val, exc_info[2])
print "** Returning nsresult of NS_ERROR_FAILURE"
return nsError.NS_ERROR_FAILURE
# Called whenever an unhandled Python exception is detected as a result
# of _CallMethod_ - this exception may have been raised during the _CallMethod_
# invocation, or after its return, but when unpacking the results
# eg, type errors, such as a Python integer being used as a string "out" param.
def _CallMethodException_(self, com_object, index, info, params, exc_info):
# Later we may want to have some smart "am I debugging" flags?
# Or maybe just delegate to the actual object - it's probably got the best
# idea what to do with them!
flags, name, param_descs, ret = info
exc_typ, exc_val, exc_tb = exc_info
# use the xpt module to get a better repr for the method.
# But if we fail, ignore it!
try:
import xpcom.xpt
m = xpcom.xpt.Method(info, index, None)
func_repr = m.Describe().lstrip()
except:
func_repr = "%s(%r)" % (name, param_descs)
return self._doHandleException(func_repr, exc_info)
# Called whenever a gateway fails due to anything other than _CallMethod_.
# Really only used for the component loader etc objects, so most
# users should never see exceptions triggered here.
def _GatewayException_(self, name, exc_info):
return self._doHandleException(name, exc_info)
_supports_primitives_data_ = [
("nsISupportsString", "__str__", str),
("nsISupportsWString", "__str__", str),
("nsISupportsPRUint64", "__long__", long),
("nsISupportsPRInt64", "__long__", long),
("nsISupportsPRUint32", "__int__", int),
("nsISupportsPRInt32", "__int__", int),
("nsISupportsPRUint16", "__int__", int),
("nsISupportsPRInt16", "__int__", int),
("nsISupportsPRUint8", "__int__", int),
("nsISupportsPRBool", "__nonzero__", operator.truth),
("nsISupportsDouble", "__float__", float),
("nsISupportsFloat", "__float__", float),
]
# Support for the nsISupports primitives:
class SupportsPrimitive:
_com_interfaces_ = ["nsISupports"]
def __init__(self, iid, base_ob, attr_name, converter):
self.iid = iid
self.base_ob = base_ob
self.attr_name = attr_name
self.converter = converter
def _query_interface_(self, iid):
if iid == self.iid:
return 1
return None
def get_data(self):
method = getattr(self.base_ob, self.attr_name)
val = method()
return self.converter(val)
def set_data(self, val):
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
def toString(self):
return str(self.get_data())

View File

@@ -0,0 +1,219 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsFileStream.h>
static char *PyTraceback_AsString(PyObject *exc_tb);
// The internal helper that actually moves the
// formatted string to the target!
void LogMessage(const char *prefix, const char *pszMessageText)
{
nsOutputConsoleStream console;
console << prefix << pszMessageText;
}
// A helper for the various logging routines.
static void VLogF(const char *prefix, const char *fmt, va_list argptr)
{
char buff[512];
vsprintf(buff, fmt, argptr);
LogMessage(prefix, buff);
}
void PyXPCOM_LogError(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Error: ", fmt, marker);
// If we have a Python exception, also log that:
PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
PyErr_Fetch( &exc_typ, &exc_val, &exc_tb);
if (exc_typ) {
PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb);
char *string1 = nsnull;
nsOutputStringStream streamout(string1);
if (exc_tb) {
const char *szTraceback = PyTraceback_AsString(exc_tb);
if (szTraceback == NULL)
streamout << "Can't get the traceback info!";
else {
streamout << "Traceback (most recent call last):\n";
streamout << szTraceback;
PyMem_Free((ANY *)szTraceback);
}
}
PyObject *temp = PyObject_Str(exc_typ);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can't convert exception to a string!";
streamout << ": ";
if (exc_val != NULL) {
temp = PyObject_Str(exc_val);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can't convert exception value to a string!";
}
streamout << "\n";
LogMessage("PyXPCOM Exception:", string1);
}
PyErr_Restore(exc_typ, exc_val, exc_tb);
}
void PyXPCOM_LogWarning(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Warning: ", fmt, marker);
}
#ifdef DEBUG
void PyXPCOM_LogDebug(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Debug: ", fmt, marker);
}
#endif
PyObject *PyXPCOM_BuildPyException(nsresult r)
{
// Need the message etc.
PyObject *evalue = Py_BuildValue("i", r);
PyErr_SetObject(PyXPCOM_Error, evalue);
Py_XDECREF(evalue);
return NULL;
}
nsresult PyXPCOM_SetCOMErrorFromPyException()
{
if (!PyErr_Occurred())
// No error occurred
return NS_OK;
return NS_ERROR_FAILURE;
}
/* Obtains a string from a Python traceback.
This is the exact same string as "traceback.print_exc" would return.
Pass in a Python traceback object (probably obtained from PyErr_Fetch())
Result is a string which must be free'd using PyMem_Free()
*/
#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
char *PyTraceback_AsString(PyObject *exc_tb)
{
char *errMsg = NULL; /* a static that hold a local error message */
char *result = NULL; /* a valid, allocated result. */
PyObject *modStringIO = NULL;
PyObject *modTB = NULL;
PyObject *obFuncStringIO = NULL;
PyObject *obStringIO = NULL;
PyObject *obFuncTB = NULL;
PyObject *argsTB = NULL;
PyObject *obResult = NULL;
/* Import the modules we need - cStringIO and traceback */
modStringIO = PyImport_ImportModule("cStringIO");
if (modStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant import cStringIO\n");
modTB = PyImport_ImportModule("traceback");
if (modTB==NULL)
TRACEBACK_FETCH_ERROR("cant import traceback\n");
/* Construct a cStringIO object */
obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n");
obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
if (obStringIO==NULL)
TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n");
/* Get the traceback.print_exception function, and call it. */
obFuncTB = PyObject_GetAttrString(modTB, "print_tb");
if (obFuncTB==NULL)
TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n");
argsTB = Py_BuildValue("OOO",
exc_tb ? exc_tb : Py_None,
Py_None,
obStringIO);
if (argsTB==NULL)
TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n");
obResult = PyObject_CallObject(obFuncTB, argsTB);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n");
/* Now call the getvalue() method in the StringIO instance */
Py_DECREF(obFuncStringIO);
obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find getvalue function\n");
Py_DECREF(obResult);
obResult = PyObject_CallObject(obFuncStringIO, NULL);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("getvalue() failed.\n");
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult))
TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n");
{ // a temp scope so I can use temp locals.
char *tempResult = PyString_AsString(obResult);
result = (char *)PyMem_Malloc(strlen(tempResult)+1);
if (result==NULL)
TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string");
strcpy(result, tempResult);
} // end of temp scope.
done:
/* All finished - first see if we encountered an error */
if (result==NULL && errMsg != NULL) {
result = (char *)PyMem_Malloc(strlen(errMsg)+1);
if (result != NULL)
/* if it does, not much we can do! */
strcpy(result, errMsg);
}
Py_XDECREF(modStringIO);
Py_XDECREF(modTB);
Py_XDECREF(obFuncStringIO);
Py_XDECREF(obStringIO);
Py_XDECREF(obFuncTB);
Py_XDECREF(argsTB);
Py_XDECREF(obResult);
return result;
}
// See comments in PyXPCOM.h for why we need this!
void PyXPCOM_MakePendingCalls()
{
while (1) {
int rc = Py_MakePendingCalls();
if (rc == 0)
break;
// An exception - just report it as normal.
// Note that a traceback is very unlikely!
PyXPCOM_LogError("Unhandled exception detected before entering Python.\n");
PyErr_Clear();
// And loop around again until we are told everything is done!
}
}

View File

@@ -0,0 +1,757 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// PyGBase.cpp - implementation of the PyG_Base class
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIModule.h>
#include <nsIComponentLoader.h>
#include <nsIInputStream.h>
static PRInt32 cGateways = 0;
PRInt32 _PyXPCOM_GetGatewayCount(void)
{
return cGateways;
}
extern PyG_Base *MakePyG_nsIModule(PyObject *);
extern PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance);
extern PyG_Base *MakePyG_nsIInputStream(PyObject *instance);
static char *PyXPCOM_szDefaultGatewayAttributeName = "_com_instance_default_gateway_";
nsresult GetDefaultGateway(PyObject *instance, REFNSIID iid, void **ret);
void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway);
/*static*/ nsresult
PyG_Base::CreateNew(PyObject *pPyInstance, const nsIID &iid, void **ppResult)
{
NS_PRECONDITION(ppResult && *ppResult==NULL, "NULL or uninitialized pointer");
if (ppResult==nsnull)
return NS_ERROR_NULL_POINTER;
PyG_Base *ret;
// Hack for few extra gateways we support.
if (iid.Equals(NS_GET_IID(nsIModule)))
ret = MakePyG_nsIModule(pPyInstance);
else if (iid.Equals(NS_GET_IID(nsIComponentLoader)))
ret = MakePyG_nsIComponentLoader(pPyInstance);
else if (iid.Equals(NS_GET_IID(nsIInputStream)))
ret = MakePyG_nsIInputStream(pPyInstance);
else
ret = new PyXPCOM_XPTStub(pPyInstance, iid);
if (ret==nsnull)
return NS_ERROR_OUT_OF_MEMORY;
ret->AddRef(); // The first reference for the caller.
*ppResult = ret->ThisAsIID(iid);
NS_ABORT_IF_FALSE(*ppResult != NULL, "ThisAsIID() gave NULL, but we know it supports it!");
return *ppResult ? NS_OK : NS_ERROR_FAILURE;
}
PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid)
{
// Note that "instance" is the _policy_ instance!!
NS_INIT_REFCNT();
PR_AtomicIncrement(&cGateways);
m_pBaseObject = NULL;
// m_pWeakRef is an nsCOMPtr and needs no init.
m_iid = iid;
m_pPyObject = instance;
NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!");
#ifdef DEBUG_LIFETIMES
{
char *iid_repr;
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
if (iim!=nsnull)
iim->GetNameForIID(&iid, &iid_repr);
PyObject *real_instance = PyObject_GetAttrString(instance, "_obj_");
PyObject *real_repr = PyObject_Repr(real_instance);
PYXPCOM_LOG_DEBUG("PyG_Base created at %p\n instance_repr=%s\n IID=%s\n", this, PyString_AsString(real_repr), iid_repr);
nsAllocator::Free(iid_repr);
Py_XDECREF(real_instance);
Py_XDECREF(real_repr);
}
#endif // DEBUG_LIFETIMES
Py_XINCREF(instance); // instance should never be NULL - but whats an X between friends!
PyXPCOM_DLLAddRef();
#ifdef DEBUG_FULL
LogF("PyGatewayBase: created %s", m_pPyObject ? m_pPyObject->ob_type->tp_name : "<NULL>");
#endif
}
PyG_Base::~PyG_Base()
{
PR_AtomicDecrement(&cGateways);
#ifdef DEBUG_LIFETIMES
PYXPCOM_LOG_DEBUG("PyG_Base: deleted %p", this);
#endif
if ( m_pPyObject ) {
CEnterLeavePython celp;
Py_DECREF(m_pPyObject);
}
if (m_pBaseObject)
m_pBaseObject->Release();
if (m_pWeakRef) {
// Need to ensure some other thread isnt doing a QueryReferent on
// our weak reference at the same time
CEnterLeaveXPCOMFramework _celf;
PyXPCOM_GatewayWeakReference *p = (PyXPCOM_GatewayWeakReference *)(nsISupports *)m_pWeakRef;
p->m_pBase = nsnull;
m_pWeakRef = nsnull;
}
PyXPCOM_DLLRelease();
}
// Get the correct interface pointer for this object given the IID.
void *PyG_Base::ThisAsIID( const nsIID &iid )
{
if (this==NULL) return NULL;
if (iid.Equals(NS_GET_IID(nsISupports)))
return (nsISupports *)(nsIInternalPython *)this;
if (iid.Equals(NS_GET_IID(nsISupportsWeakReference)))
return (nsISupportsWeakReference *)this;
if (iid.Equals(NS_GET_IID(nsIInternalPython)))
return (nsISupports *)(nsIInternalPython *)this;
return NULL;
};
// Call back into Python, passing a Python instance, and get back
// an interface object that wraps the instance.
/*static*/ PRBool
PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **ppret)
{
NS_PRECONDITION(ppret!=NULL, "null pointer when wrapping a Python instance!");
NS_PRECONDITION(ob && PyInstance_Check(ob), "AutoWrapPythonInstance is expecting an non-NULL instance!");
PRBool ok = PR_FALSE;
// XXX - todo - this static object leaks! (but Python on Windows leaks 2000+ objects as it is ;-)
static PyObject *func = NULL; // fetch this once and remember!
PyObject *obIID = NULL;
PyObject *wrap_ret = NULL;
PyObject *args = NULL;
if (func==NULL) { // not thread-safe, but nothing bad can happen, except an extra reference leak
PyObject *mod = PyImport_ImportModule("xpcom.server");
if (mod)
func = PyObject_GetAttrString(mod, "WrapObject");
Py_XDECREF(mod);
if (func==NULL) goto done;
}
// See if the instance has previously been wrapped.
if (CheckDefaultGateway(ob, iid, ppret)) {
ok = PR_TRUE; // life is good!
} else {
PyErr_Clear();
obIID = Py_nsIID::PyObjectFromIID(iid);
if (obIID==NULL) goto done;
args = Py_BuildValue("OO", ob, obIID);
if (args==NULL) goto done;
wrap_ret = PyEval_CallObject(func, args);
if (wrap_ret==NULL) goto done;
ok = Py_nsISupports::InterfaceFromPyObject(wrap_ret, iid, ppret, PR_FALSE, PR_FALSE);
#ifdef DEBUG
if (ok)
// Check we _now_ have a default gateway
{
nsISupports *temp = NULL;
NS_ABORT_IF_FALSE(CheckDefaultGateway(ob, iid, &temp), "Auto-wrapped object didnt get a default gateway!");
if (temp) temp->Release();
}
#endif
}
done:
// Py_XDECREF(func); -- func is static for performance reasons.
Py_XDECREF(obIID);
Py_XDECREF(wrap_ret);
Py_XDECREF(args);
return ok;
}
// Call back into Python, passing a raw nsIInterface object, getting back
// the object to actually use as the gateway parameter for this interface.
// For example, it is expected that the policy will wrap the interface
// object in one of the xpcom.client.Interface objects, allowing
// natural usage of the interface from Python clients.
// Note that piid will usually be NULL - this is because the runtime
// reflection interfaces dont provide this information to me.
// In this case, the Python code may choose to lookup the complete
// interface info to obtain the IID.
// It is expected (but should not be assumed) that the method info
// or the IID will be NULL.
// Worst case, the code should provide a wrapper for the nsiSupports interface,
// so at least the user can simply QI the object.
PyObject *
PyG_Base::MakeInterfaceParam(nsISupports *pis,
const nsIID *piid,
int methodIndex /* = -1 */,
const XPTParamDescriptor *d /* = NULL */,
int paramIndex /* = -1 */)
{
if (pis==NULL) {
Py_INCREF(Py_None);
return Py_None;
}
// This condition is true today, but not necessarily so.
// But if it ever triggers, the poor Python code has no real hope
// of returning something useful, so we should at least do our
// best to provide the useful data.
NS_WARN_IF_FALSE( ((piid != NULL) ^ (d != NULL)) == 1, "No information on the interface available - Python's gunna have a hard time doing much with it!");
PyObject *obIID = NULL;
PyObject *obISupports = NULL;
PyObject *obParamDesc = NULL;
PyObject *result = NULL;
// get the basic interface first, as if we fail, we can try and use this.
nsIID iid_check = piid ? *piid : NS_GET_IID(nsISupports);
obISupports = Py_nsISupports::PyObjectFromInterface(pis, iid_check, PR_TRUE, PR_FALSE);
if (!obISupports)
goto done;
if (piid==NULL) {
obIID = Py_None;
Py_INCREF(Py_None);
} else
obIID = Py_nsIID::PyObjectFromIID(*piid);
if (obIID==NULL)
goto done;
obParamDesc = PyObject_FromXPTParamDescriptor(d);
if (obParamDesc==NULL)
goto done;
result = PyObject_CallMethod(m_pPyObject,
"_MakeInterfaceParam_",
"OOiOi",
obISupports,
obIID,
methodIndex,
obParamDesc,
paramIndex);
done:
if (PyErr_Occurred()) {
NS_WARN_IF_FALSE(result==NULL, "Have an error, but also a result!");
PyXPCOM_LogError("Wrapping an interface object for the gateway failed\n");
}
Py_XDECREF(obIID);
Py_XDECREF(obParamDesc);
if (result==NULL) // we had an error.
// return our obISupports. If NULL, we are really hosed and nothing we can do.
return obISupports;
// Dont need to return this - we have a better result.
Py_XDECREF(obISupports);
return result;
}
NS_IMETHODIMP
PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
{
#ifdef PYXPCOM_DEBUG_FULL
{
char *sziid = iid.ToString();
LogF("PyGatewayBase::QueryInterface: %s", sziid);
Allocator::Free(sziid);
}
#endif
NS_PRECONDITION(ppv, "NULL pointer");
if (ppv==nsnull)
return NS_ERROR_NULL_POINTER;
*ppv = nsnull;
// If one of our native interfaces (but NOT nsISupports if we have a base)
// return this.
// It is important is that nsISupports come from the base object
// to ensure that we live by XPCOM identity rules (other interfaces need
// not abide by this rule - only nsISupports.)
if ( (m_pBaseObject==NULL || !iid.Equals(NS_GET_IID(nsISupports)))
&& (*ppv=ThisAsIID(iid)) != NULL ) {
AddRef();
return NS_OK;
}
// If we have a "base object", then we need to delegate _every_ remaining
// QI to it.
if (m_pBaseObject != NULL && (m_pBaseObject->QueryInterface(iid, ppv)==NS_OK))
return NS_OK;
// Call the Python policy to see if it (says it) supports the interface
PRBool supports = PR_FALSE;
{ // temp scope for Python lock
CEnterLeavePython celp;
PyObject * ob = Py_nsIID::PyObjectFromIID(iid);
PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface((nsIInternalPython *)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE);
if ( !ob || !this_interface_ob) {
Py_XDECREF(ob);
Py_XDECREF(this_interface_ob);
return NS_ERROR_OUT_OF_MEMORY;
}
PyObject *result = PyObject_CallMethod(m_pPyObject, "_QueryInterface_",
"OO",
this_interface_ob, ob);
Py_DECREF(ob);
Py_DECREF(this_interface_ob);
if ( result ) {
if (Py_nsISupports::InterfaceFromPyObject(result, iid, (nsISupports **)ppv, PR_TRUE)) {
// If OK, but NULL, _QI_ returned None, which simply means
// "no such interface"
supports = (*ppv!=NULL);
// result has been QI'd and AddRef'd all ready for return.
} else {
// Dump this message and any Python exception before
// reporting the fact that QI failed - this error
// may provide clues!
PyXPCOM_LogError("The _QueryInterface_ method returned an object of type '%s', but an interface was expected\n", result->ob_type->tp_name);
// supports remains false
}
Py_DECREF(result);
} else {
NS_ABORT_IF_FALSE(PyErr_Occurred(), "Got NULL result, but no Python error flagged!");
NS_WARN_IF_FALSE(!supports, "Have failure with success flag set!");
PyXPCOM_LogError("The _QueryInterface_ processing failed.\n");
// supports remains false.
// We have reported the error, and are returning to COM,
// so we should clear it.
PyErr_Clear();
}
} // end of temp scope for Python lock - lock released here!
if ( !supports )
return NS_ERROR_NO_INTERFACE;
// Now setup the base object pointer back to me.
// We do a QI on our internal one to ensure we can safely cast
// the result to a PyG_Base (both from the POV that is may not
// be a Python object, and that the vtables offsets may screw
// us even if it is!)
nsISupports *pLook = (nsISupports *)(*ppv);
nsIInternalPython *pTemp;
if (pLook->QueryInterface(NS_GET_IID(nsIInternalPython), (void **)&pTemp)==NS_OK) {
// One of our objects, so set the base object if it doesnt already have one
PyG_Base *pG = (PyG_Base *)pTemp;
// Eeek - just these few next lines need to be thread-safe :-(
CEnterLeaveXPCOMFramework _celf;
if (pG->m_pBaseObject==NULL && pG != (PyG_Base *)this) {
pG->m_pBaseObject = this;
pG->m_pBaseObject->AddRef();
#ifdef DEBUG_LIFETIMES
PYXPCOM_LOG_DEBUG("PyG_Base setting BaseObject of %p to %p\n", pG, this);
#endif
}
pTemp->Release();
}
return NS_OK;
}
nsrefcnt
PyG_Base::AddRef(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt);
NS_LOG_ADDREF(this, cnt, "PyG_Base", sizeof(*this));
return cnt;
}
nsrefcnt
PyG_Base::Release(void)
{
nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
NS_LOG_RELEASE(this, cnt, "PyG_Base");
if ( cnt == 0 )
delete this;
return cnt;
}
NS_IMETHODIMP
PyG_Base::GetWeakReference(nsIWeakReference **ret)
{
NS_PRECONDITION(ret, "null pointer");
if (ret==nsnull) return NS_ERROR_INVALID_POINTER;
if (!m_pWeakRef) {
// First query for a weak reference - create it.
m_pWeakRef = new PyXPCOM_GatewayWeakReference(this);
NS_ABORT_IF_FALSE(m_pWeakRef, "Shouldn't be able to fail creating a weak reference!");
if (!m_pWeakRef)
return NS_ERROR_UNEXPECTED;
}
*ret = m_pWeakRef;
(*ret)->AddRef();
return NS_OK;
}
nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName)
{
nsresult rc = NS_OK;
if (PyErr_Occurred()) {
// The error handling - fairly involved, but worth it as
// good error reporting is critical for users to know WTF
// is going on - especially with TypeErrors etc in their
// return values (ie, after the Python code has successfully
// existed, but we encountered errors unpacking their
// result values for the COM caller - there is literally no
// way to catch these exceptions from Python code, as their
// is no Python function on the call-stack)
// First line of attack in an error is to call-back on the policy.
// If the callback of the error handler succeeds and returns an
// integer (for the nsresult), we take no further action.
// If this callback fails, we log _2_ exceptions - the error handler
// error, and the original error.
PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing!
PyObject *exc_typ, *exc_val, *exc_tb;
PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
PyObject *err_result = PyObject_CallMethod(m_pPyObject,
"_GatewayException_",
"z(OOO)",
szMethodName,
exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming...
exc_val ? exc_val : Py_None, // may well be NULL.
exc_tb ? exc_tb : Py_None); // may well be NULL.
if (err_result == NULL) {
PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n");
} else if (err_result == Py_None) {
// The exception handler has chosen not to do anything with
// this error, so we still need to print it!
;
} else if (PyInt_Check(err_result)) {
// The exception handler has given us the nresult.
rc = PyInt_AsLong(err_result);
bProcessMainError = PR_FALSE;
} else {
// The exception handler succeeded, but returned other than
// int or None.
PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", err_result->ob_type->tp_name);
}
Py_XDECREF(err_result);
PyErr_Restore(exc_typ, exc_val, exc_tb);
if (bProcessMainError) {
PyXPCOM_LogError("The function '%s' failed\n", szMethodName);
rc = PyXPCOM_SetCOMErrorFromPyException();
}
PyErr_Clear();
}
return rc;
}
static nsresult do_dispatch(
PyObject *pPyObject,
PyObject **ppResult,
const char *szMethodName,
const char *szFormat,
va_list va
)
{
NS_PRECONDITION(ppResult, "Must provide a result buffer");
*ppResult = nsnull;
// Build the Invoke arguments...
PyObject *args = NULL;
PyObject *method = NULL;
PyObject *real_ob = NULL;
nsresult ret = NS_ERROR_FAILURE;
if ( szFormat )
args = Py_VaBuildValue((char *)szFormat, va);
else
args = PyTuple_New(0);
if ( !args )
goto done;
// make sure a tuple.
if ( !PyTuple_Check(args) ) {
PyObject *a = PyTuple_New(1);
if ( a == NULL )
{
Py_DECREF(args);
goto done;
}
PyTuple_SET_ITEM(a, 0, args);
args = a;
}
// Bit to a hack here to maintain the use of a policy.
// We actually get the policies underlying object
// to make the call on.
real_ob = PyObject_GetAttrString(pPyObject, "_obj_");
if (real_ob == NULL) {
PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
goto done;
}
method = PyObject_GetAttrString(real_ob, (char *)szMethodName);
if ( !method ) {
PyErr_Clear();
ret = NS_COMFALSE;
goto done;
}
// Make the call
*ppResult = PyEval_CallObject(method, args);
ret = *ppResult ? NS_OK : NS_ERROR_FAILURE;
done:
Py_XDECREF(method);
Py_XDECREF(real_ob);
Py_XDECREF(args);
return ret;
}
nsresult PyG_Base::InvokeNativeViaPolicyInternal(
const char *szMethodName,
PyObject **ppResult,
const char *szFormat,
va_list va
)
{
if ( m_pPyObject == NULL || szMethodName == NULL )
return NS_ERROR_NULL_POINTER;
PyObject *temp = nsnull;
if (ppResult == nsnull)
ppResult = &temp;
nsresult nr = do_dispatch(m_pPyObject, ppResult, szMethodName, szFormat, va);
// If temp is NULL, they provided a buffer, and we dont touch it.
// If not NULL, *ppResult = temp, and _we_ do own it.
Py_XDECREF(temp);
return nr;
}
nsresult PyG_Base::InvokeNativeViaPolicy(
const char *szMethodName,
PyObject **ppResult /* = NULL */,
const char *szFormat /* = NULL */,
...
)
{
va_list va;
va_start(va, szFormat);
nsresult nr = InvokeNativeViaPolicyInternal(szMethodName, ppResult, szFormat, va);
va_end(va);
if (nr==NS_COMFALSE) {
// Only problem was missing method.
PyErr_Format(PyExc_AttributeError, "The object does not have a '%s' function.", szMethodName);
}
return nr == NS_OK ? NS_OK : HandleNativeGatewayError(szMethodName);
}
nsresult PyG_Base::InvokeNativeGetViaPolicy(
const char *szPropertyName,
PyObject **ppResult /* = NULL */
)
{
PyObject *ob_ret = NULL;
nsresult ret = NS_OK;
PyObject *real_ob = NULL;
if ( m_pPyObject == NULL || szPropertyName == NULL )
return NS_ERROR_NULL_POINTER;
// First see if we have a method of that name.
char buf[256];
strcpy(buf, "get_");
strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1);
buf[sizeof(buf)/sizeof(buf[0])-1] = '\0';
ret = InvokeNativeViaPolicyInternal(buf, ppResult, nsnull, nsnull);
if (ret == NS_COMFALSE) {
// No method of that name - just try a property.
// Bit to a hack here to maintain the use of a policy.
// We actually get the policies underlying object
// to make the call on.
real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_");
if (real_ob == NULL) {
PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
ret = HandleNativeGatewayError(szPropertyName);
goto done;
}
ob_ret = PyObject_GetAttrString(real_ob, (char *)szPropertyName);
if (ob_ret==NULL) {
PyErr_Format(PyExc_AttributeError,
"The object does not have a 'get_%s' function, or a '%s attribute.",
szPropertyName, szPropertyName);
} else {
ret = NS_OK;
if (ppResult)
*ppResult = ob_ret;
else
Py_XDECREF(ob_ret);
}
}
if (ret != NS_OK)
ret = HandleNativeGatewayError(szPropertyName);
done:
Py_XDECREF(real_ob);
return ret;
}
nsresult PyG_Base::InvokeNativeSetViaPolicy(
const char *szPropertyName,
...
)
{
if ( m_pPyObject == NULL || szPropertyName == NULL )
return NS_ERROR_NULL_POINTER;
PyObject *ob_ret = NULL;
nsresult ret = NS_OK;
PyObject *real_ob = NULL;
char buf[256];
strcpy(buf, "set_");
strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1);
buf[sizeof(buf)/sizeof(buf[0])-1] = '\0';
va_list va;
va_start(va, szPropertyName);
ret = InvokeNativeViaPolicyInternal(buf, NULL, "O", va);
va_end(va);
if (ret == NS_COMFALSE) {
// No method of that name - just try a property.
// Bit to a hack here to maintain the use of a policy.
// We actually get the policies underlying object
// to make the call on.
real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_");
if (real_ob == NULL) {
PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute.");
ret = HandleNativeGatewayError(szPropertyName);
goto done;
}
va_list va2;
va_start(va2, szPropertyName);
PyObject *arg = va_arg( va2, PyObject *);
va_end(va2);
if (PyObject_SetAttrString(real_ob, (char *)szPropertyName, arg) == 0)
ret = NS_OK;
else {
PyErr_Format(PyExc_AttributeError,
"The object does not have a 'set_%s' function, or a '%s attribute.",
szPropertyName, szPropertyName);
}
}
if (ret != NS_OK)
ret = HandleNativeGatewayError(szPropertyName);
done:
Py_XDECREF(real_ob);
return ret;
}
/******************************************************
Some special support to help with object identity.
In the simplest case, assume a Python COM object is
supporting a function "nsIWhatever GetWhatever()",
so implements it as:
return this
it is almost certain they intend returning
the same COM OBJECT to the caller! Thus, if a user of this COM
object does:
p1 = foo.GetWhatever();
p2 = foo.GetWhatever();
We almost certainly expect p1==p2==foo.
We previously _did_ have special support for the "this"
example above, but this implements a generic scheme that
works for _all_ objects.
Whenever we are asked to "AutoWrap" a Python object, the
first thing we do is see if it has been auto-wrapped before.
If not, we create a new wrapper, then make a COM weak reference
to that wrapper, and store it directly back into the instance
we are auto-wrapping! The use of a weak-reference prevents
cycles.
The existance of this attribute in an instance indicates if it
has been previously auto-wrapped.
If it _has_ previously been auto-wrapped, we de-reference the
weak reference, and use that gateway.
*********************************************************************/
nsresult GetDefaultGateway(PyObject *instance, REFNSIID iid, void **ret)
{
// NOTE: Instance is the real instance, _not_ the policy.
PyObject *ob_existing_weak = PyObject_GetAttrString(instance, PyXPCOM_szDefaultGatewayAttributeName);
if (ob_existing_weak != NULL) {
PRBool ok = PR_TRUE;
nsCOMPtr<nsIWeakReference> pWeakRef;
ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak,
NS_GET_IID(nsIWeakReference),
getter_AddRefs(pWeakRef),
PR_FALSE));
Py_DECREF(ob_existing_weak);
if (ok)
return pWeakRef->QueryReferent( iid, ret);
} else
PyErr_Clear();
return NS_ERROR_FAILURE;
}
PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway)
{
NS_ABORT_IF_FALSE(real_inst, "Did not have an _obj_ attribute");
if (real_inst==NULL) {
PyErr_Clear();
return PR_FALSE;
}
PyObject *ob_existing_weak = PyObject_GetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName);
if (ob_existing_weak != NULL) {
// We have an existing default, but as it is a weak reference, it
// may no longer be valid. Check it.
PRBool ok = PR_TRUE;
nsCOMPtr<nsIWeakReference> pWeakRef;
ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak,
NS_GET_IID(nsIWeakReference),
getter_AddRefs(pWeakRef),
PR_FALSE));
Py_DECREF(ob_existing_weak);
if (ok) {
Py_BEGIN_ALLOW_THREADS;
ok = NS_SUCCEEDED(pWeakRef->QueryReferent( iid, (void **)(ret_gateway)));
Py_END_ALLOW_THREADS;
}
if (!ok) {
// We have the attribute, but not valid - wipe it
// before restoring it.
if (0 != PyObject_DelAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName))
PyErr_Clear();
}
return ok;
}
PyErr_Clear();
return PR_FALSE;
}
void AddDefaultGateway(PyObject *instance, nsISupports *gateway)
{
// NOTE: Instance is the _policy_!
PyObject *real_inst = PyObject_GetAttrString(instance, "_obj_");
NS_ABORT_IF_FALSE(real_inst, "Could not get the '_obj_' element");
if (!real_inst) return;
if (!PyObject_HasAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) {
nsCOMPtr<nsISupportsWeakReference> swr( do_QueryInterface((nsISupportsWeakReference *)(gateway)) );
NS_ABORT_IF_FALSE(swr, "Our gateway failed with a weak reference query");
// Create the new default gateway - get a weak reference for our gateway.
if (swr) {
nsIWeakReference *pWeakReference = NULL;
swr->GetWeakReference( &pWeakReference );
if (pWeakReference) {
PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference,
NS_GET_IID(nsIWeakReference),
PR_FALSE, /* bAddRef */
PR_FALSE ); /* bMakeNicePyObject */
// pWeakReference reference consumed.
if (ob_new_weak) {
PyObject_SetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName, ob_new_weak);
Py_DECREF(ob_new_weak);
}
}
}
}
Py_DECREF(real_inst);
}

View File

@@ -0,0 +1,143 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// PyGInputStream.cpp
//
// This code is part of the XPCOM extensions for Python.
//
// Written October 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIInputStream.h>
class PyG_nsIInputStream : public PyG_Base, public nsIInputStream
{
public:
PyG_nsIInputStream(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIInputStream)) {;}
PYGATEWAY_BASE_SUPPORT(nsIInputStream, PyG_Base);
NS_IMETHOD Close(void);
NS_IMETHOD Available(PRUint32 *_retval);
NS_IMETHOD Read(char * buf, PRUint32 count, PRUint32 *_retval);
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval);
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
NS_IMETHOD GetObserver(nsIInputStreamObserver * *aObserver);
NS_IMETHOD SetObserver(nsIInputStreamObserver * aObserver);
};
PyG_Base *MakePyG_nsIInputStream(PyObject *instance)
{
return new PyG_nsIInputStream(instance);
}
NS_IMETHODIMP
PyG_nsIInputStream::Close()
{
CEnterLeavePython _celp;
const char *methodName = "close";
return InvokeNativeViaPolicy(methodName, NULL);
}
NS_IMETHODIMP
PyG_nsIInputStream::Available(PRUint32 *_retval)
{
NS_PRECONDITION(_retval, "null pointer");
CEnterLeavePython _celp;
PyObject *ret;
const char *methodName = "available";
nsresult nr = InvokeNativeViaPolicy(methodName, &ret);
if (NS_SUCCEEDED(nr)) {
*_retval = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
Py_XDECREF(ret);
}
return nr;
}
NS_IMETHODIMP
PyG_nsIInputStream::Read(char * buf, PRUint32 count, PRUint32 *_retval)
{
NS_PRECONDITION(_retval, "null pointer");
NS_PRECONDITION(buf, "null pointer");
CEnterLeavePython _celp;
PyObject *ret;
const char *methodName = "read";
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", count);
if (NS_SUCCEEDED(nr)) {
PRUint32 py_size;
const void *py_buf;
if (PyObject_AsReadBuffer(ret, &py_buf, (int *)&py_size)!=0) {
PyErr_Format(PyExc_TypeError, "nsIInputStream::read() method must return a buffer object - not a '%s' object", ret->ob_type->tp_name);
nr = HandleNativeGatewayError(methodName);
} else {
if (py_size > count) {
PyXPCOM_LogWarning("nsIInputStream::read() was asked for %d bytes, but the string returned is %d bytes - truncating!\n", count, py_size);
py_size = count;
}
memcpy(buf, py_buf, py_size);
*_retval = py_size;
}
}
return nr;
}
NS_IMETHODIMP
PyG_nsIInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
{
NS_WARNING("ReadSegments() not implemented!!!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PyG_nsIInputStream::GetNonBlocking(PRBool *aNonBlocking)
{
NS_PRECONDITION(aNonBlocking, "null pointer");
CEnterLeavePython _celp;
PyObject *ret;
const char *propName = "nonBlocking";
nsresult nr = InvokeNativeGetViaPolicy(propName, &ret);
if (NS_SUCCEEDED(nr)) {
*aNonBlocking = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(propName);
Py_XDECREF(ret);
}
return nr;
}
NS_IMETHODIMP
PyG_nsIInputStream::GetObserver(nsIInputStreamObserver * *aObserver)
{
NS_PRECONDITION(aObserver, "null pointer");
CEnterLeavePython _celp;
PyObject *ret;
const char *propName = "observer";
nsresult nr = InvokeNativeGetViaPolicy(propName, &ret);
if (NS_SUCCEEDED(nr)) {
Py_nsISupports::InterfaceFromPyObject(ret, NS_GET_IID(nsIInputStreamObserver), (nsISupports **)aObserver, PR_FALSE);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(propName);
}
return nr;
}
NS_IMETHODIMP
PyG_nsIInputStream::SetObserver(nsIInputStreamObserver * aObserver)
{
CEnterLeavePython _celp;
const char *propName = "observer";
PyObject *obObserver = MakeInterfaceParam(aObserver, &NS_GET_IID(nsIInputStreamObserver));
if (obObserver==NULL)
return HandleNativeGatewayError(propName);
nsresult nr = InvokeNativeSetViaPolicy(propName, obObserver);
Py_DECREF(obObserver);
return nr;
}

View File

@@ -0,0 +1,331 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
// Unfortunately, we can not use an XPConnect object for
// the nsiModule and nsiComponentLoader interfaces.
// As XPCOM shuts down, it shuts down the interface manager before
// it releases all the modules. This is a bit of a problem for
// us, as it means we can't get runtime info on the interface at shutdown time.
#include "PyXPCOM_std.h"
#include <nsIModule.h>
#include <nsIComponentLoader.h>
#ifdef XP_WIN
// Can only assume dynamic loading on Windows.
#define LOADER_LINKS_WITH_PYTHON
#endif // XP_WIN
extern void PyXPCOM_InterpreterState_Ensure();
////////////////////////////////////////////////////////////
// This is the main entry point called by the Python component
// loader.
extern "C" NS_EXPORT nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr,
nsIFile* location,
nsIModule** result)
{
NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!");
NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!");
NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!");
#ifndef LOADER_LINKS_WITH_PYTHON
if (!Py_IsInitialized()) {
Py_Initialize();
if (!Py_IsInitialized()) {
PyXPCOM_LogError("Python initialization failed!\n");
return NS_ERROR_FAILURE;
}
PyEval_InitThreads();
PyXPCOM_InterpreterState_Ensure();
PyEval_SaveThread();
}
#endif // LOADER_LINKS_WITH_PYTHON
CEnterLeavePython _celp;
PyObject *func = NULL;
PyObject *obServMgr = NULL;
PyObject *obLocation = NULL;
PyObject *wrap_ret = NULL;
PyObject *args = NULL;
PyObject *mod = PyImport_ImportModule("xpcom.server");
if (!mod) goto done;
func = PyObject_GetAttrString(mod, "NS_GetModule");
if (func==NULL) goto done;
obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager), PR_TRUE);
if (obServMgr==NULL) goto done;
obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile), PR_TRUE);
if (obLocation==NULL) goto done;
args = Py_BuildValue("OO", obServMgr, obLocation);
if (args==NULL) goto done;
wrap_ret = PyEval_CallObject(func, args);
if (wrap_ret==NULL) goto done;
Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE);
done:
nsresult nr = NS_OK;
if (PyErr_Occurred()) {
PyXPCOM_LogError("Obtaining the module object from Python failed.\n");
nr = PyXPCOM_SetCOMErrorFromPyException();
}
Py_XDECREF(func);
Py_XDECREF(obServMgr);
Py_XDECREF(obLocation);
Py_XDECREF(wrap_ret);
Py_XDECREF(mod);
Py_XDECREF(args);
return nr;
}
class PyG_nsIModule : public PyG_Base, public nsIModule
{
public:
PyG_nsIModule(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIModule)) {;}
PYGATEWAY_BASE_SUPPORT(nsIModule, PyG_Base);
NS_IMETHOD GetClassObject(nsIComponentManager *aCompMgr, const nsCID & aClass, const nsIID & aIID, void * *result);
NS_IMETHOD RegisterSelf(nsIComponentManager *aCompMgr, nsIFile *location, const char *registryLocation, const char *componentType);
NS_IMETHOD UnregisterSelf(nsIComponentManager *aCompMgr, nsIFile *location, const char *registryLocation);
NS_IMETHOD CanUnload(nsIComponentManager *aCompMgr, PRBool *_retval);
};
PyG_Base *MakePyG_nsIModule(PyObject *instance)
{
return new PyG_nsIModule(instance);
}
// Create a factory object for creating instances of aClass.
NS_IMETHODIMP
PyG_nsIModule::GetClassObject(nsIComponentManager *aCompMgr,
const nsCID& aClass,
const nsIID& aIID,
void** r_classObj)
{
NS_PRECONDITION(r_classObj, "null pointer");
*r_classObj = nsnull;
CEnterLeavePython _celp;
PyObject *cm = MakeInterfaceParam(aCompMgr, &NS_GET_IID(nsIComponentManager));
PyObject *iid = Py_nsIID::PyObjectFromIID(aIID);
PyObject *clsid = Py_nsIID::PyObjectFromIID(aClass);
const char *methodName = "getClassObject";
PyObject *ret = NULL;
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "OOO", cm, clsid, iid);
Py_XDECREF(cm);
Py_XDECREF(iid);
Py_XDECREF(clsid);
if (NS_SUCCEEDED(nr)) {
nr = Py_nsISupports::InterfaceFromPyObject(ret, aIID, (nsISupports **)r_classObj, PR_FALSE);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
if (NS_FAILED(nr)) {
NS_ABORT_IF_FALSE(*r_classObj==NULL, "returning error result with an interface - probable leak!");
}
Py_XDECREF(ret);
return nr;
}
NS_IMETHODIMP
PyG_nsIModule::RegisterSelf(nsIComponentManager *aCompMgr,
nsIFile* aPath,
const char* registryLocation,
const char* componentType)
{
NS_PRECONDITION(aCompMgr, "null pointer");
NS_PRECONDITION(aPath, "null pointer");
CEnterLeavePython _celp;
PyObject *cm = MakeInterfaceParam(aCompMgr, &NS_GET_IID(nsIComponentManager));
PyObject *path = MakeInterfaceParam(aPath, &NS_GET_IID(nsIFile));
const char *methodName = "registerSelf";
nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOzz", cm, path, registryLocation, componentType);
Py_XDECREF(cm);
Py_XDECREF(path);
return nr;
}
NS_IMETHODIMP
PyG_nsIModule::UnregisterSelf(nsIComponentManager* aCompMgr,
nsIFile* aPath,
const char* registryLocation)
{
NS_PRECONDITION(aCompMgr, "null pointer");
NS_PRECONDITION(aPath, "null pointer");
CEnterLeavePython _celp;
PyObject *cm = MakeInterfaceParam(aCompMgr, &NS_GET_IID(nsIComponentManager));
PyObject *path = MakeInterfaceParam(aPath, &NS_GET_IID(nsIFile));
const char *methodName = "unregisterSelf";
nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOz", cm, path, registryLocation);
Py_XDECREF(cm);
Py_XDECREF(path);
return nr;
}
NS_IMETHODIMP
PyG_nsIModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload)
{
NS_PRECONDITION(aCompMgr, "null pointer");
NS_PRECONDITION(okToUnload, "null pointer");
CEnterLeavePython _celp;
PyObject *cm = MakeInterfaceParam(aCompMgr, &NS_GET_IID(nsIComponentManager));
const char *methodName = "canUnload";
PyObject *ret = NULL;
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "O", cm);
Py_XDECREF(cm);
if (NS_SUCCEEDED(nr)) {
*okToUnload = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
Py_XDECREF(ret);
return nr;
}
///////////////////////////////////////////////////////////////////////////////////
class PyG_nsIComponentLoader : public PyG_Base, public nsIComponentLoader
{
public:
PyG_nsIComponentLoader(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIComponentLoader)) {;}
PYGATEWAY_BASE_SUPPORT(nsIComponentLoader, PyG_Base);
NS_DECL_NSICOMPONENTLOADER
};
PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance)
{
return new PyG_nsIComponentLoader(instance);
}
/* nsIFactory getFactory (in nsIIDRef aCID, in string aLocation, in string aType); */
NS_IMETHODIMP PyG_nsIComponentLoader::GetFactory(const nsIID & aCID, const char *aLocation, const char *aType, nsIFactory **_retval)
{
CEnterLeavePython _celp;
const char *methodName = "getFactory";
PyObject *iid = Py_nsIID::PyObjectFromIID(aCID);
PyObject *ret = NULL;
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "Ozz",
iid,
aLocation,
aType);
Py_XDECREF(iid);
if (NS_SUCCEEDED(nr)) {
Py_nsISupports::InterfaceFromPyObject(ret, NS_GET_IID(nsIFactory), (nsISupports **)_retval, PR_FALSE);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
Py_XDECREF(ret);
return nr;
}
/* void init (in nsIComponentManager aCompMgr, in nsISupports aRegistry); */
NS_IMETHODIMP PyG_nsIComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aRegistry)
{
CEnterLeavePython _celp;
const char *methodName = "init";
PyObject *c = MakeInterfaceParam(aCompMgr, &NS_GET_IID(nsIComponentManager));
PyObject *r = MakeInterfaceParam(aRegistry, &NS_GET_IID(nsISupports));
nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OO", c, r);
Py_XDECREF(c);
Py_XDECREF(r);
return nr;
}
/* void onRegister (in nsIIDRef aCID, in string aType, in string aClassName, in string aContractID, in string aLocation, in boolean aReplace, in boolean aPersist); */
NS_IMETHODIMP PyG_nsIComponentLoader::OnRegister(const nsIID & aCID, const char *aType, const char *aClassName, const char *aContractID, const char *aLocation, PRBool aReplace, PRBool aPersist)
{
CEnterLeavePython _celp;
const char *methodName = "onRegister";
PyObject *iid = Py_nsIID::PyObjectFromIID(aCID);
nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "Ossssii",
iid,
aType,
aClassName,
aContractID,
aLocation,
aReplace,
aPersist);
Py_XDECREF(iid);
return nr;
}
/* void autoRegisterComponents (in long aWhen, in nsIFile aDirectory); */
NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponents(PRInt32 aWhen, nsIFile *aDirectory)
{
CEnterLeavePython _celp;
const char *methodName = "autoRegisterComponents";
PyObject *c = MakeInterfaceParam(aDirectory, &NS_GET_IID(nsIFile));
nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "iO", aWhen, c);
Py_XDECREF(c);
return nr;
}
/* boolean autoRegisterComponent (in long aWhen, in nsIFile aComponent); */
NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval)
{
CEnterLeavePython _celp;
const char *methodName = "autoRegisterComponent";
PyObject *ret = NULL;
PyObject *c = MakeInterfaceParam(aComponent, &NS_GET_IID(nsIFile));
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c);
Py_XDECREF(c);
if (NS_SUCCEEDED(nr)) {
*_retval = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
Py_XDECREF(ret);
return nr;
}
/* boolean autoUnregisterComponent (in long aWhen, in nsIFile aComponent); */
NS_IMETHODIMP PyG_nsIComponentLoader::AutoUnregisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval)
{
CEnterLeavePython _celp;
const char *methodName = "autoUnregisterComponent";
PyObject *ret = NULL;
PyObject *c = MakeInterfaceParam(aComponent, &NS_GET_IID(nsIFile));
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c);
Py_XDECREF(c);
if (NS_SUCCEEDED(nr)) {
*_retval = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
Py_XDECREF(ret);
return nr;
}
/* boolean registerDeferredComponents (in long aWhen); */
NS_IMETHODIMP PyG_nsIComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, PRBool *_retval)
{
CEnterLeavePython _celp;
const char *methodName = "registerDeferredComponents";
PyObject *ret = NULL;
nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", aWhen);
if (NS_SUCCEEDED(nr)) {
*_retval = PyInt_AsLong(ret);
if (PyErr_Occurred())
nr = HandleNativeGatewayError(methodName);
}
Py_XDECREF(ret);
return nr;
}
/* void unloadAll (in long aWhen); */
NS_IMETHODIMP PyG_nsIComponentLoader::UnloadAll(PRInt32 aWhen)
{
CEnterLeavePython _celp;
const char *methodName = "unloadAll";
return InvokeNativeViaPolicy(methodName, NULL, "i", aWhen);
}

View File

@@ -0,0 +1,144 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// PyXPTStub - the stub for implementing interfaces.
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIInterfaceInfoManager.h>
void *PyXPCOM_XPTStub::ThisAsIID(const nsIID &iid)
{
if (iid.Equals(NS_GET_IID(nsISupports)))
return (nsISupports *)(nsXPTCStubBase *)this;
else if (iid.Equals(m_iid))
return (nsISupports *)(nsXPTCStubBase *)this;
else
return PyG_Base::ThisAsIID(iid);
}
NS_IMETHODIMP
PyXPCOM_XPTStub::GetInterfaceInfo(nsIInterfaceInfo** info)
{
NS_PRECONDITION(info, "NULL pointer");
if (info==nsnull)
return NS_ERROR_NULL_POINTER;
// Simply get the XPCOM runtime to provide this
// (but there must be some reason why they dont get it themselves!?
// Maybe because they dont know the IID?
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!");
if (iim==nsnull)
return NS_ERROR_FAILURE;
return iim->GetInfoForIID( &m_iid, info);
}
// call this method and return result
NS_IMETHODIMP
PyXPCOM_XPTStub::CallMethod(PRUint16 methodIndex,
const nsXPTMethodInfo* info,
nsXPTCMiniVariant* params)
{
nsresult rc = NS_ERROR_FAILURE;
NS_PRECONDITION(info, "NULL methodinfo pointer");
NS_PRECONDITION(params, "NULL variant pointer");
CEnterLeavePython _celp;
PyObject *obParams = NULL;
PyObject *result = NULL;
PyObject *obThisObject = NULL;
PyObject *obMI = PyObject_FromXPTMethodDescriptor(info);
PyXPCOM_GatewayVariantHelper arg_helper(this, methodIndex, info, params);
if (obMI==NULL)
goto done;
// base object is passed raw.
obThisObject = Py_nsISupports::PyObjectFromInterface((nsIInternalPython*)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE);
obParams = arg_helper.MakePyArgs();
if (obParams==NULL)
goto done;
result = PyObject_CallMethod(m_pPyObject,
"_CallMethod_",
"OiOO",
obThisObject,
(int)methodIndex,
obMI,
obParams);
if (result!=NULL) {
rc = arg_helper.ProcessPythonResult(result);
// Use an xor to check failure && pyerr, or !failure && !pyerr.
NS_ABORT_IF_FALSE( ((NS_FAILED(rc)!=0)^(PyErr_Occurred()!=0)) == 0, "We must have failure with a Python error, or success without a Python error.");
}
done:
if (PyErr_Occurred()) {
// The error handling - fairly involved, but worth it as
// good error reporting is critical for users to know WTF
// is going on - especially with TypeErrors etc in their
// return values (ie, after the Python code has successfully
// existed, but we encountered errors unpacking their
// result values for the COM caller - there is literally no
// way to catch these exceptions from Python code, as their
// is no Python function on the call-stack)
// First line of attack in an error is to call-back on the policy.
// If the callback of the error handler succeeds and returns an
// integer (for the nsresult), we take no further action.
// If this callback fails, we log _2_ exceptions - the error handler
// error, and the original error.
PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing!
PyObject *exc_typ, *exc_val, *exc_tb;
PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb);
PyObject *err_result = PyObject_CallMethod(m_pPyObject,
"_CallMethodException_",
"OiOO(OOO)",
obThisObject,
(int)methodIndex,
obMI,
obParams,
exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming...
exc_val ? exc_val : Py_None, // may well be NULL.
exc_tb ? exc_tb : Py_None); // may well be NULL.
if (err_result == NULL) {
PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n");
} else if (err_result == Py_None) {
// The exception handler has chosen not to do anything with
// this error, so we still need to print it!
;
} else if (PyInt_Check(err_result)) {
// The exception handler has given us the nresult.
rc = PyInt_AsLong(err_result);
bProcessMainError = PR_FALSE;
} else {
// The exception handler succeeded, but returned other than
// int or None.
PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", err_result->ob_type->tp_name);
}
Py_XDECREF(err_result);
PyErr_Restore(exc_typ, exc_val, exc_tb);
if (bProcessMainError) {
PyXPCOM_LogError("The function '%s' failed\n", info->GetName());
rc = PyXPCOM_SetCOMErrorFromPyException();
}
// else everything is already setup,
// just clear the Python error state.
PyErr_Clear();
}
Py_XDECREF(obMI);
Py_XDECREF(obParams);
Py_XDECREF(obThisObject);
Py_XDECREF(result);
return rc;
}

View File

@@ -0,0 +1,51 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// PyGWeakReference - implements weak references for gateways.
//
// This code is part of the XPCOM extensions for Python.
//
// Written November 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
PyXPCOM_GatewayWeakReference::PyXPCOM_GatewayWeakReference( PyG_Base *base )
{
m_pBase = base;
NS_INIT_REFCNT();
}
PyXPCOM_GatewayWeakReference::~PyXPCOM_GatewayWeakReference()
{
// Simply zap my reference to the gateway!
// No need to zap my gateway's reference to me, as
// it already holds a reference, so if we are destructing,
// then it can't possibly hold one.
m_pBase = NULL;
}
NS_IMPL_THREADSAFE_ADDREF(PyXPCOM_GatewayWeakReference);
NS_IMPL_THREADSAFE_RELEASE(PyXPCOM_GatewayWeakReference);
NS_IMPL_THREADSAFE_QUERY_INTERFACE(PyXPCOM_GatewayWeakReference, NS_GET_IID(nsIWeakReference));
NS_IMETHODIMP
PyXPCOM_GatewayWeakReference::QueryReferent(REFNSIID iid, void * *ret)
{
{
// Temp scope for lock. We can't hold the lock during
// a QI, as this may itself need the lock.
// Make sure our object isn't dieing right now on another thread.
CEnterLeaveXPCOMFramework _celf;
if (m_pBase == NULL)
return NS_ERROR_NULL_POINTER;
m_pBase->AddRef(); // Can't die while we have a ref.
} // end of lock scope - lock unlocked.
nsresult nr = m_pBase->QueryInterface(iid, ret);
m_pBase->Release();
return nr;
}

View File

@@ -0,0 +1,165 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIComponentManager.h>
static nsIComponentManager *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIComponentManager);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIComponentManager *)Py_nsISupports::GetI(self);
}
static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
{
char *pid, *notyet = NULL;
PyObject *obIID = NULL;
if (!PyArg_ParseTuple(args, "s|zO", &pid, &notyet, &obIID))
return NULL;
if (notyet != NULL) {
PyErr_SetString(PyExc_ValueError, "2nd arg must be none");
return NULL;
}
nsIComponentManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID iid;
if (obIID==NULL)
iid = NS_GET_IID(nsISupports);
else
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *pis;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->CreateInstanceByContractID(pid, NULL, iid, (void **)&pis);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
}
static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args)
{
char *pid;
if (!PyArg_ParseTuple(args, "s", &pid))
return NULL;
nsIComponentManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID iid;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->ContractIDToClassID(pid, &iid);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsIID::PyObjectFromIID(iid);
}
static PyObject *PyCLSIDToContractID(PyObject *self, PyObject *args)
{
PyObject *obIID;
if (!PyArg_ParseTuple(args, "O", &obIID))
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
char *ret_pid = nsnull;
char *ret_class = nsnull;
nsIComponentManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->CLSIDToContractID(iid, &ret_class, &ret_pid);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ob_pid = PyString_FromString(ret_pid);
PyObject *ob_class = PyString_FromString(ret_class);
PyObject *ret = Py_BuildValue("OO", ob_pid, ob_class);
nsAllocator::Free(ret_pid);
nsAllocator::Free(ret_class);
Py_XDECREF(ob_pid);
Py_XDECREF(ob_class);
return ret;
}
static PyObject *PyEnumerateCLSIDs(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIEnumerator *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->EnumerateCLSIDs(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE);
}
static PyObject *PyEnumerateContractIDs(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIEnumerator *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->EnumerateContractIDs(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE);
}
struct PyMethodDef
PyMethods_IComponentManager[] =
{
{ "CreateInstanceByContractID", PyCreateInstanceByContractID, 1},
{ "createInstanceByContractID", PyCreateInstanceByContractID, 1},
{ "EnumerateCLSIDs", PyEnumerateCLSIDs, 1},
{ "enumerateCLSIDs", PyEnumerateCLSIDs, 1},
{ "EnumerateContractIDs", PyEnumerateContractIDs, 1},
{ "enumerateContractIDs", PyEnumerateContractIDs, 1},
{ "ContractIDToClassID", PyContractIDToClassID, 1},
{ "contractIDToClassID", PyContractIDToClassID, 1},
{ "CLSIDToContractID", PyCLSIDToContractID, 1},
{NULL}
};

View File

@@ -0,0 +1,198 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIEnumerator.h>
static nsIEnumerator *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIEnumerator);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIEnumerator *)Py_nsISupports::GetI(self);
}
static PyObject *PyFirst(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":First"))
return NULL;
nsIEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->First();
Py_END_ALLOW_THREADS;
return PyInt_FromLong(r);
}
static PyObject *PyNext(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":Next"))
return NULL;
nsIEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->Next();
Py_END_ALLOW_THREADS;
return PyInt_FromLong(r);
}
static PyObject *PyCurrentItem(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
if (!PyArg_ParseTuple(args, "|O:CurrentItem", &obIID))
return NULL;
nsIID iid(NS_GET_IID(nsISupports));
if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsIEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
nsISupports *pRet = nsnull;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->CurrentItem(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
if (obIID) {
nsISupports *temp;
Py_BEGIN_ALLOW_THREADS;
r = pRet->QueryInterface(iid, (void **)&temp);
pRet->Release();
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) ) {
return PyXPCOM_BuildPyException(r);
}
pRet = temp;
}
return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE);
}
// A method added for Python performance if you really need
// it. Allows you to fetch a block of objects in one
// hit, allowing the loop to remain implemented in C.
static PyObject *PyFetchBlock(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
int n_wanted;
int n_fetched = 0;
if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID))
return NULL;
nsIID iid(NS_GET_IID(nsISupports));
if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsIEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
// We want to fetch with the thread-lock released,
// but this means we can not append to the PyList
nsISupports **fetched = new nsISupports*[n_wanted];
if (fetched==nsnull) {
PyErr_NoMemory();
return NULL;
}
memset(fetched, 0, sizeof(nsISupports *) * n_wanted);
nsresult r = NS_OK;
Py_BEGIN_ALLOW_THREADS;
for (;n_fetched<n_wanted;) {
nsISupports *pNew;
r = pI->CurrentItem(&pNew);
if (NS_FAILED(r)) {
r = 0; // Normal enum end
break;
}
if (obIID) {
nsISupports *temp;
r = pNew->QueryInterface(iid, (void **)&temp);
pNew->Release();
if ( NS_FAILED(r) ) {
break;
}
pNew = temp;
}
fetched[n_fetched] = pNew;
n_fetched++; // must increment before breaking out.
if (NS_FAILED(pI->Next()))
break; // not an error condition.
}
Py_END_ALLOW_THREADS;
PyObject *ret;
if (NS_SUCCEEDED(r)) {
ret = PyList_New(n_fetched);
if (ret)
for (int i=0;i<n_fetched;i++) {
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid, PR_FALSE);
PyList_SET_ITEM(ret, i, new_ob);
}
} else
ret = PyXPCOM_BuildPyException(r);
if ( ret == NULL ) {
// Free the objects we consumed.
for (int i=0;i<n_fetched;i++)
fetched[i]->Release();
}
delete [] fetched;
return ret;
}
static PyObject *PyIsDone(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":IsDone"))
return NULL;
nsIEnumerator *pI = GetI(self);
nsresult r;
if (pI==NULL)
return NULL;
Py_BEGIN_ALLOW_THREADS;
r = pI->IsDone();
Py_END_ALLOW_THREADS;
if (NS_FAILED(r))
return PyXPCOM_BuildPyException(r);
PyObject *ret = r==NS_OK ? Py_True : Py_False;
Py_INCREF(ret);
return ret;
}
struct PyMethodDef
PyMethods_IEnumerator[] =
{
{ "First", PyFirst, 1},
{ "first", PyFirst, 1},
{ "Next", PyNext, 1},
{ "next", PyNext, 1},
{ "CurrentItem", PyCurrentItem, 1},
{ "currentItem", PyCurrentItem, 1},
{ "IsDone", PyIsDone, 1},
{ "isDone", PyIsDone, 1},
{ "FetchBlock", PyFetchBlock, 1},
{ "fetchBlock", PyFetchBlock, 1},
{NULL}
};

View File

@@ -0,0 +1,202 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// Py_nsIID.cpp -- IID type for Python/XPCOM
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
//
// @doc
#include "PyXPCOM_std.h"
#include <nsIInterfaceInfoManager.h>
nsIID Py_nsIID_NULL = {0,0,0,{0,0,0,0,0,0,0,0}};
// @pymethod <o Py_nsIID>|xpcom|IID|Creates a new IID object
PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args)
{
PyObject *obIID;
PyObject *obBuf;
if ( PyArg_ParseTuple(args, "O", &obBuf)) {
if (PyBuffer_Check(obBuf)) {
PyBufferProcs *pb = NULL;
pb = obBuf->ob_type->tp_as_buffer;
void *buf = NULL;
int size = (*pb->bf_getreadbuffer)(obBuf, 0, &buf);
if (size != sizeof(nsIID) || buf==NULL) {
PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", sizeof(nsIID));
return NULL;
}
nsIID iid;
unsigned char *ptr = (unsigned char *)buf;
iid.m0 = XPT_SWAB32(*((PRUint32 *)ptr));
ptr = ((unsigned char *)buf) + offsetof(nsIID, m1);
iid.m1 = XPT_SWAB16(*((PRUint16 *)ptr));
ptr = ((unsigned char *)buf) + offsetof(nsIID, m2);
iid.m2 = XPT_SWAB16(*((PRUint16 *)ptr));
ptr = ((unsigned char *)buf) + offsetof(nsIID, m3);
for (int i=0;i<8;i++) {
iid.m3[i] = *((PRUint8 *)ptr);
ptr += sizeof(PRUint8);
}
return new Py_nsIID(iid);
}
}
PyErr_Clear();
// @pyparm string/Unicode|iidString||A string representation of an IID, or a ContractID.
if ( !PyArg_ParseTuple(args, "O", &obIID) )
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
return new Py_nsIID(iid);
}
/*static*/ PRBool
Py_nsIID::IIDFromPyObject(PyObject *ob, nsIID *pRet) {
PRBool ok = PR_TRUE;
nsIID iid;
if (ob==NULL) {
PyErr_SetString(PyExc_RuntimeError, "The object is invalid!");
return PR_FALSE;
}
if (PyString_Check(ob)) {
ok = iid.Parse(PyString_AsString(ob));
if (!ok) {
PyXPCOM_BuildPyException(NS_ERROR_ILLEGAL_VALUE);
return PR_FALSE;
}
} else if (ob->ob_type == &type) {
iid = ((Py_nsIID *)ob)->m_iid;
} else if (PyInstance_Check(ob)) {
// Get the _iidobj_ attribute
PyObject *use_ob = PyObject_GetAttrString(ob, "_iidobj_");
if (use_ob==NULL) {
PyErr_SetString(PyExc_TypeError, "Only instances with _iidobj_ attributes can be used as IID objects");
return PR_FALSE;
}
if (use_ob->ob_type != &type) {
Py_DECREF(use_ob);
PyErr_SetString(PyExc_TypeError, "instance _iidobj_ attributes must be raw IID object");
return PR_FALSE;
}
iid = ((Py_nsIID *)use_ob)->m_iid;
Py_DECREF(use_ob);
} else {
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an IID", ob->ob_type->tp_name);
ok = PR_FALSE;
}
if (ok) *pRet = iid;
return ok;
}
// @object Py_nsIID|A Python object, representing an IID/CLSID.
// <nl>All pythoncom functions that return a CLSID/IID will return one of these
// objects. However, in almost all cases, functions that expect a CLSID/IID
// as a param will accept either a string object, or a native Py_nsIID object.
PyTypeObject Py_nsIID::type =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"IID",
sizeof(Py_nsIID),
0,
PyTypeMethod_dealloc, /* tp_dealloc */
0, /* tp_print */
PyTypeMethod_getattr, /* tp_getattr */
0, /* tp_setattr */
PyTypeMethod_compare, /* tp_compare */
PyTypeMethod_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
PyTypeMethod_hash, /* tp_hash */
0, /* tp_call */
PyTypeMethod_str, /* tp_str */
};
Py_nsIID::Py_nsIID(const nsIID &riid)
{
ob_type = &type;
_Py_NewReference(this);
m_iid = riid;
}
/*static*/PyObject *
Py_nsIID::PyTypeMethod_getattr(PyObject *self, char *name)
{
Py_nsIID *me = (Py_nsIID *)self;
if (strcmp(name, "name")==0) {
char *iid_repr = nsnull;
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
if (iim!=nsnull)
iim->GetNameForIID(&me->m_iid, &iid_repr);
if (iid_repr==nsnull)
iid_repr = me->m_iid.ToString();
PyObject *ret;
if (iid_repr != nsnull) {
ret = PyString_FromString(iid_repr);
nsAllocator::Free(iid_repr);
} else
ret = PyString_FromString("<cant get IID info!>");
return ret;
}
return PyErr_Format(PyExc_AttributeError, "IID objects have no attribute '%s'", name);
}
/* static */ int
Py_nsIID::PyTypeMethod_compare(PyObject *self, PyObject *other)
{
Py_nsIID *s_iid = (Py_nsIID *)self;
Py_nsIID *o_iid = (Py_nsIID *)other;
return memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid));
}
/* static */ PyObject *
Py_nsIID::PyTypeMethod_repr(PyObject *self)
{
Py_nsIID *s_iid = (Py_nsIID *)self;
char buf[256];
char *sziid = s_iid->m_iid.ToString();
sprintf(buf, "_xpcom.IID('%s')", sziid);
nsAllocator::Free(sziid);
return PyString_FromString(buf);
}
/* static */ PyObject *
Py_nsIID::PyTypeMethod_str(PyObject *self)
{
Py_nsIID *s_iid = (Py_nsIID *)self;
char *sziid = s_iid->m_iid.ToString();
PyObject *ret = PyString_FromString(sziid);
nsAllocator::Free(sziid);
return ret;
}
/* static */long
Py_nsIID::PyTypeMethod_hash(PyObject *self)
{
const nsIID &iid = ((Py_nsIID *)self)->m_iid;
long ret = iid.m0 + iid.m1 + iid.m2;
for (int i=0;i<7;i++)
ret += iid.m3[i];
if ( ret == -1 )
return -2;
return ret;
}
/*static*/ void
Py_nsIID::PyTypeMethod_dealloc(PyObject *ob)
{
delete (Py_nsIID *)ob;
}

View File

@@ -0,0 +1,127 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written September 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include "nsIInputStream.h"
// Prevents us needing to use an nsIScriptableInputStream
// (and even that can't read binary data!!!)
static nsIInputStream *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIInputStream);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIInputStream *)Py_nsISupports::GetI(self);
}
static PyObject *DoPyRead_Buffer(nsIInputStream *pI, PyObject *obBuffer, PRUint32 n)
{
PRUint32 nread;
void *buf;
PRUint32 buf_len;
if (PyObject_AsWriteBuffer(obBuffer, &buf, (int *)&buf_len) != 0) {
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "The buffer object does not have a write buffer!");
return NULL;
}
if (n==(PRUint32)-1) {
n = buf_len;
} else {
if (n > buf_len) {
NS_WARNING("Warning: PyIInputStream::read() was passed an integer size greater than the size of the passed buffer! Buffer size used.\n");
n = buf_len;
}
}
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->Read((char *)buf, n, &nread);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyInt_FromLong(nread);
}
static PyObject *DoPyRead_Size(nsIInputStream *pI, PRUint32 n)
{
if (n==-1) {
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->Available(&n);
Py_END_ALLOW_THREADS;
if (NS_FAILED(r))
return PyXPCOM_BuildPyException(r);
}
char *buf = (char *)nsAllocator::Alloc(n);
if (buf==NULL) {
PyErr_NoMemory();
return NULL;
}
nsresult r;
PRUint32 nread;
Py_BEGIN_ALLOW_THREADS;
r = pI->Read(buf, n, &nread);
Py_END_ALLOW_THREADS;
PyObject *rc = NULL;
if ( NS_SUCCEEDED(r) ) {
rc = PyBuffer_New(nread);
if (rc != NULL) {
void *ob_buf;
PRUint32 buf_len;
if (PyObject_AsWriteBuffer(rc, &ob_buf, (int *)&buf_len) != 0) {
// should never fail - we just created it!
return NULL;
}
if (buf_len != nread) {
PyErr_SetString(PyExc_RuntimeError, "New buffer isnt the size we create it!");
return NULL;
}
memcpy(ob_buf, buf, nread);
}
} else
PyXPCOM_BuildPyException(r);
nsAllocator::Free(buf);
return rc;
}
static PyObject *PyRead(PyObject *self, PyObject *args)
{
PyObject *obBuffer = NULL;
PRUint32 n = (PRUint32)-1;
nsIInputStream *pI = GetI(self);
if (pI==NULL)
return NULL;
if (PyArg_ParseTuple(args, "|i", (int *)&n))
// This worked - no args, or just an int.
return DoPyRead_Size(pI, n);
// try our other supported arg format.
PyErr_Clear();
if (!PyArg_ParseTuple(args, "O|i", &obBuffer, (int *)&n)) {
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "'read()' must be called as (buffer_ob, int_size=-1) or (int_size=-1)");
return NULL;
}
return DoPyRead_Buffer(pI, obBuffer, n);
}
struct PyMethodDef
PyMethods_IInputStream[] =
{
{ "read", PyRead, 1},
// The rest are handled as normal
{NULL}
};

View File

@@ -0,0 +1,391 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
static nsIInterfaceInfo *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIInterfaceInfo);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIInterfaceInfo *)Py_nsISupports::GetI(self);
}
static PyObject *PyGetName(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":GetName"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
char *name;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetName(&name);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret = PyString_FromString(name);
nsAllocator::Free(name);
return ret;
}
static PyObject *PyGetIID(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":GetIID"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID *iid_ret;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetIID(&iid_ret);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret);
nsAllocator::Free(iid_ret);
return ret;
}
static PyObject *PyIsScriptable(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":IsScriptable"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
PRBool b_ret;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->IsScriptable(&b_ret);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyInt_FromLong(b_ret);
}
static PyObject *PyGetParent(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":GetParent"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIInterfaceInfo *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetParent(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
}
static PyObject *PyGetMethodCount(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":GetMethodCount"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
PRUint16 ret;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetMethodCount(&ret);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyInt_FromLong(ret);
}
static PyObject *PyGetConstantCount(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":GetConstantCount"))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
PRUint16 ret;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetConstantCount(&ret);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyInt_FromLong(ret);
}
static PyObject *PyGetMethodInfo(PyObject *self, PyObject *args)
{
PRUint16 index;
if (!PyArg_ParseTuple(args, "h:GetMethodInfo", &index))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
PRUint16 nmethods;
pI->GetMethodCount(&nmethods);
if (index>=nmethods) {
PyErr_SetString(PyExc_ValueError, "The method index is out of range");
return NULL;
}
const nsXPTMethodInfo *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetMethodInfo(index, &pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyObject_FromXPTMethodDescriptor(pRet);
}
static PyObject *PyGetMethodInfoForName(PyObject *self, PyObject *args)
{
char *name;
if (!PyArg_ParseTuple(args, "s:GetMethodInfoForName", &name))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
const nsXPTMethodInfo *pRet;
PRUint16 index;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetMethodInfoForName(name, &index, &pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret_i = PyObject_FromXPTMethodDescriptor(pRet);
if (ret_i==NULL)
return NULL;
PyObject *real_ret = Py_BuildValue("iO", (int)index, ret_i);
Py_DECREF(ret_i);
return real_ret;
}
static PyObject *PyGetConstant(PyObject *self, PyObject *args)
{
PRUint16 index;
if (!PyArg_ParseTuple(args, "h:GetConstant", &index))
return NULL;
nsIInterfaceInfo *pI = GetI(self);
if (pI==NULL)
return NULL;
const nsXPTConstant *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetConstant(index, &pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyObject_FromXPTConstant(pRet);
}
static PRBool __GetMethodInfoHelper(nsIInterfaceInfo *pii, int mi, int pi, const nsXPTMethodInfo **ppmi)
{
PRUint16 nmethods=0;
pii->GetMethodCount(&nmethods);
if (mi<0 || mi>=nmethods) {
PyErr_SetString(PyExc_ValueError, "The method index is out of range");
return PR_FALSE;
}
const nsXPTMethodInfo *pmi;
nsresult r = pii->GetMethodInfo(mi, &pmi);
if ( NS_FAILED(r) ) {
PyXPCOM_BuildPyException(r);
return PR_FALSE;
}
int nparams=0;
nparams = pmi->GetParamCount();
if (pi<0 || pi>=nparams) {
PyErr_SetString(PyExc_ValueError, "The param index is out of range");
return PR_FALSE;
}
*ppmi = pmi;
return PR_TRUE;
}
static PyObject *PyGetInfoForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi;
if (!PyArg_ParseTuple(args, "hh:GetInfoForParam", &mi, &pi))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsIInterfaceInfo *pnewii = nsnull;
nsresult n = pii->GetInfoForParam(mi, &param_info, &pnewii);
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
}
static PyObject *PyGetIIDForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi;
if (!PyArg_ParseTuple(args, "hh:GetIIDForParam", &mi, &pi))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsIID *piid;
nsresult n = pii->GetIIDForParam(mi, &param_info, &piid);
if (NS_FAILED(n) || piid==nsnull)
return PyXPCOM_BuildPyException(n);
return Py_nsIID::PyObjectFromIID(*piid);
}
static PyObject *PyGetTypeForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi, dim;
if (!PyArg_ParseTuple(args, "hhh:GetTypeForParam", &mi, &pi, &dim))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
nsXPTType datumType;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsresult n = pii->GetTypeForParam(mi, &param_info, dim, &datumType);
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return PyObject_FromXPTTypeDescriptor((const XPTTypeDescriptor *)&datumType);
}
static PyObject *PyGetSizeIsArgNumberForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi, dim;
if (!PyArg_ParseTuple(args, "hhh:GetSizeIsArgNumberForParam", &mi, &pi, &dim))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
PRUint8 ret;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsresult n = pii->GetSizeIsArgNumberForParam(mi, &param_info, dim, &ret);
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return PyInt_FromLong(ret);
}
static PyObject *PyGetLengthIsArgNumberForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi, dim;
if (!PyArg_ParseTuple(args, "hhh:GetLengthIsArgNumberForParam", &mi, &pi, &dim))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
PRUint8 ret;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsresult n = pii->GetLengthIsArgNumberForParam(mi, &param_info, dim, &ret);
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return PyInt_FromLong(ret);
}
static PyObject *PyGetInterfaceIsArgNumberForParam(PyObject *self, PyObject *args)
{
nsIInterfaceInfo *pii = GetI(self);
if (pii==NULL)
return NULL;
PRUint16 mi, pi;
if (!PyArg_ParseTuple(args, "hhh:GetInterfaceIsArgNumberForParam", &mi, &pi))
return NULL;
const nsXPTMethodInfo *pmi;
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
PRUint8 ret;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsresult n = pii->GetInterfaceIsArgNumberForParam(mi, &param_info, &ret);
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return PyInt_FromLong(ret);
}
struct PyMethodDef
PyMethods_IInterfaceInfo[] =
{
{ "GetName", PyGetName, 1},
{ "GetIID", PyGetIID, 1},
{ "IsScriptable", PyIsScriptable, 1},
{ "GetParent", PyGetParent, 1},
{ "GetMethodCount", PyGetMethodCount, 1},
{ "GetConstantCount", PyGetConstantCount, 1},
{ "GetMethodInfo", PyGetMethodInfo, 1},
{ "GetMethodInfoForName", PyGetMethodInfoForName, 1},
{ "GetConstant", PyGetConstant, 1},
{ "GetInfoForParam", PyGetInfoForParam, 1},
{ "GetIIDForParam", PyGetIIDForParam, 1},
{ "GetTypeForParam", PyGetTypeForParam, 1},
{ "GetSizeIsArgNumberForParam", PyGetSizeIsArgNumberForParam, 1},
{ "GetLengthIsArgNumberForParam", PyGetLengthIsArgNumberForParam, 1},
{ "GetInterfaceIsArgNumberForParam", PyGetInterfaceIsArgNumberForParam, 1},
{NULL}
};
/*
NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) = 0;
NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) = 0;
NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) = 0;
NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) = 0;
NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) = 0;
NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) = 0;
NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0;
NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0;
NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) = 0;
*/

View File

@@ -0,0 +1,167 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIInterfaceInfoManager.h>
static nsIInterfaceInfoManager *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIInterfaceInfoManager);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIInterfaceInfoManager *)Py_nsISupports::GetI(self);
}
static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
if (!PyArg_ParseTuple(args, "O", &obIID))
return NULL;
nsIInterfaceInfoManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsIInterfaceInfo *pi;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetInfoForIID(&iid, &pi);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
nsIID new_iid = NS_GET_IID(nsIInterfaceInfo);
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE, PR_FALSE);
}
static PyObject *PyGetInfoForName(PyObject *self, PyObject *args)
{
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
nsIInterfaceInfoManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIInterfaceInfo *pi;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetInfoForName(name, &pi);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE);
}
static PyObject *PyGetNameForIID(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
if (!PyArg_ParseTuple(args, "O", &obIID))
return NULL;
nsIInterfaceInfoManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
char *ret_name = NULL;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetNameForIID(&iid, &ret_name);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret = PyString_FromString(ret_name);
nsAllocator::Free(ret_name);
return ret;
}
static PyObject *PyGetIIDForName(PyObject *self, PyObject *args)
{
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
nsIInterfaceInfoManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIID *iid_ret;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetIIDForName(name, &iid_ret);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret);
nsAllocator::Free(iid_ret);
return ret;
}
static PyObject *PyEnumerateInterfaces(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIInterfaceInfoManager *pI = GetI(self);
if (pI==NULL)
return NULL;
nsIEnumerator *pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->EnumerateInterfaces(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE);
}
// TODO:
// void autoRegisterInterfaces();
PyMethodDef
PyMethods_IInterfaceInfoManager[] =
{
{ "GetInfoForIID", PyGetInfoForIID, 1},
{ "getInfoForIID", PyGetInfoForIID, 1},
{ "GetInfoForName", PyGetInfoForName, 1},
{ "getInfoForName", PyGetInfoForName, 1},
{ "GetIIDForName", PyGetIIDForName, 1},
{ "getIIDForName", PyGetIIDForName, 1},
{ "GetNameForIID", PyGetNameForIID, 1},
{ "getNameForIID", PyGetNameForIID, 1},
{ "EnumerateInterfaces", PyEnumerateInterfaces, 1},
{ "enumerateInterfaces", PyEnumerateInterfaces, 1},
{NULL}
};

View File

@@ -0,0 +1,101 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIServiceManager.h>
static nsIServiceManager *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsIServiceManager);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsIServiceManager *)Py_nsISupports::GetI(self);
}
static PyObject *PyRegisterService(PyObject *self, PyObject *args)
{
nsIServiceManager *pI = GetI(self);
if (pI==NULL)
return NULL;
PyObject *obCID, *obInterface;
if (!PyArg_ParseTuple(args, "OO", &obCID, &obInterface))
return NULL;
nsCOMPtr<nsISupports> pis;
if (!Py_nsISupports::InterfaceFromPyObject(obInterface, NS_GET_IID(nsISupports), getter_AddRefs(pis), PR_FALSE))
return NULL;
nsresult r;
if (PyString_Check(obCID) || PyUnicode_Check(obCID)) {
const char *val = PyString_AsString(obCID);
Py_BEGIN_ALLOW_THREADS;
r = pI->RegisterService(val, pis);
Py_END_ALLOW_THREADS;
} else {
nsCID cid;
if (!Py_nsIID::IIDFromPyObject(obCID, &cid))
return NULL;
Py_BEGIN_ALLOW_THREADS;
r = pI->RegisterService(cid, pis);
Py_END_ALLOW_THREADS;
}
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *PyGetService(PyObject *self, PyObject *args)
{
nsIServiceManager *pI = GetI(self);
if (pI==NULL)
return NULL;
PyObject *obIID, *obCID;
if (!PyArg_ParseTuple(args, "OO", &obCID, &obIID))
return NULL;
nsIID cid, iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *pis;
nsresult r;
if (PyString_Check(obCID) || PyUnicode_Check(obCID)) {
char *val = PyString_AsString(obCID);
Py_BEGIN_ALLOW_THREADS;
r = pI->GetService(val, iid, &pis);
Py_END_ALLOW_THREADS;
} else {
if (!Py_nsIID::IIDFromPyObject(obCID, &cid))
return NULL;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetService(cid, iid, &pis);
Py_END_ALLOW_THREADS;
}
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
}
struct PyMethodDef
PyMethods_IServiceManager[] =
{
{ "GetService", PyGetService, 1},
{ "getService", PyGetService, 1},
{ "RegisterService", PyRegisterService, 1},
{ "registerService", PyRegisterService, 1},
{NULL}
};

View File

@@ -0,0 +1,165 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsISimpleEnumerator.h>
static nsISimpleEnumerator *GetI(PyObject *self) {
nsIID iid = NS_GET_IID(nsISimpleEnumerator);
if (!Py_nsISupports::Check(self, iid)) {
PyErr_SetString(PyExc_TypeError, "This object is not the correct interface");
return NULL;
}
return (nsISimpleEnumerator *)Py_nsISupports::GetI(self);
}
static PyObject *PyHasMoreElements(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":HasMoreElements"))
return NULL;
nsISimpleEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
nsresult r;
PRBool more;
Py_BEGIN_ALLOW_THREADS;
r = pI->HasMoreElements(&more);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return PyInt_FromLong(more);
}
static PyObject *PyGetNext(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
if (!PyArg_ParseTuple(args, "|O:GetNext", &obIID))
return NULL;
nsIID iid(NS_GET_IID(nsISupports));
if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISimpleEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
nsISupports *pRet = nsnull;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetNext(&pRet);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
if (obIID) {
nsISupports *temp;
Py_BEGIN_ALLOW_THREADS;
r = pRet->QueryInterface(iid, (void **)&temp);
pRet->Release();
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) ) {
return PyXPCOM_BuildPyException(r);
}
pRet = temp;
}
return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE);
}
// A method added for Python performance if you really need
// it. Allows you to fetch a block of objects in one
// hit, allowing the loop to remain implemented in C.
static PyObject *PyFetchBlock(PyObject *self, PyObject *args)
{
PyObject *obIID = NULL;
int n_wanted;
int n_fetched = 0;
if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID))
return NULL;
nsIID iid(NS_GET_IID(nsISupports));
if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISimpleEnumerator *pI = GetI(self);
if (pI==NULL)
return NULL;
// We want to fetch with the thread-lock released,
// but this means we can not append to the PyList
nsISupports **fetched = new nsISupports*[n_wanted];
if (fetched==nsnull) {
PyErr_NoMemory();
return NULL;
}
memset(fetched, 0, sizeof(nsISupports *) * n_wanted);
nsresult r;
PRBool more;
Py_BEGIN_ALLOW_THREADS;
for (;n_fetched<n_wanted;) {
r = pI->HasMoreElements(&more);
if (NS_FAILED(r))
break; // this _is_ an error!
if (!more)
break; // Normal enum end.
nsISupports *pNew;
r = pI->GetNext(&pNew);
if (NS_FAILED(r)) // IS an error
break;
if (obIID) {
nsISupports *temp;
r = pNew->QueryInterface(iid, (void **)&temp);
pNew->Release();
if ( NS_FAILED(r) ) {
break;
}
pNew = temp;
}
fetched[n_fetched] = pNew;
n_fetched++;
}
Py_END_ALLOW_THREADS;
PyObject *ret;
if (NS_SUCCEEDED(r)) {
ret = PyList_New(n_fetched);
if (ret)
for (int i=0;i<n_fetched;i++) {
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid, PR_FALSE);
PyList_SET_ITEM(ret, i, new_ob);
}
} else
ret = PyXPCOM_BuildPyException(r);
if ( ret == NULL ) {
// Free the objects we consumed.
for (int i=0;i<n_fetched;i++)
fetched[i]->Release();
}
delete [] fetched;
return ret;
}
struct PyMethodDef
PyMethods_ISimpleEnumerator[] =
{
{ "HasMoreElements", PyHasMoreElements, 1},
{ "hasMoreElements", PyHasMoreElements, 1},
{ "GetNext", PyGetNext, 1},
{ "getNext", PyGetNext, 1},
{ "FetchBlock", PyFetchBlock, 1},
{ "fetchBlock", PyFetchBlock, 1},
{NULL}
};

View File

@@ -0,0 +1,343 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
static PRInt32 cInterfaces=0;
static PyObject *g_obFuncMakeInterfaceCount = NULL; // XXX - never released!!!
PRInt32
_PyXPCOM_GetInterfaceCount(void)
{
return cInterfaces;
}
Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyTypeObject *this_type)
{
ob_type = this_type;
m_obj = punk;
m_iid = iid;
// refcnt of object managed by caller.
PR_AtomicIncrement(&cInterfaces);
PyXPCOM_DLLAddRef();
_Py_NewReference(this);
}
Py_nsISupports::~Py_nsISupports()
{
SafeRelease(this);
PR_AtomicDecrement(&cInterfaces);
PyXPCOM_DLLRelease();
}
/*static*/ nsISupports *
Py_nsISupports::GetI(PyObject *self, nsIID *ret_iid)
{
if (self==NULL) {
PyErr_SetString(PyExc_ValueError, "The Python object is invalid");
return NULL;
}
Py_nsISupports *pis = (Py_nsISupports *)self;
if (pis->m_obj==NULL) {
// This should never be able to happen.
PyErr_SetString(PyExc_ValueError, "Internal Error - The XPCOM object has been released.");
return NULL;
}
if (ret_iid)
*ret_iid = pis->m_iid;
return pis->m_obj;
}
/*static*/ void
Py_nsISupports::SafeRelease(Py_nsISupports *ob)
{
if (!ob)
return;
if (ob->m_obj)
{
long rcnt;
Py_BEGIN_ALLOW_THREADS;
rcnt = ob->m_obj->Release();
Py_END_ALLOW_THREADS;
#ifdef _DEBUG_LIFETIMES
LogF(buf, " SafeRelease(%ld) -> %s at 0x%0lx, nsISupports at 0x%0lx - Release() returned %ld",GetCurrentThreadId(), ob->ob_type->tp_name,ob, ob->m_obj,rcnt);
#endif
ob->m_obj = NULL;
}
}
/*static*/ Py_nsISupports *
Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid)
{
return new Py_nsISupports(pInitObj,
iid,
type);
}
/*static*/PRBool
Py_nsISupports::InterfaceFromPyObject(PyObject *ob,
const nsIID &iid,
nsISupports **ppv,
PRBool bNoneOK,
PRBool bTryAutoWrap /* = PR_TRUE */)
{
if ( ob == NULL )
{
// don't overwrite an error message
if ( !PyErr_Occurred() )
PyErr_SetString(PyExc_TypeError, "The Python object is invalid");
return PR_FALSE;
}
if ( ob == Py_None )
{
if ( bNoneOK )
{
*ppv = NULL;
return PR_TRUE;
}
else
{
PyErr_SetString(PyExc_TypeError, "None is not a invalid interface object in this context");
return PR_FALSE;
}
}
if (PyInstance_Check(ob)) {
// Get the _comobj_ attribute
PyObject *use_ob = PyObject_GetAttrString(ob, "_comobj_");
if (use_ob==NULL) {
PyErr_Clear();
if (bTryAutoWrap)
// Try and auto-wrap it - errors will leave Py exception set,
return PyXPCOM_XPTStub::AutoWrapPythonInstance(ob, iid, ppv);
PyErr_SetString(PyExc_TypeError, "The Python instance can not be converted to an XP COM object");
return PR_FALSE;
} else
ob = use_ob;
} else {
Py_XINCREF(ob);
}
nsISupports *pis;
PRBool rc = PR_FALSE;
if ( !Check(ob) )
{
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be used as COM objects", ob->ob_type->tp_name);
goto done;
}
nsIID already_iid;
pis = GetI(ob, &already_iid);
if ( !pis )
goto done; /* exception was set by GetI() */
/* note: we don't (yet) explicitly hold a reference to pis */
if (iid.Equals(Py_nsIID_NULL)) {
// a bit of a hack - we are asking for the arbitary interface
// wrapped by this object, not some other specific interface -
// so no QI, just an AddRef();
Py_BEGIN_ALLOW_THREADS
pis->AddRef();
Py_END_ALLOW_THREADS
*ppv = pis;
} else {
// specific interface requested - if it is not already the
// specific interface, QI for it and discard pis.
if (iid.Equals(already_iid)) {
*ppv = pis;
pis->AddRef();
} else {
nsresult r;
Py_BEGIN_ALLOW_THREADS
r = pis->QueryInterface(iid, (void **)ppv);
Py_END_ALLOW_THREADS
if ( NS_FAILED(r) )
{
PyXPCOM_BuildPyException(r);
goto done;
}
/* note: the QI added a ref for the return value */
}
}
rc = PR_TRUE;
done:
Py_XDECREF(ob);
return rc;
}
// Interface conversions
/*static*/void
Py_nsISupports::RegisterInterface( const nsIID &iid, PyTypeObject *t)
{
if (mapIIDToType==NULL)
mapIIDToType = PyDict_New();
if (mapIIDToType) {
PyObject *key = Py_nsIID::PyObjectFromIID(iid);
if (key)
PyDict_SetItem(mapIIDToType, key, (PyObject *)t);
Py_XDECREF(key);
}
}
/*static */PyObject *
Py_nsISupports::PyObjectFromInterface(nsISupports *pis,
const nsIID &riid,
PRBool bAddRef,
PRBool bMakeNicePyObject /* = PR_TRUE */)
{
// Quick exit.
if (pis==NULL) {
Py_INCREF(Py_None);
return Py_None;
}
PyTypeObject *createType = NULL;
// If the IID is for nsISupports, dont bother with
// a map lookup as we know the type!
if (!riid.Equals(NS_GET_IID(nsISupports))) {
// Look up the map
PyObject *obiid = Py_nsIID::PyObjectFromIID(riid);
if (!obiid) return NULL;
if (mapIIDToType != NULL)
createType = (PyTypeObject *)PyDict_GetItem(mapIIDToType, obiid);
Py_DECREF(obiid);
}
if (createType==NULL)
createType = Py_nsISupports::type;
// Check it is indeed one of our types.
if (!PyXPCOM_TypeObject::IsType(createType)) {
PyErr_SetString(PyExc_RuntimeError, "The type map is invalid");
return NULL;
}
// we can now safely cast the thing to a PyComTypeObject and use it
PyXPCOM_TypeObject *myCreateType = (PyXPCOM_TypeObject *)createType;
if (myCreateType->ctor==NULL) {
PyErr_SetString(PyExc_TypeError, "The type does not declare a PyCom constructor");
return NULL;
}
Py_nsISupports *ret = (*myCreateType->ctor)(pis, riid);
#ifdef _DEBUG_LIFETIMES
PyXPCOM_LogF("XPCOM Object created at 0x%0xld, nsISupports at 0x%0xld",
ret, ret->m_obj);
#endif
if (ret && bAddRef && pis) pis->AddRef();
if (ret && bMakeNicePyObject)
return MakeInterfaceResult(ret, riid);
return ret;
}
// Call back into Python, passing a raw nsIInterface object, getting back
// the object to actually pass to Python.
PyObject *
Py_nsISupports::MakeInterfaceResult(PyObject *pyis,
const nsIID &iid)
{
NS_PRECONDITION(pyis, "NULL pyobject!");
PyObject *obIID = NULL;
PyObject *args = NULL;
PyObject *func = NULL;
PyObject *mod = NULL;
PyObject *ret = NULL;
obIID = Py_nsIID::PyObjectFromIID(iid);
if (obIID==NULL)
goto done;
if (g_obFuncMakeInterfaceCount==NULL) {
PyObject *mod = PyImport_ImportModule("xpcom.client");
if (mod)
g_obFuncMakeInterfaceCount = PyObject_GetAttrString(mod, "MakeInterfaceResult");
Py_XDECREF(mod);
}
if (g_obFuncMakeInterfaceCount==NULL) goto done;
args = Py_BuildValue("OO", pyis, obIID);
if (args==NULL) goto done;
ret = PyEval_CallObject(g_obFuncMakeInterfaceCount, args);
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");
PyErr_Clear();
}
Py_XDECREF(mod);
Py_XDECREF(args);
Py_XDECREF(obIID);
if (ret==NULL) // eek - error - return the original with no refcount mod.
ret = pyis;
else
// no error - decref the old object
Py_DECREF(pyis);
// return our obISupports. If NULL, we are really hosed and nothing we can do.
return ret;
}
// @pymethod <o Py_nsISupports>|Py_nsISupports|QueryInterface|Queries an object for a specific interface.
PyObject *
Py_nsISupports::QueryInterface(PyObject *self, PyObject *args)
{
PyObject *obiid;
int bWrap = 1;
// @pyparm IID|iid||The IID requested.
// @rdesc The result is always a <o Py_nsISupports> object.
// Any error (including E_NOINTERFACE) will generate a <o com_error> exception.
if (!PyArg_ParseTuple(args, "O|i:QueryInterface", &obiid, &bWrap))
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obiid, &iid))
return NULL;
nsISupports *pMyIS = GetI(self);
if (pMyIS==NULL) return NULL;
nsISupports *pis;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pMyIS->QueryInterface(iid, (void **)&pis);
Py_END_ALLOW_THREADS;
/* Note that this failure may include E_NOINTERFACE */
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
return PyObjectFromInterface(pis, iid, PR_FALSE, (PRBool)bWrap);
}
// @object Py_nsISupports|The base object for all PythonCOM objects. Wraps a COM nsISupports interface.
/*static*/ struct PyMethodDef
Py_nsISupports::methods[] =
{
{ "queryInterface", Py_nsISupports::QueryInterface, 1, "Queries the object for an interface."},
{ "QueryInterface", Py_nsISupports::QueryInterface, 1, "An alias for queryInterface."},
{NULL}
};
/*static*/void Py_nsISupports::InitType(void)
{
type = new PyXPCOM_TypeObject(
"nsISupports",
NULL,
sizeof(Py_nsISupports),
methods,
Constructor);
}
PyXPCOM_TypeObject *Py_nsISupports::type = NULL;
PyObject *Py_nsISupports::mapIIDToType = NULL;

View File

@@ -0,0 +1,557 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// PyXPCOM.h - the main header file for the Python XPCOM support.
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#ifndef __PYXPCOM_H__
#define __PYXPCOM_H__
#ifdef XP_WIN
# ifdef BUILD_PYXPCOM
/* We are building the main dll */
# define PYXPCOM_EXPORT __declspec(dllexport)
# else
/* This module uses the dll */
# define PYXPCOM_EXPORT __declspec(dllimport)
# endif // BUILD_PYXPCOM
// We need these libs!
# pragma comment(lib, "xpcom.lib")
# pragma comment(lib, "nspr4.lib")
#else // XP_WIN
# define PYXPCOM_EXPORT
#endif // XP_WIN
// An IID we treat as NULL when passing as a reference.
extern nsIID Py_nsIID_NULL;
/*************************************************************************
**************************************************************************
Error and exception related function.
**************************************************************************
*************************************************************************/
// The exception object (loaded from the xpcom .py code)
extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error;
// Client related functions - generally called by interfaces before
// they return NULL back to Python to indicate the error.
// All these functions return NULL so interfaces can generally
// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)"
PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res);
// Used in gateways to handle the current Python exception
// NOTE: this function assumes it is operating within the Python context
PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException();
// A couple of logging/error functions. These probably end up
// being written to the console service.
// Log a warning for the user - something at runtime
// they may care about, but nothing that prevents us actually
// working.
// As it's designed for user error/warning, it exists in non-debug builds.
PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...);
// Log an error for the user - something that _has_ prevented
// us working. This is probably accompanied by a traceback.
// As it's designed for user error/warning, it exists in non-debug builds.
PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...);
#ifdef DEBUG
// Mainly designed for developers of the XPCOM package.
// Only enabled in debug builds.
PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug
#else
#define PYXPCOM_LOG_DEBUG()
#endif // DEBUG
/*************************************************************************
**************************************************************************
Support for CALLING (ie, using) interfaces.
**************************************************************************
*************************************************************************/
class Py_nsISupports;
typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &);
//////////////////////////////////////////////////////////////////////////
// class PyXPCOM_TypeObject
// Base class for (most of) the type objects.
class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject {
public:
PyXPCOM_TypeObject(
const char *name,
PyXPCOM_TypeObject *pBaseType,
int typeSize,
struct PyMethodDef* methodList,
PyXPCOM_I_CTOR ctor);
~PyXPCOM_TypeObject();
PyMethodChain chain;
PyXPCOM_TypeObject *baseType;
PyXPCOM_I_CTOR ctor;
static PRBool IsType(PyTypeObject *t);
// Static methods for the Python type.
static void Py_dealloc(PyObject *ob);
static PyObject *Py_repr(PyObject *ob);
static PyObject *Py_str(PyObject *ob);
static PyObject *Py_getattr(PyObject *self, char *name);
static int Py_setattr(PyObject *op, char *name, PyObject *v);
static int Py_cmp(PyObject *ob1, PyObject *ob2);
static long Py_hash(PyObject *self);
};
//////////////////////////////////////////////////////////////////////////
// class Py_nsISupports
// This class serves 2 purposes:
// * It is a base class for other interfaces we support "natively"
// * It is instantiated for _all_ other interfaces.
//
// This is different than win32com, where a PyIUnknown only
// ever holds an IUnknown - but here, we could be holding
// _any_ interface.
class PYXPCOM_EXPORT Py_nsISupports : public PyObject
{
public:
static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) {
Py_nsISupports *self = static_cast<Py_nsISupports *>(ob);
if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type ))
return PR_FALSE;
if (!checkIID.Equals(Py_nsIID_NULL))
return self->m_iid.Equals(checkIID) != 0;
return PR_TRUE;
}
// Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL);
nsISupports *m_obj;
nsIID m_iid;
// Given an nsISupports and an Interface ID, create and return an object
// Does not QI the object - the caller must ensure the nsISupports object
// is really a pointer to an object identified by the IID.
// PRBool bAddRef indicates if a COM reference count should be added to the interface.
// This depends purely on the context in which it is called. If the interface is obtained
// from a function that creates a new ref (eg, ???) then you should use
// FALSE. If you receive the pointer as (eg) a param to a gateway function, then
// you normally need to pass TRUE, as this is truly a new reference.
// *** ALWAYS take the time to get this right. ***
// PRBool bMakeNicePyObject indicates if we should call back into
// Python to wrap the object. This allows Python code to
// see the correct xpcom.client.Interface object even when calling
// xpcom function directly.
static PyObject *PyObjectFromInterface(nsISupports *ps,
const nsIID &iid,
PRBool bAddRef,
PRBool bMakeNicePyObject = PR_TRUE);
// Given a Python object that is a registered COM type, return a given
// interface pointer on its underlying object, with a NEW REFERENCE ADDED.
// bTryAutoWrap indicates if a Python instance object should attempt to
// be automatically wrapped in an XPCOM object. This is really only
// provided to stop accidental recursion should the object returned by
// the wrap process itself be in instance (where it should already be
// a COM object.
static PRBool InterfaceFromPyObject(
PyObject *ob,
const nsIID &iid,
nsISupports **ppret,
PRBool bNoneOK,
PRBool bTryAutoWrap = PR_TRUE);
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid);
// The Python methods
static PyObject *QueryInterface(PyObject *self, PyObject *args);
// Internal (sort-of) objects.
static PyXPCOM_TypeObject *type;
static PyMethodDef methods[];
static PyObject *mapIIDToType;
static void SafeRelease(Py_nsISupports *ob);
static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
static void InitType();
~Py_nsISupports();
protected:
// ctor is protected - must create objects via
// PyObjectFromInterface()
Py_nsISupports(nsISupports *p,
const nsIID &iid,
PyTypeObject *type);
static PyObject *MakeInterfaceResult(PyObject *pyis, const nsIID &iid);
};
// Python/XPCOM IID support
class PYXPCOM_EXPORT Py_nsIID : public PyObject
{
public:
Py_nsIID(const nsIID &riid);
nsIID m_iid;
PRBool
IsEqual(const nsIID &riid) {
return m_iid.Equals(riid);
}
PRBool
IsEqual(PyObject *ob) {
return ob &&
ob->ob_type== &type &&
m_iid.Equals(((Py_nsIID *)ob)->m_iid);
}
PRBool
IsEqual(Py_nsIID &iid) {
return m_iid.Equals(iid.m_iid);
}
static PyObject *
PyObjectFromIID(const nsIID &iid) {
return new Py_nsIID(iid);
}
static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet);
/* Python support */
static PyObject *PyTypeMethod_getattr(PyObject *self, char *name);
static int PyTypeMethod_compare(PyObject *self, PyObject *ob);
static PyObject *PyTypeMethod_repr(PyObject *self);
static long PyTypeMethod_hash(PyObject *self);
static PyObject *PyTypeMethod_str(PyObject *self);
static void PyTypeMethod_dealloc(PyObject *self);
static PyTypeObject type;
static PyMethodDef methods[];
};
///////////////////////////////////////////////////////
//
// Helper classes for managing arrays of variants.
class PythonTypeDescriptor; // Forward declare.
class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper {
public:
PyXPCOM_InterfaceVariantHelper();
~PyXPCOM_InterfaceVariantHelper();
PRBool Init(PyObject *obParams);
PRBool FillArray();
PyObject *MakePythonResult();
nsXPTCVariant *m_var_array;
int m_num_array;
protected:
PyObject *MakeSinglePythonResult(int index);
PRBool FillInVariant(const PythonTypeDescriptor &, int, int);
PRBool PrepareOutVariant(const PythonTypeDescriptor &td, int value_index);
PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
PyObject *m_pyparams; // sequence of actual params passed (ie, not including hidden)
PyObject *m_typedescs; // desc of _all_ params, including hidden.
PythonTypeDescriptor *m_python_type_desc_array;
void **m_buffer_array;
};
/*************************************************************************
**************************************************************************
Support for IMPLEMENTING interfaces.
**************************************************************************
*************************************************************************/
#define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20"
#define NS_IINTERNALPYTHON_IID \
{ 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } }
class PyXPCOM_GatewayWeakReference;
// This interface is needed primarily to give us a known vtable base.
// If we QI a Python object for this interface, we can safely cast the result
// to a PyG_Base. Any other interface, we do now know which vtable we will get.
// Later, we may get some internal functions
// (eg, win32com allows us to get the underlying Python object, but
// we should try and avoid that if possible.
class nsIInternalPython : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IINTERNALPYTHON_IID)
};
// This is roughly equivilent to PyGatewayBase in win32com
//
class PYXPCOM_EXPORT PyG_Base : public nsIInternalPython, public nsISupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISUPPORTSWEAKREFERENCE
// A static "constructor" - the real ctor is protected.
static nsresult CreateNew(PyObject *pPyInstance,
const nsIID &iid,
void **ppResult);
// A utility to auto-wrap an arbitary Python instance
// in a COM gateway.
static PRBool AutoWrapPythonInstance(PyObject *ob,
const nsIID &iid,
nsISupports **ppret);
// A helper that creates objects to be passed for nsISupports
// objects. See extensive comments in PyG_Base.cpp.
PyObject *MakeInterfaceParam(nsISupports *pis,
const nsIID *piid,
int methodIndex = -1,
const XPTParamDescriptor *d = NULL,
int paramIndex = -1);
// A helper that ensures all casting and vtable offsetting etc
// done against this object happens in the one spot!
virtual void *ThisAsIID( const nsIID &iid ) = 0;
// Helpers for "native" interfaces.
// Not used by the generic stub interface.
nsresult HandleNativeGatewayError(const char *szMethodName);
// These data members used by the converter helper functions - hence public
nsIID m_iid;
PyObject * m_pPyObject;
// We keep a reference count on this object, and the object
// itself uses normal refcount rules - thus, it will only
// die when we die, and all external references are removed.
// This means that once we have created it (and while we
// are alive) it will never die.
nsCOMPtr<nsIWeakReference> m_pWeakRef;
protected:
PyG_Base(PyObject *instance, const nsIID &iid);
virtual ~PyG_Base();
PyG_Base *m_pBaseObject; // A chain to implement identity rules.
nsresult InvokeNativeViaPolicy( const char *szMethodName,
PyObject **ppResult = NULL,
const char *szFormat = NULL,
...
);
nsresult InvokeNativeViaPolicyInternal( const char *szMethodName,
PyObject **ppResult,
const char *szFormat,
va_list va);
nsresult InvokeNativeGetViaPolicy(const char *szPropertyName,
PyObject **ppResult = NULL
);
nsresult InvokeNativeSetViaPolicy(const char *szPropertyName,
...);
};
class PYXPCOM_EXPORT PyXPCOM_XPTStub : public PyG_Base, public nsXPTCStubBase
{
friend class PyG_Base;
public:
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
{return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \
NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \
NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info);
// call this method and return result
NS_IMETHOD CallMethod(PRUint16 methodIndex,
const nsXPTMethodInfo* info,
nsXPTCMiniVariant* params);
virtual void *ThisAsIID(const nsIID &iid);
protected:
PyXPCOM_XPTStub(PyObject *instance, const nsIID &iid) : PyG_Base(instance, iid) {;}
private:
};
// For the Gateways me manually implement.
#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \
{return PyG_Base::QueryInterface(aIID, aInstancePtr);} \
NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \
NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \
virtual void *ThisAsIID(const nsIID &iid) { \
if (iid.Equals(NS_GET_IID(INTERFACE))) return (INTERFACE *)this; \
return GATEWAY_BASE::ThisAsIID(iid); \
} \
// Weak Reference class. This is a true COM object, representing
// a weak reference to a Python object. For each Python XPCOM object,
// there is exactly zero or one corresponding weak reference instance.
// When both are alive, each holds a pointer to the other. When the main
// object dies due to XPCOM reference counting, it zaps the pointer
// in its corresponding weak reference object. Thus, the weak-reference
// can live beyond the object (possibly with a NULL pointer back to the
// "real" object, but as implemented, the weak reference will never be
// destroyed before the object
class PYXPCOM_EXPORT PyXPCOM_GatewayWeakReference : public nsIWeakReference {
public:
PyXPCOM_GatewayWeakReference(PyG_Base *base);
~PyXPCOM_GatewayWeakReference();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEAKREFERENCE;
PyG_Base *m_pBase; // NO REF COUNT!!!
};
// Helpers classes for our gateways.
class PYXPCOM_EXPORT PyXPCOM_GatewayVariantHelper
{
public:
PyXPCOM_GatewayVariantHelper( PyG_Base *gateway,
int methodIndex,
const nsXPTMethodInfo *info,
nsXPTCMiniVariant* params );
~PyXPCOM_GatewayVariantHelper();
PyObject *MakePyArgs();
nsresult ProcessPythonResult(PyObject *ob);
PyG_Base *m_gateway;
private:
nsresult BackFillVariant( PyObject *ob, int index);
PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td);
PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret);
nsresult GetArrayType(PRUint8 index, PRUint8 *ret);
PRUint32 GetSizeIs( int var_index, PRBool is_arg1);
PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size);
PRBool CanSetSizeIs( int var_index, PRBool is_arg1 );
nsXPTCMiniVariant* m_params;
const nsXPTMethodInfo *m_info;
int m_method_index;
PythonTypeDescriptor *m_python_type_desc_array;
int m_num_type_descs;
};
// Misc converters.
PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d);
PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d);
PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d);
PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d);
// DLL reference counting functions.
// Although we maintain the count, we never actually
// finalize Python when it hits zero!
void PyXPCOM_DLLAddRef();
void PyXPCOM_DLLRelease();
/*************************************************************************
**************************************************************************
LOCKING AND THREADING
**************************************************************************
*************************************************************************/
//
// We have 2 discrete locks in use (when no free-threaded is used, anyway).
// The first type of lock is the global Python lock. This is the standard lock
// in use by Python, and must be used as documented by Python. Specifically, no
// 2 threads may _ever_ call _any_ Python code (including INCREF/DECREF) without
// first having this thread lock.
//
// The second type of lock is a "global framework lock", and used whenever 2 threads
// of C code need access to global data. This is different than the Python
// lock - this lock is used when no Python code can ever be called by the
// threads, but the C code still needs thread-safety.
// We also supply helper classes which make the usage of these locks a one-liner.
// The "framework" lock, implemented as a PRLock
PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void);
PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void);
// Helper class for the DLL global lock.
//
// This class magically waits for PyXPCOM framework global lock, and releases it
// when finished.
// NEVER new one of these objects - only use on the stack!
class CEnterLeaveXPCOMFramework {
public:
CEnterLeaveXPCOMFramework() {PyXPCOM_AcquireGlobalLock();}
~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();}
};
// Python thread-lock stuff. Free-threading patches use different semantics, but
// these are abstracted away here...
//#include <threadstate.h>
// Helper class for Enter/Leave Python
//
// This class magically waits for the Python global lock, and releases it
// when finished.
// Nested invocations will deadlock, so be careful.
// NEVER new one of these objects - only use on the stack!
extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState;
extern PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure();
extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free();
extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear();
extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire();
extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release();
extern PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls();
extern PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure();
class CEnterLeavePython {
public:
CEnterLeavePython() {
created = PyXPCOM_ThreadState_Ensure();
PyXPCOM_InterpreterLock_Acquire();
if (created) {
// If pending python calls are waiting as we enter Python,
// it will generally mean an asynch signal handler, etc.
// We can either call it here, or wait for Python to call it
// as part of its "even 'n' opcodes" check. If we wait for
// Python to check it and the pending call raises an exception,
// then it is _our_ code that will fail - this is unfair,
// as the signal was raised before we were entered - indeed,
// we may be directly responding to the signal!
// Thus, we flush all the pending calls here, and report any
// exceptions via our normal exception reporting mechanism.
// We can then execute our code in the knowledge that only
// signals raised _while_ we are executing will cause exceptions.
PyXPCOM_MakePendingCalls();
}
}
~CEnterLeavePython() {
// The interpreter state must be cleared
// _before_ we release the lock, as some of
// the sys. attributes cleared (eg, the current exception)
// may need the lock to invoke their destructors -
// specifically, when exc_value is a class instance, and
// the exception holds the last reference!
if ( created )
PyXPCOM_ThreadState_Clear();
PyXPCOM_InterpreterLock_Release();
if ( created )
PyXPCOM_ThreadState_Free();
}
private:
PRBool created;
};
#endif // __PYXPCOM_H__

View File

@@ -0,0 +1,49 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// standard include - sets up all the defines used by
// the mozilla make process - too lazy to work out how to integrate
// with their make, so this will do!
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
// Main Mozilla cross-platform declarations.
#include "xp_core.h"
#ifdef _DEBUG
# ifndef DEBUG
# define DEBUG
# endif
# define DEVELOPER_DEBUG
# define NS_DEBUG
# define DEBUG_markh
#endif // DEBUG
#include <nsIAllocator.h>
#include <nsIWeakReference.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"
#define BUILD_PYXPCOM
#ifdef HAVE_LONG_LONG
// Mozilla also defines this - we undefine it to
// prevent a compiler warning.
# undef HAVE_LONG_LONG
#endif // HAVE_LONG_LONG
#include "Python.h"
#include "PyXPCOM.h"

View File

@@ -0,0 +1,136 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// Pyxpt_info.cpp - wrappers for the xpt_info objects.
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d)
{
if (d==nsnull) {
Py_INCREF(Py_None);
return Py_None;
}
return Py_BuildValue("bbbh",
d->prefix.flags,
d->argnum,
d->argnum2,
d->type.iface // this is actually a union!
);
}
PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d)
{
if (d==nsnull) {
Py_INCREF(Py_None);
return Py_None;
}
PyObject *ob = PyObject_FromXPTTypeDescriptor(&d->type);
PyObject *ret = Py_BuildValue("bO", d->flags, ob);
Py_DECREF(ob);
return ret;
}
PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d)
{
if (d==nsnull) {
Py_INCREF(Py_None);
return Py_None;
}
PyObject *ob_params = PyTuple_New(d->num_args);
if (ob_params==NULL)
return NULL;
for (int i=0;i<d->num_args;i++)
PyTuple_SET_ITEM(ob_params, i, PyObject_FromXPTParamDescriptor(d->params+i));
PyObject *ob_ret = PyObject_FromXPTParamDescriptor(d->result);
PyObject *ret = Py_BuildValue("bsOO", d->flags, d->name, ob_params, ob_ret);
Py_XDECREF(ob_ret);
Py_XDECREF(ob_params);
return ret;
}
PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c)
{
if (c==nsnull) {
Py_INCREF(Py_None);
return Py_None;
}
PyObject *ob_type = PyObject_FromXPTTypeDescriptor(&c->type);
if (ob_type==NULL)
return NULL;
PyObject *v = NULL;
switch (c->type.prefix.flags) {
case TD_INT8:
v = PyInt_FromLong( c->value.i8 );
break;
case TD_INT16:
v = PyInt_FromLong( c->value.i16 );
break;
case TD_INT32:
v = PyInt_FromLong( c->value.i32 );
break;
case TD_INT64:
v = PyLong_FromLongLong(c->value.i64);
break;
case TD_UINT8:
v = PyInt_FromLong( c->value.ui8 );
break;
case TD_UINT16:
v = PyInt_FromLong( c->value.ui16 );
break;
case TD_UINT32:
v = PyInt_FromLong( c->value.ui8 );
break;
case TD_UINT64:
v = PyLong_FromUnsignedLongLong(c->value.ui64);
break;
case TD_FLOAT:
v = PyFloat_FromDouble(c->value.flt);
break;
case TD_DOUBLE:
v = PyFloat_FromDouble(c->value.dbl);
break;
case TD_BOOL:
v = c->value.bul ? Py_True : Py_False;
Py_INCREF(v);
break;
case TD_CHAR:
v = PyString_FromStringAndSize(&c->value.ch, 1);
break;
case TD_WCHAR:
v = PyUnicode_FromUnicode(&c->value.wch, 1);
break;
// TD_VOID = 13,
case TD_PNSIID:
v = Py_nsIID::PyObjectFromIID(*c->value.iid);
break;
// TD_PBSTR = 15,
case TD_PSTRING:
v = PyString_FromString(c->value.str);
break;
case TD_PWSTRING:
v = PyUnicode_FromUnicode(c->value.wstr, nsCRT::strlen(c->value.wstr));
break;
// TD_INTERFACE_TYPE = 18,
// TD_INTERFACE_IS_TYPE = 19,
// TD_ARRAY = 20,
// TD_PSTRING_SIZE_IS = 21,
// TD_PWSTRING_SIZE_IS = 22
default:
v = PyString_FromString("Unknown type code!!");
break;
}
PyObject *ret = Py_BuildValue("sbO", c->name, ob_type, v);
Py_DECREF(ob_type);
Py_DECREF(v);
return ret;
}

View File

@@ -0,0 +1,194 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <nsIInterfaceInfoManager.h>
#include <nsISupportsPrimitives.h>
static PyTypeObject PyInterfaceType_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* Number of items for varobject */
"interface-type", /* Name of this type */
sizeof(PyTypeObject), /* Basic object size */
0, /* Item size for varobject */
0, /*tp_dealloc*/
0, /*tp_print*/
PyType_Type.tp_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
PyType_Type.tp_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_xxx1*/
0, /*tp_xxx2*/
0, /*tp_xxx3*/
0, /*tp_xxx4*/
"Define the behavior of a PythonCOM Interface type.",
};
/*static*/ PRBool
PyXPCOM_TypeObject::IsType(PyTypeObject *t)
{
return t->ob_type == &PyInterfaceType_Type;
}
////////////////////////////////////////////////////////////////////
//
// The type methods
//
/*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);
}
/*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;
}
// @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity.
/*static*/int
PyXPCOM_TypeObject::Py_cmp(PyObject *self, PyObject *other)
{
// @comm NOTE: Copied from COM - have not confirmed these rules are true for XPCOM
// @comm As per the XPCOM rules for object identity, both objects are queried for nsISupports, and these values compared.
// The only meaningful test is for equality - the result of other comparisons is undefined
// (ie, determined by the object's relative addresses in memory.
nsISupports *pUnkOther;
nsISupports *pUnkThis;
if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE))
return -1;
if (!Py_nsISupports::InterfaceFromPyObject(other, NS_GET_IID(nsISupports), &pUnkOther, PR_FALSE)) {
pUnkThis->Release();
return -1;
}
int rc = pUnkThis==pUnkOther ? 0 :
(pUnkThis < pUnkOther ? -1 : 1);
pUnkThis->Release();
pUnkOther->Release();
return rc;
}
// @pymethod int|Py_nsISupports|__hash__|Implement a hash-code for the XPCOM object using XPCOM identity rules.
/*static*/long PyXPCOM_TypeObject::Py_hash(PyObject *self)
{
// We always return the value of the nsISupports *.
nsISupports *pUnkThis;
if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE))
return -1;
long ret = _Py_HashPointer(pUnkThis);
pUnkThis->Release();
return ret;
}
// @method string|Py_nsISupports|__repr__|Called to create a representation of a Py_nsISupports object
/*static */PyObject *
PyXPCOM_TypeObject::Py_repr(PyObject *self)
{
// @comm The repr of this object displays both the object's address, and its attached nsISupports's address
Py_nsISupports *pis = (Py_nsISupports *)self;
// Try and get the IID name.
char *iid_repr;
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
if (iim!=nsnull)
iim->GetNameForIID(&pis->m_iid, &iid_repr);
if (iid_repr==nsnull)
// no IIM available, or it doesnt know the name.
iid_repr = pis->m_iid.ToString();
// XXX - need some sort of buffer overflow.
char buf[512];
sprintf(buf, "<XPCOM object (%s) at 0x%p/0x%p>", iid_repr, self, pis->m_obj);
nsAllocator::Free(iid_repr);
return PyString_FromString(buf);
}
/*static */PyObject *
PyXPCOM_TypeObject::Py_str(PyObject *self)
{
Py_nsISupports *pis = (Py_nsISupports *)self;
nsresult rv;
char *val = NULL;
Py_BEGIN_ALLOW_THREADS;
{ // scope to kill pointer while thread-lock released.
nsCOMPtr<nsISupportsString> ss( do_QueryInterface(pis->m_obj, &rv ));
if (NS_SUCCEEDED(rv))
rv = ss->ToString(&val);
} // end-scope
Py_END_ALLOW_THREADS;
PyObject *ret;
if (NS_FAILED(rv))
ret = Py_repr(self);
else
ret = PyString_FromString(val);
if (val) nsAllocator::Free(val);
return ret;
}
/* static */void
PyXPCOM_TypeObject::Py_dealloc(PyObject *self)
{
delete (Py_nsISupports *)self;
}
PyXPCOM_TypeObject::PyXPCOM_TypeObject( const char *name, PyXPCOM_TypeObject *pBase, int typeSize, struct PyMethodDef* methodList, PyXPCOM_I_CTOR thector)
{
static const PyTypeObject type_template = {
PyObject_HEAD_INIT(&PyInterfaceType_Type)
0, /*ob_size*/
"XPCOMTypeTemplate", /*tp_name*/
sizeof(Py_nsISupports), /*tp_basicsize*/
0, /*tp_itemsize*/
Py_dealloc, /* tp_dealloc */
0, /* tp_print */
Py_getattr, /* tp_getattr */
Py_setattr, /* tp_setattr */
Py_cmp, /* tp_compare */
Py_repr, /* tp_repr */
0, /* tp_as_number*/
0, /* tp_as_sequence */
0, /* tp_as_mapping */
Py_hash, /* tp_hash */
0, /* tp_call */
Py_str, /* tp_str */
};
*((PyTypeObject *)this) = type_template;
chain.methods = methodList;
chain.link = pBase ? &pBase->chain : NULL;
baseType = pBase;
ctor = thector;
// cast away const, as Python doesnt use it.
tp_name = (char *)name;
tp_basicsize = typeSize;
}
PyXPCOM_TypeObject::~PyXPCOM_TypeObject()
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include <prthread.h>
#ifdef XP_WIN
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
static PRInt32 g_cLockCount = 0;
static PRBool bDidInitPython = PR_FALSE;
static PyThreadState *ptsGlobal = nsnull;
PyInterpreterState *PyXPCOM_InterpreterState;
static PRLock *g_lockMain = nsnull;
PRUintn tlsIndex = 0;
////////////////////////////////////////////////////////////
// Thread-state helpers/global functions.
//
// This function must be called at some time when the interpreter lock and state is valid.
// Called by init{module} functions and also COM factory entry point.
void PyXPCOM_InterpreterState_Ensure()
{
if (PyXPCOM_InterpreterState==NULL) {
PyThreadState *threadStateSave = PyThreadState_Swap(NULL);
if (threadStateSave==NULL)
Py_FatalError("Can not setup interpreter state, as current state is invalid");
PyXPCOM_InterpreterState = threadStateSave->interp;
PyThreadState_Swap(threadStateSave);
}
}
void PyXPCOM_InterpreterState_Free()
{
PyXPCOM_ThreadState_Free();
PyXPCOM_InterpreterState = NULL; // Eek - should I be freeing something?
}
// This structure is stored in the TLS slot. At this stage only a Python thread state
// is kept, but this may change in the future...
struct ThreadData{
PyThreadState *ts;
};
// Ensure that we have a Python thread state available to use.
// If this is called for the first time on a thread, it will allocate
// the thread state. This does NOT change the state of the Python lock.
// Returns TRUE if a new thread state was created, or FALSE if a
// thread state already existed.
PRBool PyXPCOM_ThreadState_Ensure()
{
ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
if (pData==NULL) { /* First request on this thread */
/* Check we have an interpreter state */
if (PyXPCOM_InterpreterState==NULL) {
Py_FatalError("Can not setup thread state, as have no interpreter state");
}
pData = (ThreadData *)nsAllocator::Alloc(sizeof(ThreadData));
if (!pData)
Py_FatalError("Out of memory allocating thread state.");
memset(pData, 0, sizeof(*pData));
if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) {
NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!");
Py_FatalError("Could not thread private thread data!");
}
pData->ts = PyThreadState_New(PyXPCOM_InterpreterState);
return PR_TRUE; // Did create a thread state state
}
return PR_FALSE; // Thread state was previously created
}
// Asuming we have a valid thread state, acquire the Python lock.
void PyXPCOM_InterpreterLock_Acquire()
{
ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!");
PyThreadState *thisThreadState = pData->ts;
PyEval_AcquireThread(thisThreadState);
}
// Asuming we have a valid thread state, release the Python lock.
void PyXPCOM_InterpreterLock_Release()
{
ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!");
PyThreadState *thisThreadState = pData->ts;
PyEval_ReleaseThread(thisThreadState);
}
// Free the thread state for the current thread
// (Presumably previously create with a call to
// PyXPCOM_ThreadState_Ensure)
void PyXPCOM_ThreadState_Free()
{
ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
if (!pData) return;
PyThreadState *thisThreadState = pData->ts;
PyThreadState_Delete(thisThreadState);
PR_SetThreadPrivate(tlsIndex, NULL);
nsAllocator::Free(pData);
}
void PyXPCOM_ThreadState_Clear()
{
ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
PyThreadState *thisThreadState = pData->ts;
PyThreadState_Clear(thisThreadState);
}
////////////////////////////////////////////////////////////
// Lock/exclusion global functions.
//
void PyXPCOM_AcquireGlobalLock(void)
{
NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!");
PR_Lock(g_lockMain);
}
void PyXPCOM_ReleaseGlobalLock(void)
{
NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!");
PR_Unlock(g_lockMain);
}
void PyXPCOM_DLLAddRef(void)
{
// Must be thread-safe, although cant have the Python lock!
CEnterLeaveXPCOMFramework _celf;
PRInt32 cnt = PR_AtomicIncrement(&g_cLockCount);
if (cnt==1) { // First call
if (!Py_IsInitialized()) {
Py_Initialize();
// Make sure our Windows framework is all setup.
PyXPCOM_Globals_Ensure();
// Make sure we have _something_ as sys.argv.
if (PySys_GetObject("argv")==NULL) {
PyObject *path = PyList_New(0);
PyObject *str = PyString_FromString("");
PyList_Append(path, str);
PySys_SetObject("argv", path);
Py_XDECREF(path);
Py_XDECREF(str);
}
// Must force Python to start using thread locks, as
// we are free-threaded (maybe, I think, sometimes :-)
PyEval_InitThreads();
// Release Python lock, as first thing we do is re-get it.
ptsGlobal = PyEval_SaveThread();
// NOTE: We never finalize Python!!
}
}
}
void PyXPCOM_DLLRelease(void)
{
PR_AtomicDecrement(&g_cLockCount);
}
extern "C" PRBool _init(void)
{
PRStatus status;
g_lockMain = PR_NewLock();
status = PR_NewThreadPrivateIndex( &tlsIndex, NULL );
NS_WARN_IF_FALSE(status==0, "Could not allocate TLS storage");
if (NS_FAILED(status)) {
PR_DestroyLock(g_lockMain);
return PR_FALSE;
}
return PR_TRUE;
}
extern "C" void _fini(void)
{
PR_DestroyLock(g_lockMain);
// I can't locate a way to kill this -
// should I pass a dtor to PR_NewThreadPrivateIndex??
// TlsFree(tlsIndex);
}
#ifdef XP_WIN
extern "C" __declspec(dllexport)
BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH: {
if (!_init())
return FALSE;
break;
}
case DLL_PROCESS_DETACH:
{
_fini();
break;
}
default:
break;
}
return TRUE; // ok
}
#endif // XP_WIN

View File

@@ -0,0 +1,392 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// pyloader
//
// Not part of the main Python _xpcom package, but a seperate, thin DLL.
//
// The main loader and registrar for Python. A thin DLL that is designed to live in
// the xpcom "components" directory. Simply locates and loads the standard
// _xpcom support module and transfers control to that.
#include "xp_core.h"
#include "nsIComponentLoader.h"
#include "nsIRegistry.h"
#include "nsISupports.h"
#include "nsIModule.h"
#include <nsFileStream.h> // For console logging.
#ifdef HAVE_LONG_LONG
#undef HAVE_LONG_LONG
#endif
#ifdef XP_WIN
// Can only assume dynamic loading on Windows.
#define LOADER_LINKS_WITH_PYTHON
#endif
#ifdef LOADER_LINKS_WITH_PYTHON
#include "Python.h"
static PyThreadState *ptsGlobal = nsnull;
static char *PyTraceback_AsString(PyObject *exc_tb);
#else // LOADER_LINKS_WITH_PYTHON
static PRBool find_xpcom_module(char *buf, size_t bufsize);
#endif // LOADER_LINKS_WITH_PYTHON
#ifdef XP_WIN
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#ifdef XP_UNIX
#include <dlfcn.h>
#include <sys/stat.h>
#endif
typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr,
nsIFile* location,
nsIModule** result);
pfnPyXPCOM_NSGetModule pfnEntryPoint = nsnull;
static void LogError(const char *fmt, ...);
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
nsIFile* location,
nsIModule** result)
{
// What to do for other platforms here?
// I tried using their nsDll class, but it wont allow
// a LoadLibrary() - it insists on a full path it can load.
// So if Im going to the trouble of locating the DLL on Windows,
// I may as well just do the whole thing myself.
#ifdef LOADER_LINKS_WITH_PYTHON
PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-)
if (bDidInitPython) {
// If Python was already initialized, we almost certainly
// do not have the thread-lock, so can not attempt to import anything
// We simply must assume/hope that Python already has our module loaded.
Py_Initialize();
if (!Py_IsInitialized()) {
LogError("Python initialization failed!\n");
return NS_ERROR_FAILURE;
}
PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
if (mod==NULL) {
LogError("Could not import the Python XPCOM extension\n");
return NS_ERROR_FAILURE;
}
}
#endif // LOADER_LINKS_WITH_PYTHON
if (pfnEntryPoint == nsnull) {
#ifdef XP_WIN
#ifdef DEBUG
const char *mod_name = "_xpcom_d.pyd";
#else
const char *mod_name = "_xpcom.pyd";
#endif
HMODULE hmod = GetModuleHandle(mod_name);
if (hmod==NULL) {
LogError("Could not get a handle to the Python XPCOM extension\n");
return NS_ERROR_FAILURE;
}
pfnEntryPoint = (pfnPyXPCOM_NSGetModule)GetProcAddress(hmod, "PyXPCOM_NSGetModule");
#endif // XP_WIN
#ifdef XP_UNIX
static char module_path[1024];
if (!find_xpcom_module(module_path, sizeof(module_path)))
return NS_ERROR_FAILURE;
void *handle = dlopen(module_path, RTLD_GLOBAL | RTLD_LAZY);
if (handle==NULL) {
LogError("Could not open the Python XPCOM extension at '%s' - '%s'\n", module_path, dlerror());
return NS_ERROR_FAILURE;
}
pfnEntryPoint = (pfnPyXPCOM_NSGetModule)dlsym(handle, "PyXPCOM_NSGetModule");
#endif // XP_UNIX
}
if (pfnEntryPoint==NULL) {
LogError("Could not load main Python entry point\n");
return NS_ERROR_FAILURE;
}
#ifdef LOADER_LINKS_WITH_PYTHON
// We abandon the thread-lock, as the first thing Python does
// is re-establish the lock (the Python thread-state story SUCKS!!!
if (bDidInitPython)
ptsGlobal = PyEval_SaveThread();
// Note this is never restored, and Python is never finalized!
#endif // LOADER_LINKS_WITH_PYTHON
return (*pfnEntryPoint)(servMgr, location, result);
}
// The internal helper that actually moves the
// formatted string to the target!
void LogMessage(const char *prefix, const char *pszMessageText)
{
nsOutputConsoleStream console;
console << prefix << pszMessageText;
}
// A helper for the various logging routines.
static void VLogF(const char *prefix, const char *fmt, va_list argptr)
{
char buff[512];
vsprintf(buff, fmt, argptr);
LogMessage(prefix, buff);
}
static void LogError(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Error: ", fmt, marker);
#ifdef LOADER_LINKS_WITH_PYTHON
// If we have a Python exception, also log that:
PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
PyErr_Fetch( &exc_typ, &exc_val, &exc_tb);
if (exc_typ) {
char *string1 = nsnull;
nsOutputStringStream streamout(string1);
if (exc_tb) {
const char *szTraceback = PyTraceback_AsString(exc_tb);
if (szTraceback == NULL)
streamout << "Can't get the traceback info!";
else {
streamout << "Traceback (most recent call last):\n";
streamout << szTraceback;
PyMem_Free((ANY *)szTraceback);
}
}
PyObject *temp = PyObject_Str(exc_typ);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can convert exception to a string!";
streamout << ": ";
if (exc_val != NULL) {
temp = PyObject_Str(exc_val);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can convert exception value to a string!";
}
streamout << "\n";
LogMessage("PyXPCOM Exception:", string1);
}
PyErr_Restore(exc_typ, exc_val, exc_tb);
#endif // LOADER_LINKS_WITH_PYTHON
}
static void LogWarning(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Warning: ", fmt, marker);
}
#ifdef DEBUG
void LogDebug(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Debug: ", fmt, marker);
}
#else
#define LogDebug()
#endif
#ifdef LOADER_LINKS_WITH_PYTHON
/* Obtains a string from a Python traceback.
This is the exact same string as "traceback.print_exc" would return.
Pass in a Python traceback object (probably obtained from PyErr_Fetch())
Result is a string which must be free'd using PyMem_Free()
*/
#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
char *PyTraceback_AsString(PyObject *exc_tb)
{
char *errMsg = NULL; /* a static that hold a local error message */
char *result = NULL; /* a valid, allocated result. */
PyObject *modStringIO = NULL;
PyObject *modTB = NULL;
PyObject *obFuncStringIO = NULL;
PyObject *obStringIO = NULL;
PyObject *obFuncTB = NULL;
PyObject *argsTB = NULL;
PyObject *obResult = NULL;
/* Import the modules we need - cStringIO and traceback */
modStringIO = PyImport_ImportModule("cStringIO");
if (modStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant import cStringIO\n");
modTB = PyImport_ImportModule("traceback");
if (modTB==NULL)
TRACEBACK_FETCH_ERROR("cant import traceback\n");
/* Construct a cStringIO object */
obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n");
obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
if (obStringIO==NULL)
TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n");
/* Get the traceback.print_exception function, and call it. */
obFuncTB = PyObject_GetAttrString(modTB, "print_tb");
if (obFuncTB==NULL)
TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n");
argsTB = Py_BuildValue("OOO",
exc_tb ? exc_tb : Py_None,
Py_None,
obStringIO);
if (argsTB==NULL)
TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n");
obResult = PyObject_CallObject(obFuncTB, argsTB);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n");
/* Now call the getvalue() method in the StringIO instance */
Py_DECREF(obFuncStringIO);
obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find getvalue function\n");
Py_DECREF(obResult);
obResult = PyObject_CallObject(obFuncStringIO, NULL);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("getvalue() failed.\n");
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult))
TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n");
{ // a temp scope so I can use temp locals.
char *tempResult = PyString_AsString(obResult);
result = (char *)PyMem_Malloc(strlen(tempResult)+1);
if (result==NULL)
TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string");
strcpy(result, tempResult);
} // end of temp scope.
done:
/* All finished - first see if we encountered an error */
if (result==NULL && errMsg != NULL) {
result = (char *)PyMem_Malloc(strlen(errMsg)+1);
if (result != NULL)
/* if it does, not much we can do! */
strcpy(result, errMsg);
}
Py_XDECREF(modStringIO);
Py_XDECREF(modTB);
Py_XDECREF(obFuncStringIO);
Py_XDECREF(obStringIO);
Py_XDECREF(obFuncTB);
Py_XDECREF(argsTB);
Py_XDECREF(obResult);
return result;
}
#else // LOADER_LINKS_WITH_PYTHON
#ifdef XP_UNIX
// From Python getpath.c
#ifndef S_ISREG
#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#endif
static int
isfile(char *filename) /* Is file, not directory */
{
struct stat buf;
if (stat(filename, &buf) != 0)
return 0;
if (!S_ISREG(buf.st_mode))
return 0;
return 1;
}
static int
isxfile(char *filename) /* Is executable file */
{
struct stat buf;
if (stat(filename, &buf) != 0)
return 0;
if (!S_ISREG(buf.st_mode))
return 0;
if ((buf.st_mode & 0111) == 0)
return 0;
return 1;
}
static int
isdir(char *filename) /* Is directory */
{
struct stat buf;
if (stat(filename, &buf) != 0)
return 0;
if (!S_ISDIR(buf.st_mode))
return 0;
return 1;
}
PRBool find_xpcom_module(char *buf, size_t bufsize)
{
char *pypath = getenv("PYTHONPATH");
char *searchPath = pypath ? strdup(pypath) : NULL;
char *tok = searchPath ? strtok(searchPath, ":") : NULL;
while (tok != NULL) {
int thissize = bufsize;
int baselen = strlen(tok);
strncpy(buf, tok, thissize);
thissize-=baselen;
if (thissize > 1 && buf[baselen-1] != '/') {
buf[baselen++]='/';
}
strncpy(buf+baselen, "xpcom/_xpcommodule.so", thissize);
// LogDebug("Python _xpcom module at '%s'?\n", buf);
if (isfile(buf)) {
// LogDebug("Found python _xpcom module at '%s'\n", buf);
return PR_TRUE;
}
tok = strtok(NULL, ":");
}
LogError("Failed to find a Python _xpcom module\n");
return PR_FALSE;
}
#endif // XP_UNIX
#endif // LOADER_LINKS_WITH_PYTHON

View File

@@ -0,0 +1,66 @@
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation. -->
<!-- See the file LICENSE.txt for licensing information. -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Building the Python XPCOM package</title>
</head>
<body>
<h1>Building the Python XPCOM package.</h1>
<p>This file describes how to build the Python XPCOM C++ sources.</p>
<p>There are the following steps</p>
<ul>
<li><a href="#ConfiguringTheEnvironment">Configure environment variables</a></li>
<li><a href="#BuildingTheSources">Building the sources</a></li>
</ul>
<p>Testing etc is described in the <a href="../readme.html">main readme</a>.</p>
<h2><a name="ConfiguringTheEnvironment">Configuring environment variables</a></h2>
<h3> MOZ_SRC&nbsp;</h3>
<p><b>Windows: </b>Run the standard MOZENV.BAT used to build Mozilla.&nbsp; This
sets MOZ_SRC</p>
<p><b>Unix:</b> Set MOZ_SRC to point to the base source directory - assumes
&quot;mozilla&quot; sub-directory with mozilla directory tree under that. eg: assuming
<i>/home/user/src/mozilla/dist/...</i>&quot;</p>
<pre>export MOZ_SRC=/home/user/src</pre>
<h3>PYTHON_SRC</h3>
<p><b>Windows:</b> Set <i> PYTHON_SRC</i> to point to the base Python source directory.&nbsp;
eg: assuming <i>c:\src\python\PCBuild\...</i><pre>set PYTHON_SRC=c:\src\python</pre>
<p>Unix: Set PYTHON_SRC to point to the base of an &quot;installed&quot; Python
tree. eg:<pre>export PYTHON_SRC=/usr/local/ActivePython-1.6</pre>
<h2><a name="BuildingTheSources">Building the sources</a></h2>
<p>You must ensure some environment variables are setup.&nbsp; The section on <a href="#ConfiguringTheEnvironment">configuring
environment variables explains how.</a></p>
<p>There are 2 build processes to run All C++ sources are in the <i>xpcom\src</i>
directory.:</p>
<h3>Windows</h3>
<ul>
<li> Execute &quot;compile.py&quot; in this directory. This will take <i>Setup.in</i>, create an MSDev project, and build
<i>..\_xpcom.pyd</i> and <i>..\_xpcom_d.pyd</i>&quot;</li>
<li> Change to the <i>loader</i> directory.</li>
<li> Run <i>nmake -f makefile.win</i>. This will create <i>pyloader.dll</i>, and
automatically copy it to the Mozilla build directory.</li>
<a href="#ConfiguringTheEnvironment">
</ul>
<p>Finally, </a><a href="../readme.html#RunningTheTests">run the tests</a>,
where we also test everything imports correctly.</p>
<h3>Linux</h3>
<p><b> NOTE:</b> Do not attempt to use &quot;Setup.in&quot; to create a Makefile&nbsp;</p>
<ul>
<li>Run &quot;make&quot; in this directory.&nbsp; This will create <i>../_xpcommodule.so</i></li>
<li> Run "make" in the loader directory. This will create <i>libpyloader.so</i>,
and copy it to the Mozilla directory.</li>
<a href="#ConfiguringTheEnvironment">
</ul>
<p>Finally, </a><a href="../readme.html#RunningTheTests">running the tests</a>,
where we also test everything imports correctly.</p>
</body>
</html>

View File

@@ -0,0 +1,532 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (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>
#ifdef XP_WIN
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#include <nsIEventQueue.h>
#include <nsIProxyObjectManager.h>
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
extern void PyXPCOM_InterpreterState_Ensure();
extern PRInt32 _PyXPCOM_GetGatewayCount(void);
extern PRInt32 _PyXPCOM_GetInterfaceCount(void);
extern void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
// 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!
static PyObject *
PyXPCOMMethod_NS_LocateSpecialSystemDirectory(PyObject *self, PyObject *args)
{
int typ;
if (!PyArg_ParseTuple(args, "i", &typ))
return NULL;
nsIFileSpec *spec = NULL;
nsSpecialSystemDirectory systemDir((nsSpecialSystemDirectory::SystemDirectories)typ);
return PyString_FromString(systemDir.GetNativePathCString());
}
static PyObject *
PyXPCOMMethod_NS_NewFileSpec(PyObject *self, PyObject *args)
{
char *szspec = NULL;
if (!PyArg_ParseTuple(args, "|s", &szspec))
return NULL;
nsIFileSpec *spec = NULL;
nsresult nr;
Py_BEGIN_ALLOW_THREADS;
nr = NS_NewFileSpec(&spec);
if (NS_SUCCEEDED(nr) && spec && szspec)
nr = spec->SetNativePath(szspec);
Py_END_ALLOW_THREADS;
if (NS_FAILED(nr) || spec==nsnull)
return PyXPCOM_BuildPyException(nr);
return Py_nsISupports::PyObjectFromInterface(spec, NS_GET_IID(nsIFileSpec), PR_TRUE);
}
static PyObject *
PyXPCOMMethod_NS_GetGlobalComponentManager(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager* cm;
nsresult rv;
Py_BEGIN_ALLOW_THREADS;
rv = NS_GetGlobalComponentManager(&cm);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(rv) )
return PyXPCOM_BuildPyException(rv);
// NOTE - NS_GetGlobalComponentManager DOES NOT ADD A REFCOUNT
// (naughty, naughty) - we we explicitly ask our converter to
// add one, even tho this is not the common pattern.
// Return a type based on the IID
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_TRUE, PR_FALSE);
}
static PyObject *
PyXPCOMMethod_GetGlobalServiceManager(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIServiceManager* sm;
nsresult rv;
Py_BEGIN_ALLOW_THREADS;
rv = nsServiceManager::GetGlobalServiceManager(&sm);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(rv) )
return PyXPCOM_BuildPyException(rv);
// NOTE - GetGlobalServiceManager DOES NOT ADD A REFCOUNT
// (naughty, naughty) - we we explicitly ask our converter to
// add one, even tho this is not the common pattern.
// Return a type based on the IID
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager), PR_TRUE, PR_FALSE);
}
static PyObject *
PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIInterfaceInfoManager* im;
Py_BEGIN_ALLOW_THREADS;
im = XPTI_GetInterfaceInfoManager();
Py_END_ALLOW_THREADS;
if ( im == nsnull )
return PyXPCOM_BuildPyException(NS_ERROR_FAILURE);
/* Return a type based on the IID (with no extra ref) */
// Can not auto-wrap the interface info manager as it is critical to
// building the support we need for autowrap.
return Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE, PR_FALSE);
}
static PyObject *
PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args)
{
PyObject *obIS, *obParams;
nsCOMPtr<nsISupports> pis;
int index;
// We no longer rely on PyErr_Occurred() for our error state,
// but keeping this assertion can't hurt - it should still always be true!
NS_WARN_IF_FALSE(!PyErr_Occurred(), "Should be no pending Python error!");
if (!PyArg_ParseTuple(args, "OiO", &obIS, &index, &obParams))
return NULL;
// Ack! We must ask for the "native" interface supported by
// the object, not specifically nsISupports, else we may not
// back the same pointer (eg, Python, following identity rules,
// will return the "original" gateway when QI'd for nsISupports)
if (!Py_nsISupports::InterfaceFromPyObject(
obIS,
Py_nsIID_NULL,
getter_AddRefs(pis),
PR_FALSE))
return NULL;
PyXPCOM_InterfaceVariantHelper arg_helper;
if (!arg_helper.Init(obParams))
return NULL;
if (!arg_helper.FillArray())
return NULL;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = XPTC_InvokeByIndex(pis, index, arg_helper.m_num_array, arg_helper.m_var_array);
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
return arg_helper.MakePythonResult();
}
static PyObject *
PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
{
PyObject *ob, *obIID;
if (!PyArg_ParseTuple(args, "OO", &ob, &obIID))
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *ret = NULL;
nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, (void **)&ret);
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
// _ALL_ wrapped objects are associated with a weak-ref
// to their "main" instance.
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);
}
// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance
static PyObject *
PyXPCOMMethod_GetInterfaceCount(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":_GetInterfaceCount"))
return NULL;
return PyInt_FromLong(_PyXPCOM_GetInterfaceCount());
// @comm If is occasionally a good idea to call this function before your Python program
// terminates. If this function returns non-zero, then you still have PythonCOM objects
// alive in your program (possibly in global variables).
}
// @pymethod int|pythoncom|_GetGatewayCount|Retrieves the number of gateway objects currently in existance
static PyObject *
PyXPCOMMethod_GetGatewayCount(PyObject *self, PyObject *args)
{
// @comm This is the number of Python object that implement COM servers which
// are still alive (ie, serving a client). The only way to reduce this count
// is to have the process which uses these PythonCOM servers release its references.
if (!PyArg_ParseTuple(args, ":_GetGatewayCount"))
return NULL;
return PyInt_FromLong(_PyXPCOM_GetGatewayCount());
}
static PyObject *
PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args)
{
// @comm This is the number of Python object that implement COM servers which
// are still alive (ie, serving a client). The only way to reduce this count
// is to have the process which uses these PythonCOM servers release its references.
if (!PyArg_ParseTuple(args, ":NS_ShutdownXPCOM"))
return NULL;
nsresult nr;
Py_BEGIN_ALLOW_THREADS;
nr = NS_ShutdownXPCOM(nsnull);
Py_END_ALLOW_THREADS;
// Dont raise an exception - as we are probably shutting down
// and dont really case - just return the status
return PyInt_FromLong(nr);
}
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
// A hack to work around their magic constants!
static PyObject *
PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args)
{
PyObject *obQueue, *obIID, *obOb;
int flags;
if (!PyArg_ParseTuple(args, "OOOi", &obQueue, &obIID, &obOb, &flags))
return NULL;
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsCOMPtr<nsISupports> pob;
if (!Py_nsISupports::InterfaceFromPyObject(obOb, iid, getter_AddRefs(pob), PR_FALSE))
return NULL;
nsIEventQueue *pQueue = NULL;
nsIEventQueue *pQueueRelease = NULL;
if (PyInt_Check(obQueue)) {
pQueue = (nsIEventQueue *)PyInt_AsLong(obQueue);
} else {
if (!Py_nsISupports::InterfaceFromPyObject(obQueue, NS_GET_IID(nsIEventQueue), (nsISupports **)&pQueue, PR_TRUE))
return NULL;
pQueueRelease = pQueue;
}
nsresult rv_proxy;
nsISupports *presult = nsnull;
Py_BEGIN_ALLOW_THREADS;
NS_WITH_SERVICE(nsIProxyObjectManager,
proxyMgr,
kProxyObjectManagerCID,
&rv_proxy);
if ( NS_SUCCEEDED(rv_proxy) ) {
rv_proxy = proxyMgr->GetProxyForObject(pQueue,
iid,
pob,
flags,
(void **)&presult);
}
if (pQueueRelease)
pQueueRelease->Release();
Py_END_ALLOW_THREADS;
PyObject *result;
if (NS_SUCCEEDED(rv_proxy) ) {
result = Py_nsISupports::PyObjectFromInterface(presult, iid, PR_FALSE);
} else {
result = PyXPCOM_BuildPyException(rv_proxy);
}
return result;
}
PyObject *AllocateBuffer(PyObject *self, PyObject *args)
{
int bufSize;
if (!PyArg_ParseTuple(args, "i", &bufSize))
return NULL;
return PyBuffer_New(bufSize);
}
PyObject *LogWarning(PyObject *self, PyObject *args)
{
char *msg;
if (!PyArg_ParseTuple(args, "s", &msg))
return NULL;
PyXPCOM_LogWarning("%s", msg);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *LogError(PyObject *self, PyObject *args)
{
char *msg;
if (!PyArg_ParseTuple(args, "s", &msg))
return NULL;
PyXPCOM_LogError("%s", msg);
Py_INCREF(Py_None);
return Py_None;
}
extern PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args);
static struct PyMethodDef xpcom_methods[]=
{
{"NS_LocateSpecialSystemDirectory", PyXPCOMMethod_NS_LocateSpecialSystemDirectory, 1},
{"NS_GetGlobalComponentManager", PyXPCOMMethod_NS_GetGlobalComponentManager, 1},
{"NS_NewFileSpec", PyXPCOMMethod_NS_NewFileSpec, 1},
{"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1},
{"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1},
{"GetGlobalServiceManager", PyXPCOMMethod_GetGlobalServiceManager, 1},
{"IID", PyXPCOMMethod_IID, 1}, // IID is wrong - deprecated - not just IID, but CID, etc.
{"ID", PyXPCOMMethod_IID, 1}, // This is the official name.
{"NS_ShutdownXPCOM", PyXPCOMMethod_NS_ShutdownXPCOM, 1},
{"WrapObject", PyXPCOMMethod_WrapObject, 1},
{"_GetInterfaceCount", PyXPCOMMethod_GetInterfaceCount, 1},
{"_GetGatewayCount", PyXPCOMMethod_GetGatewayCount, 1},
{"getProxyForObject", PyXPCOMMethod_GetProxyForObject, 1},
{"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1},
{"AllocateBuffer", AllocateBuffer, 1},
{"LogWarning", LogWarning, 1},
{"LogError", LogError, 1},
{ NULL }
};
////////////////////////////////////////////////////////////
// Other helpers/global functions.
//
PRBool PyXPCOM_Globals_Ensure()
{
PRBool rc = PR_TRUE;
PyXPCOM_InterpreterState_Ensure();
// The exception object - we load it from .py code!
if (PyXPCOM_Error == NULL) {
rc = PR_FALSE;
PyObject *mod = NULL;
mod = PyImport_ImportModule("xpcom");
if (mod!=NULL) {
PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception");
Py_DECREF(mod);
}
rc = (PyXPCOM_Error != NULL);
}
if (!rc)
return rc;
static PRBool bHaveInitXPCOM = PR_FALSE;
if (!bHaveInitXPCOM) {
nsCOMPtr<nsIThread> thread_check;
// xpcom appears to assert if already initialized
// Is there an official way to determine this?
if (NS_FAILED(nsIThread::GetMainThread(getter_AddRefs(thread_check)))) {
// not already initialized.
// We need to locate the Mozilla bin directory.
#ifdef XP_WIN
// On Windows this by using "xpcom.dll"
char landmark[MAX_PATH+1];
HMODULE hmod = GetModuleHandle("xpcom.dll");
if (hmod==NULL) {
PyErr_SetString(PyExc_RuntimeError, "We dont appear to be linked against xpcom.dll!?!?");
return PR_FALSE;
}
GetModuleFileName(hmod, landmark, sizeof(landmark)/sizeof(landmark[0]));
char *end = landmark + (strlen(landmark)-1);
while (end > landmark && *end != '\\')
end--;
if (end > landmark) *end = '\0';
nsCOMPtr<nsILocalFile> ns_bin_dir;
NS_NewLocalFile(landmark, PR_FALSE, getter_AddRefs(ns_bin_dir));
nsresult rv = NS_InitXPCOM(nsnull, ns_bin_dir);
#else
// Elsewhere, Mozilla can find it itself (we hope!)
nsresult rv = NS_InitXPCOM(nsnull, nsnull);
#endif // XP_WIN
if (NS_FAILED(rv)) {
PyErr_SetString(PyExc_RuntimeError, "The XPCOM subsystem could not be initialized");
return PR_FALSE;
}
// Also set the "special directory"
#ifdef XP_WIN
nsFileSpec spec(landmark);
nsSpecialSystemDirectory::Set(nsSpecialSystemDirectory::OS_CurrentProcessDirectory, &spec);
#endif // XP_WIN
}
// Even if xpcom was already init, we want to flag it as init!
bHaveInitXPCOM = PR_TRUE;
}
return rc;
}
#define REGISTER_IID(t) { \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \
PyDict_SetItemString(dict, "IID_"#t, iid_ob); \
Py_DECREF(iid_ob); \
}
#define REGISTER_INT(val) { \
PyObject *ob = PyInt_FromLong(val); \
PyDict_SetItemString(dict, #val, ob); \
Py_DECREF(ob); \
}
////////////////////////////////////////////////////////////
// The module init code.
//
extern "C"
#ifdef MS_WIN32
__declspec(dllexport)
#endif
void
init_xpcom() {
PyObject *oModule;
// ensure the framework has valid state to work with.
if (!PyXPCOM_Globals_Ensure())
return;
// Must force Python to start using thread locks
PyEval_InitThreads();
// Create the module and add the functions
oModule = Py_InitModule("_xpcom", xpcom_methods);
PyObject *dict = PyModule_GetDict(oModule);
PyObject *pycom_Error = PyXPCOM_Error;
if (pycom_Error == NULL || PyDict_SetItemString(dict, "error", pycom_Error) != 0)
{
PyErr_SetString(PyExc_MemoryError, "can't define error");
return;
}
PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type);
REGISTER_IID(nsISupports);
REGISTER_IID(nsISupportsString);
REGISTER_IID(nsIModule);
REGISTER_IID(nsIFactory);
REGISTER_IID(nsIWeakReference);
REGISTER_IID(nsISupportsWeakReference);
// Register our custom interfaces.
Py_nsISupports::InitType();
Py_nsIComponentManager::InitType(dict);
Py_nsIInterfaceInfoManager::InitType(dict);
Py_nsIEnumerator::InitType(dict);
Py_nsISimpleEnumerator::InitType(dict);
Py_nsIInterfaceInfo::InitType(dict);
Py_nsIServiceManager::InitType(dict);
Py_nsIInputStream::InitType(dict);
// We have special support for proxies - may as well add their constants!
REGISTER_INT(PROXY_SYNC);
REGISTER_INT(PROXY_ASYNC);
REGISTER_INT(PROXY_ALWAYS);
}

View File

@@ -0,0 +1,8 @@
test_com_exceptions
** Unhandled exception calling 'int8 do_short(in int16, inout int16, out int16, out retval int16);'
** Returning nsresult of NS_ERROR_FAILURE
** Unhandled exception calling 'int8 do_unsigned_short(in uint16, inout uint16, out uint16, out retval uint16);'
** Returning nsresult of NS_ERROR_FAILURE
** Unhandled exception calling 'int8 do_unsigned_long_long(in uint64, inout uint64, out uint64, out retval uint64);'
** Returning nsresult of NS_ERROR_FAILURE
The xpcom exception tests passed

View File

@@ -0,0 +1,7 @@
test_comfile
Open as string test worked.
Open as URL test worked.
File test using buffers worked.
Local file read test worked.
Read the correct data.
Chunks read the correct data.

View File

@@ -0,0 +1,4 @@
test_components
The interfaces object appeared to work!
The classes object appeared to work!
The ID function appeared to work!

View File

@@ -0,0 +1,2 @@
test_isupports_primitives
The nsISupports primitive interface tests appeared to work

View File

@@ -0,0 +1,9 @@
test_misc
Running all tests - use '-h' to see command-line options...
The netscape sample worked!
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

View File

@@ -0,0 +1 @@
test_streams

View File

@@ -0,0 +1,4 @@
test_test_component
Testing the Python.TestComponent component
The Python test component worked!
Javascript could successfully use the Python test component.

View File

@@ -0,0 +1,2 @@
test_weakreferences
Weak-reference tests appear to have worked!

View File

@@ -0,0 +1,18 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# regrtest.py
#
# The Regression Tests for the xpcom package.
import os
import sys
import test.regrtest # The standard Python test suite.
path = os.path.abspath(os.path.split(sys.argv[0])[0])
tests = []
for arg in sys.argv[1:]:
if arg[0] not in "-/":
tests.append(arg)
tests = tests or test.regrtest.findtests(path, [])
test.regrtest.main(tests, path)

View File

@@ -0,0 +1,70 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Test pyxpcom exception.
from xpcom import components, nsError, ServerException, COMException
from xpcom.server import WrapObject
class PythonFailingComponent:
# Re-use the test interface for this test.
_com_interfaces_ = components.interfaces.nsIPythonTestInterfaceExtra
def do_boolean(self, p1, p2):
# This should cause the caller to see a "silent" NS_ERROR_FAILURE exception.
raise ServerException()
def do_octet(self, p1, p2):
# This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception.
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
def do_short(self, p1, p2):
# This should cause the caller to see a "debug" NS_ERROR_FAILURE exception.
raise COMException(nsError.NS_ERROR_NOT_IMPLEMENTED)
def do_unsigned_short(self, p1, p2):
# This should cause the caller to see a "debug" NS_ERROR_FAILURE exception.
raise "Foo"
def do_long(self, p1, p2):
# This should cause the caller to see a "silent" NS_ERROR_FAILURE exception.
raise ServerException
def do_unsigned_long(self, p1, p2):
# This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception.
raise ServerException, nsError.NS_ERROR_NOT_IMPLEMENTED
def do_long_long(self, p1, p2):
# This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception.
raise ServerException, (nsError.NS_ERROR_NOT_IMPLEMENTED, "testing")
def do_unsigned_long_long(self, p1, p2):
# Report of a crash in this case - test it!
raise ServerException, "A bad exception param"
def _testit(expected_errno, func, *args):
try:
apply(func, args)
except COMException, what:
if what.errno != expected_errno:
raise
def test():
# For the benefit of the test suite, we print some reassuring messages.
import sys
sys.__stderr__.write("***** NOTE: Three tracebacks below this is normal\n")
ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra)
_testit(nsError.NS_ERROR_FAILURE, ob.do_boolean, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_octet, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_short, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_short, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_long, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_unsigned_long, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_long_long, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_long_long, 0, 0)
print "The xpcom exception tests passed"
# For the benefit of the test suite, some more reassuring messages.
sys.__stderr__.write("***** NOTE: Three tracebacks printed above this is normal\n")
sys.__stderr__.write("***** It is testing the Python XPCOM Exception semantics\n")
test()

View File

@@ -0,0 +1,7 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
"""Test the xpcom.file module."""
# Called "test_comfile" as Python has a standard test called test_file :-(
import xpcom.file
xpcom.file._TestAll()

View File

@@ -0,0 +1,149 @@
<!-- Copyright (c) 2000-2001 ActiveState Tool Corporation. -->
<!-- See the file LICENSE.txt for licensing information. -->
<center><b><font size=+2>Python Component Sample</font></b>
<p>
<br>
Last modified
<script>
document.write(document.lastModified);
</script>
</center>
<p>XPConnect allows JavaScript
to transparantly access and manipulate XPCOM objects;
<p>Big Deal, I hear you say! But it also works for Python!!!
<p>
This sample demonstrates accessing a XPCOM object through XPConnect.
The JavaScript executed when this page loads creates an instance
of the Python object by
using the <tt>Components</tt> object, then accesses it through
the <a href="py_test_component.idl">nsISample</a> interface by calling <tt>QueryInterface</tt>:
<br>
<pre>
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var sample = Components.classes["component://mozilla/sample/sample-world"].createInstance();
sample = sample.QueryInterface(Components.interfaces.nsISample);
</pre>
<p>
The buttons on the form are connected to JavaScript event handlers which
call the methods defined in Python
<p><b><a name="Compiling">Compiling the idl</b>
<p>The XPIDL compiler (xpidl on Unix, xpidl.exe on Windows, and a CodeWarrior plugin on Mac)
is compiled at build time (except on Mac) thus
you will have to build mozilla in order to test this out. If you
have already built mozilla then the compiler will be located at <tt>mozilla\dist\WIN32_D.OBJ\bin\xpidl.exe</tt>.
<p>Once you have the XPIDL compiler enter the following command at your
prompt:
<br><tt>D:\whereever\xpcom\test\test_component>d:\mozilla\dist\WIN32_D.OBJ\bin\xpidl -I
d:\mozilla\dist\idl -m typelib py_test_component.idl</tt>. You must then copy the generated .xpt file
to the mozilla component directory.
<p>The <tt>-I d:\mozilla\dist\idl</tt> points the compiler to the folder
containing the other idl files, needed because nsISample.idl inherits from
nsISupports.idl. The <tt>-m typelib</tt> instruction tells the compiler
to build the .XPT typelib file.</tt>.
<p>
For more information on compilation see the <a href="http://www.mozilla.org/scriptable/xpidl/">xpidl
compiler page</a>.
<p><b>Running the sample</b>
<p><b>NOTE: This doesnt work for me - I get an access denied error using XPConnect!</b>
<p>Using Mozilla, load this file. Pay attention
to the console when clicking "write".
<!-- XXX keep in sync with stuff in pre tag below -->
<script>
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var sample = Components.classes["Python.TestComponent"].createInstance();
sample = sample.QueryInterface(Components.interfaces.nsIPythonTestInterface);
dump("sample = " + sample + "\n");
function get()
{
var field = document.getElementById('Value');
field.value = sample.str_value;
}
function set()
{
var field = document.getElementById('Value');
sample.str_value = field.value;
}
function poke()
{
var field = document.getElementById('Value');
sample.poke(field.value);
}
function write()
{
sample.writeValue("here is what I'm writing: ");
}
</script>
<p>
<form name="form">
<input type="button" value="Get" onclick="get();">
<input type="button" value="Set" onclick="set();">
<input type="button" value="Poke" onclick="poke();">
<input type="text" id="Value">
<input type="button" value="Write" onclick="write();">
<form>
<hr>
<p>
JavaScript and form source:
<!-- XXX keep in sync with actual script -->
<pre>
&lt;script&gt;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var sample = Components.classes["component://Python.TestComponent"].createInstance();
sample = sample.QueryInterface(Components.interfaces.nsIPythonTestInterface);
dump("sample = " + sample + "\n");
function get()
{
var field = document.getElementById('Value');
field.value = sample.str_value;
}
function set()
{
var field = document.getElementById('Value');
sample.str_value = field.value;
}
function poke()
{
var field = document.getElementById('Value');
sample.poke(field.value);
}
function write()
{
sample.writeValue("here is what I'm writing: ");
}
&lt;/script&gt;
&lt;form name=&quot;form&quot;&gt;
&lt;input type=&quot;button&quot; value=&quot;Get&quot; onclick=&quot;get();&quot;&gt;
&lt;input type=&quot;button&quot; value=&quot;Set&quot; onclick=&quot;set();&quot;&gt;
&lt;input type=&quot;button&quot; value=&quot;Poke&quot; onclick=&quot;poke();&quot;&gt;
&lt;input type=&quot;text&quot; id=&quot;Value&quot;&gt;
&lt;input type=&quot;button&quot; value=&quot;Write&quot; onclick=&quot;write();&quot;&gt;
&lt;form>
</pre>

View File

@@ -0,0 +1,183 @@
/* Copyright (c) 2000-2001 ActiveState Tool Corporation.
See the file LICENSE.txt for licensing information. */
// NOTE: This is a TEST interface, not a DEMO interface :-)
// We try to get as many data-types etc exposed, meaning this
// doesnt really make a good demo of a "simple component"
#include "nsISupports.idl"
[scriptable, uuid(1ECAED4F-E4D5-4ee7-ABF0-7D72AE1441D7)]
interface nsIPythonTestInterface : nsISupports
{
// Some constants for us to test - one for every type supported by xpidl
const short One = 1;
const long Two = 2;
const long MinusOne = -1;
const long BigLong = 0x7FFFFFFF;
const long BigULong = 0xFFFFFFFF;
// Declare every type supported as an attribute.
attribute boolean boolean_value; // PRBool
attribute octet octet_value; // PRUint8
attribute short short_value; // PRInt16
attribute unsigned short ushort_value; // PRUint16
attribute long long_value; // PRInt32
attribute unsigned long ulong_value; // PRUint32
attribute long long long_long_value; // PRInt64
attribute unsigned long long ulong_long_value; // PRUint64
attribute float float_value; // float
attribute double double_value; // double
attribute char char_value; // char
attribute wchar wchar_value; // PRUnichar
attribute string string_value; // char *
attribute wstring wstring_value; // PRUnichar*
attribute nsIIDRef iid_value; // an IID
attribute nsIPythonTestInterface interface_value; // A specific interface
attribute nsISupports isupports_value; // A generic interface
// Declare every type supported as a method with an "in", "in/out" and "out" params
boolean do_boolean(in boolean p1, inout boolean p2, out boolean p3);
octet do_octet(in octet p1, inout octet p2, out octet p3);
short do_short(in short p1, inout short p2, out short p3);
unsigned short do_unsigned_short(in unsigned short p1, inout unsigned short p2, out unsigned short p3);
long do_long(in long p1, inout long p2, out long p3);
unsigned long do_unsigned_long(in unsigned long p1, inout unsigned long p2, out unsigned long p3);
long long do_long_long(in long long p1, inout long long p2, out long long p3);
unsigned long long do_unsigned_long_long(in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3);
float do_float(in float p1, inout float p2, out float p3);
double do_double(in double p1, inout double p2, out double p3);
char do_char(in char p1, inout char p2, out char p3);
wchar do_wchar(in wchar p1, inout wchar p2, out wchar p3);
string do_string(in string p1, inout string p2, out string p3);
wstring do_wstring(in wstring p1, inout wstring p2, out wstring p3);
nsIIDRef do_nsIIDRef(in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3);
nsIPythonTestInterface do_nsIPythonTestInterface(in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3);
nsISupports do_nsISupports(in nsISupports p1, inout nsISupports p2, out nsISupports p3);
void do_nsISupportsIs(in nsIIDRef iid, [iid_is(iid),retval] out nsQIResult result);
// Do I really need these??
// void do_nsISupportsIs2(inout nsIIDRef iid, [iid_is(iid)] inout nsQIResult result);
// void do_nsISupportsIs3(out nsIIDRef iid, [iid_is(iid)] inout nsQIResult result);
// void do_nsISupportsIs4(out nsIIDRef iid, [iid_is(iid)] out nsQIResult result);
};
// Another interface - we use another interface purely for testing purposes -
// We ensure that the entire interface hierarcy is available correctly.
[scriptable, uuid(B38D1538-FE92-42c3-831F-285242EDEEA4)]
interface nsIPythonTestInterfaceExtra : nsIPythonTestInterface
{
// These were copied from the XPCOM test 'xpctest.idl'
// (and a few extras added)
void MultiplyEachItemInIntegerArray(
in PRInt32 val,
in PRUint32 count,
[array, size_is(count)] inout PRInt32 valueArray);
void MultiplyEachItemInIntegerArrayAndAppend(
in PRInt32 val,
inout PRUint32 count,
[array, size_is(count)] inout PRInt32 valueArray);
// Note that this method shares a single "size_is" between 2 params!
void CompareStringArrays([array, size_is(count)] in string arr1,
[array, size_is(count)] in string arr2,
in unsigned long count,
[retval] out short result);
void DoubleStringArray(inout PRUint32 count,
[array, size_is(count)] inout string valueArray);
void ReverseStringArray(in PRUint32 count,
[array, size_is(count)] inout string valueArray);
// One count, one inout array.
void DoubleString(inout PRUint32 count,
[size_is(count)] inout string str);
// One in count and in array, plus out count and out array
void DoubleString2(in PRUint32 in_count, [size_is(in_count)] in string in_str,
out PRUint32 out_count, [size_is(out_count)] out string out_str);
// As per DoubleString2, but out string also marked retval
void DoubleString3(in PRUint32 in_count, [size_is(in_count)] in string in_str,
out PRUint32 out_count, [size_is(out_count), retval] out string out_str);
// One in array, one out array, one share inout count.
void DoubleString4([size_is(count)] in string in_str, inout PRUint32 count, [size_is(count)] out string out_str);
// UpString defines the count as only "in" - meaning the result must be the same size
void UpString(in PRUint32 count,
[size_is(count)] inout string str);
// UpString2 defines count as only "in", and a string as only "out"
void UpString2(in PRUint32 count,
[size_is(count)] in string in_str,
[size_is(count)]out string out_str);
// Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!)
void GetFixedString(in PRUint32 count, [size_is(count)]out string out_str);
void DoubleWideString(inout PRUint32 count,
[size_is(count)] inout wstring str);
void DoubleWideString2(in PRUint32 in_count, [size_is(in_count)] in wstring in_str,
out PRUint32 out_count, [size_is(out_count)] out wstring out_str);
void DoubleWideString3(in PRUint32 in_count, [size_is(in_count)] in wstring in_str,
out PRUint32 out_count, [size_is(out_count), retval] out wstring out_str);
void DoubleWideString4([size_is(count)] in wstring in_str, inout PRUint32 count, [size_is(count)] out wstring out_str);
// UpWideString defines the count as only "in" - meaning the result must be the same size
void UpWideString(in PRUint32 count,
[size_is(count)] inout wstring str);
// UpWideString2 defines count as only "in", and a string as only "out"
void UpWideString2(in PRUint32 count,
[size_is(count)] in wstring in_str,
[size_is(count)]out wstring out_str);
// Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!)
void GetFixedWideString(in PRUint32 count, [size_is(count)]out string out_str);
void GetStrings(out PRUint32 count,
[retval, array, size_is(count)] out string str);
void UpOctetArray(inout PRUint32 count,
[array, size_is(count)] inout PRUint8 data);
void UpOctetArray2(inout PRUint32 count,
[array, size_is(count)] inout PRUint8 data);
// Arrays of interfaces
void CheckInterfaceArray(in PRUint32 count,
[array, size_is(count)] in nsISupports data,
[retval] out PRBool all_non_null);
void GetInterfaceArray(out PRUint32 count,
[array, size_is(count)] out nsISupports data);
void ExtendInterfaceArray(inout PRUint32 count,
[array, size_is(count)] inout nsISupports data);
// Arrays of IIDs
void CheckIIDArray(in PRUint32 count,
[array, size_is(count)] in nsIIDRef data,
[retval] out PRBool all_mine);
void GetIIDArray(out PRUint32 count,
[array, size_is(count)] out nsIIDRef data);
void ExtendIIDArray(inout PRUint32 count,
[array, size_is(count)] inout nsIIDRef data);
// More specific tests.
// Test our count param can be shared as an "in" param.
void SumArrays(in PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]in PRInt32 array2, [retval]out PRInt32 result);
// Test our count param can be shared as an "out" param.
void GetArrays(out PRUint32 count, [array, size_is(count)]out PRInt32 array1, [array, size_is(count)]out PRInt32 array2);
// Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!)
void GetFixedArray(in PRUint32 count, [array, size_is(count)]out PRInt32 array1);
// Test our "in" count param can be shared as one "in", plus one "out" param.
void CopyArray(in PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]out PRInt32 array2);
// Test our "in-out" count param can be shared as one "in", plus one "out" param.
void CopyAndDoubleArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]out PRInt32 array2);
// Test our "in-out" count param can be shared as one "in", plus one "in-out" param.
void AppendArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]inout PRInt32 array2);
};
// DOM String support is a "recent" (01/2001) addition to XPCOM. These test
// have their own interface for no real good reason ;-)
[scriptable, uuid(657ae651-a973-4818-8c06-f4b948b3d758)]
interface nsIPythonTestInterfaceDOMStrings : nsIPythonTestInterfaceExtra
{
DOMString GetDOMStringResult();
void GetDOMStringOut([retval] out DOMString s);
PRUint32 GetDOMStringLength(in DOMString s);
PRUint32 GetDOMStringRefLength(in DOMStringRef s);
PRUint32 GetDOMStringPtrLength(in DOMStringPtr s);
void ConcatDOMStrings(in DOMString s1, in DOMString s2, out DOMString ret);
attribute DOMString domstring_value;
readonly attribute DOMString domstring_value_ro;
};

View File

@@ -0,0 +1,344 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# NOTE: This is a TEST interface, not a DEMO interface :-)
# We try to get as many data-types etc exposed, meaning this
# doesnt really make a good demo of a "simple component"
from xpcom import components, verbose
class PythonTestComponent:
# Note we only list the "child" interface, not our intermediate interfaces
# (which we must, by definition, also support)
_com_interfaces_ = components.interfaces.nsIPythonTestInterfaceDOMStrings
_reg_clsid_ = "{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}"
_reg_contractid_ = "Python.TestComponent"
def __init__(self):
self.boolean_value = 1
self.octet_value = 2
self.short_value = 3
self.ushort_value = 4
self.long_value = 5
self.ulong_value = 6
self.long_long_value = 7
self.ulong_long_value = 8
self.float_value = 9.0
self.double_value = 10.0
self.char_value = "a"
self.wchar_value = "b"
self.string_value = "cee"
self.wstring_value = "dee"
self.iid_value = self._reg_clsid_
self.interface_value = None
self.isupports_value = None
self.domstring_value = "dom"
def __del__(self):
if verbose:
print "Python.TestComponent: __del__ method called - object is destructing"
def do_boolean(self, p1, p2):
# boolean do_boolean(in boolean p1, inout boolean p2, out boolean p3);
ret = p1 ^ p2
return ret, not ret, ret
def do_octet(self, p1, p2):
# octet do_octet(in octet p1, inout octet p2, out octet p3);
return p1+p2, p1-p2, p1*p2
def do_short(self, p1, p2):
# short do_short(in short p1, inout short p2, out short p3);
return p1+p2, p1-p2, p1*p2
def do_unsigned_short(self, p1, p2):
# unsigned short do_unsigned_short(in unsigned short p1, inout unsigned short p2, out unsigned short p3);
return p1+p2, p1-p2, p1*p2
def do_long(self, p1, p2):
# long do_long(in long p1, inout long p2, out long p3);
return p1+p2, p1-p2, p1*p2
def do_unsigned_long(self, p1, p2):
# unsigned long do_unsigned_long(in unsigned long p1, inout unsigned long p2, out unsigned long p3);
return p1+p2, p1-p2, p1*p2
def do_long_long(self, p1, p2):
# long long do_long_long(in long long p1, inout long long p2, out long long p3);
return p1+p2, p1-p2, p1*p2
def do_unsigned_long_long(self, p1, p2):
# unsigned long long do_unsigned_long_long(in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3);
return p1+p2, p1-p2, p1*p2
def do_float(self, p1, p2):
# float do_float(in float p1, inout float p2, out float p3);
return p1+p2, p1-p2, p1*p2
def do_double(self, p1, p2):
# double do_double(in double p1, inout double p2, out double p3);
return p1+p2, p1-p2, p1*p2
def do_char(self, p1, p2):
# char do_char(in char p1, inout char p2, out char p3);
return chr(ord(p1)+ord(p2)), p2, p1
def do_wchar(self, p1, p2):
# wchar do_wchar(in wchar p1, inout wchar p2, out wchar p3);
return chr(ord(p1)+ord(p2)), p2, p1
def do_string(self, p1, p2):
# string do_string(in string p1, inout string p2, out string p3);
ret = ""
if p1 is not None: ret = ret + p1
if p2 is not None: ret = ret + p2
return ret, p1, p2
def do_wstring(self, p1, p2):
# wstring do_wstring(in wstring p1, inout wstring p2, out wstring p3);
ret = u""
if p1 is not None: ret = ret + p1
if p2 is not None: ret = ret + p2
return ret, p1, p2
def do_nsIIDRef(self, p1, p2):
# nsIIDRef do_nsIIDRef(in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3);
return p1, self._reg_clsid_, p2
def do_nsIPythonTestInterface(self, p1, p2):
# nsIPythonTestInterface do_nsIPythonTestInterface(in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3);
return p2, p1, self
def do_nsISupports(self, p1, p2):
# nsISupports do_nsISupports(in nsISupports p1, inout nsISupports p2, out nsISupports p3);
return self, p1, p2
def do_nsISupportsIs(self, iid):
# void do_nsISupportsIs(in nsIIDRef iid, [iid_is(iid),retval] out nsQIResult result)
# Note the framework does the QI etc on us, so there is no real point me doing it.
# (However, user code _should_ do the QI - otherwise any errors are deemed "internal" (as they
# are raised by the C++ framework), and therefore logged to the console, etc.
# A user QI allows the user to fail gracefully, whatever gracefully means for them!
return self
# Do I really need these??
## def do_nsISupportsIs2(self, iid, interface):
## # void do_nsISupportsIs2(inout nsIIDRef iid, [iid_is(iid),retval] inout nsQIResult result);
## return iid, interface
## def do_nsISupportsIs3(self, interface):
## # void do_nsISupportsIs3(out nsIIDRef iid, [iid_is(iid)] inout nsQIResult result);
## return self._com_interfaces_, interface
## def do_nsISupportsIs4(self):
## # void do_nsISupportsIs4(out nsIIDRef iid, [iid_is(iid)] out nsQIResult result);
## return self._com_interfaces_, self
# Methods from the nsIPythonTestInterfaceExtra interface
#
def MultiplyEachItemInIntegerArray(self, val, valueArray):
# void MultiplyEachItemInIntegerArray(
# in PRInt32 val,
# in PRUint32 count,
# [array, size_is(count)] inout PRInt32 valueArray);
# NOTE - the "sizeis" params are never passed to or returned from Python!
results = []
for item in valueArray:
results.append(item * val)
return results
def MultiplyEachItemInIntegerArrayAndAppend(self, val, valueArray):
#void MultiplyEachItemInIntegerArrayAndAppend(
# in PRInt32 val,
# inout PRUint32 count,
# [array, size_is(count)] inout PRInt32 valueArray);
results = valueArray[:]
for item in valueArray:
results.append(item * val)
return results
def DoubleStringArray(self, valueArray):
# void DoubleStringArray(inout PRUint32 count,
# [array, size_is(count)] inout string valueArray);
results = []
for item in valueArray:
results.append(item * 2)
return results
def ReverseStringArray(self, valueArray):
# void ReverseStringArray(in PRUint32 count,
# [array, size_is(count)] inout string valueArray);
valueArray.reverse()
return valueArray
# Note that this method shares a single "size_is" between 2 params!
def CompareStringArrays(self, ar1, ar2):
# void CompareStringArrays([array, size_is(count)] in string arr1,
# [array, size_is(count)] in string arr2,
# in unsigned long count,
# [retval] out short result);
return cmp(ar1, ar2)
def DoubleString(self, val):
# void DoubleString(inout PRUint32 count,
# [size_is(count)] inout string str);
return val * 2
def DoubleString2(self, val):
# void DoubleString2(in PRUint32 in_count, [size_is(in_count)] in string in_str,
# out PRUint32 out_count, [size_is(out_count)] out string out_str);
return val * 2
def DoubleString3(self, val):
# void DoubleString3(in PRUint32 in_count, [size_is(in_count)] in string in_str,
# out PRUint32 out_count, [size_is(out_count), retval] string out_str);
return val * 2
def DoubleString4(self, val):
# void DoubleString4([size_is(count)] in string in_str, inout PRUint32 count, [size_is(count)] out string out_str);
return val * 2
def UpString(self, val):
# // UpString defines the count as only "in" - meaning the result must be the same size
# void UpString(in PRUint32 count,
# [size_is(count)] inout string str);
return val.upper()
UpString2 = UpString
# // UpString2 defines count as only "in", and a string as only "out"
# void UpString2(in PRUint32 count,
# [size_is(count)] inout string in_str,
# [size_is(count)]out string out_str);
def GetFixedString(self, count):
# void GetFixedString(in PRUint32 count, [size_is(count)out string out_str);
return "A" * count
# DoubleWideString functions are identical to DoubleString, except use wide chars!
def DoubleWideString(self, val):
return val * 2
def DoubleWideString2(self, val):
return val * 2
def DoubleWideString3(self, val):
return val * 2
def DoubleWideString4(self, val):
return val * 2
def UpWideString(self, val):
return val.upper()
UpWideString2 = UpWideString
# Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!)
def GetFixedWideString(self, count):
# void GetFixedWideString(in PRUint32 count, [size_is(count)out string out_str);
return u"A" * count
def GetStrings(self):
# void GetStrings(out PRUint32 count,
# [retval, array, size_is(count)] out string str);
return "Hello from the Python test component".split()
# Some tests for our special "PRUint8" support.
def UpOctetArray( self, data ):
# void UpOctetArray(inout PRUint32 count,
# [array, size_is(count)] inout PRUint8 data);
return data.upper()
def UpOctetArray2( self, data ):
# void UpOctetArray2(inout PRUint32 count,
# [array, size_is(count)] inout PRUint8 data);
data = data.upper()
# This time we return a list of integers.
return map( ord, data )
# Arrays of interfaces
def CheckInterfaceArray(self, interfaces):
# void CheckInterfaceArray(in PRUint32 count,
# [array, size_is(count)] in nsISupports data,
# [retval] out PRBool all_non_null);
ret = 1
for i in interfaces:
if i is None:
ret = 0
break
return ret
def GetInterfaceArray(self):
# void GetInterfaceArray(out PRUint32 count,
# [array, size_is(count)] out nsISupports data);
return self, self, self, None
def ExtendInterfaceArray(self, data):
# void ExtendInterfaceArray(inout PRUint32 count,
# [array, size_is(count)] inout nsISupports data);
return data * 2
# Arrays of IIDs
def CheckIIDArray(self, data):
# void CheckIIDArray(in PRUint32 count,
# [array, size_is(count)] in nsIIDRef data,
# [retval] out PRBool all_mine);
ret = 1
for i in data:
if i!= self._com_interfaces_ and i != self._reg_clsid_:
ret = 0
break
return ret
def GetIIDArray(self):
# void GetIIDArray(out PRUint32 count,
# [array, size_is(count)] out nsIIDRef data);
return self._com_interfaces_, self._reg_clsid_
def ExtendIIDArray(self, data):
# void ExtendIIDArray(inout PRUint32 count,
# [array, size_is(count)] inout nsIIDRef data);
return data * 2
# Test our count param can be shared as an "in" param.
def SumArrays(self, array1, array2):
# void SumArrays(in PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]in array2, [retval]result);
if len(array1)!=len(array2):
print "SumArrays - not expecting different lengths!"
result = 0
for i in array1:
result = result + i
for i in array2:
result = result+i
return result
# Test our count param can be shared as an "out" param.
def GetArrays(self):
# void GetArrays(out PRUint32 count, [array, size_is(count)]out array1, [array, size_is(count)]out array2);
return (1,2,3), (4,5,6)
# Test we can get an "out" array with an "in" size
def GetFixedArray(self, size):
# void GetFixedArray(in PRUint32 count, [array, size_is(count)]out PRInt32 array1]);
return 0 * size
# Test our "in" count param can be shared as one "in", plus one "out" param.
def CopyArray(self, array1):
# void CopyArray(in PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]out array2);
return array1
# Test our "in-out" count param can be shared as one "in", plus one "out" param.
def CopyAndDoubleArray(self, array):
# void CopyAndDoubleArray(inout PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]out array2);
return array + array
# Test our "in-out" count param can be shared as one "in", plus one "in-out" param.
def AppendArray(self, array1, array2):
# void AppendArray(inout PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]inout array2);
rc = array1
if array2 is not None:
rc.extend(array2)
return rc
# Some tests for the "new" (Feb-2001) DOMString type.
def GetDOMStringResult( self ):
# Result: DOMString &
return "A DOM String"
def GetDOMStringOut( self ):
# Result: DOMString &
return "Another DOM String"
def GetDOMStringLength( self, param0 ):
# Result: uint32
# In: param0: DOMString &
return len(param0)
def GetDOMStringRefLength( self, param0 ):
# Result: uint32
# In: param0: DOMString &
return len(param0)
def GetDOMStringPtrLength( self, param0 ):
# Result: uint32
# In: param0: DOMString *
return len(param0)
def ConcatDOMStrings( self, param0, param1 ):
# Result: void - None
# In: param0: DOMString &
# In: param1: DOMString &
# Out: DOMString &
return param0 + param1
def get_domstring_value( self ):
# Result: DOMString &
return self.domstring_value
def set_domstring_value( self, param0 ):
# Result: void - None
# In: param0: DOMString &
self.domstring_value = param0
def get_domstring_value_ro( self ):
# Result: DOMString &
return self.domstring_value

View File

@@ -0,0 +1,78 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
"""Tests the "xpcom.components" object.
"""
import xpcom.components
if not __debug__:
raise RuntimeError, "This test uses assert, so must be run in debug mode"
def test_interfaces():
"Test the xpcom.components.interfaces object"
iid = xpcom.components.interfaces.nsISupports
assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!"
iid = xpcom.components.interfaces['nsISupports']
assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!"
# Test dictionary semantics
num_fetched = num_nsisupports = 0
for name, iid in xpcom.components.interfaces.items():
num_fetched = num_fetched + 1
if name == "nsISupports":
num_nsisupports = num_nsisupports + 1
assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!"
assert xpcom.components.interfaces[name] == iid
# Check all the lengths match.
assert len(xpcom.components.interfaces.keys()) == len(xpcom.components.interfaces.values()) == \
len(xpcom.components.interfaces.items()) == len(xpcom.components.interfaces) == \
num_fetched, "The collection lengths were wrong"
if num_nsisupports != 1:
print "Didnt find exactly 1 nsiSupports!"
print "The interfaces object appeared to work!"
def test_classes():
# Need a well-known contractID here?
prog_id = "@mozilla.org/filelocator;1"
clsid = xpcom.components.ID("{78043e01-e603-11d2-915f-f08a208628fc}")
# Check we can create the instance (dont check we can do anything with it tho!)
klass = xpcom.components.classes[prog_id]
instance = klass.createInstance()
# Test dictionary semantics
num_fetched = num_mine = 0
for name, klass in xpcom.components.classes.items():
num_fetched = num_fetched + 1
if name == prog_id:
if klass.clsid != clsid:
print "Eeek - didn't get the correct IID - got", klass.clsid
num_mine = num_mine + 1
# xpcom appears to add charset info to the contractid!?
# assert xpcom.components.classes[name].contractid == prog_id, "Expected '%s', got '%s'" % (prog_id, xpcom.components.classes[name].contractid)
# Check all the lengths match.
if len(xpcom.components.classes.keys()) == len(xpcom.components.classes.values()) == \
len(xpcom.components.classes.items()) == len(xpcom.components.classes) == \
num_fetched:
pass
else:
raise RuntimeError, "The collection lengths were wrong"
if num_fetched <= 0:
raise RuntimeError, "Didnt get any classes!!!"
if num_mine != 1:
raise RuntimeError, "Didnt find exactly 1 of my contractid! (%d)" % (num_mine,)
print "The classes object appeared to work!"
def test_id():
id = xpcom.components.ID(str(xpcom._xpcom.IID_nsISupports))
assert id == xpcom._xpcom.IID_nsISupports
print "The ID function appeared to work!"
# regrtest doesnt like if __name__=='__main__' blocks - it fails when running as a test!
test_interfaces()
test_classes()
test_id()

View File

@@ -0,0 +1,116 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Test our support for the interfaces defined in nsISupportsPrimitives.idl
#
# The framework supports nsISupportsString and nsISupportsWString, but
# only if our class doesnt provide explicit support.
from xpcom import components
class NoSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports]
pass
class ImplicitSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports]
def __str__(self):
return "<MyImplicitStrObject>"
class ExplicitSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports, components.interfaces.nsISupportsString]
# __str__ will be ignored by XPCOM, as we have _explicit_ support.
def __str__(self):
return "<MyImplicitStrObject>"
# This is the one that will be used.
def toString(self):
return "<MyExplicitStrObject>"
class ImplicitSupportsInt:
_com_interfaces_ = [components.interfaces.nsISupports]
def __int__(self):
return 99
class ExplicitSupportsInt:
_com_interfaces_ = [components.interfaces.nsISupportsPRInt32]
def get_data(self):
return 99
class ImplicitSupportsLong:
_com_interfaces_ = [components.interfaces.nsISupports]
def __long__(self):
return 99L
class ExplicitSupportsLong:
_com_interfaces_ = [components.interfaces.nsISupportsPRInt64]
def get_data(self):
return 99
class ExplicitSupportsFloat:
_com_interfaces_ = [components.interfaces.nsISupportsDouble]
def get_data(self):
return 99.99
class ImplicitSupportsFloat:
_com_interfaces_ = [components.interfaces.nsISupports]
def __float__(self):
return 99.99
def test():
import xpcom.server, xpcom.client
ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports)
if not str(ob).startswith("<XPCOM interface"):
raise RuntimeError, "Wrong str() value: %s" % (ob,)
ob = xpcom.server.WrapObject( ImplicitSupportsString(), components.interfaces.nsISupports)
if str(ob) != "<MyImplicitStrObject>":
raise RuntimeError, "Wrong str() value: %s" % (ob,)
ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports)
if str(ob) != "<MyExplicitStrObject>":
raise RuntimeError, "Wrong str() value: %s" % (ob,)
# Try our conversions.
try:
int(ob)
raise RuntimeError, "Expected to get a ValueError converting this COM object to an int"
except ValueError:
pass
ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports)
if float(ob) != 99.99:
raise RuntimeError, "Bad value: %s" % (float(ob),)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports)
if float(ob) != 99.99:
raise RuntimeError, "Bad value: %s" % (float(ob),)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
print "The nsISupports primitive interface tests appeared to work"
test()

View File

@@ -0,0 +1,171 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import xpcom
import xpcom.client
import xpcom._xpcom
import xpcom.components
import string
import traceback, getopt, sys
verbose_level = 0
def DumpEveryInterfaceUnderTheSun():
"Dump every interface under the sun!"
import xpcom, xpcom.xpt, xpcom._xpcom
iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager()
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)"
enum = iim.EnumerateInterfaces()
rc = enum.First()
num = 0
while rc==0:
item = enum.CurrentItem(xpcom._xpcom.IID_nsIInterfaceInfo)
try:
iid = item.GetIID()
except xpcom.Exception:
if verbose_level:
print "Can't dump", item
continue # Dont bother dumping this.
interface = xpcom.xpt.Interface(iid)
num = num + 1
text = interface.Describe()
if verbose_level:
print text
rc = enum.Next()
if num < 200:
print "Only found", num, "interfaces - this seems unusually low!"
print "Finished dumping all the interfaces."
def EnumContractIDs():
"""Enumerate all the ContractIDs registered"""
cm = xpcom._xpcom.NS_GetGlobalComponentManager()
enum = cm.EnumerateContractIDs()
rc = enum.First()
n = 0
while rc == 0:
n = n + 1
if verbose_level:
print "ContractID:", enum.CurrentItem()
rc = enum.Next()
if n < 200:
print "Only found", n, "ContractIDs - this seems unusually low!"
print "Enumerated all the ContractIDs"
def TestSampleComponent():
"""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)
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!"
def TestHash():
"Test that hashing COM objects works"
d = {}
contractid = "@mozilla.org/sample;1" # The C++ version.
c = xpcom.components.classes[contractid].createInstance() \
.queryInterface(xpcom.components.interfaces.nsISample)
d[c] = None
if not d.has_key(c):
raise RuntimeError, "Can't get the exact same object back!"
if not d.has_key(c.queryInterface(xpcom.components.interfaces.nsISupports)):
raise RuntimeError, "Can't get back as nsISupports"
# And the same in reverse - stick an nsISupports in, and make sure an explicit interface comes back.
d = {}
contractid = "@mozilla.org/sample;1" # The C++ version.
c = xpcom.components.classes[contractid].createInstance() \
.queryInterface(xpcom.components.interfaces.nsISupports)
d[c] = None
if not d.has_key(c):
raise RuntimeError, "Can't get the exact same object back!"
if not d.has_key(c.queryInterface(xpcom.components.interfaces.nsISample)):
raise RuntimeError, "Can't get back as nsISupports"
print "xpcom object hashing tests seemed to work"
def TestIIDs():
"Do some basic IID semantic tests."
iid_str = "{7ee4bdc6-cb53-42c1-a9e4-616b8e012aba}"
IID = xpcom._xpcom.IID
assert IID(iid_str)==IID(iid_str), "IIDs with identical strings dont compare!"
assert hash(IID(iid_str))==hash(IID(iid_str)), "IIDs with identical strings dont have identical hashes!"
assert IID(iid_str)==IID(iid_str.upper()), "IIDs with case-different strings dont compare!"
assert hash(IID(iid_str))==hash(IID(iid_str.upper())), "IIDs with case-different strings dont have identical hashes!"
# If the above work, this shoud too, but WTF
dict = {}
dict[IID(iid_str)] = None
assert dict.has_key(IID(iid_str))
assert dict.has_key(IID(iid_str.upper()))
print "The IID tests seemed to work"
def usage(tests):
import os
print "Usage: %s [-v] [Test ...]" % os.path.basename(sys.argv[0])
print " -v : Verbose - print more information"
print "where Test is one of:"
for t in tests:
print t.__name__,":", t.__doc__
print
print "If not tests are specified, all tests are run"
sys.exit(1)
def main():
tests = []
args = []
for ob in globals().values():
if type(ob)==type(main) and ob.__doc__:
tests.append(ob)
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:
if opt=="-h":
usage(tests)
if opt=="-v":
global verbose_level
verbose_level = verbose_level + 1
if len(args)==0:
print "Running all tests - use '-h' to see command-line options..."
dotests = tests
else:
dotests = []
for arg in args:
for t in tests:
if t.__name__==arg:
dotests.append(t)
break
else:
print "Test '%s' unknown - skipping" % arg
if not len(dotests):
print "Nothing to do!"
usage(tests)
for test in dotests:
try:
test()
except:
print "Test %s failed" % test.__name__
traceback.print_exc()
# regrtest doesnt like if __name__=='__main__' blocks - it fails when running as a test!
main()
if __name__=='__main__':
# We can only afford to shutdown if we are truly running as the main script.
# (xpcom can't handle shutdown/init pairs)
xpcom._xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)

View File

@@ -0,0 +1,86 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import xpcom
from xpcom import _xpcom, components, COMException, ServerException, nsError
from StringIO import StringIO
test_data = "abcdefeghijklmnopqrstuvwxyz"
class koTestSimpleStreamBase:
_com_interfaces_ = [components.interfaces.nsIInputStream]
# We avoid registering this object - see comments in get_test_inout_? below.
def __init__(self):
self.data=StringIO(test_data)
def close( self ):
pass
def available( self ):
return self.data.len-self.data.pos
def readStr( self, amount):
return self.data.read(amount)
read=readStr
def get_observer( self ):
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
def set_observer( self, param0 ):
raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED)
# This class has "nonBlocking" as an attribute.
class koTestSimpleStream1(koTestSimpleStreamBase):
nonBlocking=0
# This class has "nonBlocking" as getter/setters.
class koTestSimpleStream2(koTestSimpleStreamBase):
def __init__(self):
koTestSimpleStreamBase.__init__(self)
self.isNonBlocking = 0
def get_nonBlocking(self):
return self.isNonBlocking
def get_test_input_1():
# We use a couple of internal hacks here that mean we can avoid having the object
# registered. This code means that we are still working over the xpcom boundaries, tho
# (and the point of this test is not the registration, etc).
import xpcom.server, xpcom.client
ob = xpcom.server.WrapObject( koTestSimpleStream1(), _xpcom.IID_nsISupports)
ob = xpcom.client.Component(ob, components.interfaces.nsIInputStream)
return ob
def get_test_input_2():
# We use a couple of internal hacks here that mean we can avoid having the object
# registered. This code means that we are still working over the xpcom boundaries, tho
# (and the point of this test is not the registration, etc).
import xpcom.server, xpcom.client
ob = xpcom.server.WrapObject( koTestSimpleStream2(), _xpcom.IID_nsISupports)
ob = xpcom.client.Component(ob, components.interfaces.nsIInputStream)
return ob
def test_input(myStream):
if myStream.read(5) != test_data[:5]:
raise "Read the wrong data!"
if myStream.read(0) != '':
raise "Read the wrong emtpy data!"
if myStream.read(5) != test_data[5:10]:
raise "Read the wrong data after an empty read!"
if myStream.read(-1) != test_data[10:]:
raise "Couldnt read the rest of the data"
if myStream.nonBlocking:
raise "Expected default to be blocking"
try:
myStream.observer = None
raise "Shouldnt get here!"
except COMException, details:
if details.errno != nsError.NS_ERROR_NOT_IMPLEMENTED:
raise "Unexpected COM exception: %s (%r)" % (details, details)
if __name__=='__main__':
test_input( get_test_input_1() )
test_input( get_test_input_2() )
print "The stream tests worked!"

View File

@@ -0,0 +1,80 @@
/* Javascript code calling the Python test interface. */
function MakeTestInterface()
{
var clazz = Components.classes["Python.TestComponent"];
var iface = Components.interfaces.nsIPythonTestInterfaceDOMStrings;
return new clazz(iface);
}
var c = new MakeTestInterface();
if (c.boolean_value != 1)
throw("boolean_value has wrong initial value");
c.boolean_value = false;
if (c.boolean_value != false)
throw("boolean_value has wrong new value");
// Python's own test does thorough testing of all numeric types
// Wont bother from here!
if (c.char_value != 'a')
throw("char_value has wrong initial value");
c.char_value = 'b';
if (c.char_value != 'b')
throw("char_value has wrong new value");
if (c.wchar_value != 'b')
throw("wchar_value has wrong initial value");
c.wchar_value = 'c';
if (c.wchar_value != 'c')
throw("wchar_value has wrong new value");
if (c.string_value != 'cee')
throw("string_value has wrong initial value");
c.string_value = 'dee';
if (c.string_value != 'dee')
throw("string_value has wrong new value");
if (c.wstring_value != 'dee')
throw("wstring_value has wrong initial value");
c.wstring_value = 'eee';
if (c.wstring_value != 'eee')
throw("wstring_value has wrong new value");
if (c.domstring_value != 'dom')
throw("domstring_value has wrong initial value");
c.domstring_value = 'New value';
if (c.domstring_value != 'New value')
throw("domstring_value has wrong new value");
var v = new Object();
v.value = "Hello"
var l = new Object();
l.value = v.value.length;
c.DoubleString(l, v);
if ( v.value != "HelloHello")
throw("Could not double the string!");
var v = new Object();
v.value = "Hello"
var l = new Object();
l.value = v.value.length;
c.DoubleWideString(l, v);
if ( v.value != "HelloHello")
throw("Could not double the wide string!");
// Some basic array tests
var v = new Array()
v[0] = 1;
v[2] = 2;
v[3] = 3;
var v2 = new Array()
v2[0] = 4;
v2[2] = 5;
v2[3] = 6;
if (c.SumArrays(v.length, v, v2) != 21)
throw("Could not sum an array of integers!");
print("javascript successfully tested the Python test component.");

View File

@@ -0,0 +1,435 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
import sys, os
import xpcom.components
import xpcom._xpcom
import xpcom.nsError
num_errors = 0
component_iid = xpcom.components.ID("{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}")
new_iid = xpcom.components.ID("{2AF747D3-ECBC-457b-9AF9-5C5D80EDC360}")
contractid = "Python.TestComponent"
really_big_string = "This is really repetitive!" * 10000
really_big_wstring = u"This is really repetitive!" * 10000
def print_error(error):
print error
global num_errors
num_errors = num_errors + 1
def _test_value(what, got, expecting):
ok = got == expecting
if type(got)==type(expecting)==type(0.0):
ok = abs(got-expecting) < 0.001
if not ok:
print_error("*** Error %s - got '%r', but expecting '%r'" % (what, got, expecting))
def test_attribute(ob, attr_name, expected_init, new_value, new_value_really = None):
if xpcom.verbose:
print "Testing attribute %s" % (attr_name,)
if new_value_really is None:
new_value_really = new_value # Handy for eg bools - set a BOOL to 2, you still get back 1!
_test_value( "getting initial attribute value (%s)" % (attr_name,), getattr(ob, attr_name), expected_init)
setattr(ob, attr_name, new_value)
_test_value( "getting new attribute value (%s)" % (attr_name,), getattr(ob, attr_name), new_value_really)
# And set it back to the expected init.
setattr(ob, attr_name, expected_init)
_test_value( "getting back initial attribute value after change (%s)" % (attr_name,), getattr(ob, attr_name), expected_init)
def test_attribute_failure(ob, attr_name, new_value, expected_exception):
try:
setattr(ob, attr_name, new_value)
print_error("*** Setting attribute '%s' to '%r' didnt yield an exception!" % (attr_name, new_value) )
except:
exc_typ = sys.exc_info()[0]
ok = issubclass(exc_typ, expected_exception)
if not ok:
print_error("*** Wrong exception setting '%s' to '%r'- got '%s: %s', expected '%s'" % (attr_name, new_value, exc_typ, exc_val, expected_exception))
def test_method(method, args, expected_results):
if xpcom.verbose:
print "Testing %s%s" % (method.__name__, `args`)
ret = method(*args)
if ret != expected_results:
print_error("calling method %s - expected %s, but got %s" % (method.__name__, expected_results, ret))
def test_int_method(meth):
test_method(meth, (0,0), (0,0,0))
test_method(meth, (1,1), (2,0,1))
test_method(meth, (5,2), (7,3,10))
# test_method(meth, (2,5), (7,-3,10))
def test_constant(ob, cname, val):
v = getattr(ob, cname)
if v != val:
print_error("Bad value for constant '%s' - got '%r'" % (cname, v))
try:
setattr(ob, cname, 0)
print_error("The object allowed us to set the constant '%s'" % (cname,))
except AttributeError:
pass
def test_base_interface(c):
test_attribute(c, "boolean_value", 1, 0)
test_attribute(c, "boolean_value", 1, -1, 1) # Set a bool to anything, you should always get back 0 or 1
test_attribute(c, "boolean_value", 1, 4, 1) # Set a bool to anything, you should always get back 0 or 1
test_attribute(c, "boolean_value", 1, "1", 1) # This works by virtual of PyNumber_Int - not sure I agree, but...
test_attribute_failure(c, "boolean_value", "boo", ValueError)
test_attribute_failure(c, "boolean_value", test_base_interface, TypeError)
test_attribute(c, "octet_value", 2, 5)
test_attribute(c, "octet_value", 2, 0)
test_attribute(c, "octet_value", 2, 128) # octet is unsigned 8 bit
test_attribute(c, "octet_value", 2, 255) # octet is unsigned 8 bit
test_attribute(c, "octet_value", 2, -1, 255) # octet is unsigned 8 bit
test_attribute_failure(c, "octet_value", "boo", ValueError)
test_attribute(c, "short_value", 3, 10)
test_attribute(c, "short_value", 3, -1) # 16 bit signed
test_attribute(c, "short_value", 3, 0xFFFF, -1) # 16 bit signed
test_attribute(c, "short_value", 3, 0L)
test_attribute(c, "short_value", 3, 1L)
test_attribute(c, "short_value", 3, -1L)
test_attribute(c, "short_value", 3, 0xFFFFL, -1)
test_attribute_failure(c, "short_value", "boo", ValueError)
test_attribute(c, "ushort_value", 4, 5)
test_attribute(c, "ushort_value", 4, 0)
test_attribute(c, "ushort_value", 4, -1, 0xFFFF) # 16 bit signed
test_attribute(c, "ushort_value", 4, 0xFFFF) # 16 bit signed
test_attribute(c, "ushort_value", 4, 0L)
test_attribute(c, "ushort_value", 4, 1L)
test_attribute(c, "ushort_value", 4, -1L, 0xFFFF)
test_attribute_failure(c, "ushort_value", "boo", ValueError)
test_attribute(c, "long_value", 5, 7)
test_attribute(c, "long_value", 5, 0)
test_attribute(c, "long_value", 5, 0xFFFFFFFF, -1) # 32 bit signed.
test_attribute(c, "long_value", 5, -1) # 32 bit signed.
test_attribute(c, "long_value", 5, 0L)
test_attribute(c, "long_value", 5, 1L)
test_attribute(c, "long_value", 5, -1L)
test_attribute_failure(c, "long_value", 0xFFFFL * 0xFFFF, OverflowError) # long int too long to convert
test_attribute_failure(c, "long_value", "boo", ValueError)
test_attribute(c, "ulong_value", 6, 7)
test_attribute(c, "ulong_value", 6, 0)
test_attribute(c, "ulong_value", 6, 0xFFFFFFFF) # 32 bit signed.
test_attribute_failure(c, "ulong_value", "boo", ValueError)
test_attribute(c, "long_long_value", 7, 8)
test_attribute(c, "long_long_value", 7, 0)
test_attribute(c, "long_long_value", 7, -1)
test_attribute(c, "long_long_value", 7, 0xFFFF)
test_attribute(c, "long_long_value", 7, 0xFFFFL * 2)
test_attribute_failure(c, "long_long_value", 0xFFFFL * 0xFFFF * 0xFFFF * 0xFFFF, OverflowError) # long int too long to convert
test_attribute_failure(c, "long_long_value", "boo", ValueError)
test_attribute(c, "ulong_long_value", 8, 9)
test_attribute(c, "ulong_long_value", 8, 0)
test_attribute_failure(c, "ulong_long_value", "boo", ValueError)
test_attribute_failure(c, "ulong_long_value", -1, OverflowError) # can't convert negative value to unsigned long)
test_attribute(c, "float_value", 9.0, 10.2)
test_attribute(c, "float_value", 9.0, 0)
test_attribute(c, "float_value", 9.0, -1)
test_attribute(c, "float_value", 9.0, 1L)
test_attribute_failure(c, "float_value", "boo", ValueError)
test_attribute(c, "double_value", 10.0, 9.0)
test_attribute(c, "double_value", 10.0, 0)
test_attribute(c, "double_value", 10.0, -1)
test_attribute(c, "double_value", 10.0, 1L)
test_attribute_failure(c, "double_value", "boo", ValueError)
test_attribute(c, "char_value", "a", "b")
test_attribute(c, "char_value", "a", "\0")
test_attribute_failure(c, "char_value", "xy", ValueError)
test_attribute(c, "char_value", "a", u"c")
test_attribute(c, "char_value", "a", u"\0")
test_attribute_failure(c, "char_value", u"xy", ValueError)
test_attribute(c, "wchar_value", "b", "a")
test_attribute(c, "wchar_value", "b", "\0")
test_attribute_failure(c, "wchar_value", "hi", ValueError)
test_attribute(c, "wchar_value", "b", u"a")
test_attribute(c, "wchar_value", "b", u"\0")
test_attribute_failure(c, "wchar_value", u"hi", ValueError)
test_attribute(c, "string_value", "cee", "dee")
test_attribute(c, "string_value", "cee", "a null >\0<", "a null >") # strings are NULL terminated!!
test_attribute(c, "string_value", "cee", "")
test_attribute(c, "string_value", "cee", u"dee")
test_attribute(c, "string_value", "cee", u"a null >\0<", "a null >") # strings are NULL terminated!!
test_attribute(c, "string_value", "cee", u"")
test_attribute(c, "wstring_value", "dee", "cee")
test_attribute(c, "wstring_value", "dee", "a null >\0<", "a null >") # strings are NULL terminated!!
test_attribute(c, "wstring_value", "dee", "")
test_attribute(c, "wstring_value", "dee", really_big_string)
test_attribute(c, "wstring_value", "dee", u"cee")
test_attribute(c, "wstring_value", "dee", u"a null >\0<", "a null >") # strings are NULL terminated!!
test_attribute(c, "wstring_value", "dee", u"")
test_attribute(c, "wstring_value", "dee", really_big_wstring)
test_attribute(c, "iid_value", component_iid, new_iid)
test_attribute(c, "iid_value", component_iid, str(new_iid), new_iid)
test_attribute(c, "iid_value", component_iid, xpcom._xpcom.IID(new_iid))
test_attribute_failure(c, "no_attribute", "boo", AttributeError)
test_attribute(c, "interface_value", None, c)
test_attribute_failure(c, "interface_value", 2, TypeError)
test_attribute(c, "isupports_value", None, c)
# The methods
test_method(c.do_boolean, (0,1), (1,0,1))
test_method(c.do_boolean, (1,0), (1,0,1))
test_method(c.do_boolean, (1,1), (0,1,0))
test_int_method(c.do_octet)
test_int_method(c.do_short)
test_int_method(c.do_unsigned_short)
test_int_method(c.do_long)
test_int_method(c.do_unsigned_long)
test_int_method(c.do_long_long)
test_int_method(c.do_unsigned_long)
test_int_method(c.do_float)
test_int_method(c.do_double)
test_method(c.do_char, ("A", " "), (chr(ord("A")+ord(" ")), " ","A") )
test_method(c.do_char, ("A", "\0"), ("A", "\0","A") )
test_method(c.do_wchar, ("A", " "), (chr(ord("A")+ord(" ")), " ","A") )
test_method(c.do_wchar, ("A", "\0"), ("A", "\0","A") )
test_method(c.do_string, ("Hello from ", "Python"), ("Hello from Python", "Hello from ", "Python") )
test_method(c.do_string, (u"Hello from ", u"Python"), ("Hello from Python", "Hello from ", "Python") )
test_method(c.do_string, (None, u"Python"), ("Python", None, "Python") )
test_method(c.do_string, (None, really_big_string), (really_big_string, None, really_big_string) )
test_method(c.do_string, (None, really_big_wstring), (really_big_string, None, really_big_string) )
test_method(c.do_wstring, ("Hello from ", "Python"), ("Hello from Python", "Hello from ", "Python") )
test_method(c.do_wstring, (u"Hello from ", u"Python"), ("Hello from Python", "Hello from ", "Python") )
test_method(c.do_string, (None, really_big_wstring), (really_big_wstring, None, really_big_wstring) )
test_method(c.do_string, (None, really_big_string), (really_big_wstring, None, really_big_wstring) )
test_method(c.do_nsIIDRef, (component_iid, new_iid), (component_iid, component_iid, new_iid))
test_method(c.do_nsIIDRef, (new_iid, component_iid), (new_iid, component_iid, component_iid))
test_method(c.do_nsIPythonTestInterface, (None, None), (None, None, c))
test_method(c.do_nsIPythonTestInterface, (c, c), (c, c, c))
test_method(c.do_nsISupports, (None, None), (c, None, None))
test_method(c.do_nsISupports, (c,c), (c, c, c))
test_method(c.do_nsISupportsIs, (xpcom._xpcom.IID_nsISupports,), c)
test_method(c.do_nsISupportsIs, (xpcom.components.interfaces.nsIPythonTestInterface,), c)
## test_method(c.do_nsISupportsIs2, (xpcom.components.interfaces.nsIPythonTestInterface,c), (xpcom.components.interfaces.nsIPythonTestInterface,c))
## test_method(c.do_nsISupportsIs3, (c,), (xpcom.components.interfaces.nsIPythonTestInterface,c))
## test_method(c.do_nsISupportsIs4, (), (xpcom.components.interfaces.nsIPythonTestInterface,c))
# Test the constants.
test_constant(c, "One", 1)
test_constant(c, "Two", 2)
test_constant(c, "MinusOne", -1)
test_constant(c, "BigLong", 0x7FFFFFFF)
test_constant(c, "BigULong", 0xFFFFFFFF)
# Test the components.Interfaces semantics
i = xpcom.components.interfaces.nsIPythonTestInterface
test_constant(i, "One", 1)
test_constant(i, "Two", 2)
test_constant(i, "MinusOne", -1)
test_constant(i, "BigLong", 0x7FFFFFFF)
test_constant(i, "BigULong", 0xFFFFFFFF)
def test_derived_interface(c):
val = "Hello\0there"
expected = val * 2
test_method(c.DoubleString, (val,), expected)
test_method(c.DoubleString2, (val,), expected)
test_method(c.DoubleString3, (val,), expected)
test_method(c.DoubleString4, (val,), expected)
test_method(c.UpString, (val,), val.upper())
test_method(c.UpString2, (val,), val.upper())
test_method(c.GetFixedString, (20,), "A"*20)
val = u"Hello\0there"
expected = val * 2
test_method(c.DoubleWideString, (val,), expected)
test_method(c.DoubleWideString2, (val,), expected)
test_method(c.DoubleWideString3, (val,), expected)
test_method(c.DoubleWideString4, (val,), expected)
test_method(c.UpWideString, (val,), val.upper())
test_method(c.UpWideString2, (val,), val.upper())
test_method(c.GetFixedWideString, (20,), u"A"*20)
items = [1,2,3,4,5]
test_method(c.MultiplyEachItemInIntegerArray, (3, items,), map(lambda i:i*3, items))
test_method(c.MultiplyEachItemInIntegerArrayAndAppend, (3, items), items + map(lambda i:i*3, items))
items = "Hello from Python".split()
expected = map( lambda x: x*2, items)
test_method(c.DoubleStringArray, (items,), expected)
test_method(c.CompareStringArrays, (items, items), cmp(items, items))
# Can we pass lists and tuples correctly?
test_method(c.CompareStringArrays, (items, tuple(items)), cmp(items, items))
items2 = ["Not", "the", "same"]
test_method(c.CompareStringArrays, (items, items2), cmp(items, items2))
expected = items[:]
expected.reverse()
test_method(c.ReverseStringArray, (items,), expected)
expected = "Hello from the Python test component".split()
test_method(c.GetStrings, (), expected)
val = "Hello\0there"
test_method(c.UpOctetArray, (val,), val.upper())
test_method(c.UpOctetArray2, (val,), val.upper())
test_method(c.CheckInterfaceArray, ((c, c),), 1)
test_method(c.CheckInterfaceArray, ((c, None),), 0)
test_method(c.CheckInterfaceArray, ((),), 1)
test_method(c.GetInterfaceArray, (), [c,c,c, None])
test_method(c.ExtendInterfaceArray, ((c,c,c, None),), [c,c,c,None,c,c,c,None] )
expected = [xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings, xpcom.components.classes[contractid].clsid]
test_method(c.GetIIDArray, (), expected)
val = [xpcom.components.interfaces.nsIPythonTestInterfaceExtra, xpcom.components.classes[contractid].clsid]
expected = val * 2
test_method(c.ExtendIIDArray, (val,), expected)
test_method(c.GetArrays, (), ( [1,2,3], [4,5,6] ) )
test_method(c.CopyArray, ([1,2,3],), [1,2,3] )
test_method(c.CopyAndDoubleArray, ([1,2,3],), [1,2,3,1,2,3] )
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)
test_method(c.GetDOMStringResult, (), "A DOM String")
test_method(c.GetDOMStringOut, (), "Another DOM String")
val = "Hello there"
test_method(c.GetDOMStringLength, (val,), len(val))
test_method(c.GetDOMStringRefLength, (val,), len(val))
test_method(c.GetDOMStringPtrLength, (val,), len(val))
test_method(c.ConcatDOMStrings, (val,val), val+val)
test_attribute(c, "domstring_value", "dom", "new dom")
if c.domstring_value_ro != "dom":
print "Read-only DOMString not currect - got", c.domstring_ro
try:
c.dom_string_ro = "new dom"
print "Managed to set a readonly attribute - eek!"
except AttributeError:
pass
except:
print "Unexpected exception when setting readonly attribute: %s: %s" % (sys.exc_info()[0], sys.exc_info()[1])
if c.domstring_value_ro != "dom":
print "Read-only DOMString not correct after failed set attempt - got", c.domstring_ro
def do_test_failures():
c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterfaceExtra)
try:
ret = c.do_nsISupportsIs( xpcom._xpcom.IID_nsIInterfaceInfoManager )
print "*** got", ret, "***"
raise RuntimeError, "We worked when using an IID we dont support!?!"
except xpcom.Exception, details:
if details.errno != xpcom.nsError.NS_ERROR_NO_INTERFACE:
raise RuntimeError, "Wrong COM exception type: %r" % (details,)
def test_failures():
# This extra stack-frame ensures Python cleans up sys.last_traceback etc
do_test_failures()
def test_all():
c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterface)
test_base_interface(c)
# Now create an instance using the derived IID, and test that.
c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterfaceExtra)
test_base_interface(c)
test_derived_interface(c)
test_failures()
try:
from sys import gettotalrefcount
except ImportError:
# Not a Debug build - assume no references (can't be leaks then :-)
def gettotalrefcount():
return 0
def test_from_js():
# Ensure we can find the js test script - same dir as this!
# Assume the path of sys.argv[0] is where we can find the js test code.
# (Running under the regression test is a little painful)
script_dir = os.path.split(sys.argv[0])[0]
fname = os.path.join( script_dir, "test_test_component.js")
if not os.path.isfile(fname):
raise RuntimeError, "Can not find '%s'" % (fname,)
# Note we _dont_ pump the test output out, as debug "xpcshell" spews
# extra debug info that will cause our output comparison to fail.
try:
data = os.popen('xpcshell "' + fname + '"').readlines()
good = 0
for line in data:
if line.strip() == "javascript successfully tested the Python test component.":
good = 1
if good:
print "Javascript could successfully use the Python test component."
else:
print "** The javascript test appeared to fail! Test output follows **"
print "".join(data)
print "** End of javascript test output **"
except os.error, why:
print "Error executing the javascript test program:", why
def doit(num_loops = -1):
if "-v" in sys.argv: # Hack the verbose flag for the server
xpcom.verbose = 1
# Do the test lots of times - can help shake-out ref-count bugs.
print "Testing the Python.TestComponent component"
if num_loops == -1: num_loops = 10
for i in xrange(num_loops):
test_all()
if i==0:
# First loop is likely to "leak" as we cache things.
# Leaking after that is a problem.
num_refs = gettotalrefcount()
if num_errors:
break
lost = gettotalrefcount() - num_refs
# Sometimes we get spurious counts off by 1 or 2.
# This can't indicate a real leak, as we have looped
# more than twice!
if abs(lost)>2:
print "*** Lost %d references" % (lost,)
if num_errors:
print "There were", num_errors, "errors testing the Python component :-("
else:
print "The Python test component worked!"
# regrtest doesnt like if __name__=='__main__' blocks - it fails when running as a test!
num_iters = -1
if __name__=='__main__' and len(sys.argv) > 1:
num_iters = int(sys.argv[1])
doit(num_iters)
test_from_js()
if __name__=='__main__':
# But we can only do this if _not_ testing - otherwise we
# screw up any tests that want to run later.
xpcom._xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)

View File

@@ -0,0 +1,52 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# test_weakreferences.py - Test our weak reference implementation.
from xpcom import components, _xpcom
import xpcom.server, xpcom.client
num_alive = 0
class koTestSimple:
_com_interfaces_ = [components.interfaces.nsIInputStream]
def __init__(self):
global num_alive
num_alive += 1
def __del__(self):
global num_alive
num_alive -= 1
def close( self ):
pass
def test():
ob = xpcom.server.WrapObject( koTestSimple(), components.interfaces.nsIInputStream)
if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
# Check we can create a weak reference to our object.
wr = xpcom.client.WeakReference(ob)
if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
# Check we can call methods via the weak reference.
if wr() is None: raise RuntimeError, "Our weak-reference is returning None before it should!"
wr().close()
ob = None # This should kill the object.
if num_alive != 0: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
if wr() is not None: raise RuntimeError, "Our weak-reference is not returning None when it should!"
# Now a test that we can get a _new_ interface from the weak reference - ie,
# an IID the real object has never previously been queried for
# (this behaviour previously caused a bug - never again ;-)
ob = xpcom.server.WrapObject( koTestSimple(), components.interfaces.nsISupports)
if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
wr = xpcom.client.WeakReference(ob, components.interfaces.nsIInputStream)
if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
wr() # This would die once upon a time ;-)
ob = None # This should kill the object.
if num_alive != 0: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,)
if wr() is not None: raise RuntimeError, "Our weak-reference is not returning None when it should!"
test()
print "Weak-reference tests appear to have worked!"

View File

@@ -0,0 +1,33 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# regxpcom.py - basically the standard regxpcom.cpp ported to Python.
from xpcom import components, _xpcom
import sys
import os
def ProcessArgs(args):
unregister = 0
for arg in args:
if arg == "-u":
unregister = 1
else:
spec = components.classes['@mozilla.org/file/local;1'].createInstance()
spec = spec.QueryInterface(components.interfaces.nsILocalFile)
spec.initWithPath(os.path.abspath(arg))
if unregister:
components.manager.autoUnregisterComponent( components.manager.NS_Startup, spec)
print "Successfully unregistered", spec.path
else:
components.manager.autoRegisterComponent( components.manager.NS_Startup, spec)
print "Successfully registered", spec.path
unregister = 0
import xpcom
if len(sys.argv) < 2:
components.manager.autoRegister( components.manager.NS_Startup, None)
else:
ProcessArgs(sys.argv[1:])
_xpcom.NS_ShutdownXPCOM()

View File

@@ -0,0 +1,79 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# This is a demo is how to use the xpcom.server "tracer" facility.
#
# This demo installs a tracer that uses the Python profiler. It then
# creates the Python test component, and references some methods
# and properties. It then dumps the profile statistics.
# This same technique could also be used for debugging, for example.
import profile
p = profile.Profile()
getters = {}
setters = {}
# A wrapper around a function - looks like a function,
# but actually profiles the delegate.
class TracerDelegate:
def __init__(self, callme):
self.callme = callme
def __call__(self, *args):
return p.runcall(self.callme, *args)
# A wrapper around each of our XPCOM objects. All PyXPCOM calls
# in are made on this object, which creates a TracerDelagate around
# every function. As the function is called, it collects profile info.
class Tracer:
def __init__(self, ob):
self.__dict__['_ob'] = ob
def __repr__(self):
return "<Tracer around %r>" % (self._ob,)
def __str__(self):
return "<Tracer around %r>" % (self._ob,)
def __getattr__(self, attr):
ret = getattr(self._ob, attr) # Attribute error just goes up
if callable(ret):
return TracerDelegate(ret)
else:
if not attr.startswith("_com_") and not attr.startswith("_reg_"):
getters[attr] = getters.setdefault(attr,0) + 1
return ret
def __setattr__(self, attr, val):
if self.__dict__.has_key(attr):
self.__dict__[attr] = val
return
setters[attr] = setters.setdefault(attr,0) + 1
setattr(self._ob, attr, val)
# Installed as a global XPCOM function that if exists, will be called
# to wrap each XPCOM object created.
def MakeTracer(ob):
# In some cases we may be asked to wrap ourself, so handle that.
if isinstance(ob, Tracer):
return ob
return Tracer(ob)
def test():
import xpcom.server, xpcom.components
xpcom.server.tracer = MakeTracer
contractid = "Python.TestComponent"
for i in range(100):
c = xpcom.components.classes[contractid].createInstance().queryInterface(xpcom.components.interfaces.nsIPythonTestInterface)
c.boolean_value = 0
a = c.boolean_value
c.do_boolean(0,1)
print "Finshed"
p.print_stats()
print "%-30s%s" % ("Attribute Gets", "Number")
print "-" * 36
for name, num in getters.items():
print "%-30s%d" % (name, num)
print "%-30s%s" % ("Attribute Sets", "Number")
print "-" * 36
for name, num in setters.items():
print "%-30s%d" % (name, num)
test()

View File

@@ -0,0 +1,202 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
# Could maybe later have a process that extracted these enums should they change.
# from nsFileLocations.h
App_DirectoryBase = 0x00010000
App_PrefsDirectory30 = App_DirectoryBase + 1
App_PrefsDirectory40 = App_DirectoryBase + 2
App_PrefsDirectory50 = App_DirectoryBase + 3
App_ResDirectory = App_DirectoryBase + 5
App_UserProfileDirectory30 = App_DirectoryBase + 10
App_UserProfileDirectory40 = App_DirectoryBase + 11
App_UserProfileDirectory50 = App_DirectoryBase + 12
App_DefaultUserProfileRoot30 = App_DirectoryBase + 13
App_DefaultUserProfileRoot40 = App_DirectoryBase + 14
App_DefaultUserProfileRoot50 = App_DirectoryBase + 15
App_ProfileDefaultsFolder30 = App_DirectoryBase + 16
App_ProfileDefaultsFolder40 = App_DirectoryBase + 17
App_ProfileDefaultsFolder50 = App_DirectoryBase + 18
App_PrefDefaultsFolder50 = App_DirectoryBase + 19
App_DefaultsFolder50 = App_DirectoryBase + 25
App_ComponentsDirectory = App_DirectoryBase + 30
App_ChromeDirectory = App_DirectoryBase + 31
App_PluginsDirectory = App_DirectoryBase + 32
App_UserChromeDirectory = App_DirectoryBase + 40
App_FileBase = App_DirectoryBase + 1000
App_PreferencesFile30 = App_FileBase + 1
App_PreferencesFile40 = App_FileBase + 2
App_PreferencesFile50 = App_FileBase + 3
App_BookmarksFile30 = App_FileBase + 10
App_BookmarksFile40 = App_FileBase + 11
App_BookmarksFile50 = App_FileBase + 12
App_Registry40 = App_FileBase + 20
App_Registry50 = App_FileBase + 21
App_LocalStore50 = App_FileBase + 30
App_History50 = App_FileBase + 40
App_MailDirectory50 = App_FileBase + 50
App_ImapMailDirectory50 = App_FileBase + 60
App_NewsDirectory50 = App_FileBase + 70
App_MessengerFolderCache50 = App_FileBase + 80
App_UsersPanels50 = App_FileBase + 90
App_SearchFile50 = App_FileBase + 100
App_SearchDirectory50 = App_FileBase + 101
# From nsSpecialSystemDirectory.h
OS_DriveDirectory = 1
OS_TemporaryDirectory = 2
OS_CurrentProcessDirectory= 3
OS_CurrentWorkingDirectory= 4
XPCOM_CurrentProcessComponentDirectory= 5
XPCOM_CurrentProcessComponentRegistry= 6
Moz_BinDirectory = 10
Mac_SystemDirectory = 101
Mac_DesktopDirectory = 102
Mac_TrashDirectory = 103
Mac_StartupDirectory = 104
Mac_ShutdownDirectory = 105
Mac_AppleMenuDirectory = 106
Mac_ControlPanelDirectory = 107
Mac_ExtensionDirectory = 108
Mac_FontsDirectory = 109
Mac_PreferencesDirectory = 110
Mac_DocumentsDirectory = 111
Mac_InternetSearchDirectory = 112
Win_SystemDirectory = 201
Win_WindowsDirectory = 202
Win_HomeDirectory = 203
Win_Desktop = 204
Win_Programs = 205
Win_Controls = 206
Win_Printers = 207
Win_Personal = 208
Win_Favorites = 209
Win_Startup = 210
Win_Recent = 211
Win_Sendto = 212
Win_Bitbucket = 213
Win_Startmenu = 214
Win_Desktopdirectory = 215
Win_Drives = 216
Win_Network = 217
Win_Nethood = 218
Win_Fonts = 219
Win_Templates = 220
Win_Common_Startmenu = 221
Win_Common_Programs = 222
Win_Common_Startup = 223
Win_Common_Desktopdirectory = 224
Win_Appdata = 225
Win_Printhood = 226
Unix_LocalDirectory = 301
Unix_LibDirectory = 302
Unix_HomeDirectory = 303
BeOS_SettingsDirectory = 401
BeOS_HomeDirectory = 402
BeOS_DesktopDirectory = 403
BeOS_SystemDirectory = 404
OS2_SystemDirectory = 501
# Type/Variant related constants.
TD_INT8 = 0
TD_INT16 = 1
TD_INT32 = 2
TD_INT64 = 3
TD_UINT8 = 4
TD_UINT16 = 5
TD_UINT32 = 6
TD_UINT64 = 7
TD_FLOAT = 8
TD_DOUBLE = 9
TD_BOOL = 10
TD_CHAR = 11
TD_WCHAR = 12
TD_VOID = 13
TD_PNSIID = 14
TD_DOMSTRING = 15
TD_PSTRING = 16
TD_PWSTRING = 17
TD_INTERFACE_TYPE = 18
TD_INTERFACE_IS_TYPE = 19
TD_ARRAY = 20
TD_PSTRING_SIZE_IS = 21
TD_PWSTRING_SIZE_IS = 22
# From xpt_struct.h
XPT_TDP_POINTER = 0x80
XPT_TDP_UNIQUE_POINTER = 0x40
XPT_TDP_REFERENCE = 0x20
XPT_TDP_FLAGMASK = 0xe0
XPT_TDP_TAGMASK = (~XPT_TDP_FLAGMASK)
def XPT_TDP_TAG(tdp): return (tdp & XPT_TDP_TAGMASK)
def XPT_TDP_IS_POINTER(flags): return (flags & XPT_TDP_POINTER)
def XPT_TDP_IS_UNIQUE_POINTER(flags): return (flags & XPT_TDP_UNIQUE_POINTER)
def XPT_TDP_IS_REFERENCE(flags): return (flags & XPT_TDP_REFERENCE)
XPT_ID_SCRIPTABLE = 0x80
XPT_ID_FLAGMASK = 0x80
XPT_ID_TAGMASK = ~XPT_ID_FLAGMASK
def XPT_ID_TAG(id): return id & XPT_ID_TAGMASK
def XPT_ID_IS_SCRIPTABLE(flags): return flags & XPT_ID_SCRIPTABLE
XPT_PD_IN = 0x80
XPT_PD_OUT = 0x40
XPT_PD_RETVAL = 0x20
XPT_PD_SHARED = 0x10
XPT_PD_DIPPER = 0x08
XPT_PD_FLAGMASK = 0xf0
def XPT_PD_IS_IN(flags): return (flags & XPT_PD_IN)
def XPT_PD_IS_OUT(flags): return (flags & XPT_PD_OUT)
def XPT_PD_IS_RETVAL(flags): return (flags & XPT_PD_RETVAL)
def XPT_PD_IS_SHARED(flags): return (flags & XPT_PD_SHARED)
def XPT_PD_IS_DIPPER(flags): return (flags & XPT_PD_DIPPER)
XPT_MD_GETTER = 0x80
XPT_MD_SETTER = 0x40
XPT_MD_NOTXPCOM = 0x20
XPT_MD_CTOR = 0x10
XPT_MD_HIDDEN = 0x08
XPT_MD_FLAGMASK = 0xf8
def XPT_MD_IS_GETTER(flags): return (flags & XPT_MD_GETTER)
def XPT_MD_IS_SETTER(flags): return (flags & XPT_MD_SETTER)
def XPT_MD_IS_NOTXPCOM(flags): return (flags & XPT_MD_NOTXPCOM)
def XPT_MD_IS_CTOR(flags): return (flags & XPT_MD_CTOR)
def XPT_MD_IS_HIDDEN(flags): return (flags & XPT_MD_HIDDEN)
# From xptinfo.h
T_I8 = TD_INT8
T_I16 = TD_INT16
T_I32 = TD_INT32
T_I64 = TD_INT64
T_U8 = TD_UINT8
T_U16 = TD_UINT16
T_U32 = TD_UINT32
T_U64 = TD_UINT64
T_FLOAT = TD_FLOAT
T_DOUBLE = TD_DOUBLE
T_BOOL = TD_BOOL
T_CHAR = TD_CHAR
T_WCHAR = TD_WCHAR
T_VOID = TD_VOID
T_IID = TD_PNSIID
T_DOMSTRING = TD_DOMSTRING
T_CHAR_STR = TD_PSTRING
T_WCHAR_STR = TD_PWSTRING
T_INTERFACE = TD_INTERFACE_TYPE
T_INTERFACE_IS = TD_INTERFACE_IS_TYPE
T_ARRAY = TD_ARRAY
T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS
T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS

View File

@@ -0,0 +1,435 @@
# Copyright (c) 2000-2001 ActiveState Tool Corporation.
# See the file LICENSE.txt for licensing information.
"""
Program: xpt.py
Task: describe interfaces etc using XPCOM reflection.
Subtasks:
output (nearly) exactly the same stuff as xpt_dump, for verification
output Python source code that can be used as a template for an interface
Status: Works pretty well if you ask me :-)
Author:
David Ascher did an original version that parsed XPT files
directly. Mark Hammond changed it to use the reflection interfaces,
but kept most of the printing logic.
Revision:
0.1: March 6, 2000
0.2: April 2000 - Mark removed lots of Davids lovely parsing code in favour
of the new xpcom interfaces that provide this info.
May 2000 - Moved into Perforce - track the log there!
Todo:
Fill out this todo list.
"""
import string, sys
import xpcom
import xpcom._xpcom
from xpcom_consts import *
class Interface:
def __init__(self, iid):
iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager()
if hasattr(iid, "upper"): # Is it a stringy thing.
item = iim.GetInfoForName(iid)
else:
item = iim.GetInfoForIID(iid)
self.interface_info = item
self.namespace = "" # where does this come from?
self.methods = Methods(item)
self.constants = Constants(item)
# delegate attributes to the real interface
def __getattr__(self, attr):
return getattr(self.interface_info, attr)
def GetParent(self):
try:
raw_parent = self.interface_info.GetParent()
if raw_parent is None:
return None
return Interface(raw_parent.GetIID())
except xpcom.Exception:
# Parent interface is probably not scriptable - assume nsISupports.
if xpcom.verbose:
# The user may be confused as to why this is happening!
print "The parent interface of IID '%s' can not be located - assuming nsISupports"
return Interface(xpcom._xpcom.IID_nsISupports)
def Describe_Python(self):
method_reprs = []
methods = filter(lambda m: not m.IsNotXPCOM(), self.methods)
for m in methods:
method_reprs.append(m.Describe_Python())
method_joiner = "\n"
methods_repr = method_joiner.join(method_reprs)
return \
"""class %s:
_com_interfaces_ = xpcom.components.interfaces.%s
# If this object needs to be registered, the following 2 are also needed.
# _reg_clsid_ = "{a new clsid generated for this object}"
# _reg_contractid_ = "The.Object.Name"\n%s""" % (self.GetName(), self.GetIID().name, methods_repr)
def Describe(self):
# Make the IID look like xtp_dump - "(" instead of "{"
iid_use = "(" + str(self.GetIID())[1:-1] + ")"
s = ' - '+self.namespace+'::'+ self.GetName() + ' ' + iid_use + ':\n'
parent = self.GetParent()
if parent is not None:
s = s + ' Parent: ' + parent.namespace + '::' + parent.GetName() + '\n'
s = s + ' Flags:\n'
if self.IsScriptable(): word = 'TRUE'
else: word = 'FALSE'
s = s + ' Scriptable: ' + word + '\n'
s = s + ' Methods:\n'
methods = filter(lambda m: not m.IsNotXPCOM(), self.methods)
if len(methods):
for m in methods:
s = s + ' ' + m.Describe() + '\n'
else:
s = s + ' No Methods\n'
s = s + ' Constants:\n'
if self.constants:
for c in self.constants:
s = s + ' ' + c.Describe() + '\n'
else:
s = s + ' No Constants\n'
return s
# A class that allows caching and iterating of methods.
class Methods:
def __init__(self, interface_info):
self.interface_info = interface_info
try:
self.items = [None] * interface_info.GetMethodCount()
except xpcom.Exception:
if xpcom.verbose:
print "** GetMethodCount failed?? - assuming no methods"
self.items = []
def __len__(self):
return len(self.items)
def __getitem__(self, index):
ret = self.items[index]
if ret is None:
mi = self.interface_info.GetMethodInfo(index)
ret = self.items[index] = Method(mi, index, self.interface_info)
return ret
class Method:
def __init__(self, method_info, method_index, interface_info = None):
self.interface_info = interface_info
self.method_index = method_index
self.flags, self.name, param_descs, self.result_desc = method_info
# Build the params.
self.params = []
pi=0
for pd in param_descs:
self.params.append( Parameter(pd, pi, method_index, interface_info) )
pi = pi + 1
# Run over the params setting the "sizeof" params to hidden.
for p in self.params:
td = p.type_desc
tag = XPT_TDP_TAG(td[0])
if tag==T_ARRAY and p.IsIn():
self.params[td[1]].hidden_indicator = 2
elif tag in [T_PSTRING_SIZE_IS, T_PWSTRING_SIZE_IS] and p.IsIn():
self.params[td[1]].hidden_indicator = 1
def IsGetter(self):
return (self.flags & XPT_MD_GETTER)
def IsSetter(self):
return (self.flags & XPT_MD_SETTER)
def IsNotXPCOM(self):
return (self.flags & XPT_MD_NOTXPCOM)
def IsConstructor(self):
return (self.flags & XPT_MD_CTOR)
def IsHidden(self):
return (self.flags & XPT_MD_HIDDEN)
def Describe_Python(self):
if self.method_index < 3: # Ignore QI etc
return ""
base_name = self.name
if self.IsGetter():
name = "get_%s" % (base_name,)
elif self.IsSetter():
name = "set_%s" % (base_name,)
else:
name = base_name
param_decls = ["self"]
in_comments = []
out_descs = []
result_comment = "Result: void - None"
for p in self.params:
in_desc, in_desc_comments, out_desc, this_result_comment = p.Describe_Python()
if in_desc is not None:
param_decls.append(in_desc)
if in_desc_comments is not None:
in_comments.append(in_desc_comments)
if out_desc is not None:
out_descs.append(out_desc)
if this_result_comment is not None:
result_comment = this_result_comment
joiner = "\n # "
in_comment = out_desc = ""
if in_comments: in_comment = joiner + joiner.join(in_comments)
if out_descs: out_desc = joiner + joiner.join(out_descs)
return """ def %s( %s ):
# %s%s%s
pass""" % (name, ", ".join(param_decls), result_comment, in_comment, out_desc)
def Describe(self):
s = ''
if self.IsGetter():
G = 'G'
else:
G = ' '
if self.IsSetter():
S = 'S'
else: S = ' '
if self.IsHidden():
H = 'H'
else:
H = ' '
if self.IsNotXPCOM():
N = 'N'
else:
N = ' '
if self.IsConstructor():
C = 'C'
else:
C = ' '
def desc(a): return a.Describe()
method_desc = string.join(map(desc, self.params), ', ')
result_type = TypeDescriber(self.result_desc[0], None)
return_desc = result_type.Describe()
i = string.find(return_desc, 'retval ')
if i != -1:
return_desc = return_desc[:i] + return_desc[i+len('retval '):]
return G+S+H+N+C+' '+return_desc+' '+self.name + '('+ method_desc + ');'
class Parameter:
def __init__(self, param_desc, param_index, method_index, interface_info = None):
self.param_flags, self.type_desc = param_desc
self.hidden_indicator = 0 # Is this a special "size" type param that will be hidden from Python?
self.param_index = param_index
self.method_index= method_index
self.interface_info = interface_info
def __repr__(self):
return "<param %(param_index)d (method %(method_index)d) - flags = 0x%(param_flags)x, type = %(type_desc)s>" % self.__dict__
def IsIn(self):
return XPT_PD_IS_IN(self.param_flags)
def IsOut(self):
return XPT_PD_IS_OUT(self.param_flags)
def IsInOut(self):
return self.IsIn() and self.IsOut()
def IsRetval(self):
return XPT_PD_IS_RETVAL(self.param_flags)
def IsShared(self):
return XPT_PD_IS_SHARED(self.param_flags)
def IsDipper(self):
return XPT_PD_IS_DIPPER(self.param_flags)
def Describe_Python(self):
name = "param%d" % (self.param_index,)
if self.hidden_indicator:
# Could remove the comment - Im trying to tell the user where that param has
# gone from the signature!
return None, "%s is a hidden parameter" % (name,), None, None
t = TypeDescriber(self.type_desc[0], self)
decl = in_comment = out_comment = result_comment = None
type_desc = t.Describe()
if self.IsIn() and not self.IsDipper():
decl = name
extra=""
if self.IsOut():
extra = "Out"
in_comment = "In%s: %s: %s" % (extra, name, type_desc)
elif self.IsOut() or self.IsDipper():
if self.IsRetval():
result_comment = "Result: %s" % (type_desc,)
else:
out_comment = "Out: %s" % (type_desc,)
return decl, in_comment, out_comment, result_comment
def Describe(self):
parts = []
if self.IsInOut():
parts.append('inout')
elif self.IsIn():
parts.append('in')
elif self.IsOut():
parts.append('out')
if self.IsDipper(): parts.append("dipper")
if self.IsRetval(): parts.append('retval')
if self.IsShared(): parts.append('shared')
t = TypeDescriber(self.type_desc[0], self)
type_str = t.Describe()
parts.append(type_str)
return string.join(parts)
# A class that allows caching and iterating of constants.
class Constants:
def __init__(self, interface_info):
self.interface_info = interface_info
try:
self.items = [None] * interface_info.GetConstantCount()
except xpcom.Exception:
if xpcom.verbose:
print "** GetConstantCount failed?? - assuming no constants"
self.items = []
def __len__(self):
return len(self.items)
def __getitem__(self, index):
ret = self.items[index]
if ret is None:
ci = self.interface_info.GetConstant(index)
ret = self.items[index] = Constant(ci)
return ret
class Constant:
def __init__(self, ci):
self.name, self.type, self.value = ci
def Describe(self):
return TypeDescriber(self.type, None).Describe() + ' ' +self.name+' = '+str(self.value)+';'
__str__ = Describe
def MakeReprForInvoke(param):
tag = param.type_desc[0] & XPT_TDP_TAGMASK
if tag == T_INTERFACE:
i_info = param.interface_info
try:
iid = i_info.GetIIDForParam(param.method_index, param.param_index)
except xpcom.Exception:
# IID not available (probably not scriptable) - just use nsISupports.
iid = xpcom._xpcom.IID_nsISupports
return param.type_desc[0], 0, 0, str(iid)
elif tag == T_ARRAY:
i_info = param.interface_info
array_desc = i_info.GetTypeForParam(param.method_index, param.param_index, 1)
return param.type_desc[:-1] + array_desc[:1]
return param.type_desc
class TypeDescriber:
def __init__(self, type_flags, param):
self.type_flags = type_flags
self.tag = XPT_TDP_TAG(self.type_flags)
self.param = param
def IsPointer(self):
return XPT_TDP_IS_POINTER(self.type_flags)
def IsUniquePointer(self):
return XPT_TDP_IS_UNIQUE_POINTER(self.type_flags)
def IsReference(self):
return XPT_TDP_IS_REFERENCE(self.type_flags)
def repr_for_invoke(self):
return (self.type_flags,)
def GetName(self):
is_ptr = self.IsPointer()
data = type_info_map.get(self.tag)
if data is None:
data = ("unknown",)
if self.IsReference():
if len(data) > 2:
return data[2]
return data[0] + " &"
if self.IsPointer():
if len(data)>1:
return data[1]
return data[0] + " *"
return data[0]
def Describe(self):
if self.tag == T_ARRAY:
# NOTE - Adding a type specifier to the array is different from xpt_dump.exe
if self.param is None or self.param.interface_info is None:
type_desc = "" # Dont have explicit info about the array type :-(
else:
i_info = self.param.interface_info
type_code = i_info.GetTypeForParam(self.param.method_index, self.param.param_index, 1)
type_desc = TypeDescriber( type_code[0], None).Describe()
return self.GetName() + "[" + type_desc + "]"
elif self.tag == T_INTERFACE:
if self.param is None or self.param.interface_info is None:
return "nsISomething" # Dont have explicit info about the IID :-(
i_info = self.param.interface_info
m_index = self.param.method_index
p_index = self.param.param_index
try:
iid = i_info.GetIIDForParam(m_index, p_index)
return iid.name
except xpcom.Exception:
return "nsISomething"
return self.GetName()
# These are just for output purposes, so should be
# the same as xpt_dump uses
type_info_map = {
T_I8 : ("int8",),
T_I16 : ("int16",),
T_I32 : ("int32",),
T_I64 : ("int64",),
T_U8 : ("uint8",),
T_U16 : ("uint16",),
T_U32 : ("uint32",),
T_U64 : ("uint64",),
T_FLOAT : ("float",),
T_DOUBLE : ("double",),
T_BOOL : ("boolean",),
T_CHAR : ("char",),
T_WCHAR : ("wchar_t", "wstring"),
T_VOID : ("void",),
T_IID : ("reserved", "nsIID *", "nsIID &"),
T_DOMSTRING : ("DOMString",),
T_CHAR_STR : ("reserved", "string"),
T_WCHAR_STR : ("reserved", "wstring"),
T_INTERFACE : ("reserved", "Interface"),
T_INTERFACE_IS : ("reserved", "InterfaceIs *"),
T_ARRAY : ("reserved", "Array"),
T_PSTRING_SIZE_IS : ("reserved", "string_s"),
T_PWSTRING_SIZE_IS : ("reserved", "wstring_s"),
}
def dump_interface(iid, mode):
interface = Interface(iid)
describer_name = "Describe"
if mode == "xptinfo": mode = None
if mode is not None:
describer_name = describer_name + "_" + mode.capitalize()
describer = getattr(interface, describer_name)
print describer()
if __name__=='__main__':
if len(sys.argv) == 1:
print "Usage: xpt.py [-xptinfo] interface_name, ..."
print " -info: Dump in a style similar to the xptdump tool"
print "Dumping nsISupports and nsIInterfaceInfo"
sys.argv.append('nsIInterfaceInfo')
sys.argv.append('-xptinfo')
sys.argv.append('nsISupports')
sys.argv.append('nsIInterfaceInfo')
mode = "Python"
for i in sys.argv[1:]:
if i[0] == "-":
mode = i[1:]
else:
dump_interface(i, mode)