michael@0: michael@0: michael@0: michael@0:
XPConnect Sample michael@0: michael@0:

michael@0: Ariel Blackenroth <arielb@rice.edu> michael@0:
michael@0: Michael Ang <mang@subcarrier.org> michael@0:
michael@0: Last modified michael@0: michael@0:

michael@0: michael@0:

In the spirit of "worse is better" this somewhat rough guide is being michael@0: released to the world. It will be expanded upon and improved. michael@0: michael@0:

XPConnect allows JavaScript michael@0: to transparantly access and manipulate XPCOM objects; this communication michael@0: between JavaScript and michael@0: native code is done by having their interfaces defined in the XPIDL interface michael@0: definition language. See the Roadmap michael@0: for documentation on XPCOM, XPConnect, XPTCall and XPIDL for more information. michael@0: michael@0:

Overview michael@0: michael@0:

michael@0: This sample demonstrates accessing a XPCOM object through XPConnect. michael@0: The JavaScript executed when this page loads creates an instance michael@0: of the object by michael@0: using the Components object, then accesses it through michael@0: the nsISample interface by calling QueryInterface: michael@0:
michael@0:

michael@0: netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
michael@0: var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
michael@0: sample = sample.QueryInterface(Components.interfaces.nsISample);
michael@0: 
michael@0: michael@0:

michael@0: The buttons on the form are connected to JavaScript event handlers which michael@0: call the methods defined in C++. michael@0: michael@0: michael@0:

nsISample.idl michael@0:

This is the interface declaration for the XPCOM object. It defines michael@0: two functions, their parameters, and one attribute. It also defines michael@0: the interface's id. The idl file is compiled by the xpidl compiler michael@0: into a C++ header, nsISample.h and a .xpt file which is a binary representation michael@0: of the interface used at runtime. michael@0:
attribute string value; michael@0:
void writeValue(in string aPrefix); michael@0:
void poke(in string aValue); michael@0:

nsSample.cpp michael@0:

This contains the implementation of nsISample.idl. SampleImpl michael@0: inherits from nsISample.h, the header dynamically created by the xpidl michael@0: compiler. The attribute Value has been expanded into a get and set michael@0: and the return values have been modified to NS_IMETHOD, a success status michael@0: for the method. The macro NS_DECL_ISUPPORTS, defined in mozilla/xpcom/public/nsISupportsUtils.h michael@0: defines the inherited methods from nsISupports.h. michael@0:
NS_IMPL_ISUPPORTS(SampleImpl, nsISample) michael@0:
In the constructor, the macro NS_INIT_REFCNT is called which sets the michael@0: reference count to 0.

michael@0: Note that the methods in the C++ bindings use InterCaps style, while the IDL michael@0: and JavaScript versions should use interCaps naming. The JavaScript binding michael@0: matches the case of the IDL, except QueryInterface. michael@0:

nsSampleFactory.cpp michael@0:

This is the class which builds the instance of the nsSample class. michael@0: The COM framework uses factories to create instance of implementations michael@0: rather than having the implementations instantiate themselves in order to michael@0: increase portability of code. This factory inherits from nsFactory, michael@0: which is also an XPCOM object. To gain more knowledge of factories michael@0: see the generic michael@0: factory document or the Modularization techniques document. michael@0:

nsSample.js michael@0:

This file implements the nsISample interface, and associated factory glue, michael@0: in JavaScript. michael@0: michael@0:

Compiling the idl michael@0: michael@0:

The XPIDL compiler (xpidl on Unix, xpidl.exe on Windows, and a CodeWarrior plugin on Mac) michael@0: is compiled at build time (except on Mac) thus michael@0: you will have to build mozilla in order to test this out. If you michael@0: have already built mozilla then the compiler will be located at mozilla\dist\WIN32_D.OBJ\bin\xpidl.exe. michael@0: michael@0:

Once you have the XPIDL compiler enter the following command at your michael@0: prompt: michael@0:
D:\mozilla\xpcom\sample>d:\mozilla\dist\WIN32_D.OBJ\bin\xpidl -I michael@0: d:\mozilla\dist\idl -m header nsISample.idl michael@0: michael@0:

The -I d:\mozilla\dist\idl points the compiler to the folder michael@0: containing the other idl files, needed because nsISample.idl inherits from michael@0: nsISupports.idl. The -m header instruction tells the compiler michael@0: to build the C++ header. To build the .xpt file substitute -m michael@0: typelib. michael@0: michael@0:

michael@0: For more information on compilation see the xpidl michael@0: compiler page. michael@0: michael@0:

Building the Sample michael@0: michael@0:

To build the Sample just enter michael@0:
d:\mozilla\xpcom\sample>nmake /f makefile.win michael@0: michael@0:

In order to do this you need to have your environment variables set michael@0: correctly. See the Build michael@0: page for more information. michael@0: michael@0:

Running the sample michael@0:

Using Mozilla, load michael@0: resource://res/samples/xpconnect-sample.html (i.e. what michael@0: you're reading now). Pay attention michael@0: to the console when clicking "write". Notice that the value michael@0: printed is calculated in C++ code defined in nsSample.cpp. michael@0: michael@0: michael@0: michael@0: michael@0:

michael@0:

michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
michael@0: michael@0:

michael@0: JavaScript and form source: michael@0: michael@0: michael@0:

michael@0: <script>
michael@0: /* to use nsSample.js version, use "@mozilla.org/jssample;1" */
michael@0: netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
michael@0: var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
michael@0: sample = sample.QueryInterface(Components.interfaces.nsISample);
michael@0: dump("sample = " + sample + "\n");
michael@0: 
michael@0: function get()
michael@0: {
michael@0:   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
michael@0:   field.value = sample.value;
michael@0: }
michael@0: 
michael@0: function set()
michael@0: {
michael@0:   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
michael@0:   sample.value = field.value;
michael@0: }
michael@0: 
michael@0: function poke()
michael@0: {
michael@0:   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
michael@0:   sample.poke(field.value);
michael@0: }
michael@0: 
michael@0: function sampleWrite()
michael@0: {
michael@0:   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
michael@0:   sample.writeValue("here is what I'm writing: ");
michael@0: }
michael@0: </script>
michael@0: 
michael@0: <form name="form">
michael@0: <input type="button" value="Get" onclick="get();">
michael@0: <input type="button" value="Set" onclick="set();">
michael@0: <input type="button" value="Poke" onclick="poke();">
michael@0: <input type="text" id="Value">
michael@0: <input type="button" value="Write" onclick="sampleWrite();">
michael@0: <form>
michael@0: 
michael@0: 
michael@0: michael@0:

michael@0:


michael@0: Resources: michael@0: michael@0:
michael@0: Comments to: michael@0: Michael Ang <mang@subcarrier.org>