Chapter 9

Instance Initialization and Destruction


CONTENTS


Introduction

When Netscape encounters an unknown MIME type, it checks the plug-in registry and determines which plug-in, if any, to load. After loading the plug-in, the Navigator must call initialization routines within the newly loaded code module. Conversely, after finishing with the plug-in, API routines are called to free system resources previously allocated, and the module is unloaded from system memory.

Typically, a plug-in allocates a block of instance data for itself for reference throughout its operation. Many other system resources can also be allocated during initialization, including memory, files, and multimedia devices. These resources are freed during the plug-in destruction process.

This chapter covers the following initialization and destruction routines:

NPP_Initialize
NPP_Shutdown
NPP_New
NPP_Destroy
NPN_Version

At the end of the chapter, you find a quick reference to these functions, including sample code.

Instance Data

The plug-in architecture relies heavily on instance data. An "instance" of your plug-in is created every time a new URL of your MIME type is encountered by the Web browser. A new data block is allocated by your code for every instance. In many cases, multiple instances of your plug-in might be active at the same time! Consider the following HTML code:

<html>
<head>
   <title>My Plug-in Test Page</title>
</head>
<body>

<h2 align=center>First Plug-in Instance</h2>

<center><p><embed SRC=audio1.wav WIDTH=400 HEIGHT=60></p></center>

<h2 align=center>Second Plug-in Instance</h2>

<h2 align=center><embed SRC=audio2.wav WIDTH=400 HEIGHT=60></h2>

</body>
</html>

Note
This HTML code embeds a plug-in that plays Microsoft's .WAV audio files. A plug-in like this can be found, with its source code, on the CD-ROM included with this book.

This code causes the Navigator to load two instances of the plug-in registered for the MIME type audio/x-wav. Each instance of the plug-in will have a private copy of data. In the case of an audio player plug-in, assuming a single audio card, one instance might be active and control the audio card while another might be waiting. If desired, control of the card can be changed to another instance by user input on the plug-in's embedded window.

Warning
A bug in Navigator 2.x allows only one plug-in instance to be created from a Web page that embeds two identical URLs in a single page. The workaround is to copy the second object and rename it, thus creating unique URLs.

Global Initialization and NPP_Initialize

API mapping, which is covered in Chapter 8, "The Plug-In Application Programming Interface (API)," is performed first before any standard initialization routines are called. After this is done, your routine NPP_Initialize is called. NPP_Initialize is called only one time, when the plug-in code is loaded into memory. Therefore, you should use this function for global initializations only. In many cases, you won't even need or want to do anything during this time.

Some plug-ins might need communication between multiple instances. The NPP_Initialize routine can be used to allocate a global data structure to be shared across instances. Windows 95 and NT developers should be careful to serialize access to this data:

// Use critical sections to serialize access to global plug-in data. Watch out
// for deadlocks! Many plug-in APIs are re-entrant.
EnterCriticalSection (&CritSect);

pGlobalData->fFlag = TRUE;
pGlobalData->nState = RUNNING;

LeaveCriticalSection (&CritSect);

Global Destruction and NPP_Shutdown

Immediately before your plug-in is unloaded from memory, NPP_Shutdown is called. This routine enables you to free any resources created with NPP_Initialize.

Note
In a Windows DLL, NPP_Initialize and NPP_Shutdown originate from the DLL entry points NP_Initialize and NP_Shutdown, respectively.

Instance Initialization and NPP_New

After NPP_Initialize is complete, NPP_New is called. NPP_New enables you to allocate per instance resources. Additionally, this routine provides your plug-in with valuable information relating your instance.

MIME Type

The first thing that NPP_New tells you is which MIME type caused the creation of this plug-in instance. This is important because a single plug-in can support multiple MIME types. It helps to know which one you are dealing with.

An example MIME type is audio/x-wav.

Instance Pointers

The second parameter of NPP_New is a pointer to a structure called NPP. This structure contains pointers to both your plug-in's instance data and Netscape's. This structure is currently defined as follows:

typedef struct _NPP
{
    void*   pdata;    // Plug-in's instance data
    void*   ndata;    // Netscape's instance data
} NPP_t;

typedef NPP_t*  NPP;

Note
It's interesting to note that Netscape gives a pointer to its instance data also, but at this time it is undocumented. Happy hacking!

This structure comes into NPP_New with the plug-in's instance data pointer set to NULL. Your job is to create a block of instance data for the plug-in and attach it to the supplied pointer. It might look something like this:

myInstance* myinstance = (myInstance *)NPN_MemAlloc (sizeof(myInstance));
instance->pdata = myinstance;

Notice the usage of Netscape's memory allocation routine NPN_MemAlloc. This API is covered in Chapter 12, "Memory Management." In some cases, you might not need to use NPN_MemAlloc, and you could perhaps use malloc(), but why take the risk?

Mode

The third parameter of NPP_New contains the mode in which your plug-in is running. These modes are as follows:

Note
Netscape Navigator 2.x has not implemented NP_BACKGROUND. Look for this feature in 3.x and above.

HTML Arguments

The fourth, fifth, and sixth NPP_New parameters are relevant only to the plug-in mode of NP_EMBED. These parameters contain a pre-parsed version of the HTML code following the embed tag.

Of these parameters, the first, argc, contains the argument count. This count starts after the embed tag.

The second, argn, is an array of pointers that reference the first value of a name/value pair.

The third, argv, is an array of pointers that reference the second value of a name/value pair.

Warning
Netscape makes no guarantee that the HTML arguments are valid in any mode but NP_EMBED. Always check for NP_EMBED before you attempt to access any of these arguments.

Consider the following HTML line:

<embed SRC=audio1.wav WIDTH=400 HEIGHT=60>

HTML arguments from this line look like this:

argc = 3

argn[0] = "SRC"                  argv[0] = "audio1.wav"
argn[1] = "WIDTH"
                argv[1] = "400"
argn[2] = "HEIGHT
"                argv[2] = "60"

To ease HTML coding for users of your plug-in, you might want to parse these strings without reference to case.

Previously Saved Data

The seventh and last parameter of NPP_New is a pointer to a structure called NPSavedData. This structure, if allocated, points to a block of data saved from a previous instance. You can access your saved data like this:

… NPSavedData* pSavedData, …

if (pSavedData)
{
    if (pSavedData->len == sizeof(MyData))
    {
        MyData* mydata = (MyData *)pSavedData->buf;
    }
}

Warning
Netscape Navigator 2.x gives a GPF if you return an error from NPP_New. This bug is in Windows Navigators only and has been fixed in 3.x.

Instance Destruction with NPP_Destroy

Whatever is created must be destroyed. Netscape provides for your plug-in's instance data destruction by calling NPP_Destroy. During this call, you can free instance data, unsubclass Netscape's client window, delete objects, and perform any other cleanup duties.

Warning
Resizing a Web page can cause your plug-in to be destroyed and re-created in Netscape Navigator 2.x.

Saving Data with NPP_Destroy

In many cases, you might want to save data between your plug-in instances. This can be accomplished through the use of the NPSavedData structure pointer passed to you in NPP_Destroy. The structure is currently defined as follows:

typedef struct _NPSavedData
{
    int32   len;
    void*   buf;
} NPSavedData;

NPP_Destroy is actually passed only the address of a pointer to the NPSavedData structure. It's up to your code to allocate the structure and point it to your saved data. Perhaps, you could use something like this:

(*save) = (NPSavedData *) NPN_MemAlloc (sizeof(NPSavedData));
(*save)->buf = myinstance;
(*save)->len = sizeof(MyInstance);

In this example, you save your whole instance. Often, you might want to define a special structure just for saved data. Make sure that you use NPN_MemAlloc to allocate this memory. NPN_MemAlloc registers the memory block with Netscape, which can free it later.

If you use the new operator to allocate a saved memory object, you need to overload it within that class. The following class, called CNetscapeMemObject, does this:

#ifndef NETSCAPEMEMOBJECT_H
#define NETSCAPEMEMOBJECT_H

#include <defines.h>

#ifndef _NPAPI_H_
#include "npapi.h"
#endif

class CNetscapeMemObject
{
    public:
        void* operator new(size_t size)
            { return NPN_MemAlloc( size ); };
        void operator delete( void* theThing, size_t size )
            { NPN_MemFree( theThing ); };
};

#endif

Any class derived from this class will inherit its behavior. You can use this as a base class for your saved memory object.

In some rare cases, you might never see the saved memory block again. Netscape makes no guarantee that this data will ever return. In light of that, make sure you use this technique for noncritical data such as a volume setting or a video frame number.

Note
The data in the saved data buffer must be flat. That is, it must not contain pointers to any data that it owns. Navigator would not be able to resolve those references if it had to free some memory, which would lead to a memory leak.

Warning
Saved data does not work for the mode of NP_FULL; it only works for NP_EMBED in Netscape Navigator 2.x.

Version Information with NPN_Version

NPN_Version is a simple method designed to tell you the plug-in API's major and minor version numbers, in addition to your plug-in's major and minor numbers. A major version is a major product release and a minor version is usually a point release. The major and minor plug-in API version numbers do not correspond to the release versions of the Navigator.

It's interesting to note that the code for NPN_Version resides fully within your plug-in. If you remember from the previous chapter, NPN stands for an API within the Navigator, but this is an exception to the rule. The Navigator version information, however, was brought to you from Netscape via your plug-in's initialization routine.

Windows developers can find the code for NPN_Version in NPWIN.CPP:

void NPN_Version (int* plugin_major,
    int* plugin_minor,
    int* netscape_major,
    int* netscape_minor)
{
    *plugin_major   = NP_VERSION_MAJOR;
    *plugin_minor   = NP_VERSION_MINOR;
    *netscape_major = HIBYTE(g_pNavigatorFuncs->version);
    *netscape_minor = LOBYTE(g_pNavigatorFuncs->version);
}

The same block of code is also in NPMac.cpp for Macintosh developers in the Macintosh SDK.

You can see that your plug-in's version information is simply defined from NPAPI.H, while the Netscape plug-in API version numbers are within the Navigator function pointer structure, having been retrieved earlier.

API Quick Reference

The following sections give in-depth information on the APIs used in this chapter.

NPP_Initialize

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypePlug-in implemented method.
PurposeUse this routine to perform any load time initialization for your code module.
SyntaxNPError NPP_Initialize (void)
Includes#include <npapi.h>
DescriptionCalled from the Navigator only once after the code module is loaded. In the case of a Windows DLL, this routine is called from the NP_Initialize DLL entry point located in the Netscape Windows SDK file NPWIN.CPP.

This is the first API called in your plug-in code.

Any error codes returned (aside from NPERR_NO_ERROR) cause the plug-in to be unloaded by the Navigator.

ReturnsNPERR_NO_ERROR: No error.

NPERR_GENERIC_ERROR: An unknown error occurred.

NPERR_OUT_OF_MEMORY_ERROR: Out of memory.

See AlsoNPP_Shutdown
Example#include <npapi.h>

MyGlobalData* pGlobalData;

// // One time initialization of plug-in
//
NPError NPP_Initialize(void)
{
     if (pGlobalData = NPN_MemAlloc
(sizeof(MyGlobalData))
         return NPERR_NO_ERROR;
      return NPERR_OUT_OF_MEMORY_ERROR
}

NPP_Shutdown

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypePlug-in implemented method.
PurposePerform any final global resource freeing before plug-in is unloaded.
Syntaxvoid NPP_Shutdown (void)
Includes#include <npapi.h>
DescriptionThis function is called immediately before the plug-in is unloaded. It is called only once. Use it to free any global resources. In the case of a Windows DLL, this routine is called from the NP_Shutdown DLL entry point located in the Netscape Windows SDK file NPWIN.CPP.
ReturnsNone.
See alsoNPP_Initialize
Example#include <npapi.h>

MyGlobalData* pGlobalData;

//
// Cleanup plug-in library
//
void NPP_Shutdown(void)
{
     if (pGlobalData)
         NPN_MemFree (pGlobalData)
}

NPP_New

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypePlug-in implemented method.
PurposeCreates new instance data to associate with a plug-in instance.
SyntaxNPError NPP_New (NPMIMEType pluginType,
      NPP instance,
      uint16 mode,
      int16 argc,
      char* argn[],
      char* argv[],
      NPSavedData* saved)

NPMIMEType pluginType: A character pointer to the plug-in's MIME type.

NPP instance: A pointer to structure NPP, which contains poin-ters to both the plug-in's and Netscape's private instance data.

NPP instance: A pointer to structure NPP, which contains poin-ters to both the plug-in's and Netscape's private instance data.

int16 argc: A short determining the number of HTML arguments for an embedded plug-in.

char* argn[]: A character pointer to an array of strings representing the first of a name pair from HTML code for an embedded plug-in.

char* argv[]: A character pointer to an array of strings representing the second of a name/value pair from HTML code for an embedded plug-in.

NPSavedData* saved: A pointer to an NPSavedData structure containing the length and a pointer to plug-in data saved previously with NPP_Destroy.

Includes#include <npapi.h>
DescriptionNPP_New is called immediately after NPP_Initialize. The routine resides in your plug-in module and is designed to provide your plug-in instance with relevant startup information such as MIME type, mode, and HTML arguments.

NPP_New also gives a plug-in developer the capability for allocation of both instance data and data objects. A pointer to this data is returned to the Navigator and is later passed to your APIs for future reference.

Saved data from a previous call to NPP_Destroy can be returned via the NPP_New call.

ReturnsNPERR_NO_ERROR: No error.

NPERR_GENERIC_ERROR: An unknown error occurred.

NPERR_INVALID_INSTANCE_ERROR: The instance value is invalid.

NPERR_OUT_OF_MEMORY_ERROR: Out of memory.

See AlsoNPP_Destroy
Example#include <npapi.h>
//
// Create a new instance for our plug-in
// NPError NP_LOADDS NPP_New (NPMIMEType pluginType,
     NPP instance,
     uint16 mode,
     int16 argc,
     char* argn[],
     char* argv[],
     NPSavedData* saved)
{
     // Check for spurious calls from Netscape      if (instance == NULL)
         return NPERR_INVALID_INSTANCE_ERROR;

     // Allocate instance data for this plug-in instance
      MyInstance* myinstance = (MyInstance *)NPN_MemAlloc (sizeof(MyInstance));
      myinstance->pWindow = NULL;    // the window pointer
     myinstance->pObject = new CPluginObject ();  //
Âallocate main plug-in object
     myinstance->mode = mode;  // Save the mode: NP_FULL,
ÂNP_EMBED, NP_HIDDEN

     if (mode == NP_EMBED)
     {
         // Embedded plug-ins have HTML arguments

        // Extract them here…(argc, argn, argv)
     }

    // Save our instance pointer which will be passed back
Âin all calls
      instance->pdata = myinstance;
      return NPERR_NO_ERROR;
}

NPP_Destroy

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypePlug-in implemented method.
PurposeFrees any instance data allocated via NPP_New. Frees any per instance resources.
SyntaxNPError NPP_Destroy (NPP instance, NPSavedData** save)

NPP instance: A pointer to structure NPP, which contains pointers to both the plug-in's and Netscape's private instance data.

NPSavedData** save: A pointer to a pointer that references an NPSavedData structure containing the length and a pointer to plug-in instance data.

Includes#include <npapi.h>
DescriptionNPP_Destroy is called to free all per instance data and resources. This call usually, but not always, indicates that Navigator is done with your plug-in. Typically, this routine is used to delete objects attached to a plug-in instance, free instance memory, and in the case of Windows, unsubclass Netscape's plug-in window.

NPP_Destroy provides a mechanism to save data for a later instance of the plug-in via the NPSavedData structure. A pointer to this structure should be returned during the next NPP_New call. Be sure to use NPN_MemAlloc to allocate the saved structure because you might not have the opportunity to free it. Netscape frees the memory in this case.

The saved data is given to the next call to NPP_New whose SRC is the same as that associated with this instance of the plug-in. For example, if this is a movie plug-in, the saved data only shows up the next time that the same movie is viewed.

ReturnsNPERR_NO_ERROR: No error.

NPERR_GENERIC_ERROR: An unknown error occurred.

NPERR_OUT_OF_MEMORY_ERROR: Out of memory.

See AlsoNPP_New
Example#include <npapi.h>

//
// Destroy a plug-in instance
// NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData**
Âsave) {
     MyInstance* myinstance = (MyInstance *)instance-
Â>pdata;

     // In windows, unsubclass the window

     myinstance->pWindow->UnSubclassNetscapesWindow ();

    myinstance->pWindow->CleanupWindow();

     // Delete objects

     delete myinstance->pWindow;
     delete myinstance->pObject

     // Allocate a save structure and attach our instance
Âto it for next time.

     (*save) = (NPSavedData *)NPN_MemAlloc
Â(sizeof(NPSavedData));
     (*save)->buf = myinstance;
     (*save)->len = sizeof(MyInstance);

     return NPERR_NO_ERROR;
}

NPN_Version

CompatibilityWindows 3.1/95/NT, Macintosh, UNIX.
API TypeNavigator implemented method.
PurposeRetrieves the major and minor version numbers for both the Navigator plug-in API and your plug-in.
Syntaxvoid NPN_Version (int* plugin_major,
      int* plugin_minor,
      int* netscape_major,
      int* netscape_minor);

int* plugin_major: An integer pointer to your plug-in's major version number.

int* plugin_minor: An integer pointer to your plug-in's minor version number.

int* netscape_major: An integer pointer to the Navigator plug-in API's major version number.

int* netscape_minor: An integer pointer to the Navigator plug-in API's minor version number.

Includes#include <npapi.h>
DescriptionThis routine does not actually call the Navigator. It calls local code in your plug-in that stored version information during plug-in initialization. A major version is a major code release number, and a minor version is a point release.

For example, Navigator plug-in API version 0.6 would be major 0, minor 6.

ReturnsNone.
See AlsoNone.
Example#include <npapi.h>
.
.
.
int plugin_major, plugin_minor, netscape_major,
netscape_minor;

//
// Get our version info.
//
NPN_Version (&plugin_major, &plugin_minor, &netscape_major, &netscape_minor);
.
.
.

Conclusion

In this chapter, you've learned how your plug-in is loaded, initialized, destroyed, and unloaded. Remember that NPP_Initialize and NPP_Shutdown are called only once for the time that your plug-in is loaded and unloaded from memory. NPP_New and NPP_Destroy are called for each new instance of your plug-in. Multiple instances of a plug-in are quite common.

Also, keep in mind that NPN_Version returns the Navigator's plug-in API version, not the Navigator browser version.

What's Next?

Now that you've mastered instance initialization and destruction, it's time to move on to stream creation and destruction. In the next chapter, you learn about the following topics: