Home : Using SAFEARRAYs from Java
Q30430 - HOWTO: Using SAFEARRAYs from Java

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]);
  }
}

Related Articles
No Related Articles Available.

Article Attachments
2dSAFEARRAY.zip

Related External Links
No Related Links Available.
Help us improve this article...
What did you think of this article?

poor 
1
2
3
4
5
6
7
8
9
10

 excellent
Tell us why you rated the content this way. (optional)
 
Approved Comments...
No user comments available for this article.
Created on 6/23/2006.
Last Modified on 7/14/2006.
Last Modified by No Author Name Available!.
Article has been viewed 11440 times.
Rated 4 out of 10 based on 6 votes.
Print Article
Email Article