webbmp.c
资源名称:webbmp.zip [点击查看]
上传用户:juruiw
上传日期:2007-01-04
资源大小:101k
文件大小:30k
源码类别:
PlugIns编程
开发平台:
Visual C++
- #include <windows.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <stdarg.h>
- #include "npupp.h"
- #include "npapi.h"
- #include "resource.h"
- NPError NPN_GetValue(NPP instance, NPNVariable variable, void *ret_value);
- #define DLLFILENAME "npwebbmp.dll"
- #define PRGNAME "WebBMP Plug-in"
- #define VERS "1.1.0"
- #define FHS 14 /* bitmap file header size ( == sizeof(BITMAPFILEHEADER) )*/
- #define ST_NOTLOADED 0
- #define ST_LOADED 1
- /* plugin-specific data */
- typedef struct
- {
- NPWindow* fWindow;
- uint16 fMode;
- HWND fhWnd;
- WNDPROC fDefaultWindowProc;
- NPP instance;
- int windowless;
- char url[2048]; /* the url of the stream */
- int status; /* is the image finished loading? (either ST_LOADED or ST_NOTLOADED) */
- LPBITMAPINFOHEADER lpdib; /* the memory block we're storing the image in */
- int diballoc; /* number of bytes allocated for hdib */
- int dibused; /* number of bytes read into the DIB so far (there may be unused bytes in hdib)
- * if status==ST_LOADED, this equals the size of the DIB */
- int streamend; /* size of stream, or 0 if unknown */
- BITMAPFILEHEADER fileheader;
- int imgwidth,imgheight, imgbpp, imgcompr, palettesize;
- int prevpainted;
- FILETIME lastpaint; /* used to prevent repainting too often during progressive display */
- } PluginInstance;
- /* global variables */
- extern NPNetscapeFuncs* g_pNavigatorFuncs;
- const char* gInstanceLookupString = "pdata";
- HMODULE hInst;
- HMENU hmenuContext=NULL;
- /* forward declarations of functions */
- LRESULT CALLBACK DlgProcAbout(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
- LRESULT CALLBACK PluginWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
- void PaintBitmap(PluginInstance *This, HDC hdc, RECT *rect, int erase);
- void ContextMenu(PluginInstance *This, int x, int y, HWND hwnd);
- /* ----------------------------------------------------------------------- */
- /* safe version of strncpy, which always null-terminates strings */
- void Strncpy(char *dest, const char *src, int len)
- {
- if(src) {
- strncpy(dest,src,len-1);
- dest[len-1]=' ';
- }
- else dest[0]=' ';
- }
- HWND GetHWND(PluginInstance *This)
- {
- HWND hwnd;
- if(!This->windowless) {
- return This->fhWnd;
- }
- NPN_GetValue(This->instance, NPNVnetscapeWindow, (void*)&hwnd);
- return hwnd;
- }
- void warn(PluginInstance *This, char *fmt, ...)
- {
- va_list ap;
- char buf[2048];
- HWND hwnd;
- va_start(ap, fmt);
- vsprintf(buf,fmt, ap);
- va_end(ap);
- if(This) hwnd=GetHWND(This);
- else hwnd=NULL;
- MessageBox(hwnd,buf,"WebBMP Plug-in",MB_OK|MB_ICONWARNING);
- }
- void WindowlessPaint(PluginInstance *This)
- {
- HDC hdc;
- RECT rect;
- if(!This->fWindow) return;
- if(!This->fWindow->window) return;
- /* This is to work around an problem where Netscape initially
- * makes spurious one or more SetWindow calls with coordinates of (0,0).
- * This isn't a perfect fix, since (0,0) is sometimes the correct
- * coordinates. */
- if( !This->prevpainted && This->fMode==NP_EMBED &&
- This->fWindow->x==0 && This->fWindow->y==0)
- {
- return;
- }
- This->prevpainted=1;
- hdc=(HDC)(This->fWindow->window);
- rect.left= This->fWindow->x;
- rect.top= This->fWindow->y;
- rect.right= This->fWindow->width;
- rect.bottom= This->fWindow->height;
- PaintBitmap(This, hdc, &rect, 1);
- }
- /* ----------------------------------------------------------------------- */
- /* Global initialization */
- NPError NPP_Initialize(void)
- {
- hInst=GetModuleHandle(DLLFILENAME);
- if(!hInst) {
- warn(NULL,"Cannot load resources. Make sure plug-in file is named %s",DLLFILENAME);
- }
- hmenuContext=LoadMenu(hInst,"CONTEXTMENU");
- return NPERR_NO_ERROR;
- }
- /* Global shutdown */
- void NPP_Shutdown(void)
- {
- if(hmenuContext) DestroyMenu(hmenuContext);
- }
- /* Once-per-instance initialization */
- NPError NPP_New(NPMIMEType pluginType,NPP instance,uint16 mode,
- int16 argc,char* argn[],char* argv[],NPSavedData* saved)
- {
- PluginInstance* This;
- int i;
- if (instance == NULL) {
- return NPERR_INVALID_INSTANCE_ERROR;
- }
- /* instance->pdata = NPN_MemAlloc(sizeof(PluginInstance)); */
- instance->pdata = malloc(sizeof(PluginInstance));
- This = (PluginInstance*) instance->pdata;
- if (This == NULL) {
- return NPERR_OUT_OF_MEMORY_ERROR;
- }
- This->windowless=0;
- /* examine the <embed> tag argumente */
- for(i=0;i<argc;i++) {
- if(!_stricmp(argn[i],"windowless")) {
- if(atoi(argv[i])==1) This->windowless=1;
- }
- }
- /* record some info for later lookup */
- This->fWindow = NULL;
- This->fMode = mode;
- This->fhWnd = NULL;
- This->fDefaultWindowProc = NULL;
- This->instance = instance; /* save the instance id for reverse lookups */
- This->lpdib=NULL;
- This->diballoc=0;
- This->dibused=0;
- This->status=ST_NOTLOADED;
- This->prevpainted=0;
- if(This->windowless) {
- /* tell the browser we are windowless */
- NPN_SetValue(This->instance,NPPVpluginWindowBool,(void*)0);
- /* tell the browser if we are opaque(0) or transparent(1) */
- NPN_SetValue(This->instance,NPPVpluginTransparentBool,(void*)0);
- }
- return NPERR_NO_ERROR;
- }
- NPError NPP_Destroy(NPP instance, NPSavedData** save)
- {
- PluginInstance* This;
- if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR;
- This = (PluginInstance*) instance->pdata;
- if(!This) return NPERR_INVALID_INSTANCE_ERROR;
- if( This->fhWnd ) { /* If we have a window, clean it up. */
- SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
- This->fDefaultWindowProc = NULL;
- This->fhWnd = NULL;
- }
- if(This->lpdib) {
- GlobalFree(This->lpdib);
- This->lpdib=NULL;
- This->diballoc=0;
- }
- if (This != NULL) {
- if(instance->pdata)
- /* NPN_MemFree(instance->pdata); -- seems to crash IE sometimes... */
- free(instance->pdata);
- instance->pdata = NULL;
- }
- return NPERR_NO_ERROR;
- }
- jref NPP_GetJavaClass(void)
- {
- return NULL;
- }
- /* Browser is providing us with a window */
- NPError NPP_SetWindow(NPP instance, NPWindow* window)
- {
- NPError result = NPERR_NO_ERROR;
- PluginInstance* This;
- if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR;
- This = (PluginInstance*) instance->pdata;
- if(This->windowless) {
- This->fhWnd = NULL;
- This->fWindow = window;
- WindowlessPaint(This);
- return NPERR_NO_ERROR;
- }
- /* if( This->fWindow != NULL ) -- from example in Netscape's API, but not really correct */
- if( This->fhWnd != NULL ) { /* If we already have a window... */
- if( (window == NULL) || ( window->window == NULL ) ) {
- /* There is now no window to use. get rid of the old
- * one and exit. */
- SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
- This->fDefaultWindowProc = NULL;
- This->fhWnd = NULL;
- This->fWindow=window;
- return NPERR_NO_ERROR;
- }
- else if ( This->fhWnd == (HWND) window->window ) {
- /* The new window is the same as the old one. Redraw and get out. */
- This->fWindow=window;
- InvalidateRect( This->fhWnd, NULL, FALSE );
- /* UpdateWindow( This->fhWnd ); */
- return NPERR_NO_ERROR;
- }
- else {
- /* Unsubclass the old window, so that we can subclass the new
- * one later. */
- SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
- This->fDefaultWindowProc = NULL;
- This->fhWnd = NULL;
- }
- }
- else if( (window == NULL) || ( window->window == NULL ) ) {
- /* We can just get out of here if there is no current
- * window and there is no new window to use. */
- This->fWindow=window;
- return NPERR_NO_ERROR;
- }
- /* Subclass the new window so that we can begin drawing and
- * receiving window messages. */
- This->fDefaultWindowProc = (WNDPROC)SetWindowLong( (HWND)window->window, GWL_WNDPROC, (LONG)PluginWindowProc);
- This->fhWnd = (HWND) window->window;
- SetProp( This->fhWnd, gInstanceLookupString, (HANDLE)This);
- This->fWindow = window;
- InvalidateRect( This->fhWnd, NULL, TRUE );
- UpdateWindow( This->fhWnd );
- return result;
- }
- /*+++++++++++++++++++++++++++++++++++++++++++++++++
- * NPP_NewStream:
- * Notifies an instance of a new data stream and returns an error value.
- *
- * NPP_NewStream notifies the instance denoted by instance of the creation of
- * a new stream specifed by stream. The NPStream* pointer is valid until the
- * stream is destroyed. The MIME type of the stream is provided by the
- * parameter type.
- +++++++++++++++++++++++++++++++++++++++++++++++++*/
- NPError NPP_NewStream(NPP instance,NPMIMEType type,NPStream *stream,
- NPBool seekable,uint16 *stype) {
- PluginInstance* This;
- if(instance==NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
- This = (PluginInstance*) instance->pdata;
- if(!This)
- return NPERR_GENERIC_ERROR;
- /* save the URL for later */
- Strncpy(This->url,stream->url,2048);
- /* (*stype)=NP_ASFILE; -- request stream to be given as a file */
- if(This->lpdib) {
- GlobalFree(This->lpdib);
- This->lpdib=NULL;
- This->diballoc=0;
- }
- This->status=ST_NOTLOADED;
- This->streamend=stream->end;
- This->lastpaint.dwLowDateTime = This->lastpaint.dwHighDateTime = 0;
- return NPERR_NO_ERROR;
- }
- int32 NPP_WriteReady(NPP instance, NPStream *stream)
- {
- /* Number of bytes ready to accept in NPP_Write() */
- /* We can handle any amount, so just return some really big number. */
- return (int32)0X0FFFFFFF;
- }
- /*+++++++++++++++++++++++++++++++++++++++++++++++++
- * NPP_Write:
- * Delivers data from a stream and returns the number of bytes written.
- *
- * NPP_Write is called after a call to NPP_NewStream in which the plug-in
- * requested a normal-mode stream, in which the data in the stream is delivered
- * progressively over a series of calls to NPP_WriteReady and NPP_Write. The
- * function delivers a buffer buf of len bytes of data from the stream identified
- * by stream to the instance. The parameter offset is the logical position of
- * buf from the beginning of the data in the stream.
- *
- * The function returns the number of bytes written (consumed by the instance).
- * A negative return value causes an error on the stream, which will
- * subsequently be destroyed via a call to NPP_DestroyStream.
- *
- * Note that a plug-in must consume at least as many bytes as it indicated in the
- * preceeding NPP_WriteReady call. All data consumed must be either processed
- * immediately or copied to memory allocated by the plug-in: the buf parameter
- * is not persistent.
- +++++++++++++++++++++++++++++++++++++++++++++++++*/
- int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
- {
- PluginInstance* This;
- int32 amt;
- unsigned char *tmphdr, *tmp1;
- void *tmp_from, *tmp_to;
- int alloc, n;
- if (instance == NULL) return -1;
- This = (PluginInstance*) instance->pdata;
- if(offset<FHS) {
- tmphdr=(unsigned char*)(&This->fileheader);
- amt=FHS-offset;
- if(amt>len) amt=len;
- CopyMemory(&tmphdr[offset],buffer,amt);
- }
- if(offset+len > FHS) {
- if(!This->lpdib) {
- /* Allocate a memory block for the whole image, but how big should
- * it be? If the stream size is available from the browser, we'll
- * use that. Otherwise we'll use the info from the header of the BMP
- * file (it's not as reliable, though). */
- if(This->streamend>0) {
- alloc=This->streamend - FHS;
- }
- else {
- /* This will normally allocate 14 extra bytes. Some BMP files
- * have a size indicator that's 14 bytes off, so this protects
- * against that. */
- alloc=This->fileheader.bfSize /* - FHS */ ;
- }
- if(alloc<128) alloc=128;
- This->lpdib=(void*)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,alloc);
- This->diballoc=alloc;
- }
- if(!This->lpdib) {
- warn(This,"Out of memory");
- return -1;
- }
- if(This->diballoc < offset+len-FHS) {
- /* Oops, our memory block isn't big enough for the whole file.
- * --> Bump it up by 128K or so.
- * This will only happen if the BMP had an incorrect file size
- * in the header. Unfortunately that is common. */
- This->diballoc=offset+len+131072;
- This->lpdib=GlobalReAlloc(This->lpdib,This->diballoc, GMEM_ZEROINIT);
- }
- if(!This->lpdib) {
- warn(This,"Out of memory");
- return -1;
- }
- tmp1=(unsigned char*)(buffer);
- if(offset<FHS) {
- tmp_from= &tmp1[FHS-offset];
- tmp_to= (void*)This->lpdib;
- n=len-(FHS-offset);
- }
- else {
- tmp_from=tmp1;
- tmp_to= (void*)& ((unsigned char*)This->lpdib)[offset-FHS];
- n=len;
- }
- CopyMemory(tmp_to,tmp_from,n);
- }
- This->dibused = offset + len - FHS;
- /* progressive display */
- if(This->windowless) {
- /* WindowlessPaint(This); */
- }
- else if(This->fhWnd) {
- RECT r;
- HDC hdc;
- FILETIME ft;
- /* Since we repaint the whole image every time we do a progressive
- * display update, it can slow things down if we do this too often,
- * especially if the image is being scaled to a different size. To
- * prevent this, we make sure a certain amount of time has elapsed
- * since the last update */
- /* FILETIME (dwLoDateTime) is in 100 ns intervals, so 10000 == 1 second
- *
- * The comparison has a small bug in it that is not important here,
- * so don't copy this code without understanding it! */
- GetSystemTimeAsFileTime(&ft);
- if( (ft.dwHighDateTime > This->lastpaint.dwHighDateTime) ||
- (ft.dwLowDateTime > This->lastpaint.dwLowDateTime + 10000))
- {
- This->lastpaint.dwHighDateTime = ft.dwHighDateTime;
- This->lastpaint.dwLowDateTime = ft.dwLowDateTime;
- GetClientRect(This->fhWnd,&r);
- hdc=GetDC(This->fhWnd);
- PaintBitmap(This,hdc,&r,0); /* FIXME maybe should be 1 first time? */
- ReleaseDC(This->fhWnd,hdc);
- }
- }
- return len; /* The number of bytes accepted -- we always accept them all. */
- }
- /* DestroyStream gets called after the file has finished loading,
- */
- NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
- {
- PluginInstance* This;
- if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR;;
- This = (PluginInstance*) instance->pdata;
- if(reason==NPRES_DONE) {
- This->status=ST_LOADED;
- if(This->lpdib) {
- /* Record some image metrics for convenience.
- * Except for imgcompr(ession), these are inessential and
- * only used in the About dialog. */
- This->imgwidth = (int)This->lpdib->biWidth;
- This->imgheight = (int)This->lpdib->biHeight;
- This->imgbpp = (int)This->lpdib->biBitCount;
- This->imgcompr = (int)This->lpdib->biCompression;
- This->palettesize=0;
- if(This->imgbpp<=8) { /* paletted */
- if(This->lpdib->biSize>=36) { /* does header have an entry for palette size? */
- This->palettesize=This->lpdib->biClrUsed;
- }
- if(This->palettesize==0) { /* zero (or nonexistent) means maximum */
- This->palettesize= (1<<This->imgbpp);
- }
- }
- }
- /* Now that we have the whole image, draw it. */
- if(This->windowless) {
- WindowlessPaint(This);
- }
- else if(This->fhWnd) {
- InvalidateRect(This->fhWnd,NULL,FALSE);
- UpdateWindow(This->fhWnd);
- }
- }
- return NPERR_NO_ERROR;
- }
- /* This should not get called, since we aren't using the NP_ASFILE mode */
- void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
- {
- PluginInstance* This;
- if (instance == NULL) return;
- This = (PluginInstance*) instance->pdata;
- }
- /* Print embedded plug-in (via the browser's Print command) */
- void NPP_Print(NPP instance, NPPrint* printInfo)
- {
- PluginInstance* This;
- if (instance == NULL) return;
- This = (PluginInstance*) instance->pdata;
- if(printInfo == NULL) {
- /* Though it's not documented, if a Netscape user tries to print a full-page
- * plugin, the browser will call NPP_Print with printInfo set to NULL.
- * At this point you should print your plug-in in whatever manner you
- * choose. */
- /* PrintFullPage(); */
- return;
- }
- if (printInfo->mode == NP_FULL) {
- /* the plugin is full-page, and the browser is giving it a chance
- * to print in the manner of its choosing */
- void* platformPrint = printInfo->print.fullPrint.platformPrint;
- NPBool printOne = printInfo->print.fullPrint.printOne;
- /* Setting this to FALSE and returning *should* cause the browser to
- * call NPP_Print again, this time with mode=NP_EMBED.
- * However, that doesn't happen with any browser I've ever seen :-(.
- * Instead of the following line, you will probably need to implement
- * printing yourself. You also might as well set pluginPrinted to TRUE,
- * though every browser I've tested ignores it. */
- printInfo->print.fullPrint.pluginPrinted = FALSE;
- /* or */
- /* PrintFullPage();
- * printInfo->print.fullPrint.pluginPrinted = TRUE; */
- }
- else { /* If not fullscreen, we must be embedded */
- HDC pdc;
- int prevstretchmode;
- NPWindow* printWindow;
- if(This->status != ST_LOADED) return;
- printWindow= &(printInfo->print.embedPrint.window);
- /* embedPrint.platformPrint is a Windows device context in disguise */
- /* The definition of NPWindow changed between API verion 0.9 and 0.11,
- * increasing in size from 28 to 32 bytes. This normally makes it
- * impossible for version 0.9 browsers to print version 0.11 plugins
- * (because the platformPrint field ends up at the wrong offset) --
- * unless the plugin takes special care to detect this situation.
- * To work around it, if we are compiled with API 0.11 or higher,
- * and the browser is version 0.9 or earlier, we look for the HDC
- * 4 bytes earlier, at offset 28 instead of 32 (of the embedPrint
- * sub-structure).
- */
- if(sizeof(NPWindow)>28 && /* i.e. is plugin API >= 0.11? */
- HIBYTE(g_pNavigatorFuncs->version)==0 &&
- LOBYTE(g_pNavigatorFuncs->version)<=9) {
- char *tmpc;
- HDC *tmph;
- tmpc= (char*)&(printInfo->print.embedPrint);
- tmph= (HDC*)&tmpc[28];
- pdc= *tmph;
- }
- else {
- pdc= (HDC) (printInfo->print.embedPrint.platformPrint);
- }
- if(!This->lpdib) return;
- prevstretchmode=SetStretchBltMode(pdc,COLORONCOLOR);
- StretchDIBits(pdc,
- printWindow->x,printWindow->y,
- printWindow->width,printWindow->height, /* dest coords */
- 0,0,This->lpdib->biWidth, This->lpdib->biHeight, /* source coords */
- &((BYTE*)(This->lpdib))[This->fileheader.bfOffBits - FHS],
- (LPBITMAPINFO)This->lpdib,DIB_RGB_COLORS,SRCCOPY);
- if(prevstretchmode) SetStretchBltMode(pdc,prevstretchmode);
- }
- }
- /*+++++++++++++++++++++++++++++++++++++++++++++++++
- * NPP_URLNotify:
- * Notifies the instance of the completion of a URL request.
- +++++++++++++++++++++++++++++++++++++++++++++++++*/
- void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
- {
- }
- /*+++++++++++++++++++++++++++++++++++++++++++++++++
- * NPP_HandleEvent:
- * With normal windowed plugins, this is used only for Macs.
- * With windowless plugins, it is where everything happens.
- If the plug-in handles the event, the function should return true.
- If the plug-in ignores the event, the function returns false.
- +++++++++++++++++++++++++++++++++++++++++++++++++*/
- int16 NPP_HandleEvent(NPP instance, void* event)
- {
- NPEvent *ev;
- PluginInstance* This;
- HWND hwnd;
- POINT pt;
- if (instance == NULL) return 0;
- This = (PluginInstance*) instance->pdata;
- if(!This->windowless) return 0;
- if(This->fWindow==NULL) return 0;
- ev= (NPEvent*)event;
- switch( (UINT)ev->event ) {
- case WM_PAINT:
- WindowlessPaint(This);
- return 1;
- case WM_CONTEXTMENU: case WM_RBUTTONDOWN:
- hwnd=GetHWND(This);
- /* ContextMenu(This,LOWORD(ev->lParam),HIWORD(ev->lParam),hwnd); */
- GetCursorPos(&pt);
- ContextMenu(This,pt.x,pt.y,hwnd);
- return 1;
- case WM_LBUTTONDBLCLK: /* Netscape crashes (!) if you return 0 on a double-click */
- case WM_LBUTTONDOWN:
- return 1;
- }
- return 0;
- }
- /**********************************************************************/
- /* draw bitmap from DIB
- * rect: I am abusing the definition of RECT, and using rect->right,bottom as
- * width,height instead of absolute coordinates (it didn't matter until
- * I added windowless mode).
- * erase: 1==erase background first
- */
- void PaintBitmap(PluginInstance *This, HDC hdc, RECT *rect1, int erase)
- {
- int prevstretchmode;
- HPEN oldpen;
- HBRUSH oldbrush;
- RECT rect;
- /* make a local copy */
- rect.left=rect1->left; rect.top=rect1->top;
- rect.right=rect1->right; rect.bottom=rect1->bottom;
- if(erase) {
- oldpen=SelectObject(hdc,GetStockObject(NULL_PEN));
- oldbrush=SelectObject(hdc,GetStockObject(WHITE_BRUSH));
- Rectangle(hdc,rect1->left,rect1->top,
- rect1->left+rect1->right+1,rect1->top+rect1->bottom+1);
- if(oldpen) SelectObject(hdc,oldpen);
- if(oldbrush) SelectObject(hdc,oldbrush);
- }
- /* We consider displaying it only if it is completely loaded, or if
- * the complete header has been loaded */
- if(!This->lpdib) return;
- if(This->status!=ST_LOADED) {
- /* Is enough loaded to do progressive display? */
- if(This->dibused < sizeof(BITMAPINFOHEADER)) return;
- /* Progressive display of compressed images would be difficult to do,
- * so we don't do it. So there! */
- if(This->lpdib->biCompression==BI_RLE4 ||
- This->lpdib->biCompression==BI_RLE8) return;
- }
- /* Show full-screen images their natural size, unless they don't fit
- * in the browser, in which case scale them down (the Right Thing to do
- * would be to create scroll bars, etc.) */
- if(This->fMode==NP_FULL) {
- int w,h,x,y;
- w=This->lpdib->biWidth;
- h=This->lpdib->biHeight;
- /* reduce size if needed */
- if(w>rect.right) {
- h= (int)(((double)h * (double)rect.right)/(double)w);
- w= rect.right;
- }
- if(h>rect.bottom) {
- w= (int)(((double)w * (double)rect.bottom)/(double)h);
- h= rect.bottom;
- }
- /* center the image if there's room */
- if(w < rect.right) x=(rect.right-w)/2; else x=0;
- if(h < rect.bottom) y=(rect.bottom-h)/2; else y=0;
- rect.left=x;
- rect.right=w;
- rect.top=y;
- rect.bottom=h;
- }
- prevstretchmode=SetStretchBltMode(hdc,COLORONCOLOR);
- StretchDIBits(hdc,
- rect.left,rect.top,rect.right,rect.bottom, /* dest */
- 0,0,This->lpdib->biWidth, This->lpdib->biHeight, /* source */
- &((BYTE*)(This->lpdib))[This->fileheader.bfOffBits - FHS],
- (LPBITMAPINFO)This->lpdib,DIB_RGB_COLORS,SRCCOPY);
- if(prevstretchmode) SetStretchBltMode(hdc,prevstretchmode);
- }
- void CopyToClipboard(PluginInstance *This,unsigned char *mem,int size,UINT format)
- {
- HGLOBAL hClip;
- LPVOID lpClip;
- if(!mem) return;
- if(!OpenClipboard(NULL)) {
- warn(This,"Can't open the clipboard");
- return;
- }
- if(EmptyClipboard()) {
- hClip=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,size);
- lpClip=GlobalLock(hClip);
- if(lpClip) {
- CopyMemory(lpClip,mem,size);
- GlobalUnlock(hClip);
- if(!SetClipboardData(format,hClip)) {
- warn(This,"Can't set clipboard data");
- }
- }
- else {
- warn(This,"Can't allocate memory for clipboard");
- }
- }
- else {
- warn(This,"Can't clear the clipboard");
- }
- CloseClipboard();
- }
- int SaveToBMPFile(PluginInstance *This, char *filename)
- {
- HANDLE hFile;
- DWORD written;
- if(!This->lpdib) return 0;
- hFile=CreateFile(filename,GENERIC_WRITE,0,NULL,
- CREATE_ALWAYS,0,NULL);
- if(hFile==INVALID_HANDLE_VALUE) {
- warn(This,"Could not save file '%s'",filename);
- return 0;
- }
- /* First write our copy of the file header, then the DIB.
- * That should result in an exact copy of the original file. */
- WriteFile(hFile,(LPVOID)&(This->fileheader),FHS,&written,NULL);
- WriteFile(hFile,This->lpdib,This->dibused,&written,NULL);
- CloseHandle(hFile);
- return 1;
- }
- /* A vitally important feature ;-) */
- void SetAsWallpaper(PluginInstance *This, int tiled)
- {
- char fn[512];
- HKEY key;
- LONG rv;
- if(!This->lpdib || This->status!=ST_LOADED) {
- warn(This,"Image not loaded. Can't set as wallpaper");
- return;
- }
- GetWindowsDirectory(fn,256);
- strcat(fn,"\WebBMP Wallpaper.bmp");
- if(!SaveToBMPFile(This,fn)) return;
- rv=RegOpenKeyEx(HKEY_CURRENT_USER,"Control Panel\desktop",
- (DWORD)0,KEY_SET_VALUE,&key);
- if(rv==ERROR_SUCCESS) {
- RegSetValueEx(key,"Wallpaper",0,REG_SZ,(BYTE*)fn,1+strlen(fn));
- RegSetValueEx(key,"TileWallpaper",0,REG_SZ,tiled?"1":"0",2);
- RegCloseKey(key);
- }
- SystemParametersInfo(SPI_SETDESKWALLPAPER,(UINT)0,(PVOID)fn,SPIF_SENDCHANGE);
- }
- /* Try to make a filename from the url. Caller must provide fn[256] buffer.
- * This function attempts to extract a bitmap filename from a URL,
- * but if it doesn't look like it contains an appropriate name,
- * it leaves it blank.
- * (No matter what Microsoft thinks, URLs are *not* filenames!) */
- void url2filename(char *fn, char *url)
- {
- int title,ext,i;
- strcpy(fn,"");
- ext=0; /* position of the file extention */
- title=0; /* position of the base filename */
- for(i=0;url[i];i++) {
- if(url[i]=='.') ext=i+1;
- if(url[i]=='/') title=i+1;
- if(url[i]==':') title=i+1;
- if(url[i]=='=') title=i+1;
- }
- if(!_stricmp(&url[ext],"bmp")) {
- Strncpy(fn,&url[title],256);
- }
- }
- /* Write the image to a local file; see SaveToBMPFile() */
- void SaveImage(PluginInstance *This)
- {
- OPENFILENAME ofn;
- char fn[MAX_PATH];
- if(This->status != ST_LOADED) {
- warn(This,"Image not loaded -- can't save");
- return;
- }
- if(strlen(This->url)) {
- url2filename(fn,This->url);
- }
- else {
- strcpy(fn,"");
- }
- ZeroMemory(&ofn,sizeof(OPENFILENAME));
- ofn.lStructSize=sizeof(OPENFILENAME);
- ofn.hwndOwner=GetHWND(This);
- ofn.lpstrFilter="BMP (*.bmp) *.bmp ";
- ofn.nFilterIndex=1;
- ofn.lpstrTitle="Save Image As...";
- ofn.lpstrFile=fn;
- ofn.nMaxFile=MAX_PATH;
- ofn.Flags=OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT;
- ofn.lpstrDefExt="bmp";
- if(GetSaveFileName(&ofn)) {
- SaveToBMPFile(This,ofn.lpstrFile);
- }
- }
- void AboutDialog(PluginInstance *This)
- {
- DialogBoxParam(hInst,"ABOUTDLG",GetHWND(This),(DLGPROC)DlgProcAbout,(LPARAM)This);
- }
- void ContextMenu(PluginInstance *This, int x, int y, HWND hwnd)
- {
- HMENU sub;
- int cmd;
- sub=GetSubMenu(hmenuContext,0);
- cmd=TrackPopupMenuEx(sub, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_NONOTIFY|TPM_RETURNCMD|
- TPM_RIGHTBUTTON,x,y,hwnd,NULL);
- switch(cmd) {
- case ID_SAVEAS: SaveImage(This); break;
- case ID_COPYIMAGE:
- if(This->status==ST_LOADED && This->lpdib) {
- CopyToClipboard(This,(unsigned char*)This->lpdib,This->dibused,CF_DIB);
- }
- else {
- warn(This,"No image to copy");
- }
- break;
- case ID_COPYURL:
- if(strlen(This->url)) {
- CopyToClipboard(This,This->url,strlen(This->url)+1,CF_TEXT);
- }
- else {
- warn(This,"No link to copy");
- }
- break;
- case ID_SETASWALLPAPERC: SetAsWallpaper(This,0); break;
- case ID_SETASWALLPAPERT: SetAsWallpaper(This,1); break;
- case ID_VIEWIMAGE:
- if(strlen(This->url))
- NPN_GetURL(This->instance,This->url,"_self");
- break;
- case ID_ABOUT: AboutDialog(This); break;
- }
- }
- /*+++++++++++++++++++++++++++++++++++++++++++++++++
- * PluginWindowProc
- * Handle the Windows window-event loop.
- +++++++++++++++++++++++++++++++++++++++++++++++++*/
- LRESULT CALLBACK PluginWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
- {
- PluginInstance* This = (PluginInstance*) GetProp(hWnd, gInstanceLookupString);
- if(!This) return DefWindowProc( hWnd, Msg, wParam, lParam);
- switch(Msg) {
- case WM_ERASEBKGND:
- /* Disable background-erasing. It seems a little unreliable, so we'll
- * do it ourselves in WM_PAINT */
- return 1;
- case WM_CONTEXTMENU:
- ContextMenu(This,LOWORD(lParam),HIWORD(lParam), hWnd);
- return 0;
- case WM_PAINT:
- {
- PAINTSTRUCT paintStruct;
- HDC hdc;
- RECT rect;
- hdc = BeginPaint( hWnd, &paintStruct );
- GetClientRect(hWnd,&rect);
- PaintBitmap(This, hdc, &rect, 1);
- EndPaint( hWnd, &paintStruct );
- return 0;
- }
- }
- /* Forward unprocessed messages on to their original destination
- * (the window proc we replaced) */
- return This->fDefaultWindowProc(hWnd, Msg, wParam, lParam);
- }
- char *GetCompressionName(int c)
- {
- switch(c) {
- case BI_RGB:
- case BI_BITFIELDS: return "None";
- case BI_RLE4: return "RLE4";
- case BI_RLE8: return "RLE8";
- }
- return "Unknown";
- }
- LRESULT CALLBACK DlgProcAbout(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
- {
- switch(Msg) {
- case WM_INITDIALOG:
- {
- char buf[4096];
- char info[1024];
- DWORD tabs[1];
- PluginInstance *This=(PluginInstance*)lParam;
- tabs[0]= 60;
- SendDlgItemMessage(hWnd,IDC_IMGINFO,EM_SETTABSTOPS,(WPARAM)1,(LPARAM)tabs);
- sprintf(buf,"WebBMP Plug-in, Version %srn%s"
- #ifdef _DEBUG
- " DEBUG BUILD"
- #endif
- "rnBy Jason Summers"
- ,VERS,__DATE__);
- SetDlgItemText(hWnd,IDC_PRGINFO,buf);
- sprintf(buf,"URL:t%srn",This->url);
- if(This->status==ST_LOADED) {
- sprintf(info,"Size:t%d bytesrn",(int)(This->dibused+FHS));
- strcat(buf,info);
- #ifdef _DEBUG
- sprintf(info,"Reported size:t%d bytesrn",(int)This->fileheader.bfSize);
- strcat(buf,info);
- sprintf(info,"Memory alloc:t%d bytesrn",(int)(This->diballoc+FHS));
- strcat(buf,info);
- #endif
- sprintf(info,"Dimensions:t%d x %d pixelsrn",This->imgwidth,This->imgheight);
- strcat(buf,info);
- sprintf(info,"Bits/pixel:t%drn",This->imgbpp);
- strcat(buf,info);
- sprintf(info,"Palette entries:t%drn",This->palettesize);
- strcat(buf,info);
- sprintf(info,"Compression:t%srn",GetCompressionName((int)This->imgcompr));
- strcat(buf,info);
- }
- sprintf(info,"Browser:t%srn",NPN_UserAgent(This->instance));
- strcat(buf,info);
- sprintf(info,"Browser API:t%d.%drn",HIBYTE(g_pNavigatorFuncs->version),
- LOBYTE(g_pNavigatorFuncs->version));
- strcat(buf,info);
- sprintf(info,"Plug-in API:t%d.%drn",NP_VERSION_MAJOR,NP_VERSION_MINOR);
- strcat(buf,info);
- sprintf(info,"Mode:t%srn",This->windowless?" Windowless":" Windowed");
- strcat(buf,info);
- SetDlgItemText(hWnd,IDC_IMGINFO,buf);
- }
- return(TRUE);
- case WM_CLOSE:
- EndDialog(hWnd,0);
- return(TRUE);
- case WM_COMMAND:
- switch(wParam) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hWnd,0);
- return(TRUE);
- }
- }
- return(FALSE);
- }