- 浏览: 335733 次
- 性别:
- 来自: 温州
文章分类
最新评论
-
helloworldlove:
Axis_UNZIP_PATH\Axis-version\we ...
3步把您的java程序转换为webservice -
hcqenjoy:
这个工具能再提供下吗 已经没办法下载了 谢谢
汉化 Flex Builder 3 帮助文档 -
NASa_CJ:
String source = HttpClientExamp ...
利用HttpClient获取网页内容 -
zlsj80:
下载地址无效了,楼主修正一下吧
汉化 Flex Builder 3 帮助文档 -
fykyx521:
下载地址都不能用了,是不过时了
汉化 Flex Builder 3 帮助文档
原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-eclrcp/index.html?ca=drs-cn-0605
Windows 应用程序非常丰富,而有时我们的 Eclipse RCP 程序所需要的一些功能已经有一些现有的 Windows 本地应用程序的实现,我们希望能够在我们的 RCP 程序中重用这些功能。一种最简单的重用方法就是直接在我们 RCP 窗口中嵌入本地应用程序窗口。要使得一个 Windows 本地应用程序能够在我们的 RCP 程序中运行,我们可以使用 Windows 提供的 reparent 机制。利用这种机制实现窗口嵌入的主要过程是:首先要在我们的程序中启动要嵌入的 Windows 程序,然后我们设法获取程序启动后的主窗口句柄,再将我们RCP程序的窗口设置成 Windows 程序主窗口的父窗口。
由于我们需要启动 Windows 本地程序并且获取它的主窗口句柄,这些只能使用 Windows 本地调用来实现,所以我们先用 Windows 本地调用实现相应的功能,然后我们再用 JNI 进行调用。
JNI 的全称是 Java Native Interface,JNI 标准是 Java 平台的一部分,它用来将 Java 代码和其他语言写的代码进行交互。下面简单介绍一下使用 JNI 的步骤:
这里以 HelloWorld 为例:
清单 1. Hello World Java 代码
|
先编译这个 java 类: javac HelloWorld.java,然后再生成扩展名为 .h 的头文件,java 提供了命令 javah 来生成头文件:javah –jni HelloWorld,下面的清单显示了生成的头文件的内容:
清单 2. Hello World C++ 头文件
|
前面已经生成了 c/c++ 的头文件,下面要实现头文件中声明的函数,具体的实现代码如下面的清单所示,示例代码中仅仅是输出一行文字“HelloWorld”:
清单 3. Hello World C++ 实现代码
|
接下来要做的就是将这个 c++ 的代码编译成动态库文件,在 HelloWorld.cpp 文件目录下面,使用 VC 的编译器 cl 命令来编译:
cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorld.cpp –Fehelloworld.dll
注 意:生成的 dll 文件名在选项 -Fe 后面配置,这里是 helloworld.dll,因为前面我们在 HelloWorld.java 文件中 loadLibary 的时候使用的名字是 helloworld。所以要保证这里的名字和前面 load 的名字一致。另外需要将 -I%java_home%\include -I%java_home%\include\win32 参数加上,因为在第四步里面编写本地方法的时候引入了 jni.h 文件,所以在这里需要加入这些头文件的路径。
完成了这些步骤之后就可以运行这个程序:java HelloWorld,运行的结果就是在控制台输出字符串“HelloWorld”。
前面部分介绍了如何使用 JNI,接下来介绍如何通过 JNI 启动一个 Windows 的本地应用程序并且将其主窗口设置为指定窗口的子窗口。首先创建一个 Java 类,如下面的清单所示:
public class ReparentUtil { |
其中 System.loadLibrary("reparent") 是用来加载名为 reparent 的动态库,我们会在这个动态库中具体实现方法 startAndReparent(…)。
startAndReparent 定义方法来启动 Windows 程序,并且将其窗口 reparent 到我们指定的窗口。其中:
- int parentWnd: 父窗口句柄
- String command:Windows 程序启动命令
- String wndClass:Windows 程序主窗口类型
由于有的程序启动后会创建多个顶级窗口,所以我们在这里要指定一个主窗口类型来区分不同的顶级窗口。这个方法是一个本地方法,我们会用 C++ 生成为一个叫 reparent.dll 的动态库,这个方法即存在于这个动态库中。
这 个 Java 函数对应的的 C++ 函数是 Java_com_reparent_ReparentUtil_startAndReparent(JNIEnv *env, jclass classobj, jint parent, jstring command, jstring wndClass), 这个函数主要实现两部分的功能:
- 启动 Windows 应用程序;
- 获取 Windows 应用程序的主窗口句柄;
- 将 Windows 应用主窗口设置成指定窗口的子窗口。
下面我们来看看启动 Windows 应用程序的实现. 我们先将函数传入的 Java 字符串参数转化成 C 字符串。这个过程主要通过 GetStringChars() 来实现。
JNIEXPORT jint JNICALL Java_com_reparent_ReparentUtil_startAndReparent |
接着,我们使用 Windows 的 API:CreateProcess 函数来启动我们要集成的应用程序。
sInfo.cb = sizeof(STARTUPINFO); |
CreateProcess 函数的定义是:
BOOL CreateProcess ( |
其中 lpApplicationName:指向一个 NULL 结尾的、用来指定可执行模块的字符串。lpCommandLine:指向一个 NULL 结尾的、用来指定要运行的命令行。lpProcessAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。lpThreadAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。bInheritHandles:指示新进程是否从调用进程处继承了句柄。 dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志。lpEnvironment:指向一个新进程的环境块。 lpCurrentDirectory:指向一个以 NULL 结尾的字符串,这个字符串用来指定子进程的工作路径。lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的 STARTUPINFO 结构体。lpProcessInformation:指向一个用来接收新进程的识别信息的 PROCESS_INFORMATION 结构体。
为了获取启动后的程序的主窗口句柄,在调用 CreateProcess() 之前,我们需要使用一个 Windows 的系统钩子来截获窗口创建的事件:
hHook = SetWindowsHookEx(WH_SHELL, ShellProc,(HINSTANCE)hDllHandle,NULL); |
这里,我们使用的钩子类型是 WH_SHELL。这种钩子可以截获所有顶级窗口创建或者激活的事件。函数的第二个参数是事件处理函数。我们的处理函数叫 ShellProc。我们之后会介绍。
启动应用程序之后,我们需要获取应用程序的主窗口之后才能继续运行。这里需要实现进程间的同步。在我们的主进程中,我们需要等待,当应用程序的主窗口创建之后,我们发一个消息,通知我们的主进程继续执行。
我 们这里使用 Windows 的 Event 来实现同步。我们首先调用 CreateEvent 来创建一个事件,然后调用 WaitForSingleObject()等待事件的状态改变。在我们的 ShellProc 处理函数中,我们一旦获取应用程序主窗口句柄,我们会改变事件的状态以通知主进程继续执行。
以下是创建事件的代码,我们创建了一个名为 Global\WaitWindowCreatedEvent 的事件:
SECURITY_ATTRIBUTES secuAtt; |
等待事件状态变化可以调用以下代码:
WaitForSingleObject(hEvent,1000*60); |
为了避免无限的等待下去,我们设置了一个最长的等待时间,为60秒。
下 面我们再来看 ShellProc 的处理代码。这个函数中,我们主要是要获取应用程序的主窗口。根据 Windows 系统 WH_SHELL 钩子的定义,钩子的处理函数的第一个参数是事件类型,第二个参数是窗口句柄。我们首先判断窗口的类型是否是 HSHELL_WINDOWCREATED,然后判断对应窗口所属的进程号是否等于我们所启动的应用程序,如果需要还要判断窗口类型。一旦我们找到了应用 程序主窗口,我们通过调用 SetEvent 来通知主进程继续执行。
LRESULT CALLBACK ShellProc(int nCode,WPARAM wParam,LPARAM lParam){ |
获 取应用程序的主窗口句柄之后,在 Java_com_reparent_ReparentUtil_startAndReparent 函数的最后,我们通过调用 Windows 的 SetParent 函数将其设置成我们的子窗口,同时调整一下应用程序窗口的大小以使其能刚好显示在我们的窗口中。为了避免窗口的闪烁,我们先将窗口隐藏,reparent 之后再显示。为了去掉应用程序的窗口栏,我们需要将应用程序的窗口类型改为 WS_POPUP。
if(hChildWnd!=0){ |
实 现了 startAndReparent 方法后,只要将我们 SWT 窗口句柄传入,我们就可以将一个 Windows 本地应用嵌到我们的 SWT 窗口中了。为了方便使用,我们可以将 Windows 本地应用包装到一个 SWT Control 中,这样我们就可以象使用普通 SWT Control 一样使用 Windows 应用程序的窗口。下面我们来看如何实现对 Windows 应用程序窗口的包装。
首先我们定义一个 Control,它从 Canvas 继承而来。我们用它来作为本地应用程序窗口的父窗口,同时实现对它的管理。我们主要要实现以下几个方面的管理:
- 窗口的创建:当我们 SWT 窗口创建时,我们需要将本地应用程序窗口创建出来
- 窗口的销毁:当我们 SWT 窗口销毁时,我们也要将本地应用程序窗口销毁。
- 焦点控制:当我们的 SWT 窗口获取到焦点时,我们要将焦点设置到本地应用程序窗口中。
- 窗口大小的变化:当我们的 SWT 窗口的位置或大小发生变化时,我们要通知本地应用程序窗口改变它的位置或大小。
首 先我们来看窗口的创建和销毁。我们需要监听 SWT 窗口的 Paint 事件和 Dispose 事件,在响应 Paint 事件中创建本地应用程序窗口,在响应 Dispose 事件中关闭本地应用程序窗口。需要注意的是,我们创建本地应用窗口可能需要花较长的时间,为了避免阻塞 UI 线程,我们将其放在一个线程中执行。如下面的清单所示:
public class NativeControl extends Canvas{ |
在 paintControl(PaintEvent arg0) 函数中调用 ReparentUtil.startAndReparent(NativeControl.this.handle,startCommand,wndClassName) 来启动 Windows 应用程序并将应用程序窗口显示到 SWT 控件中。当 SWT 空间销毁的时候也要将 Windows 应用程序的窗口销毁。SWT 的 OS 类提供了 SendMessage 方法来实现将窗口销毁:OS.SendMessage(childWnd, OS.WM_CLOSE, 0, 0);childWnd 就是要销毁的窗口的句柄。
窗口焦点的控制和窗口的销毁比较类似,我们先监听父窗口的焦点事件,一旦获取焦点,我们将焦点设置到本地应用程序的窗口中。同时,我们需要加一个键盘事件监听器,这样当用户按“Tab”键时,焦点才能跳转到我们的父窗口控件。如下面的清单所示:
this.addFocusListener(new FocusListener(){ |
SWT 的 OS 类提供了 SetForegroundWindow 函数来将焦点设置到某个窗口上,函数的参数指定要设置焦点的窗口句柄。
窗口的大小的控制也是类似的。我们需要监听父窗口的窗口事件,一旦有窗口大小变化,我们就调整本地应用程序的窗口大小。
this.addControlListener(new ControlListener(){ |
同样的我们利用 SWT 提供的函数来设置窗口的大小和位置,SetWindowPos 的参数分别是要设置的窗口句柄以及窗口位置大小。
最后我们需要添加一些方法,让用户可以设置启动应用程序的命令以及应用程序的窗口类型。
public void setStartParameters(String startCommand,String wndClassName){ |
这样我们就开发了一个 SWT 的控件,它可以将指定的 Windows 本地应用程序启动并将程序的窗口嵌入到控件中。对这个控件的使用和普通 SWT 的控件一样,唯一的区别就是要在窗口显示前调用 setStartParameters() 方法设置 Windows 本地应用程序的启动命令和窗口的类型。
下面是一个简单的例子,把 Windows Messager 嵌入到了我们的 SWT 的窗口中。
public class ReparentTest { |
通过 setStartParameters() 方法来设置要启动的程序的路径以及该程序的窗口类型,在这里我们启动 MSN,对应的窗口类型是 MSBLClass:
control.setStartParameters("C:\\Program Files\\Messenger\\Msmsgs.exe","MSBLClass"); |
以下是代码显示的结果。我们可以拉伸改变窗口的大小,这时里面的 Messager 的窗口大小也会随之而变化。当焦点在 Test 按钮上时,按“Tab”键,焦点也会跳转到 Messager 的窗口上。
图 1. 图片示例
本 文介绍了将一个本地应用程序窗口集成到 Eclipse RCP 窗口中的相关技术。文中主要讨论的集成第三方的应用程序,由于我们不掌握第三方应用程序的代码,这种集成方式还是比较简单。例如本地应用程序的菜单还是显 示在我们的SWT父窗口中,而不是显示在 Eclipse RCP 应用程序的主菜单中。有时,我们也需要将我们自己开发本地应用程序集成到 Eclipse RCP 程序中。其实现原理也和本文讲述的一样。不同的是,我们可以实现更多的对我们本地应用程序的控制,从而实现更紧密的集成。例如,我们的本地应用程序可以提 供 API 让 RCP 程序获取自己的主菜单,并且将其主菜单显示在 RCP 程序的主菜单中。
相关推荐
SWT是Eclipse RCP的一部分,提供了一套与操作系统原生控件相集成的GUI组件,使得Eclipse RCP应用能够拥有与本地应用相似的外观和感觉。SWT通过JNI(Java Native Interface)与操作系统交互,实现了高性能的图形用户...
Eclipse Rich Client Platform (Eclipse RCP) 是一个基于Eclipse框架构建跨平台富客户端应用程序的开发平台。Eclipse RCP 利用 Eclipse 的核心组件和技术,如 OSGi 和 Equinox,来构建灵活且可扩展的应用程序。 - *...
5. **国际化和本地化**:Eclipse RCP内置对多语言支持,方便开发者为不同地区和语言的用户提供本地化的应用程序。 6. **版本控制集成**:Eclipse RCP与多种版本控制系统(如Git、SVN等)无缝集成,便于团队协作和...
通过解压并运行这个压缩包中的Eclipse RCP,开发者可以获得一个完整的开发环境,用于创建、测试和调试基于Eclipse RCP的应用程序。开发者可以根据需求选择和安装额外的插件,以支持特定的编程语言或开发工具,如...
传统的Eclipse插件开发通常聚焦于集成到IDE环境,而RCP则拓宽了应用的边界,鼓励开发者思考自定义框架以及如何让他人整合进自己的产品中。 ### RCP架构师的角色 RCP架构师不仅负责编写应用程序,还涉及多个层面的...
Eclipse Rich Client Platform (RCP) 是一个强大的框架,用于构建桌面应用程序,它基于 Java 技术并充分利用了 Eclipse 的插件系统。本教程将引导您了解如何创建并测试您的第一个 Eclipse RCP 应用程序。 一、...
8. **国际化(i18n)与本地化(l10n)**:Eclipse RCP支持多语言环境,开发者可以通过简单的配置实现应用程序的国际化和本地化。 9. **调试与测试**:Eclipse RCP提供了一套完整的调试工具,包括插件调试器,使得...
标题中的"RCP-publin"可能是指一个关于Eclipse RCP开发的发布或演示项目,而提供的描述提到了一个5MB大小的可执行文件(exe),这通常是一个Windows平台下的应用程序。 这个5MB的`Soft_Q7661026.exe`文件很可能包含...
RCP(Rich Client Platform)是Eclipse基金会推出的一个框架,用于构建复杂的桌面应用程序。它为开发者提供了一种结构化的开发环境,支持插件化,允许开发者通过添加、扩展功能来创建自定义的桌面应用。在RCP环境中...
### Eclipse富客户端平台:设计、编码与打包Java...通过本书的学习,开发者可以快速掌握如何构建具有丰富、本地化的图形用户界面的Java应用程序,并能够充分利用Eclipse RCP的强大功能,创建出高质量的桌面应用程序。
Tomcat允许开发者在本地环境中部署和运行Java Web应用程序。在Eclipse中集成Tomcat,可以方便地进行Java Web项目的开发、调试和测试,无需离开IDE就能启动和停止服务器,大大提高了开发效率。 为了在Eclipse中使用...
相较于传统的客户端/服务器或浏览器/服务器模式,RCP 应用程序提供了更丰富的用户体验,支持离线工作,并能够利用本地计算机资源。 #### 二、Eclipse RCP 架构详解 Eclipse RCP 是基于 Eclipse 平台构建的应用程序...
1. **RCP架构**:RCP应用程序的基础结构,包括工作台(Workbench)、窗口(Windows)、视图(Views)和编辑器(Editors)。 2. **启动配置**:理解启动配置文件(`.product`),定义RCP应用程序的外观和行为。 3. ...
DWR 是一种开源的Java库,它简化了Web应用程序中JavaScript与服务器端Java代码之间的通信。通过DWR,开发者可以像操作本地对象一样操作远程对象,极大地提高了用户体验,因为它减少了页面刷新的需求。DWR的核心特性...