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版之开启开发者模式,接入微信公众平台开发
第一部分:微信公众号对接的基本介绍 一.填写服务器配置信息的介绍 登录微信公众平台官网后,进入到公众平台后台管理页面. 选择 公众号基本设置->基本配置 ,点击“修改配置”按钮,填写服务器地址( ...
随机推荐
- 仿SiteMap实现Asp.net 网站的菜单和权限管理
在Asp.net中,SiteMap用于站点导航,可以与Menu等控件一起使用实现网站的菜单和权限管理.但是SiteMap提供的方法都是只读的,无法再运行时修改(菜单)导航文件,需要手动修改配置web. ...
- mongodb(二) 安装和使用
mongodb的安装和使用 最近的项目需要使用到mongodb,从而开始熟悉nosql,有了本篇文章,记录和方便他人. mongodb的安装 下载地址:http://www.mongodb.org/d ...
- javascript高级程序设计阅读笔记(一)
javascript高级程序设计阅读笔记(一) 工作之余开发些web应用作为兴趣,在交互方面需要掌握javascript和css.HTML5等技术,因此读书笔记是必要的. javascript简介 J ...
- 通过Anuglar Material串串学客户端开发 - javascript编译和gulpfile.js
Angular Material不仅仅有本身框架的源代码,还有在这个框架上实现的一个应用docs.更为强大的是,这个应用是真正的产品网站:就是它的官网.我有理由相信,这个网站是从源代码直接发布的,从网 ...
- JSLint JavaScript代码质量审查工具汉化中文版隆重发布
JSLint是一款JavaScript代码质量审查工具,它可以指出代码中错误.不规范的地方,非常之严格,甚至多写一个空格都会发出警告. JSLint的审查规则,根据众多前辈多年编程经验而写,字字珠玑, ...
- 【Android】Eclipse Memory Analyzer 进行堆内存溢出分析
MAT 不是一个万能工具,它并不能处理所有类型的堆存储文件. 不同厂家的 JVM 所生成的堆转储文件在数据存储格式以及数据存储内容上有很多区别,但是比较主流的厂家和格式,例如 Sun, HP, ...
- Atitit org.eclipse.jdt 的ast 架构 Eclipse JDT API spec
Atitit org.eclipse.jdt 的ast 架构 Eclipse JDT API spec 继承树1 Expression的子类1 获取子类2 继承树 Astnode>express ...
- Atitit..文件上传组件选型and最佳实践总结(3)----断点续传控件的实现
Atitit..文件上传组件选型and最佳实践总结(3)----断点续传控件的实现 1. 实现思路:::元插件,元设置... 1 2. 实现流程downzip,unzip,exec 1 3. Zip ...
- 好消息!Html5游戏和动画的福音
今年基本都淡出了cocos2d-js的开发,更多集中在普通H5应用上,还有自己的Fanvas组件(http://code.tencent.com/),做canvas动画. 不过,最近回头一看WebGL ...
- QT on Android开发
1.安装QT 2.安装JDK 配置如下系统环境变量: JAVA_HOME D:\Java\jdk Path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin CLASSPATH ...