Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / Visual C++ 9.0

Debugging a JNI Application using Netbeans and Visual Studio

Rate me:
Please Sign up or sign in to vote.
4.69/5 (13 votes)
14 May 2012CPOL8 min read 102.6K   1.2K   17   34
This article shows how to create a Java Swing GUI application in Netbeans and interface it with JNI DLL.

Introduction

This article explains how to create a Java swing application using the Netbeans IDE and how to use JNI to communicate with native C++ code. It also shows how to debug both the Java application as well as the native C++ DLL.

Background

Many times, we may be in a situation where the major part of an application including the GUI needs to be developed in Java and some legacy library already written in C or C++ needs to be used for some functionality of the application. In such a situation, Java Native Interface (JNI) is used to write wrappers around the C/C++ library calls and then interface those wrapper DLLs with Java code.

Let's Begin...

First let us start by creating a simple desktop application using the Netbeans IDE.

Start a new Java project in Netbeans and select "Java Desktop application" from the New Project wizard.

DebugJavaJNIApplication/01_NewJavaProj.jpg

In the next page, set the name of the project as NativeGUI, you can choose the name you like.

DebugJavaJNIApplication/02_NewJavaProjName.jpg

The wizard will populate the project with the code for a basic Desktop Application and open up the interactive GUI editor.

DebugJavaJNIApplication/03_DesktopApp.jpg

Select and delete the menubar and the statusbar. Add components to the GUI as shown in the image below:

DebugJavaJNIApplication/04_DesktopAppMod.jpg

Delete lines 29 to 81 in the NativeGUIView.java file by switching into the Source view mode. This was the code autogenerated for the statusbar animation which needs to be removed. Also remove the unused member variables. Netbeans IDE will visually help you do all this. Optionally, you may choose to keep the menubar and statusbar to avoid hassles of deleting the code correctly.

Switch back to Design view mode and right click on the Add button and click Set Action from the context menu. You will get the Set Action dialog. Drop down the Action combo-box and select Create New Action.

DebugJavaJNIApplication/05_AddListener.jpg

Enter the action name as onAddClicked and press OK.

DebugJavaJNIApplication/06_ActionName.jpg

The wizard will add the code for the Listener and you will be taken to the code editor where you will enter the following code -- shown in bold.

Java
@Action
public void onAddClicked() {
    double d = 0.0;
    try
    {
        d = NativeAdd.add(Double.parseDouble(jSpinner1.getValue().toString()), 
        Double.parseDouble(jSpinner2.getValue().toString()));
    }
    catch(Exception e)
    {
        JOptionPane.showMessageDialog(mainPanel, e.getMessage());
    }
    jTextField1.setText(Double.toString(d));
} 

Similarly create an Action and set it for the Quit button too. You can switch back to the UI editor by clicking the Design button on the panel just above the editor.

DebugJavaJNIApplication/07_DesignView.jpg

Add a Listener using the same procedure.

Java
@Action
public void onQuitClicked() {
        System.exit(0);
}  

Now right-click the nativegui package in the Projects view and click Add -> Java Class. In the Class dialog, enter the name NativeAdd and click Finish.

DebugJavaJNIApplication/08_AddJavaClass.jpg

The code editor will open up with the newly added class code. Add the following static method lines to the class (shown in bold). This class is the wrapper class for loading and executing the native DLL and execute a method in it.

Java
public class NativeAdd {
    native public static double add(double n1, double n2);
    static
    {
        System.loadLibrary( "NativeAdd" );
    }
}

Run the project once by clicking the green arrow in the toolbar above.

DebugJavaJNIApplication/10_RunProj.jpg

This will serve two purposes for us:

  1. We can see how the GUI looks like so that we can make necessary changes to the layout
  2. It will generate the class files for all the java files. We need the NativeAdd.class file for further processing for JNI.

Click the Add button and you will see lots of errors in the Netbeans output window. These are related to the missing DLL that we are supposed to provide so that the line System.loadLibrary( "NativeAdd" ); finds the DLL to load. This will be solved when we create the DLL with JNI code and place it in a locatable folder by the JVM.

Now open a command prompt window and navigate to the <Your Project Folder>\NativeGUI\build\classes\nativegui folder. All the built classes would be found here. chdir to one level up and issue the following command:

javah nativegui.NativeAdd 

javah.exe is the JNI header generating tool found in the bin folder of your Java SDK installation. Ensure it to be in your path.

You will find a C header file in the name nativegui_NativeAdd.h generated in the folder. The file name is in the format packagename_classname.h. Open it to find a function in name Java_nativegui_NativeAdd_add. The name is in the format Java_packagename_classname_methodname. This function would actually be loaded from a DLL named NativeAdd.dll. Remember the argument we had given for the System.LoadLibrary method? This is the content of the nativegui_NativeAdd.h file.

C++
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class nativegui_NativeAdd */

#ifndef _Included_nativegui_NativeAdd
#define _Included_nativegui_NativeAdd
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     nativegui_NativeAdd
 * Method:    add
 * Signature: (DD)D
 */
JNIEXPORT jdouble JNICALL Java_nativegui_NativeAdd_add
  (JNIEnv *, jclass, jdouble, jdouble);

#ifdef __cplusplus
}
#endif
#endif 

We will be using this code to create the JNI DLL that implements the function. Remember, only the header has been generated by javah.exe. We need to provide the function implementation. Remember, the code we implement in the NativeAdd.dll is only a wrapper around the native/legacy software API we wish to use with Java. Here, for demonstration purposes, we simply write code to add two numbers. In real life applications, the code for native APIs are called. The design of JNI classes and methods should be done after careful study of the native API functions or classes that you wish to call. You can also call COM APIs on Windows.

Now let us start implementing the code for the DLL.

Start Visual Studio and create a new Win32 Project with the name NativeAdd.

DebugJavaJNIApplication/11_NewWin32Proj.jpg

Select DLL in Application type and click Finish.

DebugJavaJNIApplication/12_DllProj.jpg

The project will be created and populated with code to create a DLL. The file NativeAdd.cpp is also created with only the inclusion of stdafx.h. Add a new header file to the project in the name NativeAdd.h. Now copy the contents of the file nativegui_NativeAdd.h (generated in the netbeans folder) and paste it into the Nativeadd.h file. Implement the function in the Nativeadd.cpp file as shown below:

C++
#include "NativeAdd.h"

jdouble JNICALL Java_nativegui_NativeAdd_add
  (JNIEnv *env, jclass cls, jdouble n1, jdouble n2)
{
    return n1 + n2;
}

Add the java include folder path to Visual Studio either by the following steps ..

1) In the Solution Explorer, right click the project -> Properties.

2) In the property pages, expand C/C++ tree and select General node.

3) In the page add the "<path_to_jdk>\include" and "<path_to_jdk>\include\win32" folder path to "Additional Include Directories".

or by the steps below...

1) Click on Tools->Options in the menu bar.

2) In the Options dialog navigate to the Projects and Solutions->VC++ Directories node.

3) In the page, use the drop down box labelled "Show Directories For" to select "Include Files".

4) Create a new entry for "<path_to_jdk>\include" and "<path_to_jdk>\include\win32" folder path.

The second option is more prefered to the first one which is project specific only.

Now we are good to build the project.

Build the project. The file NativeAdd.dll is created in the Debug folder in the DLL Project path.

Note: You also have to add the library path and jvm.lib library entry to the linker if you would be accessing the JVM inside the C++ code.

Now we have the JNI code DLL and the Java GUI that uses it. But how will the DLL get loaded? For that, you have to copy the DLL in the <Your Java SDK Folder>\bin. But if we are running the GUI project from Netbeans, it is not required. We can simply set the working directory in the Run settings of the Project Properties dialog. You can right-click the project in the Netbeans Project View window and click on Properties to get the dialog.

DebugJavaJNIApplication/13_RunProperties.jpg

Be sure to choose the path of your project... Not mine! :)

Now run the GUI project and test the addition of two numbers. Hurrah! You have just interfaced native C code to a Java application using JNI. Now let us get into the debugging of the application and see the native C code getting called. Start debugging the Java program by clicking the Debug button on the toolbar. Add a breakpoint in the onAddClicked method of the NativeGUIView class. Enter two values in the spinboxes of the application and click Add.

The debugger halts at the breakpoint.

DebugJavaJNIApplication/14_NetbeansDebug.jpg

Now we must set breakpoint in the native DLL code. In Visual Studio, click Debug -> Attach to Process.

DebugJavaJNIApplication/15_VSDebug.jpg

From the Attach to Process dialog, select the java.exe that runs your application. Remember, there may be more than one instances of java.exe running on your system if some other Java application is running. Be careful to select the java.exe running your application. Click Attach.

DebugJavaJNIApplication/16_VSDebugProcess.jpg


Then add a breakpoint, in Visual Studio, in the native JNI function implementation.

DebugJavaJNIApplication/17_VSBreakpoint.jpg

Note: The breakpoint will not be hit since the DLL has not been loaded by the JVM. The breakpoint symbol is with a small warning icon and the tooltip states that it won't be hit.

Go back to Netbeans IDE and step over each block of code by pressing F8. After you step over the line calling the NativeADD.add method, the DLL will be dynamically loaded by the JVM and Visual Studio will automatically come on top with the breakpoint hit.

DebugJavaJNIApplication/18_BreakpointHit.jpg

Step through the code in Visual Studio by pressing F10 and finally F5 when Visual Studio shows up the warning message box for showing disassembly. The Java application will be shown back on top. Then to further debug the application, go to Netbeans IDE and continue the debugging.

Hope you enjoyed this article!

Points of Interest

COM Server Applications can also be debugged in a similar fashion by attaching the Server EXE to the debugger.

Tip

This is an additional tip from CodeProject member wc2009 (follow the comments portion). If you want to compile the DLL project with MinGW compiler, you must add "-Wl,--add-stdcall-alias" to additional compiler options.

History

  • 31st March, 2010: First release
  • 12th April, 2010: Added tip for MinGW compiler

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager Mahindra & Mahindra
India India
Sharjith is a Mechanical Engineer with strong passion for Automobiles, Aircrafts and Software development.

Comments and Discussions

 
QuestionConcerning the DLL Pin
MohamedMansour28-Jun-12 22:32
MohamedMansour28-Jun-12 22:32 
AnswerRe: Concerning the DLL Pin
Sharjith29-Jun-12 11:26
professionalSharjith29-Jun-12 11:26 
GeneralRe: Concerning the DLL Pin
MohamedMansour1-Jul-12 10:19
MohamedMansour1-Jul-12 10:19 
GeneralRe: Concerning the DLL Pin
MohamedMansour1-Jul-12 23:56
MohamedMansour1-Jul-12 23:56 
GeneralExcellent Tutorial Pin
MohamedMansour27-Jun-12 10:46
MohamedMansour27-Jun-12 10:46 
GeneralMy vote of 5 Pin
Volynsky Alex16-May-12 11:00
professionalVolynsky Alex16-May-12 11:00 
GeneralRe: My vote of 5 Pin
Sharjith17-May-12 14:47
professionalSharjith17-May-12 14:47 
QuestionGreat Article, One Suggestion Pin
David_Eisner14-May-12 10:04
David_Eisner14-May-12 10:04 
AnswerRe: Great Article, One Suggestion Pin
Sharjith14-May-12 10:52
professionalSharjith14-May-12 10:52 
QuestionCaused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
JBoinker26-Mar-12 9:58
JBoinker26-Mar-12 9:58 
AnswerRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
Sharjith26-Mar-12 12:19
professionalSharjith26-Mar-12 12:19 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
JBoinker26-Mar-12 18:22
JBoinker26-Mar-12 18:22 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
Sharjith27-Mar-12 1:37
professionalSharjith27-Mar-12 1:37 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
JBoinker27-Mar-12 3:11
JBoinker27-Mar-12 3:11 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
Sharjith27-Mar-12 12:56
professionalSharjith27-Mar-12 12:56 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
JBoinker30-Mar-12 5:21
JBoinker30-Mar-12 5:21 
GeneralRe: Caused by: java.lang.UnsatisfiedLinkError: desktopapplication1.NativeAdd.add(DD)D Error Pin
Sharjith30-Mar-12 6:12
professionalSharjith30-Mar-12 6:12 
QuestionI get the following error while i exceute the code Pin
JNIprog13-Dec-11 21:22
JNIprog13-Dec-11 21:22 
AnswerRe: I get the following error while i exceute the code Pin
Sharjith14-Dec-11 9:01
professionalSharjith14-Dec-11 9:01 
GeneralRe: I get the following error while i exceute the code Pin
JNIprog14-Dec-11 23:29
JNIprog14-Dec-11 23:29 
Hi,

I have added the path in the current working directory ..

If you see the error log , the path which it displays is correct and dll is at the same place as the path .

Can you pls help ??
GeneralRe: I get the following error while i exceute the code Pin
Sharjith15-Dec-11 1:38
professionalSharjith15-Dec-11 1:38 
GeneralExcellent Pin
danielbc8227-Mar-11 16:39
danielbc8227-Mar-11 16:39 
GeneralDebugging on VS6.0 Pin
gilmarshow1-Nov-10 21:52
gilmarshow1-Nov-10 21:52 
GeneralRe: Debugging on VS6.0 Pin
Sharjith8-Nov-10 13:43
professionalSharjith8-Nov-10 13:43 
GeneralHi I get a bug when i do yours Pin
Ghuie20-Aug-10 8:40
Ghuie20-Aug-10 8:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.