Skip to content

Commit 1cdd3e9

Browse files
Make conversion to/from java in c.s.j.p.win32.COM.util more flexible
ProxyObject and Callback both use the Convert class as helper to convert java object to/from VARIANT. This change adds more flexibility and adds tests to fixate and check conversion.
1 parent 7843544 commit 1cdd3e9

File tree

7 files changed

+701
-94
lines changed

7 files changed

+701
-94
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Features
4646
* [#618](https://github.com/java-native-access/jna/pull/618): Implement SAFEARRAY access and bugfix VARIANT - [@matthiasblaesing](https://github.com/matthiasblaesing).
4747
* [#616](https://github.com/java-native-access/jna/pull/616): Allow access to base interfaces (most important IDispatch) via ProxyObject and improve binding by allowing to use dispId for the call - [@matthiasblaesing](https://github.com/matthiasblaesing).
4848
* [#621](https://github.com/java-native-access/jna/pull/621): Added TYPEFLAGS-constants for `wTypeFlags` in `com.sun.jna.platform.win32.OaIdl.TYPEATTR` - [@SevenOf9Sleeper](https://github.com/SevenOf9Sleeper).
49+
* [#625](https://github.com/java-native-access/jna/pull/625): Make conversion to/from java to/from VARIANT in `com.sun.jna.platform.win32.COM.util.Convert` more flexible and dependable by introducing more conversions and unittests - [@matthiasblaesing](https://github.com/matthiasblaesing).
4950

5051
Bug Fixes
5152
---------

contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java

+2-18
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,8 @@ void invokeOnThread(final DISPID dispIdMember, final REFIID riid, LCID lcid, WOR
133133
for ( int i = 0; i < vargs.variantArg.length; i++) {
134134
Class targetClass = params[vargs.variantArg.length - 1 - i];
135135
Variant.VARIANT varg = vargs.variantArg[i];
136-
Object jarg = Convert.toJavaObject(varg, targetClass);
137-
if (jarg instanceof IDispatch) {
138-
// If a dispatch is returned try to wrap it into a proxy
139-
// helper if the target is ComInterface annotated
140-
IDispatch dispatch = (IDispatch) jarg;
141-
//get raw IUnknown interface
142-
PointerByReference ppvObject = new PointerByReference();
143-
IID iid = com.sun.jna.platform.win32.COM.IUnknown.IID_IUNKNOWN;
144-
dispatch.QueryInterface(new REFIID(iid), ppvObject);
145-
IUnknown unk = CallbackProxy.this.factory.createProxy(IUnknown.class, dispatch);
146-
if(targetClass.getAnnotation(ComInterface.class) != null) {
147-
rjargs.add(unk.queryInterface(targetClass));
148-
} else {
149-
rjargs.add(unk);
150-
}
151-
} else {
152-
rjargs.add(jarg);
153-
}
136+
Object jarg = Convert.toJavaObject(varg, targetClass, factory, true);
137+
rjargs.add(jarg);
154138
}
155139
}
156140

contrib/platform/src/com/sun/jna/platform/win32/COM/util/Convert.java

+220-36
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
package com.sun.jna.platform.win32.COM.util;
1414

15+
import com.sun.jna.platform.win32.OaIdl.DATE;
1516
import com.sun.jna.platform.win32.OaIdl.VARIANT_BOOL;
1617
import com.sun.jna.platform.win32.OleAuto;
1718
import com.sun.jna.platform.win32.Variant;
@@ -21,10 +22,43 @@
2122
import java.lang.reflect.Proxy;
2223
import java.util.Date;
2324

24-
import com.sun.jna.platform.win32.WTypes;
2525
import com.sun.jna.platform.win32.WinDef;
2626
import com.sun.jna.platform.win32.Variant.VARIANT;
2727
import com.sun.jna.platform.win32.WTypes.BSTR;
28+
import com.sun.jna.platform.win32.WinDef.BOOL;
29+
import com.sun.jna.platform.win32.WinDef.BYTE;
30+
import com.sun.jna.platform.win32.WinDef.CHAR;
31+
import com.sun.jna.platform.win32.WinDef.LONG;
32+
import com.sun.jna.platform.win32.WinDef.SHORT;
33+
import com.sun.jna.platform.win32.OaIdl;
34+
import static com.sun.jna.platform.win32.Variant.VT_ARRAY;
35+
import static com.sun.jna.platform.win32.Variant.VT_BOOL;
36+
import static com.sun.jna.platform.win32.Variant.VT_BSTR;
37+
import static com.sun.jna.platform.win32.Variant.VT_BYREF;
38+
import static com.sun.jna.platform.win32.Variant.VT_CY;
39+
import static com.sun.jna.platform.win32.Variant.VT_DATE;
40+
import static com.sun.jna.platform.win32.Variant.VT_DECIMAL;
41+
import static com.sun.jna.platform.win32.Variant.VT_DISPATCH;
42+
import static com.sun.jna.platform.win32.Variant.VT_EMPTY;
43+
import static com.sun.jna.platform.win32.Variant.VT_ERROR;
44+
import static com.sun.jna.platform.win32.Variant.VT_I1;
45+
import static com.sun.jna.platform.win32.Variant.VT_I2;
46+
import static com.sun.jna.platform.win32.Variant.VT_I4;
47+
import static com.sun.jna.platform.win32.Variant.VT_I8;
48+
import static com.sun.jna.platform.win32.Variant.VT_INT;
49+
import static com.sun.jna.platform.win32.Variant.VT_NULL;
50+
import static com.sun.jna.platform.win32.Variant.VT_R4;
51+
import static com.sun.jna.platform.win32.Variant.VT_R8;
52+
import static com.sun.jna.platform.win32.Variant.VT_RECORD;
53+
import static com.sun.jna.platform.win32.Variant.VT_SAFEARRAY;
54+
import static com.sun.jna.platform.win32.Variant.VT_UI1;
55+
import static com.sun.jna.platform.win32.Variant.VT_UI2;
56+
import static com.sun.jna.platform.win32.Variant.VT_UI4;
57+
import static com.sun.jna.platform.win32.Variant.VT_UI8;
58+
import static com.sun.jna.platform.win32.Variant.VT_UINT;
59+
import static com.sun.jna.platform.win32.Variant.VT_UNKNOWN;
60+
import static com.sun.jna.platform.win32.Variant.VT_VARIANT;
61+
import com.sun.jna.platform.win32.WinDef.PVOID;
2862

2963
/**
3064
* This class is considered internal to the package.
@@ -50,20 +84,42 @@ class Convert {
5084
public static VARIANT toVariant(Object value) {
5185
if (value instanceof VARIANT) {
5286
return (VARIANT) value;
53-
} else if (value instanceof Boolean) {
54-
return new VARIANT((Boolean) value);
55-
} else if (value instanceof Long) {
56-
return new VARIANT(new WinDef.LONG((Long) value));
87+
} else if (value instanceof BSTR) {
88+
return new VARIANT((BSTR) value);
89+
} else if (value instanceof VARIANT_BOOL) {
90+
return new VARIANT((VARIANT_BOOL) value);
91+
} else if (value instanceof BOOL) {
92+
return new VARIANT((BOOL) value);
93+
} else if (value instanceof LONG) {
94+
return new VARIANT((LONG) value);
95+
} else if (value instanceof SHORT) {
96+
return new VARIANT((SHORT) value);
97+
} else if (value instanceof DATE) {
98+
return new VARIANT((DATE) value);
99+
} else if (value instanceof BYTE) {
100+
return new VARIANT((BYTE) value);
101+
} else if (value instanceof Byte) {
102+
return new VARIANT((Byte) value);
103+
} else if (value instanceof Character) {
104+
return new VARIANT((Character) value);
105+
} else if (value instanceof CHAR) {
106+
return new VARIANT((CHAR) value);
107+
} else if (value instanceof Short) {
108+
return new VARIANT((Short) value);
57109
} else if (value instanceof Integer) {
58110
return new VARIANT((Integer) value);
59-
} else if (value instanceof Short) {
60-
return new VARIANT(new WinDef.SHORT((Short) value));
111+
} else if (value instanceof Long) {
112+
return new VARIANT((Long) value);
61113
} else if (value instanceof Float) {
62114
return new VARIANT((Float) value);
63115
} else if (value instanceof Double) {
64116
return new VARIANT((Double) value);
65117
} else if (value instanceof String) {
66118
return new VARIANT((String) value);
119+
} else if (value instanceof Boolean) {
120+
return new VARIANT((Boolean) value);
121+
} else if (value instanceof com.sun.jna.platform.win32.COM.IDispatch) {
122+
return new VARIANT((com.sun.jna.platform.win32.COM.IDispatch) value);
67123
} else if (value instanceof Date) {
68124
return new VARIANT((Date) value);
69125
} else if (value instanceof Proxy) {
@@ -78,43 +134,171 @@ public static VARIANT toVariant(Object value) {
78134
}
79135
}
80136

81-
public static Object toJavaObject(VARIANT value, Class targetClass) {
82-
if (null==value) {
137+
public static Object toJavaObject(VARIANT value, Class targetClass, Factory factory, boolean addReference) {
138+
if (null==value
139+
|| value.getVarType().intValue() == VT_EMPTY
140+
|| value.getVarType().intValue() == VT_NULL) {
83141
return null;
84142
}
85143

144+
if (targetClass != null
145+
&& (!targetClass.isAssignableFrom(Object.class))) {
146+
if (targetClass != null && targetClass.isAssignableFrom(value.getClass())) {
147+
return value;
148+
}
149+
150+
Object vobj = value.getValue();
151+
if (vobj != null && (targetClass == null || targetClass.isAssignableFrom(vobj.getClass()))) {
152+
return vobj;
153+
}
154+
}
155+
156+
if (value.getVarType().intValue() == (VT_BYREF | VT_VARIANT)) {
157+
value = (VARIANT) value.getValue();
158+
}
159+
86160
// Passing null or Object.class as targetClass switch to default
87161
// handling
88-
boolean concreteClassRequested = targetClass != null
89-
&& (! targetClass.isAssignableFrom(Object.class));
90-
91-
if (concreteClassRequested && targetClass.isAssignableFrom(value.getClass())) {
92-
return value;
162+
if (targetClass == null
163+
|| (targetClass.isAssignableFrom(Object.class))) {
164+
165+
targetClass = null;
166+
167+
int varType = value.getVarType().intValue();
168+
169+
switch (value.getVarType().intValue()) {
170+
case VT_UI1:
171+
case VT_I1:
172+
case VT_BYREF | VT_UI1:
173+
case VT_BYREF | VT_I1:
174+
targetClass = Byte.class;
175+
break;
176+
case VT_I2:
177+
case VT_BYREF | VT_I2:
178+
targetClass = Short.class;
179+
break;
180+
case VT_UI2:
181+
case VT_BYREF | VT_UI2:
182+
targetClass = Character.class;
183+
break;
184+
case VT_INT:
185+
case VT_UINT:
186+
case VT_UI4:
187+
case VT_I4:
188+
case VT_BYREF | VT_I4:
189+
case VT_BYREF | VT_UI4:
190+
case VT_BYREF | VT_INT:
191+
case VT_BYREF | VT_UINT:
192+
targetClass = Integer.class;
193+
break;
194+
case VT_UI8:
195+
case VT_I8:
196+
case VT_BYREF | VT_I8:
197+
case VT_BYREF | VT_UI8:
198+
targetClass = Long.class;
199+
break;
200+
case VT_R4:
201+
case VT_BYREF | VT_R4:
202+
targetClass = Float.class;
203+
break;
204+
case VT_R8:
205+
case VT_BYREF | VT_R8:
206+
targetClass = Double.class;
207+
break;
208+
case VT_BOOL:
209+
case VT_BYREF | VT_BOOL:
210+
targetClass = Boolean.class;
211+
break;
212+
case VT_ERROR:
213+
case VT_BYREF | VT_ERROR:
214+
targetClass = WinDef.SCODE.class;
215+
break;
216+
case VT_CY:
217+
case VT_BYREF | VT_CY:
218+
targetClass = OaIdl.CURRENCY.class;
219+
break;
220+
case VT_DATE:
221+
case VT_BYREF | VT_DATE:
222+
targetClass = Date.class;
223+
break;
224+
case VT_BSTR:
225+
case VT_BYREF | VT_BSTR:
226+
targetClass = String.class;
227+
break;
228+
case VT_UNKNOWN:
229+
case VT_BYREF | VT_UNKNOWN:
230+
targetClass = com.sun.jna.platform.win32.COM.IUnknown.class;
231+
break;
232+
case VT_DISPATCH:
233+
case VT_BYREF | VT_DISPATCH:
234+
targetClass = IDispatch.class;
235+
break;
236+
case VT_BYREF | VT_VARIANT:
237+
targetClass = Variant.class;
238+
break;
239+
case VT_BYREF:
240+
targetClass = PVOID.class;
241+
break;
242+
case VT_BYREF | VT_DECIMAL:
243+
targetClass = OaIdl.DECIMAL.class;
244+
break;
245+
case VT_RECORD:
246+
default:
247+
if ((varType & VT_ARRAY) > 0
248+
|| ((varType & VT_SAFEARRAY) > 0)) {
249+
targetClass = OaIdl.SAFEARRAY.class;
250+
}
251+
}
93252
}
94-
Object vobj = value.getValue();
95-
if (vobj != null && concreteClassRequested && targetClass.isAssignableFrom(vobj.getClass())) {
96-
return vobj;
253+
254+
Object result;
255+
if(Byte.class.equals(targetClass) || byte.class.equals(targetClass)) {
256+
result = value.byteValue();
257+
} else if (Short.class.equals(targetClass) || short.class.equals(targetClass)) {
258+
result = value.shortValue();
259+
} else if (Character.class.equals(targetClass) || char.class.equals(targetClass)) {
260+
result = (char) value.intValue();
261+
} else if (Integer.class.equals(targetClass) || int.class.equals(targetClass)) {
262+
result = value.intValue();
263+
} else if (Long.class.equals(targetClass) || long.class.equals(targetClass) || IComEnum.class.isAssignableFrom(targetClass)) {
264+
result = value.longValue();
265+
} else if (Float.class.equals(targetClass) || float.class.equals(targetClass)) {
266+
result = value.floatValue();
267+
} else if (Double.class.equals(targetClass) || double.class.equals(targetClass)) {
268+
result = value.doubleValue();
269+
} else if (Boolean.class.equals(targetClass) || boolean.class.equals(targetClass)) {
270+
result = value.booleanValue();
271+
} else if (Date.class.equals(targetClass)) {
272+
result = value.dateValue();
273+
} else if (String.class.equals(targetClass)) {
274+
result = value.stringValue();
275+
} else if (value.getValue() instanceof com.sun.jna.platform.win32.COM.IDispatch) {
276+
com.sun.jna.platform.win32.COM.IDispatch d = (com.sun.jna.platform.win32.COM.IDispatch) value.getValue();
277+
Object proxy = factory.createProxy(targetClass, d);
278+
// must release a COM reference, createProxy adds one, as does the
279+
// call
280+
if (!addReference) {
281+
int n = d.Release();
282+
}
283+
result = proxy;
284+
} else {
285+
/*
286+
WinDef.SCODE.class.equals(targetClass)
287+
|| OaIdl.CURRENCY.class.equals(targetClass)
288+
|| OaIdl.DECIMAL.class.equals(targetClass)
289+
|| OaIdl.SAFEARRAY.class.equals(targetClass)
290+
|| com.sun.jna.platform.win32.COM.IUnknown.class.equals(targetClass)
291+
|| Variant.class.equals(targetClass)
292+
|| PVOID.class.equals(targetClass
293+
*/
294+
result = value.getValue();
97295
}
98-
// Handle VARIANTByRef
99-
if(vobj instanceof VARIANT) {
100-
vobj = ((VARIANT) vobj).getValue();
296+
297+
if (IComEnum.class.isAssignableFrom(targetClass)) {
298+
return targetClass.cast(Convert.toComEnum((Class<? extends IComEnum>) targetClass, result));
299+
} else {
300+
return result;
101301
}
102-
if (vobj instanceof WinDef.BOOL) {
103-
return ((WinDef.BOOL) vobj).booleanValue();
104-
} else if (vobj instanceof VARIANT_BOOL) {
105-
return ((VARIANT_BOOL) vobj).booleanValue();
106-
} else if (vobj instanceof WinDef.LONG) {
107-
return ((WinDef.LONG) vobj).longValue();
108-
} else if (vobj instanceof WinDef.SHORT) {
109-
return ((WinDef.SHORT) vobj).shortValue();
110-
} else if (vobj instanceof WinDef.UINT) {
111-
return ((WinDef.UINT) vobj).intValue();
112-
} else if (vobj instanceof WinDef.WORD) {
113-
return ((WinDef.WORD) vobj).intValue();
114-
} else if (vobj instanceof WTypes.BSTR) {
115-
return ((WTypes.BSTR) vobj).getValue();
116-
}
117-
return vobj;
118302
}
119303

120304
public static <T extends IComEnum> T toComEnum(Class<T> enumType, Object value) {

contrib/platform/src/com/sun/jna/platform/win32/COM/util/ProxyObject.java

+3-14
Original file line numberDiff line numberDiff line change
@@ -402,20 +402,9 @@ public <T> T invokeMethod(Class<T> returnType, DISPID dispID, Object... args) {
402402
}
403403

404404
private <T> T convertAndFreeReturn(VARIANT.ByReference result, Class<T> returnType) {
405-
Object jobj = Convert.toJavaObject(result, returnType);
406-
if (IComEnum.class.isAssignableFrom(returnType)) {
407-
return returnType.cast(Convert.toComEnum((Class<? extends IComEnum>) returnType, jobj));
408-
} else if (jobj instanceof IDispatch) {
409-
IDispatch d = (IDispatch) jobj;
410-
T t = this.factory.createProxy(returnType, d);
411-
// must release a COM reference, createProxy adds one, as does the
412-
// call
413-
int n = d.Release();
414-
return t;
415-
} else {
416-
Convert.free(result, returnType);
417-
return returnType.cast(jobj);
418-
}
405+
Object jobj = Convert.toJavaObject(result, returnType, factory, false);
406+
Convert.free(result, returnType);
407+
return returnType.cast(jobj);
419408
}
420409

421410
@Override

0 commit comments

Comments
 (0)