From 62b6061c923f79e805332d3d6ade5a5801c713ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Thu, 5 May 2016 21:45:07 +0200 Subject: [PATCH] Implement named callback parameters for COM Callbacks --- .../win32/COM/COMBindingBaseObject.java | 8 +- .../win32/COM/util/CallbackProxy.java | 123 +++++++++++++----- .../platform/win32/COM/util/ProxyObject.java | 7 +- .../com/sun/jna/platform/win32/OleAuto.java | 67 ++++++++-- .../win32/COM/ComEventCallbacks_Test.java | 43 +++--- .../COM/util/ComEventCallbacks2_Test.java | 118 +++++++++++++++++ .../COM/util/HybdridCOMInvocationTest.java | 8 +- 7 files changed, 288 insertions(+), 86 deletions(-) create mode 100644 contrib/platform/test/com/sun/jna/platform/win32/COM/util/ComEventCallbacks2_Test.java diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java index 857ecd2a14..ddad2c231e 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java @@ -236,16 +236,12 @@ protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, // Handle special-case for property-puts! if (nType == OleAuto.DISPATCH_PROPERTYPUT) { - dp.cNamedArgs = new UINT(_argsLen); - dp.rgdispidNamedArgs = new DISPIDByReference( - OaIdl.DISPID_PROPERTYPUT); + dp.setRgdispidNamedArgs(new DISPID[] {OaIdl.DISPID_PROPERTYPUT}); } // Build DISPPARAMS if (_argsLen > 0) { - dp.cArgs = new UINT(_args.length); - // make pointer of variant array - dp.rgvarg = new VariantArg.ByReference(_args); + dp.setArgs(_args); // write 'DISPPARAMS' structure to memory dp.write(); diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java index 0504051d4a..8b768b7256 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java @@ -20,7 +20,6 @@ import com.sun.jna.Pointer; import com.sun.jna.WString; -import com.sun.jna.platform.win32.Guid; import com.sun.jna.platform.win32.Guid.IID; import com.sun.jna.platform.win32.Guid.REFIID; import com.sun.jna.platform.win32.OaIdl.DISPID; @@ -29,7 +28,6 @@ import com.sun.jna.platform.win32.OleAuto.DISPPARAMS; import com.sun.jna.platform.win32.Variant; import com.sun.jna.platform.win32.Variant.VARIANT; -import com.sun.jna.platform.win32.Variant.VariantArg; import com.sun.jna.platform.win32.WinDef.LCID; import com.sun.jna.platform.win32.WinDef.UINT; import com.sun.jna.platform.win32.WinDef.UINTByReference; @@ -40,7 +38,6 @@ import com.sun.jna.platform.win32.COM.COMUtils; import com.sun.jna.platform.win32.COM.Dispatch; import com.sun.jna.platform.win32.COM.DispatchListener; -import com.sun.jna.platform.win32.COM.IDispatch; import com.sun.jna.platform.win32.COM.IDispatchCallback; import com.sun.jna.platform.win32.COM.Unknown; import com.sun.jna.platform.win32.COM.util.annotation.ComEventCallback; @@ -50,6 +47,14 @@ public class CallbackProxy implements IDispatchCallback { + private static boolean DEFAULT_BOOLEAN; + private static byte DEFAULT_BYTE; + private static short DEFAULT_SHORT; + private static int DEFAULT_INT; + private static long DEFAULT_LONG; + private static float DEFAULT_FLOAT; + private static double DEFAULT_DOUBLE; + public CallbackProxy(Factory factory, Class comEventCallbackInterface, IComEventCallbackListener comEventCallbackListener) { this.factory = factory; @@ -90,6 +95,11 @@ Map createDispIdMap(Class comEventCallbackInterface) { if (-1 == dispId) { dispId = this.fetchDispIdFromName(annotation); } + if(dispId == -1) { + CallbackProxy.this.comEventCallbackListener.errorReceivingCallbackEvent( + "DISPID for " + meth.getName() + " not found", + null); + } map.put(new DISPID(dispId), meth); } } @@ -105,50 +115,101 @@ int fetchDispIdFromName(ComEventCallback annotation) { void invokeOnThread(final DISPID dispIdMember, final REFIID riid, LCID lcid, WORD wFlags, final DISPPARAMS.ByReference pDispParams) { - final Method eventMethod; - if (CallbackProxy.this.dsipIdMap.containsKey(dispIdMember)) { - eventMethod = CallbackProxy.this.dsipIdMap.get(dispIdMember); - if (eventMethod.getParameterTypes().length != pDispParams.cArgs.intValue()) { - CallbackProxy.this.comEventCallbackListener.errorReceivingCallbackEvent( - "Trying to invoke method " + eventMethod + " with " + pDispParams.cArgs.intValue() + " arguments", - null); - return; - } - } else { + VARIANT[] arguments = pDispParams.getArgs(); + + final Method eventMethod = CallbackProxy.this.dsipIdMap.get(dispIdMember); + if (eventMethod == null) { CallbackProxy.this.comEventCallbackListener.errorReceivingCallbackEvent( "No method found with dispId = " + dispIdMember, null); return; } + // DISPPARAMs can use two different ways to pass arguments + // Arguments can be passed as a linear list with all arguments + // specified to a certain position (positional) or the position of + // an argument can be passed via the rgdispidNamedArgs array (named). + // + // pDispParams.rgvarg (length in pDispParams.cArgs) contains all + // arguments (named + position based) + // + // pDispParams.rgdispidNamedArgs (length in pDispParams.cNamedArgs) contains + // the named parameters as DISPIDs - the DISPIDs are the target index + // in the method signature (zero based). + // + // Each entry in pDispParams.rgvarg is either position based or name + // based and the position bases arguments are passed in reverse order, + // so getting this: + // + // rgvarg = ["arg1", "arg2", "arg3", "arg4", "arg5"] + // rgdispidNamedArgs = [3, 4] + // + // Would lead to this paramater array in the handler: + // + // ["arg5", "arg4", "arg3", "arg1", "arg2"] + // + // See also: https://msdn.microsoft.com/de-de/library/windows/desktop/ms221653%28v=vs.85%29.aspx + + // Arguments are converted to the JAVA side and IDispatch Interfaces // are wrapped into an ProxyObject if so requested. // // Out-Parameter need to be specified as VARIANT, VARIANT args are // not converted, so COM memory allocation rules apply. - final Class[] params = eventMethod.getParameterTypes(); - List rjargs = new ArrayList(); - if (pDispParams.cArgs.intValue() > 0) { - VariantArg vargs = pDispParams.rgvarg; - vargs.setArraySize(pDispParams.cArgs.intValue()); - for ( int i = 0; i < vargs.variantArg.length; i++) { - Class targetClass = params[vargs.variantArg.length - 1 - i]; - Variant.VARIANT varg = vargs.variantArg[i]; - Object jarg = Convert.toJavaObject(varg, targetClass, factory, true, false); - rjargs.add(jarg); + + DISPID[] positionMap = pDispParams.getRgdispidNamedArgs(); + + final Class[] paramTypes = eventMethod.getParameterTypes(); + final Object[] params = new Object[paramTypes.length]; + + // Handle position based parameters first + for ( int i = 0; i < params.length && (arguments.length - positionMap.length - i) > 0; i++) { + Class targetClass = paramTypes[i]; + Variant.VARIANT varg = arguments[arguments.length - i - 1]; + params[i] = Convert.toJavaObject(varg, targetClass, factory, true, false); + } + + for ( int i = 0; i < positionMap.length; i++) { + int targetPosition = positionMap[i].intValue(); + if(targetPosition >= params.length) { + // If less parameters are mapped then supplied, ignore + continue; + } + Class targetClass = paramTypes[targetPosition]; + Variant.VARIANT varg = arguments[i]; + params[targetPosition] = Convert.toJavaObject(varg, targetClass, factory, true, false); + } + + + // Make sure the parameters are correctly initialized -- primitives + // should not throw a nullpointer exception, but + for(int i = 0; i < params.length; i++) { + if(params[i] == null && paramTypes[i].isPrimitive()) { + if (paramTypes[i].equals(boolean.class)) { + params[i] = DEFAULT_BOOLEAN; + } else if (paramTypes[i].equals(byte.class)) { + params[i] = DEFAULT_BYTE; + } else if (paramTypes[i].equals(short.class)) { + params[i] = DEFAULT_SHORT; + } else if (paramTypes[i].equals(int.class)) { + params[i] = DEFAULT_INT; + } else if (paramTypes[i].equals(long.class)) { + params[i] = DEFAULT_LONG; + } else if (paramTypes[i].equals(float.class)) { + params[i] = DEFAULT_FLOAT; + } else if (paramTypes[i].equals(double.class)) { + params[i] = DEFAULT_DOUBLE; + } else { + throw new IllegalArgumentException("Class type " + paramTypes[i].getName() + " not mapped to primitive default value."); + } } } - List margs = new ArrayList(); try { // Reverse order from calling convention - int lastParamIdx = eventMethod.getParameterTypes().length - 1; - for (int i = lastParamIdx; i >= 0; i--) { - margs.add(rjargs.get(i)); - } - eventMethod.invoke(comEventCallbackListener, margs.toArray()); + eventMethod.invoke(comEventCallbackListener, params); } catch (Exception e) { - List decodedClassNames = new ArrayList(margs.size()); - for(Object o: margs) { + List decodedClassNames = new ArrayList(params.length); + for(Object o: params) { if(o == null) { decodedClassNames.add("NULL"); } else { 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 62dfeb4a11..9b01908b81 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 @@ -595,8 +595,7 @@ protected HRESULT oleMethod(final int nType, final VARIANT.ByReference pvResult, // Handle special-case for property-puts! if (nType == OleAuto.DISPATCH_PROPERTYPUT) { - dp.cNamedArgs = new UINT(_argsLen); - dp.rgdispidNamedArgs = new DISPIDByReference(OaIdl.DISPID_PROPERTYPUT); + dp.setRgdispidNamedArgs(new DISPID[] {OaIdl.DISPID_PROPERTYPUT}); } // Apply "fix" according to @@ -631,9 +630,7 @@ protected HRESULT oleMethod(final int nType, final VARIANT.ByReference pvResult, // Build DISPPARAMS if (_argsLen > 0) { - dp.cArgs = new UINT(_args.length); - // make pointer of variant array - dp.rgvarg = new VariantArg.ByReference(_args); + dp.setArgs(_args); // write 'DISPPARAMS' structure to memory dp.write(); diff --git a/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java b/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java index a7af894e49..e93aebf8d7 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/OleAuto.java @@ -12,6 +12,7 @@ */ package com.sun.jna.platform.win32; +import com.sun.jna.Memory; import java.util.List; import com.sun.jna.Native; @@ -19,7 +20,7 @@ import com.sun.jna.Structure; import com.sun.jna.WString; import com.sun.jna.platform.win32.Guid.GUID; -import com.sun.jna.platform.win32.OaIdl.DISPIDByReference; +import com.sun.jna.platform.win32.OaIdl.DISPID; import com.sun.jna.platform.win32.OaIdl.SAFEARRAY; import com.sun.jna.platform.win32.OaIdl.SAFEARRAYBOUND; import com.sun.jna.platform.win32.Variant.VARIANT; @@ -563,15 +564,61 @@ public static class ByReference extends DISPPARAMS implements /** The rgvarg. */ public VariantArg.ByReference rgvarg; - /** The rgdispid named args. */ - public DISPIDByReference rgdispidNamedArgs; - - /** The c args. */ - public UINT cArgs; - - /** The c named args. */ - public UINT cNamedArgs; - + /** The rgdispid named args. */ + public Pointer rgdispidNamedArgs = Pointer.NULL; + + /** The c args. - use setArgs to update arguments */ + public UINT cArgs = new UINT(0); + + /** The c named args. - use setRgdispidNamedArgs to update named arguments map */ + public UINT cNamedArgs = new UINT(0); + + public DISPID[] getRgdispidNamedArgs() { + DISPID[] namedArgs = null; + int count = cNamedArgs.intValue(); + if(rgdispidNamedArgs != null && count > 0) { + int[] rawData = rgdispidNamedArgs.getIntArray(0, count); + namedArgs = new DISPID[count]; + for(int i = 0; i < count; i++) { + namedArgs[i] = new DISPID(rawData[i]); + } + } else { + namedArgs = new DISPID[0]; + } + return namedArgs; + } + + public void setRgdispidNamedArgs(DISPID[] namedArgs) { + if(namedArgs == null) { + namedArgs = new DISPID[0]; + } + cNamedArgs = new UINT(namedArgs.length); + rgdispidNamedArgs = new Memory(DISPID.SIZE * namedArgs.length); + int[] rawData = new int[namedArgs.length]; + for(int i = 0; i < rawData.length; i++) { + rawData[i] = namedArgs[i].intValue(); + } + rgdispidNamedArgs.write(0, rawData, 0, namedArgs.length); + } + + public VARIANT[] getArgs() { + if(this.rgvarg != null) { + this.rgvarg.setArraySize(cArgs.intValue()); + return this.rgvarg.variantArg; + } else { + return new VARIANT[0]; + } + } + + public void setArgs(VARIANT[] arguments) { + if(arguments == null) { + arguments = new VARIANT[0]; + } + + rgvarg = new VariantArg.ByReference(arguments); + cArgs = new UINT(arguments.length); + } + /** * Instantiates a new dispparams. */ diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java index 4652cb6328..7d54294940 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java @@ -92,9 +92,6 @@ public void before() { public void after() { // Shutdown Internet Explorer DISPPARAMS.ByReference pDispParams = new DISPPARAMS.ByReference(); - pDispParams.cArgs = new UINT(0); - pDispParams.cNamedArgs = new UINT(0); - pDispParams.rgvarg = null; VARIANT.ByReference pVarResult = new VARIANT.ByReference(); IntByReference puArgErr = new IntByReference(); EXCEPINFO.ByReference pExcepInfo = new EXCEPINFO.ByReference(); @@ -196,27 +193,24 @@ public HRESULT Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, VARIANT.ByReference pVarResult, EXCEPINFO.ByReference pExcepInfo, IntByReference puArgErr) { - // @toDo: Move setArraySize into invoke method - if (pDispParams.rgvarg != null && pDispParams.cArgs.intValue() > 0) { - pDispParams.rgvarg.setArraySize(pDispParams.cArgs.intValue()); - } + VARIANT[] arguments = pDispParams.getArgs(); try { switch (dispIdMember.intValue()) { case DISPID_NavigateComplete2: navigateComplete2Called = true; // URL ist passed as VARIANT$ByReference - VARIANT urlByRef = pDispParams.rgvarg.variantArg[0]; + VARIANT urlByRef = arguments[0]; navigateComplete2String = ((VARIANT) urlByRef.getValue()).stringValue(); break; case DISPID_BeforeNavigate2: - VARIANT Cancel = pDispParams.rgvarg.variantArg[0]; - VARIANT Headers = pDispParams.rgvarg.variantArg[1]; - VARIANT PostData = pDispParams.rgvarg.variantArg[2]; - VARIANT TargetFrameName = pDispParams.rgvarg.variantArg[3]; - VARIANT Flags = pDispParams.rgvarg.variantArg[4]; - VARIANT URL = pDispParams.rgvarg.variantArg[5]; - VARIANT pDisp = pDispParams.rgvarg.variantArg[6]; + VARIANT Cancel = arguments[0]; + VARIANT Headers = arguments[1]; + VARIANT PostData = arguments[2]; + VARIANT TargetFrameName = arguments[3]; + VARIANT Flags = arguments[4]; + VARIANT URL = arguments[5]; + VARIANT pDisp = arguments[6]; VARIANT_BOOLByReference cancelValue = ((VARIANT_BOOLByReference) Cancel.getValue()); if (blockNavigation) { cancelValue.setValue(Variant.VARIANT_TRUE); @@ -280,11 +274,8 @@ public void testComEventCallback() throws InterruptedException { DISPPARAMS.ByReference pDispParams; pDispParams = new DISPPARAMS.ByReference(); - pDispParams.cArgs = new UINT(1); - pDispParams.cNamedArgs = new UINT(1); - pDispParams.rgvarg = new Variant.VariantArg.ByReference(new VARIANT[1]); - pDispParams.rgvarg.variantArg[0] = new VARIANT(true); - pDispParams.rgdispidNamedArgs = new DISPIDByReference(new DISPID(OaIdl.DISPID_PROPERTYPUT.intValue())); + pDispParams.setArgs(new VARIANT[] {new VARIANT(true)}); + pDispParams.setRgdispidNamedArgs(new DISPID[] {OaIdl.DISPID_PROPERTYPUT}); // Visible-Prioperty hr = ieDispatch.Invoke(dispIdVisible.getValue(), niid, lcid, propertyPutFlags, pDispParams, null, null, null); COMUtils.checkRC(hr); @@ -319,11 +310,9 @@ public void testComEventCallback() throws InterruptedException { String navigateURL = "https://github.com/java-native-access/jna"; String blockedURL = "http://www.google.de"; + VARIANT[] arguments = new VARIANT[] {new VARIANT(navigateURL)}; pDispParams = new DISPPARAMS.ByReference(); - pDispParams.cArgs = new UINT(1); - pDispParams.cNamedArgs = new UINT(0); - pDispParams.rgvarg = new Variant.VariantArg.ByReference(new VARIANT[1]); - pDispParams.rgvarg.variantArg[0] = new VARIANT(navigateURL); + pDispParams.setArgs(arguments); hr = ieDispatch.Invoke(dispIdNavigate.getValue(), niid, lcid, methodFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); COMUtils.checkRC(hr, pExcepInfo, puArgErr); @@ -343,11 +332,9 @@ public void testComEventCallback() throws InterruptedException { listener.navigateComplete2String = null; listener.blockNavigation = true; + arguments = new VARIANT[]{new VARIANT(blockedURL)}; pDispParams = new DISPPARAMS.ByReference(); - pDispParams.cArgs = new UINT(1); - pDispParams.cNamedArgs = new UINT(0); - pDispParams.rgvarg = new Variant.VariantArg.ByReference(new VARIANT[1]); - pDispParams.rgvarg.variantArg[0] = new VARIANT(blockedURL); + pDispParams.setArgs(arguments); hr = ieDispatch.Invoke(dispIdNavigate.getValue(), niid, lcid, methodFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); COMUtils.checkRC(hr, pExcepInfo, puArgErr); diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ComEventCallbacks2_Test.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ComEventCallbacks2_Test.java new file mode 100644 index 0000000000..71f934ecf3 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ComEventCallbacks2_Test.java @@ -0,0 +1,118 @@ +package com.sun.jna.platform.win32.COM.util; + +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.COM.util.annotation.ComEventCallback; +import com.sun.jna.platform.win32.COM.util.annotation.ComInterface; +import com.sun.jna.platform.win32.COM.util.annotation.ComObject; +import com.sun.jna.platform.win32.Ole32; +import com.sun.jna.platform.win32.Variant; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ComEventCallbacks2_Test { + + static { + ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true); + } + + Factory factory; + + @Before + public void before() { + Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED); + this.factory = new Factory(); + } + + @After + public void after() { + this.factory.disposeAll(); + Ole32.INSTANCE.CoUninitialize(); + } + + @Test + public void testFireCloseHandler() throws InterruptedException { + + class ApplicatonEventsHandler extends AbstractComEventCallbackListener implements ApplicationEvents4Listener { + + public volatile boolean changed = false; + public volatile boolean beforeClose = false; + public volatile boolean error = false; + + @Override + public void errorReceivingCallbackEvent(String string, Exception excptn) { + if(string.startsWith("No method found with")) { + return; // Normal case + } + System.out.println("Error: " + string); + error = true; + } + + public void DocumentChange() { + changed = true; + } + + public void DocumentBeforeClose(IDispatch Doc, Variant.VARIANT Cancel) { + beforeClose = true; + } + } + + ApplicatonEventsHandler handler = new ApplicatonEventsHandler(); + + Application appX = factory.createObject(Application.class); + + Thread.sleep(500); + + IComEventCallbackCookie cookie = appX.advise(ApplicationEvents4Listener.class, handler); + + IDispatch doc = appX.getProperty(IDispatch.class, "Documents").invokeMethod(IDispatch.class, "Add"); + + Thread.sleep(500); + + doc.getProperty(IDispatch.class, "Paragraphs") + .invokeMethod(IDispatch.class, "Item", 1) + .getProperty(IDispatch.class, "Range") + .setProperty("Text", "Test text"); + + Thread.sleep(500); + + doc.invokeMethod(Void.class, "Close", Boolean.FALSE); + + Thread.sleep(500); + + appX.unadvise(ApplicationEvents4Listener.class, cookie); + + appX.invokeMethod(Void.class, "Quit", Boolean.FALSE); + + Assert.assertTrue(handler.changed); + Assert.assertTrue(handler.beforeClose); + Assert.assertFalse(handler.error); + } + + @ComInterface(iid="{00020A01-0000-0000-C000-000000000046}") + interface ApplicationEvents4Listener { + + /** + *

+ * id(0x3)

+ */ + @ComEventCallback(dispid = 0x3) + void DocumentChange(); + + /** + *

+ * id(0x6)

+ */ + @ComEventCallback(dispid = 0x6) + void DocumentBeforeClose(IDispatch Doc, Variant.VARIANT Cancel); + } + + @ComObject(clsId = "{000209FF-0000-0000-C000-000000000046}") + public interface Application extends + IDispatch, + IConnectionPoint, + IUnknown { + + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/HybdridCOMInvocationTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/HybdridCOMInvocationTest.java index 363cb7f96b..b375a91930 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/HybdridCOMInvocationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/HybdridCOMInvocationTest.java @@ -129,12 +129,8 @@ public void testOfficeInvocationDemonstration() { WORD wFlagsCombined = new WinDef.WORD(OleAuto.DISPATCH_METHOD | OleAuto.DISPATCH_PROPERTYGET); OleAuto.DISPPARAMS.ByReference pDispParams = new OleAuto.DISPPARAMS.ByReference(); - VARIANT[] params = new VARIANT[1]; - params[0] = new VARIANT(1f); - pDispParams.cArgs = new UINT(1); - pDispParams.cNamedArgs = new UINT(0); - pDispParams.rgvarg = new Variant.VariantArg.ByReference(params); - pDispParams.rgdispidNamedArgs = new OaIdl.DISPIDByReference(); + VARIANT[] params = new VARIANT[] {new VARIANT(1f)}; + pDispParams.setArgs(params); // Call InchesToPoints as a method hr = dp.Invoke(dispId, new REFIID(Guid.IID_NULL), LOCALE_SYSTEM_DEFAULT, wFlagsMethod, pDispParams, result, pExcepInfo, puArgErr);