JNative can only live with your donations and advertisement


Dealing with out structures

星期五 2007年1月26日.
 

This is a simple DLL call that puts its output in a structure :

I take the example of Kernel32’s GetSystemTime() for example as asked by Rods

This is the comment of the out structure you can find it on the msdn


        /**
         * SystemTime
         *
         * <pre>
         *         typedef struct _SYSTEMTIME {
         *                   WORD wYear;
         *                   WORD wMonth;
         *                   WORD wDayOfWeek;
         *                   WORD wDay;
         *                   WORD wHour;
         *                   WORD wMinute;
         *                   WORD wSecond;
         *                   WORD wMilliseconds;
         *                 } SYSTEMTIME,
         * </pre>
         */

Then we need to translate that in a Java class. It will be based on a help class that was designed for that usage : AbstractBasicData this class is a generic one since its method getValue() will return an object of the parametrized type. So this its declaration :


        public static class SystemTime extends AbstractBasicData<SystemTime> {

Note the static keyword since GetSystemTime() will be a static method of Kernel32 and SystemTime an inner class of Kernel32.

The C WORD type is two byte storage area : its counterpart in Java is short type so :


                public short wYear;
                public short wMonth;
                public short wDayOfWeek;
                public short wDay;
                public short wHour;
                public short wMinute;
                public short wSecond;
                public short wMilliseconds;
Note the public access : this is not very good design since those members may only be read by Java classes. They should be private with only a getter method. This article is not a Java course so we don’t mind.

We need to implement abstract methods of AbstractBasicData :

-  public int getSizeOf()

This method must return the size of the structure. Here is 16 since a WORD is 2 bytes and there is 8 WORDS.


                public int getSizeOf() {
                        return 8*2; //8 WORDS of 2 bytes
                }

-  public Pointer createPointer()

This method creates a new native storage area, it’s generally called once in the constructor.


                public Pointer createPointer() throws NativeException {
                        pointer = new Pointer(MemoryBlockFactory.createMemoryBlock(getSizeOf()));
                        return pointer;
                }
The pointer member is inherited from AbstractBasicData.

-  public SystemTime getValueFromPointer()

This method copies the native values in the Java variables. Do not misuse this method and getValue() getValue() returns the Java object without coping the native values !!! If you don’t mind loosing some milliseconds, override getValue() and return getValueFromPointer() in it.


                public SystemTime getValueFromPointer() throws NativeException {
                        wYear          = getNextShort();
                        wMonth         = getNextShort();
                        wDayOfWeek     = getNextShort();
                        wDay           = getNextShort();
                        wHour          = getNextShort();
                        wMinute        = getNextShort();
                        wSecond        = getNextShort();
                        wMilliseconds  = getNextShort();
                        return this;
                }

-  The constructor

The AbstractBasicData constructor takes one parameter which is the default value, in this case we only need to create the native memory block.


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

Note the mValue = this; line, so when calling getValue() it will return this.

-  The function call in the Kernel32 DLL :


        public static SystemTime GetSystemTime() throws Exception {
                //Create a JNative object called nGetSystemTime : here
                JNative nGetSystemTime = new JNative("Kernel32.dll", "GetSystemTime");
                //Create a SystemTime object that holds the native out structure
                SystemTime systemTime = new SystemTime();
                //Pass its pointer address as the first parameter (first is zero !!!)
                nGetSystemTime.setParameter(0, systemTime.getPointer());
                //Invoke the native GetSystemTime function
                nGetSystemTime.invoke();
                //Return the populated SystemTime object
                return systemTime.getValueFromPointer();
        }

And now the complete code :



        /**
         * SystemTime
         *
         * <pre>
         *         typedef struct _SYSTEMTIME {
         *                   WORD wYear;
         *                   WORD wMonth;
         *                   WORD wDayOfWeek;
         *                   WORD wDay;
         *                   WORD wHour;
         *                   WORD wMinute;
         *                   WORD wSecond;
         *                   WORD wMilliseconds;
         *                 } SYSTEMTIME,
         * </pre>
         */
        public static class SystemTime extends AbstractBasicData<SystemTime> {
                public short wYear;
                public short wMonth;
                public short wDayOfWeek;
                public short wDay;
                public short wHour;
                public short wMinute;
                public short wSecond;
                public short wMilliseconds;
               
                public Pointer createPointer() throws NativeException {
                        pointer = new Pointer(MemoryBlockFactory.createMemoryBlock(getSizeOf()));
                        return pointer;
                }
                public int getSizeOf() {
                        return 8*2; //8 WORDS of 2 bytes
                }
                public SystemTime getValueFromPointer() throws NativeException {
                        wYear          = getNextShort();
                        wMonth         = getNextShort();
                        wDayOfWeek     = getNextShort();
                        wDay           = getNextShort();
                        wHour          = getNextShort();
                        wMinute        = getNextShort();
                        wSecond        = getNextShort();
                        wMilliseconds  = getNextShort();
                        return this;
                }

                public SystemTime() throws NativeException {
                        super(null);
                        createPointer();
                        mValue = this;
                }
               
                @Override
                public String toString() {
                        return wYear + "/" + wMonth+"/"+wDay+" at + "+wHour+":"+wMinute+":"+wSecond+":"+wMlliseconds;
                }
        }

        public static SystemTime GetSystemTime() throws NativeException, IllegalAccessException {
                JNative nGetSystemTime = new JNative(DLL_NAME, "GetSystemTime");
                SystemTime systemTime = new SystemTime();
                nGetSystemTime.setParameter(0, systemTime.getPointer());
                nGetSystemTime.invoke();
                return systemTime.getValueFromPointer();
        }

        public static void main(String[] args) throws NativeException, IllegalAccessException {
                System.err.println(GetSystemTime());
        }

And the output : 2007/1/26 at 21:45:19:718

I hope this little tutorial can help some of you lazy guys ;)

— Marc

回复文章