load native lib (SWT) with JNI on windows

Ranjit Mathew rmathew@hotmail.com
Wed Nov 20 21:55:00 GMT 2002


Ingo Bormann wrote:
> I did not find it particulary difficult to buid. 
 > You can simply take the swt.jar (containing the class
 > files)and give it to gcj.

This is indeed a simpler approach and I tried it out last
night. In short, it doesn't work yet but we're getting
there. Read on for the gory details.

I extracted all the files in swt.jar into a folder and
created a simple script that invoked "gcj -fjni -c" on
each of the class files.

Right off the hook, I got lots of errors from gcj like
"error parsing constant pool". It turns out that the
GCJ jar tool extracts files in text mode instead of
binary mode - this was easy to fix and I'll submit a
separate patch for fixing this.

Then I ran into problems with the "Point" class in
SWT. What happened was that there's a class named
"org.eclipse.swt.graphics.Point" and there's another
class named "org.eclipse.swt.internal.win32.POINT" -
on the case insensitive Windows filesystem, the
object file names (Point.o and POINT.o) clash and one
of them is overwritten. I fixed this bit by modifying
my script to explicitly compile "foo.bar.Wombat.class"
to "foo_bar_Wombat.o".

After all the object files were created (except for
the Win32 AWT Integration classes in the package
"org.eclipse.swt.internal.awt.win32" as Ingo had
pointed out), I created libswt.a like this:

    ar rcs libswt.a *.o
    ranlib libswt.a

Now I was finally able to link my "HelloSWT" program!

However, when I tried to run it I got an UnsatisfiedLinkError
for GetVersionExW. This error had me completely off
track for a while - as if explicitly designed to thwart
the attempts of prospective JNI hackers, the
"org.eclipse.swt.internal.win32.OS" class declares
(and swt-win32-2049.dll defines) JNI methods that
have the *same name as Win32 API functions*! Ugh!

In any case, it turned out that the SWT DLL exports
JNI native methods as "_Java_foo_Bar" as opposed to
all the GCC created DLLs that I'd been working with all
the while that export JNI native methods as "Java_foo_Bar".
So I had to modify LookupJNIMethod (jni.cc) with a kludge
where it first looks for "Java_foo_Bar" and then (only
for Windows) looks for "_Java_foo_Bar".

Now when I tried to run it I got an UnsatisfiedLinkError
for IsDBCSLeadByte. After some digging around I found
out that the LookupJNIMethod was trying to look for
"[...]IsDBCSLeadByte@9" while it was exported by the
SWT DLL as "[...]IsDBCSLeadByte@12".

The SWT JNI IsDBCSLeadByte method takes a single "byte"
parameter - together with the implicit "JNIEnv *" and
"jclass *", GCJ calculates the parameters to take up
9 bytes and not 12 bytes as the function expects.

Apparently the stdcall convention uses an "@nn" suffix
for function names where "nn" is the *number of bytes
popped off the stack by the function* and not just "number
of bytes in the argument list" as the MSDN documentation
would have us believe:

http://msdn.microsoft.com/library/en-us/vclang/html/_core___stdcall.asp

So I must figure out how to do this properly before
I can proceed any further. :-(

To paraphrase Alice (to reflect Anthony's sentiments):
"It is getting grosser and grosser!" ;-)

BTW, I noticed a couple of things during this exercise:

1. GCJ searches for "JNI_OnLoad" in a loaded DLL - this
    symbol has to change on Windows to use the suffix
    implied by stdcall.

2. It never searches for, nor invokes, "JNI_OnUnload".
    Is that because DLLs are never explicitly unloaded?

Sincerely Yours,
Ranjit.

-- 
Ranjit Mathew          Email: rmathew AT hotmail DOT com

Bangalore, INDIA.      Web: http://ranjitmathew.tripod.com/





More information about the Java mailing list