-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support of array of variants #522
Comments
Please feel free to contribute. |
@charphi you can try this fork: https://github.com/matthiasblaesing/jna/tree/safearray It would be good if you could give it a spin. I used your sample code as basis to create a unittest excercising the SAFEARRAY function. I will rebase that branch once the fix_com branch or a equivalent was merged. |
I've just tested this fork and it works properly. Thanks :) |
Feel free to submit a PR with some utility methods on the SafeArray class or other appropriate place which makes the extraction more natural. |
Here is the code i'm using to create a java array from a safearray: public static Object toJavaArray(OaIdl.SAFEARRAY sa) {
int size = 1;
int[] dimArray = new int[sa.rgsabound.length];
for (int i = 0; i < dimArray.length; i++) {
dimArray[i] = sa.rgsabound[i].cElements.intValue();
size *= dimArray[i];
}
OleAuto.INSTANCE.SafeArrayLock(sa);
try {
Variant.VARIANT[] variantArray = (Variant.VARIANT[]) (new Variant.VARIANT(sa.pvData.getPointer()).toArray(size));
Object result = Array.newInstance(Object.class, dimArray);
fillJavaArray(result, dimArray, 0, variantArray, 0);
return result;
} finally {
OleAuto.INSTANCE.SafeArrayUnlock(sa);
}
}
private static void fillJavaArray(Object array, int[] dimArray, int dimIndex, Variant.VARIANT[] variantArray, int variantIndex) {
if (dimArray.length == dimIndex + 1) {
for (int i = 0; i < dimArray[dimIndex]; i++) {
Array.set(array, i, toJavaObject(variantArray[variantIndex + i], null));
}
} else {
for (int i = 0; i < dimArray[dimIndex]; i++) {
fillJavaArray(Array.get(array, i), dimArray, dimIndex + 1, variantArray, variantIndex + dimArray[dimIndex + 1] * i);
}
}
} |
Wouldn’t that be nicer with some Generics? Casting to an array from an Object seems so late 90s.
|
Maybe but I don't know how to write it since a SAFEARRAY is a multidimensional array and you get the number of dimensions at runtime. |
Could you show me an example of usage? Presumably you have to do something to the |
I revisited the branch and updated it with more functionality. I also added an object-oriented wrapper/helper (I admit it is a thin blanket). This request is primary directed to @charphi, please take a look at the branch and give it a spin. I think the test demonstrates, that the common cases are covered, but then more eyes are better. |
Your wrapper seems ok but I was thinking about something more "higher level". Here is an example of usage: import com.sun.jna.platform.win32.COM.util.Factory;
import com.sun.jna.platform.win32.COM.util.IComEnum;
import com.sun.jna.platform.win32.COM.util.annotation.ComInterface;
import com.sun.jna.platform.win32.COM.util.annotation.ComMethod;
import com.sun.jna.platform.win32.COM.util.annotation.ComObject;
import com.sun.jna.platform.win32.COM.util.annotation.ComProperty;
/**
*
* @author Philippe Charles
*/
public final class Adodb {
public static void main(String[] args) {
Factory factory = new Factory();
try (Connection conn = factory.createObject(Connection.class)) {
conn.open("Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
try (Recordset rs = conn.execute("SELECT TOP 5 System.ItemPathDisplay, System.ItemName, System.ItemUrl FROM SYSTEMINDEX ORDER BY System.ItemUrl")) {
while (!rs.isEOF()) {
System.out.println(rs.getFields().getItem(0).getValue());
rs.moveNext();
}
// Object[][] obj = rs.getRows();
// System.out.println(java.util.Arrays.deepToString(obj));
}
} finally {
factory.disposeAll();
}
}
private Adodb() {
// static class
}
@ComObject(progId = "ADODB.Connection")
public interface Connection extends AutoCloseable {
@ComMethod
void open(String connectionString);
@Override
@ComMethod
void close();
@ComMethod
Recordset execute(String commandText);
}
@ComInterface
public interface Recordset extends AutoCloseable {
@Override
@ComMethod
void close();
@ComProperty(name = "EOF")
boolean isEOF();
@ComMethod
void moveNext();
@ComProperty
Fields getFields();
@ComMethod
Object[][] getRows();
// Variant.VARIANT getRows();
}
@ComInterface
public interface Fields {
@ComProperty
Number getCount();
@ComProperty
Field getItem(int index);
@ComProperty
Field getItem(String name);
}
@ComInterface
public interface Field {
@ComProperty
String getName();
@ComProperty
DataTypeEnum getType();
@ComProperty
Object getValue();
@ComProperty
Object getPrecision();
}
public enum DataTypeEnum implements IComEnum {
adEmpty(0),
adSmallInt(2),
adInteger(3),
adSingle(4),
adDouble(5),
adCurrency(6),
adDate(7),
adBSTR(8),
adIDispatch(9),
adError(10),
adBoolean(11),
adVariant(12),
adIUnknown(13),
adDecimal(14),
adTinyInt(16),
adUnsignedTinyInt(17),
adUnsignedSmallInt(18),
adUnsignedInt(19),
adBigInt(20),
adUnsignedBigInt(21),
adFileTime(64),
adGUID(72),
adBinary(128),
adChar(129),
adWChar(130),
adNumeric(131),
adUserDefined(132),
adDBDate(133),
adDBTime(134),
adDBTimeStamp(135),
adChapter(136),
adPropVariant(138),
adVarNumeric(139),
adVarChar(200),
adLongVarChar(201),
adVarWChar(202),
adLongVarWChar(203),
adVarBinary(204),
adLongVarBinary(205),
adArray(0x2000);
private final long value;
private DataTypeEnum(long value) {
this.value = value;
}
@Override
public long getValue() {
return value;
}
}
} In order to return } else if (vobj instanceof WTypes.BSTR) {
return ((WTypes.BSTR) vobj).getValue();
} else if (vobj instanceof OaIdl.SAFEARRAY) {
return toJavaArray((OaIdl.SAFEARRAY) vobj);
}
return vobj; |
Ok - I just pushed a second iteration (rebased on current master):
The most relevant part is most probably the helper, for which an example can be found in com.sun.jna.platform.win32.SAFEARRAYTest, line 665. |
- Bind more functions from OleAut32.dll - Fix bug in function bindings from OleAut32.dll (long vs. LONG) - Ensure SAFEARRAY.rgsabound is completely accessible - Modify Variant#getValue and Variant#setValue to allow flexible access to data - Add object oriented helper methods to SAFEARRAY and move functionality from limited methods in OleAutoUtil to SAFEARRAY - Add unittests based on windows search provider that excercise SAFEARRAY functions - Added a helper for optimized conversion from SAFEARRAY to Object[] Closes java-native-access#522
- Bind more functions from OleAut32.dll - Fix bug in function bindings from OleAut32.dll (long vs. LONG) - Ensure SAFEARRAY.rgsabound is completely accessible - Modify Variant#getValue and Variant#setValue to allow flexible access to data - Add object oriented helper methods to SAFEARRAY and move functionality from limited methods in OleAutoUtil to SAFEARRAY - Add unittests based on windows search provider that excercise SAFEARRAY functions - Added a helper for optimized conversion from SAFEARRAY to Object[] Closes java-native-access#522
Hi guys, @matthiasblaesing , @charphi , you've implemented an excellent tool, which is very easy to use. But I cannot find a way, how to make it work faster with big arrays (>100000 elements). It takes minutes to fetch elements. As I understand these methods fetch SafeArray elements one at a time, and of course every call adds an overhead. What I do is very simple call to the Mapping class:
Looks like it goes to memory every time. Is there a way to import this array once into Java and then work with it in the same fashion. I'm pretty sure this would be a major performance improvement. |
In general, please use the jna-users forum/mailinglist/group: https://groups.google.com/forum/#!forum/jna-users As a first hint: Have a look at OaIdl#toPrimitiveArray. That routine uses SafeArrayAccessData to access the raw memory of the SAFEARRAY. This way you can read large arrays of values at once and pay the costs for the Java<->Native transition only once. |
|
@oyvfos thanks for giving this advise, some comments:
|
Motivation: The quic implementation supports 0-RTT and early data but did lack a test for it. Modifications: Add test case Result: Automated testing of 0-RTT and early data
I need to call a COM method that returns an array of variant.
The var type is
8204
and correspond toVT_ARRAY | VT_VARIANT
.I guess that the code should be added in the class
com.sun.jna.platform.win32.Variant
.Here is an example of use in vbs (see
GetRows
):The text was updated successfully, but these errors were encountered: