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版之开启开发者模式,接入微信公众平台开发
第一部分:微信公众号对接的基本介绍 一.填写服务器配置信息的介绍 登录微信公众平台官网后,进入到公众平台后台管理页面. 选择 公众号基本设置->基本配置 ,点击“修改配置”按钮,填写服务器地址( ...
随机推荐
- 轻量级模块化开发框架 Hasor 核心模块 v0.0.2 发布
首先引用Wiki的介绍一下Hasor: “Hasor是一款开源框架.它是为了解决企业模块化开发中复杂性而创建的.Hasor遵循简单的依赖.单一职责,在开发多模块企业项目中更加有调理.然 而Ha ...
- Lambda应用设计模式
前言 在使用 Lambda 表达式时,我们常会碰到一些典型的应用场景,而从常用场景中抽取出来的应用方式可以描述为应用模式.这些模式可能不全是新的模式,有的参考自 JavaScript 的设计模式,但至 ...
- 分享我用Qt开发的应用程序【二】在Qt应用程序中使用字体图标fontawesome
为了使用简单,需要先写一个单件类,头文件的代码如下: 其中静态方法Instance保证IconHelper的实例全局唯一 (注意构造函数已经私有化了) #ifndefICONHELPER_H #def ...
- Free download
http://blogs.msdn.com/b/mssmallbiz/archive/2014/07/07/largest-collection-of-free-microsoft-ebooks-ev ...
- listen--监听数量
listen--监听数量 #include <sys/socket.h> int listen(int sockfd, int backlog); /* backlog指定了该套接口排队的 ...
- [自制简单操作系统] 7、多任务(二)——任务管理自动化&任务休眠
前言 >_<" 这里仿照窗口管理的方式将任务管理也修改成相应的管理模式,这样可以灵活的添加多个任务,而不必每次都要修改任务切换函数:此外还在任务休眠做了尝试,通过将任务挂起和唤醒 ...
- 用Redis打造URL缩短服务
此文章的英文版本已首发于 CodeProject : Building a simple URL shorten service with Redis 阅读文章之前,我建议你先下载源码,一边看文章,一 ...
- Jetty 9嵌入式开发
官方网址:http://www.eclipse.org/jetty/ 下载地址:http://download.eclipse.org/jetty/stable-9/dist/ 文档网址:http:/ ...
- PHP读取日志里数据方法理解
需要函数: fopen($file, "r")打开文件 fgets($file, 1024 * 10)读取一行,注意设置字节数大小,默认的1024B可能太小了 strpos($lo ...
- Atitit.java eval功能的实现 Compiler API
Atitit.java eval功能的实现 Compiler API 输出echo2 输出目录配置2 针对编译器,JDK 设计了两个接口,分别是 JavaCompiler 和JavaCompiler ...