com.sun.jna.platform.win32.COM.util.ProxyObject Maven / Gradle / Ivy
/* Copyright (c) 2014 Dr David H. Akehurst (itemis), All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform.win32.COM.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.internal.ReflectionUtils;
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.Kernel32Util;
import com.sun.jna.platform.win32.OaIdl;
import com.sun.jna.platform.win32.OaIdl.DISPID;
import com.sun.jna.platform.win32.OaIdl.DISPIDByReference;
import com.sun.jna.platform.win32.OaIdl.EXCEPINFO;
import com.sun.jna.platform.win32.OleAuto;
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.WinDef;
import com.sun.jna.platform.win32.WinDef.DWORDByReference;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.platform.win32.COM.COMException;
import com.sun.jna.platform.win32.COM.COMUtils;
import com.sun.jna.platform.win32.COM.ConnectionPoint;
import com.sun.jna.platform.win32.COM.ConnectionPointContainer;
import com.sun.jna.platform.win32.COM.Dispatch;
import com.sun.jna.platform.win32.COM.IDispatch;
import com.sun.jna.platform.win32.COM.IDispatchCallback;
import com.sun.jna.platform.win32.COM.util.annotation.ComInterface;
import com.sun.jna.platform.win32.COM.util.annotation.ComMethod;
import com.sun.jna.platform.win32.COM.util.annotation.ComProperty;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
/**
* This object acts as the invocation handler for interfaces annotated with
* ComInterface. It wraps all (necessary) low level COM calls and dispatches
* them through the COM runtime.
*
* The caller of the methods is responsible for correct initialization of the
* COM runtime and appropriate thread-handling - depending on the choosen
* handling model.
*
* @see MSDN - Processes, Threads, and Apartments
* @see MSDN - Understanding and Using COM Threading Models
*/
public class ProxyObject implements InvocationHandler, com.sun.jna.platform.win32.COM.util.IDispatch,
IRawDispatchHandle, IConnectionPoint {
// cached value of the IUnknown interface pointer
// Rules of COM state that querying for the IUnknown interface must return
// an identical pointer value
private long unknownId;
private final Class> theInterface;
private final ObjectFactory factory;
private final com.sun.jna.platform.win32.COM.IDispatch rawDispatch;
@SuppressWarnings("LeakingThisInConstructor")
public ProxyObject(Class> theInterface, IDispatch rawDispatch, ObjectFactory factory) {
this.unknownId = -1;
this.rawDispatch = rawDispatch;
this.theInterface = theInterface;
this.factory = factory;
// make sure dispatch object knows we have a reference to it
// (for debug it is usefult to be able to see how many refs are present
int n = this.rawDispatch.AddRef();
this.getUnknownId(); // pre cache/calculate it
factory.register(this);
}
private long getUnknownId() {
assert COMUtils.comIsInitialized() : "COM not initialized";
if (-1 == this.unknownId) {
try {
final PointerByReference ppvObject = new PointerByReference();
Thread current = Thread.currentThread();
String tn = current.getName();
IID iid = com.sun.jna.platform.win32.COM.IUnknown.IID_IUNKNOWN;
HRESULT hr = ProxyObject.this.getRawDispatch().QueryInterface(new REFIID(iid), ppvObject);
if (WinNT.S_OK.equals(hr)) {
Dispatch dispatch = new Dispatch(ppvObject.getValue());
this.unknownId = Pointer.nativeValue(dispatch.getPointer());
// QueryInterface returns a COM object pointer with a +1
// reference, we must drop one,
// Note: createProxy adds one;
int n = dispatch.Release();
} else {
String formatMessageFromHR = Kernel32Util.formatMessage(hr);
throw new COMException("getUnknownId: " + formatMessageFromHR, hr);
}
} catch (RuntimeException e) {
// Do not rewrap COMException
if (e instanceof COMException) {
throw e;
} else {
throw new COMException("Error occured when trying get Unknown Id ", e);
}
}
}
return this.unknownId;
}
@Override
protected void finalize() throws Throwable {
this.dispose();
super.finalize();
}
public synchronized void dispose() {
if (((Dispatch) this.rawDispatch).getPointer() != Pointer.NULL) {
this.rawDispatch.Release();
((Dispatch) this.rawDispatch).setPointer(Pointer.NULL);
factory.unregister(this);
}
}
@Override
public com.sun.jna.platform.win32.COM.IDispatch getRawDispatch() {
return this.rawDispatch;
}
// -------------------- Object -------------------------
/*
* The QueryInterface rule state that 'a call to QueryInterface with
* IID_IUnknown must always return the same physical pointer value.'
*
* [http://msdn.microsoft.com/en-us/library/ms686590%28VS.85%29.aspx]
*
* therefore we can compare the pointers
*/
@Override
public boolean equals(Object arg) {
if (null == arg) {
return false;
} else if (arg instanceof ProxyObject) {
ProxyObject other = (ProxyObject) arg;
return this.getUnknownId() == other.getUnknownId();
} else if (Proxy.isProxyClass(arg.getClass())) {
InvocationHandler handler = Proxy.getInvocationHandler(arg);
if (handler instanceof ProxyObject) {
try {
ProxyObject other = (ProxyObject) handler;
return this.getUnknownId() == other.getUnknownId();
} catch (Exception e) {
// if can't do this comparison, return false
// (queryInterface may throw if COM objects become invalid)
return false;
}
} else {
return false;
}
} else {
return false;
}
}
@Override
public int hashCode() {
long id = this.getUnknownId();
return (int) ((id >>> 32) & 0xFFFFFFFF) + (int) (id & 0xFFFFFFFF);
}
@Override
public String toString() {
return this.theInterface.getName() + "{unk=" + this.hashCode() + "}";
}
// --------------------- InvocationHandler -----------------------------
@Override
public Object invoke(final Object proxy, final java.lang.reflect.Method method, final Object[] args)
throws Throwable {
boolean declaredAsInterface
= (method.getAnnotation(ComMethod.class) != null)
|| (method.getAnnotation(ComProperty.class) != null);
if ((!declaredAsInterface) && (method.getDeclaringClass().equals(Object.class)
|| method.getDeclaringClass().equals(IRawDispatchHandle.class)
|| method.getDeclaringClass().equals(com.sun.jna.platform.win32.COM.util.IUnknown.class)
|| method.getDeclaringClass().equals(com.sun.jna.platform.win32.COM.util.IDispatch.class)
|| method.getDeclaringClass().equals(IConnectionPoint.class))) {
try {
return method.invoke(this, args);
} catch (InvocationTargetException ex) {
throw ex.getCause();
}
}
if((!declaredAsInterface) && ReflectionUtils.isDefault(method)) {
Object methodHandle = ReflectionUtils.getMethodHandle(method);
return ReflectionUtils.invokeDefaultMethod(proxy, methodHandle, args);
}
Class> returnType = method.getReturnType();
boolean isVoid = Void.TYPE.equals(returnType);
ComProperty prop = method.getAnnotation(ComProperty.class);
if (null != prop) {
int dispId = prop.dispId();
Object[] fullLengthArgs = unfoldWhenVarargs(method, args);
if (isVoid) {
if (dispId != -1) {
this.setProperty(new DISPID(dispId), fullLengthArgs);
return null;
} else {
String propName = this.getMutatorName(method, prop);
this.setProperty(propName, fullLengthArgs);
return null;
}
} else {
if (dispId != -1) {
return this.getProperty(returnType, new DISPID(dispId), args);
} else {
String propName = this.getAccessorName(method, prop);
return this.getProperty(returnType, propName, args);
}
}
}
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), fullLengthArgs);
} else {
String methName = this.getMethodName(method, meth);
return this.invokeMethod(returnType, methName, fullLengthArgs);
}
}
return null;
}
// ---------------------- IConnectionPoint ----------------------
private ConnectionPoint fetchRawConnectionPoint(IID iid) {
assert COMUtils.comIsInitialized() : "COM not initialized";
// query for ConnectionPointContainer
IConnectionPointContainer cpc = this.queryInterface(IConnectionPointContainer.class);
Dispatch rawCpcDispatch = (Dispatch) cpc.getRawDispatch();
final ConnectionPointContainer rawCpc = new ConnectionPointContainer(rawCpcDispatch.getPointer());
// find connection point for comEventCallback interface
final REFIID adviseRiid = new REFIID(iid.getPointer());
final PointerByReference ppCp = new PointerByReference();
HRESULT hr = rawCpc.FindConnectionPoint(adviseRiid, ppCp);
COMUtils.checkRC(hr);
final ConnectionPoint rawCp = new ConnectionPoint(ppCp.getValue());
return rawCp;
}
@Override
public IComEventCallbackCookie advise(Class> comEventCallbackInterface,
final IComEventCallbackListener comEventCallbackListener)
throws COMException {
assert COMUtils.comIsInitialized() : "COM not initialized";
try {
ComInterface comInterfaceAnnotation = comEventCallbackInterface.getAnnotation(ComInterface.class);
if (null == comInterfaceAnnotation) {
throw new COMException(
"advise: Interface must define a value for either iid via the ComInterface annotation");
}
final IID iid = this.getIID(comInterfaceAnnotation);
final ConnectionPoint rawCp = this.fetchRawConnectionPoint(iid);
// create the dispatch listener
final IDispatchCallback rawListener = factory.createDispatchCallback(comEventCallbackInterface, comEventCallbackListener);
// store it the comEventCallback argument, so it is not garbage
// collected.
comEventCallbackListener.setDispatchCallbackListener(rawListener);
// set the dispatch listener to listen to events from the connection
// point
final DWORDByReference pdwCookie = new DWORDByReference();
HRESULT hr = rawCp.Advise(rawListener, pdwCookie);
int n = rawCp.Release(); // release before check in case check
// throws exception
COMUtils.checkRC(hr);
// return the cookie so that a call to stop listening can be made
return new ComEventCallbackCookie(pdwCookie.getValue());
} catch (RuntimeException e) {
// Do not rewrap COMException
if (e instanceof COMException) {
throw e;
} else {
throw new COMException("Error occured in advise when trying to connect the listener " + comEventCallbackListener, e);
}
}
}
@Override
public void unadvise(Class> comEventCallbackInterface, final IComEventCallbackCookie cookie) throws COMException {
assert COMUtils.comIsInitialized() : "COM not initialized";
try {
ComInterface comInterfaceAnnotation = comEventCallbackInterface.getAnnotation(ComInterface.class);
if (null == comInterfaceAnnotation) {
throw new COMException(
"unadvise: Interface must define a value for iid via the ComInterface annotation");
}
IID iid = this.getIID(comInterfaceAnnotation);
final ConnectionPoint rawCp = this.fetchRawConnectionPoint(iid);
HRESULT hr = rawCp.Unadvise(((ComEventCallbackCookie) cookie).getValue());
rawCp.Release();
COMUtils.checkRC(hr);
} catch (RuntimeException e) {
// Do not rewrap COMException
if (e instanceof COMException) {
throw e;
} else {
throw new COMException("Error occured in unadvise when trying to disconnect the listener from " + this, e);
}
}
}
// --------------------- IDispatch ------------------------------
@Override
public void setProperty(String name, T value) {
DISPID dispID = resolveDispId(this.getRawDispatch(), name);
setProperty(dispID, value);
}
@Override
public void setProperty(DISPID dispId, T value) {
assert COMUtils.comIsInitialized() : "COM not initialized";
VARIANT v = Convert.toVariant(value);
WinNT.HRESULT hr = this.oleMethod(OleAuto.DISPATCH_PROPERTYPUT, null, this.getRawDispatch(), dispId, v);
Convert.free(v, value); // Free value allocated by Convert#toVariant
COMUtils.checkRC(hr);
}
private void setProperty(String name, Object... args) {
assert COMUtils.comIsInitialized() : "COM not initialized";
DISPID dispID = resolveDispId(this.getRawDispatch(), name);
setProperty(dispID, args);
}
private void setProperty(DISPID dispID, Object... args) {
assert COMUtils.comIsInitialized() : "COM not initialized";
VARIANT[] vargs;
if (null == args) {
vargs = new VARIANT[0];
} else {
vargs = new VARIANT[args.length];
}
for (int i = 0; i < vargs.length; ++i) {
vargs[i] = Convert.toVariant(args[i]);
}
WinNT.HRESULT hr = this.oleMethod(OleAuto.DISPATCH_PROPERTYPUT, null, this.getRawDispatch(), dispID, vargs);
for (int i = 0; i < vargs.length; i++) {
// Free value allocated by Convert#toVariant
Convert.free(vargs[i], args[i]);
}
COMUtils.checkRC(hr);
}
@Override
public T getProperty(Class returnType, String name, Object... args) {
DISPID dispID = resolveDispId(this.getRawDispatch(), name);
return getProperty(returnType, dispID, args);
}
@Override
public T getProperty(Class returnType, DISPID dispID, Object... args) {
VARIANT[] vargs;
if (null == args) {
vargs = new VARIANT[0];
} else {
vargs = new VARIANT[args.length];
}
for (int i = 0; i < vargs.length; ++i) {
vargs[i] = Convert.toVariant(args[i]);
}
Variant.VARIANT.ByReference result = new Variant.VARIANT.ByReference();
WinNT.HRESULT hr = this.oleMethod(OleAuto.DISPATCH_PROPERTYGET, result, this.getRawDispatch(), dispID, vargs);
for (int i = 0; i < vargs.length; i++) {
// Free value allocated by Convert#toVariant
Convert.free(vargs[i], args[i]);
}
COMUtils.checkRC(hr);
return (T) Convert.toJavaObject(result, returnType, factory, false, true);
}
@Override
public T invokeMethod(Class returnType, String name, Object... args) {
DISPID dispID = resolveDispId(this.getRawDispatch(), name);
return invokeMethod(returnType, dispID, args);
}
@Override
public T invokeMethod(Class returnType, DISPID dispID, Object... args) {
assert COMUtils.comIsInitialized() : "COM not initialized";
VARIANT[] vargs;
if (null == args) {
vargs = new VARIANT[0];
} else {
vargs = new VARIANT[args.length];
}
for (int i = 0; i < vargs.length; ++i) {
vargs[i] = Convert.toVariant(args[i]);
}
Variant.VARIANT.ByReference result = new Variant.VARIANT.ByReference();
WinNT.HRESULT hr = this.oleMethod(OleAuto.DISPATCH_METHOD, result, this.getRawDispatch(), dispID, vargs);
for (int i = 0; i < vargs.length; i++) {
// Free value allocated by Convert#toVariant
Convert.free(vargs[i], args[i]);
}
COMUtils.checkRC(hr);
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";
try {
ComInterface comInterfaceAnnotation = comInterface.getAnnotation(ComInterface.class);
if (null == comInterfaceAnnotation) {
throw new COMException(
"queryInterface: Interface must define a value for iid via the ComInterface annotation");
}
final IID iid = this.getIID(comInterfaceAnnotation);
final PointerByReference ppvObject = new PointerByReference();
HRESULT hr = ProxyObject.this.getRawDispatch().QueryInterface(new REFIID(iid), ppvObject);
if (WinNT.S_OK.equals(hr)) {
Dispatch dispatch = new Dispatch(ppvObject.getValue());
T t = this.factory.createProxy(comInterface, dispatch);
// QueryInterface returns a COM object pointer with a +1
// reference, we must drop one,
// Note: createProxy adds one;
int n = dispatch.Release();
return t;
} else {
String formatMessageFromHR = Kernel32Util.formatMessage(hr);
throw new COMException("queryInterface: " + formatMessageFromHR, hr);
}
} catch (RuntimeException e) {
// Do not rewrap COMException
if (e instanceof COMException) {
throw e;
} else {
throw new COMException("Error occured when trying to query for interface " + comInterface.getName(), e);
}
}
}
private IID getIID(ComInterface annotation) {
String iidStr = annotation.iid();
if (null != iidStr && !iidStr.isEmpty()) {
return new IID(iidStr);
} else {
throw new COMException("ComInterface must define a value for iid");
}
}
// --------------------- ProxyObject ---------------------
private String getAccessorName(java.lang.reflect.Method method, ComProperty prop) {
if (prop.name().isEmpty()) {
String methName = method.getName();
if (methName.startsWith("get")) {
return methName.replaceFirst("get", "");
} else {
throw new RuntimeException(
"Property Accessor name must start with 'get', or set the anotation 'name' value");
}
} else {
return prop.name();
}
}
private String getMutatorName(java.lang.reflect.Method method, ComProperty prop) {
if (prop.name().isEmpty()) {
String methName = method.getName();
if (methName.startsWith("set")) {
return methName.replaceFirst("set", "");
} else {
throw new RuntimeException(
"Property Mutator name must start with 'set', or set the anotation 'name' value");
}
} else {
return prop.name();
}
}
private String getMethodName(java.lang.reflect.Method method, ComMethod meth) {
if (meth.name().isEmpty()) {
String methName = method.getName();
return methName;
} else {
return meth.name();
}
}
@SuppressWarnings("deprecation")
protected DISPID resolveDispId(String name) {
return resolveDispId(getRawDispatch(), name);
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, String name, VARIANT pArg)
throws COMException {
return this.oleMethod(nType, pvResult, name, new VARIANT[] { pArg });
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, DISPID dispId, VARIANT pArg)
throws COMException {
return this.oleMethod(nType, pvResult, dispId, new VARIANT[] { pArg });
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, String name)
throws COMException {
return this.oleMethod(nType, pvResult, name, (VARIANT[]) null);
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, DISPID dispId)
throws COMException {
return this.oleMethod(nType, pvResult, dispId, (VARIANT[]) null);
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, String name,
VARIANT[] pArgs) throws COMException {
return this.oleMethod(nType, pvResult, resolveDispId(name), pArgs);
}
@SuppressWarnings("deprecation")
protected HRESULT oleMethod(final int nType, final VARIANT.ByReference pvResult,
final DISPID dispId, VARIANT[] pArgs) throws COMException {
return oleMethod(nType, pvResult, getRawDispatch(), dispId, pArgs);
}
@Deprecated
protected DISPID resolveDispId(final IDispatch pDisp, String name) {
assert COMUtils.comIsInitialized() : "COM not initialized";
if (pDisp == null) {
throw new COMException("pDisp (IDispatch) parameter is null!");
}
final WString[] ptName = new WString[]{new WString(name)};
final DISPIDByReference pdispID = new DISPIDByReference();
HRESULT hr = pDisp.GetIDsOfNames(
new REFIID(Guid.IID_NULL),
ptName,
1,
factory.getLCID(),
pdispID);
COMUtils.checkRC(hr);
return pdispID.getValue();
}
@Deprecated
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, IDispatch pDisp, String name, VARIANT pArg)
throws COMException {
return this.oleMethod(nType, pvResult, pDisp, name, new VARIANT[]{pArg});
}
@Deprecated
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, IDispatch pDisp, DISPID dispId, VARIANT pArg)
throws COMException {
return this.oleMethod(nType, pvResult, pDisp, dispId, new VARIANT[]{pArg});
}
@Deprecated
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, IDispatch pDisp, String name)
throws COMException {
return this.oleMethod(nType, pvResult, pDisp, name, (VARIANT[]) null);
}
@Deprecated
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, IDispatch pDisp, DISPID dispId)
throws COMException {
return this.oleMethod(nType, pvResult, pDisp, dispId, (VARIANT[]) null);
}
@Deprecated
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult, final IDispatch pDisp, String name,
VARIANT[] pArgs) throws COMException {
return this.oleMethod(nType, pvResult, pDisp, resolveDispId(pDisp, name), pArgs);
}
@Deprecated
protected HRESULT oleMethod(final int nType, final VARIANT.ByReference pvResult, final IDispatch pDisp,
final DISPID dispId, VARIANT[] pArgs) throws COMException {
assert COMUtils.comIsInitialized() : "COM not initialized";
if (pDisp == null) {
throw new COMException("pDisp (IDispatch) parameter is null!");
}
// variable declaration
int _argsLen = 0;
VARIANT[] _args = null;
final DISPPARAMS.ByReference dp = new DISPPARAMS.ByReference();
final EXCEPINFO.ByReference pExcepInfo = new EXCEPINFO.ByReference();
final IntByReference puArgErr = new IntByReference();
// make parameter reverse ordering as expected by COM runtime
if ((pArgs != null) && (pArgs.length > 0)) {
_argsLen = pArgs.length;
_args = new VARIANT[_argsLen];
int revCount = _argsLen;
for (int i = 0; i < _argsLen; i++) {
_args[i] = pArgs[--revCount];
}
}
// Handle special-case for property-puts!
if (nType == OleAuto.DISPATCH_PROPERTYPUT) {
dp.setRgdispidNamedArgs(new DISPID[]{OaIdl.DISPID_PROPERTYPUT});
}
// Apply "fix" according to
// https://www.delphitools.info/2013/04/30/gaining-visual-basic-ole-super-powers/
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms221486(v=vs.85).aspx
//
// Summary: there are methods in the word typelibrary that require both
// PROPERTYGET _and_ METHOD to be set. With only one of these set the call
// fails.
//
// The article from delphitools argues, that automation compatible libraries
// need to be compatible with VisualBasic which does not distingish methods
// and property getters and will set both flags always.
//
// The MSDN article advises this behaviour: "[...] Some languages cannot
// distinguish between retrieving a property and calling a method. In this
//case, you should set the flags DISPATCH_PROPERTYGET and DISPATCH_METHOD.
// [...]"))
//
// This was found when trying to bind InchesToPoints from the _Application
// dispatch interface of the MS Word 15 type library
//
// The signature according the ITypeLib Viewer (OLE/COM Object Viewer):
// [id(0x00000172), helpcontext(0x09700172)]
// single InchesToPoints([in] single Inches);
final int finalNType;
if (nType == OleAuto.DISPATCH_METHOD || nType == OleAuto.DISPATCH_PROPERTYGET) {
finalNType = OleAuto.DISPATCH_METHOD | OleAuto.DISPATCH_PROPERTYGET;
} else {
finalNType = nType;
}
// Build DISPPARAMS
if (_argsLen > 0) {
dp.setArgs(_args);
// write 'DISPPARAMS' structure to memory
dp.write();
}
HRESULT hr = pDisp.Invoke(
dispId,
new REFIID(Guid.IID_NULL),
factory.getLCID(),
new WinDef.WORD(finalNType),
dp,
pvResult,
pExcepInfo,
puArgErr);
COMUtils.checkRC(hr, pExcepInfo, puArgErr);
return hr;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy