diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/util/ProxyObject.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/util/ProxyObject.java index 14c5c63e9a..62dfeb4a11 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/util/ProxyObject.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/util/ProxyObject.java @@ -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; @@ -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 @@ -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); } } @@ -401,6 +402,21 @@ public T invokeMethod(Class 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 queryInterface(Class comInterface) throws COMException { assert COMUtils.comIsInitialized() : "COM not initialized"; diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ProxyObject_Test.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ProxyObject_Test.java index a3cd6bd6ee..51bd2f3145 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ProxyObject_Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ProxyObject_Test.java @@ -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; @@ -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 { } @@ -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); + } }