Skip to content
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

feature #630: use of ellipsis/varargs in COM methods #642

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Features
* [#621](https://github.com/java-native-access/jna/pull/621): Added TYPEFLAGS-constants for `wTypeFlags` in `com.sun.jna.platform.win32.OaIdl.TYPEATTR` - [@SevenOf9Sleeper](https://github.com/SevenOf9Sleeper).
* [#625](https://github.com/java-native-access/jna/pull/625): Make conversion to/from java to/from VARIANT in `com.sun.jna.platform.win32.COM.util.Convert` more flexible and dependable - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#639](https://github.com/java-native-access/jna/pull/639): Add getloadavg() to OS X and Unix - [@dbwiddis](https://github.com/dbwiddis).
* [#642](https://github.com/java-native-access/jna/pull/642): COM calls with variable number of arguments (varargs) are now supported - [@SevenOf9Sleeper](https://github.com/SevenOf9Sleeper).

Bug Fixes
---------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package com.sun.jna.platform.win32.COM.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
Expand Down Expand Up @@ -51,7 +52,6 @@
import com.sun.jna.platform.win32.COM.util.annotation.ComProperty;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import java.lang.reflect.InvocationTargetException;

/**
* This object acts as the invocation handler for interfaces annotated with
Expand Down Expand Up @@ -232,12 +232,13 @@ public Object invoke(final Object proxy, final java.lang.reflect.Method method,

ComMethod meth = method.getAnnotation(ComMethod.class);
if (null != meth) {
Object[] fullLengthArgs = unfoldWhenVarargs(method, args);
int dispId = meth.dispId();
if(dispId != -1) {
return this.invokeMethod(returnType, new DISPID(dispId), args);
return this.invokeMethod(returnType, new DISPID(dispId), fullLengthArgs);
} else {
String methName = this.getMethodName(method, meth);
return this.invokeMethod(returnType, methName, args);
return this.invokeMethod(returnType, methName, fullLengthArgs);
}
}

Expand Down Expand Up @@ -401,6 +402,21 @@ public <T> T invokeMethod(Class<T> returnType, DISPID dispID, Object... args) {
return (T) Convert.toJavaObject(result, returnType, factory, false, true);
}

private Object[] unfoldWhenVarargs(java.lang.reflect.Method method, Object[] argParams) {
if (null == argParams) {
return null;
}
if (argParams.length == 0 || !method.isVarArgs() || !(argParams[argParams.length - 1] instanceof Object[])) {
return argParams;
}
// when last parameter is Object[] -> unfold the ellipsis:
Object[] varargs = (Object[]) argParams[argParams.length - 1];
Object[] args = new Object[argParams.length - 1 + varargs.length];
System.arraycopy(argParams, 0, args, 0, argParams.length - 1);
System.arraycopy(varargs, 0, args, argParams.length - 1, varargs.length);
return args;
}

@Override
public <T> T queryInterface(Class<T> comInterface) throws COMException {
assert COMUtils.comIsInitialized() : "COM not initialized";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.sun.jna.Pointer;
import static org.junit.Assert.*;

import java.io.File;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -41,8 +43,53 @@ interface Application extends IUnknown {

@ComMethod
void Quit(boolean SaveChanges, Object OriginalFormat, Boolean RouteDocument);

@ComMethod
public void Quit(Object... someArgs);

@ComMethod(dispId = 0x00000183)
public float PointsToPixels(float points, Object... someArgs);

@ComProperty(dispId = 0x00000006)
public Documents getDocuments();
}


@ComInterface(iid = "{0002096C-0000-0000-C000-000000000046}")
public interface Documents extends IDispatch {
@ComMethod
public _Document Add(Object template, Object newTemplate, Object documentType, Object visible);

@ComMethod
public _Document Add(Object... someArgs);
}

@ComInterface(iid = "{0002096B-0000-0000-C000-000000000046}")
public interface _Document extends IDispatch {
@ComMethod
public void SaveAs(Object fileName, Object fileFormat, Object lockComments, Object password,
Object addToRecentFiles, Object writePassword, Object readOnlyRecommended, Object embedTrueTypeFonts,
Object saveNativePictureFormat, Object saveFormsData, Object saveAsAOCELetter, Object encoding,
Object insertLineBreaks, Object allowSubstitutions, Object lineEnding, Object addBiDiMarks);

@ComMethod
public void SaveAs(Object... someArgs);
}

public enum WdSaveFormat implements IComEnum {
wdFormatDocument(0), wdFormatText(2), wdFormatRTF(6), wdFormatHTML(8), wdFormatPDF(17);

private long _value;

private WdSaveFormat(long value) {
_value = value;
}

@Override
public long getValue() {
return _value;
}
}

@ComObject(progId="Word.Application")
interface MsWordApp extends Application {
}
Expand Down Expand Up @@ -116,4 +163,27 @@ public void accessWhilstDisposing() {

}

@Test
public void testVarargsCallWithoutVarargParameter() {
MsWordApp comObj = this.factory.createObject(MsWordApp.class);

// call must work without exception:
float f = comObj.PointsToPixels(25.3f);
comObj.Quit();
}

@Test
public void testVarargsCallWithParameter() {
MsWordApp comObj = this.factory.createObject(MsWordApp.class);

Documents documents = comObj.getDocuments();
_Document myDocument = documents.Add();

String path = new File(".").getAbsolutePath();
myDocument.SaveAs(path + "\\abcdefg", WdSaveFormat.wdFormatPDF);
comObj.Quit();

boolean wasDeleted = new File("abcdefg.pdf").delete();
assertTrue(wasDeleted);
}
}