Wednesday, December 3, 2008

Java Native Interface. Fun

Switching gears for a moment and dumping some vital Java knowledge for later.


Using Eclipse 3.2 and JDK 1.6.10 update 11 and jre6 I have finally managed to call a freaking hello world function in a freaking native dll. This only after three days of flailing around with directories and dll files. The final trick however should have been apparent from day one.


Here's what I'm working with currently. First some Java code that declares a native function:


package org.cainan.jnitest;

public class HelloWorld {

public static native void printTest();

public static void main(String[] args) {
// TODO Auto-generated method stub
HelloWorld.printTest();
}

static {
System.loadLibrary("HelloWorld");
}
}


Second, the C implementation of the declared native function:


#include "org_cainan_jnitest_HelloWorld.h"
#include

JNIEXPORT void JNICALL Java_org_cainan_jnitest_HelloWorld_printTest(JNIEnv* env, jclass ptrThis)
{
printf("Hello bitches!\n");
}


Note the "org_cainan_jnitest_HelloWorld.h" is the header file that was created with this command:

javah -jni org.cainan.jnitest.HelloWorld

This was done that the top level bin folder because javah walked down the folders org, cainan, and jnitest to find HelloWorld.class.


Now, onto the problem.


After getting all this set up and loading the correct library into the Java program, I still got an error saying that the printTest method is not implemented. After MANY attempts at figuring this out I finally loaded up this nifty little app : Anywhere PE Viewer. This little app dumps the export table for a library like the "Dumpbin.exe /EXPORTS" of Visual Studio fame.


This is the only function that was originally exported in my library:

Java_org_cainan_jnitest_HelloWorld_printTest@8

Notice the @8 appended to the end. I believe this is the bytes that are to be passed to this function. I'm not entirely sure, but, I do know that the export name is wrong. It should look like this:

Java_org_cainan_jnitest_HelloWorld_printTest

Minus any other appended crap. Ok. Now that we know that how do we get the name fixed. In Eclipse I have a "Managed" C project that compiles the native code into a shared library (dll) but the export of the function is messed up. In order to fix this I need an additional linker option. This option can be added in the project properties under "C/C++ Build" branch, the "Tool Settings" tab, and under "GCC C Linker"->"Miscellaneous"->"Other options".


The option that worked for me was "--add-stdcall-alias". This option is specefic to the Portable Executable (PE) format i386 linker of the GCC. According to the GNU Linker manual, the command:

If given, symbols with a stdcall suffix (@nn) will be exported as-is and also with the suffix stripped. [This option is specific to the i386 PE targeted port of the linker]

This means that when using the option then the dll will export both version of the function (mangled with the stdcall's suffix and clean). After doing this and getting my exported functions named correctly my little JNI test finally worked.



Fortunately for me, I found this guys post that had the linker switch and some other insights.


He is offering a $50 for an answer to his question. I wish I could help.

Monday, November 24, 2008

Collection binding to a C# DataGridView.

In my current work assignment I have a custom collection that inherits from the .Net System.Collection.Generic.List. I called it MyCustomClassCollection and so far it works just fine.

Now I want to bind this kick-ass custom collection to my form's DataGridView. Here's the solution I've come up with so far.


private void BindDataSource()
{
BindingSource bs = new BindingSource();
bs.DataSource = this.myConnection.CustomCollection;

if (!this.dgvCot.InvokeRequired)
{
this.dgvCot.DataSource = bs;
}
else
{
this.dgvCot.BeginInvoke(new MethodInvoker(delegate() {
this.dgvCot.DataSource = bs; }));
}
}

This works but as you can probably guess this code is being called from another thread, hence all of the BeginInvoke and InvokeRequired stuff in there. Specifically, this is part of an event handler that is fired every time I receive some data that is serialized into mycustomclass and then added to the custom collection.

I would think that I shouldn't have to bind the collection every time something is added to the custom collection. But I can't get the DataGridView to update if the binding code is not in this event.

I've tried inheriting from BindingList<> but its behavior is kind of strange. The DataGridView will only show one of the objects in the collection and never show anymore.

I guess it will come to me.

Wednesday, October 15, 2008

First freaking post...

Consider this a test in the inability to spell or punctuate correctly. I will write some detailed instructions about the stuff that I do. Such as, flashing DD-WRT on my Linksys WRT54GL router. But that will happen later