Building a firefox plugin – part three

August 4, 2009 201 Comments by Richard

Note: For a better way to create a Browser Plugin (that will work on all browsers, not just NPAPI), check out the FireBreath project.

Getting help: For a better place to ask NPAPI-related questions, go to StackOverflow and make sure to use the “npapi” and/or “firebreath” tags.

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:

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:

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 deallocate function, or free(). 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:

#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:

// 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:

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:

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:

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 part two and look at the plugin lifecycle, you’ll see on entry #5 that “Plugin creates a scriptable NPObject and returns a pointer to it (after calling 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:

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:

  1. HasMethod(NPIdentifier name);
  2. 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.

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:

    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:

    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

Building a firefox plugin – part four

Getting more help

Update May 14, 2011: Many people have been asking questions in the comments; while I don’t mind that, it would probably be more useful if you ask your question on the FireBreath forums. There is a forum there for those just using NPAPI as well!

49 Comments

  1. Kishore
    7 years ago

    Taxilan, Thanks for your quick response
    But for JS statement var obj1 = new MyObject();
    NP construct function only getting called.
    So i needed to implement it.
    I created NP object and assigned to result pointer which is passed as parameter.
    With that i am able to create multiple instances at the time of execution of JS.

    btw, Your posts about NPAPI are so informative. Keep up the good work.
    Cheers.

  2. Kishore
    7 years ago

    Taxilan, Thanks for your quick response
    But for JS statement var obj1 = new MyObject();
    NP construct function only getting called.
    So i needed to implement it.
    I created NP object and assigned to result pointer which is passed as parameter.
    With that i am able to create multiple instances at the time of execution of JS.

    btw, Your posts about NPAPI are so informative. Keep up the good work.
    Cheers.

  3. taxilian
    7 years ago

    If you want to do it that way, then yes, you'll need to implement the NPN_Construct function; personally I'd just use a method that acts as a constructor, because it's easier to support cross-browser.

    var obj1 = plugin.createMyObject();
    either way, though, creating the NPObject works the same.

  4. taxilian
    7 years ago

    If you want to do it that way, then yes, you'll need to implement the NPN_Construct function; personally I'd just use a method that acts as a constructor, because it's easier to support cross-browser.

    var obj1 = plugin.createMyObject();
    either way, though, creating the NPObject works the same.

  5. Varsha
    7 years ago

    Hi,

    I want to create plugin , in that there are two functions start timer and stop timer and I want to call these function from html buttob using javascript.

    I used npruntime as basic plugin, I have modified that plugin's getproperty method

    Code: Select all
    ScriptablePluginObject::GetProperty(NPIdentifier name, NPVariant *result)

    In that I checked
    int d;

    Code: Select all
    ScriptablePluginObject::GetProperty(NPIdentifier name, NPVariant *result)
    {
    if (name == sBar_id) //start timer
    {
    static int a = 17;
    d=SetTimer(NULL, 1, 1, (TIMERPROC) TimerProc);
    a=d;
    INT32_TO_NPVARIANT(a, *result);
    // a += 5;
    return true;
    }

    if (name == sFoo_id) //stop timer
    {
    static int a = 16;
    KillTimer(NULL,d);
    }
    }
    void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
    {
    capturewindow();
    }

    But using this if name=”bar” , then timer started , and if name=”foo” I want to stop timer.
    but I have one question is that what would be the handle for settimer because here I used NULL so, my timer never stop.

    please help me , How to stop timer?
    Is it there any optimized way to start and stop timer in plugin using JS function call.

    Regards
    Varsha

  6. Varsha
    7 years ago

    Hi,

    I want to create plugin , in that there are two functions start timer and stop timer and I want to call these function from html buttob using javascript.

    I used npruntime as basic plugin, I have modified that plugin's getproperty method

    Code: Select all
    ScriptablePluginObject::GetProperty(NPIdentifier name, NPVariant *result)

    In that I checked
    int d;

    Code: Select all
    ScriptablePluginObject::GetProperty(NPIdentifier name, NPVariant *result)
    {
    if (name == sBar_id) //start timer
    {
    static int a = 17;
    d=SetTimer(NULL, 1, 1, (TIMERPROC) TimerProc);
    a=d;
    INT32_TO_NPVARIANT(a, *result);
    // a += 5;
    return true;
    }

    if (name == sFoo_id) //stop timer
    {
    static int a = 16;
    KillTimer(NULL,d);
    }
    }
    void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
    {
    capturewindow();
    }

    But using this if name=”bar” , then timer started , and if name=”foo” I want to stop timer.
    but I have one question is that what would be the handle for settimer because here I used NULL so, my timer never stop.

    please help me , How to stop timer?
    Is it there any optimized way to start and stop timer in plugin using JS function call.

    Regards
    Varsha

  7. gf
    7 years ago

    For what you want to do, properties don't really fit. You should use methods (which are invoked), i.e. “startTimer” and “stopTimer”. “startTimer” could return a handle to the timer and “stopTimer” would take a handle as an argument.

    Alternatively you could use a scriptable object as a “Timer” property and provide “start” and “stop” methods for it.

  8. gf
    7 years ago

    For what you want to do, properties don't really fit. You should use methods (which are invoked), i.e. “startTimer” and “stopTimer”. “startTimer” could return a handle to the timer and “stopTimer” would take a handle as an argument.

    Alternatively you could use a scriptable object as a “Timer” property and provide “start” and “stop” methods for it.

  9. taxilian
    7 years ago

    Couple of comments:

    First, I second what gf said; you don't want to use properties, use methods. Properties don't make any sense. Then instead of using NULL as the handle, give it some sort of identifier.

    Second, do *not* use static variables for something like this; if there is more than one instance of your plugin it will cause you problems. Use a class variable.

    Third, if this timer is to interact with javascript at all, you want it tied to the window, not NULL. Then just use a UINT_PTR to identify it and it's easy to cancel. I say this a lot, but I recommend looking at FireBreath (http://firebreath.googlecode.com) for something like this because a lot of the dirty work is taken care of for you; you just have to make sure you don't try to start the timer before the window is set.

  10. taxilian
    7 years ago

    Couple of comments:

    First, I second what gf said; you don't want to use properties, use methods. Properties don't make any sense. Then instead of using NULL as the handle, give it some sort of identifier.

    Second, do *not* use static variables for something like this; if there is more than one instance of your plugin it will cause you problems. Use a class variable.

    Third, if this timer is to interact with javascript at all, you want it tied to the window, not NULL. Then just use a UINT_PTR to identify it and it's easy to cancel. I say this a lot, but I recommend looking at FireBreath (http://firebreath.googlecode.com) for something like this because a lot of the dirty work is taken care of for you; you just have to make sure you don't try to start the timer before the window is set.

  11. Navaid
    7 years ago

    Nice articles series. Would appreciate if you could give an example of how one would implement a property or method in the scriptable class (skeleton code). You have explained but an example would elucidate further.

  12. Navaid
    7 years ago

    Nice articles series. Would appreciate if you could give an example of how one would implement a property or method in the scriptable class (skeleton code). You have explained but an example would elucidate further.

  13. varsha
    7 years ago

    Hi,

    I have npruntime plugin which is working when I manully added npruntime.dll in mozilla/plugin folder.
    Now I want to install plugin when first time html page containing npruntime plugin open in browser.

    I searched on mozilla website, for plugin installation but I want example whch contains plugin installtion package like requuired
    xpt and xpi files.

    If any body has these files for npruntime plugin. Explain me code for same.

    I am confused about “How to create xpt file and xpi file?” or what would be the contents in these two files?

    Thanks & regards
    Varsha

  14. varsha
    7 years ago

    Hi,

    I have npruntime plugin which is working when I manully added npruntime.dll in mozilla/plugin folder.
    Now I want to install plugin when first time html page containing npruntime plugin open in browser.

    I searched on mozilla website, for plugin installation but I want example whch contains plugin installtion package like requuired
    xpt and xpi files.

    If any body has these files for npruntime plugin. Explain me code for same.

    I am confused about “How to create xpt file and xpi file?” or what would be the contents in these two files?

    Thanks & regards
    Varsha

  15. varsha
    7 years ago

    Hi,

    Thanks for reply.
    I fixed my problem using methods explained by u.

    Thanks and Regards
    Varsha

  16. varsha
    7 years ago

    Hi,

    Thanks for reply.
    I fixed my problem using methods explained by u.

    Thanks and Regards
    Varsha

  17. varsha
    7 years ago

    Hi

    Thanks for reply.
    Here you explained somthing about http://firebreath.googlecode.com
    but I sorry, I am not getting source of any sample plugin.
    Where is it available? Can u tell me abt it?

    Thanks & Regards
    Varsha

  18. varsha
    7 years ago

    Hi

    Thanks for reply.
    Here you explained somthing about http://firebreath.googlecode.com
    but I sorry, I am not getting source of any sample plugin.
    Where is it available? Can u tell me abt it?

    Thanks & Regards
    Varsha

  19. gf
    7 years ago

    Follow the instructions on “getting started” at the main page to get the source. If you got that, you can find two examples in the examples/ directory.
    Also take a look on how to create new plugin projects: http://code.google.com/p/firebreath/wiki/Creati

  20. gf
    7 years ago

    (Moved reply to where it should have been)

  21. taxilian
    7 years ago

    couple of oddities here; npruntime.dll? is that the name of your plugin? (if not, you don't need it) if so, it's a really bad name for a plugin dll, since it says nothing about who wrote the plugin and what it does =]

    I recommend against using xpi installers for plugins, since that makes the plugin only work on firefox. Check out https://developer.mozilla.org/en/Plugins/The_Fi

    xpt files are no longer neccesary for plugins. XPI files are outside the context of this blog (and I don't like them for plugins, and thus don't support them)

  22. taxilian
    7 years ago

    couple of oddities here; npruntime.dll? is that the name of your plugin? (if not, you don't need it) if so, it's a really bad name for a plugin dll, since it says nothing about who wrote the plugin and what it does =]

    I recommend against using xpi installers for plugins, since that makes the plugin only work on firefox. Check out https://developer.mozilla.org/en/Plugins/The_Fi

    xpt files are no longer neccesary for plugins. XPI files are outside the context of this blog (and I don't like them for plugins, and thus don't support them)

  23. gf
    7 years ago

    Follow the instructions on “getting started” at the main page to get the source. If you got that, you can find two examples in the examples/ directory.
    Alternatively browse the code online: http://code.google.com/p/firebreath/source/browse/.

    Also take a look on how to create new plugin projects: http://code.google.com/p/firebreath/wiki/Creati… and other wiki pages.

  24. gf
    7 years ago

    Follow the instructions on “getting started” at the main page to get the source. If you got that, you can find two examples in the examples/ directory.
    Alternatively browse the code online: http://code.google.com/p/firebreath/source/browse/.

    Also take a look on how to create new plugin projects: http://code.google.com/p/firebreath/wiki/Creati… and other wiki pages.

  25. Eric
    7 years ago

    Thanks so much Richard for this excellent post series. It clarified a lot of mysterious operation in the NPAPI plugin. I am still having trouble understanding how to work with the reference counting (I'm having one of those 'hard to track problems' you mentioned). Is there any resource describing what each function does to the reference count? Do you have any advice for coding to protect the plugin from degenerate reference counting from third-party code?

    Thanks again for the amazing posts! Hope you do some more

    Eric

  26. Eric
    7 years ago

    Thanks so much Richard for this excellent post series. It clarified a lot of mysterious operation in the NPAPI plugin. I am still having trouble understanding how to work with the reference counting (I'm having one of those 'hard to track problems' you mentioned). Is there any resource describing what each function does to the reference count? Do you have any advice for coding to protect the plugin from degenerate reference counting from third-party code?

    Thanks again for the amazing posts! Hope you do some more

    Eric

  27. taxilian
    7 years ago

    The best documentation out there is the documentation on the MDC:

    https://developer.mozilla.org/en/NPN_ReleaseObject
    https://developer.mozilla.org/en/NPN_RetainObject
    and
    https://developer.mozilla.org/en/NPN_CreateObject

    On the last one you'll note that when you create the object, the reference count is initialized to 1, so you don't need to do an initial retain; but if you call release without retaining, it will deallocate the object. I covered this in a little more detail here:
    http://colonelpanic.net/2009/12/memory-manageme

    Unfortunately, I and some friends of mine have encountered an issue where it seems that some browsers do not correctly reference count, which can cause objects you are using (that have been correctly retained) to go away at unexpected times; Safari 64 bit in particular has exhibited this bug. in this case, the only way we've found to deal with it is to do an extra retain, which will prevent those objects from getting destroyed during the lifetime of the page. this, as you can imagine, is both good and bad.

    It's a tricky problem.

  28. taxilian
    7 years ago

    The best documentation out there is the documentation on the MDC:

    https://developer.mozilla.org/en/NPN_ReleaseObject
    https://developer.mozilla.org/en/NPN_RetainObject
    and
    https://developer.mozilla.org/en/NPN_CreateObject

    On the last one you'll note that when you create the object, the reference count is initialized to 1, so you don't need to do an initial retain; but if you call release without retaining, it will deallocate the object. I covered this in a little more detail here:
    http://colonelpanic.net/2009/12/memory-manageme

    Unfortunately, I and some friends of mine have encountered an issue where it seems that some browsers do not correctly reference count, which can cause objects you are using (that have been correctly retained) to go away at unexpected times; Safari 64 bit in particular has exhibited this bug. in this case, the only way we've found to deal with it is to do an extra retain, which will prevent those objects from getting destroyed during the lifetime of the page. this, as you can imagine, is both good and bad.

    It's a tricky problem.

  29. Cristo
    7 years ago

    Hi, Taxilian, you posts are very informative and helpful. Thank you!
    I’m working on a plugin for Google Chrome and have to deal with registering/unregistering event listeners. I’ve encountered one strange (for me) problem – I can register event listener but can not unregister it… My test code looks like this:
    NPError NPP_New((/*args*/){

    NPObject * windowObject = NULL;
    NPN_GetValue(m_npp, NPNVWindowNPObject, &windowObject);

    NPVariant params[3];

    // arg0: event type
    STRINGZ_TO_NPVARIANT(“click”, params[0]);

    // arg1: listener
    params[1].type = NPVariantType_Object;
    params[1].value.objectValue =ScriptableObject::NewObject(npp);

    // arg2: useCapture
    params[2].type = NPVariantType_Bool;
    params[2].value.boolValue = true;

    NPIdentifier addEventListener_id = NPN_GetStringIdentifier(“addEventListener”);
    NPVariant result_add;
    // windowObject.addEventListener(“click”, listener, false);
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_add);

    NPIdentifier removeEventListener_id = NPN_GetStringIdentifier(“removeEventListener”);
    NPVariant result_remove;
    // windowObject.removeEventListener(“click”, listener, false);
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_remove);

    }
    All function invocations are successull, no run-time erros but nevertheless I still get handleEvent() invoked on params[1].value.objectValue NPObject when I click in window area… What could be wrong? Any ideas would be greatly appreciated.

    I’ve noticed that referenceCount of params[1].value.objectValue is incremented after NPN_Invoke(…addEventListener_id, …) and (!) after NPN_Invoke(…removeEventListener_id, …) – is it right?

  30. Cristo
    7 years ago

    Hi, Taxilian, you posts are very informative and helpful. Thank you!
    I’m working on a plugin for Google Chrome and have to deal with registering/unregistering event listeners. I’ve encountered one strange (for me) problem – I can register event listener but can not unregister it… My test code looks like this:
    NPError NPP_New((/*args*/){

    NPObject * windowObject = NULL;
    NPN_GetValue(m_npp, NPNVWindowNPObject, &windowObject);

    NPVariant params[3];

    // arg0: event type
    STRINGZ_TO_NPVARIANT(“click”, params[0]);

    // arg1: listener
    params[1].type = NPVariantType_Object;
    params[1].value.objectValue =ScriptableObject::NewObject(npp);

    // arg2: useCapture
    params[2].type = NPVariantType_Bool;
    params[2].value.boolValue = true;

    NPIdentifier addEventListener_id = NPN_GetStringIdentifier(“addEventListener”);
    NPVariant result_add;
    // windowObject.addEventListener(“click”, listener, false);
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_add);

    NPIdentifier removeEventListener_id = NPN_GetStringIdentifier(“removeEventListener”);
    NPVariant result_remove;
    // windowObject.removeEventListener(“click”, listener, false);
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_remove);

    }
    All function invocations are successull, no run-time erros but nevertheless I still get handleEvent() invoked on params[1].value.objectValue NPObject when I click in window area… What could be wrong? Any ideas would be greatly appreciated.

    I’ve noticed that referenceCount of params[1].value.objectValue is incremented after NPN_Invoke(…addEventListener_id, …) and (!) after NPN_Invoke(…removeEventListener_id, …) – is it right?

  31. Cristo
    7 years ago

    Ohh, of course I mean these calls:
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_add);

    NPN_Invoke(npp, windowObject, removeEventListener_id, &params[0], 3, &result_remove);

    And after it I'm still getting handeEvent() invoked… What could be wrong??
    Thank you in advance!

  32. Cristo
    7 years ago

    Ohh, of course I mean these calls:
    NPN_Invoke(npp, windowObject, addEventListener_id, &params[0], 3, &result_add);

    NPN_Invoke(npp, windowObject, removeEventListener_id, &params[0], 3, &result_remove);

    And after it I'm still getting handeEvent() invoked… What could be wrong??
    Thank you in advance!

  33. taxilian
    7 years ago

    Unfortunately, I've never tried attaching an event from the C side; I have never needed to. If the reference count gets decremented when you call removeEventListener then it should have released the object. This sounds very much like a browser bug; have you tried it on Safari or Firefox to see if it does the same thing there?

  34. Cristo
    7 years ago

    No, I have no experience with writing plugins for Firefox or Safari so I didn't try it on these browsers.
    Today I have found another problem – sometimes NPN_Invoke(…, removeEventListeners_id, …) returns false (and doesn't increment referenceCount of handler-NPObject. In this case it looks right though). Well… I have no idea why things go these ways…

  35. varsha
    7 years ago

    Hi,

    In my plugin I want to create new thread .

    In HTML page i have html button on that button click I called plugin method.

    On that plugin method, I created new thread using “_beginthreadex” and in threadproc callback I called method which is from C library
    but that method does not return anything to me.

    When I clicked on HTML button my firefox crashed. why is it happened?

    Basically, C library function in it s gives me char array of images and I want to display that images in plugin window.
    For that in callback function I want to convert image char array into HBITMAP and call
    InvalidateRect(m_hWnd, NULL, TRUE);
    UpdateWindow(m_hWnd)

    But my C library function
    like this

    void (*callbackDisplayData)(void * , OneirixSVReceiver *) = DisplayData;

    ppobj = (OneirixSVReceiver **) malloc(sizeof(OneirixSVReceiver *));

    char pimg = (char*)malloc(dispWidth * dispHeight * 3 * sizeof(char));

    objenum=OneirixSVReceiverSetup(ppobj,server_ip_address,1500,1600,dispWidth,dispHeight,pimg, NULL,callbackDisplayData);

    DisplayData is the callback function which is called from c library and OneirixSVReceiverSetup is the function that does not gives me any response so my firefox goes in hang mode.

    For that I have created one thread and in threadrpc of that I have called OneirixSVReceiverSetup .
    http://forums.mozillazine.org/posting.php?mode=
    But after that my firefox crashed.

    Is this because of thread? can We create thread in plugin?
    Can you provide me any sample source code for create new thread in plugin.

    Thanks & Regards
    Varsha

  36. taxilian
    7 years ago

    To answer most of your question, no, I can't give you source code to do threading stuff; all of my plugin source code that can be given away is in FireBreath: http://firebreath.googlecode.com

    we haven't yet added threading libraries to it.

    However, I will tell you that the main trick with threads is that you can't call any NPN_ functions from any thread other than the main one. If you're crashing, and it's browser related (try your thread code in a seperate application), then it's most likely due to that.

  37. varsha
    7 years ago

    Hi,

    My Threading cod working in nomal win32 appliation.
    From Js function I called plugin function display() i.e. invoke method.
    On that function, I have created new thread using “_beginthreadex” and in threadproc callback I called method which is from C library. No call for NPN_ functions from that thread callback.

    Can you tell me “_ NPN_PluginThreadAsyncCall” about this is it useful for threading in plugin. You have any idea about “can we create thread in plugin?”

    Thanks & Regards
    Varsha

  38. taxilian
    7 years ago

    NPN_PluginThreadAsyncCall can be used to schedule a single function call on the main thread, which can be used to call other NPN_ functions from other threads. It is asynchronous.

    Keep in mind that you can't interact with your plugin's window from other threads either; the window needs to always be dealt with on the main thread.

  39. varsha
    7 years ago

    Hi,

    In my npruntime plugin, We are displaying bitmap images continuously, But when I scroll the scrollbar window getting refreshed i.e.
    repainted.
    How to stop this?
    Is it any setting, to take decision to update window or not.

    Thanks
    Varsha

  40. taxilian
    7 years ago

    You can't stop this; when you scroll the browser window, it repaints itself; over the top of your plugin. The correct way to deal with this is to respond to the paint message and redraw whatever you have so that it doesn't disappear.

    This is standard with any windows program; some frameworks just hide it. The way a windowed plugin works, there is no way to do this.

  41. varsha
    7 years ago

    Hi,

    Thanks for reply.

    Can you tell me, is it plugin windows WM_VSCROLL or WM_HSCROLL message fired on browser window scroll.

    If not, Where can I send redraw plugin window.

    Thanks & Regards
    Varsha

  42. taxilian
    7 years ago

    Well, my recomendation would be to *try it*, and *find out*. However, consider that it's not the plugin's window that is scrolling, so it seems unlikely that those events will be sent.

    Also, as in *any* windows application (you have your own window, so it all works about the same), you redraw the plugin window when the operating system tells you to — when you get the WM_PAINT message.

  43. Rashmi
    7 years ago

    Hi,

    I have an NPObjectExtended object where I need to return an array of numbers/structure. How can I do this?

  44. taxilian
    7 years ago

    You could:
    * Use FireBreath
    * Create an NPObject that pretends to be an array
    * Call window.array() from your plugin (on the main thread) to get an array and then set the values on that.

    If you want to use one of the last two options, these links will help you:
    * http://stackoverflow.com/questions/1896166/npva
    * http://groups.google.com/group/mozilla.dev.tech
    * http://groups.google.com/group/mozilla.dev.tech

  45. amar4kintu
    7 years ago

    Hello taxilian,

    I am new to plugin development and I want to create an image editing plugin which should be compatible to almost all browsers of all Operating System.
    I read your posts for plugin developments and it seems fine for someone to get started.

    while searching for help on google I came across following link, which says that using there framework we can achieve browser compatible plugin. You can go through it once, if It can help you achieving your goal.

    http://qt.nokia.com/doc/solutions/4/qtbrowserpl

    Though I do not know much about it.

    I am currently learning to create basic plugin using firebreath as there are steps given to get started and create dll of plugin.

    I have one question regarding dll generation. I am using windows server 2003 as OS.

    Is it necessary to have Visual Studio installed to generate dll?

    Is there any other way we can do it? I am using Ecliplse ide for PHP and Java? Is it possible with eclipse?

    Just wanted to know that.

    Thanks for your article and help.

    Amar

  46. taxilian
    7 years ago

    Thanks for the link; interesting. I believe that Nokia has added some non-standard extensions to their NPAPI, so if you're developing for one of the devices that use it that's probably not a bad way to go.

    The best place to ask questions about FireBreath is the firebreath users group, http://groups.google.com/group/firebreath-dev/. I recommend addressing future questions there.

    There is not currently another way to compile a plugin on windows with FireBreath other than Visual Studio. The reason for this is that the ActiveX (IE) side of FireBreath relies heavily on ATL, which is only available with Visual Studio.

  47. amar4kintu
    7 years ago

    Hello Taxilian,

    Thanks for the answer. I have joined the group firebreath-dev on google groups. So I will discuss my further problems there.

    Thanks.

    Amar4Kintu

  48. Navaid
    7 years ago

    Your second last para is unclear. When you say 'array of NPObjects' don't you mean 'array of NPVariants'? Also, what do you mean by 'saved npobjects' – NPObjects saved during addEventListener?

    If there are multiple functions in the event sink on JS side, how will they arrive in addEventListener e.g.

    var EventSink =
    {
    foo1 : function(x, y)
    {
    // ..
    },
    foo2 : function(url)
    {
    // ..
    },
    };
    pluginObj.addEventListener(EventSink)

    Where can I find the prototype of addEventListener/removeEventListener? Does it have anything to do with nsIDOMEventTarget? That's what keeps coming in the searches? Is that XPCOM?

    I think we could do with a detailed article on this as you indicated :)

  49. Guybrush
    7 years ago

    Can anyone describe the difference between Plug-in entry points (NPP_*) and Netscape Entry Points (NPN_*) ? To me it seems that plugin entry points are all functionality that deal with creation and querying status of the plugin. and Netscape entry points all those that have to do with the plugin executing its core exposed functionality.

One Trackback

  1. By ColonelPanic » Memory management in NPAPI on March 9, 2010 at 2:37 pm

    […] that are used by the browser to pass information.  NPObjects are, for those who haven’t read my previous post on NPAPI, the basic datatype for anything that is scriptable — that is, javascript objects and objects […]

Post a Comment

Your email is never published or shared. Required fields are marked *