firefoxpluginsnpapi

How can I associate a scriptable Mozilla plugin instance with its NObject?


I'm running into a problem associating an invoked method in a plugin I'm writing with the appropriate plugin instance. The documentation at http://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins doesn't give enough information to be truly useful on this.

In a nutshell, I'm trying to understand just which scriptable object the plugin is expected to return in response to a call to NPP_GetValue with the variable argument equal to NPPpluginScriptableNPObject. I'm guessing that there should be an NPObject instance for each instance of the plugin, but how is the invoke() method in the NPClass supposed to find the plugin instance (NPP) from the scriptable NPObject it's given as an argument? I suppose I could implement a lookup table to do that, but I have the feeling there's something obvious I'm missing.

I'm storing a pointer to an instance of a C++ class (the instance implements the functionality of the plugin) in the pdata member of the NPP, in NPP_New().


Solution

  • I guess I'm answering my own question...

    The solution I found (and I would still appreciate comments on its validity, especially if you think there's a better way of doing it) was to allocate an NPObject derived structure which has a pointer to my implementation class in the allocate() function I expose to Firefox from my plugin. I then store a pointer to that NPObject in the NPP's pdata member, in NPP_New().

    In invoke(), I cast the NPObject pointer I get to the derived structure's additional members, so that I can get a pointer to the instance of the implementation class.

    That, as far as I can tell, is the intent of the design - NPObject objects are instances of the NPClass they point to, they implement methods and properties through the NPClass function pointers that deal with these entities, and any private data is expected to be allocated and deallocated by the implementation, and its format is unspecified.

    It would look something like this:

     static NPClass refObject = {
        NP_CLASS_STRUCT_VERSION,
        My_Allocate,
        My_Deallocate,
        NULL,
        My_HasMethod,
        My_Invoke,
        My_InvokeDefault,
        My_HasProperty,
        My_GetProperty,
        NULL,
        NULL,
    };
    
    class MyImplClass {
        // Implementation goes here
    };
    
    struct MyNPObject : public NPObject {
        MyImplClass *my_impl_instance;
    };
    
    // This is just a bit of memory management - Mozilla wants us to allocate our own memory:
    NPObject *My_Allocate(NPP inst, NPClass *)
    {
        // We initialize the structure in NPP_New() below
        return (NPObject *)malloc(sizeof(MyNPObject));
    }
    
    NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
                 char* argn[], char* argv[], NPSavedData* saved )
    {
        NPObject *scriptable_object = npnfuncs->createobject(instance, &refObject);
        npnfuncs->retainobject(scriptable_object);
        MyImplClass *new_player = new MyImplClass(); 
    
        instance->pdata = scriptable_object;
        ((MyNPObject*)instance->pdata)->my_impl_instance = new_player;
        return NPERR_NO_ERROR;
    

    }