gecko/modules/plugin/samples/4x-scriptable/doc.html

221 lines
11 KiB
HTML

<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.76 [en]C-AOLNSCP (Win98; U) [Netscape]">
<title>Scripting Old Style Plugins with Mozilla</title>
</head>
<body>
<center><b><font size=+2>Scripting Old Style Plugins in Mozilla</font></b>
<br><i>April 11, 2001</i>
<br>(see online version for the latest updates:
<a href="http://mozilla.org/docs/scripting-plugins.html">http://mozilla.org/docs/scripting-plugins.html</a>)
</center>
<p><a href="readme.html#introduction">Introduction</a>
<br><a href="readme.html#mozilla">New in Mozilla code</a>
<br><a href="readme.html#plugin">New in plugin code</a>
<br><a href="readme.html#script">JavaScript code</a>
<br><a href="readme.html#build">Building and installing the plugin</a>
<br><a href="readme.html#more">What else to read</a>
<br><a href="readme.html#example1">Examples</a>
<p><a NAME="introduction"></a><b>Introduction</b>
<p>Plugins that used to take advantage of being scriptable via LiveConnect
in 4.x Netscape browsers lost this possibility in the new world. The main
reason for this is that there is no guarantee of Java compatibility on
a binary level due to the jri/jni switch. The newly introduced <a href="http://www.mozilla.org/docs/plugin.html">Mozilla
Plugin API</a> allows plugins be scriptable via a different mechanism called
<a href="http://www.mozilla.org/scriptable/index.html">XPConnect.</a>&nbsp;
Basically, this means that in order to use and take full advantage of this
new API, which is interface-based,&nbsp; and to be scriptable, plugins
must be rewritten to become <a href="http://www.mozilla.org/projects/xpcom/">XPCOM</a>
components. Switching to the new world may not be immediately desirable
by some plugin makers, since the task involves a fair amount of effort,
and if the plugin mostly works fine lacking only scriptability, developers
will probably just give up on this feature, which may result in unpleasant
experience for the end user.
<p>In order to make the transtion smoother, some changes have been made
to the Mozilla code. The changes allow to make existing 4.x plugins scriptable
with only minor modifications in their code. The present document describes
the steps of what should be done to the plugin code to turn it scriptable
again.
<p><a NAME="mozilla"></a><b>What's in the Mozilla code?</b>
<p>A couple of lines have been added to the DOM code asking a plugin to
return a scriptable iid and a pointer to a scriptable instance object.
The old Plugin API call <tt>NPP_GetValue</tt> is used to retrieve this
information from the plugin. So the plugin project should be aware of two
new additions to <tt>NPPVariable</tt> enumeration type which are now defined
in npapi.h as
<p><tt>&nbsp; NPPVpluginScriptableInstance = 10,</tt>
<br><tt>&nbsp; NPPVpluginScriptableIID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
11</tt>
<p>and two analogous additions to nsPluginInstanceVariable type in nsplugindefs.h
as
<p><tt>&nbsp; nsPluginInstanceVariable_ScriptableInstance = 10,</tt>
<br><tt>&nbsp; nsPluginInstanceVariable_ScriptableIID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
= 11</tt>
<p><a NAME="plugin"></a><b>What's in the plugin code?</b>
<p>1. A unique interface id should be obtained. Windows command <tt>uuidgen</tt>
should be sufficient.
<p>2. An Interface Definition (<tt>.idl</tt>) file describing the plugin
scriptable interface should be added to the project (<a href="#example1">see
example 1</a>).
<p>3. A Scriptable instance object should be implemented in the plugin.
This class will contain native methods callable from JavaScript. This class
should also inherit from nsISecurityCheckedComponent and implement its
methods to be able to request all necessary privileges from the Mozilla
security manager (<a href="#example2">see example 2</a>).
<p>4. Two new cases for the above mentioned new variables should be added
to the plugin implementation of <tt>NPP_GetValue</tt> (<a href="#example3">see
example 3</a>).
<p><a NAME="script"></a><b>How to call plugin native methods</b>
<p>The following HTML code will do the job:
<p><tt>&lt;embed type="application/plugin-mimetype"></tt>
<br><tt>&lt;script></tt>
<br><tt>var embed = document.embeds[0];</tt>
<br><tt>embed.nativeMethod();</tt>
<br><tt>&lt;/script></tt>
<p><a NAME="build"></a><b>How to build and install</b>
<p>Having the built Mozilla tree is probably not necessary, but building
the plugin with a scriptable instance interface will require Mozilla headers
and the XPCOM compatible idl compiler -- xpidl.exe. <i>MS DevStudio MIDL
should not be used</i>. (Let's assume 'TestPlugin' as a plugin name-place
holder.)
<p>1. Compile nsITestPlugin.idl with the idl compiler. This will generate
nsITestPlugin.h and nsITestPlugin.xpt files.
<p>2. Put nsITestPlugin.xpt to the Components folder.
<p>3. Build nptestplugin.dll with nsITestPlugin.h included for compiling
scriptable instance class implementaion.
<p>4. Put nptestplugin.dll to the Plugins folder.
<p><a NAME="more"></a><b>Related sources</b>
<br>&nbsp;
<ul>
<li>
<a href="http://bugzilla.mozilla.org/">http://bugzilla.mozilla.org</a>
has two bugs in its database which are related to this topic: <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=73856">73856
</a>and <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=73874">73874</a>.
The latter contains the full sample plugin code.</li>
<li>
IBM Developer Works has published <a href="http://www-106.ibm.com/developerworks/components/library/co-xpcom.html">a
good article on XPCOM.</a></li>
</ul>
<p><a NAME="example1"></a><b>Example 1. Sample .idl file</b>
<p><tt>#include "nsISupports.idl"</tt>
<p><tt>[scriptable, uuid(bedb0778-2ee0-11d5-9cf8-0060b0fbd8ac)]</tt>
<br><tt>interface nsITestPlugin : nsISupports {</tt>
<br><tt>&nbsp; void nativeMethod();</tt>
<br><tt>};</tt>
<p><a NAME="example2"></a><b>Example 2. Scriptable instance class</b>
<p><tt>#include "nsITestPlugin.h"</tt>
<br><tt>#include "nsISecurityCheckedComponent.h"</tt>
<p><tt>class nsScriptablePeer : public nsITestPlugin,</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
public nsISecurityCheckedComponent</tt>
<br><tt>{</tt>
<br><tt>public:</tt>
<br><tt>&nbsp; nsScriptablePeer();</tt>
<br><tt>&nbsp; ~nsScriptablePeer();</tt>
<p><tt>&nbsp; NS_DECL_ISUPPORTS</tt>
<br><tt>&nbsp; NS_DECL_NSITESTPLUGIN</tt>
<br><tt>&nbsp; NS_DECL_NSISECURITYCHECKEDCOMPONENT</tt>
<br><tt>};</tt>
<p><tt>nsScriptablePeer::nsScriptablePeer()</tt>
<br><tt>{</tt>
<br><tt>&nbsp; NS_INIT_ISUPPORTS();</tt>
<br><tt>}</tt>
<p><tt>nsScriptablePeer::~nsScriptablePeer()</tt>
<br><tt>{</tt>
<br><tt>}</tt>
<p><tt>NS_IMPL_ISUPPORTS2(nsScriptablePeer, nsITestPlugin, nsISecurityCheckedComponent)</tt>
<p><tt>// the following method will be callable from JavaScript</tt>
<br><tt>NS_IMETHODIMP nsScriptablePeer::NativeMethod()</tt>
<br><tt>{</tt>
<br><tt>&nbsp; return NS_OK;</tt>
<br><tt>}</tt>
<p><tt>// the purpose of the rest of the code is to get successfully</tt>
<br><tt>// through the Mozilla Security Manager</tt>
<br><tt>static const char gAllAccess[] = "AllAccess";</tt>
<br><tt>NS_IMETHODIMP nsScriptablePeer::CanCreateWrapper(const nsIID *
iid, char **_retval)</tt>
<br><tt>{</tt>
<br><tt>&nbsp; if (!_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_NULL_POINTER;</tt>
<br><tt>&nbsp; *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
<br><tt>&nbsp; if (!*_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_OUT_OF_MEMORY;</tt>
<br><tt>&nbsp; strcpy(*_retval, gAllAccess);</tt>
<br><tt>&nbsp; return NS_OK;</tt>
<br><tt>}</tt>
<p><tt>NS_IMETHODIMP nsScriptablePeer::CanCallMethod(const nsIID * iid,
const PRUnichar *methodName, char **_retval)</tt>
<br><tt>{</tt>
<br><tt>&nbsp; if (!_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_NULL_POINTER;</tt>
<br><tt>&nbsp; *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
<br><tt>&nbsp; if (!*_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_OUT_OF_MEMORY;</tt>
<br><tt>&nbsp; strcpy(*_retval, gAllAccess);</tt>
<br><tt>&nbsp; return NS_OK;</tt>
<br><tt>}</tt>
<p><tt>NS_IMETHODIMP nsScriptablePeer::CanGetProperty(const nsIID * iid,
const PRUnichar *propertyName, char **_retval)</tt>
<br><tt>{</tt>
<br><tt>&nbsp; if (!_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_NULL_POINTER;</tt>
<br><tt>&nbsp; *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
<br><tt>&nbsp; if (!*_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_OUT_OF_MEMORY;</tt>
<br><tt>&nbsp; strcpy(*_retval, gAllAccess);</tt>
<br><tt>&nbsp; return NS_OK;</tt>
<br><tt>}</tt>
<p><tt>NS_IMETHODIMP nsScriptablePeer::CanSetProperty(const nsIID * iid,
const PRUnichar *propertyName, char **_retval)</tt>
<br><tt>{</tt>
<br><tt>&nbsp; if (!_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_NULL_POINTER;</tt>
<br><tt>&nbsp; *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
<br><tt>&nbsp; if (!*_retval)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NS_ERROR_OUT_OF_MEMORY;</tt>
<br><tt>&nbsp; strcpy(*_retval, gAllAccess);</tt>
<br><tt>&nbsp; return NS_OK;</tt>
<br><tt>}</tt>
<p><a NAME="example3"></a><b>Example 3. NPP_GetValue implementation</b>
<p><tt>#include "nsITestPlugin.h"</tt>
<p><tt>NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)</tt>
<br><tt>{</tt>
<br><tt>&nbsp; if(instance == NULL)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; return NPERR_INVALID_INSTANCE_ERROR;</tt>
<p><tt>&nbsp; NPError rv = NPERR_NO_ERROR;</tt>
<br><tt>&nbsp; static nsIID scriptableIID = NS_ITESTPLUGIN_IID;</tt>
<p><tt>&nbsp; if (variable == NPPVpluginScriptableInstance)</tt>
<br><tt>&nbsp; {</tt>
<br><tt>&nbsp;&nbsp;&nbsp; if (this is first time and we haven't created
it yet)</tt>
<br><tt>&nbsp;&nbsp;&nbsp; {</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nsITestPlugin * scriptablePeer =
new nsScriptablePeer();</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(scriptablePeer)</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // addref for ourself,
don't forget to release on shutdown to trigger its destruction</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NS_ADDREF(scriptablePeer);</tt>
<br><tt>&nbsp;&nbsp;&nbsp; }</tt>
<br><tt>&nbsp;&nbsp;&nbsp; // add reference for the caller requesting the
object</tt>
<br><tt>&nbsp;&nbsp;&nbsp; NS_ADDREF(scriptablePeer);</tt>
<br><tt>&nbsp;&nbsp; *(nsISupports **)value = scriptablePeer;</tt>
<br><tt>&nbsp; }</tt>
<br><tt>&nbsp; else if (variable == NPPVpluginScriptableIID)</tt>
<br><tt>&nbsp; {</tt>
<br><tt>&nbsp;&nbsp;&nbsp; nsIID* ptr = (nsIID *)NPN_MemAlloc(sizeof(nsIID));</tt>
<br><tt>&nbsp;&nbsp;&nbsp; *ptr = scriptableIID;</tt>
<br><tt>&nbsp;&nbsp;&nbsp; *(nsIID **)value = ptr;</tt>
<br><tt>&nbsp; }</tt>
<br><tt>&nbsp; return rv;</tt>
<br><tt>}</tt>
<br>&nbsp;
</body>
</html>