Articles

Navigation ( archives ›› 2010 ›› October ›› 21 ›› How to communicate back to JavaScript from NPAPI plugin )

How to communicate back to JavaScript from NPAPI plugin

Posted on October 21, 2010, 8:18 pm EST

I might be a bit late learning plugin development for the browser, but I really wanted to know how to create a plugin. It turned out to be such an easy task and awesome framework. You can do a lot with NPAPI, and the cool thing about it is the ability to let your C++ code communicate back to the JavaScript world easily.

How to send a debug message to the browsers console

The best way to teach someone how to send a message back to the browser is with an example. Afterwards, I will explain each step in detail. So here is the JavaScript code that we want to call from our C++ plugin:

   console.debug("Hello from C++");
 

The equivalent C++ code for the above JavaScript would be the following:

  // The message we want to send.
  char* message = "Hello from C++";
  
  // Get window object.
  NPObject* window = NULL;
  NPN_GetValue(npp_, NPNVWindowNPObject, &window);

  // Get console object.
  NPVariant consoleVar;
  NPIdentifier id = NPN_GetStringIdentifier("console");
  NPN_GetProperty(npp_, window, id, &consoleVar);
  NPObject* console = NPVARIANT_TO_OBJECT(consoleVar);

  // Get the debug object.
  id = NPN_GetStringIdentifier("debug");

  // Invoke the call with the message!
  NPVariant type;
  STRINGZ_TO_NPVARIANT(message, type);
  NPVariant args[] = { type };
  NPVariant voidResponse;
  NPN_Invoke(npp_, console, id, args,
             sizeof(args) / sizeof(args[0]),
             &voidResponse);

  // Cleanup all allocated objects, otherwise, reference count and
  // memory leaks will happen.
  NPN_ReleaseObject(window);
  NPN_ReleaseVariantValue(&consoleVar);
  NPN_ReleaseVariantValue(&voidResponse);
 

The browser object

  NPObject* window = NULL;
  NPN_GetValue(npp_, NPNVWindowNPObject, &window);
 

The first thing we need is an NPObject representation of the browser object. From there, the functions in this API can be used to get and set properties and call methods on those browser objects.

The browser object in this case is javascript's window object. The window object represents the window itself, which we want to execute a property in our case the console. Console debugging is the default debugging messaging for Google Chrome and Firebug on Firefox.

To access the browser object from NPAPI, it is done by using an extension to NPN_GetValue(). The extension is the NPNVWindowNPObject enumeration. By calling NPN_GetValue with that enumeration, it will return an NPObject representing the browser object.

An NPObject is a structure that holds a pointer to an NPClass which is defined within your plugin. It is the type that is used to express objects exposed by the browser in this case. This is the entry point of what we need to execute in the JavaScript side.

So now we have access to the window object within the JavaScript DOM.

Calling the console property

   // Get console object.
  NPVariant consoleVar;
  NPIdentifier id = NPN_GetStringIdentifier("console");
  NPN_GetProperty(npp_, window, id, &consoleVar);
  NPObject* console = NPVARIANT_TO_OBJECT(consoleVar);
 

The plugin now has a pointer to the browser's window DOM object. Now time to call its' console property which allows us to call its functions such as, console.debug()

To do so, we need an NPIdentifer that identies the JavaScript string that we want to call. We can use the macro, NPN_GetStringIdentifier to quickly get the identifier for that string. That is used to tell NPAPI what to execute in the NPObject.

Since we have the window object and id identifier we can execute that property to retrieve the console NPVariant. The NPVariant is a struct that holds a value and the type of that value. Think of it as a JavaScript representation of a variable in NPAPI. It is the response that comes back from the browsers, in this case, it is just a console NPObject. Since we know its an NPObject, we can extract the NPVariant to an NPObject with the simple to use macro, NPVARIANT_TO_OBJECT

Invoking debug

  // Get the debug object.
  id = NPN_GetStringIdentifier("debug");

  // Invoke the call with the message!
  NPVariant type;
  STRINGZ_TO_NPVARIANT(message, type);
  NPVariant args[] = { type };
  NPVariant voidResponse;
  NPN_Invoke(npp_, console, id, args,
             sizeof(args) / sizeof(args[0]),
             &voidResponse); 
 

The final step is to invoke a debug function on the console NPObject returned by the previous step. We do the same thing we did before, we need an NPIdentifer that idenfies the javascript, in this case debug. Note, we reuse the same NPIdentifier id.

Since window.console.debug(message) requests a string parameter, as we discussed before, a parameter is just an NPVariant. To convert a char* to a NPVariant string, we can use a macro, STRINGZ_TO_NPVARIANT. All the NPAPI macros are defined in the NPVariant docs. You should read them, it is great to know which macros are available. Makes your life easier to use them.

Once we constructed our NPVariant args array, we can finally invoke the console NPObject defined earlier with the args we defined right now. The result would just be a void response.

Don't forget to cleanup!

  // Cleanup all allocated objects, otherwise, reference count and
  // memory leaks will happen.
  NPN_ReleaseObject(window);
  NPN_ReleaseVariantValue(&consoleVar);
  NPN_ReleaseVariantValue(&voidResponse);
 

As you all know, cleaning up unused pointers is critical to any C++ application :). Failing to do so in NPAPI, will result in buggy plugins that will crash. Yes, I said it, it will "really" crash!. So cleanup your window object, and your variants as shown in the snippet!

Conclusion

I hope you realize how easy it is to call JavaScript directly from NPAPI, once you understand the code involves, it becomes easy to do anything. Just be careful cleaning up afterwards, or you will have memory leaks and plugin crashes. I hope this article will benefit any of you, and I am excited to share my NPAPI journey with you in the near future!

My next article will be talking about the design and architecture of a NPAPI plugin, and what the future has with NPAPI. Google engineers are working hard creating future sandboxes plugins which are safer and easier to use such as PEPPER and NaCL (discontinued "kinda" in favor of PEPPER) :)

About this Article:

Comments (18) - Add yours, or View the replies

Categoy (Software)

Views (40179)

Digg it: Digg this article