1 | <html>
|
---|
2 | <!-- ***** BEGIN LICENSE BLOCK *****
|
---|
3 | - Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | -
|
---|
5 | - The contents of this file are subject to the Mozilla Public License Version
|
---|
6 | - 1.1 (the "License"); you may not use this file except in compliance with
|
---|
7 | - the License. You may obtain a copy of the License at
|
---|
8 | - http://www.mozilla.org/MPL/
|
---|
9 | -
|
---|
10 | - Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | - for the specific language governing rights and limitations under the
|
---|
13 | - License.
|
---|
14 | -
|
---|
15 | - The Original Code is PyXPCOM.
|
---|
16 | -
|
---|
17 | - The Initial Developer of the Original Code is
|
---|
18 | - ActiveState Tool Corporation.
|
---|
19 | - Portions created by the Initial Developer are Copyright (C) 2000-2001
|
---|
20 | - the Initial Developer. All Rights Reserved.
|
---|
21 | -
|
---|
22 | - Contributor(s):
|
---|
23 | -
|
---|
24 | - Alternatively, the contents of this file may be used under the terms of
|
---|
25 | - either the GNU General Public License Version 2 or later (the "GPL"), or
|
---|
26 | - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
27 | - in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
28 | - of those above. If you wish to allow use of your version of this file only
|
---|
29 | - under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
30 | - use your version of this file under the terms of the MPL, indicate your
|
---|
31 | - decision by deleting the provisions above and replace them with the notice
|
---|
32 | - and other provisions required by the LGPL or the GPL. If you do not delete
|
---|
33 | - the provisions above, a recipient may use your version of this file under
|
---|
34 | - the terms of any one of the MPL, the GPL or the LGPL.
|
---|
35 | -
|
---|
36 | - ***** END LICENSE BLOCK ***** -->
|
---|
37 |
|
---|
38 | <head>
|
---|
39 | <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
---|
40 | <meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
---|
41 | <meta name="ProgId" content="FrontPage.Editor.Document">
|
---|
42 | <title>Python XPCOM Package Tutorial</title>
|
---|
43 | </head>
|
---|
44 |
|
---|
45 | <body>
|
---|
46 |
|
---|
47 | <h1>Python XPCOM Package Tutorial</h1>
|
---|
48 | <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>,
|
---|
49 | and have experience both using and implementing XPCOM objects in some other
|
---|
50 | language (e.g., C++ or JavaScript). We <b><i>do not</i></b> attempt to
|
---|
51 | provide a tutorial to XPCOM or Python itself, only to using Python <i>and</i>
|
---|
52 | XPCOM.</p>
|
---|
53 | <p>This tutorial contains the following sections:</p>
|
---|
54 | <ul>
|
---|
55 | <li><a href="#Using">Using XPCOM Objects and Interfaces</a> - when you wish to
|
---|
56 | <i>use</i> a component written by anyone else in any XPCOM supported
|
---|
57 | language.</li>
|
---|
58 | <li><a href="#Implementing">Implementing XPCOM Objects and Interfaces</a> -
|
---|
59 | when you wish to implement a component for use by anyone else in any xpcom
|
---|
60 | supported language.</li>
|
---|
61 | <li><a href="#Parameters">Parameters and Types</a> - useful information
|
---|
62 | regarding how Python translates XPCOM types, and handles byref parameters.</li>
|
---|
63 | </ul>
|
---|
64 | <p>For anything not covered here, try the <a href="advanced.html">advanced
|
---|
65 | documentation</a>, and if that fails, use the source, Luke!</p>
|
---|
66 | <h2><a name="Using">Using XPCOM object and interfaces.</a></h2>
|
---|
67 | <p>The techniques for using XPCOM in Python have been borrowed from JavaScript -
|
---|
68 | thus, the model described here should be quite familiar to existing JavaScript
|
---|
69 | XPCOM programmers.</p>
|
---|
70 | <h3>xpcom.components module</h3>
|
---|
71 | <p>When using an XPCOM object, the primary module used is the <u><i>xpcom.components</i></u>
|
---|
72 | module. Using this module, you can get a Python object that supports any
|
---|
73 | scriptable XPCOM interface. Once you have this Python object, you can
|
---|
74 | simply call XPCOM methods on the object, as normal.</p>
|
---|
75 | <p>The <u><i>xpcom.components</i></u> module defines the following public
|
---|
76 | members:</p>
|
---|
77 | <table border="1" width="100%">
|
---|
78 | <tr>
|
---|
79 | <td width="16%"><b>Name</b></td>
|
---|
80 | <td width="84%"><b>Description</b></td>
|
---|
81 | </tr>
|
---|
82 | <tr>
|
---|
83 | <td width="16%">classes</td>
|
---|
84 | <td width="84%">A mapping (dictionary-like object) used to get XPCOM
|
---|
85 | "classes". These are indexed by XPCOM contract ID, just
|
---|
86 | like the JavaScript object of the same name.
|
---|
87 | <p>Example:</p>
|
---|
88 | <pre>cls = components.classes["@mozilla.org/sample;1"]
|
---|
89 | ob = cls.createInstance() # Now have an nsISupports</pre>
|
---|
90 | </td>
|
---|
91 | </tr>
|
---|
92 | <tr>
|
---|
93 | <td width="16%">interfaces</td>
|
---|
94 | <td width="84%">An object that exposes all XPCOM interface IDs (IIDs).
|
---|
95 | Like the JavaScript object of the same name, this object uses
|
---|
96 | "dot" notation, as demonstrated below.
|
---|
97 | <p>Example:</p>
|
---|
98 | <pre>ob = cls.createInstance(components.interfaces.nsISample)
|
---|
99 | # Now have an nsISample</pre>
|
---|
100 | </td>
|
---|
101 | </tr>
|
---|
102 | </table>
|
---|
103 | <p>For many people, this is all you need to know. Consider the Mozilla Sample Component. The Mozilla Sample
|
---|
104 | Component has a contract ID of <i>@mozilla.org/sample;1</i>,
|
---|
105 | and implements the <i>nsISample</i> interface.</p>
|
---|
106 | <p>Thus, a complete Python program that uses this component is shown below.</p>
|
---|
107 | <pre>from xpcom import components
|
---|
108 | cls = components.classes["@mozilla.org/sample;1"]
|
---|
109 | ob = cls.createInstance() # no need to specify an IID for most components
|
---|
110 | # nsISample defines a "value" property - let's use it!
|
---|
111 | ob.value = "new value"
|
---|
112 | if ob.value != "new value":
|
---|
113 | print "Eeek - what happened?"</pre>
|
---|
114 | <p>And that is it - a complete Python program that uses XPCOM.</p>
|
---|
115 | <h2><a name="Implementing">Implementing XPCOM Objects and Interfaces.</a></h2>
|
---|
116 | <p>Implementing XPCOM objects is almost as simple as using them. The
|
---|
117 | basic strategy is this:</p>
|
---|
118 | <ol>
|
---|
119 | <li>Create a standard Python source file, with a standard Python class.</li>
|
---|
120 | <li>Add some special <a href="#Attributes"> attributes</a> to your class for use by the Python XPCOM
|
---|
121 | framework. This controls the XPCOM behavior of your object.</li>
|
---|
122 | <li>Implement the XPCOM <a href="#Properties"> properties</a> and methods of your classes as normal.</li>
|
---|
123 | <li>Put the Python source file in the Mozilla <i> components</i> directory.</li>
|
---|
124 | <li>Run <i> regxpcom.</i></li>
|
---|
125 | </ol>
|
---|
126 | <p>Your component is now ready to be used.</p>
|
---|
127 | <h3><a name="Attributes">Attributes</a></h3>
|
---|
128 | <p>There are two classes of attributes: those used at runtime to define the object
|
---|
129 | behavior and those used at registration time to control object
|
---|
130 | registration. Not all objects require registration, thus not all
|
---|
131 | Python XPCOM objects will have registration-related attributes.</p>
|
---|
132 | <table border="1" width="100%">
|
---|
133 | <tr>
|
---|
134 | <td width="17%"><b>Attribute</b></td>
|
---|
135 | <td width="83%"><b>Description</b></td>
|
---|
136 | </tr>
|
---|
137 | <tr>
|
---|
138 | <td width="17%">_com_interfaces_</td>
|
---|
139 | <td width="83%">The interface IDs (IIDs) supported by the component.
|
---|
140 | For simplicity, this may be either a single IID, or a list of IIDs.
|
---|
141 | There is no need to specify base interfaces, as all parent interfaces are
|
---|
142 | automatically supported. Thus, it is never necessary to nominate <i>
|
---|
143 | nsISupports</i> in the list of interfaces.
|
---|
144 | <p>This attribute is required. Objects without such an attribute are
|
---|
145 | deemed unsuitable for use as a XPCOM object.</td>
|
---|
146 | </tr>
|
---|
147 | <tr>
|
---|
148 | <td width="17%">_reg_contractid_</td>
|
---|
149 | <td width="83%">The contract ID of the component. Required if the
|
---|
150 | component requires registration (i.e., exists in the components directory).</td>
|
---|
151 | </tr>
|
---|
152 | <tr>
|
---|
153 | <td width="17%">_reg_clsid_</td>
|
---|
154 | <td width="83%">The Class ID (CLSID) of the component, as a string in the
|
---|
155 | standard "{XXX-XXX-XXX-XXX}" format. Required if the
|
---|
156 | component requires registration (i.e., exists in the components directory).</td>
|
---|
157 | </tr>
|
---|
158 | <tr>
|
---|
159 | <td width="17%">_reg_registrar_</td>
|
---|
160 | <td width="83%">Nominates a function that is called at registration
|
---|
161 | time. The default is for no extra function to be called. This can
|
---|
162 | be useful if a component has special registration requirements and needs
|
---|
163 | to hook into the registration process.</td>
|
---|
164 | </tr>
|
---|
165 | <tr>
|
---|
166 | <td width="17%">_reg_desc_</td>
|
---|
167 | <td width="83%">The description of the XPCOM object. This may be used by
|
---|
168 | browsers or other such objects. If not specified, the contract ID
|
---|
169 | is used.</td>
|
---|
170 | </tr>
|
---|
171 | </table>
|
---|
172 | <h3><a name="Properties">Properties</a></h3>
|
---|
173 | <p>A Python class can support XPCOM properties in one of two ways. Either
|
---|
174 | a standard Python property of the same name can exist - our sample
|
---|
175 | component demonstrates this with the <i>boolean_value</i> property.
|
---|
176 | Alternatively, the class can provide the <i>get_propertyName(self)</i> and <i>set_propertyName(self,
|
---|
177 | value)</i> functions (with <i>propertyName</i> changed to the appropriate value for the
|
---|
178 | property), and these functions will be called instead.</p>
|
---|
179 | <h4>Example: The Python XPCOM Test Component</h4>
|
---|
180 | <p>As an example, examine the Python XPCOM Test Component. This
|
---|
181 | code can be found in <i>py_test_component.py</i>.</p>
|
---|
182 | <pre>from xpcom import components
|
---|
183 |
|
---|
184 | class PythonTestComponent:
|
---|
185 | _com_interfaces_ = components.interfaces.nsIPythonTestInterface
|
---|
186 | _reg_clsid_ = "{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}"
|
---|
187 | _reg_contractid_ = "Python.TestComponent"
|
---|
188 | def __init__(self):
|
---|
189 | self.boolean_value = 1
|
---|
190 | ...
|
---|
191 | def do_boolean(self, p1, p2):
|
---|
192 | ret = p1 ^ p2
|
---|
193 | return ret, not ret, ret
|
---|
194 | ...</pre>
|
---|
195 | <p><b>Note:</b> This component only specifies the mandatory attributes - <i>_com_interfaces</i>,
|
---|
196 | <i>_reg_clsid_</i> and <i>_reg_contractid_</i>.</p>
|
---|
197 | <p>This sample code demonstrates supporting the <i>boolean_value</i> attribute,
|
---|
198 | supported implicitly, as it is defined in the IDL and exists as a real Python
|
---|
199 | attribute of that name, and a method called <i>do_boolean</i>.</p>
|
---|
200 | <h4>Tip: The xpcom/xpt.py Script</h4>
|
---|
201 | <p> The xpcom/xpt.py script is a useful script that can generate the skeleton of a class for
|
---|
202 | any XPCOM interface. Just specify the interface name on the command-line,
|
---|
203 | and paste the output into your source file.</p>
|
---|
204 | <p>This is the output of running this program over the <i>nsISample</i>
|
---|
205 | interface (i.e., assuming we wanted to implement a component that supported this
|
---|
206 | interface):</p>
|
---|
207 | <pre>class nsISample:
|
---|
208 | _com_interfaces_ = xpcom.components.interfaces.nsISample
|
---|
209 | # If this object needs to be registered, the following 2 are also needed.
|
---|
210 | # _reg_clsid_ = {a new clsid generated for this object}
|
---|
211 | # _reg_contractid_ = "The.Object.Name"
|
---|
212 |
|
---|
213 | def get_value( self ):
|
---|
214 | # Result: string
|
---|
215 | pass
|
---|
216 | def set_value( self, param0 ):
|
---|
217 | # Result: void - None
|
---|
218 | # In: param0: string
|
---|
219 | pass
|
---|
220 | def writeValue( self, param0 ):
|
---|
221 | # Result: void - None
|
---|
222 | # In: param0: string
|
---|
223 | pass
|
---|
224 | def poke( self, param0 ):
|
---|
225 | # Result: void - None
|
---|
226 | # In: param0: string
|
---|
227 | pass</pre>
|
---|
228 | <p><b>Note:</b> The types of the parameters and the function itself are included in
|
---|
229 | the comments. You need to implement the functions
|
---|
230 | themselves. Another advantage of this script is that the <a href="#HiddenParams">hidden
|
---|
231 | parameters</a> are handled for you; the comments indicate when parameters
|
---|
232 | have been hidden.</p>
|
---|
233 | <h2><a name="Parameters">Parameters and Types</a></h2>
|
---|
234 | <p>This section briefly describes the XPCOM type support in
|
---|
235 | Python.</p>
|
---|
236 | <p>All XPCOM interfaces define parameters of a specific type. There is
|
---|
237 | currently no concept of a variant, or union of all types. Thus, the
|
---|
238 | conversion rules are very straightforward, and generally surprise free: for
|
---|
239 | any given XPCOM method, there is only one possible type for a given parameter.</p>
|
---|
240 | <h3>Type Conversion Rules:</h3>
|
---|
241 | <ul>
|
---|
242 | <li>All numeric types will attempt to be coerced to the correct type.
|
---|
243 | Thus, you can pass a Python float to an XPCOM method expecting an integer,
|
---|
244 | or vice-versa. Specifically, when an integer is required, you can pass
|
---|
245 | any Python object for which <i>int()</i> would succeed; for a Python float,
|
---|
246 | any object for which <i>float()</i> would succeed is acceptable. This
|
---|
247 | means that you can pass a Python string object as an integer, as long as the
|
---|
248 | string was holding a valid integer.</li>
|
---|
249 | <li>Strings and Unicode objects are interchangeable, but no other automatic
|
---|
250 | string conversions are performed. Thus, you can not pass an integer
|
---|
251 | where a string is expected, even though the reverse is true.</li>
|
---|
252 | <li>Any sequence object can be passed as an array. List objects are
|
---|
253 | always returned for arrays.</li>
|
---|
254 | <li>Any Python instance suitable for use as a XPCOM object (i.e., with the
|
---|
255 | <a href="#Implementing">necessary annotations</a>) can be
|
---|
256 | passed as a XPCOM object. No special wrapping step is needed to turn a
|
---|
257 | Python instance into a XPCOM object. Note you must pass a class <i>instance</i>,
|
---|
258 | not the class itself.</li>
|
---|
259 | <li><a name="HiddenParams">Many XPCOM <b> method signatures</b> specify
|
---|
260 | "count" or "size" parameters. For example, every
|
---|
261 | time an array is passed via XPCOM, the method signature will always specify
|
---|
262 | an integer that holds the count of the array. These parameters are
|
---|
263 | always hidden in Python. As the size param can be implied from the
|
---|
264 | length of the Python sequence passed, the Python programmer need never pass
|
---|
265 | these parameters; in contrast, JavaScript requires these redundant parameters.</a></li>
|
---|
266 | </ul>
|
---|
267 |
|
---|
268 | <h2>Interface Flattening</h2>
|
---|
269 | <p>Most people can ignore this information - Python XPCOM objects just
|
---|
270 | work. However, if you are familiar with xpcom from C++ and the concept of <i>QueryInterface</i>,
|
---|
271 | you may like to read this.</p>
|
---|
272 | <p>Most components support the concept of "interface
|
---|
273 | flattening". Such objects can report the interfaces they support,
|
---|
274 | allowing languages such as Python and Javascript avoid using <i>QueryInterface</i>.
|
---|
275 | When you are using an XPCOM object from Python, you can just call methods and
|
---|
276 | reference properties without regard for the interface that implements it.</p>
|
---|
277 | <p>When multiple interfaces share the same method or property name, you can use
|
---|
278 | the name of the interface as a differentiator. Thus, <i>ob.nsIFoo.close()</i>
|
---|
279 | will call close on <i>ob</i>'s <i>nsIFoo</i> interface, while <i>ob.nsIBar.close()</i>
|
---|
280 | will use the <i>nsIBar</i> interface. <i>ob.close()</i> is not defined.</p>
|
---|
281 |
|
---|
282 | </body>
|
---|
283 |
|
---|
284 | </html>
|
---|
285 |
|
---|
286 |
|
---|