Home Page (on the Web) - News and Updates
Part One - Introduction and Tutorial
Part Two - Techniques and Examples
Part Three - The Invocation API
Quick Start If you're familiar with Delphi and JNI and want to get started right away. Background Why JNI? Why Delphi? Overview What's here? Translation A brief look at translating the C/C++ header file to Delphi. Example The canonical HelloWorld program. A Closer Look The HelloWorld program in excruciating detail. Troubleshooting Typical errors when programming with the JNI. Debugging Stepping through your Delphi DLL at runtime. Summary What's next? Helpful Resources Sources to help you with Delphi and the JNI
C/C++ programmers should check out these pages:
Programming with the Java Native Interface This is a tutorial that shows how to use the Java Native Interface with Linux, Solaris, and Windows NT.
Using the Java Native Interface with C++ This has a lot of examples of how you might use the Java Native Interface. Contrasts Sun's vision with Microsoft's. Also includes some crude benchmarks. This is an older document. (January 1998)
Experienced JNI/Delphi programmers should grab JNI.pas and JNI_MD.INC and get started. The source files used in this part of the tutorial can be downloaded here.Delphi programmers may also want to check out the C/C++ links above. Although those pages are targeted at C/C++ programmers, there is information about the Java Native Interface (not necessarily related to C/C++) that may not be duplicated here.
A couple of years ago I did some exploration of the Java Native Interface. At that time, everything "native" was being done in C/C++. That really wasn't a problem, though, since the syntax of the Java language targets C++ programmers. (This is clearly evident by the similarities between the two languages.) Now, this isn't to say that Java is identical to C++ (or unlike other languages for that matter.) It's just an observation of the syntax of the two languages. Also, all of the available JNI documentation/references were aimed at C/C++ programmers.My first go-round with the JNI is documented here. I basically just presented my findings (albeit, crude.) There wasn't much documentation around at the time (circa January 1998), so I didn't have too many references. After that initial exposure, I refined the experiment. That result was more of a tutorial and can be found here.
Since the time of those experiments, I have continued to receive occasional emails from people asking for further assistance. When I was able to help, I did. Until recently, I hadn't even looked at the JNI stuff. That changed a few weeks ago when I decided to try implementing the native portion using Borland/Inprise's Delphi language. The result: The acronyms 'JNI' and 'RAD' can now be used in the same sentence. I'm not going to get into a debate over why one would want to use native code from within Java code, I'm just going to show you how to do it. Again, this document is aimed specifically at Delphi programmers. C/C++ programmers would want to check out one or both of the links mentioned above.
Before starting this, you should be able to compile and execute Java code on your machine. This document focuses on getting you up to speed with Delphi and the Java Native Interface. I'm not an expert on Java, and setting up and configuring a compile-time and run-time environment sometimes seems harder than actually writing the Java code (although I think that the Java 2 stuff makes it a little easier.)Another important point about this Delphi interface is that it hasn't been tested thoroughly. I present several different "tests" (examples), but there are over 200 distinct functions in the API of the JNI. I'm probably only using a couple dozen at most. But, you'll see how similar they are. In fact, 90% of the Delphi interface looks pretty repetitive. Once you get the "pattern" down, you can easily translate any function's signature. For Part One, though, you shouldn't have any problems because I'm really not using any of the JNI API.
One last thing: I used version 5.0 of Delphi to develop this. I'm not sure how the other versions will handle it. If I find the time, I will run the tests through the other versions. (I have all 5 versions of Delphi, I just don't want to spend the time installing/uninstalling them!!) If anyone tries this with another version, please feel free to let me know how it went.
The tutorials have been updated to reflect Kylix, the Linux version of Delphi. These documents were originally written before Kylix, so naturally they were Windows-only. However, most (if not all) of the material applies to Kylix and Linux as well. Rather than re-write a separate document for Kylix (which would be about 98% identical in content) or use the phrases "Delphi or Kylix" and "DLL or SO" everywhere, I've left it Windows-specific. I've tried to point out any differences between the two environments, but may have missed something along the way. When I say Delphi, I am referring to both Delphi and Kylix. When I say DLL, I am referring to both DLLs (.DLL) on Windows and shared libraries (.so) on Linux.
First off, it's important to note that this isn't the only possible translation. As I will show later, you can translate a type incorrectly (loosely speaking), but as long as the two types have the same size, everything will work. As a preview to this, you'll see a lot of things typed as Pointer, which is very generic, and as far as the JNI is concerned, any type that is exactly 4-bytes wide (at the time of this writing) is compatible with a Delphi pointer.
Originally, I had planned to explain the jni.pas in detail. But, I've decided to leave that for a more advanced topic. It's not that the translation is advanced (quite the contrary), it's just that it isn't necessary to understand the details to start using the JNI with Delphi, which I'm assuming is why you're here. I will describe a couple of key points about the translation from C/C++ to Delphi. If you are not interested (and it's quite alright if you are not interested) you can skip to the Example below. If you do wish to know more, you should look at these:
- jni.pas - A Delphi interface to the Java Native Interface.
- The JNI Specification - This is Sun's documentation. It's well written and is considered the authority on the subject. If there is a conflict between what I say and what Sun says, you should follow Sun's advice.
The two most important guidelines when translating a C/C++ header file (interface) is to make sure that:
Size
- the Delphi type you are mapping to a C/C++ type is the same size as the C/C++ type.
- the fields declared in a Delphi record are in the same order as the fields in the corresponding C/C++ struct.
OrderIt is important that the data types that are passed between Java and native code are the same size. The table below shows this mapping. The types labeled as Native Type are the types that will be defined in Delphi. This is safer than trying to remember that a long in Java is an Int64 in Delphi, or that an int in Java is a Longint in Delphi. Also, there is no void type in Delphi, but there is a 'void pointer', Pointer, which we will see a lot. This table is not exhaustive. It just shows the primitive types.
Java Type Delphi Type C++ Type Native Type Description boolean Boolean unsigned char jboolean 8 bits, unsigned byte Shortint char jbyte 8 bits, signed char WideChar unsigned short jchar 16 bits, unsigned double Double double jdouble 64 bits float Single float jfloat 32 bits int Longint long jint 32 bits, signed long Int64 __int64 jlong 64 bits, signed short Smallint short jshort 16 bits, signed void N/A void void N/A The type definitions below are excerpts from jni_md.pas and jni.pas which show how Delphi types are mapped into Java types:
type (* * These are Win32-specific types *) JInt = Integer; JLong = Int64; JByte = Shortint; (* * JNI Types *) JBoolean = Byte; JChar = WideChar; JShort = Smallint; JFloat = Single; JDouble = Double;
Preview:
Here are a couple of Java functions:and this is how they would appear in Delphi:double CalculateAverage(int A, int B, int C); void printString(String value);
Actually, the functions would look more like this:function CalculateAverage(A: JInt; B: JInt; C: JInt): JDouble; procedure printString(Value: JString);
but we're not there yet. At this point, it's important that you recognize the correlation between Java types and Delphi types.function Java_Native_CalculateAverage(PEnv: PJNIEnv; Obj: JObject; A: JInt; B: JInt; C: JInt); stdcall; procedure Java_Native_printString(PEnv: PJNIEnv; Obj: JObject; Value: JString); stdcall;
The majority of the methods declared in jni.pas are methods of a this record:
JNINativeInterface_ = packed record reserved0 : Pointer; reserved1 : Pointer; reserved2 : Pointer; reserved3 : Pointer; GetVersion : function(Env: PJNIEnv): JInt; stdcall; (* . . . Over 200 additional methods declared here . . . *) end;Every translation of the C/C++ header file jni.h must declare the methods of a record in the exact same order.Note that the order of the records in the Delphi file is not important. Only the order of the methods within the records is important.
One of the best ways to learn a new programming skill is by example. In keeping with tradition, I present the canonical programming example that simply prints the words "Hello World!" to the display. The twist is that Java code will invoke a native function to do the actual printing via the Delphi library function, WriteLn.1. Create the Java files. First, create the two Java files as shown below.
HelloWorld.java:2. Compile the Java files.Main.java:class HelloWorld { public native void displayHelloWorld(); static { System.loadLibrary("HelloWorldImpl"); } }
class Main { public static void main(String[] args) { HelloWorld hw = new HelloWorld(); hw.displayHelloWorld(); } }
3. Create and build the Delphi file. You will end up with a file called HelloWorldImpl.dll.javac HelloWorld.java javac Main.javaHelloWorldImpl.dpr:4. Execute the program. You should open a command window (DOS prompt) in the directory where your Delphi and Java files are and execute it there.library HelloWorldImpl; uses JNI; procedure Java_HelloWorld_displayHelloWorld(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} begin Writeln('Hello world!'); end; exports Java_HelloWorld_DisplayHelloWorld; end.
java Main Hello world! <--- this is displayed on the screen
1. Create the Java Files4. Execute the program. In a nutshell, this is what's happening:HelloWorld.java Create the Java class that declares the native method. In this example, the Java class definition is trivial. There are no members or methods defined within the class. There are 2 key points here:2. Compile the Java files.
- Make sure to include the native keyword when declaring the native method, otherwise, it's just another Java class method. This also tells the JVM at runtime that the function is implemented in a DLL somewhere and not in this class.
- Also, be sure that the name of the shared library is correct. Note that the name of the DLL does not have to have the same name as the class that exposes the method. In the example, the name of the class is HelloWorld and the name of the DLL is HelloWorldImpl. (The static section of a class is executed when the class is loaded. We use this section to load the DLL that contains the implementation of the native method.)
Additional note: There is a tool that comes with the JDK called javah. This is a program that automatically generates a C/C++ header file from the native methods in a class file. That's another reason why it is important to include the native keyword. (Note to self: Write a javah-like tool that produces a Delphi-compatible file.)class HelloWorld { public native void displayHelloWorld(); static { System.loadLibrary("HelloWorldImpl"); } }
There is now a tool available that will produce a Delphi/Kylix project file (.dpr) from a Java class file (.class). It is available from my Delphi/JNI home page. There are actually two tools: a Java-based one (JavaToDPR) and a native Delphi-based one (javadpr) that do the same thing.
Main.java Create the Java class that will test the native method.
- Notice that this Java code has no knowledge that the method displayHelloWorld is a native method. This allows the implementor of HelloWorld.displayHelloWorld() to implement it either as a native method, or as a Java method. The calling program will never know and will never need to be changed if the implementation of HelloWorld.displayHelloWorld() ever changes.
class Main { public static void main(String[] args) { HelloWorld hw = new HelloWorld(); hw.displayHelloWorld(); } }
3. Create and build the Delphi file.javac HelloWorld.java javac Main.javaThis, of course, compiles the Java files and creates two files, HelloWorld.class and Main.class, respectively.Now things are getting a little interesting. There are several points here that you should take notice of. I'll go through this code in much more detail than the Java code above. That's the main purpose of this document: I want to show you how to use Delphi to implement native methods to be called from Java. I've also included line numbers below, so that I can easily refer to the source code.First of all, notice that the file that implements the native method, HelloWorldImpl.dpr, is a .dpr file: a Delphi project file. Some Delphi programmers may never have spent much time dealing with this file. This is quite natural, since the Delphi IDE does a pretty good job of generating and modifying this file for you automatically. The project file is not that different from other units (.pas files.) I decided to put everything in the project file because the code to implement the method was so trivial. (You could have put the function in a unit file and then added the unit to the uses section in the project file.)
Ok, let's look at the file in detail:
1. library HelloWorldImpl; 2. 3. uses 4. JNI; 5. 6. procedure Java_HelloWorld_displayHelloWorld(PEnv: PJNIEnv; Obj: JObject); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} 7. begin 8. WriteLn('Hello world!'); 9. end; 10. 11. exports 12. Java_HelloWorld_displayHelloWorld; 13. 14. end.
- Line 1: Since this is a DLL, and not an executable program (.exe), we use the library keyword to tell Delphi to create a DLL file. The name of the DLL will be HelloWorldImpl.dll.
- Line 4: This is probably the most important line (if there can be only one.) This file, jni.pas, contains the interface to the JNI. This will be used by every DLL that needs to be accessed by Java. You can basically consider it a black box. However, you have the source, so you can view it to get a better understanding of what's going on behind-the-scenes.
- Line 6: There are several pieces of important information here that must be specified with each function that is going to be called from Java:
- This function is actually a Delphi procedure. This is simply because there is no return value. Had the Java class declared the method to return a value, you would have seen the function keyword instead. We will see functions later on. Unless otherwise specified, when I refer to a Delphi function I am also talking about a Delphi procedure as well.
- All functions/procedures that you want to be accessed from a Java class must have the term Java_ prepended to them. Also, the name of the class that declares the native method (HelloWorld in our example) must follow the Java_ term. An underscore character follows the Java class name and, finally, the name of the method itself. In our example, the fully decorated function name is Java_HelloWorld_displayHelloWorld. Unlike Delphi, the Java language is case-sensitive, so you must make sure that the Delphi function definitions use the same case as the Java method declarations. (Another reason for a tool like javah. Maybe call it javad? Any takers?)
- What gives with the parameters? There were no parameters specified in the Java class! Every Java method that is implemented in native code will have two additional parameters. They are both pointers that the native function can use to access functions in the Java object that called the function and to access functions in the Java runtime environment. The types PJNIEnv and JObject are both defined in jni.pas
The first parameter is a pointer to the runtime environment. The second parameter is a pointer to the object that called this method. The second parameter is sort of like the Self member of a class in Delphi. In this example, since the function is so trivial, we don't use either of these. However, it is important that you include them in the definition of the function because they will always be passed in to the function whether or not they are used. Later, we will see heavy use of these parameters.
- Unless you have written DLLs before or have had to access code written in another language (or implemented a Windows callback), you may have never used the stdcall directive. This tells Delphi to generate code that will push the arguments onto the stack from right to left. Delphi uses the fast register calling convention by default, which uses a combination of registers and the stack to pass arguments to functions. It's not important to understand the details, but if you forget to add the stdcall directive, your DLL will most surely cause an exception.
Kylix note: Use the cdecl directive instead of stdcall. If you plan on writing apps to run on both Windows and Linux, you should use the IFDEF technique shown above.
- Line 8: This is what we are actually trying to accomplish! It seems like a lot of work to print a line of text, and it is. However, it's doubtful that anyone would go through this much trouble to print a line of text when they could clearly do it from Java. But, as you probably have already figured out, in the real world we would be using/implementing some serious native code that just isn't possible or efficient to implement in Java.
- Line 12: In order for our function to be accessible from the outside, we must export it. This is done in the exports section of a Delphi library (DLL.) Notice that you don't provide the parameters or function/procedure keyword.
java Main <--- you type this at the console
- Java loads Main.class and calls main. This is typical for Java program.
- Java executes the line:
HelloWorld hw = new HelloWorld();This line causes a new HelloWorld object to be created. When this class is created, the code inside it's static section executes:The System.loadLibrary method causes the DLL (HelloWorldImpl.dll) to be loaded by the operating system. If our DLL would have wanted to perform any kind of startup action or initialization, it would have performed it at this time. (For this simple example there is no initialization code.)System.loadLibrary("HelloWorldImpl");
- Next, Java executes the line:
hw.displayHelloWorld();This is a call to the displayHelloWorld method in the HelloWorld object. However, since this method is a native method of the HelloWorld object, the call ends up going to the displayHelloWorld method (Java_HelloWorld_displayHelloWorld) implemented in HelloWorldImpl.dll. This displays the text Hello World! on the screen. This "routing" of method calls from a Java object to a native-code DLL is all transparent to the calling class, Main. Graphically, the process looks like this:
View a large image here.
These are the explanations of the circled numbers in the graphic:
- Java loads Main.class and calls the public static method main.
- Java creates a new HelloWorld object.
- When the HelloWorld object is created, it implicitly calls System.loadLibrary("HelloWorldImpl"); (because it is in the static section of the class) which loads the DLL into memory.
- The DLL is loaded into memory by the operating system.
- Any initialization routines within the DLL are called. (Our example has no initialization.)
- Java executes the statement: hw.displayHelloWorld();
- HelloWorld.displayHelloWorld() is a native method so its implementation is in the Delphi DLL (Java_HelloWorld_displayHelloWorld.)
- The Delphi code executes the WriteLn('Hello World!'); statement which displays the text Hello World! on the screen.
Whew. That sure seemed like a lot of work. Actually, the explanation of what is going on is far more verbose than the actual code. If you look at the Java files, you'll see that each file has about 4 lines of Java code. The Delphi DLL source file contains about 10 or so (depending how you want to format the code.) There's really only 1 line of executable code in the DLL; the line that prints 'Hello World!' to the screen. It's important to realize that (in the graphic above) steps 1 - 5 are executed only once, regardless of how many times hw.displayHelloWorld() (or any other native method of the HelloWorld class) is called. This is similar to how DLLs work with regular executables (.exe) programs: the DLL is loaded and any overhead associated with the loading and initialization of the DLL is done once at load time.Also, this is just a very high-level view of what's going on. There are some pretty interesting things going on under the covers. But, that's beauty of it: you don't need to know or worry about those details.
For the most part, programming with the JNI is a pretty straight-forward process. However, there are a lot of details involved. As is true with most programming, one missing piece can cause the whole program to fail. In this section, I will show you most of the mistakes that you are likely to make. (I've made them all at one time or another!) Understanding the error messages and exceptions will help you to locate the problems within your code. I was able to cause all of these errors by modifying the example above. Hence, some of the error messages will refer to the files in the HelloWorld example. If you are trying this example on your own I highly encourage you to cause these errors to occur. You will see first-hand what I'm talking about and learn from these common errors. By far, the most popular is the java.lang.UnsatisfiedLinkError:java.lang.UnsatisfiedLinkError
There are basically two categories of UnsatisfiedLinkError errors.
- The first type of java.lang.UnsatisfiedLinkError looks something like:
This message says that Java can't locate the HelloWorldImpl DLL. Here are some common causes:Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorldImpl in java.library.path
- The DLL is named incorrectly. Make sure that the name of the DLL you are loading in the static section matches the name of the DLL on the disk. Be sure that you are not including the .dll extension in the call to System.loadLibrary:
static { System.loadLibrary("HelloWorldImpl"); // correct System.loadLibrary("HelloWorldImpl.dll"); // WRONG! }- The DLL is not in the search path. In Windows (DOS) by default, the directory you are in (at a command prompt) is included in the search path. If you want Java to be able to find the DLL from another directory, make sure that you add that directory to the system path or move the DLL into a directory that is already in the system path.
- Another java.lang.UnsatisfiedLinkError error might look like this:
This message indicates that the HelloWorldImpl DLL was located and loaded by the system. However, it says it can't find the indicated method (displayHelloWorld in the example.) There are several reasons that this might happen:Exception in thread "main" java.lang.UnsatisfiedLinkError: displayHelloWorld at Main.main(Main.java:6)
- The name of the method is incorrect. Make sure that the name in the DLL matches the name in the Java class exactly. You may have made one or more of these errors:
- You spelled the method name differently. (It happens!)
- The case is incorrect. Remember, Java is case-sensitive and Delphi is not, so you may have inadvertently used the wrong case.
- You decorated the method name incorrectly. It must start with Java_ then the class name HelloWorld, then and underscore _, then the name of the method displayHelloWorld. (For classes other than our HelloWorld example, you would substitute that class name in place of HelloWorld.)
Technically, the class name is the fully qualified name, including the package name. These examples are trivial, so packages are not used. If your Java class resides in a package, make sure to include the package name as part of the class name.
- The method is not exported. The method must be added to the exports section of the project file. (It is common to forget this when you first start writing DLLs.)
Run-time exceptions
There are many ways that a native DLL can cause an exception. However, the errors I show are unique to JNI programming and not programming in general. For example, dividing by zero can cause an exception, but that isn't related to JNI programming.
It's also important to realize that the compiler can't help you here by detecting potential conflicts. This is because the Delphi compiler has no knowledge of the Java code and the Java compiler has no knowledge of the Delphi code. Sure, we've mapped the types and decorated the function names, but there is no way for the compiler to check that for us. A tool like javah would help minimize the problems, but it still wouldn't be fool-proof.
Since these are Windows DLLs, exceptions are likely to cause a dialog box to be displayed (as opposed to the Java exceptions listed above that printed error messages to the screen.) Rather than describing these "cryptic" error messages, I'll just insert screen shots so you can see for yourself. (Note that the hex numbers and addresses may be different on your machine.)
Most of the exceptions generate similar error messages so it is usually difficult (if not impossible) to tell what caused the error simply by looking at the dialog box. However, I'll point out some subtle clues that can help you locate the problems.
- Missing stdcall directive. The most common mistake made by Delphi programmers is forgetting to add the stdcall directive at the end of the procedure/function. (I'm guessing about the other Delphi programmers because, frankly, I haven't talked with any other Delphites about their JNI experiences. I'm just assuming that they would make this mistake because I made it often!)
A subtle difference in this exception as opposed to other exceptions is that the method call fails immediately. What I mean to say is that the call itself causes the exception. None of the code is executed within the native method. This can be helpful because some exceptions (as we'll see shortly) occur when the method returns, so all of the code within the method is executed. When I remove the stdcall directive in our example, the text Hello World! never gets displayed. This is an indication that the calling convention is incorrect.
This is the message I get when I remove the stdcall directive:
- Incorrect procedure/function signature. This happens when the number, type, and order of parameters in the Java class don't match the number, type, and order of the parameters in the Delphi code. In our example, the displayHelloWorld method was declared as taking 0 parameters. In the Delphi code, we made sure that the procedure expected 0 parameters. (This is not counting the two hidden arguments I discussed that all JNI methods include.) If we add a parameter to the Delphi procedure (an extra integer parameter) we can force this error to happen:
This is the error message I receive:procedure Java_HelloWorld_displayHelloWorld(PEnv: PJNIEnv; Obj: JObject; Extra: JInt); stdcall;
The subtle difference between this exception and the previous one (where I removed the stdcall directive) is that this time the text Hello World! is displayed on the screen before the error message is displayed. It's subtle differences like this that can help you locate where the problems are.
It is not difficult to debug your DLLs. Most modern Integrated Development Environments allow you to specify the host application: the executable program that loads the DLL at run-time. For JNI debugging, the host application is java.exe. To specify the name and location of the application to use to debug the DLL, choose Parameters... from the Run menu:
This displays the Run Parameters dialog box:
In the Host Application edit box, enter the full path to java.exe. (Your path will probably be different.)
In the Parameters edit box, enter Main for our example.At this point, you can set a break point on the WriteLn('Hello World!') statement in the Delphi Java_HelloWorld_displayHelloWorld procedure. Now, press F9 to run the program within the debugger. The debugger should stop on the WriteLn('Hello World!') statement.
Note that you will not be able to step through the Java code. The Delphi debugger has no knowledge of the Java code.
In this document, I showed you how easy it is to access code from a DLL that was created with Delphi. However, 95% of what I discussed applies equally well to C/C++ or any other native language. This introduction to Using the Java Native Interface with Delphi is more of a tutorial than a reference. If you remove all of the detailed explanations above, you will see that the amount of code necessary to call a DLL from Java is quite trivial. Newcomers to Delphi, DLLs, and/or JNI may find this detail necessary and enlightening. More advanced developers may already understand these points.Before proceeding onto Part Two, I strongly encourage you to try this example on your own. The main reason is to prove to yourself that your machine is properly configured to compile and execute Java code. If you are currently able to do so, then it is likely that this example will work just fine. It's a lot easier to troubleshoot problems when the example is trivial.
Download the files used in this tutorial.
Using the Java Native Interface with Delphi (Part Two)
Using the Java Native Interface with Delphi (Part Three)
JNI SpecificationsBooks:
- JNI - Java Native Interface. This link points to the JNI specification set forth by Sun. Consider this the JNI Bible This link includes the specifications for both JDK 1.1 and JDK 1.2 as well as a JNI FAQ. This is the place to start on Sun's page.
Delphi on the Web:
- Essential JNI: Java Native Interface (Essential Java) by Rob Gordon, Robert Gordon, Alan McClellan (Prentice Hall Computer Books, April 1998. ISBN 0136798950)
- The Java Native Interface: Programmer's Guide and Specification by Sheng Liang (Addison-Wesley Publishing Company, June 1999. ISBN 0201325772)
- Delphi in a Nutshell by Ray Lischner (O'Reilly and Associates, March 2000. ISBN 1-56592-659-5)
- Delphi 4 Developer's Guide by Xavier Pacheco, Steve Teixeira (Sams Publishing, August 1998. ISBN 0672312840)
My other JNI work:
- Project JEDI From their mission statement: "An international community of Delphi developers with a mission to exploit our pooled efforts, experiences and resources to make Delphi--the greatest Windows development tool--even greater."
- Pascal Header Translations by Charlie Calvert. This is geared towards achieving "JEDI status." There is a lot of information regarding translating C/C++ header files to Delphi.
- Dr. Bob's Header Conversion I stumbled across this while creating these references. Looks cool!
- Marco Cantu's Essential Pascal This is from his Mastering Delphi series and is an excellent document on Delphi's Pascal-based language.
- Programming with the Java Native Interface This is a tutorial that shows how to use C++ with the Java Native Interface on Linux, Solaris, and Windows NT.
- Using the Java Native Interface with C++. This document has a wealth of examples and techniques for using the JNI with C++. There is a detailed comparison between Microsoft's implementation and Sun's implementation, including the differences in syntax and runtime performance. In addition to the basics, there are examples that demonstrate two-dimensional arrays, callbacks, and exceptions, among other concepts.