chrome PPAPI 开发(一)

您所在的位置:网站首页 金属制品公司名称大全免费 chrome PPAPI 开发(一)

chrome PPAPI 开发(一)

#chrome PPAPI 开发(一)| 来源: 网络整理| 查看: 265

    最近遇到一个需要在chrome49版本的浏览器上支持老版本 ActiveX 插件的问题。     在网上翻来覆去找资料,最终的矛头都指向chrome的 PPAPI 开发,于是下载了一个ppapi的资源包。大家可从“我的资源”去下载。     下面说一下如何开发一个可调试的ppapi 例子的过程。     1. 环境准备     安装Visual Studio。我的是VS2013。     2. 解压ppapi 资源包到某个目录,例如 D://APIs/BHO-master/     3. 在VS2013中新建一个最简单的 Win32 的DLL(C++ 工程),去掉StdAfx.h 和StdAfx.cpp 文件。     4. 在工程主文件中输入代码。

#include #include #include #include #include

#include "Win32Project1.h"

#include "ppapi/c/pp_completion_callback.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" #include "ppapi/c/pp_rect.h" #include "ppapi/c/pp_var.h" #include "ppapi/c/ppb.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_graphics_2d.h" #include "ppapi/c/ppb_image_data.h" #include "ppapi/c/ppb_instance.h" #include "ppapi/c/ppb_view.h" #include "ppapi/c/ppp.h" #include "ppapi/c/ppp_instance.h" #include "ppapi/c/ppb_input_event.h" #include "ppapi/c/ppp_input_event.h"

#include "ppapi/c/ppb_var.h" #include "ppapi/c/ppb_var_dictionary.h" #include "ppapi/c/ppb_var_array.h" #include "ppapi/c/ppb_messaging.h" #include "ppapi/c/ppp_messaging.h" #include

PPB_GetInterface g_get_browser_interface = NULL;

const PPB_Core* g_core_interface; const PPB_Graphics2D* g_graphics_2d_interface; const PPB_ImageData* g_image_data_interface; const PPB_Instance* g_instance_interface; const PPB_View* g_view_interface; const PPB_InputEvent *g_input_interface; const PPB_MouseInputEvent *g_mouse_interface;

const PPB_Var* g_var_interface; const PPB_VarDictionary *g_dictionary_interface; const PPB_VarArray *g_array_interface; const PPB_Messaging *g_message_interface;

/******foruok: create native window begin******/

static HWND g_child_window = NULL; struct CreateChildWinParam {     struct PP_Rect r;     HWND hWndParent; }; HANDLE g_hThread = NULL; DWORD g_dwThreadId = 0; BOOL g_bInProcess = 0;

static LRESULT CALLBACK VideoWindowProc(HWND hwnd,     UINT uMsg,     WPARAM wParam,     LPARAM lParam     ) {     PAINTSTRUCT ps;     HDC hdc;     RECT r;     TCHAR textIn[] = _T("Child Window(in-process)");     TCHAR text[] = _T("Child Window(out-process)");     switch (uMsg)     {     case WM_PAINT:         GetClientRect(hwnd, &r);         hdc = BeginPaint(hwnd, &ps);         SetTextColor(hdc, RGB(0, 200, 0));         FillRect(hdc, &r, (HBRUSH)GetStockObject(GRAY_BRUSH));         if (g_bInProcess)         {             TextOut(hdc, 10, 50, textIn, ARRAYSIZE(textIn) - 1);         }         else         {             TextOut(hdc, 10, 50, text, ARRAYSIZE(text) - 1);         }         EndPaint(hwnd, &ps);         return 0;     }     return DefWindowProc(hwnd, uMsg, wParam, lParam); }

static void RegisterVideoWindowClass() {     WNDCLASSEX wcex = {         /* cbSize = */ sizeof(WNDCLASSEX),         /* style = */ CS_HREDRAW | CS_VREDRAW,         /* lpfnWndProc = */ VideoWindowProc,         /* cbClsExtra = */ 0,         /* cbWndExtra = */ 0,         /* hInstance = */ GetModuleHandle(NULL),         /* hIcon = */ NULL,         /* hCursor = */ LoadCursor(NULL, IDC_ARROW),         /* hbrBackground = */ 0,         /* lpszMenuName = */ NULL,         /* lpszClassName = */ _T("_ChildWindowClass"),         /* hIconSm = */ NULL,     };     RegisterClassEx(&wcex); }

DWORD WINAPI ThreadProc(LPVOID lpParam) {     MSG msg;

    struct CreateChildWinParam *para = (struct CreateChildWinParam *)lpParam;

    TCHAR szLog[256] = { 0 };     g_child_window = CreateWindowEx(0, _T("_ChildWindowClass"), _T("ChildWindow"),         para->hWndParent == NULL ? (WS_OVERLAPPEDWINDOW | WS_VISIBLE) : (WS_CHILD | WS_VISIBLE | WS_DISABLED),         para->r.point.x, para->r.point.y, para->r.size.width, para->r.size.height,         para->hWndParent, NULL, GetModuleHandle(NULL), NULL);     _stprintf_s(szLog, 256, _T("create child window(standalone msg loop) at (%d, %d) child = 0x%08x\r\n"),         para->r.point.x, para->r.point.y,         g_child_window);     OutputDebugString(szLog);

    BOOL fGotMessage;     while ((fGotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && fGotMessage != -1)     {         TranslateMessage(&msg);         if (msg.message == WM_USER && msg.hwnd == NULL)         {             OutputDebugString(_T("child window message loop quit\r\n"));             g_dwThreadId = 0;             g_hThread = NULL;             g_child_window = NULL;             return 0;         }         DispatchMessage(&msg);     }     return msg.wParam; }

void CreateChildWindowOnMainThread(void *param, int32_t result) {     struct CreateChildWinParam *p = (struct CreateChildWinParam *)param;     g_child_window = CreateWindowEx(0, _T("_ChildWindowClass"), _T("ChildWindow"),         WS_CHILD | WS_VISIBLE,         p->r.point.x, p->r.point.y, p->r.size.width, p->r.size.height,         p->hWndParent, NULL, GetModuleHandle(NULL), NULL);     TCHAR szLog[256] = { 0 };     _stprintf_s(szLog, 256, _T("create child window(in-process) at (%d, %d) child = 0x%08x\r\n"),         p->r.point.x, p->r.point.y,         g_child_window);     OutputDebugString(szLog);     ShowWindow(g_child_window, SW_SHOW);     UpdateWindow(g_child_window); }

void CreateChildWindow(struct PP_Rect *r) {     HWND hwnd = FindWindowEx(NULL, NULL, _T("CefBrowserWindow"), NULL);     HWND hwndWeb = FindWindowEx(hwnd, NULL, _T("Chrome_WidgetWin_0"), NULL);;     /*if (hwndWeb)     {     hwndWeb = FindWindowEx(hwndWeb, NULL, _T("Chrome_RenderWidgetHostHWND"), NULL); //web contents     }*/     if (hwndWeb != NULL)OutputDebugString(_T("Got Chrome_RenderWidgetHostHWND\r\n"));     DWORD pluginPid = GetCurrentProcessId();     DWORD browserPid = 0;     GetWindowThreadProcessId(hwnd, &browserPid);     TCHAR szLog[256] = { 0 };     _stprintf_s(szLog, 256, _T("Browser pid - %d, plugin pid - %d, brower hwnd - 0x%08x, webpage hwnd - 0x%08x\r\n"),         browserPid, pluginPid, hwnd, hwndWeb);     OutputDebugString(szLog);     struct CreateChildWinParam *para = (CreateChildWinParam *)(struct PP_Rect *)malloc(sizeof(struct CreateChildWinParam));     para->r = *r;     para->hWndParent = hwndWeb;

    if (browserPid == pluginPid)     {         g_bInProcess = TRUE;         g_core_interface->CallOnMainThread(0, PP_MakeCompletionCallback(CreateChildWindowOnMainThread, para), 0);     }     else     {         g_bInProcess = FALSE;         g_hThread = CreateThread(NULL, 0, ThreadProc, para, 0, &g_dwThreadId);         if (g_hThread != NULL)         {             OutputDebugString(_T("Launch child window thread.\r\n"));         }         else         {             OutputDebugString(_T("Launch child window thread FAILED!\r\n"));         }     } }

/* PPP_Instance implementation -----------------------------------------------*/

struct InstanceInfo {     PP_Instance pp_instance;     struct PP_Size last_size;     PP_Resource graphics;

    struct InstanceInfo* next; };

/** Linked list of all live instances. */ struct InstanceInfo* all_instances = NULL;

/** Returns a refed resource corresponding to the created graphics 2d. */ PP_Resource MakeAndBindGraphics2D(PP_Instance instance,     const struct PP_Size* size) {     PP_Resource graphics;

    graphics = g_graphics_2d_interface->Create(instance, size, PP_FALSE);     if (!graphics)         return 0;

    if (!g_instance_interface->BindGraphics(instance, graphics)) {         g_core_interface->ReleaseResource(graphics);         return 0;     }     return graphics; }

void FlushCompletionCallback(void* user_data, int32_t result) {     /* Don't need to do anything here. */ }

unsigned int g_colors[4] = { 0xFF888888, 0xFFFF00FF, 0xFF00FFFF, 0xFFEA00FF }; unsigned int g_color_index = 0;

void Repaint(struct InstanceInfo* instance, const struct PP_Size* size) {     PP_Resource image;     struct PP_ImageDataDesc image_desc;     uint32_t* image_data;     int num_words, i;

    /* Ensure the graphics 2d is ready. */     if (!instance->graphics) {         instance->graphics = MakeAndBindGraphics2D(instance->pp_instance, size);         if (!instance->graphics)             return;     }

    /* Create image data to paint into. */     image = g_image_data_interface->Create(         instance->pp_instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, PP_TRUE);     if (!image)         return;     g_image_data_interface->Describe(image, &image_desc);

    /* Fill the image with blue. */     image_data = (uint32_t*)g_image_data_interface->Map(image);     if (!image_data) {         g_core_interface->ReleaseResource(image);         return;     }     num_words = image_desc.stride * size->height / 4;

    g_color_index++;     if (g_color_index >= sizeof(g_colors) / sizeof(g_colors[0])) g_color_index = 0;

    for (i = 0; i < num_words; i++)         image_data[i] = g_colors[g_color_index];

    /* Paint image to graphics 2d. */     g_graphics_2d_interface->ReplaceContents(instance->graphics, image);     g_graphics_2d_interface->Flush(instance->graphics,         PP_MakeCompletionCallback(&FlushCompletionCallback, NULL));

    g_core_interface->ReleaseResource(image); }

/** Returns the info for the given instance, or NULL if it's not found. */ struct InstanceInfo* FindInstance(PP_Instance instance) {     struct InstanceInfo* cur = all_instances;     while (cur) {         if (cur->pp_instance == instance)             return cur;         cur = cur->next;     }     return NULL; }

PP_Bool Instance_DidCreate(PP_Instance instance,     uint32_t argc,     const char* argn[],     const char* argv[]) {     struct InstanceInfo* info =         (struct InstanceInfo*)malloc(sizeof(struct InstanceInfo));     info->pp_instance = instance;     info->last_size.width = 0;     info->last_size.height = 0;     info->graphics = 0;

    /* Insert into linked list of live instances. */     info->next = all_instances;     all_instances = info;

    g_input_interface->RequestInputEvents(instance, PP_INPUTEVENT_CLASS_MOUSE);     g_input_interface->RequestFilteringInputEvents(instance, PP_INPUTEVENT_CLASS_MOUSE);

    OutputDebugString(_T("Instance_DidCreate\r\n"));

    return PP_TRUE; }

void Instance_DidDestroy(PP_Instance instance) {     /* Find the matching item in the linked list, delete it, and patch the     * links.     */     struct InstanceInfo** prev_ptr = &all_instances;     struct InstanceInfo* cur = all_instances;     while (cur) {         if (instance == cur->pp_instance) {             *prev_ptr = cur->next;             g_core_interface->ReleaseResource(cur->graphics);             free(cur);             return;         }         prev_ptr = &cur->next;         cur = cur->next;     }

    /**foruok: close native window**/     if (g_child_window != NULL)SendMessage(g_child_window, WM_CLOSE, 0, 0);     if (g_dwThreadId != 0)     {         OutputDebugString(_T("Plugin was destroyed, tell child window close and thread exit\r\n"));         PostThreadMessage(g_dwThreadId, WM_USER, 0, 0);     } }

void Instance_DidChangeView(PP_Instance pp_instance,     PP_Resource view) {     struct PP_Rect position;     struct InstanceInfo* info = FindInstance(pp_instance);     if (!info)         return;

    if (g_view_interface->GetRect(view, &position) == PP_FALSE)         return;

    if (info->last_size.width != position.size.width ||         info->last_size.height != position.size.height) {         /* Got a resize, repaint the plugin. */         Repaint(info, &position.size);         info->last_size.width = position.size.width;         info->last_size.height = position.size.height;

        /**foruok: call create window**/         if (g_child_window == NULL)         {             CreateChildWindow(&position);         }     }

    OutputDebugString(_T("Instance_DidChangeView\r\n")); }

void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) { }

PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,     PP_Resource pp_url_loader) {     return PP_FALSE; }

static PPP_Instance instance_interface = {     &Instance_DidCreate,     &Instance_DidDestroy,     &Instance_DidChangeView,     &Instance_DidChangeFocus,     &Instance_HandleDocumentLoad };

PP_Bool InputEvent_HandleInputEvent(PP_Instance instance, PP_Resource input_event) {     struct PP_Point pt;     TCHAR szLog[512] = { 0 };     switch (g_input_interface->GetType(input_event))     {     case PP_INPUTEVENT_TYPE_MOUSEDOWN:         pt = g_mouse_interface->GetPosition(input_event);         _stprintf_s(szLog, 512, _T("InputEvent_HandleInputEvent, mouse down at [%d, %d]\r\n"), pt.x, pt.y);         OutputDebugString(szLog);         break;         /*         case PP_INPUTEVENT_TYPE_MOUSEUP:         OutputDebugString(_T("InputEvent_HandleInputEvent, mouse up\r\n"));         break;

        case PP_INPUTEVENT_TYPE_MOUSEMOVE:         OutputDebugString(_T("InputEvent_HandleInputEvent, mouse move\r\n"));         break;         case PP_INPUTEVENT_TYPE_MOUSEENTER:         OutputDebugString(_T("InputEvent_HandleInputEvent, mouse enter\r\n"));         break;         case PP_INPUTEVENT_TYPE_MOUSELEAVE:         OutputDebugString(_T("InputEvent_HandleInputEvent, mouse leave\r\n"));         break;         */     default:         return PP_FALSE;     }     struct InstanceInfo* info = FindInstance(instance);     if (info && info->last_size.width > 0)     {         Repaint(info, &info->last_size);     }     return PP_TRUE; }

static PPP_InputEvent input_interface = {     &InputEvent_HandleInputEvent };

/* Global entrypoints --------------------------------------------------------*/

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module,     PPB_GetInterface get_browser_interface) {

    /**foruok: register window class**/     RegisterVideoWindowClass();

    g_get_browser_interface = get_browser_interface;

    g_core_interface = (const PPB_Core*)         get_browser_interface(PPB_CORE_INTERFACE);     g_instance_interface = (const PPB_Instance*)         get_browser_interface(PPB_INSTANCE_INTERFACE);     g_image_data_interface = (const PPB_ImageData*)         get_browser_interface(PPB_IMAGEDATA_INTERFACE);     g_graphics_2d_interface = (const PPB_Graphics2D*)         get_browser_interface(PPB_GRAPHICS_2D_INTERFACE);     g_view_interface = (const PPB_View*)         get_browser_interface(PPB_VIEW_INTERFACE);     g_input_interface = (const PPB_InputEvent*)get_browser_interface(PPB_INPUT_EVENT_INTERFACE);     g_mouse_interface = (const PPB_MouseInputEvent*)get_browser_interface(PPB_MOUSE_INPUT_EVENT_INTERFACE);

    if (!g_core_interface || !g_instance_interface || !g_image_data_interface ||         !g_graphics_2d_interface || !g_view_interface ||         !g_input_interface || !g_mouse_interface)         return -1;

    g_var_interface = (const PPB_Var*)get_browser_interface(PPB_VAR_INTERFACE);     g_dictionary_interface = (const PPB_VarDictionary*)get_browser_interface(PPB_VAR_DICTIONARY_INTERFACE);     g_array_interface = (const PPB_VarArray*)get_browser_interface(PPB_VAR_ARRAY_INTERFACE);     g_message_interface = (const PPB_Messaging*)get_browser_interface(PPB_MESSAGING_INTERFACE);

    OutputDebugString(_T("PPP_InitializeModule\r\n"));     return PP_OK; }

PP_EXPORT void PPP_ShutdownModule() { }

void Plugin_HandleMessage(PP_Instance instance, struct PP_Var message) {     char szLog[256] = { 0 };     //sprintf_s(szLog, 256, "Plugin_HandleMessage, type = %d\r\n", message.type);     OutputDebugStringA(szLog);

    if (message.type == PP_VARTYPE_DICTIONARY)     {         char command[] = "command";         struct PP_Var commandKey = g_var_interface->VarFromUtf8(command, sizeof(command)-1);         struct PP_Var commandVar = g_dictionary_interface->Get(message, commandKey);         int len = 0;         const char *strCommand = g_var_interface->VarToUtf8(commandVar, (uint32_t*)&len);         g_var_interface->Release(commandKey);

        //sprintf_s(szLog, 256, "Plugin_HandleMessage, dict, command = %s, len = %d\r\n", strCommand, len);         OutputDebugStringA(szLog);

        if (len == 0)         {             OutputDebugString(_T("Tang_plugin, recv invalid command\r\n"));             g_var_interface->Release(commandVar);             return;         }         if (strncmp(strCommand, "joinConf", len) == 0)         {             char confIdKey[] = "confId";             char userNameKey[] = "userName";             char *szConfId = 0;             char*szUserName = 0;             struct PP_Var idKey = g_var_interface->VarFromUtf8(confIdKey, sizeof(confIdKey)-1);             struct PP_Var userKey = g_var_interface->VarFromUtf8(userNameKey, sizeof(userNameKey)-1);             struct PP_Var var = g_dictionary_interface->Get(message, idKey);             const char *value = g_var_interface->VarToUtf8(var, (uint32_t*)&len);             if (len > 0)             {                 szConfId = (char*)malloc(len + 1);                 strncpy_s(szConfId, len + 1, value, len);                 szConfId[len] = 0;             }             g_var_interface->Release(var);

            var = g_dictionary_interface->Get(message, userKey);             value = g_var_interface->VarToUtf8(var, (uint32_t*)&len);             if (len > 0)             {                 szUserName = (char*)malloc(len + 1);                 strncpy_s(szUserName, len + 1, value, len);                 szUserName[len] = 0;             }             g_var_interface->Release(var);

            //sprintf_s(szLog, 256, "Plugin_HandleMessage, dict, command = joinConf, user = %s, confId = %s\r\n", szUserName, szConfId);             OutputDebugStringA(szLog);

            if (szConfId && szUserName)             {                 //sprintf_s(szLog, 256, "plugin got confId - %s, user - %s\r\n", szConfId, szUserName);                 OutputDebugStringA(szLog);                 //joinConf(szConfId, szUserName);             }             else             {                 OutputDebugString(_T("Invalid conference id or userName\r\n"));             }             if (szConfId) free(szConfId);             if (szUserName) free(szUserName);             g_var_interface->Release(idKey);             g_var_interface->Release(userKey);

            /* fake attendees*/             char szMsgTypeValue[] = "userlist";             char szTypeKey[] = "type";             struct PP_Var typeKey = g_var_interface->VarFromUtf8(szTypeKey, sizeof(szTypeKey)-1);             struct PP_Var typeValue = g_var_interface->VarFromUtf8(szMsgTypeValue, sizeof(szMsgTypeValue)-1);             struct PP_Var attendee = g_dictionary_interface->Create();             g_dictionary_interface->Set(attendee, typeKey, typeValue);

            struct PP_Var userArray = g_array_interface->Create();             char szUser1[] = "ZhangSan";             char szUser2[] = "LiSi";             struct PP_Var user1 = g_var_interface->VarFromUtf8(szUser1, sizeof(szUser1)-1);             struct PP_Var user2 = g_var_interface->VarFromUtf8(szUser2, sizeof(szUser2)-1);             g_array_interface->Set(userArray, 0, user1);             g_array_interface->Set(userArray, 1, user2);

            char szValueKey[] = "value";             struct PP_Var valueKey = g_var_interface->VarFromUtf8(szValueKey, sizeof(szValueKey)-1);             g_dictionary_interface->Set(attendee, valueKey, userArray);

            g_message_interface->PostMessage(instance, attendee);             OutputDebugString(_T("Post attendee to browser"));

            g_var_interface->Release(typeKey);             g_var_interface->Release(typeValue);             g_var_interface->Release(user1);             g_var_interface->Release(user2);             g_var_interface->Release(valueKey);             g_var_interface->Release(userArray);             g_var_interface->Release(attendee);         }         else if (strncmp(strCommand, "viewVideo", len) == 0)         {             char userIdKey[] = "userId";             char *szUserId = 0;             struct PP_Var idKey = g_var_interface->VarFromUtf8(userIdKey, sizeof(userIdKey)-1);             struct PP_Var var = g_dictionary_interface->Get(message, idKey);             const char *value = g_var_interface->VarToUtf8(var, (uint32_t*)&len);             if (len > 0)             {                 szUserId = (char*)malloc(len + 1);                 strncpy_s(szUserId, len + 1, value, len);                 szUserId[len] = 0;             }             if (szUserId)             {                 //sprintf_s(szLog, 256, "plugin got userId - %s\r\n", szUserId);                 OutputDebugStringA(szLog);                 //viewVideo(szUserId, g_child_window);             }             else             {                 OutputDebugString(_T("Invalid viewVideo command without userId\r\n"));             }             if (szUserId) free(szUserId);             g_var_interface->Release(var);             g_var_interface->Release(idKey);         }         g_var_interface->Release(commandVar);     }     else if (message.type == PP_VARTYPE_STRING)     {         char hello_world[] = "Hello world!";         struct PP_Var var = g_var_interface->VarFromUtf8(hello_world, sizeof(hello_world)-1);         g_message_interface->PostMessage(instance, var); // var will be copyed         g_var_interface->Release(var);     } }

static PPP_Messaging message_interface = {     &Plugin_HandleMessage };

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {     if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)     {         OutputDebugString(_T("PPP_GetInterface, instance_interface\r\n"));         return &instance_interface;     }     else if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)     {         OutputDebugString(_T("PPP_GetInterface, input_interface\r\n"));         return &input_interface;     }     else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0)     {         OutputDebugString(_T("PPP_GetInterface, message_interface\r\n"));         return &message_interface;     }

    return NULL; }

 

    5. 右键选择工程属性,在工程的包含目录中加入  D://APIs/BHO-master/     6. 编译工程得到一个 dll,例如 ppapiexample.dll。     7. 编写一个cef.html 文件,

          #contacts     {         margin: 10px;         width: 300px;         height: 200px;         background-color: gray;     }               function handleMessage(message) {         alert(message.data.type);         if(message.data.type.localeCompare("userlist") == 0){           var i = 0;           ul = document.getElementById("attendee");           for(; i < message.data.value.length; i++){             var li = document.createElement("li");             li.appendChild(document.createTextNode(message.data.value[i]));             ul.appendChild(li);           }         }       }

      function joinConference(){         plugin = document.getElementById('tangplugin');         plugin.postMessage({             command:"joinConf",              confId: document.getElementById("confId").value,              userName: document.getElementById("userName").value           });       }       function viewSharedVideo(){         plugin = document.getElementById('tangplugin');         plugin.postMessage({             command:"viewVideo",              userId: document.getElementById("userId").value           });       }

      function initialize() {         plugin = document.getElementById('tangplugin');         plugin.addEventListener('message', handleMessage, false);       }

      document.addEventListener('DOMContentLoaded', initialize, false);       Tang in Plugin

ConferenceID: ;;User:  ;;

contacts:

  UserId:;;View Video

share video:

    8. 制作一个 .bat 文件,文件内容类似如下: chrome --register-pepper- plugins="C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\49.0.2623.110\\tplugin\\ppapiexample.dll;application/x-ppapi-tang-video"  D:\\APIs\\BHO-master\\cef.html     9.  运行该 .bat 文件,查看效果。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3