jNative Howto

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 :

  • JNative.jar : this is the java side suitable for all platforms with Java5,
  • JNative.dll : this is the Win32 native side for W2K/XP/2003,
  • libjnative.so : this is the Linux native side.

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

  For Windows users :JNative.dll must be in the path, so put it in thecurrent directory or in C:\Windows orC:\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 ithere this sample will demonstrate the use of the Color dialog (you can get the white paperhere)

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

Structure handling

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

  • Dirty : you need one call and do not use all the members of the struct,
  • Clean : you create a library, your code must be reusable, you have 5 minutes to do it,I’ll elaborate theclean way as it is the recommanded one.

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).

TypeLength [4]JNative class
DWORD4org.xvolks.jnative.misc.basicStructures.LONG
HWND4org.xvolks.jnative.misc.basicStructures.HWND
COLORREF [MSDN1]4org.xvolks.jnative.misc.basicStructures.LONG
COLORREF* [MSDN1]4org.xvolks.jnative.pointers.Pointer
LPARAM4org.xvolks.jnative.misc.basicStructures.LPARAM
LPCCHOOKPROC [MSDN2]4org.xvolks.jnative.util.Callback
LPCTSTR4org.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 aChooseColor 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值