Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Embedding a JavaBean in a MFC-Dialog

0.00/5 (No votes)
5 Mar 2004 1  
Embedding a JavaBean without using Sun's ActiveX-Bridge.

Introduction

Some weeks ago, I was wondering how Sun's ActiveX-Bridge was embedding JavaBeans in MFC-Dialogs. After reading some newsgroup articles on that topic, I came to the conclusion that there was no real working example of embedding an own JavaBean in a Dialog by means of the MFC. So I decided to write my own JavaBridge and here is the outcome of my efforts.

But first of all, please excuse me for any mistakes in my written English or the structure of this article, because this is the first article on CodeProject I have ever written.

Using the code

Before you can run the sample project, please make sure that you have properly installed the Java Software Development Kit (SDK) version 1.4.2 or higher on your computer. You can get the SDK from here.

Please also take care, that the JAVA_HOME environment variable is set to the appropriate directory on your system.

I am using the Java Native Interface (respectively the Invocation Interface) for loading the Java Virtual Machine and instantiating the JavaBean. For a better understanding, I divided the classes into two groups. The first group consists of classes covering the JNI issue. You will find them in the subfolder JBridge. Don't bother too much with those classes, because this article is not intended to be an introduction on JNI. You will find proper papers on that topic in the web (see Links below).

The other group of classes cover the MFC issue. Especially CEmbeddedJFrame will be the main point of our interest.

When you start the application, an instance of CEmbeddedJFrame will be created and the init() member function will be invoked from within CGUIBeanDlg::OnInitDialog().

My idea was to create the JavaBean, to embed it in a JFrame instance and to make this frame object a child window of my dialog. The code fragment below shows where this is implemented.

The Java VM and the bean are loaded in line 9. As you can see, the bean is delivered by a Java archive file called bean.jar. You will find this file in the bean subdirectory from your project's working directory. After instantiating the bean, the JFrame object is created. Because I did not want to bother you with JNI details, I wrapped the appropriate JNI invocations in the JFrame class from the JBridge subfolder. Before the frame is shown for the first time, the bean instance is added to the content pane of that frame (see line 23).

For making the frame to a child window of the dialog, it is essential to get the HWND of it. There are two ways (let me better say: two ways I know of) to get the HWND of a Java object from a native application. The first approach is by using JNI to get a pointer to the JAWT interface. This interface provides some functions for getting the drawing surface of a graphics object like JFrame. You can identify the HWND from this drawing surface. But when I implemented this, it was a very unstable and error-prone solution. So I decided to do it the dirty way by searching the appropriate title of the frame. This is done in the operation Attach_JavaFrame().

1  void CEmbeddedJFrame::init()
2  {
3    TCHAR szExePath[MAX_PATH];
4    GetModuleFileName(AfxGetInstanceHandle(), szExePath, MAX_PATH);
5    CString beanjar = szExePath;
6    beanjar = beanjar.Left(beanjar.ReverseFind('\\') + 1) + "bean\\bean.jar";
7
8    //JavaBean laden

9    theAdapter.initf(beanjar, "codeproject", "Editor");
10    JNIEnv *env = theAdapter.getJVMLoader()->getENV();
11
12
13    srand((unsigned)time(NULL));
14    CString title;
15    title.Format("bean_Editor_%d%d", rand(), rand());
16
17    //JFrame-Instanz erzeugen

18    frame = new JFrame((const char*)title);
19
20    frame->setBounds(-100,-100,0,0);
21    frame->show();
22    frame->setVisible(JNI_FALSE);
23    frame->add(theAdapter.getBeanInstance());
24
25    //Nun das JFrame-Objekt zum Child-Window machen

26    Attach_JavaFrame((const char*)title);
27
28    dockundock();
29
30    //Hier wieder einschalten

31    frame->setVisible(JNI_TRUE);
32 }

Finally, this Java frame is made a child window of the dialog by setting the WS_CHILDWINDOW style and the right parent. Please take a closer look into the dockundock() member function.

Known Bugs (your help is welcome ;)

In this example, the JavaBean is directly embedded in the dialog and everything is OK. But if you put that CEmbeddedJFrame in a CTabCtrl, then AWT sends hundreds of WM_NCHITTEST and WM_GETDLGCODE messages (per second!) to that container. Due to that message flooding, the CPU usage increases up to 100% and the whole system hangs.

My first assumption was that this effect has something to do with the container, in this case the CTabCtrl. I decided to embed the CEmbeddedJFrame in a CDialog anytime, using the CDialog as an intermediate layer. But when I forced the CDialog to be a child window of CTabCtrl, it ended up in the same system deadlock.

If you want to see this effect, please try to embed the CEmbeddedJFrame in a CTabCtrl. You can do this easily in the MSVC resource editor. But be careful. When you are using Spy++ and start the application in a debug session, then your system may hang at the beginning of InitApplication().

Any contribution of any kind is welcome on this topic. If you have some ideas why this may happen, please don't hesitate and post a comment.

Links

History

Version 1.0 - Stable on Win2K/XP except one major problem (see above).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here