⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 npwebwko.c

📁 c++ Builder中网络图象渐进传输实例
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C; tab-width: 4; -*- */
/* npwebwko.c
 * WebWKO - a Win32 browser plug-in that displays WKO image files
 * By Daniel Vollmer, based on WebBMP by Jason Summers
 */
#define PRGNAME "WebWKO Plug-in"
#define VERS    "1.0.0"

/* Note: Depending on your compiler, npwin.cpp may need to be altered by
 * wrapping the g_pNavigatorFuncs definition with 'extern "C"' as such:
 *
 *  extern "C" {
 *  NPNetscapeFuncs* g_pNavigatorFuncs = 0;
 *  }
 *
 */

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <process.h>
#include <time.h>
#include "npupp.h"
#include "npapi.h"
#include "resource.h"

#include "../wavelet/bit.h"
#include "../wavelet/wavelet.h"
#include "../wavelet/mchannel.h"

#define ST_NOTLOADED	0
#define ST_LOADED	1

#define DELAY_PER_3K 2
#define INITIAL_UPDATE_BITS 1024

#define INVALID_THREAD (NULL)

/*IE插件事件数据类型定义 */
typedef struct plugininstance_struct
{
	NPWindow*	fWindow; 
	uint16		fMode; 
	HWND		fhWnd;
	WNDPROC	fDefaultWindowProc;
	NPP			instance;

	char url[2048];		//数据流的url源
	int status;			//是否完成了图象的装载
					//若完成,取值ST_LOADED;否则取值ST_NOTLOADED。
	int streamend;		//传输数据流的大小,如果为0表示数据流大小未知
	int valid;			//图象属性是否有效
	unsigned int last_bits_drawn;
	time_t last_time_drawn;
	unsigned int update_bits;
	
	BITMAPINFO bi;	//解码BMP后的图象文件头信息
	HBITMAP dib;		//BMP图象数据
	unsigned int *dib_bits;

	int	wvh_is_yuv;
	t_wv_header wvh;
	
	CRITICAL_SECTION bitmap_lock;
	CRITICAL_SECTION lpbits_lock;
	HANDLE decode_thread, last_thread;

	unsigned char *lpbits;	//指向图象数据流的指针
	unsigned int bits_read;	//数据数据流的比特位数量
	int bytes_alloc;		//相应计算机字节内存分配的大小
} 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 UpdateBitmap(PluginInstance *This);
void PaintBitmap(PluginInstance *This, HDC hdc, RECT *rect);
void ContextMenu(PluginInstance *This, int x, int y, HWND hwnd);


/* ----------------------------------------------------------------------- */

BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved)
{
    switch(reason) {
    case DLL_PROCESS_ATTACH:
		hInst=hModule;
		break;
    case DLL_THREAD_ATTACH:
		break;
    case DLL_THREAD_DETACH:
		break;
    case DLL_PROCESS_DETACH:
		break;
    }
    return TRUE;
}


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=This->fhWnd;
	else
		hwnd=NULL;

	MessageBox(hwnd,buf,"WebWKO Plug-in",MB_OK|MB_ICONWARNING);
}


/* if enough of the image is loaded, extract its width, height, etc. */
void GetImageInfo(PluginInstance *This)
{
	t_bit_file *bf;

	/*********
	1 bit:	is yuv
	24 bits:magic number
	4 bits:	header version
	4 bits: bitstream version
	1 bit:	have non-pow2 dimensions
		16 bit:	width - 1
		16 bit: height - 1
	4 bits:	num channels - 1
	4 bits:	pow2 width
	4 bits:	pow2 height
	4 bits:	num blocks - 1
	5 bits:	size min block
	-----------------
	55 bits (dimension bit 0) or 87 bits (dimension bit 1)
	**********/
	
	if (!This->lpbits || This->bits_read < 87)
		return;

	bf = bit_open(This->lpbits, "rm", This->bits_read);
	if (bf)
	{
		t_wv_header hdr;

		This->wvh_is_yuv = bit_read(1, bf);
		if (wv_read_header(&hdr, bf) != NULL)
		{
			This->wvh = hdr;
			if (This->wvh.width >= 1 && This->wvh.height >= 1 && This->wvh.size_min_block > 0)
			{
				This->bi.bmiHeader.biSize = sizeof This->bi.bmiHeader;
				This->bi.bmiHeader.biWidth = This->wvh.owidth;
				This->bi.bmiHeader.biHeight = This->wvh.oheight;
				This->bi.bmiHeader.biPlanes = 1;
				This->bi.bmiHeader.biBitCount = 32;
				This->bi.bmiHeader.biCompression = BI_RGB;
				This->bi.bmiHeader.biSizeImage = This->wvh.owidth * This->wvh.oheight * 4;
				This->bi.bmiHeader.biXPelsPerMeter = This->bi.bmiHeader.biYPelsPerMeter = 0;
				This->bi.bmiHeader.biClrUsed = This->bi.bmiHeader.biClrImportant = 0;
				
				This->valid = 1;
			}
		}
		bit_close(bf, NULL);
	}
}


/* ----------------------------------------------------------------------- */

/* Global initialization */
NPError NPP_Initialize(void)
{
	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;
	
	if (!instance)
		return NPERR_INVALID_INSTANCE_ERROR;
	
	instance->pdata = malloc(sizeof (PluginInstance));
	This = (PluginInstance*)instance->pdata;
	if (!This)
	    return NPERR_OUT_OF_MEMORY_ERROR;

	memset(This, 0, sizeof *This);
	/* 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->lpbits = NULL;
	This->bits_read = 0;
	This->bytes_alloc=0;
	This->status=ST_NOTLOADED;
	This->valid=0;

	This->dib = NULL;
	This->dib_bits = NULL;

	This->decode_thread = This->last_thread = INVALID_THREAD;
	InitializeCriticalSection(&This->bitmap_lock);
	InitializeCriticalSection(&This->lpbits_lock);

	return NPERR_NO_ERROR;
}

NPError NPP_Destroy(NPP instance, NPSavedData** save)
{
	PluginInstance* This;

	if (!instance)
		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 (un-subclass it)
		SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
		This->fDefaultWindowProc = NULL;
		This->fhWnd = NULL;
	}

	if (This->last_thread != INVALID_THREAD)
	{
		WaitForSingleObject(This->last_thread, INFINITE);
		CloseHandle(This->last_thread);
		This->last_thread = INVALID_THREAD;
	}

	DeleteCriticalSection(&This->bitmap_lock);
	DeleteCriticalSection(&This->lpbits_lock);
	
	if (This->lpbits)
	{
		free(This->lpbits);
		This->lpbits = NULL;
		This->bytes_alloc = 0;
		This->bits_read = 0;
	}

	if (This->dib)
	{
		DeleteObject(This->dib);
		This->dib = NULL;
	}

	if (This)
	{
		if (instance->pdata)
		{
			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)
		return NPERR_INVALID_INSTANCE_ERROR;

	This = (PluginInstance*)instance->pdata;

	/* if( This->fWindow != NULL )  -- from example in Netscape's API, but not really correct */

	if (This->fhWnd)
	{   /* If we already have a window... */
		if ((!window) || (!window->window))
		{
			/* 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);
			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) || (!window->window))
	{
		/* 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, FALSE);
//	UpdateWindow(This->fhWnd);

	return result;
}


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;
	//保存数据流的url地址
	strncpy(This->url, stream->url, 2048);
	This->url[2047]='\0';

	*stype = NP_NORMAL;

	if (This->last_thread != INVALID_THREAD)
	{
		WaitForSingleObject(This->last_thread, INFINITE);
		CloseHandle(This->last_thread);
		This->last_thread = INVALID_THREAD;
	}

	if(This->lpbits)
	{
		free(This->lpbits);
		This->lpbits = NULL;
		This->bytes_alloc=0;
	}
	if (This->dib)
	{
		DeleteObject(This->dib);
		This->dib = NULL;
		This->dib_bits = NULL;
	}
	This->status=ST_NOTLOADED;
	This->streamend = stream->end;
	This->bits_read = 0;
	This->last_bits_drawn = 0;
	This->last_time_drawn = 0;
	This->last_time_drawn = time(NULL);
	This->update_bits = INITIAL_UPDATE_BITS;
	This->valid = 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;
//	return (int32)INITIAL_UPDATE_BITS / 8;
}


int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
{
	PluginInstance* This;
	int32 new_alloc;
	//如果插件事件无效,返回无效值
	if (!instance)
		return -1;
	//如果数据流为空,返回无效值
	This = (PluginInstance*)instance->pdata;
	if (!This)
		return -1;
	//创建新的数据空间
	new_alloc = This->bytes_alloc;
	if (!This->lpbits)
		new_alloc = This->streamend > 0 ? This->streamend : offset + len;
	new_alloc = max(new_alloc, offset + len);
	if (new_alloc != This->bytes_alloc)
	{
		EnterCriticalSection(&This->lpbits_lock);
		This->lpbits = realloc(This->lpbits, new_alloc);
		This->bytes_alloc = new_alloc;
		This->bits_read = (offset + len) * 8; 
		LeaveCriticalSection(&This->lpbits_lock);
		if (!This->lpbits)
		{
			warn(This,"Out of memory");
			return -1;
		}
		memset(This->lpbits + This->bytes_alloc, 0, new_alloc - This->bytes_alloc);
	}
	else
		This->bits_read = (offset + len) * 8; // hopefully we read everything _before_ that, too...
	
	memcpy(This->lpbits + offset, buffer, len);
	
	if (!This->valid)
		GetImageInfo(This);
	if (This->fhWnd && This->valid && This->bits_read - This->last_bits_drawn >= This->update_bits)
	{
		//渐进显示
		time_t ct;
		int timeofs;

		/*因为在IE的同一个图象区域显示不同的图象,都是以渐进传输显示的方式处理图象数据,
		特别是当图象的尺寸与IE的显示区域不相同的时候,将影响渐进传输过程。为了防止这种
		情况,必须确定最后一次数据更新后的时耗总量。*/
		ct = time(NULL);

		timeofs = ((This->wvh.width + This->wvh.height) * This->wvh.num_channels * DELAY_PER_3K) / (3 * 1024);
		if (ct - This->last_time_drawn >= timeofs)
			UpdateBitmap(This);
	}
	//函数返回有效的数据字节数,系统将处理其全部接收到的数据
	return len;
}




NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
{
	PluginInstance* This;
	//如果插件事件无效,返回无效值
	if (!instance)
		return NPERR_INVALID_INSTANCE_ERROR;
	This = (PluginInstance*)instance->pdata;
	if (!This)
		return NPERR_INVALID_INSTANCE_ERROR;

	if (!This->valid)
		GetImageInfo(This);
	
	if (reason == NPRES_DONE)
	{
		This->status = This->valid ? ST_LOADED : ST_NOTLOADED;

		if (!This->valid)
			warn(This, "Invalid WKO image");
	}
	
	if (This->fhWnd && This->bits_read - This->last_bits_drawn > 0)
	{
		if (This->last_thread != INVALID_THREAD)
		{
			WaitForSingleObject(This->last_thread, INFINITE);
			CloseHandle(This->last_thread);
			This->last_thread = INVALID_THREAD;
		}
		// 如果数据流装载没有完成,同样更新IE窗口
		UpdateBitmap(This); 
	}
	//返回默认有效值
	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)
{
	return;
}

/* Print embedded plug-in (via the browser's Print command) */
void NPP_Print(NPP instance, NPPrint* printInfo)
{
	PluginInstance* This;
	
	if (!instance)
		return;
	This = (PluginInstance*) instance->pdata;
	if (!This)
		return;

	if (!This->valid)
		return;

	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();  */     /* not implemented */
		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 :-(.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -