#pragma once
#include "pluginbase.h"
class Plugin :
public nsPluginInstanceBase
{
private:
NPP m_pNPInstance;
NPBool m_bInitialized;
public:
Plugin(NPP pNPInstance);
~Plugin();
NPBool init(NPWindow* pNPWindow);
void shut();
NPBool isInitialized();
};
NPBool Plugin::init(NPWindow* pNPWindow)
{
m_bInitialized = TRUE;
return TRUE;
}
void Plugin::shut()
{
m_bInitialized = FALSE;
}
NPBool Plugin::isInitialized()
{
return m_bInitialized;
}
nsPluginInstanceBase * NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
if(!aCreateDataStruct)
return NULL;
Plugin * plugin = new Plugin(aCreateDataStruct->instance);
BOOL bWindowed = FALSE;
NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, (void *)bWindowed);//winless插件需要在这里指出,默认为windowed
return plugin;
}
用NPN_SetValue指定我们要创建的插件是winless的。上面的写法是中规中矩的写法,如果图省事可以写成NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, NULL);NPError Plugin::SetWindow(NPWindow* Window)
{
mWindow=Window;
return NPERR_NO_ERROR;
}
其他功能都要在事件处理函数中实现,因此基类的虚函数HandleEvent需要加以实现。
uint16_t Plugin::HandleEvent(void* aEvent)
{
NPEvent *event = (NPEvent *)aEvent;
switch(event->event)
{
case WM_PAINT:
{
if(!mWindow)
break;
// get the dirty rectangle to update or repaint the whole window
RECT * drc = (RECT *)event->lParam;
if(drc)
FillRect((HDC)event->wParam, drc, (HBRUSH)(COLOR_WINDOW));
else {
RECT rc;
rc.bottom = mWindow->y + mWindow->height;
rc.left = mWindow->x;
rc.right = mWindow->x + mWindow->width;
rc.top = mWindow->y;
FillRect((HDC)event->wParam, &rc, (HBRUSH)(COLOR_WINDOW));
}
break;
}
下一个功能:按下鼠标左键时发声:
case WM_LBUTTONDOWN:
Beep(1000,200);
break;
最后实现画线的功能,这也是真正展示处理窗口的window成员的地方:case WM_LBUTTONDOWN:
Beep(1000,200);
m_oldX=LOWORD(event->lParam);
m_OldY=HIWORD(event->lParam);
break;
接着实现鼠标移动的事件响应代码:
case WM_MOUSEMOVE:
{
m_newX=LOWORD(event->lParam);
m_newY=HIWORD(event->lParam);
HDC hDC = (HDC)mWindow->window;
MoveToEx(hDC,m_oldX,m_OldY,NULL);
LineTo(hDC,m_newX,m_newY);
m_oldX=m_newX;m_OldY=m_newY;
break;
}
这里直接将mWindow->window强制转换为HDC,是因为对于winless的插件window成员在windows平台下就是该插件的HDC。注意由于这里有变量hDC的定义,因此这个case的代码必须用大括号括起来,否则会报错。下面是事件处理函数最后一点代码:
default:
return 0;
}
return 1;
}
实现完毕之后,生成项目,然后用前面的测试页面对这个新的dll进行测试。如下图:
上面实现的有一个问题,就是只有窗口重绘的时候才会显示出画的线,但我想已经说明了window成员在winless类型的插件中的使用,因此就不深入研究了,如果谁看到这个例子能够给出好的改进意见,我将不胜感激。
可能有的朋友一步步跟下来之后发现还是有问题,下面贴出前面这个项目的plugin.h文件及plugin.cpp文件的完整内容
//Plugin.h文件
#pragma once
#include "pluginbase.h"
class Plugin :
public nsPluginInstanceBase
{
private:
NPP m_pNPInstance;
NPBool m_bInitialized;
NPWindow* mWindow;
int m_oldX,m_OldY,m_newX,m_newY;
bool bMdown;
public:
Plugin(NPP pNPInstance);
~Plugin();
NPBool init(NPWindow* pNPWindow);
void shut();
NPBool isInitialized();
NPError SetWindow(NPWindow* Window);
uint16_t HandleEvent(void* event);//windowed 插件窗口自己接收消息,不需handleevent。
};
//Plugin.cpp文件
#include "Plugin.h"
////// functions /////////
NPError NS_PluginInitialize()
{
return NPERR_NO_ERROR;
}
void NS_PluginShutdown()
{
}
nsPluginInstanceBase * NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
if(!aCreateDataStruct)
return NULL;
Plugin * plugin = new Plugin(aCreateDataStruct->instance);
BOOL bWindowed = FALSE;
NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, (void *)bWindowed);//winless插件需要在这里指出,默认为windowed
return plugin;
}
void NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
{
if(aPlugin)
delete (Plugin *)aPlugin;
}
////// Plugin /////////
Plugin::Plugin(NPP pNPInstance):nsPluginInstanceBase(),
m_pNPInstance(pNPInstance),
m_bInitialized(FALSE)
{
bMdown=false;
}
NPBool Plugin::init(NPWindow* pNPWindow)
{
m_bInitialized = TRUE;
return TRUE;
}
void Plugin::shut()
{
m_bInitialized = FALSE;
}
NPBool Plugin::isInitialized()
{
return m_bInitialized;
}
Plugin::~Plugin(void)
{
}
NPError Plugin::SetWindow(NPWindow* Window)
{
mWindow=Window;
return NPERR_NO_ERROR;
}
uint16_t Plugin::HandleEvent(void* aEvent)
{
NPEvent *event = (NPEvent *)aEvent;
switch(event->event)
{
case WM_PAINT:
{
if(!mWindow)
break;
// get the dirty rectangle to update or repaint the whole window
RECT * drc = (RECT *)event->lParam;
if(drc)
FillRect((HDC)event->wParam, drc, (HBRUSH)(COLOR_WINDOW));
else {
RECT rc;
rc.bottom = mWindow->y + mWindow->height;
rc.left = mWindow->x;
rc.right = mWindow->x + mWindow->width;
rc.top = mWindow->y;
FillRect((HDC)event->wParam, &rc, (HBRUSH)(COLOR_WINDOW));
}
break;
}
case WM_LBUTTONDOWN:
Beep(1000,200);
m_oldX=LOWORD(event->lParam);
m_OldY=HIWORD(event->lParam);
bMdown=true;
break;
case WM_MOUSEMOVE:
{
m_newX=LOWORD(event->lParam);
m_newY=HIWORD(event->lParam);
if (bMdown)
{
HDC hDC = (HDC)mWindow->window;
MoveToEx(hDC,m_oldX,m_OldY,NULL);
LineTo(hDC,m_newX,m_newY);
}
NPN_ForceRedraw(m_pNPInstance);
m_oldX=m_newX;m_OldY=m_newY;
break;
}
case WM_LBUTTONUP:
bMdown=false;NPN_ForceRedraw(m_pNPInstance);break;
default:
return 0;
}
//
return 1;
}
BOOL bWindowed = TRUE;
NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, (void *)bWindowed);//winless插件需要在这里指出,默认为windowed
也可以什么都不写,因为默认就是创建windowed的插件。这个例子实现两个功能:设置背景并在创建窗口中输出一段文字。static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);
static WNDPROC lpOldProc = NULL;
在类的构造函数中将m_hWnd初始化为NULLNPBool Plugin::init(NPWindow* pNPWindow)
{
mWindow=pNPWindow;
m_hWnd =(HWND)pNPWindow->window;
if (m_hWnd==NULL) return FALSE;
// 对窗口进行子类化,这样就可以对消息进行处理并在窗口中进行绘制
lpOldProc = SubclassWindow(m_hWnd, (WNDPROC)PluginWinProc);
// 将窗口与 Plugin 对象相关联,这样就可以在窗口处理中访问Plugin 对象
SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
m_bInitialized = TRUE;
return TRUE;
}
对于windowed的插件pNPWindow->window存储就是插件窗口的句柄,上面将其转换为HWND,并将窗口进行子类化,关键代码的作用请参看注释。将Plugin::shut修改为:void Plugin::shut()
{
// 反子类化subclass it back
SubclassWindow(m_hWnd, lpOldProc);
m_hWnd = NULL;
m_bInitialized = FALSE;
}
到这一步已经完成了对窗口句柄的获取与释放,最后还需要的就是消息处理函数了,如下:
static LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_PAINT:
{
// draw a frame and display some string
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
FillRect( hdc, &rc, (HBRUSH) (COLOR_WINDOW));
FrameRect(hdc, &rc, GetStockBrush(BLACK_BRUSH));
Plugin * p = (Plugin*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(p) {
char *s = "Hello , MY FIRST PLUGIN!";//p->GetGuiText();
DrawText(hdc, s, strlen(s), &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
EndPaint(hWnd, &ps);
}
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
这里只是对WM_PAINT消息进行了处理,其他消息用DefWindowProc进行默认的处理。在WM_PAINT的消息处理代码中我们为窗口设置了背景,并输出一段文字"Hello , MY FIRST PLUGIN!",没错,这就是我们的插件的hello world!!最后这个项目的plugin.h文件和plugin.cpp文件完整内容
//Plugin.h
#pragma once
#include "pluginbase.h"
class Plugin :
public nsPluginInstanceBase
{
private:
NPP m_pNPInstance;
NPBool m_bInitialized;
NPWindow* mWindow;
HWND m_hWnd;
public:
Plugin(NPP pNPInstance);
~Plugin();
NPBool init(NPWindow* pNPWindow);// { m_bInitialized = TRUE; return TRUE;}
void shut();// { m_bInitialized = FALSE; }
NPBool isInitialized();// { return m_bInitialized; }
};
//Plugin.cpp
#include "Plugin.h"
#include
////// functions /////////
NPError NS_PluginInitialize()
{
return NPERR_NO_ERROR;
}
void NS_PluginShutdown()
{
}
nsPluginInstanceBase * NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
if(!aCreateDataStruct)
return NULL;
Plugin * plugin = new Plugin(aCreateDataStruct->instance);
return plugin;
}
void NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
{
if(aPlugin)
delete (Plugin *)aPlugin;
}
////// Plugin /////////
Plugin::Plugin(NPP pNPInstance):nsPluginInstanceBase(),
m_pNPInstance(pNPInstance),
m_bInitialized(FALSE)
{
m_hWnd = NULL;
}
Plugin::~Plugin(void)
{
}
static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);
static WNDPROC lpOldProc = NULL;
NPBool Plugin::init(NPWindow* pNPWindow)
{
mWindow=pNPWindow;
m_hWnd =(HWND)pNPWindow->window;
if (m_hWnd==NULL) return FALSE;
// 对窗口进行子类化,这样就可以对消息进行处理并在窗口中进行绘制
lpOldProc = SubclassWindow(m_hWnd, (WNDPROC)PluginWinProc);
// 将窗口与 Plugin 对象相关联,这样就可以在窗口处理中访问Plugin 对象
SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
m_bInitialized = TRUE;
return TRUE;
}
void Plugin::shut()
{
// 将窗口子类化回去subclass it back
SubclassWindow(m_hWnd, lpOldProc);
m_hWnd = NULL;
m_bInitialized = FALSE;
}
NPBool Plugin::isInitialized()
{
return m_bInitialized;
}
static LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_PAINT:
{
// draw a frame and display some string
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
FillRect( hdc, &rc, (HBRUSH) (COLOR_WINDOW));
FrameRect(hdc, &rc, GetStockBrush(BLACK_BRUSH));
Plugin * p = (Plugin*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(p) {
char *s = "Hello , MY FIRST PLUGIN!";//p->GetGuiText();
DrawText(hdc, s, strlen(s), &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
EndPaint(hWnd, &ps);
}
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
注:写完本文之后我才发现,原来sdk中还有一个藏得比较深的例子,在basic目录下,这个例子就是windowed插件的最基本实现,有需要的可以参考参考。