Using SAFEARRAYs from Java |
|
SAFEARRAY is a type of VARIANT which Visual Basic (and other COM environments) use for arrays of types. This example shows you how to pass such an array from Java to a COM object implemented in Visual C++.
One Dimensional Array
The COM Object
For convenience, I used ATL to create the COM object. Here is the IDL:
// newatl.idl : IDL source for newatl.dll
// This file will be processed by the MIDL tool to
// produce the type library (newatl.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(F16C5666-2828-4328-9A41-81617CF31DF7),
dual,
helpstring("IWhatever Interface"),
pointer_default(unique)
]
interface IWhatever : IDispatch
{
[id(1), helpstring("method Method")] HRESULT Method([in]VARIANT p1);
};
[
uuid(7FFA6B5D-F5F5-473B-9B2F-249326E1759C),
version(1.0),
helpstring("newatl 1.0 Type Library")
]
library NEWATLLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(C953061E-832B-4D6C-8192-FC20A478FA1A),
helpstring("Whatever Class")
]
coclass Whatever
{
[default] interface IWhatever;
};
};
Here is the implementation of the Method in VC++:
STDMETHODIMP Whatever::Method(VARIANT tVariant) {
// TODO: Add your implementation code here
if (tVariant.vt != (VT_ARRAY | VT_UI1))
return 1;// return an error.
// iterate through the array, printing out the items.
SAFEARRAY* pSafeArray = tVariant.parray;
for (unsigned int i=0; irgsabound->cElements; i++) {
char szMessage[40];
sprintf(szMessage, "%d", ((char*)tVariant.parray->pvData)[i]);
MessageBox(NULL, szMessage, "Info", MB_OK);
}
return S_OK;
}
The Java Client
When you run com2java and generate your proxies, the method in Whatever.java will look like this:
/**
* method. method Method
*
* @param p1 A Variant (in)
* @exception java.io.IOException If there are communications problems.
* @exception com.linar.jintegra.AutomationException If the remote server throws an exception.
*/
public void method (Object p1) throws java.io.IOException, com.linar.jintegra.AutomationException {
try {
d_IWhateverProxy.method(p1);
} catch(com.linar.jintegra.AutomationException automationException) {
automationException.fillInStackTrace();
throw automationException;
}
}
What do you use for Object p1? Here is the Java client code:
import newatl.*;
public class client {
static public void main(String[] args) {
try {
Whatever obj = new Whatever();
byte [] param = {1, 2, 3};
obj.method(param);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
Multi-dimensional Array
The COM Object
Download the attachment 2dSAFEARRAY.zip. It contains a complete VC++ project and Java source code for the example below.
Here is the IDL:
interface IArray : IDispatch
{
[id(1), helpstring("method getTwoDimensionalDoubleArray")] HRESULT getTwoDimensionalDoubleArray([out] SAFEARRAY(VARIANT)* ppsa);
};
Here is the implementation of the Method in VC++:
STDMETHODIMP CArray::getTwoDimensionalDoubleArray(SAFEARRAY** ppsa)
{
const unsigned length = 10;
SAFEARRAYBOUND sab[2];
sab[0].lLbound = 0; sab[0].cElements = length;
sab[1].lLbound = 0; sab[1].cElements = length;
*ppsa = SafeArrayCreate(VT_VARIANT, 2, sab);
for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
VARIANT tmp;
tmp.vt = VT_R8;
tmp.dblVal = (i + 1) * (j + 1);
long indices[] = {i, j};
SafeArrayPutElement(*ppsa, indices, &tmp);
}
}
return S_OK;
}
The Java Client
When you run com2java and generate your proxies, you need to use the "Generate Arrays as Objects" option when generating your Java proxies with com2java. Otherwise com2java assumes you are passing 1D arrays. Please refer to the documentation for more information on type mappings.
The generated Java proxy looks like this:
public void getTwoDimensionalDoubleArray (
Object[] ppsa) throws java.io.IOException, com.linar.jintegra.AutomationException {
try {
d_IArrayProxy.getTwoDimensionalDoubleArray(ppsa);
} catch(com.linar.jintegra.AutomationException automationException) {
automationException.fillInStackTrace();
throw automationException;
}
}
¡¡
Here is the Java code to invoke the getTwoDimensionalDoubleArray method.
Array array = new Array();
Object[] d2 = new Object[1];
array.getTwoDimensionalDoubleArray(d2);
Object[][] temp = new Object[10][10];
temp = (Object[][]) d2[0];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println(temp[i][j]);
}
}