JNative can only live with your donations and advertisement


JNative Howto

Saturday 3 June 2006.
 
This article describe how to use JNative

Requirements

-  First you need to have [1]:

-  Unzip the jnative archive you’ve just downloaded and you obtain at least 2 or 3 files :

You have to add JNative.jar in your classpath, see in Eclipse the menu Project|Properties|Java Build Path|Libraries, click on Add External JARs... and choose JNative.jar.

-  For Windows users : JNative.dll must be in the path, so put it in the current directory or in C:\Windows or C:\Windows\System32 (assuming that your Windows is installed in C:\Windows, can also be in C:\WINNT)

-  For linux users : libjnative.so can be in your /usr/lib directory, in the i386 directory of your jre/lib, or you can add to the shell launching your application :


export LD_LIBRARY_PATH=/path/to/your/directory

You need to have the documentation of the library so you know what are the parameters and return value of a function.

I, now describe an example, you’ll need the documentation, get it here this sample will demonstrate the use of the Color dialog (you can get the white paper here)

We will implement the ChooseColor function we will also need the documentation of the CHOOSECOLOR structure

Structure handling

-  First we need to implement the structure. Basically you have 2 ways to do this :

Let’s consider this structure :

typedef struct {
   DWORD lStructSize;
   HWND hwndOwner;
   HWND hInstance;
   COLORREF rgbResult;
   COLORREF *lpCustColors;
   DWORD Flags;
   LPARAM lCustData;
   LPCCHOOKPROC lpfnHook;
   LPCTSTR lpTemplateName;
} CHOOSECOLOR, *LPCHOOSECOLOR;

We need to know the size of each elements, some of them are already known by JNative [3], for the others you’ll have to find them by yourself (remember that a pointer has a size of 4 bytes).

Type Length [4] JNative class
DWORD 4 org.xvolks.jnative.misc.basicStructures.LONG
HWND 4 org.xvolks.jnative.misc.basicStructures.HWND
COLORREF [MSDN1] 4 org.xvolks.jnative.misc.basicStructures.LONG
COLORREF* [MSDN1] 4 org.xvolks.jnative.pointers.Pointer
LPARAM 4 org.xvolks.jnative.misc.basicStructures.LPARAM
LPCCHOOKPROC [MSDN2] 4 org.xvolks.jnative.util.Callback
LPCTSTR 4 org.xvolks.jnative.pointers.Pointer

So, now we know the size of CHOOSECOLOR structure :
-  2 * DWORD + 2 * HWND + 2 * COLORDEF + LPARAM + LPCCHOOKPROC + LPCTSTR = 2*4 + 2*4 + 2*4 + 4 + 4 + 4 = 36 bytes.

we have to implement org.xvolks.jnative.pointers.AbstractBasicData so our new class will be easy to use.

AbstractBasicData is a Generic class that return an instance of your data, we are now creating a ChooseColor structure, with your IDE create a new class extending AbstractBasicData called ChooseColor:


package org.xvolks.jnative.misc;

import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.misc.basicStructures.AbstractBasicData;
import org.xvolks.jnative.pointers.Pointer;

public class ChooseColor extends AbstractBasicData<ChooseColor> {

        protected ChooseColor(ChooseColor lValue) {
                super(null);
                mValue = this;
        }

        public ChooseColor getValueFromPointer() throws NativeException {
                // TODO Auto-generated method stub
                return null;
        }

        public int getSizeOf() {
                // TODO Auto-generated method stub
                return 0;
        }

        public Pointer createPointer() throws NativeException {
                // TODO Auto-generated method stub
                return null;
        }
}

Modify this file to suit your needs:
-  Add the data members:


import org.xvolks.jnative.misc.basicStructures.*;
   
   ....

   LONG lStructSize;
   HWND hwndOwner;
   HWND hInstance;
   //This one is public because it's the return value; I should have created a getter
   public LONG rgbResult;
   static Pointer lpCustColors;
   LONG Flags;
   LPARAM lCustData;
   int lpfnHook;
   Callback fnHook;
   String lpTemplateName;

   static {
           try {
                        lpCustColors = new Pointer(MemoryBlockFactory.createMemoryBlock(16));
                } catch (NativeException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                }           
   }


-  The getSizoOf() method :


        /**
         * This method returns 36 always (it's the size of CHOOSECOLOR struct)
         * @returns 36
         */
        @Override
        public int getSizeOf() {
                return 36;
        }

-  The createPointer() method :


        public Pointer createPointer() throws NativeException {
                pointer = new Pointer(new GlobalMemoryBlock(getSizeOf()));
                pointer.setIntAt(0, getSizeOf());
                pointer.setIntAt(16, lpCustColors.getPointer());
                return pointer;
        }

-  The getValueFromPointer() method :


        public ChooseColor getValueFromPointer() throws NativeException {
                offset = 0;
                lStructSize = new LONG(getNextInt());
                hwndOwner = new HWND(getNextInt());
                hInstance = new HWND(getNextInt());
                rgbResult = new LONG(getNextInt());
                //Skip lpCustColor
                offset += 4;
                Flags = new LONG(getNextInt());
                lCustData = new LPARAM(getNextInt());
                //Skip callback
                return getValue();
        }

-  Create helper methods to manipulate callbacks :


        public void removeCallback() throws NativeException {
                if(fnHook != null) {
                        JNative.releaseCallback(fnHook);
                        fnHook = null;
                }
        }
        public void addCallback(Callback lCallback) throws NativeException {
                removeCallback();
                fnHook = lCallback;
                //The callback object must handle 4 parameters from
                //CCHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
                lpfnHook = JNative.createCallback(4, lCallback);
                pointer.setIntAt(28, lpfnHook);
        }

-  Create setters to manipulate data, they will fill the structure :


        ...

        public void setOwner(HWND owner) throws NativeException {
                hwndOwner = owner;
                pointer.setIntAt(4, hwndOwner.getValue());
        }

        public void setInstance(HWND instance) throws NativeException {
                hInstance = instance;
                pointer.setIntAt(8, hInstance.getValue());
        }

        ...

Function call

As we start to implement comdlg32.dll we have to create a class named ComDlg32 to handle its functions.

So create ComDlg32 class in org.xvolks.jnative.util package.


package org.xvolks.jnative.util;

import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.misc.ChooseColor;
import org.xvolks.jnative.misc.basicStructures.HWND;
import org.xvolks.jnative.misc.basicStructures.LONG;
import org.xvolks.jnative.misc.basicStructures.LPARAM;

public class ComDlg32 {
        public static final String DLL_NAME = "COMDLG32.DLL";

        //Cache the JNative object between calls.
        private static JNative nChooseColor;
       
        /**
         *
         * @param lOwner
         * @param hInstance
         * @param Flags
         * @param lCustData
         * @param lCallback
         * @param lTemplateName
         * @return -1 if the use does not click on OK button, the RGB value else.
         * @throws NativeException
         * @throws IllegalAccessException
         */
        public static int ChooseColor(HWND lOwner, HWND hInstance, LONG Flags, LPARAM lCustData, Callback lCallback, String lTemplateName) throws NativeException, IllegalAccessException {
                if(nChooseColor == null) {
                        //JNative uses ANSI version ChooseColorA vs ChooseColorW
                        nChooseColor = new JNative(DLL_NAME, "ChooseColorA");
                        //BOOL is in fact an INT
                        nChooseColor.setRetVal(Type.INT);
                }
                ChooseColor nChooseColorStruct = new ChooseColor();
                nChooseColorStruct.setOwner(lOwner);
                nChooseColorStruct.setInstance(hInstance);
                nChooseColorStruct.setFlags(Flags);
                nChooseColorStruct.setCustData(lCustData);
                nChooseColorStruct.addCallback(lCallback);
                nChooseColorStruct.setTemplateName(lTemplateName);
               
                nChooseColor.setParameter(0, nChooseColorStruct.getPointer());
                nChooseColor.invoke();
                if("0".equals(nChooseColor.getRetVal())) {
                        return -1;
                } else {
                        return nChooseColorStruct.getValueFromPointer().rgbResult.getValue();
                }
        }
}

Conclusion

The callback implementation is missing you’ll have to create it yourself, see the EnumWindows sample in the sources.

-  The full source of ChooseColor class


package org.xvolks.jnative.misc;

import org.xvolks.jnative.JNative;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.misc.basicStructures.AbstractBasicData;
import org.xvolks.jnative.misc.basicStructures.HWND;
import org.xvolks.jnative.misc.basicStructures.LONG;
import org.xvolks.jnative.misc.basicStructures.LPARAM;
import org.xvolks.jnative.pointers.NullPointer;
import org.xvolks.jnative.pointers.Pointer;
import org.xvolks.jnative.pointers.memory.GlobalMemoryBlock;
import org.xvolks.jnative.pointers.memory.MemoryBlockFactory;
import org.xvolks.jnative.util.Callback;

public class ChooseColor extends AbstractBasicData<ChooseColor> {
   LONG lStructSize;
   HWND hwndOwner;
   HWND hInstance;
   public LONG rgbResult;
   static Pointer lpCustColors;
   LONG Flags;
   LPARAM lCustData;
   int lpfnHook;
   Callback fnHook;
   Pointer lpTemplateName;
   
   static {
           try {
                        lpCustColors = new Pointer(MemoryBlockFactory.createMemoryBlock(16));
                } catch (NativeException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                }           
   }

        public ChooseColor() throws NativeException {
                super(null);
                mValue = this;
                createPointer();
        }

        public void removeCallback() throws NativeException {
                if(fnHook != null) {
                        JNative.releaseCallback(fnHook);
                        fnHook = null;
                }
        }
        public void addCallback(Callback lCallback) throws NativeException {
                removeCallback();
                fnHook = lCallback;
                //The callback object must handle 4 parameters from
                //CCHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
                lpfnHook = JNative.createCallback(4, lCallback);
                pointer.setIntAt(28, lpfnHook);
        }
       
        public ChooseColor getValueFromPointer() throws NativeException {
                offset = 0;
                lStructSize = new LONG(getNextInt());         // 0
                hwndOwner = new HWND(getNextInt());           // 4
                hInstance = new HWND(getNextInt());                // 8
                rgbResult = new LONG(getNextInt());         //12
                //Skip lpCustColor
                offset += 4;                                                         //16
                Flags = new LONG(getNextInt());                        //20
                lCustData = new LPARAM(getNextInt());        //24
                //Skip callback                                                 //28
                //Skip TemplateName                                         //32
                                                                                                //36 = size
                return getValue();
        }

        public int getSizeOf() {
                return 36;
        }

        public Pointer createPointer() throws NativeException {
                pointer = new Pointer(new GlobalMemoryBlock(getSizeOf()));
                pointer.setIntAt(0, getSizeOf());
                pointer.setIntAt(16, lpCustColors.getPointer());
                return pointer;
        }

        public void setOwner(HWND owner) throws NativeException {
                hwndOwner = owner;
                pointer.setIntAt(4, hwndOwner.getValue());
        }

        public void setInstance(HWND instance) throws NativeException {
                hInstance = instance;
                pointer.setIntAt(8, hInstance.getValue());
        }

        public void setFlags(LONG flags) throws NativeException {
                Flags = flags;
                pointer.setIntAt(20, Flags.getValue());
        }

        public void setCustData(LPARAM custData) throws NativeException {
                lCustData = custData;
                pointer.setIntAt(24, lCustData.getValue());
        }

        public void setTemplateName(String templateName) throws NativeException {
                if(templateName == null) {
                        lpTemplateName = new NullPointer();
                } else {
                        lpTemplateName = new Pointer(MemoryBlockFactory.createMemoryBlock(templateName.length() + 1));
                        lpTemplateName.setMemory(templateName);
                }
                pointer.setIntAt(32, lpTemplateName.getPointer());
        }
       
       
}

This tutorial was not tested and therefore is not guaranted to work, post comments if you think you need more help.

— Marc

[1] recommanded

[2] free

[3] method getSizeOf()

[4] on 32 bits computers and OS

[MSDN1] see COLORREF help

[MSDN1] see COLORREF help

[MSDN2] see CCHookProc help

Reply to this article