Accessing a SafeArray of Variants with JNI
I have a VB6 ActiveX DLL with functions that return a Variant. The Variant contains an array of node Variants, each of which contains a string Name and two data arrays (string and double). I am attempting to return this to a Java program as a jobject through JNI.
I can access the outer arra开发者_如何转开发y of nodes by calling the appropriate VB function and storing the Variant result as a SAFEARRAY. It can access the dimension and get lower and upper bounds. However, I cannot access each node through SafeArrayGetElement() or SafeArrayAccessData(). I always get an Invalid Argument exception.
1) Can I pass or cast the SAFEARRAY (or VARIANT) directly to a jobject without iterating through the nodes in C++?
2) Am I using the wrong parameters to get the SAFEARRAY data? Does the size of the access pointer (var) need to be allocated beforehand?
SAFEARRAY* outarr = t->VBFunction(&bstrparam).GetVARIANT().parray;
//Returns correct dimension (1)
printf("JNI GetNodes_States: Got array, dimension %d\n", outarr->cDims);
//Returns correct bounds
LONG lBound, rBound;
SafeArrayGetLBound(outarr, 1, &lBound);
SafeArrayGetUBound(outarr, 1, &rBound);
printf("JNI GetNodes_States: Bounds [%d, %d]\n", lBound, rBound);
//Returns Invalid Argument error (hresult=0x80070057)
//Gets first element
LONG* indexArray = new LONG[outarr->cDims];
for(unsigned short i=0; i<outarr->cDims; ++i)
indexArray[i] = 0;
_variant_t var;
hresult = SafeArrayGetElement(outarr, indexArray, (void*)&var);
if (SUCCEEDED(hresult)){
printf( "JNI GetNodes_States: %s, %d\n", "", outarr->cDims);
}
else {
printf( "JNI GetNodes_States Access Error:%X\n", hresult);
outobj = NULL;
}
delete[] indexArray;
1) Can I pass or cast the SAFEARRAY (or VARIANT) directly to a jobject without iterating through the nodes in C++?
Absolutely not, I'm afraid. You're going to walk through the array, extract all the necessary values, and convert each of them to something that Java will understand.
2) Am I using the wrong parameters to get the SAFEARRAY data? Does the size of the access pointer (var) need to be allocated beforehand?
The most suspicious argument is indexArray
, which you're setting to 0 for each dimension. However, if the array was created by Visual Basic it is quite possible that it is a 1-based array instead of a 0-based array, which would make an index of 0 illegal.
This is why your element-extraction code needs to pay attention to the results of SafeArrayGetLBound
and SafeArrayGetUBound
.
精彩评论