Building a firefox plugin – part three
Note: if you haven’t already, please read up on FireBreath, the open source cross-platform plugin framework, and consider contributing.
Previous posts
The purpose of this post is to cover the basics of providing an interface by which javascript can interface with an NPAPI plugin in a cross platform manner. The primary focus of this post will be on npruntime, which is recommended by the Mozilla development team (or at least seems to be from the meager and confusing documentation available from Mozilla). More importantly, of course, it is the framework that I recommend, which is all-important, since I’m the one writing this post. =]
Previous posts
If you are new to NPAPI plugins, you may want to go back and read part one and part two of this series, which cover the basic architecture and lifecycle of an NPAPI plugin.
What is npruntime?
I’m so glad you ask. This confused the daylights out of me when I first got into building browser plugins; there are references to XPCOM and references to LiveConnect and references to NPRuntime, which I never did quite get straightened out until I ran into a Wikipedia article on NPAPI. I recommend that you read it if you want further background information.
Beyond the simple question of “what is recommended?” is the consideration of practical needs. For me, the primary considerations that led me to decide that NPRuntimeis the only mechanism that should be used on any new plugin are:
- NPRuntime allows dynamic interfaces — more on this, and why it is useful, later
- NPRuntime is the plugin scripting standard supported by Mac Plugins, Safari (even on windows), Chrome, and Opera. My goal is always to make things as cross-platform as possible.
- Firefox 3.6 drops support for XPCOM plugins (e.g. xpt file scripting interfaces aren’t recognized)
Getting Started
Throughout this post, I will be referring to Scriptable Objects a lot. A Scriptable Object is simply an object that can be “scripted”, or accessed and used by javascript. In firefox, a Scriptable Object is always a NPObject:
1 2 3 4 5 6 7 | struct NPObject { NPClass *_class; uint32_t referenceCount; /* * Additional space may be allocated here by types of NPObjects */ }; |
As you can see, a NPObject is nothing more than a reference counted object with a pointer to a NPClass. As of the latest (as of this writing) Gecko SDK, 1.9, NPClass is defined as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct NPClass { uint32_t structVersion; // Version of the structure (to determine which features may be missing) NPAllocateFunctionPtr allocate; // Called to create a new instance of this object NPDeallocateFunctionPtr deallocate; // Called to free the instance of this object NPInvalidateFunctionPtr invalidate; // Called on live objects that belong to a plugin instance that is being destroyed. This call is always followed by a call to the <code>deallocate</code> function, or <code>free()</code>. Any attempt to use an invalidated object will result in undefined behavior. NPHasMethodFunctionPtr hasMethod; // Called to query if a method exists on the NPObject NPInvokeFunctionPtr invoke; // Used to invoke a method on the NPObject NPInvokeDefaultFunctionPtr invokeDefault; // Used to invoke the NPObject as a function NPHasPropertyFunctionPtr hasProperty; // Called to query if a property exists on the NPObject NPGetPropertyFunctionPtr getProperty; // Called to get the value of a property on the NPObject NPSetPropertyFunctionPtr setProperty; // Called to set the value of a property on the NPObject NPRemovePropertyFunctionPtr removeProperty; // Called to remove/delete a property on the NPObject NPEnumerationFunctionPtr enumerate; // Used to get a list of properties and methods that exist on the NPObject (new in FF 3, Gecko SDK 1.9) NPConstructFunctionPtr construct; // Used when the new keyword is called in javascript to create a new instance of the NPObject (new in FF 3, Gecko SDK 1.9) }; |
Making it Object Oriented
The Gecko SDK is intentionally written to use structs instead of objects; this allows it to work across many platforms, with many different types of compilers, and never worry about binary compatibility. If you haven’t figured it out yet, the NPClass structure contains a list of function pointers that should be called by the browser (or anyone else) to talk to the NPObject. These should never be called explicitly, but rather they should be called through the NPN_ functions that I briefly mentioned towards the end of part one. When one wishes to create a new instance of an NPObject, you call the NPN_CreateObject function and give it the class that should be used.
Fortunately, since all the browser cares about is the NPClass, its function pointers, and the reference count, any class that inherits from NPObject can easily satisfy that requirement; that means that it is not difficult to make a smart NPObject; simply create static methods for each of the pointers in the NPClass struct, dereference the NPObject* that they pass in, and call a member function.
Simple class definition and implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include "npapi.h" #include "npupp.h" class MyScriptableNPObject : public NPObject { protected: // Class member functions that do the real work void Deallocate(); void Invalidate(); bool HasMethod(NPIdentifier name); bool Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); bool InvokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result); bool HasProperty(NPIdentifier name); bool GetProperty(NPIdentifier name, NPVariant *result); bool SetProperty(NPIdentifier name, const NPVariant *value); bool RemoveProperty(NPIdentifier name); bool Enumerate(NPIdentifier **identifier, uint32_t *count); bool Construct(const NPVariant *args, uint32_t argCount, NPVariant *result); public: // This is the method used to create the NPObject // This method should not be called explicitly // Instead, use NPN_CreateObject static NPObject* Allocate(NPP npp, NPClass *aClass) { return (NPObject *)new MyScriptableNPObject(npp); } ///////////////////////////// // Static NPObject methods // ///////////////////////////// static void _Deallocate(NPObject *npobj); static void _Invalidate(NPObject *npobj); static bool _HasMethod(NPObject *npobj, NPIdentifier name); static bool _Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); static bool _InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); static bool _HasProperty(NPObject * npobj, NPIdentifier name); static bool _GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result); static bool _SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); static bool _RemoveProperty(NPObject *npobj, NPIdentifier name); static bool _Enumerate(NPObject *npobj, NPIdentifier **identifier, uint32_t *count); static bool _Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); static NPClass _npclass; protected: NPP m_Instance; }; |
Due to code ownership issues, I’m not able to give you the actual code that I’m using, but if there are any compiler errors I’m sure they’ll be simple to straighten out. The implementation for these static members will be pretty straightforward:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // static void MyScriptableNPObject::_Invalidate(NPObject *obj) { ((MyScriptableNPObject*)obj)->Invalidate(); } void MyScriptableNPObject::Invalidate() { // Invalidate the control however you wish } // static void MyScriptableNPObject::_Deallocate(NPObject *obj) { ((MyScriptableNPObject*)obj)->Deallocate(); delete ((MyScriptableNPObject*)obj); } void MyScriptableNPObject::Deallocate() { // Do any cleanup needed } |
For brevity, I’m not going to include all of the methods here; I will go into more detail on them later. For now, suffice it to say that after you have implemented the rest of these functions, all that is left is to define the NPClass itself:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | NPClass MyScriptableNPObject::_npclass = { NP_CLASS_STRUCT_VERSION, MyScriptableNPObject::Allocate, MyScriptableNPObject::_Deallocate, MyScriptableNPObject::_Invalidate, MyScriptableNPObject::_HasMethod, MyScriptableNPObject::_Invoke, MyScriptableNPObject::_InvokeDefault, MyScriptableNPObject::_HasProperty, MyScriptableNPObject::_GetProperty, MyScriptableNPObject::_SetProperty, MyScriptableNPObject::_RemoveProperty, MyScriptableNPObject::_Enumerate, MyScriptableNPObject::_Construct }; |
Creating the NPObject
Once you have your custom NPObject created and your NPClass defined, we can cover the basics of the NPObject lifecycle. Creating an NPObject is pretty straightforward:
1 2 | NPObject *newObj = NPN_CreateObject(m_Instance, &MyScriptableNPObject::_npclass); NPN_RetainObject(newObj); |
As you can see, all that is needed is the NPP instance handler (see part two) and a pointer to the class. Since the class is very specific to a specific NPObject, I like to create a static function to instantiate the object, like so:
1 2 3 4 | static MyScriptableNPObject* NewObject(NPP npp) { MyScriptableNPObject* newObj = (MyScriptableNPObject*)NPN_CreateObject(npp, &_npclass); return newObj; } |
This is completely voluntary, of course, but it also allows you some additional control of the creation process; for example, you may want to pass in additional parameters and have them set on the object as soon as it is created.
NPObject lifecycle
As you might guess, NPN_RetainObject increments the reference count on a given NPObject. Similarly, NPN_ReleaseObject decrements the reference count. When the reference count hits zero, the object will be destroyed by calling the specified Deallocate function, just like the Allocate function is called by NPN_CreateObject to create the object.
When code in one DLL allocates something and it is deallocated by a different DLL, heap corruption can (and often does) occur. For this reason, all things that belong to you will ultimately get created and destroyed in your code. All things that belong to the browser will get created and freed in browser code. This way everyone stays happy =] Make sure you keep track of your Retains and Releases; just like any reference counting, this can cause you a lot of hard to track problems.
Another important thing to keep in mind about the lifecycle of a NPObject is that you don’t know exactly when it will go away; the browser will release it whenever it chooses to do so. Therefore, you need to be able to handle things gracefully even if things are destroyed in a different order than you expect.
Giving the correct NPObject to the browser
Now that you know what an NPObject is and rougly what it does, you need to know how the browser finds out about it. If you’ll refer back to NPN_RetainObject on it.)” Simply put, at that point in the initialization sequence (or somewhere in there; the spec is ambiguous about the order), the Browser will call GetValue on the plugin and ask for a NPObject. If our plugin supports NPObjects, it simply needs to create one, call NPN_RetainObject on it, and return it as a void pointer. *NOTE: Make sure that you typecast it as a NPObject* before assigning it to the void pointer; I made that mistake once and spent a week trying to figure out why the wrong functions were getting called.
Here is an example implementation of GetValue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | NPError PluginInstance::NpapiGetValue(NPPVariable variable, void *value) { NPError rv = NPERR_NO_ERROR; switch(variable) { case NPPVpluginNameString: value = *((char **)value) = STRINGS_PRODUCTNAME; break; case NPPVpluginDescriptionString: // Plugin description *((char **)value) = STRINGS_FILEDESCRIPTION; break; case NPPVpluginScriptableNPObject:// Scriptable plugin interface (for accessing from javascript) *(NPObject **)value = this->getScriptableObject(); break; case NPPVpluginWindowBool: *((PRBool *)value) = this->isWindowed; break; default: rv = NPERR_GENERIC_ERROR; } return rv; } NPObject *PluginInstance::getScriptableObject() { NPObject *retval; if (this->npobj != NULL) retval = (NPObject *)this->npobj; else retval = (NPObject *)MyScriptableNPObject::NewObject(this->npp); NPN_RetainObject(retval); return retval; } |
HasMethod and HasProperty
On to the meat of the article: Say you have a javascript function like so:
var objTag = document.getElementById("myObjectTag");
alert(objTag.doSomeCoolFunction);
You may think that this looks a little strange, since “doSomeCoolFunction” sounds like a function call, but it is clearly accessed like a parameter here. In Javascript, this is legal even if that is a function, because it can be used to determine if a function exists without calling it. Therefore, you cannot have a method and a property on the same object with the same name.
When this call is made, the browser will call two functions on the NPObject:
- HasMethod(NPIdentifier name);
- HasProperty(NPIdentifier name);
The purpose of these two calls is to ascertain whether or not a property or method exists on the NPObject (as you might have guessed). So, what is with this NPIdentifier thing? Well, a NPIdentifier can map to either an integer or a string. a NPIdentifier can be converted to a string (if it is a string identifier) with NPN_UTF8FromIdentifier. To find out if it is a string identifier, use NPN_IdentifierIsString. If it is an integer, you can use NPN_IntFromIdentifier.
Now, the purpose of integer identifiers may not be immediately apparent to everyone; it wasn’t to me at first. Once I figured it out, however, I was thrilled. If you are familiar with javascript, you are doubtlessly familiar with the concept that everything in javascript is an object; arrays are actually just objects with integer keys. So, to allow array-style access, simply handle integer identifiers!
Once you have converted the identifier into something you can deal with, decide if your object has that property or method (I’ll let you figure out which goes in which function) and return true or false.
Oh, and after you get a string wtih NPN_UTF8FromIdentifier, don’t forget to release the memory with NPN_MemFree().
NPVariant
Before I go any further, I need to spend a brief paragraph or two on the NPVariant structure.
1 2 3 4 5 6 7 8 9 10 | typedef struct _NPVariant { NPVariantType type; union { bool boolValue; int32_t intValue; double_t doubleValue; NPString stringValue; NPObject *objectValue; } value; } NPVariant; |
NPVariant is the datatype used by the browser to pass variables into and out of NPObjects. From the MDC docs, the following types are valid:
| JavaScript type | NPVariantType |
|---|---|
undefined |
NPVariantType_Void |
null |
NPVariantType_Null |
boolean |
NPVariantType_Bool |
number |
NPVariantType_Int32 or NPVariantType_Double |
string |
NPVariantType_String |
| All other types | NPVariantType_Object |
Since it’s getting late and I’ve already put too much in this post (I’m over 2000 words), I’ll leave it as an excercise to the reader to read up on the macros and such for using this structure.
Properties
At this point, you should be getting a pretty good idea of how everything works. Getting and setting properties is fairly straightforward:
1 2 | bool GetProperty(NPIdentifier name, NPVariant *result); bool SetProperty(NPIdentifier name, const NPVariant *value); |
To get a property, simply check the name to see what you’re going to be doing and store the value to return in *result. If the operation succeeds, you should return true. If not, false.
To set a property, again check the name to see which property you’re working with and save the value of the NPVariant parameter however you wish. Again, return true if success, false if failure.
Methods
Methods aren’t much more difficult. The only real difference is that now you have parameters to worry about. No problem! Parameters are passed in as an array of NPVariants:
1 2 | bool Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); bool InvokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result); |
The difference between Invoke and InvokeDefault is that InvokeDefault does not ever have an identifier. If you call “objTag.funcName()” Invoke gets called; if you call “objTag()”, then InvokeDefault gets called.
As with properties, store the return value in the pointer given in the last argument and handle the other arguments however you wish.
Wrapping it up
Alright, I know I haven’t covered everything, but this is already too long. If you have specific questions, ask them in the comments and I’ll do my best to answer; the comments may determine the direction of my next post.
Since dealing with the NPIdentifiers can get to be such a pain, I recommend using a map or hashtable to store structures with function pointers to map a string name to functions to handle it; that way you don’t end up with giant if/then or case statements, and everything ends up being much cleaner.
Another idea for the adventuresome: abstract the actual logic (properties and methods) into another object that can be wrapped with your NPObject class, and then make another wrapper class that implements IDispatch so that your scriptable objects are cross platform (IDispatch objects are scriptable on Internet Explorer).
Good luck!
Building a firefox plugin – part one
Building a firefox plugin – part two
Building a firefox plugin – part three

The process you describe calling window.Object() to get an NPObject and then using SetProperty to set my_var on that, then using window.Array() to get an NPObject array and then using SetProperty to add elements to that, etc works just fine. FireBreath uses this methodology to return objects and arrays to javascript.
The process you describe calling window.Object() to get an NPObject and then using SetProperty to set my_var on that, then using window.Array() to get an NPObject array and then using SetProperty to add elements to that, etc works just fine. FireBreath uses this methodology to return objects and arrays to javascript.
Thank you taxilian! That is going to work beautifully :-)
Now, I just need to figure out how to do it in COM.
- Glauco
In COM you do it the same way. Of course, you could save yourself a heck of a lot of time and just use FireBreath, where I’ve already solved that problem in a ridiculously easy to use way.
Or, if you’re determined to do it yourself, you can look at the FireBreath code for an example: to set a property on an array (which will be an IDispatchEx object): http://code.google.com/p/firebreath/source/browse/src/ActiveXPlugin/IDispatchAPI.cpp
look at http://code.google.com/p/firebreath/source/browse/src/ActiveXPlugin/FBControl.h for an example of getting a reference to the window / document.
Yes – FireBreath is pretty cool and I’ve been checking the code a lot and it’s definitely a really nice framework. But, this is my first experience with browser plug-ins and I think to fully appreciate the framework, I need to go through the pains at least once :-)
Thanks to your help and this tutorial, I got almost everything figure out however, I have one more issue. When, in the JavaScript, I put alert(e.array[0]) I see a coma (,) – is this garbage? Only if I do alert(e.array[1]) then I actually see what I pushed from the c++ code.
I’m sure it’s something silly but I can’t see it. I’ve pasted below the main steps in the code where I fill the array. Do you see anything wrong?
// To create the array
arrayObj->GetDispID(SysAllocString(CA2W(“Array”)),
fdexNameEnsure | fdexNameCaseSensitive | 0×10000000, &dispId);
arrayObj->InvokeEx(dispId, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL, NULL);
// Push elements to array
arrayObj->GetDispID(SysAllocString(CA2W(“push”)),
fdexNameEnsure | fdexNameCaseSensitive | 0×10000000, &dispId);
VARIANT arg, result;
DISPPARAMS params = {0};
VariantInit(&arg);
VariantInit(&result);
arg.vt = VT_I2;
arg.iVal = 4; // first element of the array
params.rgvarg = &arg;
params.rgdispidNamedArgs = 0;
params.cArgs = 1;
params.cNamedArgs = 0;
hr = arrayObj->InvokeEx(dispId, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL, NULL);
Hard to say for sure, but if your code is a direct quote, you have a problem. You could be getting the dispid from the window object, then invoking Array on the window object. You should then be getting the result and getting the dispid of push from the array object.
Firebreath does this and it works exactly as you would expect; if you have more than 1 item on the array when only calling push once, something is wrong.
Yes, I’m careful to not mix these variables when calling the various methods.
Something strange that I’ve noticed is that,when I create the array, if I also add into the variant the first element of the array (so, the variant has two arguments: arg[0].vt = VT_DISPATH, arg[0].pdispVal = NULL; arg[1].vt = VT_BSTR, arg[1].bstrValue = “test”), then e.array[0] is equal to something…..only to “t” :-(
Does this ring any bell to you?
not particularly; I haven’t ever seen the problem you describe. I can’t reproduce it using the FireBreath code, so I’m not sure what would be going on. If you want you could email me the code and I could look at it, but it might be a few days before I could find time to look into it; I’m in the process of wrapping up one project and will be starting another one next week.