在探索如何将JavaBeans嵌入MFC对话框的过程中,发现现有的资料并没有提供一个完整的、可工作的示例。因此,决定自己编写一个JavaBridge,以下是努力的成果。
首先,请原谅英语写作或文章结构上可能存在的错误,因为这是在CodeProject上发表的第一篇文章。
在运行示例项目之前,请确保已经正确安装了Java软件开发工具包(SDK)版本1.4.2或更高版本。可以从获取SDK。
同时,请确保系统环境变量JAVA_HOME
设置为适当的目录。
使用Java Native Interface
(JNI)来加载Java虚拟机并实例化JavaBean。为了更好地理解,将类分为两组。第一组包括处理JNI问题的类,可以在JBridge
子文件夹中找到它们。不要过多关注这些类,因为本文不打算介绍JNI。可以在网络(参见下面的)上找到相关论文。
另一组类处理MFC问题。特别是CEmbeddedJFrame
将是关注的重点。
当启动应用程序时,将创建一个CEmbeddedJFrame
实例,并在CGUIBeanDlg::OnInitDialog()
中调用其init()
成员函数。
想法是创建一个JavaBean,将其嵌入到JFrame
实例中,并将这个框架对象作为对话框的子窗口。下面的代码片段显示了这是如何实现的。
在第9行加载Java虚拟机和bean。如所见,bean由一个名为bean.jar
的Java归档文件提供。可以在项目的工作目录的bean
子目录中找到这个文件。实例化bean后,创建了JFrame
对象。因为不想让为JNI细节烦恼,将相应的JNI调用包装在JBridge
子文件夹中的JFrame
类中。在框架首次显示之前,将bean实例添加到该框架的内容窗格中(见第23行)。
要将框架作为对话框的子窗口,关键是获取其HWND
。有两种方法(让更好地说:知道的两种方法)可以从本地应用程序获取Java对象的HWND
。第一种方法是使用JNI获取指向JAWT接口的指针。这个接口提供了一些函数,用于获取像JFrame
这样的图形对象的绘图表面。可以从这个绘图表面识别HWND
。但是当实现这个时,它是一个非常不稳定且容易出错的解决方案。所以决定用一种不太优雅的方式,通过搜索框架的适当标题来实现。这是在操作Attach_JavaFrame()
中完成的。
最后,通过设置WS_CHILDWINDOW
样式和正确的父窗口,将这个Java框架作为对话框的子窗口。请仔细查看dockundock()
成员函数。
在这个示例中,JavaBean直接嵌入到对话框中,一切都很好。但是如果将CEmbeddedJFrame
放入CTabCtrl
中,那么AWT每秒会向该容器发送数百个WM_NCHITTEST
和WM_GETDLGCODE
消息!由于这个消息泛滥,CPU使用率上升到100%,整个系统挂起。
第一个假设是这种效果与容器有关,在这种情况下是CTabCtrl
。决定在任何时候都将CEmbeddedJFrame
嵌入到CDialog
中,使用CDialog
作为中间层。但是当强制CDialog
成为CTabCtrl
的子窗口时,最终导致系统死锁。
如果想看到这种效果,请尝试将CEmbeddedJFrame
嵌入到CTabCtrl
中。可以在MSVC资源编辑器中轻松做到这一点。但要小心。当使用Spy++并在调试会话中启动应用程序时,系统可能会在InitApplication()
的开始时挂起。