实验了一个比较奇特的东西,在PPAPI插件里创建一个本地窗口,叠加在插件在网页的位置上。

CEF3默认是多进程架构,PPAPI插件在一个单独进程里跑,这个进程没启动Windows的消息循环,所以,要创建插件的话,得自己搞一个消息循环。另外浏览器窗口属于别的进程,怎么把创建出来的窗口成为浏览器窗口的子窗口,也是个问题。这个第一个要解决的问题。

CEF3还支持单进程运行,Browser、Render、Plugin合一,此时创建本地窗口又和多进程不同。这是第二个问题。

第三个问题是,如何把窗口定位到网页的插件区域。

琢磨了下,都解决了。

foruok原创,如需转载请关注foruok的微信订阅号“程序视界”联系foruok。

效果

先看看效果图。先是跨进程的:

灰色区域那里是我创建的本地窗口,上面有一行字。

再看同一进程的:

注意文字的变化。

代码

Talk is cheap,show me the code:

/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.* 2016-1-13, edited by foruok.
* 如需转载,请关注微信订阅号“程序视界”,回复foruok获取其联系方式
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <tchar.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"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;/******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, 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 = (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;OutputDebugString(_T("PPP_InitializeModule\r\n"));return PP_OK;
}PP_EXPORT void PPP_ShutdownModule() {
}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;}return NULL;
}

工程和原来差不多,不说了。

代码基于PPAPI插件的绘图与输入事件处理改造,添加的部分,在注释处加入了foruok标签,搜索即可查看。下面说明几点。

本地窗口的创建

CreateChildWindow()函数是创建本地窗口的入口函数,它利用进程id,判断了插件进程与浏览器进程是否同一进程。

如果是同一进程,通过调用PPB_Core的CallOnMainThread方法,在主线程执行CreateChildWindowOnMainThread来创建子窗口。

如果不是同一进程,就创建一个线程,在线程里创建窗口并启动了消息循环。注意,Windows下窗口的父子关注,支持跨进程,所以调用CreateWindowEx时只要指定父窗口句柄即可。

窗口定位

DidChangeView方法之前在理解PPAPI的设计里提到过,当插件和浏览器的视图关联起来或者视图发生变化时,DidChangeView方法会被调用。这次我们就在这里创建窗口。窗口的位置,可以通过PPB_View接口的GetRect()方法获取到。这个位置就是我们要创建的本地窗口的位置,传递给CreateWindowEx方法即可。

好啦,新的示例主要就这些内容了,处理输入事件的流程应该也清楚了。


这次实验的东西比较奇特,不走寻常路,仅仅是为了兼容老代码……

相关文章参考:

  • CEF Windows开发环境搭建
  • CEF加载PPAPI插件
  • VS2013编译最简单的PPAPI插件
  • 理解PPAPI的设计
  • PPAPI插件与浏览器的交互过程
  • Windows下从源码编译CEF
  • 编译PPAPI的media_stream_video示例
  • PPAPI插件的绘图与输入事件处理

在PPAPI插件中创建本地窗口相关推荐

  1. Unity中创建本地多人游戏完整案例视频教程 Learn To Create A Local Multiplayer Game In Unity

    Unity中创建本地多人游戏完整案例视频教程 Learn To Create A Local Multiplayer Game In Unity MP4 |视频:h264,1280x720 |音频:A ...

  2. linux中创建本地yum库,轻松安装Linux软件

    创建本地yum源 说明:此方法是针对于有5张LinuxCD盘所提供的创建本地yum repository的解决方案.如果您的系统盘是DVD盘,您可以通过直接将yum源指向DVD即可使用,而不用再采取这 ...

  3. 【转】win32 的DLL中创建windows窗口

    转自:https://blog.51cto.com/wangyw/1071967 因工作需求,需要写一个DLL,并在其中创建windows窗口,网上有很多关于DLL创建窗口的文章,不过都是基于MFC的 ...

  4. (面试题)html中创建模态窗口的方法有哪些?

    一.创建模态和非模态对话框 除了alert(""); confirm(""); prompt("");之外还有 创建模态对话框: vRetu ...

  5. kodi android 目录,如何在xbmc / kodi插件中创建多个目录?

    我最近开始学习如何制作xbmc / kodi插件. 我正在尝试创建多个目录,但一直得到"错误:脚本失败:"当我点击视频部分的插件图标时. 任何人都可以帮我解决这个错误并创建多个目录 ...

  6. PPAPI插件的全屏切换处理

    有时你会想让PPAPI插件全屏(比如播放视频时),这次来看看怎么做. PPAPI和CEF App两侧都要处理. foruok原创,转载请注明出处.欢迎关注foruok的订阅号"程序视界&qu ...

  7. 使用jQuery创建模态窗口登陆效果

    来源:GBin1.com 在线下载 在线演示 隐藏模态窗口技术是一种很好的解决方案,用于处理不是特有必要出现在网页上的界面元素.社交网络可以使用模态窗口传达私人讯息以及只针对会员才能看 到的表单.在博 ...

  8. 在Unity中创建基于Node节点的编辑器 (一)

    孙广东   2018.5.13 Unity  AssetStore中关于Node节点 编辑器相关的插件可是数不胜数, 状态机,行为树,Shader 可视化等等. Unity自己也有 Animator的 ...

  9. html如何做本地链接,如何创建本地连接,小编教你电脑如何创建本地连接

    有些电脑小白朋友不小心把电脑的本地连接给删掉了,我们都知道电脑要想上网,本地连接都是必须的.在面对这种电脑的使用不加以注意,会在不经意间把电脑的本地连接从电脑里面删除了的情况,该怎么去创建本地连接?下 ...

  10. php 怎么生成本地连接地址,电脑如何创建本地连接?电脑创建本地连接的操作方法...

    近期好多用户想要在电脑系统中创建本地连接,但是要如何创建呢?网上搜索系统创建本地连接的方法内容比较少,有不少的用户想要创建本地连接但是又不知道方法,为此感到很郁闷,下面,小编就给大家介绍电脑创建本地连 ...

最新文章

  1. java自定义上下文对象_Java框架_Spring应用上下文对象加载配置
  2. KDD 2019 | 结合属性随机游走的图递归网络
  3. 深度学习:神经网络基础知识总结
  4. PngEncoder_CreateInstance Failed writing PNG because unable to find libpng12.so.0
  5. [蓝桥杯][算法训练VIP]乘积最大(动态规划)
  6. EAS WebService部署
  7. win7录制系统声音 加入立体声混音 camtasia recorder录屏
  8. 拥抱创新二十载,微软“创新杯”持续孵化中国青年开发者智慧创意
  9. dj鲜生-12-富文本编辑器-tinymce 以及choice选择项目
  10. python-scrapy简单爬虫实现
  11. IP/TCP IP分组的交付与转发
  12. SIP Servlet开发环境配置
  13. 第8章 多项式回归与模型泛化 学习笔记上
  14. 《计算机操作系统》(第四版)汤小丹 第二章思维导图
  15. C# 你什么让程序员寂寞成酱紫 (男生版 娱乐中学习 抽象类 接口 继承 实现方法 )...
  16. Unity做360度全景预览
  17. 微信小程序毕业设计 基于微信小程序在线电子书阅读系统开题报告
  18. kpi绩效考核流程图_松松客服KPI绩效考核表经验分享
  19. BAT批处理基本命令
  20. Hadamard积的介绍

热门文章

  1. 8个正弦波逆变器带你感受生活中无处不在的科技魅力
  2. Eviews9.0---软件安装
  3. 《考勤信息管理系统》数据库 课程设计
  4. TLSF算法2:位图的相关计算
  5. TOPSIS法 —— python
  6. mysql用reader读取空数据时报错的处理
  7. windows安全中心接口
  8. CentOS7 时间与网络时间同步
  9. 项目resource下文件读取失败
  10. 会考计算机考试模拟软件,计算机会考考试模拟(范文).doc