JCEF3——谷歌浏览器内核Java版实现(一):使用jawt获取窗体句柄
前言
最近一段时间研究谷歌浏览器内核。谷歌浏览器内核一直开源,并维护更新,它的开源项目中内核更新速度和Chrome浏览器版本更新进度一样!而且它不同于WebKit(值得一题的是谷歌浏览器已不使用WebKit内核了),它提供的不仅仅是页面渲染,而是提供一整浏览器解决方案和插件规则。
使用方便:我们给它一个“窗体”(操作系统或系统资源管理器中的本地窗体,本系列都使用Win32平台作为示例)和一些配置参数,它就能将你需要渲染的页面在给定窗口中完美地展示。
插件支持:Adobe和Google联合开发的pepperflashplayer功能完善,而且我们作为进程外插件安装的话可以不用考虑它的自动升级给用户造成困扰或我们开发中的版本变化。而你只需要一句代码即可完成插件的启用,获取和升级插件方式也很简单(先在电脑上装一个chrome浏览器,去安装目录下copy:-_-)。谷歌对pdf的插件也可以这样。
这个随笔系列主要使用Java给谷歌浏览套一个壳。因为cef(即“谷歌浏览器内核chromium embedded framework”,后文都使用cef作为简称,并且本系列都使用cef3)使用c/c++编写,并未直接提供Java语言API,虽然有Java版的一个维护版本,但本人认为并不好用。
获取AWT窗体句柄
我们今天要做的跟cef内核还没太大关系,我们先解决一个问题:获取Java窗体的句柄。
我们都知道:Java语言提供的GUI支持是建立在操作系统资源管理系统(或者桌面环境)的支持上的(在Java的2D/GUI中,最外层的窗体肯定是操作系统相关的),那么很简单的道理,我们可以使用JNI的一些API来获取窗体句柄。
- jni?
JNI是Java语言提供的本地化代码调用接口(在Java虚拟机里实际上不在乎下一个方法入口是内部指针还是外部-操作系统指针),我们可以写一个c/c++的函数去找到窗体句柄,然后返回给Java虚拟机,让我们在虚拟机内部也知晓某个Java窗体被操作系统分配的句柄。
- jawt
Java官方已经考虑到我们这种需求了,它提供了一个接口:jawt。包括一系列c/c++包含(头文件.h,平台相关)和一系列c/c++静态库文件。
具体包括jawt.h、jawt_md.h、jawt.lib(另外jni.h以及jni_md.h是使用jni必须的)
- javah
编写动态链接库(dll)需要使用c/c++头文件与c/++源文件联合编译。我们先使用JDK自带的javah工具(javah.exe)生成一个头文件并实现它。
当然,我们先写一个Java类,标注其native方法。
/*
* Copyright 2014 JootMir Project
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Support: http://www.cnblogs.com/johness
*/
package johness.jcef3.util; import javax.swing.JFrame; /**
* AWT工具集
*
* @author ShawRyan
*/
public final class AWTUtil {
/**
* 获取某个窗体句柄(在Windows平台下)
*
* @param window
* 需要获取句柄的窗体对象
* @return 窗体应用句柄
*/
public static native int getWindowHandleInWindows(JFrame window);
}
AWTUtil
然后使用javah生成其对应头文件。


头文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class johness_jcef3_util_AWTUtil */ #ifndef _Included_johness_jcef3_util_AWTUtil
#define _Included_johness_jcef3_util_AWTUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: johness_jcef3_util_AWTUtil
* Method: getWindowHandleInWindows
* Signature: (Ljavax/swing/JFrame;)I
*/
JNIEXPORT jint JNICALL Java_johness_jcef3_util_AWTUtil_getWindowHandleInWindows
(JNIEnv *, jclass, jobject); #ifdef __cplusplus
}
#endif
#endif
jni细则我就不赘述了。
- visual studio
接下来我们使用c++代码来实现接口函数并编译为动态链接库。
经典的VC++6.0或者优秀的Dev C++我都不喜欢使用,我就用Visual Studio 2012来编写并编译吧。
建立项目


删除一切我们不需要(我们就没有需要的-_-)文件


复制jni和jawt相关头文件及库文件到项目中(值得一题的是不是说让你复制粘贴到vs窗体内,而是真正复制到你c++项目文件夹内)
%JAVA_HOME%\include\jni.h
%JAVA_HOME%\include\jawt.h
%JAVA_HOME%\include\jni_md.h
%JAVA_HOME%\include\jawt_md.h
%JAVA_HOME%\lib\jawt.lib
你项目中的那个头文件



配置项目
配置项目为Release

配置项目使用jawt.lib静态库

更改头文件,把#include <jni.h>改为#include "jni.h"

(后面的竖线是光标)
写源文件
(创建好源文件并准备开始编写代码之前取消源文件预编译头)

开始编码(jawt.h里有使用示例,我们照着改)
#include "jni.h"
#include "jawt_md.h"
#include "johness_jcef3_util_AWTUtil.h" JNIEXPORT jint JNICALL Java_johness_jcef3_util_AWTUtil_getWindowHandleInWindows (JNIEnv *env, jclass sender, jobject window) {
HWND hwnd = NULL; JAWT_DrawingSurface *ds;
JAWT_DrawingSurfaceInfo *dsi;
JAWT_Win32DrawingSurfaceInfo *win; JAWT awt;
awt.version = JAWT_VERSION_1_3; jboolean result = JAWT_GetAWT(env, &awt);
if (result == JNI_TRUE) {
ds = awt.GetDrawingSurface(env, window);
jint lock = ds -> Lock(ds);
if (lock != JAWT_LOCK_ERROR) {
dsi = ds -> GetDrawingSurfaceInfo(ds);
win = (JAWT_Win32DrawingSurfaceInfo *) dsi -> platformInfo; hwnd = win -> hwnd; ds -> FreeDrawingSurfaceInfo(dsi);
ds -> Unlock(ds);
awt.FreeDrawingSurface(ds);
return jint(hwnd);
}
return ;
}
return ;
}
johness_jcef3_util_AWTUtil
编译生成

- 使用或测试
把生成的dll复制到Java项目中,在项目配置中配置librarypath,然后编写测试代码。


测试代码也很简单:
package johness.jcef3.util;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
System.loadLibrary("jawt");
System.loadLibrary("JCEF3");
JFrame frame = new JFrame();
frame.setSize(400, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println(AWTUtil.getWindowHandleInWindows(frame));
}
}
最后总结
使用visual studio编译时注意不使用预编译文件头。当然如果你稍微了解vc++的话可能也不用这么麻烦。
使用visual studio编译生成的dll需要运行时环境,比如msvcr110.dll之类的。如果你机器上没有安装过的话可能会爆出“Can't find dependent libraries”这种错,可以把这些个运行时环境的库打包过去。
写于2016-03-29
本来我想自己做java-cef,不过官方已经做了
写于2019-11-28
java-cef已经不维护了,有很多bug。几年前我自己维护了一个maven版本的项目 https://mvnrepository.com/artifact/org.bitbucket.johness/java-cef/49.87.win32.2 https://mvnrepository.com/artifact/org.bitbucket.johness/java-cef/49.87.win64.2。但也不更新了,注意,这也是几年前的东西了,请大家不要用,尽量使用时兴的开源组件。如果一个项目你看它超过一个月没活跃(发布版本,提交代码等),那你最好别用。
联系我,一起交流
欢迎您移步我们的交流群,无聊的时候大家一起打发时间:
或者通过QQ与我联系:
(最后编辑时间2016-03-29 10:26:41)
JCEF3——谷歌浏览器内核Java版实现(一):使用jawt获取窗体句柄的更多相关文章
- 第八篇 :微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
- 微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
- 第九篇 :微信公众平台开发实战Java版之如何实现自定义分享内容
第一部分:微信JS-SDK介绍 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统 ...
- 第七篇 :微信公众平台开发实战Java版之如何获取微信用户基本信息
在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的.对于不同公众号,同一用户的openid不同). 公众号可通过本接口来根据O ...
- 第六篇 :微信公众平台开发实战Java版之如何自定义微信公众号菜单
我们来了解一下 自定义菜单创建接口: http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_to ...
- 第五篇 :微信公众平台开发实战Java版之如何获取公众号的access_token以及缓存access_token
一.access_token简介 为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台 开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等, 开 ...
- 第四篇 :微信公众平台开发实战Java版之完成消息接受与相应以及消息的处理
温馨提示: 这篇文章是依赖前几篇的文章的. 第一篇:微信公众平台开发实战之了解微信公众平台基础知识以及资料准备 第二篇 :微信公众平台开发实战之开启开发者模式,接入微信公众平台开发 第三篇 :微信公众 ...
- 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装
微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...
- 第二篇 :微信公众平台开发实战Java版之开启开发者模式,接入微信公众平台开发
第一部分:微信公众号对接的基本介绍 一.填写服务器配置信息的介绍 登录微信公众平台官网后,进入到公众平台后台管理页面. 选择 公众号基本设置->基本配置 ,点击“修改配置”按钮,填写服务器地址( ...
随机推荐
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
linux内核的移植性非常好, 目前的内核也支持非常多的体系结构(有20多个). 但是刚开始时, linux也只支持 intel i386 架构, 从 v1.2版开始支持 Digital Alpha, ...
- Android资源命名规范
Android资源命名规范 命名模板为:缩写_主界面_功能部分(一) 缩写:ic ----------------------iconbg---------------------background ...
- Nutz Dao实体中索引注解的使用(@TableIndexes@Index)
Nutz是一组轻便小型的框架的集合, 各个部分可以被独立使用,把SSH的精华封装在一个1M左右的jar包中,Nutz不对其他任何第三方库产生依赖,如果不考虑数据库链接和日志的话,创建完美的Web应用只 ...
- ASP.NET 5系列教程(七)完结篇-解读代码
在本文中,我们将一起查看TodoController 类代码. [Route] 属性定义了Controller的URL 模板: [Route("api/[controller]") ...
- Redis安装与日常使用
下载与安装 $ wget http://download.redis.io/releases/redis-3.0.3.tar.gz $ tar xzf redis-3.0.3.tar.gz $ cd ...
- atitit.设计模式(2) -----查表模式/ command 总结
atitit.设计模式(2) -----查表模式/ command 总结 1. 应用场景: 1 1. 取代一瓦if else 1 2. 建设api rpc风格的时候儿. 1 3. 菜单是Command ...
- Qt for Android 打包 SQLite 数据库
Qt for Android 调用 SQLite 数据库时, 怎样将已经存在的数据库附加到 APK 中? 直接在你项目里面的Android源码的根目录下新建一个文件夹assets, 数据库就可以放里面 ...
- python类的特性
#encoding=utf-8 class Province: #静态字段 memo = '这里是静态变量' def __init__(self,name,capital,leader,flag): ...
- Kerberos ticket lifetime及其它
前言 之前的博文中涉及到了Kerberos的内容,这里对Kerberos ticket lifetime相关的内容做一个补充. ticket lifetime Kerberos ticket具有lif ...
- 机器学习技法--学习笔记03--Kernel技巧
背景 上一讲从对偶问题的角度描述了SVM问题,但是始终需要计算原始数据feature转换后的数据.这一讲,通过一个kernel(核函数)技巧,可以省去feature转换计算,但是仍然可以利用featu ...