CEF3 C++接口实现自定义浏览器[simple version]

目录

目录... 1

一、工具准备... 2

二、编译C++接口... 2

三、实现浏览器... 5

浏览器定制... 5

浏览器默认最大化,标题从配置文件读取... 5

设置浏览器中文环境,开启npapi插件功能,并注册身份证阅读器插件(见第四节)    7

文件下载... 8

首先浏览器处理类要继承CefDownloadHandler 类... 8

并提供回调接口(继承任何处理类都要提供类似的回调接口)... 8

文件下载具体重载函数... 8

文件下载重载函数实现... 9

F5刷新功能... 10

继承按键处理类... 10

提供回调接口... 10

重载声明... 11

重载实现... 11

右键菜单添加刷新按钮... 12

继承菜单处理类... 12

提供回调接口... 12

重载声明... 12

重载实现... 13

四、身份证阅读器插件开发... 14

工程建立... 14

首先下载npapi插件开发包,解压进入... 14

新建win32 dll工程,工程名以NP开头,将上图的文件引入工程。... 14

新建stdafx.h头文件,加入... 15

设置预处理... 16

设置头文件包含... 16

功能实现... 17

加载身份证识别模块... 17

定义功能标识... 17

实现具体功能... 18

定义插件模块,其中MIMEType,是在html中调用的关键字... 19

生成插件... 20

插件部署... 20

插件测试... 21

插件调试... 23

浏览器增加启动参数... 23

启动浏览器... 24

在vs中打好断点,附加到进程... 24

进入断点... 25

 

一、工具准备

  1. vs 2017 community
  2. cmake 3.7 +
  3. 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;

}

四、身份证阅读器插件开发

工程建立

首先下载npapi插件开发包,解压进入

新建win32 dll工程,工程名以NP开头,将上图的文件引入工程。

 

新建stdafx.h头文件,加入

//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放在浏览器可执行文件目录下

 

插件测试

测试身份证阅读器是否连接

 

插件调试

浏览器增加启动参数

启动浏览器

在vs中打好断点,附加到进程

 

点击测试是否连接设备

进入断点

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章