由於接觸NP插件的時間還是比較短,下面總結一下自己對NP插件的理解。
NP插件還是對現有類的重載,然後實現自己想用的方法。在後面會具體的講怎麼用這樣的方法。
1、NP插件所要用到的官方的文件:
A、npapi.h
B、npfunctions.h
C、npruntime.h
D、nptypes.h
上面是幾個要用到的頭文件
A、np_entry.cpp
B、npn_gate.cpp
C、npp_gate.cpp
上面是要用到的源文件
2、下面說一下具體的創建dll的過程
A、開始創建工程
首先創建一個win32動態庫的空項目,如上圖所示。
B、然後將上面提到的所要用到的頭文件和源文件加入到工程中。我的工程的目錄如下 所示:
其中上面所提到的頭文件在include文件夾中。添加完成之後編譯一下代碼。這時候會 報找不到上面提到的頭文件錯誤這時候要設置頭文件的查找路徑,方法如下:
向C/C++=〉常規=〉附加包含目錄,加入所要引用的頭文件的目錄。
再次編譯上面的代碼,你會發現不會報找不到上面提到的幾個頭文件。但是會包一個找 不到Plugin.h文件。在這裏Plugin.h文件並不是官方提供的,而是我們自己要添加的文 件。所以要添加plugin.h文件,方法如下:
一般情況下是添加一個類的形式添加頭文件和源文件,因爲在Plugin.h文件中必須實現 一個CPlugin的類。
添加這個類之後,還是會報很多的錯誤,這就是沒有添加自己要填寫的代碼的緣故。
在Plugin.h文件中添加下面幾個頭文件的引用:
#include "npapi.h"
#include "npruntime.h"
#include <windef.h>
再編譯程序,你會發現程序的錯誤明顯的減少了,但是還是有錯誤,錯誤信息如下:
c:\program files (x86)\windows kits\8.1\include\um\winnt.h(147): fatal error C1189: #error : "No Target Architecture"
通過查閱資料我發現編譯這個工程需要定義許多的宏定義,下面說一下需要添加什麼宏 定義。這時我在windows下定義的宏定義:(debug模式下)
_DEBUG
MOZILLA_STRICT_API
XP_WIN
WIN32
_WINDOWS
_X86_
_USRDLL
MYSECONDNP_EXPORTS
在如下圖所示的位置添加:
再重新編譯代碼還是報錯,是不是感覺錯誤太多了啊。我也不想再弄了。太麻煩,但是 要用,不弄還不行。硬着頭皮吧。
發現CPlugin類必須有一固定格式的構造函數,如下所示:
CPlugin(NPP pNPInstance);
修改之後編譯還是會報錯,經過錯誤信息判斷是CPlugin類中有好多的函數沒有實現所 導致的。
下面就添加這些函數,你會發現沒添加一個函數,錯誤就會少一個。所以要將所有的函 數都添加進去。
下面展示一下將所有的函數都添加之後的CPlugin類:
class CPlugin
{
public:
CPlugin(NPP pNPInstance);
~CPlugin();
// 關閉
void shut();
// 判斷是否進行了初始化
NPBool isInitialized();
// 初始化插件窗口
NPBool init(NPWindow* pNPWindow);
// 獲取一個處理消息的對象
NPObject *GetScriptableObject();
// 處理時間,但這裏只是對蘋果的事件進行了處理
int16_t handleEvent(void* event);
private:
NPWindow * m_Window;
// 這個參數應該是沒有使用
NPStream * m_pNPStream;
// 保存插件是否進行了初始化工作
NPBool m_bInitialized;
// 保存提供方法對象
NPObject *m_pScriptableObject;
};
現在這個工程是可以編譯通過的。證明整個的工程的基本的框架是可以用的。下面就是 實現你的功能了。
首先說一下m_pScriptableObject 成員變量保存的是什麼。其實就是一個後面 會講到的一個類的對象。這個對象主要的作用就是處理插件提供給網頁端的函數處理 類。下面說一下這個類層次結構:
首先封裝一個類,這個類是繼承自NPObject類的,這個類是一個抽象類,所以我們封 裝一箇中間類,下面展示一下這個中間類:
class ScriptablePluginObjectBase : public NPObject
{
public:
ScriptablePluginObjectBase(NPP npp);
virtual ~ScriptablePluginObjectBase();
virtual void Invalidate();
virtual bool HasMethod(NPIdentifier name);
virtual bool Invoke(NPIdentifier name, const NPVariant *args,uint32_t argCount, NPVariant *result);
virtual bool InvokeDefault(const NPVariant *args, uint32_t argCount,NPVariant *result);
virtual bool HasProperty(NPIdentifier name);
virtual bool GetProperty(NPIdentifier name, NPVariant *result);
virtual bool SetProperty(NPIdentifier name, const NPVariant *value);
virtual bool RemoveProperty(NPIdentifier name);
virtual bool Enumerate(NPIdentifier **identifier, uint32_t *count);
virtual bool Construct(const NPVariant *args, uint32_t argCount, NPVariant *result);
public:
static void _Deallocate(NPObject *npobj);
static void _Invalidate(NPObject *npobj);
static bool _HasMethod(NPObject *npobj, NPIdentifier name);
static bool _Invoke(NPObject *npobj, NPIdentifier name,const NPVariant *args, uint32_t argCount,NPVariant *result);
static bool _InvokeDefault(NPObject *npobj, const NPVariant *args,uint32_t argCount, NPVariant *result);
static bool _HasProperty(NPObject * npobj, NPIdentifier name);
static bool _GetProperty(NPObject *npobj, NPIdentifier name,NPVariant *result);
static bool _SetProperty(NPObject *npobj, NPIdentifier name,const NPVariant *value);
static bool _RemoveProperty(NPObject *npobj, NPIdentifier name);
static bool _Enumerate(NPObject *npobj, NPIdentifier **identifier,uint32_t *count);
static bool _Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result);
protected:
NPP mNpp;
};
在上面的這個類中所有的函數幾乎都沒有實現,只是重寫了一下, 保存這個中間類不是一個抽象類。以後所有的操作類都繼承自這 箇中間類,就不必將所有的函數都重寫了。是程序的編寫更加的 方便。
下面看一下中間類都幹了些什麼吧,看看實現:
void ScriptablePluginObjectBase::Invalidate()
{
}
bool ScriptablePluginObjectBase::HasMethod(NPIdentifier name)
{
return false;
}
bool ScriptablePluginObjectBase::Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return false;
}
bool ScriptablePluginObjectBase::InvokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return false;
}
bool ScriptablePluginObjectBase::HasProperty(NPIdentifier name)
{
return false;
}
bool ScriptablePluginObjectBase::GetProperty(NPIdentifier name, NPVariant *result)
{
return false;
}
bool ScriptablePluginObjectBase::SetProperty(NPIdentifier name, const NPVariant *value)
{
return true;
}
bool ScriptablePluginObjectBase::RemoveProperty(NPIdentifier name)
{
return false;
}
bool ScriptablePluginObjectBase::Enumerate(NPIdentifier **identifier,uint32_t *count)
{
return false;
}
bool ScriptablePluginObjectBase::Construct(const NPVariant *args, uint32_t argCount,NPVariant *result)
{
return false;
}
// static
void ScriptablePluginObjectBase::_Deallocate(NPObject *npobj)
{
//調用虛析構函數
delete (ScriptablePluginObjectBase *)npobj;
}
// static 刷新
void ScriptablePluginObjectBase::_Invalidate(NPObject *npobj)
{
((ScriptablePluginObjectBase *)npobj)->Invalidate();
}
// static 判斷NPIdentifier對應的函數是不是存在
bool ScriptablePluginObjectBase::_HasMethod(NPObject *npobj, NPIdentifier name)
{
return ((ScriptablePluginObjectBase *)npobj)->HasMethod(name);
}
// static
bool ScriptablePluginObjectBase::_Invoke(NPObject *npobj, NPIdentifier name,const NPVariant *args, uint32_t argCount,NPVariant *result)
{
return ((ScriptablePluginObjectBase *)npobj)->Invoke(name, args, argCount,result);
}
// static
bool ScriptablePluginObjectBase::_InvokeDefault(NPObject *npobj,const NPVariant *args,uint32_t argCount,NPVariant *result)
{
return ((ScriptablePluginObjectBase *)npobj)->InvokeDefault(args, argCount,result);
}
// static
bool ScriptablePluginObjectBase::_HasProperty(NPObject * npobj, NPIdentifier name)
{
return ((ScriptablePluginObjectBase *)npobj)->HasProperty(name);
}
// static
bool ScriptablePluginObjectBase::_GetProperty(NPObject *npobj, NPIdentifier name,NPVariant *result)
{
return ((ScriptablePluginObjectBase *)npobj)->GetProperty(name, result);
}
// static
bool ScriptablePluginObjectBase::_SetProperty(NPObject *npobj, NPIdentifier name,const NPVariant *value)
{
return ((ScriptablePluginObjectBase *)npobj)->SetProperty(name, value);
}
// static
bool ScriptablePluginObjectBase::_RemoveProperty(NPObject *npobj, NPIdentifier name)
{
return ((ScriptablePluginObjectBase *)npobj)->RemoveProperty(name);
}
// static
bool ScriptablePluginObjectBase::_Enumerate(NPObject *npobj,NPIdentifier **identifier,uint32_t *count)
{
return ((ScriptablePluginObjectBase *)npobj)->Enumerate(identifier, count);
}
// static
bool ScriptablePluginObjectBase::_Construct(NPObject *npobj, const NPVariant *args,uint32_t argCount, NPVariant *result)
{
return ((ScriptablePluginObjectBase *)npobj)->Construct(args, argCount,result);
}
看看實現吧,確實什麼都沒做。
下面就要看一下函數和屬性處理的具體的類了,這個類繼承自中間類,在其中實現你想要的函數即可,簡單實現如下所示:
class ScriptablePluginObject : public ScriptablePluginObjectBase
{
public:
ScriptablePluginObject(NPP npp);
~ScriptablePluginObject();
virtual bool HasMethod(NPIdentifier name);
virtual bool HasProperty(NPIdentifier name);
virtual bool GetProperty(NPIdentifier name, NPVariant *result);
virtual bool SetProperty(NPIdentifier name, const NPVariant *value);
virtual bool Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result);
virtual bool InvokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result);
public:
char m_szTextGui[200];
HWND m_hWnd;
private:
char *m_pszName;
};
具體裏面怎麼實現的就看demo中的代碼吧。這裏不再寫了,寫多了你也不想看。不如在vs上面看着舒服。
C、下面看一下NP插件的特殊的設置,如果不這樣設置,插件將不能被調用。
添加def文件,文件名npMySecond.def
LIBRARY NPMYSECONDNP
EXPORTS
NP_GetEntryPoints @1
NP_Initialize @2
NP_Shutdown @3
NP_GetMIMEDescription @4
前三個函數是必須導出的,第四個根據需要導出。
添加Version資源文件,npMySecond.rc
查看代碼,然後修改裏面的一些內容。
將block改爲 BLOCK "040904e4"
添加VALUE
VALUE "MIMEType", "application/npMySecond"
經過上面的努力之後聲稱的插件就能用了。
下面介紹一下測試方法:
編輯註冊表
HKEY_CURRENT_USER\Software\MozillaPlugins下
新建子項@mozilla.com.cn/Second
並新建字符串值“Path”設值爲dll的全路徑
打開火狐瀏覽器 在地址欄輸入“about:plugins” 如果在plugin列表中有本例的npMySecondNp.dll及說明我們的plugin示例已經成功完成,
PS:
1.如果沒有,請再次查看BLOCK 的值是否是040904e4(僅僅是我遇到的)
2. 輸入about:config設置plugin.expose_full_path 設爲 true,可顯示dll全路徑
11.測試頁面
<HTML>
<HEAD>
</HEAD>
<BODY>
<embed type="application/npMySecond">
</BODY>
</HTML>