Skip to content

Commit 267bbce

Browse files
Fix SAFEARRAY ByReference in VARIANT
A SAFEARRAY byref that is wrapped in a VARIANT is a **SAFEARRAY. To model this in JNA a pseudo structure SAFEARRAYByReference is introduced. This approach is used, so that the referenced SAFEARRAY is read after a native call. To make it possible to pass a SAFEARRAYByReference and an IntByReference through the ProxyObject helper, c.s.j.platform.win32.COM.util.Convert is modified to reflectivly invoke a matching VARIANT constructor. This change was manually tested with the GdPicture.NET library using ProxyObject and COMLateBindingObject based binding.
1 parent 631c0e9 commit 267bbce

4 files changed

Lines changed: 99 additions & 90 deletions

File tree

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

Lines changed: 47 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
*/
2424
package com.sun.jna.platform.win32.COM.util;
2525

26-
import com.sun.jna.platform.win32.OaIdl.DATE;
27-
import com.sun.jna.platform.win32.OaIdl.VARIANT_BOOL;
2826
import com.sun.jna.platform.win32.OleAuto;
2927
import com.sun.jna.platform.win32.Variant;
3028
import java.lang.reflect.InvocationHandler;
@@ -36,13 +34,7 @@
3634
import com.sun.jna.platform.win32.WinDef;
3735
import com.sun.jna.platform.win32.Variant.VARIANT;
3836
import com.sun.jna.platform.win32.WTypes.BSTR;
39-
import com.sun.jna.platform.win32.WinDef.BOOL;
40-
import com.sun.jna.platform.win32.WinDef.BYTE;
41-
import com.sun.jna.platform.win32.WinDef.CHAR;
42-
import com.sun.jna.platform.win32.WinDef.LONG;
43-
import com.sun.jna.platform.win32.WinDef.SHORT;
4437
import com.sun.jna.platform.win32.OaIdl;
45-
import com.sun.jna.platform.win32.OaIdl.SAFEARRAY;
4638
import static com.sun.jna.platform.win32.Variant.VT_ARRAY;
4739
import static com.sun.jna.platform.win32.Variant.VT_BOOL;
4840
import static com.sun.jna.platform.win32.Variant.VT_BSTR;
@@ -70,6 +62,7 @@
7062
import static com.sun.jna.platform.win32.Variant.VT_UNKNOWN;
7163
import static com.sun.jna.platform.win32.Variant.VT_VARIANT;
7264
import com.sun.jna.platform.win32.WinDef.PVOID;
65+
import java.lang.reflect.Constructor;
7366

7467
/**
7568
* This class is considered internal to the package.
@@ -78,42 +71,26 @@ class Convert {
7871
/**
7972
* Convert a java value into a VARIANT suitable for passing in a COM
8073
* invocation.
81-
*
74+
*
8275
* <p><i>Implementation notes</i></p>
83-
*
76+
*
8477
* <ul>
8578
* <li>VARIANTs are not rewrapped, but passed through unmodified</li>
8679
* <li>A string is wrapped into a BSTR, that is wrapped into the VARIANT.
8780
* The string is allocated as native memory by the VARIANT constructor.
8881
* The BSTR needs to be freed by {@link com.sun.jna.platform.win32.OleAuto#SysFreeString}.</li>
8982
* </ul>
90-
*
83+
*
9184
* @param value to be wrapped
9285
* @return wrapped VARIANT
9386
*/
9487
public static VARIANT toVariant(Object value) {
95-
if (value instanceof VARIANT) {
88+
if(value instanceof VARIANT) {
9689
return (VARIANT) value;
97-
} else if (value instanceof BSTR) {
98-
return new VARIANT((BSTR) value);
99-
} else if (value instanceof VARIANT_BOOL) {
100-
return new VARIANT((VARIANT_BOOL) value);
101-
} else if (value instanceof BOOL) {
102-
return new VARIANT((BOOL) value);
103-
} else if (value instanceof LONG) {
104-
return new VARIANT((LONG) value);
105-
} else if (value instanceof SHORT) {
106-
return new VARIANT((SHORT) value);
107-
} else if (value instanceof DATE) {
108-
return new VARIANT((DATE) value);
109-
} else if (value instanceof BYTE) {
110-
return new VARIANT((BYTE) value);
11190
} else if (value instanceof Byte) {
11291
return new VARIANT((Byte) value);
11392
} else if (value instanceof Character) {
11493
return new VARIANT((Character) value);
115-
} else if (value instanceof CHAR) {
116-
return new VARIANT((CHAR) value);
11794
} else if (value instanceof Short) {
11895
return new VARIANT((Short) value);
11996
} else if (value instanceof Integer) {
@@ -132,27 +109,42 @@ public static VARIANT toVariant(Object value) {
132109
return new VARIANT((com.sun.jna.platform.win32.COM.IDispatch) value);
133110
} else if (value instanceof Date) {
134111
return new VARIANT((Date) value);
135-
} else if (value instanceof Proxy) {
112+
} else if (value instanceof Proxy) {
136113
InvocationHandler ih = Proxy.getInvocationHandler(value);
137114
ProxyObject pobj = (ProxyObject) ih;
138115
return new VARIANT(pobj.getRawDispatch());
139116
} else if (value instanceof IComEnum) {
140117
IComEnum enm = (IComEnum) value;
141118
return new VARIANT(new WinDef.LONG(enm.getValue()));
142-
} else if (value instanceof SAFEARRAY) {
143-
return new VARIANT((SAFEARRAY) value);
144-
} else {
145-
return null;
146-
}
147-
}
148-
119+
} else {
120+
Constructor<VARIANT> constructor = null;
121+
if (value != null) {
122+
for (Constructor<VARIANT> m : (Constructor<VARIANT>[]) VARIANT.class.getConstructors()) {
123+
if (m.getParameterCount() > 0
124+
&& m.getParameterTypes()[0].isAssignableFrom(value.getClass())) {
125+
constructor = m;
126+
}
127+
}
128+
}
129+
130+
if (constructor != null) {
131+
try {
132+
return constructor.newInstance(value);
133+
} catch (Exception ex) {
134+
throw new RuntimeException(ex);
135+
}
136+
}
137+
return null;
138+
}
139+
}
140+
149141
public static Object toJavaObject(VARIANT value, Class<?> targetClass, ObjectFactory factory, boolean addReference, boolean freeValue) {
150-
if (null==value
151-
|| value.getVarType().intValue() == VT_EMPTY
142+
if (null==value
143+
|| value.getVarType().intValue() == VT_EMPTY
152144
|| value.getVarType().intValue() == VT_NULL) {
153145
return null;
154146
}
155-
147+
156148
if (targetClass != null && (!targetClass.isAssignableFrom(Object.class))) {
157149
if (targetClass.isAssignableFrom(value.getClass())) {
158150
return value;
@@ -163,86 +155,67 @@ public static Object toJavaObject(VARIANT value, Class<?> targetClass, ObjectFac
163155
return vobj;
164156
}
165157
}
166-
158+
167159
VARIANT inputValue = value;
168-
160+
169161
if (value.getVarType().intValue() == (VT_BYREF | VT_VARIANT)) {
170162
value = (VARIANT) value.getValue();
171163
}
172-
164+
173165
// Passing null or Object.class as targetClass switch to default
174166
// handling
175167
if (targetClass == null || (targetClass.isAssignableFrom(Object.class))) {
176-
168+
177169
targetClass = null;
178-
170+
179171
int varType = value.getVarType().intValue();
180-
172+
181173
switch (value.getVarType().intValue()) {
182174
case VT_UI1:
183175
case VT_I1:
184-
case VT_BYREF | VT_UI1:
185-
case VT_BYREF | VT_I1:
186176
targetClass = Byte.class;
187177
break;
188178
case VT_I2:
189-
case VT_BYREF | VT_I2:
190179
targetClass = Short.class;
191180
break;
192181
case VT_UI2:
193-
case VT_BYREF | VT_UI2:
194182
targetClass = Character.class;
195183
break;
196184
case VT_INT:
197185
case VT_UINT:
198186
case VT_UI4:
199187
case VT_I4:
200-
case VT_BYREF | VT_I4:
201-
case VT_BYREF | VT_UI4:
202-
case VT_BYREF | VT_INT:
203-
case VT_BYREF | VT_UINT:
204188
targetClass = Integer.class;
205189
break;
206190
case VT_UI8:
207191
case VT_I8:
208-
case VT_BYREF | VT_I8:
209-
case VT_BYREF | VT_UI8:
210192
targetClass = Long.class;
211193
break;
212194
case VT_R4:
213-
case VT_BYREF | VT_R4:
214195
targetClass = Float.class;
215196
break;
216197
case VT_R8:
217-
case VT_BYREF | VT_R8:
218198
targetClass = Double.class;
219199
break;
220200
case VT_BOOL:
221-
case VT_BYREF | VT_BOOL:
222201
targetClass = Boolean.class;
223202
break;
224203
case VT_ERROR:
225-
case VT_BYREF | VT_ERROR:
226204
targetClass = WinDef.SCODE.class;
227205
break;
228206
case VT_CY:
229-
case VT_BYREF | VT_CY:
230207
targetClass = OaIdl.CURRENCY.class;
231208
break;
232209
case VT_DATE:
233-
case VT_BYREF | VT_DATE:
234210
targetClass = Date.class;
235211
break;
236212
case VT_BSTR:
237-
case VT_BYREF | VT_BSTR:
238213
targetClass = String.class;
239214
break;
240215
case VT_UNKNOWN:
241-
case VT_BYREF | VT_UNKNOWN:
242216
targetClass = com.sun.jna.platform.win32.COM.IUnknown.class;
243217
break;
244218
case VT_DISPATCH:
245-
case VT_BYREF | VT_DISPATCH:
246219
targetClass = IDispatch.class;
247220
break;
248221
case VT_BYREF | VT_VARIANT:
@@ -261,7 +234,7 @@ public static Object toJavaObject(VARIANT value, Class<?> targetClass, ObjectFac
261234
}
262235
}
263236
}
264-
237+
265238
Object result;
266239
if(Byte.class.equals(targetClass) || byte.class.equals(targetClass)) {
267240
result = value.byteValue();
@@ -308,14 +281,14 @@ public static Object toJavaObject(VARIANT value, Class<?> targetClass, ObjectFac
308281
if (IComEnum.class.isAssignableFrom(targetClass)) {
309282
result = targetClass.cast(Convert.toComEnum((Class<? extends IComEnum>) targetClass, result));
310283
}
311-
284+
312285
if(freeValue) {
313286
free(inputValue, result);
314287
}
315-
288+
316289
return result;
317290
}
318-
291+
319292
public static <T extends IComEnum> T toComEnum(Class<T> enumType, Object value) {
320293
try {
321294
Method m = enumType.getMethod("values");
@@ -332,13 +305,13 @@ public static <T extends IComEnum> T toComEnum(Class<T> enumType, Object value)
332305
}
333306
return null;
334307
}
335-
308+
336309
/**
337310
* Free the contents of the supplied VARIANT.
338-
*
311+
*
339312
* <p>This method is a companion to {@link #toVariant}. Primary usage is
340313
* to free BSTRs contained in VARIANTs.</p>
341-
*
314+
*
342315
* @param variant to be cleared
343316
* @param javaType type before/after conversion
344317
*/
@@ -352,13 +325,13 @@ public static void free(VARIANT variant, Class<?> javaType) {
352325
}
353326
}
354327
}
355-
328+
356329
/**
357330
* Free the contents of the supplied VARIANT.
358-
*
331+
*
359332
* <p>This method is a companion to {@link #toVariant}. Primary usage is
360333
* to free BSTRs contained in VARIANTs.</p>
361-
*
334+
*
362335
* @param variant to be cleared
363336
* @param value value before/after conversion
364337
*/

contrib/platform/src/com/sun/jna/platform/win32/OaIdl.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import com.sun.jna.IntegerType;
2828
import com.sun.jna.Memory;
29+
import com.sun.jna.Native;
2930
import com.sun.jna.NativeLong;
3031
import com.sun.jna.Pointer;
3132
import com.sun.jna.Structure;
@@ -288,7 +289,7 @@ protected List<String> getFieldOrder() {
288289
return FIELDS;
289290
}
290291
}
291-
292+
292293
/**
293294
* The Class DISPID.
294295
*/
@@ -631,7 +632,7 @@ protected List<String> getFieldOrder() {
631632
* @param size array of dimension size
632633
* @return SAFEARRAYWrapper or {@code NULL} if creation fails.
633634
*/
634-
public static SAFEARRAY createSafeArray(int... size) {
635+
public static SAFEARRAY.ByReference createSafeArray(int... size) {
635636
return createSafeArray(new WTypes.VARTYPE(Variant.VT_VARIANT), size);
636637
}
637638

@@ -647,7 +648,7 @@ public static SAFEARRAY createSafeArray(int... size) {
647648
* @param size array of dimension size
648649
* @return SAFEARRAYWrapper or {@code NULL} if creation fails.
649650
*/
650-
public static SAFEARRAY createSafeArray(VARTYPE vartype, int... size) {
651+
public static SAFEARRAY.ByReference createSafeArray(VARTYPE vartype, int... size) {
651652
OaIdl.SAFEARRAYBOUND[] rgsabound = (OaIdl.SAFEARRAYBOUND[]) new OaIdl.SAFEARRAYBOUND().toArray(size.length);
652653
for (int i = 0; i < size.length; i++) {
653654
rgsabound[i].lLbound = new WinDef.LONG(0);
@@ -1042,6 +1043,30 @@ public long getElemsize() {
10421043
}
10431044
}
10441045

1046+
public static class SAFEARRAYByReference extends Structure implements Structure.ByReference {
1047+
1048+
public SAFEARRAYByReference() {
1049+
}
1050+
1051+
public SAFEARRAYByReference(Pointer p) {
1052+
super(p);
1053+
read();
1054+
}
1055+
1056+
public SAFEARRAYByReference(SAFEARRAY.ByReference safeArray) {
1057+
pSAFEARRAY = safeArray;
1058+
}
1059+
1060+
public static final List<String> FIELDS = createFieldsOrder("pSAFEARRAY");
1061+
1062+
public SAFEARRAY.ByReference pSAFEARRAY;
1063+
1064+
@Override
1065+
protected List<String> getFieldOrder() {
1066+
return FIELDS;
1067+
}
1068+
}
1069+
10451070
public static class SAFEARRAYBOUND extends Structure {
10461071
public static class ByReference extends SAFEARRAYBOUND implements
10471072
Structure.ByReference {

0 commit comments

Comments
 (0)