Under the Hood

"It is almost impossible to successfully determine which side of the bread to butter".


Till now, you have little more than sitting around, hoping that this tutorial might dislodge some salient fact which would fall into place and make sense of an otherwise utterly bewildering plug-in, but this salient fact, if there is one, has entirely failed to do so. So throw in your computing towels and head for greener pastures. If your technical appetite jibes with the grub offered by this tutorial, then you are playing in the right ballpark.

In retrospect, we have used the newp and setwindow variables of NPPluginFuncs ; we also observed that newp gets called only once; but the million-dollar question still dangles : where's the dough on "why newp" ? Before we uncork the sprockets of the Netscape doodad, let us try out the following code. Note that we have dispensed with the setwindow variable of NPPluginFuncs of last program of the previous chapter to dig into newp a little deeper.

#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	 char *v[], NPSavedData *s)
{	int j;
	sprintf(a, "p = %s....c = %d", p, c);
	MessageBox(0, a, "hi", 0);
	for (j=0;  j < c;  j++)
	{	sprintf(a, "n[%d] = %s.....v[%d] = %s", j, n[j], j, v[j]);
		MessageBox(0, a, "hi", 0);
	}
	return 0;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points","in get entry points", 0);
	p->newp = aa;
	return 0;	
}
As must have almost become a ritual with you by now if you have been following this tutorial closely, we get a series of message boxes -- "in get entry points", " in initialize" and then the ones heaved up by the aa() . The first thing we do in this function is to display the value of the pointer p, the Mime type (that is always char *). The Mime type turns out to be the same as the one we have specified in our RC file i.e., jack/jill.

Just as kick boxers grimace differently depending on where they have been punched, Netscape behaves differently depending on what file extension it is called upon to brave. For instance, its a cinch for the browser to recognize an HTML file, and it better be that way or it'll cease to be a browser, but as regards the .zzz file, that could very conveniently send Netscape for a toss. One way to sort out this problem is to have a plug-in (and that's nothing but a DLL) which will introduce the .zzz file to Netscape. That is the way we make our browser extensible. When Netscape sees the file extension for the next time in an embed statement, it will call a dll and look for the registered extensions and their corresponding mime types. That is to say that the next time it comes across .zzz, it will know it has to call our dll because we have specified the mime type in our RC file as jack/jill.

The c, n and v are nothing but the familiar argc , argn and argv respectively. If you've had even a slight brush with C, you know that the main() gets called with argc and argv. It is pretty much the same here. Remember the HTML file where we had the embed statement? In case you have forgotten, here it is...


	a1.html
	<embed src = "john.zzz" width = 200 height = 300>
We have three arguments in it -- src , width and the height . The variable c in our code will tell us how many arguments are present in this file. It is conspicuous that we have three of them, so the value drooled out by c will be 3. Likewise, n tells us the names of the arguments like 'src', 'width' or 'height' while v takes care of their respective values like "john.zzz", 200 and 300 respectively. While the embed statement cannot make-do without src, width and height, it allows room for as many user defined names that you can think of. For instance, before signing off, we will show you how to devise a live AVI plug-in and call it your own. With an AVI file (that's an audio video file, for those caught napping), you would like to play it as it is swooping down on your machine from the Internet or after the whole file has been downloaded. For that you could have another name of argument or variable in the HTML file in the embed statement, say 'autostart = true/false'. The place where you will decipher that code is right here -- in the aa() or the function whose address is stored in newp (in addition, newp has some more entrusted tasks; we will uncover these in due course). Which indicates that the variable newp is a fairly consequential one for us, because the values of the variables read here will condition the functioning of the rest of our code.

When Netscape wakes up, it knows it is required to call two functions -- NP_GetEntryPoints and NP_Initialize . Any other function it calls will have to be explicitly invited. That is the convention Netscape prefers to live by, though we'll never know why they did not consider one function that took care of all these parameters.

Whatever we have racked our brains over till now has merely got us a window. But that far from suffices as the culmination of our plug-in-oriented efforts. We are talking here of a file being understood. But first, a file has to be downloaded from the Internet before the question of understanding arises. Therefore, the marrow of a plug-in lies in actually fetching in the data of the file in the way desired by us.

Let us get things a little clearer. When we read a file in C/C++, we use fopen(). Regardless of whether the file is created in DOS, UNIX, Windows (whether 95 or 2000), O/S2 or any other extraterrestrial operating system, fopen() works the same way. The nightmarish innards of these files never nag us when we use fopen(). Internet, however, allows the files to be lurking on any computer almost anywhere in the world. Under the sun of cyberspace, the files could as well be tanning in Miami. That's why it is better-termed as a URL and not the hackneyed file. That implies that the file name we specify with the src in the embed statement need not be some file on your local hard disk, it could be a URL of an HTTP site or FTP or any other recognized protocol for that matter as well. Since Netscape knows very well how to buck the document in, we can safely lay that issue to rest. The only thing that we need Netscape to do for us is that when it is receiving the file, we want it to keep us up-to-date on what's happening like reporting to us about the number of bytes received and at what speed etc. Lets see how that is applied:


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox( 0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	 char *v[], NPSavedData *s)
{	MessageBox(0,  "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, char *p, NPStream *s, NPBool o, unsigned short *b)
{	sprintf(a,"In bb p = %s....s = %p", p, s);
	MessageBox(0, a, "hi", 0);
	sprintf(a, "In bb s->url = %s", s->url);
	MessageBox(0, a, "hi", 0);
	return 0;
}

long cc(NPP I, NPStream *s)
{	sprintf(a, "In cc s = %p", s);
	MessageBox(0, a, "hi", 0);
	return 5;
}

long dd(NPP i, NPStream *s, long o, long l, void *b)
{	sprintf(a, "In dd s = %p...o = %ld...l = %ld", s, o, l);
	MessageBox(0, a, "hi", 0);
	return l;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->newstream = bb;
	p->writeready = cc;
	p->write = dd;
	return 0;	
}
When Netscape has to tell us that he is bringing in a certain file, he needs to know a function of our program to call. We have no recourse but to let him know which function to call, by initializing a member of a structure given to us. The structure in question is NPPluginFuncs and the member that gets called is newstream . We initialize newstream to bb() , thus making it the function to be called. The first thing that we notice here is that the function bb() gets called only once. As stated earlier, the char *p will be the mime type. We display it in message box. A stream signifies the file and its inherent data, so NPStream refers to the file john.zzz and the data in it -- ABCDEFGHIJKLMN. In our program, we are dealing only with john.zzz . Therefore, all the file handling functions will have the same value for NPStream , because in all of them NPStream betokens the same file.

This structure NPStream has a member called url which stands for the full name and location for the file, the same name that we have cited in the src of our embed statement. Since our file john.zzz is resident on our hard disk, our output of url starts with "file:/// " and goes on to specify the full address of john.zzz. If we were picking yp some file from, say, http://www.neca.com , the address of the file would be that of www.neca.com. Whether the file resides on your local hard disk or any other international machine is no hassle for Netscape because it knows how to get the file in. Quite how the file is procured is something that our program has to take care of. Once the file is opened, Netscape needs to know how to read it, that is, how many bytes are to be retrieved each time. Now we are given a free reign with these bytes and we can handle them in any way our astrologer thinks fine.

In order to control the way our file is being received, Netscape coughs up two members of NPPluginFuncs -- writeready and write . At the very outset of explaining this duo, let us be clear that apparently our friends at Netscape got really mixed up with nomenclature. These two pointers would be a trifle more explicit about what they are supposed to do if they were called readready and read respectively.

The writeready is Netscape's way of asking how many bytes we want to be read. So the 'writing' is actually occuring from Netscape's point of view while we are on the 'reading' side of the fence. As an answer, we return a value of 5, which means that we want five characters to be read from our file john.zzz . As a part of the same enterprise, write (i.e., read or better still, receive ) actually reads these 5 bytes for us. It knows that it is expected to write 5 bytes because the value 5 returned from cc() is stored in its parameter l. That is the reason why the cc() and the dd() get called more than once. Let us get a little specific about this cycle.

Just for the record, we have 14 characters in our file. For the first time, the cc() gets called and the first five characters of the file are picked up i.e., from A to E. These are then read by the dd() function. Once these five have been taken care of, the next five have to be read. So the cc() function gets called once more and thus the cycle repeats itself. In the third round, though, there are only 4 characters left in our file. So l, in the dd() , will be 4 this time inspite of the return value from cc() being 5. The fourth time, the end-of-file has been reached, so the write part need not be done. Hence, the dd() does not get called. To get a real hang of this intermittent functioning, consider this code...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[], NPSavedData *s)
{	MessageBox(0, "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, char *p, NPStream *s, NPBool o, unsigned short *b)
{	MessageBox(0, "in bb", "hi", 0);
	return 0;
}

long cc(NPP I, NPStream *s)
{	MessageBox(0, "in cc", "hi", 0);
	return 5;
}

long dd(NPP i, NPStream *s, long o, long l, void *b)
{	int j;
	char *p;
	p=(char *)b;
	sprintf(a, "in dd...o = %ld", o) ;
	MessageBox(0, a, "hi", 0);
	for(j=0;  j < l;  j++)
	{	sprintf(a, "In dd...p[%d] = %c", j, p[j]);
		MessageBox(0, a, "hi", 0);
	}
	return l;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->newstream = bb;
	p->writeready = cc;
	p->write = dd;
	return 0;	
}
 
While running the program, note the status bar. It will show the percentage of the file read. Also, mark the parameters of the dd() . The variable i that looks like NPP is the handle that uniquely identifies the embed statement that we have been referring to (there can be many of them), s is the handle of the stream, o is the offset or the stead in the file from where the writing (or reading) has to begin, l is the number of bytes to be read from the offset. The last one, however, though, is a very crucial one. It is a void pointer. Since we wish to see the value of each and every byte that is being written, we type cast b to a char pointer called p and display it as p[0], p[1], p[2], p[3] etc. in a for loop.

Netscape has its own mechanical arms that let it fetch a file in to your machine. It does not really concern us whether it gets the file in bytes or gigabytes; what matters, however, is whether you want to read it all at once after the entire file has been received (by returning a preposterously large value from the cc() or in chunks of comfortable size as and when it is being received. For instance, if you have to read a DBase file, the first 32 characters have to be read as they represent the header. Then you can do anything with the chunk of data read -- display it on the screen, save it as a file on disk or send it to a combat mission to Pluto. That's for you to decide.

Table showing various possibilities with the reading of files
Possibilities What Happens
If o is returned in the cc(), i.e, writeready write does not get called, that is, the file is never actually read
No writeready value of l will be the size of file, so the file is read as a whole
If 0 is returned in write Since that means we do not want to actually read any data, the poor cc() (writeready) keeps on getting called
If -ve value is returned from writeready The cc() gets called only once and no actual reading/writing takes place

Trouble is : We have figured out how to get the raw bytes or characters, but what if you do want to refer to them as a whole file rather than as bytes. For that purpose, try this program...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[],NPSavedData *s)
{	MessageBox(0, "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, char *p, NPStream *s, NPBool o, unsigned short *b)
{	MessageBox(0, "in bb", "hi", 0);
	return 0;
}

long cc(NPP i, NPStream *s)
{	MessageBox(0, "in cc", "hi", 0);
	return 5;
}

long dd(NPP i, NPStream *s, long o, long l, void *b)
{	MessageBox(0, "in dd", "hi", 0);	
	return l;
}

void ee(NPP i, NPStream *s, const char *f)
{	MessageBox(0, "in ee", "hi", 0);
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->newstream = bb;
	p->writeready = cc;
	p->write = dd;
	p->asfile = ee;
	return 0;	
}
Meanwhile, we employ another variable of our humble structure NPPluginFuncs called asfile. We initialize it to our function ee which has three parameters -- the handle i, the stream s and the name of the file so that the data that is being read will be in the form of an entire file.

The blip : the asfile will flunk to work as it needs some adjustments to be made in the program file. We have no resort but to make them, as follows...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
			char *v[],NPSavedData *s)
{	MessageBox(0, "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, char *p, NPStream *s, NPBool o, unsigned short *b)
{	MessageBox(0, "in  bb", "hi", 0);
	*b = NP_ASFILE;
	return 0;
}

long cc(NPP i, NPStream *s)
{	MessageBox(0, "in cc","hi",0);
	return 0xffffff;
}

long dd(NPP i, NPStream *s, long o,long l, void *b)
{	MessageBox(0, "in dd", "hi", 0);	
	return l;
}

void ee(NPP i, NPStream *s, const char *f)
{	sprintf(a, "In ee f = %s", f);
	MessageBox(0, a, "hi", 0);
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->newstream = bb;
	p->writeready = cc;
	p->write = dd;
	p->asfile = ee;
	return 0;	
}
Notice that the last parameter b of the bb() has been equated to NP_ASFILE. The bb() is what newstream points to. This time round, when the function ee() is called, we display the value of f. This is the full URL of the stream, that is, the name and the location.

But at this point in time we are also calling the cc() (writeready ) and dd() (write ), though they are of little use . So as an intelligent measure, we return a large value from the cc() function. In this case, we return a large number (0xffffff, and that's hex) so that the cc() and the dd() do not get called again and again.

That boils down to two options. You can either save a file as the entire file on to your disk or pick up a small chunk at a time. For instance, if I am downloading an AVI file, I don't have to decide how and in what numbers to get the bytes. Windows 95 gives me a set of functions that can read, write or save a file an avi file on disk. Hence one way out is that we can download the entire file, as we do not know its internal format, and then let Windows take care of how it has to be manipulated. To do that we use asfile and return a large value from the writeready function. That should make it clear that when we use asfile , we want to tell Netscape we are not interested in each and every byte. On the other hand, if the avi file in question is a dozen of megabytes large, it will be a wiser idea to play it dynamically, as it comes in, rather than watching the paint on your walls dry up. With that erudition behind us, let us try out the following code...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[], NPSavedData *s)
{	sprintf(a, "In aa...i = %p", i);
	MessageBox(0, a, "hi", 0);
	return 0;
}
  
short bb(NPP i, char *p, NPStream *s, NPBool o, unsigned short *b)
{	sprintf(a, "In bb...i = %p", i);
	MessageBox(0, a, "hi", 0);
	*b = NP_ASFILE;
	return 0;
}

long cc(NPP i, NPStream *s)
{	sprintf(a, "In cc...i = %p", i);
	MessageBox(0, a, "hi", 0);
	return 0xffffff;
}

long dd(NPP i, NPStream *s, long o, long l, void *b)
{	sprintf(a, "In dd...i = %p", i);
	MessageBox(0, a, "hi", 0);	
	return l;
}

void ee(NPP i, NPStream *s, const char *f)
{	sprintf(a, "In ee i = %p", i);
	MessageBox(0, a, "hi", 0);
}

short ff(NPP i, NPWindow *w)
{	sprintf(a, "In ff i = %p", i);
	MessageBox(0, a, "hi", 0);	
	return 0;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp=aa;
	p->newstream=bb;
	p->writeready=cc;
	p->write=dd;
	p->asfile=ee;
	p->setwindow=ff;
	return 0;	
}
In case you overlooked, which you most surely have, all our functions invariably have a pointer to the structure NPP as one of their parameters. The value of this pointer is always the same irrespective of which function it is in. From a perspective, you can compare this pointer to the first parameter of the WinMain() in C under Windows. Remember the handle that identified a window uniquely? Well, our pointer i to NPP does very much the same job -- it uniquely identifies our window to Netscape. It can be brought to a spectacular amount of use when we have multiple embeds, as we will soon.

Unless you are running out of steam, try this one...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];
NPNetscapeFuncs *g;
NPP h;

class yyy:public CWnd
{	public:
	void OnLButtonDown(UINT, CPoint p)
	{	g->status(h, "hell");
		MessageBox("after status", "hi");
		g->geturl(h, "file:///d:/shanx/a2.html", "hello");
		MessageBox("after geturl", "hi");
	}
	DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(yyy,CWnd)
	ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

yyy *b;
CWinApp q;

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	g = p;
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[], NPSavedData *s)
{	MessageBox(0,  "in aa", "hi",0);
	h = i;
	return 0;
}
  
short bb(NPP i, NPWindow *w)
{	if (b == 0 &&  w->window)
	{	b = new yyy;
		b->SubclassWindow( (HWND)w->window );
	}
	return 0;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->setwindow = bb;
	return 0;	
}
A widget of wisdom before decoding that one. We always have a give-and-take situation in our programs. Here's a metaphor -- assuming we get two cars, one without petrol and one with the tank full. We can use the filled one right away. But for the one without petrol, we will need to fill up the tank before we can move ahead. The function NP_GetEntryPoints () is the car with an empty tank and the NP_Initialize is the other. Thats because when NP_GetEntryPoints gets called, it places a structure on the stack. This structure is NPPluginFuncs . Since we have got a structure, we give values to the various members of this structure. Putting the leg in the other foot, the NP_Initialize function creates a structure too, that is NPNetscapeFuncs , but it itself fills up the members with the addresses of functions in his code. All we then need to worry about is the address of that structure.

However, if we want to use the members of this structure, we can do so through the pointer which stores its address. In NP_Initialize , we have done it already in the pointer p . But the hitch there is that p dies as soon as it reaches the end of the braces for the function. So we reserve the address of this structure in a global pointer called g by equating it to p in the NP_Initialize . Now, we have two functions as members of NPNetscapeFuncs -- status() and geturl(). But these functions require, as a parameter, the instance handle of our embed. For reasons similar to NPNetscapeFuncs , a global pointer to the structure to NPP is created and initialized in the aa() . Since these pointers are global, they can be accessed in the LButtonDown(). So now each time you click with the Left Mouse Button, the status will show 'hell'. The geturl() is supposed to get the file that has been specified as the second parameter.

In case you overlooked, this is the way we can access the internals of Netscape. The geturl is something similar to selecting the File -> New Web Browser from your Netscape browser. So, you can now do about everything using your plug-ins that you can do through Netscape!.

Lets see if you are creative enough. When you load the HTML file in the Netscape browser, have you ever tried clicking on the BACK or the RELOAD ? Well, more often than not, it will fling problems in your face. As a good programming practice in C and C++, whenever we allocated memory with malloc or new, we made sure that we deleted or free d it too. Likewise, in the case of plug-ins, whenever we initialize the pointers to functions, subclass the Windows etc., it is usually a good idea to undo all that we have done with the memory. Have a go at the following code and see if you can figure out how we do that...


#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"

char a[100];

class yyy:public CWnd
{	public:
	WNDPROC *GetSuperWndProcAddr()
	{	return CWnd::GetSuperWndProcAddr();
	}
};

yyy *b;
CWinApp q;

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[], NPSavedData *s)
{	MessageBox(0, "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, NPWindow *w)
{	MessageBox(0, "in bb", "hi", 0);
	if (b==0 && w->window)
	{	b = new yyy;
		b->SubclassWindow( (HWND)w->window );
	}
	return 0;
}

short cc(NPP i, NPSavedData **s)
{	MessageBox(0, "in cc -- destroy", "hi", 0);
	WNDPROC *l = b->GetSuperWndProcAddr();
	::SetWindowLong( b->m_hWnd, GWL_WNDPROC, (LONG)*l );
	return 0;
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->setwindow = bb;
	p->destroy = cc;
	return 0;	
}

short _stdcall NP_Shutdown()
{	MessageBox(0, "in shutdown",  "in shutdown", 0);
	return 0;
}

 
NPPluginFuncs admittedly is a very useful structure. We use another of its variable called destroy , which we initialize to the function cc() . It is an intelligent programming practice to uninitialize, unsubclass etc. here. Netscape provides us with an additional function, the third one to be precise, labelled NP_Shutdown which gets called in the end to do its earmarked tasks. This function gets called by name and so we have to export it from the def file. Bunging in that one statement should not be a unaffordable responsibility. Here's what the def file will look like...

	oops.def
	LIBRARY OOPS
	EXPORT
		NP_GetEntryPoints
		NP_Initialize
		NP_Shutdown


Dabbling in AVI files

Now we are talking. This is what the jangle surrounding plug-ins is all about. The avi extension stands for Audio Video Interleave. That means it can conveniently play sound and show screenful of video at the same time. That does sound rather splashy, but following is the code for it. Before going further, make sure you do this:

#include<afxwin.h>
#include "npapi.h"
#include "npupp.h"
#include "vfw.h"

char a[100]; 
char c[100];

class yyy:public CWnd
{	public:
	void OnLButtonDown(UINT, CPoint p)
	{	HWND h;
		h = MCIWndCreate(this->GetSafeHwnd(), AfxGetInstanceHandle(),
         		WS_CHILD | WS_CAPTION | WS_VISIBLE | MCIWNDF_SHOWPOS | 				MCIWNDF_SHOWNAME, c);
	}
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(yyy, CWnd)
	ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

yyy *b;
CWinApp q;

short _stdcall NP_Initialize(NPNetscapeFuncs *p)
{	MessageBox(0, "in initialize", "in initialize", 0);
	return 0;	
}

short aa(char *p, NPP i, unsigned short m, short c, char * n[], 
	char *v[], NPSavedData *s)
{	MessageBox(0, "in aa", "hi", 0);
	return 0;
}
  
short bb(NPP i, NPWindow *w)
{	MessageBox(0, "in bb", "hi", 0);
	if (b == 0 && w->window)
	{	b = new yyy;
		b->SubclassWindow( (HWND)w->window );
	}
	return 0;
}

short cc(NPP i, char * p, NPStream *s, NPBool a, unsigned short *b)
{	MessageBox(0, "in cc", "hi", 0);
	*b = NP_ASFILE;
	return 0;
}
long dd(NPP i, NPStream *s)
{	MessageBox(0, "in dd", "hi", 0);
	return 0xffffff;
}
long ee(NPP i, NPStream *s, long o, long l, void *b)
{	return l;
}
void ff(NPP i, NPStream *s, const char *f)
{	strcpy(c, f);
	MessageBox(0, c, f,0);
}

short _stdcall NP_GetEntryPoints(NPPluginFuncs *p)
{	MessageBox(0, "in get entry points", "in get entry points", 0);
	p->newp = aa;
	p->setwindow = bb;
	p->newstream = cc;
	p->writeready = dd;
	p->write = ee;
	p->asfile = ff;
	return 0;	
}

short _stdcall NP_Shutdown()
{	MessageBox(0, "in shutdown", "in shutdown", 0);
	return 0;
}


The names that got lost

It took us a mouthful of gall to confront the alleged 'samples'. After scraping the innards of Netscape and yanking some meaning out of the hairy plug-in samples, we gave their spectacularly unsanitary code a thorough scrubbing. In the process, some grime (or rather some function names) got laundered. If you are not inordinately fond of jargon, this section is not for you. Nevertheless, here are some functions names as they liked to call them and as we fancy calling them...
The names that got lost
Their names Our names
NPP_New aa()
NPP_NewStream bb()
NPP_WriteReady cc()
NPP_Write dd()
NPP_StreamAsFile ee()
NPP_SetWindow ff()


Weak in the knees already? How about multiple embed statements ? Just speed to the next topic or pull up to see a real-life avi plug-in designed by some of our Netscape-diehards.

Got something that you are dying to tell someone but have no one to turn to? Well, this is not an agony column, but should you have any problems with Netscape plug-ins, help is just a click away...

Need a coffee break? Stop by our Java page and take a sip of the brand spanking new, sizzlin' beverage, the steam from which is wafting over the world!

Swivel round to Vijay Mukhi's Technology Cornucopia


Please note that this document really likes the Netscape browser


Vijay Mukhi's Computer Institute
B-13, Everest Building, Tardeo, Bombay 400 034, India.
http://www.vijaymukhi.com
e-mail : vmukhi@giasbm01.vsnl.net.in