目錄
設置瀏覽器中文環境,開啓npapi插件功能,並註冊身份證閱讀器插件(見第四節) 7
首先瀏覽器處理類要繼承CefDownloadHandler 類... 8
並提供回調接口(繼承任何處理類都要提供類似的回調接口)... 8
新建win32 dll工程,工程名以NP開頭,將上圖的文件引入工程。... 14
定義插件模塊,其中MIMEType,是在html中調用的關鍵字... 19
一、工具準備
- vs 2017 community
- cmake 3.7 +
- cef_binary_3.2357.1271.g8e0674e_windows32,包含已編譯好的c接口動態庫和c++接口源碼,C++接口默認沒有編譯,以源碼提供
二、編譯C++接口
生成vs工程
進入cef源碼根目錄,進入libcef_dll。此目錄是c++接口源碼目錄。C接口動態庫放在根目錄的Release目錄中。輸入命令cmake -G "Visual Studio 15",生成VS工程
打開vs工程
右擊項目“libcef_dll_wrapper”,設置頭文件包含目錄
加入預處理命令 NOMINMAX
生成“libcef_dll_wrapper”項目
生成的c++接口
三、實現瀏覽器
瀏覽器定製
新建一個win32GUI的空工程,將cef目錄下的cefsimple相關文件拷貝進來,cefsimple實現很簡單就是打開一個網頁,我們來新增一些功能
void SimpleApp::OnContextInitialized() {
CEF_REQUIRE_UI_THREAD();
// Information used when creating the native window.
CefWindowInfo window_info;
#if defined(OS_WIN)
// On Windows we need to specify certain flags that will be passed to
// CreateWindowEx().
window_info.SetAsPopup(NULL, "cefsimple");
#endif
// 設置窗口樣式
window_info.style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE;
UINT width = GetSystemMetrics(SM_CXSCREEN);
UINT height = GetSystemMetrics(SM_CYSCREEN);
window_info.parent_window = NULL;
window_info.x = -1;
window_info.y = -1;
window_info.width = width;
window_info.height = height;
// SimpleHandler implements browser-level callbacks.
CefRefPtr<SimpleHandler> handler(new SimpleHandler());
// Specify CEF browser settings here.
CefBrowserSettings browser_settings;
char * code = "UTF-8";
cef_string_t encode = {};
cef_string_utf8_to_utf16(code, strlen(code), &encode);
browser_settings.default_encoding = encode;
//設置窗口標題
WCHAR window_name[1024];
GetPrivateProfileStringW(L"GMS", L"title", L"", window_name, 1024, L".\\gms.ini");
cef_string_wide_to_utf16(window_name, wcslen(window_name), &window_info.window_name);
// 設置訪問地址
char url[1024];
GetPrivateProfileStringA("GMS", "url", "", url, 1024, ".\\gms.ini");
// Create the first browser window.
CefBrowserHost::CreateBrowser(window_info, handler.get(), url, browser_settings, NULL);
}
設置瀏覽器中文環境,開啓npapi插件功能,並註冊身份證閱讀器插件(見第四節)
void SimpleApp::OnBeforeCommandLineProcessing(const CefString& process_type, CefRefPtr<CefCommandLine> command_line) {
//開啓插件
command_line->AppendSwitch("--enable-npapi");
//設置中文語言環境
command_line->AppendSwitchWithValue("--lang", "zh-CN");
command_line->AppendSwitchWithValue("register-netscape-plugins","NPRDCARD.dll/nprdcard-plugin");
return;
}
文件下載
首先瀏覽器處理類要繼承CefDownloadHandler 類
virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() //實現
{
return this;
}
//重載文件下載方法
virtual void OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) OVERRIDE;
virtual void OnDownloadUpdated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback) OVERRIDE;
//文件下載方法重載
void SimpleHandler::OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback)
{
callback->Continue(download_item->GetURL(), true);
}
void SimpleHandler::OnDownloadUpdated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback)
{
if (download_item->IsComplete())
{
//MessageBox.Show("下載成功");
if (browser->IsPopup() && !browser->HasDocument())
{
//browser->GetHost()->ParentWindowWillClose();
browser->GetHost()->CloseBrowser(true);
}
}
}
F5刷新功能
virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() //實現
{
return this;
}
//按鍵處理
virtual bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event,
bool* is_keyboard_shortcut) OVERRIDE;
virtual bool OnKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event) OVERRIDE;
bool SimpleHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event,
bool* is_keyboard_shortcut) {
if(event.windows_key_code==116)//F5刷新
browser->Reload();
return false;
}
bool SimpleHandler::OnKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event) {
return false;
}
右鍵菜單添加刷新按鈕
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() //實現
{
return this;
}
// 右鍵菜單處理
virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model) OVERRIDE;
virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
int command_id,
EventFlags event_flags) OVERRIDE;
void SimpleHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model) {
if (model->GetCount() > 0) {// 刷新菜單
model->AddSeparator();
model->AddItem(ID_CMD_REFRESH, __TEXT("刷新"));
}
}
bool SimpleHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
int command_id,EventFlags event_flags) {
switch (command_id)
{
case ID_CMD_REFRESH:
browser->Reload();
break;
default:
break;
}
return false;
}
四、身份證閱讀器插件開發
工程建立
新建win32 dll工程,工程名以NP開頭,將上圖的文件引入工程。
//kk: common and often used headers
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <atlstr.h>
//Mozilla-API
#include <npfunctions.h>
#include <npruntime.h>
#include "npruntime.h"
#define TRACE __noop
並在plugin.cpp中引用此頭文件
功能實現
ScriptablePluginObject(NPP npp)
: ScriptablePluginObjectBase(npp)
{
//***************************加載神思模塊**************
hInstance = LoadLibrary("RdCard.dll");
if (!hInstance) {
::MessageBox(NULL, __TEXT("加載神思接口失敗,請檢查 RdCard.dll,重新打開頁面"), __T("提示"), MB_OK);
}
}
~ScriptablePluginObject() {
FreeLibrary(hInstance);
}
// 拓展 增加方法
// 獲取身份證姓名方法
static NPIdentifier sIdCardName_id;
//測試閱讀器是否連接
static NPIdentifier sIdCardStatus_id;
修改插件方法判斷函數
// ********************測試插件是否有此方法**********************
bool
ScriptablePluginObject::HasMethod(NPIdentifier name)
{
return (name == sFoo_id || name == sIdCardStatus_id || name == sIdCardName_id);
}
// 插件提供方法調用接口
bool
ScriptablePluginObject::Invoke(NPIdentifier name, const NPVariant *args,
uint32_t argCount, NPVariant *result)
{
if (name == sFoo_id) {// foo 方法
::MessageBox(NULL, __TEXT("開始調用foo方法"), __T("提示"), MB_OKCANCEL);
char* m_szTextGui = "我是foo方法調用返回的結果";
STRINGZ_TO_NPVARIANT(toGBK(m_szTextGui), *result);
return true;
}
else if(name == sIdCardStatus_id) {//測試身份證閱讀器是否連接
::MessageBox(NULL, __TEXT("開始調用IsConnect方法"), __T("提示"), MB_OKCANCEL);
typedef int (*FUN)(...);
FUN fun;
fun = (FUN)GetProcAddress(hInstance, "IsConnect");
if (!fun) {
::MessageBox(NULL, __TEXT(" RdCard.dll 中沒有 IsConnect 函數"), __T("提示"), MB_OK);
return false;
}
bool rst = fun();
BOOLEAN_TO_NPVARIANT(rst, *result);
return true;
}
else if (name == sIdCardName_id) {// 獲取身份證姓名
typedef int (*FUN)(...);
FUN fun;
fun = (FUN)GetProcAddress(hInstance, "GetName");
if (!fun) {
::MessageBox(NULL, __TEXT(" RdCard.dll 中沒有 GetName 函數"), __T("提示"), MB_OK);
return false;
}
::MessageBox(NULL, __TEXT("開始調用getName方法"), __T("提示"), MB_OKCANCEL);
char name[20];
fun(name);
STRINGZ_TO_NPVARIANT(toGBK(name),*result);
return true;
}
return false;
}
定義插件模塊,其中MIMEType,是在html中調用的關鍵字
將生成的NPRDCARD.dll放入瀏覽器目錄的plugins目錄下
身份證閱讀器依賴的dll放在瀏覽器可執行文件目錄下
測試身份證閱讀器是否連接
插件調試
點擊測試是否連接設備