Click here to Skip to main content
Click here to Skip to main content

Working on an NPAPI-browser plugin

, 8 Jul 2010
Rate this:
Please Sign up or sign in to vote.
Extending the NPAPI-runtime to a Firefox plugin.



A browser plug-in has the same rights as a window application on the PC. Plug-ins empower websites with rich features like as graphics, or extended computation, or system access. But it also opens the doors for criminals. So everyone has to be aware which browser plug-in gets installed in their systems. As some Google guys wrote, NPAPI is a real hammer.

This sample is based on a sample npruntime of the Gecko SDK. So all credits go there; I have only extended in the way I want to show the power and share my knowledge; my additions to the original files are all marked with kk (I hope so).


The power of NPAPI is that it can work in Mozilla Firefox, Google Chrome, and Apple Safari, and is also cross platform. But that doesn't come for free; there are some installation steps to do. My plug-in now only works in Firefox on Windows. To compile the code, you need the Gecko SDK.

Using the sample

You need to copy the DLL in the plug-ins directory of Mozilla Firefox and than open Codeproject.html in the project with Firefox.

Using the code

The code is, as mentioned, based on the npruntime sample, and extended in some ways. The skeleton is setting up and initializing a plug-in which can accessed from websites.

To get a plug-in running, you have to deal with at least three languages: HTML, JavaScript, and C++.

To include a plug-in in a website, you only need this HMTL-code:

<embed type="application/npcodeproject" width=800 height=200 id="plugin">

To use the plug-in, the plug-in must be carefully installed on a PC that includes all the required stuff like DLLs. So the best thing to do is to link statically. Mozilla Firefox installs plug-ins in its "plugins" directory.

To access the plug-in from JavaScript, you need a reference to the instance of the plug-in. If it doesn't work, then something has went wrong. Dealing with that case is really a pain.

var PLUGIN = document.getElementById('plugin');

Writing the plug-in is done in C++. At first, you need to understand the startup of the plug-in: getting function pointers from the Netscape Plug-in API to work. Callback communications are done via these functions.

NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs)
  if(pFuncs == NULL)

  if(pFuncs->size < sizeof(NPPluginFuncs))

  pFuncs->version       = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
  pFuncs->newp          = NPP_New;
  pFuncs->destroy       = NPP_Destroy;
  pFuncs->setwindow     = NPP_SetWindow;
  pFuncs->newstream     = NPP_NewStream;
  pFuncs->destroystream = NPP_DestroyStream;
  pFuncs->asfile        = NPP_StreamAsFile;
  pFuncs->writeready    = NPP_WriteReady;
  pFuncs->write         = NPP_Write;
  pFuncs->print         = NPP_Print;
  pFuncs->event         = NPP_HandleEvent;
  pFuncs->urlnotify     = NPP_URLNotify;
  pFuncs->getvalue      = NPP_GetValue;
  pFuncs->setvalue      = NPP_SetValue;
  pFuncs->javaClass     = NULL;

  return NPERR_NO_ERROR;

NP_Initialize(NPNetscapeFuncs* pFuncs
#ifdef XP_UNIX
              , NPPluginFuncs* pluginFuncs
  if(pFuncs == NULL)

  if(HIBYTE(pFuncs->version) > NP_VERSION_MAJOR)

  if(pFuncs->size < sizeof(NPNetscapeFuncs))

  NPNFuncs.size                    = pFuncs->size;
  NPNFuncs.version                 = pFuncs->version;
  NPNFuncs.geturlnotify            = pFuncs->geturlnotify;
  NPNFuncs.geturl                  = pFuncs->geturl;
  NPNFuncs.posturlnotify           = pFuncs->posturlnotify;
  NPNFuncs.posturl                 = pFuncs->posturl;
  NPNFuncs.requestread             = pFuncs->requestread;
  NPNFuncs.newstream               = pFuncs->newstream;
  NPNFuncs.write                   = pFuncs->write;
  NPNFuncs.destroystream           = pFuncs->destroystream;
  NPNFuncs.status                  = pFuncs->status;
  NPNFuncs.uagent                  = pFuncs->uagent;
  NPNFuncs.memalloc                = pFuncs->memalloc;
  NPNFuncs.memfree                 = pFuncs->memfree;
  NPNFuncs.memflush                = pFuncs->memflush;
  NPNFuncs.reloadplugins           = pFuncs->reloadplugins;
  NPNFuncs.getJavaEnv              = NULL;
  NPNFuncs.getJavaPeer             = NULL;
  NPNFuncs.getvalue                = pFuncs->getvalue;
  NPNFuncs.setvalue                = pFuncs->setvalue;
  NPNFuncs.invalidaterect          = pFuncs->invalidaterect;
  NPNFuncs.invalidateregion        = pFuncs->invalidateregion;
  NPNFuncs.forceredraw             = pFuncs->forceredraw;
  NPNFuncs.getstringidentifier     = pFuncs->getstringidentifier;
  NPNFuncs.getstringidentifiers    = pFuncs->getstringidentifiers;
  NPNFuncs.getintidentifier        = pFuncs->getintidentifier;
  NPNFuncs.identifierisstring      = pFuncs->identifierisstring;
  NPNFuncs.utf8fromidentifier      = pFuncs->utf8fromidentifier;
  NPNFuncs.intfromidentifier       = pFuncs->intfromidentifier;
  NPNFuncs.createobject            = pFuncs->createobject;
  NPNFuncs.retainobject            = pFuncs->retainobject;
  NPNFuncs.releaseobject           = pFuncs->releaseobject;
  NPNFuncs.invoke                  = pFuncs->invoke;
  NPNFuncs.invokeDefault           = pFuncs->invokeDefault;
  NPNFuncs.evaluate                = pFuncs->evaluate;
  NPNFuncs.getproperty             = pFuncs->getproperty;
  NPNFuncs.setproperty             = pFuncs->setproperty;
  NPNFuncs.removeproperty          = pFuncs->removeproperty;
  NPNFuncs.hasproperty             = pFuncs->hasproperty;
  NPNFuncs.hasmethod               = pFuncs->hasmethod;
  NPNFuncs.releasevariantvalue     = pFuncs->releasevariantvalue;
  NPNFuncs.setexception            = pFuncs->setexception;
  //end of snippet

If these functions get called, the plug-in runs, and the special implementation does stuff like getting and setting properties. But before you can do that, check if the "Has" callback is implemented.

if( !strcmp( "Name", pProp ) )
    //allocating Memory for the string with invocation of Browser-API
    char *p = (char*) NPN_MemAlloc( m_pszName );
    STRINGZ_TO_NPVARIANT( p, *result);
    return true;

The interesting point here is that allocating memory with the NPAPI is needed to create the result strings. It took me some time to figure that out. The handy macro STRINGZ_TO_NPVARIANT helps in the output.

The real functionality is done via the Invoke interface. As seen, it is possible to call my "Add" function with strings and numbers mixed and also a varying count of arguments. But that is done in the tuning of the interface.

bool ScriptablePluginObject::Invoke(NPIdentifier name, 
     const NPVariant *args, uint32_t argCount, NPVariant *result)
    char *pFunc = NPN_UTF8FromIdentifier(name);

    if( !strcmp( "Add", pFunc ) )
        int sum = 0;

        for( unsigned int i = 0; i < argCount; i++ )
            if( args[i].type == NPVariantType_Int32 )
                sum += args[i].value.intValue;
            else if( args[i].type == NPVariantType_String )
                CNPString s(args[i].value.stringValue);
                sum += atoi( s );
            else return false;//an error happenend


Points of interest

It is really interesting to see how the plug-ins work under the hood. Sometimes it gets mysterious when it doesn't work. I am not happy that it doesn't work with Google Chrome and Apple Safari, but I do not have the time to figure it out now.

Internet Explorer doesn't support the NPAPI, so you will need ActiveX for it. But this should be considered in the architecture of the code.

If you write a plug-in, don't forget to set the accurate MIMEType in NPP_GetMIMEDescription() and the rc file, or you will have a headache for hours. If you can't compile the code because a lot of Windows types are unknown, include the Windows headers first!!!

The output DLL has to be named in the "np*.dll" format to be a Firefox plug-in, and goes to to the plugins directory of Firefox: "C:\Program Files\Mozilla Firefox\plugins".

Some interesting links


  • 08/07/2010: Initial release.



About the Author

Software Developer
Germany Germany

Comments and Discussions

QuestionI can not find npfunctions.h file PinmemberMember 1006688328-Jun-14 21:48 
AnswerRe: I can not find npfunctions.h file PinmemberKarstenK29-Jun-14 6:27 
QuestionWorking on an NPAPI-browser plugin for IE Pinmembergawadepd21-May-14 4:35 
AnswerRe: Working on an NPAPI-browser plugin for IE PinmemberKarstenK21-May-14 4:41 
Questionthe demo dll can work at chrome, but rebuild the dll from your source code, the chrome alert "Could not load the plugin" PinmembermaryNet14-Jun-13 0:14 
AnswerRe: the demo dll can work at chrome, but rebuild the dll from your source code, the chrome alert "Could not load the plugin" PinmemberKarstenK8-Jul-13 20:46 
Questionis this code working? PinmemberJayShin15-Jan-12 14:25 
AnswerRe: is this code working? PinmemberKarstenK15-Jan-12 21:21 
QuestionDeploying the plug-in PinmemberL4pp17-Dec-11 22:07 
AnswerRe: Deploying the plug-in PinmemberKarstenK7-Dec-11 22:41 
GeneralRe: Deploying the plug-in PinmemberL4pp17-Dec-11 22:54 
GeneralRe: Deploying the plug-in PinmemberKarstenK15-Jan-12 21:21 
QuestionPluginWinProc can receive WM_IME_* message ? Pinmemberchengdu111317-Nov-11 20:37 
AnswerRe: PluginWinProc can receive WM_IME_* message ? PinmemberKarstenK17-Nov-11 22:13 
GeneralRe: PluginWinProc can receive WM_IME_* message ? Pinmemberchengdu111320-Nov-11 16:19 
GeneralRe: PluginWinProc can receive WM_IME_* message ? PinmemberKarstenK20-Nov-11 20:47 
QuestionChrome doesn't support functions with parameters? Pinmemberdkjfsoman30-Oct-11 20:27 
AnswerRe: Chrome doesn't support functions with parameters? Pinmemberdan_mihai_ro2-Nov-11 0:42 
GeneralCrash on Firefox 4.01 Pinmemberswa00423-May-11 6:07 
GeneralRe: Crash on Firefox 4.01 PinmemberKarstenK23-May-11 21:04 
GeneralRe: Crash on Firefox 4.01 Pinmemberswa0042-Jun-11 4:13 
GeneralRe: Crash on Firefox 4.01 PinmemberKarstenK5-Jun-11 20:59 
GeneralRe: Crash on Firefox 4.01 PinmemberMurasoli Selvan K26-Feb-13 21:01 
GeneralRe: Crash on Firefox 4.01 PinmemberKarstenK26-Feb-13 21:09 
QuestionA problem Pinmemberneufeng20109-Mar-11 1:04 



| Advertise | Privacy | Mobile
Web04 | 2.8.140709.1 | Last Updated 8 Jul 2010
Article Copyright 2010 by KarstenK
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid