目录
设置浏览器中文环境,开启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放在浏览器可执行文件目录下
测试身份证阅读器是否连接
插件调试
点击测试是否连接设备