mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-11 02:10:17 +01:00
221 lines
11 KiB
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>
|
||
|
Basically, this means that in order to use and take full advantage of this
|
||
|
new API, which is interface-based, 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> NPPVpluginScriptableInstance = 10,</tt>
|
||
|
<br><tt> NPPVpluginScriptableIID =
|
||
|
11</tt>
|
||
|
<p>and two analogous additions to nsPluginInstanceVariable type in nsplugindefs.h
|
||
|
as
|
||
|
<p><tt> nsPluginInstanceVariable_ScriptableInstance = 10,</tt>
|
||
|
<br><tt> nsPluginInstanceVariable_ScriptableIID
|
||
|
= 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><embed type="application/plugin-mimetype"></tt>
|
||
|
<br><tt><script></tt>
|
||
|
<br><tt>var embed = document.embeds[0];</tt>
|
||
|
<br><tt>embed.nativeMethod();</tt>
|
||
|
<br><tt></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>
|
||
|
<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> 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>
|
||
|
public nsISecurityCheckedComponent</tt>
|
||
|
<br><tt>{</tt>
|
||
|
<br><tt>public:</tt>
|
||
|
<br><tt> nsScriptablePeer();</tt>
|
||
|
<br><tt> ~nsScriptablePeer();</tt>
|
||
|
<p><tt> NS_DECL_ISUPPORTS</tt>
|
||
|
<br><tt> NS_DECL_NSITESTPLUGIN</tt>
|
||
|
<br><tt> NS_DECL_NSISECURITYCHECKEDCOMPONENT</tt>
|
||
|
<br><tt>};</tt>
|
||
|
<p><tt>nsScriptablePeer::nsScriptablePeer()</tt>
|
||
|
<br><tt>{</tt>
|
||
|
<br><tt> 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> return NS_OK;</tt>
|
||
|
<br><tt>}</tt>
|
||
|
<p><tt>// the purpose of the rest of the code is to get succesfully</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> if (!_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_NULL_POINTER;</tt>
|
||
|
<br><tt> *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
|
||
|
<br><tt> if (!*_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_OUT_OF_MEMORY;</tt>
|
||
|
<br><tt> strcpy(*_retval, gAllAccess);</tt>
|
||
|
<br><tt> 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> if (!_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_NULL_POINTER;</tt>
|
||
|
<br><tt> *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
|
||
|
<br><tt> if (!*_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_OUT_OF_MEMORY;</tt>
|
||
|
<br><tt> strcpy(*_retval, gAllAccess);</tt>
|
||
|
<br><tt> 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> if (!_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_NULL_POINTER;</tt>
|
||
|
<br><tt> *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
|
||
|
<br><tt> if (!*_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_OUT_OF_MEMORY;</tt>
|
||
|
<br><tt> strcpy(*_retval, gAllAccess);</tt>
|
||
|
<br><tt> 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> if (!_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_NULL_POINTER;</tt>
|
||
|
<br><tt> *_retval = (char*)NPN_MemAlloc(sizeof(gAllAccess)+1);</tt>
|
||
|
<br><tt> if (!*_retval)</tt>
|
||
|
<br><tt> return NS_ERROR_OUT_OF_MEMORY;</tt>
|
||
|
<br><tt> strcpy(*_retval, gAllAccess);</tt>
|
||
|
<br><tt> 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> if(instance == NULL)</tt>
|
||
|
<br><tt> return NPERR_INVALID_INSTANCE_ERROR;</tt>
|
||
|
<p><tt> NPError rv = NPERR_NO_ERROR;</tt>
|
||
|
<br><tt> static nsIID scriptableIID = NS_ITESTPLUGIN_IID;</tt>
|
||
|
<p><tt> if (variable == NPPVpluginScriptableInstance)</tt>
|
||
|
<br><tt> {</tt>
|
||
|
<br><tt> if (this is first time and we haven't created
|
||
|
it yet)</tt>
|
||
|
<br><tt> {</tt>
|
||
|
<br><tt> nsITestPlugin * scriptablePeer =
|
||
|
new nsScriptablePeer();</tt>
|
||
|
<br><tt> if(scriptablePeer)</tt>
|
||
|
<br><tt> // addref for ourself,
|
||
|
don't forget to release on shutdown to trigger its destruction</tt>
|
||
|
<br><tt> NS_ADDREF(scriptablePeer);</tt>
|
||
|
<br><tt> }</tt>
|
||
|
<br><tt> // add reference for the caller requesting the
|
||
|
object</tt>
|
||
|
<br><tt> NS_ADDREF(scriptablePeer);</tt>
|
||
|
<br><tt> *(nsISupports **)value = scriptablePeer;</tt>
|
||
|
<br><tt> }</tt>
|
||
|
<br><tt> else if (variable == NPPVpluginScriptableIID)</tt>
|
||
|
<br><tt> {</tt>
|
||
|
<br><tt> nsIID* ptr = (nsIID *)NPN_MemAlloc(sizeof(nsIID));</tt>
|
||
|
<br><tt> *ptr = scriptableIID;</tt>
|
||
|
<br><tt> *(nsIID **)value = ptr;</tt>
|
||
|
<br><tt> }</tt>
|
||
|
<br><tt> return rv;</tt>
|
||
|
<br><tt>}</tt>
|
||
|
<br>
|
||
|
</body>
|
||
|
</html>
|