chrome PPAPI 开发(一) |
您所在的位置:网站首页 › 金属制品公司名称大全免费 › chrome PPAPI 开发(一) |
最近遇到一个需要在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 Videoshare 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 |