KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com4j > NativeType


1 package com4j;
2
3 import java.lang.reflect.ParameterizedType JavaDoc;
4 import java.lang.reflect.Type JavaDoc;
5 import java.nio.Buffer JavaDoc;
6 import java.nio.ByteBuffer JavaDoc;
7 import java.util.Calendar JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.GregorianCalendar JavaDoc;
10 import java.util.TimeZone JavaDoc;
11
12 import static com4j.Const.BYREF;
13
14 /**
15  * Native method type.
16  *
17  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
18  */

19 public enum NativeType {
20     /**
21      * <tt>BSTR</tt>.
22      *
23      * TODO: support CharSequence
24      * <p>
25      * Expected Java type:
26      * String
27      */

28     BSTR(1) {
29         public NativeType byRef() {
30             return BSTR_ByRef;
31         }
32     },
33
34     /**
35      * <tt>BSTR*</tt>.
36      *
37      * TODO: support StringBuffer
38      * <p>
39      * Expected Java type:
40      * {@link Holder<String>}
41      */

42     BSTR_ByRef(1|BYREF),
43
44
45     /**
46      * <tt>LPWSTR</tt>.
47      *
48      * More concretely, it becomes a L'\0'-terminated
49      * UTF-16LE format.
50      */

51     Unicode(2),
52     /**
53      * String will be marshalled as "char*".
54      *
55      * <p>
56      * More concretely, it becomes a '\0'-terminated
57      * multi-byte string where characters are encoded
58      * according to the platform default encoding.
59      *
60      * <p>
61      * For example, on a typical English Windows system
62      * this is just an ASCII string (more or less). On
63      * a typical Japanese Windows system, this is
64      * Shift-JIS.
65      */

66     CSTR(3),
67
68     /**
69      * <tt>INT8</tt> (byte).
70      *
71      * <p>
72      * Expected Java type:
73      * byte
74      * {@link Number}
75      */

76     Int8(100) {
77         public NativeType byRef() {
78             return Int8_ByRef;
79         }
80     },
81     Int8_ByRef(100|BYREF),
82     /**
83      * <tt>INT16</tt> (short).
84      *
85      * <p>
86      * Expected Java type:
87      * short
88      * {@link Number}
89      */

90     Int16(101) {
91         public NativeType byRef() {
92             return Int16_ByRef;
93         }
94     },
95     Int16_ByRef(101|BYREF),
96
97     /**
98      * Marshalled as 32-bit integer.
99      *
100      * <p>
101      * Java "int" is 32 bit.
102      *
103      * <p>
104      * Expected Java type:
105      * int
106      * {@link Number}
107      * {@link Enum} (see {@link ComEnum})
108      */

109     Int32(102) {
110         // the native code will see the raw pointer value as Integer
111
Object JavaDoc massage(Object JavaDoc param) {
112             Class JavaDoc<?> clazz = param.getClass();
113
114             if( Enum JavaDoc.class.isAssignableFrom(clazz) ) {
115                 // if it's an enum constant, change it to the number
116
return EnumDictionary.get((Class JavaDoc<? extends Enum JavaDoc>)clazz).value((Enum JavaDoc)param);
117             }
118             return param;
119         }
120
121         Object JavaDoc unmassage(Class JavaDoc<?> type, Type JavaDoc genericSignature, Object JavaDoc param) {
122             if( Enum JavaDoc.class.isAssignableFrom(type) ) {
123                 return EnumDictionary.get((Class JavaDoc<? extends Enum JavaDoc>)type).constant((Integer JavaDoc)param);
124             }
125
126             return param;
127         }
128
129         public NativeType byRef() {
130             return Int32_ByRef;
131         }
132     },
133     Int32_ByRef(102|BYREF),
134
135     /**
136      * The native type is 'BOOL' (defined as 'int')
137      * where <tt>true</tt> maps to -1 and <tt>false</tt> maps to 0.
138      *
139      * <p>
140      * Expected Java type:
141      * boolean
142      * {@link Boolean}
143      */

144     Bool(103),
145
146     /**
147      * The native type is 'VARIANT_BOOL' where TRUE=1 and FALSE=0.
148      * Note that <tt>sizeof(VARIANT_BOOL)==2</tt>.
149      *
150      * <p>
151      * Expected Java type:
152      * boolean
153      * {@link Boolean}
154      */

155     VariantBool(104),
156
157     /**
158      * <tt>float</tt>.
159      *
160      * <p>
161      * Expected Java type:
162      * boolean
163      * {@link Number}
164      */

165     Float(120),
166
167     /**
168      * <tt>double</tt>.
169      *
170      * <p>
171      * Expected Java type:
172      * boolean
173      * {@link Number}
174      */

175     Double(121),
176
177     /**
178      * Used only with {@link ReturnValue} for returning
179      * HRESULT of the method invocation as "int".
180      */

181     HRESULT(200),
182
183     /**
184      * The native type is determined from the Java method return type.
185      * See the documentation for mor details.
186      * TODO: link to the doc.
187      */

188     Default(201),
189
190     /**
191      * COM interface pointer.
192      *
193      * <p>
194      * Expected Java type:
195      * {@link Com4jObject}
196      */

197     ComObject(300) {
198         // the native code will see the raw pointer value as Integer
199
Object JavaDoc massage(Object JavaDoc param) {
200             return COM4J.unwrap((Com4jObject)param).getPtr();
201         }
202
203         Object JavaDoc unmassage(Class JavaDoc<?> type, Type JavaDoc genericSignature, Object JavaDoc param) {
204             if(param==null) return null;
205             if(type==Iterator JavaDoc.class) {
206                 Class JavaDoc itemType = Object JavaDoc.class;
207                 if(genericSignature instanceof ParameterizedType JavaDoc) {
208                     ParameterizedType JavaDoc pt = (ParameterizedType JavaDoc) genericSignature;
209                     Type JavaDoc it = pt.getActualTypeArguments()[0];
210                     if(it instanceof Class JavaDoc)
211                         itemType = (Class JavaDoc)it;
212                 }
213                 return new ComCollection(itemType,Wrapper.create(IEnumVARIANT.class, (Integer JavaDoc)param ));
214             }
215             return Wrapper.create( (Class JavaDoc<? extends Com4jObject>)type, (Integer JavaDoc)param );
216         }
217
218         public NativeType byRef() {
219             return ComObject_ByRef;
220         }
221     },
222
223     /**
224      * COM interface pointer by reference.
225      *
226      * <p>
227      * Expected Java type:
228      * {@link Holder<ComObject>}
229      */

230     ComObject_ByRef(300|BYREF) {
231         // the native code will see the raw pointer value as Integer
232
Object JavaDoc massage(Object JavaDoc param) {
233             Holder h = (Holder)param;
234             h.value = ComObject.massage(h.value);
235             return h;
236         }
237         Object JavaDoc unmassage(Class JavaDoc<?> type, Type JavaDoc genericSignature, Object JavaDoc param) {
238             Holder h = (Holder)param;
239             h.value = ComObject.massage(h.value);
240             return h;
241         }
242     },
243
244     /**
245      * GUID.
246      *
247      * <p>
248      * Passed by reference in COM convention but it doesn't have
249      * the "out" semantics.
250      *
251      * <p>
252      * Expected Java type:
253      * {@link GUID}
254      */

255     GUID(301) {
256         // pass in the value as two longs
257
Object JavaDoc massage(Object JavaDoc param) {
258             GUID g = (GUID)param;
259             return g.v;
260         }
261         Object JavaDoc unmassage(Class JavaDoc<?> signature, Type JavaDoc genericSignature, Object JavaDoc param) {
262             if(param==null) return null;
263             return new GUID( (long[])param );
264         }
265     },
266
267     /**
268      * <tt>VARIANT*</tt>.
269      *
270      * <p>
271      * Expected Java type:
272      * {@link Variant}
273      * {@link Object}
274      *
275      * <p>
276      * When the Java type is {@link Object}, the type of the created
277      * <tt>VARIANT</tt> is determined at run-time from the actual type
278      * of the Java object being passed in. The following table describes
279      * this inferene process:
280      *
281      * <table border=1>
282      * <tr>
283      * <td>Java type
284      * <td>COM VARIANT type
285      * <tr>
286      * <td>{@link Boolean} / boolean
287      * <td>VT_BOOL
288      * <tr>
289      * <td>{@link String}
290      * <td>VT_BSTR
291      * <tr>
292      * <td>{@link Float} / float
293      * <td>VT_R4
294      * <tr>
295      * <td>{@link Double} / double
296      * <td>VT_R8
297      * <tr>
298      * <td>{@link Short} / short
299      * <td>VT_I2
300      * <tr>
301      * <td>{@link Integer} / int
302      * <td>VT_I4
303      * <tr>
304      * <td>{@link Long} / long
305      * <td>VT_I8
306      * <tr>
307      * <td>{@link Com4jObject} or its derived types
308      * <td>VT_UNKNOWN
309      * </table>
310      * TODO: expand the list
311      */

312     VARIANT_ByRef(302|BYREF),
313
314     /**
315      * <tt>IDispatch*</tt>
316      *
317      * <p>
318      * Expected Java type:
319      * {@link Com4jObject}
320      */

321     Dispatch(303) {
322         // the native code will see the raw pointer value as Integer
323
Object JavaDoc massage(Object JavaDoc param) {
324             int ptr = COM4J.unwrap((Com4jObject)param).getPtr();
325             int disp = COM4J.queryInterface( ptr, COM4J.IID_IDispatch );
326             return disp;
327         }
328
329         Object JavaDoc unmassage(Class JavaDoc<?> type, Type JavaDoc genericSignature, Object JavaDoc param) {
330             if(param==null) return null;
331             int disp = (Integer JavaDoc)param;
332             if(disp==0) return null;
333             Native.release( disp );
334             return Wrapper.create( (Class JavaDoc<? extends Com4jObject>)type, (Integer JavaDoc)param );
335         }
336     },
337
338     /**
339      * <tt>PVOID</tt>.
340      *
341      * <p>
342      * The assumed semantics is that a region of buffer
343      * will be passed to the native method.
344      *
345      * <p>
346      * Expected Java type:
347      * direct {@link Buffer}s ({@link Buffer}s created from methods like
348      * {@link ByteBuffer#allocateDirect(int)}
349      */

350     PVOID(304) {
351         public NativeType byRef() {
352             return PVOID_ByRef;
353         }
354     },
355
356
357     /**
358      * <tt>void**</tt>.
359      *
360      * <p>
361      * The assumed semantics is that you receive a buffer.
362      *
363      * <p>
364      * Expected Java type:
365      * {@link Holder}&lt;{@link Buffer}> ({@link Buffer}s created from methods like
366      * {@link ByteBuffer#allocateDirect(int)}
367      */

368     PVOID_ByRef(304|BYREF),
369
370     /**
371      * <tt>DATE</tt>.
372      *
373      * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_The_DATE_Type.asp
374      * <p>
375      * Expected Java type:
376      * {@link java.util.Date}
377      * {@link Calendar}
378      */

379     Date(400) {
380         // the native code will see the raw pointer value as Integer
381
Object JavaDoc massage(Object JavaDoc param) {
382             java.util.Date JavaDoc dt;
383             if( param instanceof Calendar JavaDoc ) {
384                 dt = ((Calendar JavaDoc)param).getTime();
385             } else {
386                 dt = (java.util.Date JavaDoc)param;
387             }
388
389             // the number of milliseconds since January 1, 1970, 00:00:00 GMT
390
long t = dt.getTime();
391             // the number of milliseconds since January 1, 1970, 00:00:00 Local Time
392
t -= dt.getTimezoneOffset()*60*1000;
393
394             // the number of milliseconds since December 30, 1899, 00:00:00 Local Time
395
t += 2209161600000L;
396
397             // DATE is an offset from "30 December 1899"
398
if(t<0) {
399                 // -0.3 -> -0.7
400
long offset = -(t%MSPD); // TODO: check
401
t = t-MSPD+offset;
402             }
403             double d = ((double)t)/MSPD;
404             return d;
405         }
406
407         Object JavaDoc unmassage(Class JavaDoc<?> signature, Type JavaDoc genericSignature, Object JavaDoc param) {
408             double d = (Double JavaDoc)param;
409             long t = (long)(d*MSPD);
410             t -= 2209161600000L;
411             t -= defaultTimeZone.getOffset(t); // convert back to UTC
412
java.util.Date JavaDoc dt = new java.util.Date JavaDoc(t);
413             if(Calendar JavaDoc.class.isAssignableFrom(signature)) {
414                 GregorianCalendar JavaDoc cal = new GregorianCalendar JavaDoc();
415                 cal.setTime(dt);
416                 return cal;
417             } else {
418                 return dt;
419             }
420         }
421     },
422
423
424     /**
425      * <tt>SAFEARRAY</tt>.
426      *
427      * <p>
428      * The given java type is converted into a SAFEARRAY before
429      * passed to the native method.
430      *
431      * When the Java type is an array, the component type of the SAFEARRAY
432      * is automatically derived from the component type of the Java array.
433      * This inference is defined as follows:
434      * <ul>
435      * <li>boolean[] -> SAFEARRAY(VT_BOOL)
436      * <li>byte[] -> SAFEARRAY(VT_UI1)
437      * <li>char[] -> SAFEARRAY(VT_UI2) (??? is this right?)
438      * <li>short[] -> SAFEARRAY(VT_I2)
439      * <li>int[] -> SAFEARRAY(VT_I4)
440      * <li>long[] -> SAFEARRAY(VT_I8)
441      * <li>float[] -> SAFEARRAY(VT_R4)
442      * <li>double[] -> SAFEARRAY(VT_R8)
443      *
444      * <li>Object[] -> SAFEARRAY(VT_VARIANT)
445      * <li>String[] -> SAFEARRAY(VT_BSTR)
446      * </ul>
447      */

448     SafeArray(500),
449
450     ;
451
452
453
454
455
456     /**
457      * Unique identifier of this constant.
458      * Passed to the native code.
459      */

460     final int code;
461
462     NativeType( int code ) {
463         this.code = code;
464     }
465
466     /**
467      * Changes the parameter type before the parameter is passed to the native code.
468      * <p>
469      * This allows {@link NativeType}s to take more Java-friendly argument and
470      * convert it to more native code friendly form behind the scene.
471      *
472      * @param param
473      * can be null.
474      */

475     Object JavaDoc massage(Object JavaDoc param) {
476         return param;
477     }
478     /**
479      * Changes the parameter type before the method call returns.
480      * <p>
481      * The opposite of {@link #massage(java.lang.Object)}. Only useful for
482      * BYREFs.
483      *
484      * @param signature
485      * the parameter type in its raw form.
486      * @param genericSignature
487      * the parameter type in its generified form.
488      * @param param
489      */

490     Object JavaDoc unmassage(Class JavaDoc<?> signature, Type JavaDoc genericSignature, Object JavaDoc param) {
491         return param;
492     }
493
494     /**
495      * If the constant has the BYREF version, return it.
496      * Otherwise null.
497      */

498     public NativeType byRef() {
499         return null;
500     }
501
502
503     private static final long MSPD = 24*60*60*1000;
504     private static final TimeZone JavaDoc defaultTimeZone = TimeZone.getDefault();
505
506 }
507
Popular Tags