From 89d16792ae461b170e6c1761a1760d8de04015ff Mon Sep 17 00:00:00 2001 From: Bram Veenboer Date: Wed, 9 Feb 2011 08:23:47 +0000 Subject: [PATCH] --- java/.classpath | 1 + java/src/com/jacob/com/ComException.java | 141 ++ java/src/com/jacob/com/ComFailException.java | 88 + java/src/com/jacob/com/ComThread.java | 169 ++ java/src/com/jacob/com/Currency.java | 91 + java/src/com/jacob/com/DateUtilities.java | 105 + java/src/com/jacob/com/Dispatch.java | 872 +++++++ java/src/com/jacob/com/DispatchEvents.java | 219 ++ .../src/com/jacob/com/DispatchIdentifier.java | 82 + java/src/com/jacob/com/DispatchProxy.java | 92 + java/src/com/jacob/com/EnumVariant.java | 156 ++ java/src/com/jacob/com/InvocationProxy.java | 108 + .../jacob/com/InvocationProxyAllVariants.java | 123 + java/src/com/jacob/com/JacobException.java | 49 + java/src/com/jacob/com/JacobObject.java | 110 + java/src/com/jacob/com/JacobReleaseInfo.java | 96 + java/src/com/jacob/com/LibraryLoader.java | 230 ++ java/src/com/jacob/com/MainSTA.java | 29 + .../jacob/com/NotImplementedException.java | 41 + java/src/com/jacob/com/ROT.java | 279 ++ java/src/com/jacob/com/STA.java | 101 + java/src/com/jacob/com/SafeArray.java | 1172 +++++++++ java/src/com/jacob/com/Variant.java | 2235 +++++++++++++++++ java/src/com/jacob/com/VariantUtilities.java | 502 ++++ java/src/com/jacob/com/VariantViaEvent.java | 34 + .../com/jacob/com/WrongThreadException.java | 47 + java/src/pm/Main.java | 9 +- .../{iTunes.java => iTunesApplicatie.java} | 6 +- .../pm/device/javainput/JavaInputDevice.java | 12 +- .../javainput/extreme3d/Extreme3DDevice.java | 13 + .../javainput/rumblepad/RumblepadDevice.java | 25 +- .../jintellitype/JIntellitypeDevice.java | 5 +- java/src/pm/macro/Event.java | 2 +- 33 files changed, 7223 insertions(+), 21 deletions(-) create mode 100644 java/src/com/jacob/com/ComException.java create mode 100644 java/src/com/jacob/com/ComFailException.java create mode 100644 java/src/com/jacob/com/ComThread.java create mode 100644 java/src/com/jacob/com/Currency.java create mode 100644 java/src/com/jacob/com/DateUtilities.java create mode 100644 java/src/com/jacob/com/Dispatch.java create mode 100644 java/src/com/jacob/com/DispatchEvents.java create mode 100644 java/src/com/jacob/com/DispatchIdentifier.java create mode 100644 java/src/com/jacob/com/DispatchProxy.java create mode 100644 java/src/com/jacob/com/EnumVariant.java create mode 100644 java/src/com/jacob/com/InvocationProxy.java create mode 100644 java/src/com/jacob/com/InvocationProxyAllVariants.java create mode 100644 java/src/com/jacob/com/JacobException.java create mode 100644 java/src/com/jacob/com/JacobObject.java create mode 100644 java/src/com/jacob/com/JacobReleaseInfo.java create mode 100644 java/src/com/jacob/com/LibraryLoader.java create mode 100644 java/src/com/jacob/com/MainSTA.java create mode 100644 java/src/com/jacob/com/NotImplementedException.java create mode 100644 java/src/com/jacob/com/ROT.java create mode 100644 java/src/com/jacob/com/STA.java create mode 100644 java/src/com/jacob/com/SafeArray.java create mode 100644 java/src/com/jacob/com/Variant.java create mode 100644 java/src/com/jacob/com/VariantUtilities.java create mode 100644 java/src/com/jacob/com/VariantViaEvent.java create mode 100644 java/src/com/jacob/com/WrongThreadException.java rename java/src/pm/application/iTunes/{iTunes.java => iTunesApplicatie.java} (86%) diff --git a/java/.classpath b/java/.classpath index 70d3166..e4b5e09 100644 --- a/java/.classpath +++ b/java/.classpath @@ -7,5 +7,6 @@ + diff --git a/java/src/com/jacob/com/ComException.java b/java/src/com/jacob/com/ComException.java new file mode 100644 index 0000000..5daad70 --- /dev/null +++ b/java/src/com/jacob/com/ComException.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * Standard exception thrown by com jni code when there is a problem + */ +public abstract class ComException extends JacobException { + + /** + * COM code initializes this filed with an appropriate return code that was + * returned by the underlying com code + */ + protected int hr; + /** + * No documentation is available at this time. Someone should document this + * field + */ + protected int m_helpContext; + /** + * No documentation is available at this time. Someone should document this + * field + */ + protected String m_helpFile; + /** + * No documentation is available at this time. Someone should document this + * field + */ + protected String m_source; + + /** + * constructor + * + */ + public ComException() { + super(); + } + + /** + * constructor with error code? + * + * @param newHr ?? + */ + public ComException(int newHr) { + super(); + this.hr = newHr; + } + + /** + * @param newHr + * @param description + */ + public ComException(int newHr, String description) { + super(description); + this.hr = newHr; + } + + /** + * @param newHr + * @param source + * @param helpFile + * @param helpContext + */ + public ComException(int newHr, String source, String helpFile, + int helpContext) { + super(); + this.hr = newHr; + m_source = source; + m_helpFile = helpFile; + m_helpContext = helpContext; + } + + /** + * @param newHr + * @param description + * @param source + * @param helpFile + * @param helpContext + */ + public ComException(int newHr, String description, String source, + String helpFile, int helpContext) { + super(description); + this.hr = newHr; + m_source = source; + m_helpFile = helpFile; + m_helpContext = helpContext; + } + + /** + * @param description + */ + public ComException(String description) { + super(description); + } + + /** + * @return int representation of the help context + */ + // Methods + public int getHelpContext() { + return m_helpContext; + } + + /** + * @return String ??? help file + */ + public String getHelpFile() { + return m_helpFile; + } + + /** + * @return int hr result ?? + */ + public int getHResult() { + return hr; + } + + /** + * @return String source ?? + */ + public String getSource() { + return m_source; + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/ComFailException.java b/java/src/com/jacob/com/ComFailException.java new file mode 100644 index 0000000..a2a8aff --- /dev/null +++ b/java/src/com/jacob/com/ComFailException.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * COM Fail Exception class raised when there is a problem + */ +public class ComFailException extends ComException { + /** + * eclipse generated to get rid of a wanring + */ + private static final long serialVersionUID = -266047261992987700L; + + /** + * Constructor + * + * @param hrNew + */ + public ComFailException(int hrNew) { + super(hrNew); + } + + /** + * Constructor + * + * @param hrNew + * @param message + */ + public ComFailException(int hrNew, String message) { + super(hrNew, message); + } + + /** + * @param hrNew + * @param source + * @param helpFile + * @param helpContext + */ + public ComFailException(int hrNew, String source, String helpFile, + int helpContext) { + super(hrNew, source, helpFile, helpContext); + } + + /** + * Constructor + * + * @param hrNew + * @param description + * @param source + * @param helpFile + * @param helpContext + */ + public ComFailException(int hrNew, String description, String source, + String helpFile, int helpContext) { + super(hrNew, description, source, helpFile, helpContext); + } + + /** + * No argument Constructor + */ + public ComFailException() { + super(); + } + + /** + * @param message + */ + public ComFailException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/ComThread.java b/java/src/com/jacob/com/ComThread.java new file mode 100644 index 0000000..096a62a --- /dev/null +++ b/java/src/com/jacob/com/ComThread.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * Represents a COM level thread This is an abstract class because all the + * methods are static and no instances are ever created. + */ +public abstract class ComThread { + private static final int MTA = 0x0; + + private static final int STA = 0x2; + + /** + * Comment for haveSTA + */ + public static boolean haveSTA = false; + + /** + * Comment for mainSTA + */ + public static MainSTA mainSTA = null; + + /** + * Initialize the current java thread to be part of the Multi-threaded COM + * Apartment + */ + public static synchronized void InitMTA() { + InitMTA(false); + } + + /** + * Initialize the current java thread to be an STA + */ + public static synchronized void InitSTA() { + InitSTA(false); + } + + /** + * Initialize the current java thread to be part of the Multi-threaded COM + * Apartment, if createMainSTA is true, create a separate MainSTA thread + * that will house all Apartment Threaded components + * + * @param createMainSTA + */ + public static synchronized void InitMTA(boolean createMainSTA) { + Init(createMainSTA, MTA); + } + + /** + * Initialize the current java thread to be an STA COM Apartment, if + * createMainSTA is true, create a separate MainSTA thread that will house + * all Apartment Threaded components + * + * @param createMainSTA + */ + public static synchronized void InitSTA(boolean createMainSTA) { + Init(createMainSTA, STA); + } + + /** + * + */ + public static synchronized void startMainSTA() { + mainSTA = new MainSTA(); + haveSTA = true; + } + + /** + * + */ + public static synchronized void quitMainSTA() { + if (mainSTA != null) + mainSTA.quit(); + } + + /** + * Initialize the current java thread to be part of the MTA/STA COM + * Apartment + * + * @param createMainSTA + * @param mode + */ + public static synchronized void Init(boolean createMainSTA, int mode) { + if (createMainSTA && !haveSTA) { + // if the current thread is going to be in the MTA and there + // is no STA thread yet, then create a main STA thread + // to avoid COM creating its own + startMainSTA(); + } + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: before Init: " + mode); + } + doCoInitialize(mode); + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: after Init: " + mode); + } + ROT.addThread(); + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: after ROT.addThread: " + mode); + } + } + + /** + * Call CoUninitialize to release this java thread from COM + */ + public static synchronized void Release() { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: before clearObjects"); + } + ROT.clearObjects(); + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: before UnInit"); + } + doCoUninitialize(); + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ComThread: after UnInit"); + } + } + + /** + * @deprecated the java model leave the responsibility of clearing up + * objects to the Garbage Collector. Our programming model + * should not require that the user specifically remove object + * from the thread. + * + * This will remove an object from the ROT + * @param o + */ + @Deprecated + public static synchronized void RemoveObject(JacobObject o) { + ROT.removeObject(o); + } + + /** + * @param threadModel + */ + public static native void doCoInitialize(int threadModel); + + /** + * + */ + public static native void doCoUninitialize(); + + /** + * load the Jacob DLL. We do this in case COMThread is called before any + * other reference to one of the JacboObject subclasses is made. + */ + static { + LibraryLoader.loadJacobLibrary(); + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/Currency.java b/java/src/com/jacob/com/Currency.java new file mode 100644 index 0000000..d7aeef4 --- /dev/null +++ b/java/src/com/jacob/com/Currency.java @@ -0,0 +1,91 @@ +package com.jacob.com; + +/** + * Most COM bridges use java.lang.Long as their Java data type for COM Currency + * data. This is because COM currency is a 64 bit number where the last 4 digits + * represent the milli-cents. We wanted to support 64 bit Long values for x64 + * platforms so that meant we wanted to map Java.LONG to COM.LONG even though it + * only works for 64 bit platforms. The end result was we needed a new + * representation for Money so we have this. + *

+ * In the future, this should convert to and from BigDecimal or Double + */ +public class Currency { + Long embeddedValue = null; + + /** + * constructor that takes a long already in COM representation + * + * @param newValue + */ + public Currency(long newValue) { + embeddedValue = new Long(newValue); + } + + /** + * constructor that takes a String already in COM representation + * + * @param newValue + */ + public Currency(String newValue) { + embeddedValue = new Long(newValue); + } + + /** + * + * @return the currency as a primitive long + */ + public long longValue() { + return embeddedValue.longValue(); + } + + /** + * getter to the inner storage so that cmpareTo can work + * + * @return the embedded long value + */ + protected Long getLongValue() { + return embeddedValue; + } + + /** + * compares the values of two currencies + * + * @param anotherCurrency + * @return the usual compareTo results + */ + public int compareTo(Currency anotherCurrency) { + return embeddedValue.compareTo(anotherCurrency.getLongValue()); + } + + /** + * standard comparison + * + * @param o + * must be Currency or Long + * @return the usual compareTo results + */ + public int compareTo(Object o) { + if (o instanceof Currency) { + return compareTo((Currency) o); + } else if (o instanceof Long) { + return embeddedValue.compareTo((Long) o); + } else + throw new IllegalArgumentException( + "Can only compare to Long and Currency not " + + o.getClass().getName()); + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object o) { + if (o == null) { + return false; + } else if (compareTo(o) == 0) { + return true; + } else { + return false; + } + } +} diff --git a/java/src/com/jacob/com/DateUtilities.java b/java/src/com/jacob/com/DateUtilities.java new file mode 100644 index 0000000..5f8bf5e --- /dev/null +++ b/java/src/com/jacob/com/DateUtilities.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +import java.util.Calendar; +import java.util.Date; + +/** + * java / windows date conversion utilities + * + * @author joe + * + */ +public class DateUtilities { + + /** + * converts a windows time to a Java Date Object + * + * @param comTime + * @return Date object representing the windows time as specified in comTime + */ + static public Date convertWindowsTimeToDate(double comTime) { + return new Date(convertWindowsTimeToMilliseconds(comTime)); + } + + /** + * Convert a COM time from functions Date(), Time(), Now() to a Java time + * (milliseconds). Visual Basic time values are based to 30.12.1899, Java + * time values are based to 1.1.1970 (= 0 milliseconds). The difference is + * added to the Visual Basic value to get the corresponding Java value. The + * Visual Basic double value reads: .<1 + * day percentage fraction>, e.g. "38100.6453" means: 38100 days since + * 30.12.1899 plus (24 hours * 0.6453). Example usage: + * Date javaDate = new Date(toMilliseconds (vbDate));. + * + * @param comTime + * COM time. + * @return Java time. + */ + static public long convertWindowsTimeToMilliseconds(double comTime) { + long result = 0; + + // code from jacobgen: + comTime = comTime - 25569D; + Calendar cal = Calendar.getInstance(); + result = Math.round(86400000L * comTime) + - cal.get(Calendar.ZONE_OFFSET); + cal.setTime(new Date(result)); + result -= cal.get(Calendar.DST_OFFSET); + + return result; + }// convertWindowsTimeToMilliseconds() + + /** + * converts a java date to a windows time object (is this timezone safe?) + * + * @param javaDate + * the java date to be converted to windows time + * @return the double representing the date in a form windows understands + */ + static public double convertDateToWindowsTime(Date javaDate) { + if (javaDate == null) { + throw new IllegalArgumentException( + "cannot convert null to windows time"); + } + return convertMillisecondsToWindowsTime(javaDate.getTime()); + } + + /** + * Convert a Java time to a COM time. + * + * @param milliseconds + * Java time. + * @return COM time. + */ + static public double convertMillisecondsToWindowsTime(long milliseconds) { + double result = 0.0; + + // code from jacobgen: + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(milliseconds); + milliseconds += (cal.get(Calendar.ZONE_OFFSET) + cal + .get(Calendar.DST_OFFSET)); // add GMT offset + result = (milliseconds / 86400000D) + 25569D; + + return result; + }// convertMillisecondsToWindowsTime() +} diff --git a/java/src/com/jacob/com/Dispatch.java b/java/src/com/jacob/com/Dispatch.java new file mode 100644 index 0000000..861d6e4 --- /dev/null +++ b/java/src/com/jacob/com/Dispatch.java @@ -0,0 +1,872 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. All rights reserved. Originator: Dan Adler + * (http://danadler.com). Get more information about JACOB at + * http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +package com.jacob.com; + +/** + * Object represents MS level dispatch object. Each instance of this points at + * some data structure on the MS windows side. + * + * + *

+ * You're going to live here a lot + */ +public class Dispatch extends JacobObject { + + /** + * Used to set the locale in a call. The user locale is another option + */ + public static final int LOCALE_SYSTEM_DEFAULT = 2048; + /** used by callN() and callSubN() */ + public static final int Method = 1; + /** used by callN() and callSubN() */ + public static final int Get = 2; + /** used by put() */ + public static final int Put = 4; + /** not used, probably intended for putRef() */ + public static final int PutRef = 8; + /** + * One of legal values for GetDispId. Not used in this layer and probably + * not needed. + */ + public static final int fdexNameCaseSensitive = 1; + + /** + * This is public because Dispatch.cpp knows its name and accesses it + * directly to get the dispatch id. You really can't rename it or make it + * private + */ + public int m_pDispatch; + + /** program Id passed in by ActiveX components in their constructor */ + private String programId = null; + + private static int NOT_ATTACHED = 0; + + /** + * Dummy empty array used one doesn't have to be created on every invocation + */ + private final static Object[] NO_OBJECT_ARGS = new Object[0]; + /** + * Dummy empty array used one doesn't have to be created on every invocation + */ + private final static Variant[] NO_VARIANT_ARGS = new Variant[0]; + /** + * Dummy empty array used one doesn't have to be created on every invocation + */ + private final static int[] NO_INT_ARGS = new int[0]; + + /** + * zero argument constructor that sets the dispatch pointer to 0 This is the + * only way to create a Dispatch without a value in the pointer field. + */ + public Dispatch() { + m_pDispatch = NOT_ATTACHED; + } + + /** + * This constructor calls createInstance with progid. This is the + * constructor used by the ActiveXComponent or by programs that don't like + * the activeX interface but wish to create new connections to windows + * programs. + *

+ * This constructor always creates a new windows/program object because it + * is based on the CoCreate() windows function. + *

+ * + * @param requestedProgramId + * @throws IllegalArgumentException + * if null is passed in as the program id + *

+ */ + public Dispatch(String requestedProgramId) { + programId = requestedProgramId; + if (programId != null && !"".equals(programId)) { + createInstanceNative(requestedProgramId); + } else { + throw new IllegalArgumentException( + "Dispatch(String) does not accept null or an empty string as a parameter"); + } + } + + /** + * native call createInstance only used by the constructor with the same + * parm type. This probably should be private. It is the wrapper for the + * Windows CoCreate() call + *

+ * This ends up calling CoCreate down in the JNI layer + *

+ * The behavior is different if a ":" character exists in the progId. In + * that case CoGetObject and CreateInstance (someone needs to describe this + * better) + * + * @param progid + */ + private native void createInstanceNative(String progid); + + /** + * native call getActiveInstance only used by the constructor with the same + * parm type. This probably should be private. It is the wrapper for the + * Windows GetActiveObject() call + *

+ * This ends up calling GetActiveObject down in the JNI layer + *

+ * This does not have the special behavior for program ids with ":" in them + * that createInstance has. + * + * @param progid + */ + private native void getActiveInstanceNative(String progid); + + /** + * Wrapper around the native method + * + * @param pProgramIdentifier + * name of the program you wish to connect to + */ + protected void getActiveInstance(String pProgramIdentifier) { + if (pProgramIdentifier == null || "".equals(pProgramIdentifier)) { + throw new IllegalArgumentException("program id is required"); + } + this.programId = pProgramIdentifier; + getActiveInstanceNative(pProgramIdentifier); + } + + /** + * native call coCreateInstance only used by the constructor with the same + * parm type. This probably should be private. It is the wrapper for the + * Windows CoCreate() call + *

+ * This ends up calling CoCreate down in the JNI layer + *

+ * This does not have the special behavior for program ids with ":" in them + * that createInstance has. + * + * @param progid + */ + private native void coCreateInstanceNative(String progid); + + /** + * Wrapper around the native method + * + * @param pProgramIdentifier + */ + protected void coCreateInstance(String pProgramIdentifier) { + if (pProgramIdentifier == null || "".equals(pProgramIdentifier)) { + throw new IllegalArgumentException("program id is required"); + } + this.programId = pProgramIdentifier; + coCreateInstanceNative(pProgramIdentifier); + } + + /** + * Return a different interface by IID string. + *

+ * Once you have a Dispatch object, you can navigate to the other interfaces + * of a COM object by calling QueryInterafce. The argument is an IID string + * in the format: "{9BF24410-B2E0-11D4-A695-00104BFF3241}". You typically + * get this string from the idl file (it's called uuid in there). Any + * interface you try to use must be derived from IDispatch. T The atl + * example uses this. + *

+ * The Dispatch instance resulting from this query is instanciated in the + * JNI code. + * + * @param iid + * @return Dispatch a disptach that matches ?? + */ + public native Dispatch QueryInterface(String iid); + + /** + * Constructor that only gets called from JNI QueryInterface calls JNI code + * that looks up the object for the key passed in. The JNI CODE then creates + * a new dispatch object using this constructor + * + * @param pDisp + */ + protected Dispatch(int pDisp) { + m_pDispatch = pDisp; + } + + /** + * Constructor to be used by subclass that want to swap themselves in for + * the default Dispatch class. Usually you will have a class like + * WordDocument that is a subclass of Dispatch and it will have a + * constructor public WordDocument(Dispatch). That constructor should just + * call this constructor as super(Dispatch) + * + * @param dispatchToBeDisplaced + */ + public Dispatch(Dispatch dispatchToBeDisplaced) { + // TAKE OVER THE IDispatch POINTER + this.m_pDispatch = dispatchToBeDisplaced.m_pDispatch; + // NULL OUT THE INPUT POINTER + dispatchToBeDisplaced.m_pDispatch = NOT_ATTACHED; + } + + /** + * returns the program id if an activeX component created this otherwise it + * returns null. This was added to aid in debugging + * + * @return the program id an activeX component was created against + */ + public String getProgramId() { + return programId; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + @Override + protected void finalize() { + safeRelease(); + } + + /* + * (non-Javadoc) + * + * @see com.jacob.com.JacobObject#safeRelease() + */ + @Override + public void safeRelease() { + super.safeRelease(); + if (isAttached()) { + release(); + m_pDispatch = NOT_ATTACHED; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug(this.getClass().getName() + ":" + this.hashCode() + + " double release"); + } + } + } + + /** + * + * @return true if there is an underlying windows dispatch object + */ + protected boolean isAttached() { + if (m_pDispatch == NOT_ATTACHED) { + return false; + } else { + return true; + } + } + + /** + * @param theOneInQuestion + * dispatch being tested + * @throws IllegalStateException + * if this dispatch isn't hooked up + * @throws IllegalArgumentException + * if null the dispatch under test is null + */ + private static void throwIfUnattachedDispatch(Dispatch theOneInQuestion) { + if (theOneInQuestion == null) { + throw new IllegalArgumentException( + "Can't pass in null Dispatch object"); + } else if (theOneInQuestion.isAttached()) { + return; + } else { + throw new IllegalStateException( + "Dispatch not hooked to windows memory"); + } + } + + /** + * now private so only this object can access was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + /** + * not implemented yet + * + * @param dispatchTarget + * @param name + * @param val + * @throws com.jacob.com.NotImplementedException + */ + public static void put_Casesensitive(Dispatch dispatchTarget, String name, + Object val) { + throw new NotImplementedException("not implemented yet"); + } + + /* + * ============================================================ start of the + * invokev section + * =========================================================== + */ + // eliminate _Guid arg + /** + * @param dispatchTarget + * @param name + * @param dispID + * @param lcid + * @param wFlags + * @param vArg + * @param uArgErr + */ + public static void invokeSubv(Dispatch dispatchTarget, String name, + int dispID, int lcid, int wFlags, Variant[] vArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokev(dispatchTarget, name, dispID, lcid, wFlags, vArg, uArgErr); + } + + /** + * @param dispatchTarget + * @param name + * @param wFlags + * @param vArg + * @param uArgErr + */ + public static void invokeSubv(Dispatch dispatchTarget, String name, + int wFlags, Variant[] vArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, vArg, uArgErr); + } + + /** + * @param dispatchTarget + * @param dispID + * @param wFlags + * @param vArg + * @param uArgErr + */ + public static void invokeSubv(Dispatch dispatchTarget, int dispID, + int wFlags, Variant[] vArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokev(dispatchTarget, null, dispID, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, vArg, uArgErr); + } + + /** + * not implemented yet + * + * @param dispatchTarget + * @param name + * @param values + * @return never returns anything because + * @throws com.jacob.com.NotImplementedException + */ + public static Variant callN_CaseSensitive(Dispatch dispatchTarget, + String name, Object[] values) { + throw new NotImplementedException("not implemented yet"); + } + + /** + * @param dispatchTarget + * @param name + * @param args + * an array of argument objects + */ + public static void callSubN(Dispatch dispatchTarget, String name, + Object... args) { + throwIfUnattachedDispatch(dispatchTarget); + invokeSubv(dispatchTarget, name, Dispatch.Method | Dispatch.Get, + VariantUtilities.objectsToVariants(args), new int[args.length]); + } + + /** + * @param dispatchTarget + * @param dispID + * @param args + * an array of argument objects + */ + public static void callSubN(Dispatch dispatchTarget, int dispID, + Object... args) { + throwIfUnattachedDispatch(dispatchTarget); + invokeSubv(dispatchTarget, dispID, Dispatch.Method | Dispatch.Get, + VariantUtilities.objectsToVariants(args), new int[args.length]); + } + + /* + * ============================================================ start of the + * getIdsOfNames section + * =========================================================== + */ + /** + * @param dispatchTarget + * @param name + * @return int id for the passed in name + */ + public static int getIDOfName(Dispatch dispatchTarget, String name) { + int ids[] = getIDsOfNames(dispatchTarget, + Dispatch.LOCALE_SYSTEM_DEFAULT, new String[] { name }); + return ids[0]; + } + + /** + * @param dispatchTarget + * @param lcid + * @param names + * @return int[] in id array for passed in names + */ + // eliminated _Guid argument + public static native int[] getIDsOfNames(Dispatch dispatchTarget, int lcid, + String[] names); + + /** + * @param dispatchTarget + * @param names + * @return int[] int id array for passed in names + */ + // eliminated _Guid argument + public static int[] getIDsOfNames(Dispatch dispatchTarget, String[] names) { + return getIDsOfNames(dispatchTarget, Dispatch.LOCALE_SYSTEM_DEFAULT, + names); + } + + /* + * ============================================================ start of the + * invokev section + * =========================================================== + */ + /** + * @param dispatchTarget + * @param name + * @param args + * @return Variant returned by call + */ + public static Variant callN(Dispatch dispatchTarget, String name, + Object... args) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, name, Dispatch.Method | Dispatch.Get, + VariantUtilities.objectsToVariants(args), new int[args.length]); + } + + /** + * @param dispatchTarget + * @param dispID + * @param args + * @return Variant returned by call + */ + public static Variant callN(Dispatch dispatchTarget, int dispID, + Object... args) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, dispID, Dispatch.Method | Dispatch.Get, + VariantUtilities.objectsToVariants(args), new int[args.length]); + } + + /** + * @param dispatchTarget + * @param name + * @param dispID + * @param lcid + * @param wFlags + * @param oArg + * @param uArgErr + * @return Variant returned by invoke + */ + public static Variant invoke(Dispatch dispatchTarget, String name, + int dispID, int lcid, int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, name, dispID, lcid, wFlags, + VariantUtilities.objectsToVariants(oArg), uArgErr); + } + + /** + * @param dispatchTarget + * @param name + * @param wFlags + * @param oArg + * @param uArgErr + * @return Variant returned by invoke + */ + public static Variant invoke(Dispatch dispatchTarget, String name, + int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, name, wFlags, VariantUtilities + .objectsToVariants(oArg), uArgErr); + } + + /** + * @param dispatchTarget + * @param dispID + * @param wFlags + * @param oArg + * @param uArgErr + * @return Variant returned by invoke + */ + public static Variant invoke(Dispatch dispatchTarget, int dispID, + int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, dispID, wFlags, VariantUtilities + .objectsToVariants(oArg), uArgErr); + } + + /* + * ============================================================ start of the + * callN section =========================================================== + */ + + /** + * @param dispatchTarget + * @param name + * @return Variant returned by underlying callN + */ + public static Variant call(Dispatch dispatchTarget, String name) { + throwIfUnattachedDispatch(dispatchTarget); + return callN(dispatchTarget, name, NO_VARIANT_ARGS); + } + + /** + * @param dispatchTarget + * @param name + * @param attributes + * @return Variant returned by underlying callN + */ + public static Variant call(Dispatch dispatchTarget, String name, + Object... attributes) { + throwIfUnattachedDispatch(dispatchTarget); + return callN(dispatchTarget, name, attributes); + } + + /** + * @param dispatchTarget + * @param dispid + * @return Variant returned by underlying callN + */ + public static Variant call(Dispatch dispatchTarget, int dispid) { + throwIfUnattachedDispatch(dispatchTarget); + return callN(dispatchTarget, dispid, NO_VARIANT_ARGS); + } + + /** + * @param dispatchTarget + * @param dispid + * @param attributes + * var arg list of attributes that will be passed to the + * underlying function + * @return Variant returned by underlying callN + */ + public static Variant call(Dispatch dispatchTarget, int dispid, + Object... attributes) { + throwIfUnattachedDispatch(dispatchTarget); + return callN(dispatchTarget, dispid, attributes); + } + + /* + * ============================================================ start of the + * invoke section + * =========================================================== + */ + /** + * @param dispatchTarget + * @param name + * @param val + */ + public static void put(Dispatch dispatchTarget, String name, Object val) { + throwIfUnattachedDispatch(dispatchTarget); + invoke(dispatchTarget, name, Dispatch.Put, new Object[] { val }, + new int[1]); + } + + /** + * @param dispatchTarget + * @param dispid + * @param val + */ + public static void put(Dispatch dispatchTarget, int dispid, Object val) { + throwIfUnattachedDispatch(dispatchTarget); + invoke(dispatchTarget, dispid, Dispatch.Put, new Object[] { val }, + new int[1]); + } + + /* + * ============================================================ start of the + * invokev section + * =========================================================== + */ + // removed _Guid argument + /** + * @param dispatchTarget + * @param name + * @param dispID + * @param lcid + * @param wFlags + * @param vArg + * @param uArgErr + * @return Variant returned by underlying invokev + */ + public static native Variant invokev(Dispatch dispatchTarget, String name, + int dispID, int lcid, int wFlags, Variant[] vArg, int[] uArgErr); + + /** + * @param dispatchTarget + * @param name + * @param wFlags + * @param vArg + * @param uArgErr + * @return Variant returned by underlying invokev + */ + public static Variant invokev(Dispatch dispatchTarget, String name, + int wFlags, Variant[] vArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, vArg, uArgErr); + } + + /** + * @param dispatchTarget + * @param name + * @param wFlags + * @param vArg + * @param uArgErr + * @param wFlagsEx + * @return Variant returned by underlying invokev + */ + public static Variant invokev(Dispatch dispatchTarget, String name, + int wFlags, Variant[] vArg, int[] uArgErr, int wFlagsEx) { + throwIfUnattachedDispatch(dispatchTarget); + // do not implement IDispatchEx for now + return invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, vArg, uArgErr); + } + + /** + * @param dispatchTarget + * @param dispID + * @param wFlags + * @param vArg + * @param uArgErr + * @return Variant returned by underlying invokev + */ + public static Variant invokev(Dispatch dispatchTarget, int dispID, + int wFlags, Variant[] vArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, null, dispID, + Dispatch.LOCALE_SYSTEM_DEFAULT, wFlags, vArg, uArgErr); + } + + /* + * ============================================================ start of the + * invokeSubv section + * =========================================================== + */ + + // removed _Guid argument + /** + * @param dispatchTarget + * @param name + * @param dispid + * @param lcid + * @param wFlags + * @param oArg + * @param uArgErr + */ + public static void invokeSub(Dispatch dispatchTarget, String name, + int dispid, int lcid, int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokeSubv(dispatchTarget, name, dispid, lcid, wFlags, VariantUtilities + .objectsToVariants(oArg), uArgErr); + } + + /* + * ============================================================ start of the + * invokeSub section + * =========================================================== + */ + /** + * @param dispatchTarget + * @param name + * @param wFlags + * @param oArg + * @param uArgErr + */ + public static void invokeSub(Dispatch dispatchTarget, String name, + int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokeSub(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, oArg, uArgErr); + } + + /** + * @param dispatchTarget + * @param dispid + * @param wFlags + * @param oArg + * @param uArgErr + */ + public static void invokeSub(Dispatch dispatchTarget, int dispid, + int wFlags, Object[] oArg, int[] uArgErr) { + throwIfUnattachedDispatch(dispatchTarget); + invokeSub(dispatchTarget, null, dispid, Dispatch.LOCALE_SYSTEM_DEFAULT, + wFlags, oArg, uArgErr); + } + + /* + * ============================================================ start of the + * callSubN section + * =========================================================== + */ + /** + * makes call to native callSubN + * + * @param dispatchTarget + * @param name + */ + public static void callSub(Dispatch dispatchTarget, String name) { + throwIfUnattachedDispatch(dispatchTarget); + callSubN(dispatchTarget, name, NO_OBJECT_ARGS); + } + + /** + * makes call to native callSubN + * + * @param dispatchTarget + * @param name + * @param attributes + * var args list of attributes to be passed to underlying + * functions + */ + public static void callSub(Dispatch dispatchTarget, String name, + Object... attributes) { + throwIfUnattachedDispatch(dispatchTarget); + callSubN(dispatchTarget, name, attributes); + } + + /** + * makes call to native callSubN + * + * @param dispatchTarget + * @param dispid + */ + public static void callSub(Dispatch dispatchTarget, int dispid) { + throwIfUnattachedDispatch(dispatchTarget); + callSubN(dispatchTarget, dispid, NO_OBJECT_ARGS); + } + + /** + * makes call to native callSubN + * + * @param dispatchTarget + * @param dispid + * @param attributes + * var args list of attributes to be passed to underlying + * function + */ + public static void callSub(Dispatch dispatchTarget, int dispid, + Object... attributes) { + throwIfUnattachedDispatch(dispatchTarget); + callSubN(dispatchTarget, dispid, attributes); + } + + /* + * ============================================================ start of the + * invokev section + * =========================================================== + */ + /** + * Cover for call to underlying invokev() + * + * @param dispatchTarget + * @param name + * @return Variant returned by the request for retrieval of parameter + */ + public static Variant get(Dispatch dispatchTarget, String name) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, name, Dispatch.Get, NO_VARIANT_ARGS, + NO_INT_ARGS); + } + + /** + * Cover for call to underlying invokev() + * + * @param dispatchTarget + * @param dispid + * @return Variant returned by the request for retrieval of parameter + */ + public static Variant get(Dispatch dispatchTarget, int dispid) { + throwIfUnattachedDispatch(dispatchTarget); + return invokev(dispatchTarget, dispid, Dispatch.Get, NO_VARIANT_ARGS, + NO_INT_ARGS); + } + + /* + * ============================================================ start of the + * invoke section + * =========================================================== + */ + /** + * cover for underlying call to invoke + * + * @param dispatchTarget + * @param name + * @param val + */ + public static void putRef(Dispatch dispatchTarget, String name, Object val) { + throwIfUnattachedDispatch(dispatchTarget); + invoke(dispatchTarget, name, Dispatch.PutRef, new Object[] { val }, + new int[1]); + } + + /** + * cover for underlying call to invoke + * + * @param dispatchTarget + * @param dispid + * @param val + */ + public static void putRef(Dispatch dispatchTarget, int dispid, Object val) { + throwIfUnattachedDispatch(dispatchTarget); + invoke(dispatchTarget, dispid, Dispatch.PutRef, new Object[] { val }, + new int[1]); + } + + /** + * not implemented yet + * + * @param dispatchTarget + * @param name + * @return Variant never returned + * @throws com.jacob.com.NotImplementedException + */ + public static Variant get_CaseSensitive(Dispatch dispatchTarget, String name) { + throw new NotImplementedException("not implemented yet"); + } + + /** + * Cover for native method + * + * @param disp + * @param dispid + * @param lcid + * @return 0 if the dispatch is still active and 1 if it has exited + */ + public static native int hasExited(Dispatch disp, int dispid, int lcid); + + /** + * The method is used to poll until it returns 1, indicating that the COM + * server in gone. + *

+ * Sourceforge feature request 2927058 + * + * @param dispatchTarget + * @return 0 if the dispatch is still active and 1 if it has exited + */ + public static int hasExited(Dispatch dispatchTarget) { + throwIfUnattachedDispatch(dispatchTarget); + return hasExited(dispatchTarget, 0, LOCALE_SYSTEM_DEFAULT); + } + +} diff --git a/java/src/com/jacob/com/DispatchEvents.java b/java/src/com/jacob/com/DispatchEvents.java new file mode 100644 index 0000000..62de581 --- /dev/null +++ b/java/src/com/jacob/com/DispatchEvents.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * This class creates the scaffolding for event callbacks. Every instance of tis + * acts as a wrapper around some java object that wants callbacks from the + * microsoft side. It represents the connection between Java and COM for + * callbacks. + *

+ * The callback mechanism will take any event that it receives and try and find + * a java method with the same name that accepts the Variant... as a parameter. + * It will then wrap the call back data in the Variant array and call the java + * method of the object that this DispatchEvents object was initialized with. + *

+ * Instances of this class are created with "sink object" that will receive the + * event messages. The sink object is wrapped in an Invocation handler that + * actually receives the messages and then forwards them on to the "sink + * object". The constructors recognize when an instance of InvocationProxy is + * passed in and do not create a new InvocationProxy as a wrapper. They instead + * use the passed in InvocationProxy. + * + */ +public class DispatchEvents extends JacobObject { + + /** + * pointer to an MS data struct. The COM layer knows the name of this + * variable and puts the windows memory pointer here. + */ + int m_pConnPtProxy = 0; + + /** + * the wrapper for the event sink. This object is the one that will be sent + * a message when an event occurs in the MS layer. Normally, the + * InvocationProxy will forward the messages to a wrapped object that it + * contains. + */ + InvocationProxy mInvocationProxy = null; + + /** + * This is the most commonly used constructor. + *

+ * Creates the event callback linkage between the the MS program represented + * by the Dispatch object and the Java object that will receive the + * callback. + *

+ * Can be used on any object that implements IProvideClassInfo. + * + * @param sourceOfEvent + * Dispatch object who's MS app will generate callbacks + * @param eventSink + * Java object that wants to receive the events + */ + public DispatchEvents(Dispatch sourceOfEvent, Object eventSink) { + this(sourceOfEvent, eventSink, null); + } + + /** + * None of the samples use this constructor. + *

+ * Creates the event callback linkage between the the MS program represented + * by the Dispatch object and the Java object that will receive the + * callback. + *

+ * Used when the program doesn't implement IProvideClassInfo. It provides a + * way to find the TypeLib in the registry based on the programId. The + * TypeLib is looked up in the registry on the path + * HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/(CLID drived from + * progid)/ProgID/Typelib + * + * @param sourceOfEvent + * Dispatch object who's MS app will generate callbacks + * @param eventSink + * Java object that wants to receive the events + * @param progId + * program id in the registry that has a TypeLib subkey. The + * progrId is mapped to a CLSID that is they used to look up the + * key to the Typelib + */ + public DispatchEvents(Dispatch sourceOfEvent, Object eventSink, + String progId) { + this(sourceOfEvent, eventSink, progId, null); + } + + /** + * Creates the event callback linkage between the the MS program represented + * by the Dispatch object and the Java object that will receive the + * callback. + *

+ * This method was added because Excel doesn't implement IProvideClassInfo + * and the registry entry for Excel.Application doesn't include a typelib + * key. + * + *

+	 * DispatchEvents de = new DispatchEvents(someDispatch, someEventHAndler,
+	 * 		"Excel.Application",
+	 * 		"C:\\Program Files\\Microsoft Office\\OFFICE11\\EXCEL.EXE");
+	 * 
+ * + * @param sourceOfEvent + * Dispatch object who's MS app will generate callbacks + * @param eventSink + * Java object that wants to receive the events + * @param progId , + * mandatory if the typelib is specified + * @param typeLib + * The location of the typelib to use + */ + public DispatchEvents(Dispatch sourceOfEvent, Object eventSink, + String progId, String typeLib) { + if (JacobObject.isDebugEnabled()) { + System.out.println("DispatchEvents: Registering " + eventSink + + "for events "); + } + if (eventSink instanceof InvocationProxy) { + mInvocationProxy = (InvocationProxy) eventSink; + } else { + mInvocationProxy = getInvocationProxy(eventSink); + } + if (mInvocationProxy != null) { + init3(sourceOfEvent, mInvocationProxy, progId, typeLib); + } else { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("Cannot register null event sink for events"); + } + throw new IllegalArgumentException( + "Cannot register null event sink for events"); + } + } + + /** + * Returns an instance of the proxy configured with pTargetObject as its + * target + * + * @param pTargetObject + * @return InvocationProxy an instance of the proxy this DispatchEvents will + * send to the COM layer + */ + protected InvocationProxy getInvocationProxy(Object pTargetObject) { + InvocationProxy newProxy = new InvocationProxyAllVariants(); + newProxy.setTarget(pTargetObject); + return newProxy; + } + + /** + * hooks up a connection point proxy by progId event methods on the sink + * object will be called by name with a signature of (Variant[] args) + * + * You must specify the location of the typeLib. + * + * @param src + * dispatch that is the source of the messages + * @param sink + * the object that will receive the messages + * @param progId + * optional program id. most folks don't need this either + * @param typeLib + * optional parameter for those programs that don't register + * their type libs (like Excel) + */ + private native void init3(Dispatch src, Object sink, String progId, + String typeLib); + + /** + * now private so only this object can asccess was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + protected void finalize() { + safeRelease(); + } + + /* + * (non-Javadoc) + * + * @see com.jacob.com.JacobObject#safeRelease() + */ + public void safeRelease() { + if (mInvocationProxy != null) { + mInvocationProxy.setTarget(null); + } + mInvocationProxy = null; + super.safeRelease(); + if (m_pConnPtProxy != 0) { + release(); + m_pConnPtProxy = 0; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug("DispatchEvents:" + this.hashCode() + " double release"); + } + } + } + +} diff --git a/java/src/com/jacob/com/DispatchIdentifier.java b/java/src/com/jacob/com/DispatchIdentifier.java new file mode 100644 index 0000000..bc18caf --- /dev/null +++ b/java/src/com/jacob/com/DispatchIdentifier.java @@ -0,0 +1,82 @@ +/** + * + */ +package com.jacob.com; + +/** + * A bunch of DispatchIds that were pulled out of the Dispatch class for version + * 1.14. + */ +public class DispatchIdentifier { + + private DispatchIdentifier() { + // This is utility class so there is no constructor. + } + + public static final int DISPID_UNKNOWN = -1; + public static final int DISPID_VALUE = 0; + public static final int DISPID_PROPERTYPUT = -3; + public static final int DISPID_NEWENUM = -4; + public static final int DISPID_EVALUATE = -5; + public static final int DISPID_CONSTRUCTOR = -6; + public static final int DISPID_DESTRUCTOR = -7; + public static final int DISPID_COLLECT = -8; + public static final int DISPID_AUTOSIZE = -500; + public static final int DISPID_BACKCOLOR = -501; + public static final int DISPID_BACKSTYLE = -502; + public static final int DISPID_BORDERCOLOR = -503; + public static final int DISPID_BORDERSTYLE = -504; + public static final int DISPID_BORDERWIDTH = -505; + public static final int DISPID_DRAWMODE = -507; + public static final int DISPID_DRAWSTYLE = -508; + public static final int DISPID_DRAWWIDTH = -509; + public static final int DISPID_FILLCOLOR = -510; + public static final int DISPID_FILLSTYLE = -511; + public static final int DISPID_FONT = -512; + public static final int DISPID_FORECOLOR = -513; + public static final int DISPID_ENABLED = -514; + public static final int DISPID_HWND = -515; + public static final int DISPID_TABSTOP = -516; + public static final int DISPID_TEXT = -517; + public static final int DISPID_CAPTION = -518; + public static final int DISPID_BORDERVISIBLE = -519; + public static final int DISPID_APPEARANCE = -520; + public static final int DISPID_MOUSEPOINTER = -521; + public static final int DISPID_MOUSEICON = -522; + public static final int DISPID_PICTURE = -523; + public static final int DISPID_VALID = -524; + public static final int DISPID_READYSTATE = -525; + public static final int DISPID_REFRESH = -550; + public static final int DISPID_DOCLICK = -551; + public static final int DISPID_ABOUTBOX = -552; + public static final int DISPID_CLICK = -600; + public static final int DISPID_DBLCLICK = -601; + public static final int DISPID_KEYDOWN = -602; + public static final int DISPID_KEYPRESS = -603; + public static final int DISPID_KEYUP = -604; + public static final int DISPID_MOUSEDOWN = -605; + public static final int DISPID_MOUSEMOVE = -606; + public static final int DISPID_MOUSEUP = -607; + public static final int DISPID_ERROREVENT = -608; + public static final int DISPID_READYSTATECHANGE = -609; + public static final int DISPID_AMBIENT_BACKCOLOR = -701; + public static final int DISPID_AMBIENT_DISPLAYNAME = -702; + public static final int DISPID_AMBIENT_FONT = -703; + public static final int DISPID_AMBIENT_FORECOLOR = -704; + public static final int DISPID_AMBIENT_LOCALEID = -705; + public static final int DISPID_AMBIENT_MESSAGEREFLECT = -706; + public static final int DISPID_AMBIENT_SCALEUNITS = -707; + public static final int DISPID_AMBIENT_TEXTALIGN = -708; + public static final int DISPID_AMBIENT_USERMODE = -709; + public static final int DISPID_AMBIENT_UIDEAD = -710; + public static final int DISPID_AMBIENT_SHOWGRABHANDLES = -711; + public static final int DISPID_AMBIENT_SHOWHATCHING = -712; + public static final int DISPID_AMBIENT_DISPLAYASDEFAULT = -713; + public static final int DISPID_AMBIENT_SUPPORTSMNEMONICS = -714; + public static final int DISPID_AMBIENT_AUTOCLIP = -715; + public static final int DISPID_AMBIENT_APPEARANCE = -716; + public static final int DISPID_AMBIENT_CODEPAGE = -725; + public static final int DISPID_AMBIENT_PALETTE = -726; + public static final int DISPID_AMBIENT_CHARSET = -727; + public static final int DISPID_AMBIENT_TRANSFERPRIORITY = -728; +} diff --git a/java/src/com/jacob/com/DispatchProxy.java b/java/src/com/jacob/com/DispatchProxy.java new file mode 100644 index 0000000..0a4f402 --- /dev/null +++ b/java/src/com/jacob/com/DispatchProxy.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * If you need to pass a COM Dispatch object between STA threads, you have to + * marshall the interface. This class is used as follows: the STA that creates + * the Dispatch object must construct an instance of this class. Another thread + * can then call toDispatch() on that instance and get a Dispatch pointer which + * has been marshalled. WARNING: You can only call toDispatch() once! If you + * need to call it multiple times (or from multiple threads) you need to + * construct a separate DispatchProxy instance for each such case! + */ +public class DispatchProxy extends JacobObject { + /** + * Comment for m_pStream + */ + public int m_pStream; + + /** + * Marshals the passed in dispatch into the stream + * + * @param localDispatch + */ + public DispatchProxy(Dispatch localDispatch) { + MarshalIntoStream(localDispatch); + } + + /** + * + * @return Dispatch the dispatch retrieved from the stream + */ + public Dispatch toDispatch() { + return MarshalFromStream(); + } + + private native void MarshalIntoStream(Dispatch d); + + private native Dispatch MarshalFromStream(); + + /** + * now private so only this object can access was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + public void finalize() { + safeRelease(); + } + + /* + * (non-Javadoc) + * + * @see com.jacob.com.JacobObject#safeRelease() + */ + public void safeRelease() { + super.safeRelease(); + if (m_pStream != 0) { + release(); + m_pStream = 0; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug(this.getClass().getName() + ":" + this.hashCode() + + " double release"); + } + } + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/EnumVariant.java b/java/src/com/jacob/com/EnumVariant.java new file mode 100644 index 0000000..7f16542 --- /dev/null +++ b/java/src/com/jacob/com/EnumVariant.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * An implementation of IEnumVariant based on code submitted by Thomas Hallgren + * (mailto:Thomas.Hallgren@eoncompany.com) + */ +public class EnumVariant extends JacobObject implements + java.util.Enumeration { + private int m_pIEnumVARIANT; + + private final Variant[] m_recBuf = new Variant[1]; + + // this only gets called from JNI + // + protected EnumVariant(int pIEnumVARIANT) { + m_pIEnumVARIANT = pIEnumVARIANT; + } + + /** + * @param disp + */ + public EnumVariant(Dispatch disp) { + int[] hres = new int[1]; + Variant evv = Dispatch.invokev(disp, DispatchIdentifier.DISPID_NEWENUM, + Dispatch.Get, new Variant[0], hres); + if (evv.getvt() != Variant.VariantObject) + // + // The DISPID_NEWENUM did not result in a valid object + // + throw new ComFailException("Can't obtain EnumVARIANT"); + + EnumVariant tmp = evv.toEnumVariant(); + m_pIEnumVARIANT = tmp.m_pIEnumVARIANT; + tmp.m_pIEnumVARIANT = 0; + } + + /** + * Implements java.util.Enumeration + * + * @return boolean true if there are more elements in this enumeration + */ + public boolean hasMoreElements() { + { + if (m_recBuf[0] == null) { + if (this.Next(m_recBuf) <= 0) + return false; + } + return true; + } + } + + /** + * Implements java.util.Enumeration + * + * @return next element in the enumeration + */ + public Variant nextElement() { + Variant last = m_recBuf[0]; + if (last == null) { + if (this.Next(m_recBuf) <= 0) + throw new java.util.NoSuchElementException(); + last = m_recBuf[0]; + } + m_recBuf[0] = null; + return last; + } + + /** + * Get next element in collection or null if at end + * + * @return Variant that is next in the collection + * @deprecated use nextElement() instead + */ + @Deprecated + public Variant Next() { + if (hasMoreElements()) + return nextElement(); + return null; + } + + /** + * This should be private and wrapped to protect JNI layer. + * + * @param receiverArray + * @return Returns the next variant object pointer as an int from windows + * layer + */ + public native int Next(Variant[] receiverArray); + + /** + * This should be private and wrapped to protect JNI layer. + * + * @param count + * number to skip + */ + public native void Skip(int count); + + /** + * This should be private and wrapped to protect JNI layer + */ + public native void Reset(); + + /** + * now private so only this object can access was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + protected void finalize() { + safeRelease(); + } + + /* + * (non-Javadoc) + * + * @see com.jacob.com.JacobObject#safeRelease() + */ + public void safeRelease() { + super.safeRelease(); + if (m_pIEnumVARIANT != 0) { + this.release(); + m_pIEnumVARIANT = 0; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug(this.getClass().getName() + ":" + this.hashCode() + + " double release"); + } + } + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/InvocationProxy.java b/java/src/com/jacob/com/InvocationProxy.java new file mode 100644 index 0000000..ddf98e6 --- /dev/null +++ b/java/src/com/jacob/com/InvocationProxy.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * @version $Id$ + * @author joe + * + * DispatchEvents wraps this class around any event handlers before making the + * JNI call that sets up the link with EventProxy. This means that + * EventProxy.cpp just calls invoke(String,Variant[]) against the instance of + * this class. Then this class does reflection against the event listener to + * call the actual event methods. The event methods can return void or return a + * Variant. Any value returned will be passed back to the calling windows module + * by the Jacob JNI layer. + *

+ * + * The void returning signature is the standard legacy signature. The Variant + * returning signature was added in 1.10 to support event handlers returning + * values. + * + */ +public abstract class InvocationProxy { + + /** + * the object we will try and forward to. + */ + protected Object mTargetObject = null; + + /** + * dummy constructor for subclasses that don't actually wrap anything and + * just want to override the invoke() method + */ + protected InvocationProxy() { + super(); + } + + /** + * The method actually invoked by EventProxy.cpp. The method name is + * calculated by the underlying JNI code from the MS windows Callback + * function name. The method is assumed to take an array of Variant objects. + * The method may return a Variant or be a void. Those are the only two + * options that will not blow up. + *

+ * Subclasses that override this should make sure mTargetObject is not null + * before processing. + * + * @param methodName + * name of method in mTargetObject we will invoke + * @param targetParameters + * Variant[] that is the single parameter to the method + * @return an object that will be returned to the com event caller + */ + public abstract Variant invoke(String methodName, + Variant targetParameters[]); + + /** + * used by EventProxy.cpp to create variant objects in the right thread + * + * @return Variant object that will be used by the COM layer + */ + public Variant getVariant() { + return new VariantViaEvent(); + } + + /** + * Sets the target for this InvocationProxy. + * + * @param pTargetObject + * @throws IllegalArgumentException + * if target is not publicly accessible + */ + public void setTarget(Object pTargetObject) { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("InvocationProxy: setting target " + + pTargetObject); + } + if (pTargetObject != null) { + // JNI code apparently bypasses this check and could operate against + // protected classes. This seems like a security issue... + // maybe it was because JNI code isn't in a package? + if (!java.lang.reflect.Modifier.isPublic(pTargetObject.getClass() + .getModifiers())) { + throw new IllegalArgumentException( + "InvocationProxy only public classes can receive event notifications"); + } + } + mTargetObject = pTargetObject; + } + +} diff --git a/java/src/com/jacob/com/InvocationProxyAllVariants.java b/java/src/com/jacob/com/InvocationProxyAllVariants.java new file mode 100644 index 0000000..a22ff96 --- /dev/null +++ b/java/src/com/jacob/com/InvocationProxyAllVariants.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * This class acts as a proxy between the windows event callback mechanism and + * the Java classes that are looking for events. It assumes that all of the Java + * classes that are looking for events implement methods with the same names as + * the windows events and that the implemented methods accept an array of + * variant objects. The methods can return void or a Variant that will be + * returned to the calling layer. All Event methods that will be recognized by + * InvocationProxyAllEvents have the signature + * + * void eventMethodName(Variant[]) or + * Variant eventMethodName(Variant[]) + */ +public class InvocationProxyAllVariants extends InvocationProxy { + + /* + * (non-Javadoc) + * + * @see com.jacob.com.InvocationProxy#invoke(java.lang.String, + * com.jacob.com.Variant[]) + */ + @SuppressWarnings("unchecked") + public Variant invoke(String methodName, Variant targetParameters[]) { + Variant mVariantToBeReturned = null; + if (mTargetObject == null) { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("InvocationProxy: received notification (" + + methodName + ") with no target set"); + } + // structured programming guidlines say this return should not be up + // here + return null; + } + Class targetClass = mTargetObject.getClass(); + if (methodName == null) { + throw new IllegalArgumentException( + "InvocationProxy: missing method name"); + } + if (targetParameters == null) { + throw new IllegalArgumentException( + "InvocationProxy: missing Variant parameters"); + } + try { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("InvocationProxy: trying to invoke " + + methodName + " on " + mTargetObject); + } + Method targetMethod; + targetMethod = targetClass.getMethod(methodName, + new Class[] { Variant[].class }); + if (targetMethod != null) { + // protected classes can't be invoked against even if they + // let you grab the method. you could do + // targetMethod.setAccessible(true); + // but that should be stopped by the security manager + Object mReturnedByInvocation = null; + mReturnedByInvocation = targetMethod.invoke(mTargetObject, + new Object[] { targetParameters }); + if (mReturnedByInvocation == null) { + mVariantToBeReturned = null; + } else if (!(mReturnedByInvocation instanceof Variant)) { + // could try and convert to Variant here. + throw new IllegalArgumentException( + "InvocationProxy: invokation of target method returned " + + "non-null non-variant object: " + + mReturnedByInvocation); + } else { + mVariantToBeReturned = (Variant) mReturnedByInvocation; + } + } + } catch (SecurityException e) { + // what causes this exception? + e.printStackTrace(); + } catch (NoSuchMethodException e) { + // this happens whenever the listener doesn't implement all the + // methods + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("InvocationProxy: listener (" + mTargetObject + + ") doesn't implement " + methodName); + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + // we can throw these inside the catch block so need to re-throw it + throw e; + } catch (IllegalAccessException e) { + // can't access the method on the target instance for some reason + if (JacobObject.isDebugEnabled()) { + JacobObject + .debug("InvocationProxy: probably tried to access public method on non public class" + + methodName); + } + e.printStackTrace(); + } catch (InvocationTargetException e) { + // invocation of target method failed + e.printStackTrace(); + } + return mVariantToBeReturned; + + } +} diff --git a/java/src/com/jacob/com/JacobException.java b/java/src/com/jacob/com/JacobException.java new file mode 100644 index 0000000..20f62d1 --- /dev/null +++ b/java/src/com/jacob/com/JacobException.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * The parent class of all Jacob exceptions. They all used to be based off of + * RuntimeException or ComException but it was decided to base them all off of + * one owned by this project. + */ +public class JacobException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -1637125318746002715L; + + /** + * Default constructor. Calls super with a "No Message Provided" string + */ + public JacobException() { + super("No Message Provided"); + } + + /** + * standard constructor + * + * @param message + */ + public JacobException(String message) { + super(message); + } +} diff --git a/java/src/com/jacob/com/JacobObject.java b/java/src/com/jacob/com/JacobObject.java new file mode 100644 index 0000000..9442360 --- /dev/null +++ b/java/src/com/jacob/com/JacobObject.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * The superclass of all Jacob objects. It is used to create a standard API + * framework and to facilitate memory management for Java and COM memory + * elements. + *

+ * All instances of this class and subclasses are automatically managed by the + * ROT. This means the ROT cannot be a subclass of JacobObject. + *

+ * All COM object created by JACOB extend this class so that we can + * automatically release them when the thread is detached from COM - if we leave + * it to the finalizer it will call the release from another thread, which may + * result in a segmentation violation. + */ +public class JacobObject { + + /** + * Standard constructor that adds this JacobObject to the memory management + * pool. + */ + public JacobObject() { + ROT.addObject(this); + } + + /** + * Finalizers call this method. This method should release any COM data + * structures in a way that it can be called multiple times. This can happen + * if someone manually calls this and then a finalizer calls it. + */ + public void safeRelease() { + // currently does nothing - subclasses may do something + if (isDebugEnabled()) { + // this used to do a toString() but that is bad for SafeArray + debug("SafeRelease: " + this.getClass().getName()); + } + } + + /** + * When things go wrong, it is useful to be able to debug the ROT. + */ + private static final boolean DEBUG = + // true; + "true".equalsIgnoreCase(System.getProperty("com.jacob.debug")); + + protected static boolean isDebugEnabled() { + return DEBUG; + } + + /** + * Loads JacobVersion.Properties and returns the value of version in it + * + * @deprecated use JacobReleaseInfo.getBuildDate() instead. + * @return String value of version in JacobVersion.Properties or "" if none + */ + @Deprecated + public static String getBuildDate() { + return JacobReleaseInfo.getBuildDate(); + } + + /** + * Loads JacobVersion.Properties and returns the value of version in it + * + * @deprecated use JacobReleaseInfo.getBuildVersion() instead. + * @return String value of version in JacobVersion.Properties or "" if none + */ + @Deprecated + public static String getBuildVersion() { + return JacobReleaseInfo.getBuildVersion(); + } + + /** + * Very basic debugging function. + * + * @param istrMessage + */ + protected static void debug(String istrMessage) { + if (isDebugEnabled()) { + System.out.println(Thread.currentThread().getName() + ": " + + istrMessage); + } + } + + /** + * force the jacob DLL to be loaded whenever this class is referenced + */ + static { + LibraryLoader.loadJacobLibrary(); + } + +} \ No newline at end of file diff --git a/java/src/com/jacob/com/JacobReleaseInfo.java b/java/src/com/jacob/com/JacobReleaseInfo.java new file mode 100644 index 0000000..c8d8186 --- /dev/null +++ b/java/src/com/jacob/com/JacobReleaseInfo.java @@ -0,0 +1,96 @@ +package com.jacob.com; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * An interface to the version properties file. This code was removed from + * JacobObject because it doesn't belong there. + * + */ +public class JacobReleaseInfo { + + /** + * holds the build version as retrieved from the version properties file + * that exists in the JAR. This can be retrieved by calling the static + * method getBuildVersion() + * + * @see #getBuildVersion() + */ + private static String buildVersion = ""; + /** + * holds the build date as retrieved from the version properties file that + * exists in the JAR This can be retrieved by calling the static method + * getBuildDate() + * + * @see #getBuildDate() + */ + private static String buildDate = ""; + /** the name of the jacob version properties file */ + private static final String PROPERTY_FILE_NAME = "META-INF/JacobVersion.properties"; + + /** + * Loads version information from PROPERTY_FILE_NAME that was built as part + * of this release. + * + * @throws IllegalStateException + * when it can't find the version properties file + */ + private static void loadVersionProperties() { + /*Properties versionProps = new Properties(); + // can't use system class loader cause won't work in JavaWebStart + InputStream stream = JacobReleaseInfo.class.getClassLoader() + .getResourceAsStream(PROPERTY_FILE_NAME); + // This should never happen. This is an attempt to make something work + // for WebSphere. They may be using some kind of Servlet loader that + // needs an absolute path based search + if (stream == null) { + stream = JacobReleaseInfo.class.getClassLoader() + .getResourceAsStream("/" + PROPERTY_FILE_NAME); + } + // A report came in that WebSphere had trouble finding the file + // so lets trap it. Plus, it's a good idea anyway. + if (stream == null) { + throw new IllegalStateException( + "Can't find " + + PROPERTY_FILE_NAME + + " using JacobReleaseInfo.class.getClassLoader().getResourceAsStream()"); + } else { + try { + versionProps.load(stream); + stream.close(); + buildVersion = (String) versionProps.get("version"); + buildDate = (String) versionProps.get("build.date"); + } catch (IOException ioe) { + ioe.printStackTrace(); + System.err.println("Warning! Couldn't load props " + ioe); + } + }*/ + } + + /** + * loads PROPERT_FILE_NAME and returns the value of version in it + * + * @return String value of version in PROPERT_FILE_NAME or "" if none + */ + public static String getBuildDate() { + if (buildDate.equals("")) { + loadVersionProperties(); + } + return buildDate; + } + + /** + * loads PROPERT_FILE_NAME and returns the value of version in it + * + * @return String value of version in PROPERT_FILE_NAME or "" if none + */ + public static String getBuildVersion() { + if (buildVersion.equals("")) { + loadVersionProperties(); + } + return buildVersion; + } + +} diff --git a/java/src/com/jacob/com/LibraryLoader.java b/java/src/com/jacob/com/LibraryLoader.java new file mode 100644 index 0000000..85f9a16 --- /dev/null +++ b/java/src/com/jacob/com/LibraryLoader.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1999-2007 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; + +/** + * Utility class to centralize the way in which the jacob JNI library is loaded. + *

+ * + * This supports defining the path or library name using system properties or a + * custom resource file. If desired, jacob can auto-detect the correct version + * of the DLL for 32 or 64 bit windows, as long as you have named them + * differently. + * + *

    + *
  1. If system property {@link #JACOB_DLL_PATH} is defined, the file located + * there will be loaded as the jacob dll using System.load().
  2. + * + *
  3. If system property {@link #JACOB_DLL_NAME} is defined, the file located + * there will be loaded as the jacob dll.
  4. + *
  5. If system property {@link #JACOB_DLL_NAME_X86} and + * {@link #JACOB_DLL_NAME_X64} are defined, the file located there will be + * loaded as the jacob dll, depending on the version of Windows.
  6. + * + *
  7. If {@link #JACOB_DLL_NAME} is defined in the + * {@code com.jacob.com.JacobLibraryLoader} resource file, the specified dll + * will be loaded from the {@code java.library.path}.
  8. + *
  9. If {@link #JACOB_DLL_NAME_X86} and {@link #JACOB_DLL_NAME_X64} are + * defined in the {@code com.jacob.com.JacobLibraryLoader} resource file, the + * specified dll will be loaded from the {@code java.library.path}, depending + * on the version of Windows.
  10. + * + *
  11. If none of the above are true, the default is to load the library named + * "jacob-<version>-<arch>" (or + * "jacob-<version>-<arch&rt;.dll") from the {@code java.library.path}. + *
  12. + *
+ * + * The standard behavior for most applications is that {@code LoadLibrary()} + * will be called to load the dll. {@code LoadLibary()} searches directories + * specified in the variable {@code java.library.path}. This is why most test + * cases specify -Djava.library.path in their command line arguments. + *

+ * JACOB_DLL_PATH submitted sourceforge ticket 1493647 Added 1.11
+ * JACOB_DLL_NAME, JACOB_DLL_NAME_32, JACOB_DLL_NAME_64 submitted sourceforge + * ticket 1845039 Added 1.14M7 + * + * @author Scott Dickerson (sjd78) + * @author Jason Smith + */ +public final class LibraryLoader { + /** + * Name of system property (currently jacob.dll.path) that may + * contain an absolute path to the JNI library. + */ + public static final String JACOB_DLL_PATH = "jacob.dll.path"; + + /** + * Name of system property (currently jacob.dll.name) that may + * contain an alternate name for the JNI library (default is 'jacob'). + */ + public static final String JACOB_DLL_NAME = "jacob.dll.name"; + + /** + * Name of system property (currently jacob.dll.name) that may + * contain an alternate name for the JNI library (default is 'jacob'), 32 + * bit windows. + */ + public static final String JACOB_DLL_NAME_X86 = "jacob.dll.name.x86"; + + /** + * Name of system property (currently jacob.dll.name) that may + * contain an alternate name for the JNI library (default is 'jacob'), 64 + * bit windows. + */ + public static final String JACOB_DLL_NAME_X64 = "jacob.dll.name.x64"; + + /** + * Appended to "jacob" when building DLL name This string must EXACTLY match + * the string in the build.xml file + */ + public static final String DLL_NAME_MODIFIER_32_BIT = "x86"; + /** + * Appended to "jacob" when building DLL name This string must EXACTLY match + * the string in the build.xml file + */ + public static final String DLL_NAME_MODIFIER_64_BIT = "x64"; + + /** + * Load the jacob dll either from an absolute path or by a library name, + * both of which may be defined in various ways. + * + * @throws UnsatisfiedLinkError + * if the library does not exist. + */ + public static void loadJacobLibrary() { + // In some cases, a library that uses Jacob won't be able to set system + // properties + // prior to Jacob being loaded. The resource bundle provides an + // alternate way to + // override DLL name or path that will be loaded with Jacob regardless + // of other + // initialization order. + ResourceBundle resources = null; + Set keys = new HashSet(); + try { + resources = ResourceBundle.getBundle(LibraryLoader.class.getName(), + Locale.getDefault(), LibraryLoader.class.getClassLoader()); + for (Enumeration i = resources.getKeys(); i + .hasMoreElements();) { + String key = i.nextElement(); + keys.add(key); + } + } catch (MissingResourceException e) { + // Do nothing. Expected. + } + + // First, check for a defined PATH. System property overrides resource + // bundle. + String path = System.getProperty(JACOB_DLL_PATH); + if (path == null && resources != null && keys.contains(JACOB_DLL_PATH)) { + path = (String) resources.getObject(JACOB_DLL_PATH); + } + + if (path != null) { + JacobObject.debug("Loading library " + path + + " using System.loadLibrary "); + System.load(path); + } else { + // Path was not defined, so use the OS mechanism for loading + // libraries. + // Check for a defined NAME. System property overrides resource + // bundle. + String name = null; + + if (System.getProperty(JACOB_DLL_NAME) != null) { + name = System.getProperty(JACOB_DLL_NAME); + } else if (System.getProperty(JACOB_DLL_NAME_X86) != null + && shouldLoad32Bit()) { + name = System.getProperty(JACOB_DLL_NAME_X86); + } else if (System.getProperty(JACOB_DLL_NAME_X64) != null + && !shouldLoad32Bit()) { + name = System.getProperty(JACOB_DLL_NAME_X64); + } else if (resources != null && keys.contains(JACOB_DLL_NAME)) { + name = resources.getString(JACOB_DLL_NAME); + } else if (resources != null && keys.contains(JACOB_DLL_NAME_X86) + && shouldLoad32Bit()) { + name = resources.getString(JACOB_DLL_NAME_X86); + } else if (resources != null && keys.contains(JACOB_DLL_NAME_X64) + && !shouldLoad32Bit()) { + name = resources.getString(JACOB_DLL_NAME_X64); + } else { + // No alternate NAME or PATH was defined, so use the default. + // We will almost always end up here. + name = getPreferredDLLName(); + } + + JacobObject.debug("Loading library " + name + + " using System.loadLibrary "); + // System.out.println("Loading " + name); + System.loadLibrary(name); + } + } + + /** + * Developer note: This method MUST be synchronized with the DLL names + * created as part of the build process in build.xml + *

+ * The DLL name is "jacob\.release" + * + * @return the preferred name of the DLL adjusted for this platform and + * version without the ".dll" extension + */ + public static String getPreferredDLLName() { + if (shouldLoad32Bit()) { + return "jacob" + "-" + JacobReleaseInfo.getBuildVersion() + "-" + + DLL_NAME_MODIFIER_32_BIT; + } else { + return "jacob" + "-" + JacobReleaseInfo.getBuildVersion() + "-" + + DLL_NAME_MODIFIER_64_BIT; + } + } + + /** + * Detects whether this is a 32-bit JVM. + * + * @return {@code true} if this is a 32-bit JVM. + */ + protected static boolean shouldLoad32Bit() { + // This guesses whether we are running 32 or 64 bit Java. + // This works for Sun and IBM JVMs version 5.0 or later. + // May need to be adjusted for non-Sun JVMs. + + String bits = System.getProperty("sun.arch.data.model", "?"); + if (bits.equals("32")) + return true; + else if (bits.equals("64")) + return false; + + // this works for jRocket + String arch = System.getProperty("java.vm.name", "?"); + if (arch.toLowerCase().indexOf("64-bit") >= 0) + return false; + + return true; + } +} // LibraryLoader diff --git a/java/src/com/jacob/com/MainSTA.java b/java/src/com/jacob/com/MainSTA.java new file mode 100644 index 0000000..5a8f0ea --- /dev/null +++ b/java/src/com/jacob/com/MainSTA.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * We provide our own main sta thread to avoid COM tagging a random thread as + * the main STA - this is the thread in which all Apartment threaded components + * will be created if the client chooses an MTA threading model for the java + * side of the app. + */ +public class MainSTA extends STA { +} \ No newline at end of file diff --git a/java/src/com/jacob/com/NotImplementedException.java b/java/src/com/jacob/com/NotImplementedException.java new file mode 100644 index 0000000..8971158 --- /dev/null +++ b/java/src/com/jacob/com/NotImplementedException.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * Thrown by java APIs that are not implemented either because they were never + * implemented or because they are being deprecated This is a subclass of + * ComException so callers can still just catch ComException. + */ +public class NotImplementedException extends JacobException { + + /** + * + */ + private static final long serialVersionUID = -9169900832852356445L; + + /** + * @param description + */ + public NotImplementedException(String description) { + super(description); + } + +} diff --git a/java/src/com/jacob/com/ROT.java b/java/src/com/jacob/com/ROT.java new file mode 100644 index 0000000..2f5cec5 --- /dev/null +++ b/java/src/com/jacob/com/ROT.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * The Running Object Table (ROT) maps each thread to a collection of all the + * JacobObjects that were created in that thread. It always operates on the + * current thread so all the methods are static and they implicitly get the + * current thread. + *

+ * The clearObjects method is used to release all the COM objects created by + * Jacob in the current thread prior to uninitializing COM for that thread. + *

+ * Prior to 1.9, manual garbage collection was the only option in Jacob, but + * from 1.9 onward, setting the com.jacob.autogc system property allows the + * objects referenced by the ROT to be automatically GCed. Automatic GC may be + * preferable in systems with heavy event callbacks. + *

+ * Is [ 1116101 ] jacob-msg 0284 relevant??? + */ +public abstract class ROT { + /** + * Manual garbage collection was the only option pre 1.9 Can staticly cache + * the results because only one value and we don't let it change during a + * run + */ + protected static final boolean USE_AUTOMATIC_GARBAGE_COLLECTION = "true" + .equalsIgnoreCase(System.getProperty("com.jacob.autogc")); + + /** + * If the code is ran from an applet that is called from javascript the Java + * Plugin does not give full permissions to the code and thus System + * properties cannot be accessed. They can be accessed at class + * initialization time. + * + * The default behavior is to include all classes in the ROT, setting a + * boolean here to indicate this prevents a call to System.getProperty as + * part of the general call flow. + */ + protected static final Boolean INCLUDE_ALL_CLASSES_IN_ROT = Boolean + .valueOf(System.getProperty("com.jacob.includeAllClassesInROT", + "true")); + + /** + * Suffix added to class name to make up property name that determines if + * this object should be stored in the ROT. This 1.13 "feature" makes it + * possible to cause VariantViaEvent objects to not be added to the ROT in + * event callbacks. + *

+ * We don't have a static for the actual property because there is a + * different property for each class that may make use of this feature. + */ + protected static String PUT_IN_ROT_SUFFIX = ".PutInROT"; + + /** + * A hash table where each element is another HashMap that represents a + * thread. Each thread HashMap contains the com objects created in that + * thread + */ + private static HashMap> rot = new HashMap>(); + + /** + * adds a new thread storage area to rot + * + * @return Map corresponding to the thread that this call was made in + */ + protected synchronized static Map addThread() { + // should use the id here instead of the name because the name can be + // changed + String t_name = Thread.currentThread().getName(); + if (rot.containsKey(t_name)) { + // nothing to do + } else { + Map tab = null; + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: Automatic GC flag == " + + USE_AUTOMATIC_GARBAGE_COLLECTION); + } + if (!USE_AUTOMATIC_GARBAGE_COLLECTION) { + tab = new HashMap(); + } else { + tab = new WeakHashMap(); + } + rot.put(t_name, tab); + } + return getThreadObjects(false); + } + + /** + * Returns the pool for this thread if it exists. can create a new one if + * you wish by passing in TRUE + * + * @param createIfDoesNotExist + * @return Map the collection that holds the objects created in the current + * thread + */ + protected synchronized static Map getThreadObjects( + boolean createIfDoesNotExist) { + String t_name = Thread.currentThread().getName(); + if (!rot.containsKey(t_name) && createIfDoesNotExist) { + addThread(); + } + return rot.get(t_name); + } + + /** + * Iterates across all of the entries in the Hashmap in the rot that + * corresponds to this thread. This calls safeRelease() on each entry and + * then clears the map when done and removes it from the rot. All traces of + * this thread's objects will disappear. This is called by COMThread in the + * tear down and provides a synchronous way of releasing memory + */ + protected static void clearObjects() { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: " + rot.keySet().size() + + " thread tables exist"); + } + + Map tab = getThreadObjects(false); + if (tab != null) { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: " + tab.keySet().size() + + " objects to clear in this thread's ROT "); + } + // walk the values + Iterator it = tab.keySet().iterator(); + while (it.hasNext()) { + JacobObject o = it.next(); + if (o != null + // can't use this cause creates a Variant if calling SafeAray + // and we get an exception modifying the collection while + // iterating + // && o.toString() != null + ) { + if (JacobObject.isDebugEnabled()) { + if (o instanceof SafeArray) { + // SafeArray create more objects when calling + // toString() + // which causes a concurrent modification exception + // in HashMap + JacobObject.debug("ROT: removing " + + o.getClass().getName()); + } else { + // Variant toString() is probably always bad in here + JacobObject.debug("ROT: removing " + o.hashCode() + + "->" + o.getClass().getName()); + } + } + o.safeRelease(); + } + } + // empty the collection + tab.clear(); + // remove the collection from rot + ROT.removeThread(); + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: thread table cleared and removed"); + } + } else { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: nothing to clear!"); + } + } + } + + /** + * Removes the map from the rot that is associated with the current thread. + */ + private synchronized static void removeThread() { + // should this see if it exists first? + rot.remove(Thread.currentThread().getName()); + } + + /** + * @deprecated the java model leave the responsibility of clearing up + * objects to the Garbage Collector. Our programming model + * should not require that the user specifically remove object + * from the thread.
+ * This will remove an object from the ROT
+ * This does not need to be synchronized because only the rot + * modification related methods need to synchronized. Each + * individual map is only modified in a single thread. + * @param o + */ + @Deprecated + protected static void removeObject(JacobObject o) { + Map tab = ROT.getThreadObjects(false); + if (tab != null) { + tab.remove(o); + } + o.safeRelease(); + } + + /** + * Adds an object to the HashMap for the current thread.
+ *

+ * This method does not need to be threaded because the only concurrent + * modification risk is on the hash map that contains all of the thread + * related hash maps. The individual thread related maps are only used on a + * per thread basis so there isn't a locking issue. + *

+ * In addition, this method cannot be threaded because it calls + * ComThread.InitMTA. The ComThread object has some methods that call ROT so + * we could end up deadlocked. This method should be safe without the + * synchronization because the ROT works on per thread basis and the methods + * that add threads and remove thread related entries are all synchronized + * + * + * @param o + */ + protected static void addObject(JacobObject o) { + String shouldIncludeClassInROT = "true"; + // only call System.getProperty if we are not including all classes in + // the ROT. This lets us run with standard Jacob behavior in Applets + // without the security exception raised by System.getProperty in the + // flow + if (!ROT.INCLUDE_ALL_CLASSES_IN_ROT) { + shouldIncludeClassInROT = System.getProperty(o.getClass().getName() + + PUT_IN_ROT_SUFFIX, "true"); + } + if (shouldIncludeClassInROT.equalsIgnoreCase("false")) { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("JacobObject: New instance of " + + o.getClass().getName() + " not added to ROT"); + } + } else { + // first see if we have a table for this thread + Map tab = getThreadObjects(false); + if (tab == null) { + // this thread has not been initialized as a COM thread + // so make it part of MTA for backwards compatibility + ComThread.InitMTA(false); + // don't really need the "true" because the InitMTA will have + // called back to the ROT to create a table for this thread + tab = getThreadObjects(true); + } + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("ROT: adding " + o + "->" + + o.getClass().getName() + + " table size prior to addition:" + tab.size()); + } + // add the object to the table that is specific to this thread + if (tab != null) { + tab.put(o, null); + } + } + } + + /** + * ROT can't be a subclass of JacobObject because of the way ROT pools are + * managed so we force a DLL load here by referencing JacobObject + */ + static { + LibraryLoader.loadJacobLibrary(); + } + +} diff --git a/java/src/com/jacob/com/STA.java b/java/src/com/jacob/com/STA.java new file mode 100644 index 0000000..a8e29d7 --- /dev/null +++ b/java/src/com/jacob/com/STA.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * A class that implements a Single Threaded Apartment. Users will subclass this + * and override OnInit() and OnQuit() where they will create and destroy a COM + * component that wants to run in an STA other than the main STA. + */ +public class STA extends Thread { + /** + * referenced by STA.cpp + */ + public int threadID; + + /** + * constructor for STA + */ + public STA() { + start(); // start the thread + } + + /* + * (non-Javadoc) + * + * @see java.lang.Thread#run() + */ + public void run() { + // init COM + ComThread.InitSTA(); + if (OnInit()) { + // this call blocks in the win32 message loop + // until quitMessagePump is called + doMessagePump(); + } + OnQuit(); + // uninit COM + ComThread.Release(); + } + + /** + * Override this method to create and initialize any COM component that you + * want to run in this thread. If anything fails, return false to terminate + * the thread. + * + * @return always returns true + */ + public boolean OnInit() { + return true; + } + + /** + * Override this method to destroy any resource before the thread exits and + * COM in uninitialized + */ + public void OnQuit() { + // there is nothing to see here + } + + /** + * calls quitMessagePump + */ + public void quit() { + quitMessagePump(); + } + + /** + * run a message pump for the main STA + */ + public native void doMessagePump(); + + /** + * quit message pump for the main STA + */ + public native void quitMessagePump(); + + /** + * STA isn't a subclass of JacobObject so a reference to it doesn't load the + * DLL without this + */ + static { + LibraryLoader.loadJacobLibrary(); + } +} \ No newline at end of file diff --git a/java/src/com/jacob/com/SafeArray.java b/java/src/com/jacob/com/SafeArray.java new file mode 100644 index 0000000..8b14b3b --- /dev/null +++ b/java/src/com/jacob/com/SafeArray.java @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * This creates an array wrapper around Variant objects(?). This supports 1, 2 + * and n-dimensional arrays. It exists in this form because n-dimensional arrays + * were a later addition. + */ +public class SafeArray extends JacobObject { + /** The super secret int that is actually the pointer to windows memory */ + int m_pV = 0; + + /** + * Constructor. Why does this exist? Yeah, someone will post on sourceforge + * about this comment. + * + */ + public SafeArray() { + } + + /** + * Constructor. + * + * @param vt + * type of array + */ + public SafeArray(int vt) { + init(vt, new int[] { 0 }, new int[] { -1 }); + } + + /** + * Constructor for a single dimensional array whose lower bounds is 0 and + * whose upper bound is specified as a parameter + * + * @param vt + * type of the array + * @param celems + * length of the array + */ + public SafeArray(int vt, int celems) { + init(vt, new int[] { 0 }, new int[] { celems }); + } + + /** + * Creates a two dimensional SafeArray whose base indexes are 0. + * + * @param vt + * Type of the array + * @param celems1 + * length of the array in first dimension + * @param celems2 + * length of the array in second dimension + */ + public SafeArray(int vt, int celems1, int celems2) { + init(vt, new int[] { 0, 0 }, new int[] { celems1, celems2 }); + } + + /** + * Constructor with support for N-dimensional array support + *

+ * You create an N-D SafeArray by: SafeArray sa = new + * SafeArray(Variant.VariantVariant, new int[] {0,0,0,0}, new int[] + * {4,4,4,4}); Where the 1st array is lower bounds and 2nd has the lengths + * of each dimension * + * + * @param vt + * @param lbounds + * @param celems + */ + public SafeArray(int vt, int lbounds[], int celems[]) { + init(vt, lbounds, celems); + } + + /** + * convert a string to a VT_UI1 array + * + * @param s + * source string + */ + public SafeArray(String s) { + char[] ca = s.toCharArray(); + init(Variant.VariantByte, new int[] { 0 }, new int[] { ca.length }); + fromCharArray(ca); + } + + /** + * convert a VT_UI1 array to string + * + * @return variant byte as a string + */ + public String asString() { + if (getvt() != Variant.VariantByte) { + return null; + } + char ja[] = toCharArray(); + return new String(ja); + } + + public native Object clone(); + + /** + * now private so only this object can access. Was: call this to explicitly + * release the com object before gc + * + */ + private native void destroy(); + + /** + * {@inheritDoc} + */ + protected void finalize() { + safeRelease(); + } + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromBooleanArray(boolean ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromByteArray(byte ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromCharArray(char ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromDoubleArray(double ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromFloatArray(float ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromIntArray(int ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromLongArray(long ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromShortArray(short ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromStringArray(String ja[]); + + /** + * populate the safe array from the passed in array of data + * + * @param ja + */ + public native void fromVariantArray(Variant ja[]); + + /** + * boolean access + * + * @param sa_idx + * @return boolean representation + */ + public native boolean getBoolean(int sa_idx); + + /** + * get boolean value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native boolean getBoolean(int indices[]); + + /** + * boolean access + * + * @param sa_idx1 + * @param sa_idx2 + * @return boolean representation + */ + public native boolean getBoolean(int sa_idx1, int sa_idx2); + + /** + * boolean access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getBooleans(int sa_idx, int nelems, boolean ja[], + int ja_start); + + /** + * byte access + * + * @param sa_idx + * @return byte representaton + */ + public native byte getByte(int sa_idx); + + /** + * get byte value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native byte getByte(int indices[]); + + /** + * byte access + * + * @param sa_idx1 + * @param sa_idx2 + * @return byte representation + */ + public native byte getByte(int sa_idx1, int sa_idx2); + + /** + * Fills byte array from contents of this array + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getBytes(int sa_idx, int nelems, byte ja[], int ja_start); + + /** + * char access + * + * @param sa_idx + * @return single character rpeesentation + */ + public native char getChar(int sa_idx); + + /** + * get char value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native char getChar(int indices[]); + + /** + * char access + * + * @param sa_idx1 + * @param sa_idx2 + * @return single character representation + */ + public native char getChar(int sa_idx1, int sa_idx2); + + /** + * char access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getChars(int sa_idx, int nelems, char ja[], int ja_start); + + /** + * double access + * + * @param sa_idx + * @return double stored in array + */ + public native double getDouble(int sa_idx); + + /** + * get double value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native double getDouble(int indices[]); + + /** + * double access + * + * @param sa_idx1 + * @param sa_idx2 + * @return double stored in array + */ + public native double getDouble(int sa_idx1, int sa_idx2); + + /** + * double access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getDoubles(int sa_idx, int nelems, double ja[], + int ja_start); + + /** + * @return the size of each element? + */ + public native int getElemSize(); + + /** + * @return The ??features of the array? + */ + public native int getFeatures(); + + /** + * float access + * + * @param sa_idx + * @return float held in array at location + */ + public native float getFloat(int sa_idx); + + /** + * get float value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native float getFloat(int indices[]); + + /** + * float access + * + * @param sa_idx1 + * @param sa_idx2 + * @return float held in array at location + */ + public native float getFloat(int sa_idx1, int sa_idx2); + + /** + * float access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getFloats(int sa_idx, int nelems, float ja[], + int ja_start); + + /** + * get int from an single dimensional array + * + * @param sa_idx + * array index + * @return int stored in array + */ + public native int getInt(int sa_idx); + + /** + * get int value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native int getInt(int indices[]); + + /** + * get int from 2 dimensional array + * + * @param sa_idx1 + * array index first dimension + * @param sa_idx2 + * array index of second dimension + * @return int stored in array + */ + public native int getInt(int sa_idx1, int sa_idx2); + + /** + * retrieves a group of ints from a single dimensional array + * + * @param sa_idx + * the index in the array to start the get + * @param nelems + * number of elements to retrieve + * @param ja + * the structure to be filled with the ints + * @param ja_start + * the start point in the java int array to start filling + */ + public native void getInts(int sa_idx, int nelems, int ja[], int ja_start); + + /** + * get int from an single dimensional array + * + * @param sa_idx + * array index + * @return long stored in array + */ + public native long getLong(int sa_idx); + + /** + * get long value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native long getLong(int indices[]); + + /** + * get long from 2 dimensional array + * + * @param sa_idx1 + * array index first dimension + * @param sa_idx2 + * array index of second dimension + * @return long stored in array + */ + public native long getLong(int sa_idx1, int sa_idx2); + + /** + * retrieves a group of longs from a single dimensional array + * + * @param sa_idx + * the index in the array to start the get + * @param nelems + * number of elements to retrieve + * @param ja + * the structure to be filled with the longs + * @param ja_start + * the start point in the java longs array to start filling + */ + public native void getLongs(int sa_idx, int nelems, long ja[], int ja_start); + + /** + * @return The lower bounds of the array? + */ + public native int getLBound(); + + /** + * @param dim + * the dimension we are checking in a multidimensional array + * @return The lower bounds of the array? + */ + public native int getLBound(int dim); + + /** + * @return The number of dimensions in this array + */ + public native int getNumDim(); + + /** + * not implemented. + * + * @return 0 + */ + public int getNumLocks() { + return 0; + } + + /** + * short access + * + * @param sa_idx + * @return short stored in array + */ + public native short getShort(int sa_idx); + + /** + * get short value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native short getShort(int indices[]); + + /** + * short access + * + * @param sa_idx1 + * @param sa_idx2 + * @return short stored in array + */ + public native short getShort(int sa_idx1, int sa_idx2); + + /** + * short access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getShorts(int sa_idx, int nelems, short ja[], + int ja_start); + + /** + * string access + * + * @param sa_idx + * @return String stored in array + * + */ + public native String getString(int sa_idx); + + /** + * get String value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native String getString(int indices[]); + + /** + * string access + * + * @param sa_idx1 + * @param sa_idx2 + * @return String stored in array + */ + public native String getString(int sa_idx1, int sa_idx2); + + /** + * string access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getStrings(int sa_idx, int nelems, String ja[], + int ja_start); + + /** + * @return The upper bounds of the array? + */ + public native int getUBound(); + + /** + * @param dim + * the dimension we are checking in a multidimensional array + * @return The upper bounds of the array? + */ + public native int getUBound(int dim); + + /** + * variant access + * + * @param sa_idx + * @return Variant held in location in the array? + */ + public native Variant getVariant(int sa_idx); + + /** + * get Variant value from N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @return the value at the specified location + */ + public native Variant getVariant(int indices[]); + + /** + * variant access + * + * @param sa_idx1 + * @param sa_idx2 + * @return Variant held in a location in the array? + */ + public native Variant getVariant(int sa_idx1, int sa_idx2); + + /** + * variant access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void getVariants(int sa_idx, int nelems, Variant ja[], + int ja_start); + + /** + * @return the Variant type + */ + public native int getvt(); + + protected native void init(int vt, int lbounds[], int celems[]); + + /** + * Does anyone want to document this? + * + * @param sa + */ + public native void reinit(SafeArray sa); + + /** + * Does anyone want to document this? + * + * @param vt + * the variant type? + */ + public native void reinterpretType(int vt); + + /** + * {@inheritDoc} + */ + public void safeRelease() { + super.safeRelease(); + if (m_pV != 0) { + destroy(); + m_pV = 0; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug(this.getClass().getName() + ":" + this.hashCode() + + " double release"); + } + } + } + + /** + * boolean access + * + * @param sa_idx + * @param c + */ + public native void setBoolean(int sa_idx, boolean c); + + /** + * set boolean value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setBoolean(int indices[], boolean c); + + /** + * boolean access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setBoolean(int sa_idx1, int sa_idx2, boolean c); + + /** + * boolean access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setBooleans(int sa_idx, int nelems, boolean ja[], + int ja_start); + + /** + * byte access + * + * @param sa_idx + * @param c + */ + public native void setByte(int sa_idx, byte c); + + /** + * set byte value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setByte(int indices[], byte c); + + /** + * byte access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setByte(int sa_idx1, int sa_idx2, byte c); + + /** + * fills array with passed in bytes + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setBytes(int sa_idx, int nelems, byte ja[], int ja_start); + + /** + * char access + * + * @param sa_idx + * @param c + */ + public native void setChar(int sa_idx, char c); + + /** + * set char value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setChar(int indices[], char c); + + /** + * char access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setChar(int sa_idx1, int sa_idx2, char c); + + /** + * char access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setChars(int sa_idx, int nelems, char ja[], int ja_start); + + /** + * double access + * + * @param sa_idx + * @param c + */ + public native void setDouble(int sa_idx, double c); + + /** + * set double value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setDouble(int indices[], double c); + + /** + * double access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setDouble(int sa_idx1, int sa_idx2, double c); + + /** + * double access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setDoubles(int sa_idx, int nelems, double ja[], + int ja_start); + + /** + * float access + * + * @param sa_idx + * @param c + */ + public native void setFloat(int sa_idx, float c); + + /** + * set float value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setFloat(int indices[], float c); + + /** + * float access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setFloat(int sa_idx1, int sa_idx2, float c); + + /** + * float access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setFloats(int sa_idx, int nelems, float ja[], + int ja_start); + + /** + * sets the int value of an element in a single dimensional array + * + * @param sa_idx + * index into the array + * @param c + * the value to be set + */ + public native void setInt(int sa_idx, int c); + + /** + * set int value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setInt(int indices[], int c); + + /** + * sets the int value of a 2 dimensional array + * + * @param sa_idx1 + * index on the first dimension + * @param sa_idx2 + * index on the second dimension + * @param c + * the value to be set + */ + public native void setInt(int sa_idx1, int sa_idx2, int c); + + /** + * sets a group of ints into a single dimensional array + * + * @param sa_idx + * the index of the start of the array to put into + * @param nelems + * number of elements to be copied + * @param ja + * the new int values to be put into the array + * @param ja_start + * the start index in the array that we are copying into + * SafeArray + */ + public native void setInts(int sa_idx, int nelems, int ja[], int ja_start); + + /** + * sets the long value of an element in a single dimensional array + * + * @param sa_idx + * index into the array + * @param c + * the value to be set + */ + public native void setLong(int sa_idx, long c); + + /** + * set long value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setLong(int indices[], long c); + + /** + * sets the long value of a 2 dimensional array + * + * @param sa_idx1 + * index on the first dimension + * @param sa_idx2 + * index on the second dimension + * @param c + * the value to be set + */ + public native void setLong(int sa_idx1, int sa_idx2, long c); + + /** + * sets a group of longs into a single dimensional array + * + * @param sa_idx + * the index of the start of the array to put into + * @param nelems + * number of elements to be copied + * @param ja + * the new long values to be put into the array + * @param ja_start + * the start index in the array that we are copying into + * SafeArray + */ + public native void setLongs(int sa_idx, int nelems, long ja[], int ja_start); + + /** + * short access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setShort(int sa_idx1, int sa_idx2, short c); + + /** + * short access + * + * @param sa_idx + * @param c + */ + public native void setShort(int sa_idx, short c); + + /** + * set short value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setShort(int indices[], short c); + + /** + * short access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setShorts(int sa_idx, int nelems, short ja[], + int ja_start); + + /** + * puts a string into an element in a two dimensional array. + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setString(int sa_idx1, int sa_idx2, String c); + + /* + * ================================================================ The + * beginning of N-dimensional array support + * ================================================================ + */ + + /** + * puts a string into an element in a single dimensional safe array + * + * @param sa_idx + * @param c + */ + public native void setString(int sa_idx, String c); + + /** + * set Stringvalue in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param c + */ + public native void setString(int indices[], String c); + + /** + * string access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setStrings(int sa_idx, int nelems, String ja[], + int ja_start); + + /** + * variant access + * + * @param sa_idx1 + * @param sa_idx2 + * @param c + */ + public native void setVariant(int sa_idx1, int sa_idx2, Variant c); + + /** + * variant access + * + * @param sa_idx + * @param c + */ + public native void setVariant(int sa_idx, Variant c); + + /** + * set Variant value in N-dimensional array + * + * @param indices - + * length must equal Dimension of SafeArray + * @param v + */ + public native void setVariant(int indices[], Variant v); + + /** + * variant access + * + * @param sa_idx + * @param nelems + * @param ja + * @param ja_start + */ + public native void setVariants(int sa_idx, int nelems, Variant ja[], + int ja_start); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return boolean[] array of booleans contained in this collection + */ + public native boolean[] toBooleanArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return byte[] byte array contained in this collection + */ + public native byte[] toByteArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return char[] character array contained in this collection + */ + public native char[] toCharArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return double[] double array contained in this collection + */ + public native double[] toDoubleArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return float[] array of float contained in this collection + */ + public native float[] toFloatArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return int[] int array contained in this collection + */ + public native int[] toIntArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return long[] long array contained in this collection + */ + public native long[] toLongArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return short[] short array contained in this collection + */ + public native short[] toShortArray(); + + /** + * Standard toString() Warning, this creates new Variant objects! + * + * @return String contents of variant + */ + public String toString() { + String s = ""; + int ndim = getNumDim(); + if (ndim == 1) { + int ldim = getLBound(); + int udim = getUBound(); + for (int i = ldim; i <= udim; i++) { + Variant v = getVariant(i); + + if (((v.getvt() & Variant.VariantTypeMask) | Variant.VariantArray) == v + .getvt()) { + return s + "[" + v.toSafeArray().toString() + "]"; + } else { + s += " " + v.toString(); + } + } + } else if (ndim == 2) { + int ldim1 = getLBound(1); + int udim1 = getUBound(1); + + int ldim2 = getLBound(2); + int udim2 = getUBound(2); + + for (int i = ldim1; i <= udim1; i++) { + for (int j = ldim2; j <= udim2; j++) { + Variant v = getVariant(i, j); + s += " " + v.toString(); + } + s += "\n"; + } + } + return s; + } + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return String[] String array contained in this collection + */ + public native String[] toStringArray(); + + /** + * Retrieves the data from the array cast to a Java data type + * + * @return Variant[] array of variants contained in this collection + */ + public native Variant[] toVariantArray(); + +} \ No newline at end of file diff --git a/java/src/com/jacob/com/Variant.java b/java/src/com/jacob/com/Variant.java new file mode 100644 index 0000000..9aafac3 --- /dev/null +++ b/java/src/com/jacob/com/Variant.java @@ -0,0 +1,2235 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * The multi-format data type used for all call backs and most communications + * between Java and COM. It provides a single class that can handle all data + * types. + *

+ * Just loading this class creates 3 variants that get added to the ROT + *

+ * PROPVARIANT introduces new types so eventually Variant will need to be + * upgraded to support PropVariant types. + * http://blogs.msdn.com/benkaras/archive/2006/09/13/749962.aspx + *

+ * This object no longer implements Serializable because serialization is broken + * (and has been since 2000/xp). The underlying marshalling/unmarshalling code + * is broken in the JNI layer. + */ +public class Variant extends JacobObject { + + /** + * Use this constant for optional parameters + */ + public final static com.jacob.com.Variant DEFAULT; + + /** + * Same than {@link #DEFAULT} + */ + public final static com.jacob.com.Variant VT_MISSING; + + /** + * Use for true/false variant parameters + */ + public final static com.jacob.com.Variant VT_TRUE = new com.jacob.com.Variant( + true); + + /** + * Use for true/false variant parameters + */ + public final static com.jacob.com.Variant VT_FALSE = new com.jacob.com.Variant( + false); + + /** variant's type is empty : equivalent to VB Nothing and VT_EMPTY */ + public static final short VariantEmpty = 0; + + /** variant's type is null : equivalent to VB Null and VT_NULL */ + public static final short VariantNull = 1; + + /** variant's type is short VT_I2 */ + public static final short VariantShort = 2; + + /** variant's type is int VT_I4, a Long in VC */ + public static final short VariantInt = 3; + + /** variant's type is float VT_R4 */ + public static final short VariantFloat = 4; + + /** variant's type is double VT_R8 */ + public static final short VariantDouble = 5; + + /** variant's type is currency VT_CY */ + public static final short VariantCurrency = 6; + + /** variant's type is date VT_DATE */ + public static final short VariantDate = 7; + + /** variant's type is string also known as VT_BSTR */ + public static final short VariantString = 8; + + /** variant's type is dispatch VT_DISPATCH */ + public static final short VariantDispatch = 9; + + /** variant's type is error VT_ERROR */ + public static final short VariantError = 10; + + /** variant's type is boolean VT_BOOL */ + public static final short VariantBoolean = 11; + + /** variant's type is variant it encapsulate another variant VT_VARIANT */ + public static final short VariantVariant = 12; + + /** variant's type is object VT_UNKNOWN */ + public static final short VariantObject = 13; + + /** variant's type is object VT_DECIMAL */ + public static final short VariantDecimal = 14; + + // VT_I1 = 16 + + /** variant's type is byte VT_UI1 */ + public static final short VariantByte = 17; + + // VT_UI2 = 18 + // VT_UI4 = 19 + + /** + * variant's type is 64 bit long integer VT_I8 - not yet implemented in + * Jacob because we have to decide what to do with Currency and because its + * only supported on XP and later. No win2k, NT or 2003 server. + */ + public static final short VariantLongInt = 20; + + // VT_UI8 = 21 + // VT_INT = 22 + // VT_UNIT = 23 + // VT_VOID = 24 + // VT_HRESULT = 25 + + /** + * This value is for reference only and is not to be used by any callers + */ + public static final short VariantPointer = 26; + + // VT_SAFEARRAY = 27 + // VT_CARRARY = 28 + // VT_USERDEFINED = 29 + + /** what is this? VT_TYPEMASK && VT_BSTR_BLOB 0xfff */ + public static final short VariantTypeMask = 4095; + + /** variant's type is array VT_ARRAY 0x2000 */ + public static final short VariantArray = 8192; + + /** variant's type is a reference (to IDispatch?) VT_BYREF 0x4000 */ + public static final short VariantByref = 16384; + + /* + * Do the run time definition of DEFAULT and MISSING. Have to use static + * block because of the way the initialization is done via two calls instead + * of just a constructor for this type. + */ + static { + com.jacob.com.Variant vtMissing = new com.jacob.com.Variant(); + vtMissing.putVariantNoParam(); + DEFAULT = vtMissing; + VT_MISSING = vtMissing; + } + + /** + * Pointer to MS struct. + */ + int m_pVariant = 0; + + /** + * public constructor, initializes and sets type to VariantEmpty + */ + public Variant() { + this(null, false); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(boolean in) { + this(new Boolean(in)); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(byte in) { + this(new Byte(in)); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(double in) { + this(new Double(in)); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(float in) { + this(new Float(in)); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(int in) { + this(new Integer(in)); + }; + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(long in) { + this(new Long(in)); + } + + /** + * Convenience constructor that calls the main one with a byRef value of + * false + * + * @param in + * object to be made into variant + */ + public Variant(Object in) { + this(in, false); + } + + /** + * Constructor that accepts the data object and information about whether + * this is by reference or not. It calls the JavaVariantConverter to + * actually push the data into the newly created Variant. + * + * @param pValueObject + * The value object that will pushed down into windows memory. A + * null object sets this to "empty" + * @param fByRef + */ + public Variant(Object pValueObject, boolean fByRef) { + init(); + VariantUtilities.populateVariant(this, pValueObject, fByRef); + } + + /** + * Constructor that accepts a primitive rather than an object + * + * @param in + */ + public Variant(short in) { + this(new Short(in)); + } + + /** + * Cover for native method so we can cover it. + *

+ * This cannot convert an object to a byRef. It can convert from byref to + * not byref + * + * @param in + * type to convert this variant too + * @return Variant returns this same object so folks can change when + * replacing calls toXXX() with changeType().getXXX() + */ + public Variant changeType(short in) { + changeVariantType(in); + return this; + } + + /** + * Converts variant to the passed in type by converting the underlying + * windows variant structure. private so folks use public java method + * + * @param in + * the desired resulting type + */ + private native void changeVariantType(short in); + + /** + * this returns null + * + * @return ?? comment says null? + */ + @Override + public native Object clone(); + + /** + * @deprecated No longer used + * @return null ! + */ + @Deprecated + public native Variant cloneIndirect(); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + @Override + protected void finalize() { + safeRelease(); + } + + /** + * + * @return returns the value as a boolean, throws an exception if its not. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public boolean getBoolean() { + if (this.getvt() == VariantBoolean) { + return getVariantBoolean(); + } else { + throw new IllegalStateException( + "getBoolean() only legal on Variants of type VariantBoolean, not " + + this.getvt()); + } + } + + /** + * public cover for native method + * + * @return the boolean from a booleanRef + * @throws IllegalStateException + * if variant is not of the requested type + */ + public boolean getBooleanRef() { + if ((this.getvt() & VariantTypeMask) == VariantBoolean + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantBooleanRef(); + } else { + throw new IllegalStateException( + "getBooleanRef() only legal on byRef Variants of type VariantBoolean, not " + + this.getvt()); + } + } + + /** + * + * @return returns the value as a boolean, throws an exception if its not. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public byte getByte() { + if (this.getvt() == VariantByte) { + return getVariantByte(); + } else { + throw new IllegalStateException( + "getByte() only legal on Variants of type VariantByte, not " + + this.getvt()); + } + } + + /** + * public cover for native method + * + * @return the byte from a booleanRef + * @throws IllegalStateException + * if variant is not of the requested type + */ + public byte getByteRef() { + if ((this.getvt() & VariantTypeMask) == VariantByte + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantByteRef(); + } else { + throw new IllegalStateException( + "getByteRef() only legal on byRef Variants of type VariantByte, not " + + this.getvt()); + } + } + + /** + * MS Currency objects are 64 bit fixed point numbers with 15 digits to the + * left and 4 to the right of the decimal place. + * + * @return returns the currency value as a long, throws exception if not a + * currency type.. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public Currency getCurrency() { + if (this.getvt() == VariantCurrency) { + return new Currency(getVariantCurrency()); + } else { + throw new IllegalStateException( + "getCurrency() only legal on Variants of type VariantCurrency, not " + + this.getvt()); + } + } + + /** + * MS Currency objects are 64 bit fixed point numbers with 15 digits to the + * left and 4 to the right of the decimal place. + * + * @return returns the currency value as a long, throws exception if not a + * currency type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public Currency getCurrencyRef() { + if ((this.getvt() & VariantTypeMask) == VariantCurrency + && (this.getvt() & VariantByref) == VariantByref) { + return new Currency(getVariantCurrencyRef()); + } else { + throw new IllegalStateException( + "getCurrencyRef() only legal on byRef Variants of type VariantCurrency, not " + + this.getvt()); + } + } + + /** + * @return double return the date (as a double) value held in this variant + * (fails on other types?) + * @throws IllegalStateException + * if variant is not of the requested type + */ + public double getDate() { + if (this.getvt() == VariantDate) { + return getVariantDate(); + } else { + throw new IllegalStateException( + "getDate() only legal on Variants of type VariantDate, not " + + this.getvt()); + } + } + + /** + * + * @return returns the date value as a double, throws exception if not a + * date type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public double getDateRef() { + if ((this.getvt() & VariantTypeMask) == VariantDate + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantDateRef(); + } else { + throw new IllegalStateException( + "getDateRef() only legal on byRef Variants of type VariantDate, not " + + this.getvt()); + } + } + + /** + * return the BigDecimal value held in this variant (fails on other types) + * + * @return BigDecimal + * @throws IllegalStateException + * if variant is not of the requested type + */ + public BigDecimal getDecimal() { + if (this.getvt() == VariantDecimal) { + return (BigDecimal) (getVariantDec()); + } else { + throw new IllegalStateException( + "getDecimal() only legal on Variants of type VariantDecimal, not " + + this.getvt()); + } + } + + /** + * return the BigDecimal value held in this variant (fails on other types) + * + * @return BigDecimal + * @throws IllegalStateException + * if variant is not of the requested type + */ + public BigDecimal getDecimalRef() { + if ((this.getvt() & VariantTypeMask) == VariantDecimal + && (this.getvt() & VariantByref) == VariantByref) { + return (BigDecimal) (getVariantDecRef()); + } else { + throw new IllegalStateException( + "getDecimalRef() only legal on byRef Variants of type VariantDecimal, not " + + this.getvt()); + } + } + + /** + * cover for {@link #toDispatch()} This method now matches other getXXX() + * methods. It throws an IllegalStateException if the object is not of type + * VariantDispatch + * + * @return this object as a dispatch + * @throws IllegalStateException + * if wrong variant type + */ + public Dispatch getDispatch() { + if (this.getvt() == VariantDispatch) { + return toDispatch(); + } else { + throw new IllegalStateException( + "getDispatch() only legal on Variants of type VariantDispatch, not " + + this.getvt()); + } + } + + /** + * Dispatch and dispatchRef are treated the same This is just a cover for + * toDispatch() with a flag check + * + * @return the results of toDispatch() + * @throws IllegalStateException + * if variant is not of the requested type + */ + public Dispatch getDispatchRef() { + if ((this.getvt() & VariantTypeMask) == VariantDispatch + && (this.getvt() & VariantByref) == VariantByref) { + return toDispatch(); + } else { + throw new IllegalStateException( + "getDispatchRef() only legal on byRef Variants of type VariantDispatch, not " + + this.getvt()); + } + } + + /** + * @return double return the double value held in this variant (fails on + * other types?) + * @throws IllegalStateException + * if variant is not of the requested type + */ + public double getDouble() { + if (this.getvt() == VariantDouble) { + return getVariantDouble(); + } else { + throw new IllegalStateException( + "getDouble() only legal on Variants of type VariantDouble, not " + + this.getvt()); + } + } + + /** + * + * @return returns the double value, throws exception if not a Double type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public double getDoubleRef() { + if ((this.getvt() & VariantTypeMask) == VariantDouble + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantDoubleRef(); + } else { + throw new IllegalStateException( + "getDoubleRef() only legal on byRef Variants of type VariantDouble, not " + + this.getvt()); + } + } + + /** + * Pointless method that was put here so that putEmpty() has a get method. + * This would have returned null if the value was VT_EMPTY or if it wasn't + * so it would have always returned the same value. + * + * @deprecated method never did anything + */ + @Deprecated + public void getEmpty() { + } + + /** + * @return double return the error value held in this variant (fails on + * other types?) + * @throws IllegalStateException + * if variant is not of the requested type + */ + public int getError() { + if (this.getvt() == VariantError) { + return getVariantError(); + } else { + throw new IllegalStateException( + "getError() only legal on Variants of type VariantError, not " + + this.getvt()); + } + } + + /** + * + * @return returns the error value as an int, throws exception if not a + * Error type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public int getErrorRef() { + if ((this.getvt() & VariantTypeMask) == VariantError + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantErrorRef(); + } else { + throw new IllegalStateException( + "getErrorRef() only legal on byRef Variants of type VariantError, not " + + this.getvt()); + } + } + + /** + * @return returns the value as a float if the type is of type float + * @throws IllegalStateException + * if variant is not of the requested type + */ + public float getFloat() { + if (this.getvt() == VariantFloat) { + return getVariantFloat(); + } else { + throw new IllegalStateException( + "getFloat() only legal on Variants of type VariantFloat, not " + + this.getvt()); + } + } + + /** + * + * @return returns the float value, throws exception if not a Float type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public float getFloatRef() { + if ((this.getvt() & VariantTypeMask) == VariantFloat + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantFloatRef(); + } else { + throw new IllegalStateException( + "getFloatRef() only legal on byRef Variants of type VariantFloat, not " + + this.getvt()); + } + } + + /** + * return the int value held in this variant if it is an int or a short. + * Throws for other types. + * + * @return int contents of the windows memory + * @throws IllegalStateException + * if variant is not of the requested type + */ + public int getInt() { + if (this.getvt() == VariantInt) { + return getVariantInt(); + } else if (this.getvt() == VariantShort) { + return getVariantShort(); + } else { + throw new IllegalStateException( + "getInt() only legal on Variants of type VariantInt, not " + + this.getvt()); + } + } + + /** + * get the content of this variant as an int + * + * @return int + * @throws IllegalStateException + * if variant is not of the requested type + */ + public int getIntRef() { + if ((this.getvt() & VariantTypeMask) == VariantInt + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantIntRef(); + } else { + throw new IllegalStateException( + "getIntRef() only legal on byRef Variants of type VariantInt, not " + + this.getvt()); + } + } + + /** + * returns the windows time contained in this Variant to a Java Date. should + * return null if this is not a date Variant SF 959382 + * + * @return java.util.Date returns the date if this is a VariantDate != 0, + * null if it is a VariantDate == 0 and throws an + * IllegalStateException if this isn't a date. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public Date getJavaDate() { + Date returnDate = null; + if (getvt() == VariantDate) { + double windowsDate = getDate(); + if (windowsDate != 0) { + returnDate = DateUtilities.convertWindowsTimeToDate(getDate()); + } + } else { + throw new IllegalStateException( + "getJavaDate() only legal on Variants of type VariantDate, not " + + this.getvt()); + } + return returnDate; + } + + /** + * returns the windows time contained in this Variant to a Java Date should + * return null if this is not a date reference Variant SF 959382 + * + * @return java.util.Date + */ + public Date getJavaDateRef() { + double windowsDate = getDateRef(); + if (windowsDate == 0) { + return null; + } else { + return DateUtilities.convertWindowsTimeToDate(windowsDate); + } + } + + /** + * 64 bit Longs only available on x64. 64 bit long support added 1.14 + * + * @return returns the value as a long, throws exception if not a Long + * type.. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public long getLong() { + if (this.getvt() == VariantLongInt) { + return getVariantLong(); + } else { + throw new IllegalStateException( + "getLong() only legal on Variants of type VariantLongInt, not " + + this.getvt()); + } + } + + /** + * 64 bit Longs only available on x64. 64 bit long support added 1.14 + * + * @return returns the value as a long, throws exception if not a long type + * @throws IllegalStateException + * if variant is not of the requested type + */ + public long getLongRef() { + if ((this.getvt() & VariantTypeMask) == VariantLongInt + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantLongRef(); + } else { + throw new IllegalStateException( + "getLongRef() only legal on byRef Variants of type VariantLongInt, not " + + this.getvt()); + } + } + + /** + * This method would have returned null if the type was VT_NULL. But because + * we return null if the data is not of the right type, this method should + * have always returned null + * + * @deprecated method never did anything + */ + @Deprecated + public void getNull() { + } + + /** + * return the int value held in this variant (fails on other types?) + * + * @return int + * @throws IllegalStateException + * if variant is not of the requested type + */ + public short getShort() { + if (this.getvt() == VariantShort) { + return getVariantShort(); + } else { + throw new IllegalStateException( + "getShort() only legal on Variants of type VariantShort, not " + + this.getvt()); + } + } + + /** + * get the content of this variant as an int + * + * @return int + * @throws IllegalStateException + * if variant is not of the requested type + */ + public short getShortRef() { + if ((this.getvt() & VariantTypeMask) == VariantShort + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantShortRef(); + } else { + throw new IllegalStateException( + "getShortRef() only legal on byRef Variants of type VariantShort, not " + + this.getvt()); + } + } + + /** + * + * @return string contents of the variant. + * @throws IllegalStateException + * if this variant is not of type String + */ + public String getString() { + if (getvt() == Variant.VariantString) { + return getVariantString(); + } else { + throw new IllegalStateException( + "getString() only legal on Variants of type VariantString, not " + + this.getvt()); + } + } + + /** + * gets the content of the variant as a string ref + * + * @return String retrieved from the COM area. + * @throws IllegalStateException + * if variant is not of the requested type + */ + public String getStringRef() { + if ((this.getvt() & VariantTypeMask) == VariantString + && (this.getvt() & VariantByref) == VariantByref) { + return getVariantStringRef(); + } else { + throw new IllegalStateException( + "getStringRef() only legal on byRef Variants of type VariantString, not " + + this.getvt()); + } + } + + /** + * Used to get the value from a windows type of VT_VARIANT or a jacob + * Variant type of VariantVariant. Added 1.12 pre 6 - VT_VARIANT support is + * at an alpha level + * + * @return Object a java Object that represents the content of the enclosed + * Variant + */ + public Object getVariant() { + if ((this.getvt() & VariantTypeMask) == VariantVariant + && (this.getvt() & VariantByref) == VariantByref) { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("About to call getVariantVariant()"); + } + Variant enclosedVariant = new Variant(); + int enclosedVariantMemory = getVariantVariant(); + enclosedVariant.m_pVariant = enclosedVariantMemory; + Object enclosedVariantAsJava = enclosedVariant.toJavaObject(); + // zero out the reference to the underlying windows memory so that + // it is still only owned in one place by one java object + // (this object of type VariantVariant) + // enclosedVariant.putEmpty(); // don't know if this would have had + // side effects + if (JacobObject.isDebugEnabled()) { + JacobObject + .debug("Zeroing out enclosed Variant's ref to windows memory"); + } + enclosedVariant.m_pVariant = 0; + return enclosedVariantAsJava; + } else { + throw new IllegalStateException( + "getVariant() only legal on Variants of type VariantVariant, not " + + this.getvt()); + } + } + + /** + * @deprecated superseded by SafeArray + * @return never returns anything + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public Variant[] getVariantArray() { + throw new NotImplementedException("Not implemented"); + } + + /** + * @return the Variant Array that represents the data in the Variant + * @deprecated superseded by SafeArray + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public Variant[] getVariantArrayRef() { + throw new NotImplementedException("Not implemented"); + } + + /** + * + * @return the value in this Variant as a boolean, null if not a boolean + */ + private native boolean getVariantBoolean(); + + private native boolean getVariantBooleanRef(); + + /** + * @return the value in this Variant as a byte, null if not a byte + */ + private native byte getVariantByte(); + + /** + * @return the value in this Variant as a byte, null if not a byte + */ + private native byte getVariantByteRef(); + + /** + * @return the value in this Variant as a long, null if not a long + */ + private native long getVariantCurrency(); + + /** + * @return the value in this Variant as a long, null if not a long + */ + private native long getVariantCurrencyRef(); + + /** + * @return double return the date (as a double) value held in this variant + * (fails on other types?) + */ + private native double getVariantDate(); + + /** + * get the content of this variant as a double representing a date + * + * @return double + */ + private native double getVariantDateRef(); + + /** + * @return the value in this Variant as a decimal, null if not a decimal + */ + private native Object getVariantDec(); + + /** + * @return the value in this Variant (byref) as a decimal, null if not a + * decimal + */ + private native Object getVariantDecRef(); + + /** + * @return double get the content of this variant as a double + */ + private native double getVariantDouble(); + + /** + * @return double get the content of this variant as a double + */ + private native double getVariantDoubleRef(); + + private native int getVariantError(); + + private native int getVariantErrorRef(); + + /** + * @return returns the value as a float if the type is of type float + */ + private native float getVariantFloat(); + + /** + * @return returns the value as a float if the type is of type float + */ + private native float getVariantFloatRef(); + + /** + * @return the int value held in this variant (fails on other types?) + */ + private native int getVariantInt(); + + /** + * @return the int value held in this variant (fails on other types?) + */ + private native int getVariantIntRef(); + + /** + * @return the value in this Variant as a long, null if not a long + */ + private native long getVariantLong(); + + /** + * @return the value in this Variant as a long, null if not a long + */ + private native long getVariantLongRef(); + + /** + * get the content of this variant as a short + * + * @return short + */ + private native short getVariantShort(); + + /** + * @return short the content of this variant as a short + */ + private native short getVariantShortRef(); + + /** + * Native method that actually extracts a string value from the variant + * + * @return + */ + private native String getVariantString(); + + /** + * @return String the content of this variant as a string + */ + private native String getVariantStringRef(); + + /** + * Returns the variant type via a native method call + * + * @return short one of the VT_xx types + */ + private native short getVariantType(); + + /** + * Returns the variant type via a native method call. Added 1.12 pre 6 - + * VT_VARIANT support is at an alpha level + * + * @return Variant one of the VT_Variant types + */ + private native int getVariantVariant(); + + /** + * Reports the type of the underlying Variant object + * + * @return returns the variant type as a short, one of the Variantxxx values + * defined as statics in this class. returns VariantNull if not + * initialized + * @throws IllegalStateException + * if there is no underlying windows data structure + */ + public short getvt() { + if (m_pVariant != 0) { + return getVariantType(); + } else { + throw new IllegalStateException("uninitialized Variant"); + } + } + + /** + * initializes the COM Variant and puts its reference in this instance + */ + protected native void init(); + + /** + * + * @return returns true if the variant is considered null + * @throws IllegalStateException + * if there is no underlying windows memory + */ + public boolean isNull() { + getvt(); + return isVariantConsideredNull(); + } + + /** + * is the variant null or empty or error or null dispatch + * + * @return true if it is null or false if not + */ + private native boolean isVariantConsideredNull(); + + /** + * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND + * + * @deprecated replaced by putNoParam() + */ + @Deprecated + public void noParam() { + putNoParam(); + } + + /** + * returns true if the passed in Variant is a constant that should not be + * freed + * + * @param pVariant + * @return boolean that is true if Variant is a type of constant, VT_FALSE, + * VT_TRUE, VT_MISSING, DEFAULT + */ + protected boolean objectIsAConstant(Variant pVariant) { + if (pVariant == VT_FALSE || pVariant == VT_TRUE + || pVariant == VT_MISSING || pVariant == DEFAULT) { + return true; + } else { + return false; + } + + } + + /** + * puts a boolean into the variant and sets it's type + * + * @param in + * the new value + */ + public void putBoolean(boolean in) { + // verify we aren't released yet + getvt(); + putVariantBoolean(in); + } + + /** + * pushes a boolean into the variant by ref and sets the type of the variant + * to boolean + * + * @param in + */ + public void putBooleanRef(boolean in) { + // verify we aren't released yet + getvt(); + putVariantBooleanRef(in); + } + + /** + * pushes a byte into the varaint and sets the type + * + * @param in + */ + public void putByte(byte in) { + // verify we aren't released yet + getvt(); + putVariantByte(in); + }; + + /** + * @deprecated superseded by SafeArray + * @param in + * doesn't matter because this method does nothing + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public void putByteArray(Object in) { + throw new NotImplementedException("Not implemented"); + } + + /** + * pushes a byte into the variant by ref and sets the type + * + * @param in + */ + public void putByteRef(byte in) { + // verify we aren't released yet + getvt(); + putVariantByteRef(in); + } + + /** + * @param in + * the object that would be wrapped by the Variant if this method + * was implemented + * @deprecated superseded by SafeArray + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public void putCharArray(Object in) { + throw new NotImplementedException("Not implemented"); + } + + /** + * Puts a value in as a currency and sets the variant type. MS Currency + * objects are 64 bit fixed point numbers with 15 digits to the left and 4 + * to the right of the decimal place. + * + * @param in + * the long that will be put into the 64 bit currency object. + */ + public void putCurrency(Currency in) { + // verify we aren't released yet + getvt(); + putVariantCurrency(in.longValue()); + } + + /** + * Pushes a long into the variant as currency and sets the type. MS Currency + * objects are 64 bit fixed point numbers with 15 digits to the left and 4 + * to the right of the decimal place. + * + * @param in + * the long that will be put into the 64 bit currency object + */ + public void putCurrencyRef(Currency in) { + // verify we aren't released yet + getvt(); + putVariantCurrencyRef(in.longValue()); + } + + /** + * converts a java date to a windows time and calls putDate(double) SF + * 959382 + * + * @param inDate + * a Java date to be converted + * @throws IllegalArgumentException + * if inDate = null + */ + public void putDate(Date inDate) { + if (inDate == null) { + throw new IllegalArgumentException( + "Cannot put null in as windows date"); + // do nothing + } else { + putDate(DateUtilities.convertDateToWindowsTime(inDate)); + } + } + + /** + * puts a windows date double into the variant and sets the type + * + * @param in + */ + public void putDate(double in) { + // verify we aren't released yet + getvt(); + putVariantDate(in); + } + + /** + * converts a java date to a windows time and calls putDateRef(double) SF + * 959382 + * + * @param inDate + * a Java date to be converted + * @throws IllegalArgumentException + * if inDate = null + */ + public void putDateRef(Date inDate) { + if (inDate == null) { + throw new IllegalArgumentException( + "Cannot put null in as windows date"); + // do nothing + } else { + putDateRef(DateUtilities.convertDateToWindowsTime(inDate)); + } + } + + /** + * set the content of this variant to a date (VT_DATE|VT_BYREF) + * + * @param in + */ + public void putDateRef(double in) { + // verify we aren't released + getvt(); + putVariantDateRef(in); + } + + /** + * This actual does all the validating and massaging of the BigDecimalValues + * when converting them to MS Decimal types + * + * @param in + * number to be made into VT_DECIMAL + * @param byRef + * store by reference or not + * @param roundingBehavior + * one of the BigDecimal ROUND_xxx methods. Any method other than + * ROUND_UNECESSARY means that the value will be rounded to fit + */ + private void putDecimal(BigDecimal in, boolean byRef) { + // verify we aren't released + getvt(); + // first validate the min and max + VariantUtilities.validateDecimalMinMax(in); + BigInteger allWordBigInt; + allWordBigInt = in.unscaledValue(); + // Assume any required rounding has been done. + VariantUtilities.validateDecimalScaleAndBits(in); + // finally we can do what we actually came here to do + int sign = in.signum(); + // VT_DECIMAL always has positive value with just the sign + // flipped + if (in.signum() < 0) { + in = in.negate(); + } + // ugh, reusing allWordBigInt but now should always be positive + // and any round is applied + allWordBigInt = in.unscaledValue(); + byte scale = (byte) in.scale(); + int lowWord = allWordBigInt.intValue(); + BigInteger middleWordBigInt = allWordBigInt.shiftRight(32); + int middleWord = middleWordBigInt.intValue(); + BigInteger highWordBigInt = allWordBigInt.shiftRight(64); + int highWord = highWordBigInt.intValue(); + if (byRef) { + putVariantDecRef(sign, scale, lowWord, middleWord, highWord); + } else { + putVariantDec(sign, scale, lowWord, middleWord, highWord); + } + } + + /** + * EXPERIMENTAL 1.14 feature to support rounded decimals. + *

+ * Set the value of this variant and set the type. This may throw exceptions + * more often than the caller expects because most callers don't manage the + * scale of their BigDecimal objects. + *

+ * This default set method throws exceptions if precision or size is out of + * bounds + *

+ * There are 12 bytes available for the integer number. + *

+ * There is 1 byte for the scale. + * + * @param in + * the BigDecimal that will be converted to VT_DECIMAL + * @throws IllegalArgumentException + * if the scale is > 28, the maximum for VT_DECIMAL or if there + * are more than 12 bytes worth the digits + */ + public void putDecimal(BigDecimal in) { + putDecimal(in, false); + } + + /** + * Set the value of this variant and set the type. This may throw exceptions + * more often than the caller expects because most callers don't manage the + * scale of their BigDecimal objects. + *

+ * This default set method throws exceptions if precision or size is out of + * bounds + *

+ * There are 12 bytes available for the integer number. + *

+ * There is 1 byte for the scale. + * + * @param in + * the BigDecimal that will be converted to VT_DECIMAL + * @throws IllegalArgumentException + * if the scale is > 28, the maximum for VT_DECIMAL or if there + * are more than 12 bytes worth the digits + */ + public void putDecimalRef(BigDecimal in) { + putDecimal(in, true); + } + + /** + * This acts a cover for putVariant Dispatch. + * + * @param in + * the Dispatch we're putting down in the COM variant space. + */ + public void putDispatch(Dispatch in) { + putVariantDispatch(in); + } + + /** + * Dispatch and dispatchRef are treated the same This is a cover for + * putVariantDispatch(). putDispatch and putDispatchRef are treated the same + * because no one has written the COM code for putDispatchRef. + * + * @param in + * the Dispatch we're putting down in the COM variant space. + */ + public void putDispatchRef(Dispatch in) { + putVariantDispatch(in); + } + + /** + * wraps this Variant around the passed in double. + * + * @param in + */ + public void putDouble(double in) { + // verify we aren't released yet + getvt(); + putVariantDouble(in); + } + + /** + * set the content of this variant to a double (VT_R8|VT_BYREF) + * + * @param in + */ + public void putDoubleRef(double in) { + // verify we aren't released + getvt(); + putVariantDoubleRef(in); + } + + /** + * sets the type to VariantEmpty + * + */ + public void putEmpty() { + // verify we aren't released yet + getvt(); + putVariantEmpty(); + } + + /** + * puts an error code (I think) into the variant and sets the type + * + * @param in + */ + public void putError(int in) { + // verify we aren't released yet + getvt(); + putVariantError(in); + } + + /** + * pushes an error code into the variant by ref and sets the type + * + * @param in + */ + public void putErrorRef(int in) { + // verify we aren't released yet + getvt(); + putVariantErrorRef(in); + } + + /** + * fills the Variant with a float and sets the type to float + * + * @param in + */ + public void putFloat(float in) { + // verify we haven't been released yet + getvt(); + putVariantFloat(in); + } + + /** + * pushes a float into the variant and sets the type + * + * @param in + */ + public void putFloatRef(float in) { + // verify we aren't released yet + getvt(); + putVariantFloatRef(in); + } + + /** + * set the value of this variant and set the type + * + * @param in + */ + public void putInt(int in) { + // verify we aren't released yet + getvt(); + putVariantInt(in); + } + + /** + * set the content of this variant to an int (VT_I4|VT_BYREF) + * + * @param in + */ + public void putIntRef(int in) { + // verify we aren't released + getvt(); + putVariantIntRef(in); + } + + /** + * Puts a 64 bit Java Long into a 64 bit Variant Long. Only works on x64 + * systems otherwise throws an error. 64 bit long support added 1.14 + * + * @param in + * the long that will be put into the 64 bit Long object. + */ + public void putLong(long in) { + // verify we aren't released yet + getvt(); + putVariantLong(in); + } + + /** + * Puts a 64 bit Java Long into a 64 bit Variant Long. Only works on x64 + * systems otherwise throws an error. 64 bit long support added 1.14 + * + * @param in + * the long that will be put into the 64 bit Long object. + */ + public void putLongRef(long in) { + // verify we aren't released yet + getvt(); + putVariantLongRef(in); + } + + /** + * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND + */ + public void putNoParam() { + // verify we aren't released yet + getvt(); + putVariantNoParam(); + } + + /** + * Sets the type to VariantDispatch and sets the value to null Equivalent to + * VB's nothing + */ + public void putNothing() { + // verify we aren't released yet + getvt(); + putVariantNothing(); + } + + /** + * Set this Variant's type to VT_NULL (the VB equivalent of NULL) + */ + public void putNull() { + // verify we aren't released yet + getvt(); + putVariantNull(); + } + + /** + * Puts an object into the Variant -- converts to Dispatch. Acts as a cover + * for putVariantDispatch(); This primarily exists to support jacobgen. This + * should be deprecated. + * + * @param in + * the object we are putting into the Variant, assumes a + * @see Variant#putDispatch(Dispatch) + * @deprecated should use putDispatch() + */ + @Deprecated + public void putObject(Object in) { + // this should verify in instanceof Dispatch + putVariantDispatch(in); + } + + /** + * Just a cover for putObject(). We shouldn't accept any old random object. + * This has been left in to support jacobgen. This should be deprecated. + * + * @param in + * @deprecated + */ + @Deprecated + public void putObjectRef(Object in) { + putObject(in); + } + + /** + * have no idea... + * + * @param in + */ + public void putSafeArray(SafeArray in) { + // verify we haven't been released yet + getvt(); + putVariantSafeArray(in); + } + + /** + * have no idea... + * + * @param in + */ + public void putSafeArrayRef(SafeArray in) { + // verify we haven't been released yet + getvt(); + putVariantSafeArrayRef(in); + } + + /** + * set the content of this variant to a short (VT_I2) + * + * @param in + */ + public void putShort(short in) { + // verify we aren't released + getvt(); + putVariantShort(in); + } + + /** + * set the content of this variant to a short (VT_I2|VT_BYREF) + * + * @param in + */ + public void putShortRef(short in) { + // verify we aren't released + getvt(); + putVariantShortRef(in); + } + + /** + * put a string into the variant and set its type + * + * @param in + */ + public void putString(String in) { + // verify we aren't released yet + getvt(); + putVariantString(in); + } + + /** + * set the content of this variant to a string (VT_BSTR|VT_BYREF) + * + * @param in + */ + public void putStringRef(String in) { + // verify we aren't released + getvt(); + putVariantStringRef(in); + } + + /** + * Puts a variant into this variant making it type VT_VARIANT. Added 1.12 + * pre 6 + * + * @param objectToBeWrapped + * A object that is to be referenced by this variant. If + * objectToBeWrapped is already of type Variant, then it is used. + * If objectToBeWrapped is not Variant then + * new Variant(objectToBeWrapped) is called and the + * result is passed into the com layer + * @throws IllegalArgumentException + * if inVariant = null or if inVariant is a Varint + */ + public void putVariant(Object objectToBeWrapped) { + if (objectToBeWrapped == null) { + throw new IllegalArgumentException( + "Cannot put null in as a variant"); + } else if (objectToBeWrapped instanceof Variant) { + throw new IllegalArgumentException( + "Cannot putVariant() only accepts non jacob objects."); + } else { + Variant inVariant = new Variant(objectToBeWrapped); + putVariantVariant(inVariant); + // This could be done in Variant.cpp + if (JacobObject.isDebugEnabled()) { + JacobObject + .debug("Zeroing out enclosed Variant's ref to windows memory"); + } + inVariant.m_pVariant = 0; + } + } + + /** + * @deprecated superseded by SafeArray + * @param in + * doesn't matter because this method does nothing + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public void putVariantArray(Variant[] in) { + throw new NotImplementedException("Not implemented"); + } + + /** + * @param in + * the thing that would be come an array if this method was + * implemented + * @deprecated superseded by SafeArray + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public void putVariantArrayRef(Variant[] in) { + throw new NotImplementedException("Not implemented"); + } + + /** + * puts a boolean into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantBoolean(boolean in); + + /** + * puts a boolean into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantBooleanRef(boolean in); + + /** + * puts a byte into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantByte(byte in); + + /** + * puts a byte into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantByteRef(byte in); + + /** + * puts a Currency into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantCurrency(long in); + + /** + * puts a Currency into the variant and sets it's type + * + * @param in + * the new value + */ + private native void putVariantCurrencyRef(long in); + + /** + * set the value of this variant + * + * @param in + */ + private native void putVariantDate(double in); + + /** + * set the content of this variant to a date (VT_DATE|VT_BYREF) + * + * @param in + */ + private native void putVariantDateRef(double in); + + /** + * private JNI method called by putDecimal + * + * @param signum + * sign + * @param scale + * BigDecimal's scale + * @param lo + * low 32 bits + * @param mid + * middle 32 bits + * @param hi + * high 32 bits + */ + private native void putVariantDec(int signum, byte scale, int lo, int mid, + int hi); + + /** + * private JNI method called by putDecimalRef + * + * @param signum + * sign + * @param scale + * BigDecimal's scale + * @param lo + * low 32 bits + * @param mid + * middle 32 bits + * @param hi + * high 32 bits + */ + private native void putVariantDecRef(int signum, byte scale, int lo, + int mid, int hi); + + /** + * the JNI implementation for putDispatch() so that we can screen the + * incoming dispatches in putDispatch() before this is invoked + * + * @param in + * should be a dispatch object + */ + private native void putVariantDispatch(Object in); + + private native void putVariantDouble(double in); + + /** + * set the content of this variant to a double (VT_R8|VT_BYREF) + * + * @param in + */ + private native void putVariantDoubleRef(double in); + + /** + * Sets the type to VariantEmpty. No values needed + */ + private native void putVariantEmpty(); + + private native void putVariantError(int in); + + private native void putVariantErrorRef(int in); + + /** + * fills the Variant with a float and sets the type to float + * + * @param in + */ + private native void putVariantFloat(float in); + + private native void putVariantFloatRef(float in); + + /** + * set the value of this variant and set the type + * + * @param in + */ + private native void putVariantInt(int in); + + /** + * set the content of this variant to an int (VT_I4|VT_BYREF) + * + * @param in + */ + private native void putVariantIntRef(int in); + + private native void putVariantLong(long in); + + private native void putVariantLongRef(long in); + + /** + * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND + */ + private native void putVariantNoParam(); + + /** + * Sets the type to VariantDispatch and sets the value to null Equivalent to + * VB's nothing + */ + private native void putVariantNothing(); + + /** + * Set this Variant's type to VT_NULL (the VB equivalent of NULL) + */ + private native void putVariantNull(); + + private native void putVariantSafeArray(SafeArray in); + + private native void putVariantSafeArrayRef(SafeArray in); + + /** + * set the content of this variant to a short (VT_I2) + * + * @param in + */ + private native void putVariantShort(short in); + + /** + * set the content of this variant to a short (VT_I2|VT_BYREF) + * + * @param in + */ + private native void putVariantShortRef(short in); + + private native void putVariantString(String in); + + /** + * set the content of this variant to a string (VT_BSTR|VT_BYREF) + * + * @param in + */ + private native void putVariantStringRef(String in); + + /** + * All VariantVariant type variants are BYREF. + * + * Set the content of this variant to a string (VT_VARIANT|VT_BYREF). + * + * Added 1.12 pre 6 - VT_VARIANT support is at an alpha level + * + * @param in + * variant to be wrapped + * + */ + private native void putVariantVariant(Variant in); + + /** + * now private so only this object can access was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + /** + * This will release the "C" memory for the Variant unless this Variant is + * one of the constants in which case we don't want to release the memory. + *

+ * + * @see com.jacob.com.JacobObject#safeRelease() + */ + @Override + public void safeRelease() { + // The well known constants should not be released. + // Unfortunately this doesn't fix any other classes that are + // keeping constants around in their static ivars. + // those will still be busted. + // + // The only inconsistency here is that we leak + // when this class is unloaded because we won't + // free the memory even if the constants are being + // finalized. this is not a big deal at all. + // another way around this would be to create the constants + // in their own thread so that they would never be released + if (!objectIsAConstant(this)) { + super.safeRelease(); + if (m_pVariant != 0) { + release(); + m_pVariant = 0; + } else { + // looks like a double release + // this should almost always happen due to gc + // after someone has called ComThread.Release + if (isDebugEnabled()) { + debug("Variant: " + this.hashCode() + " double release"); + // Throwable x = new Throwable(); + // x.printStackTrace(); + } + } + } else { + if (isDebugEnabled()) { + debug("Variant: " + this.hashCode() + + " don't want to release a constant"); + } + } + } + + /** + * this is supposed to cause the underlying variant object struct to be + * rebuilt from a previously serialized byte array. + * + * @param ba + */ + protected native void SerializationReadFromBytes(byte[] ba); + + /** + * this is supposed to create a byte array that represents the underlying + * variant object structure + */ + protected native byte[] SerializationWriteToBytes(); + + /** + * @deprecated should be replaced by changeType() followed by getBoolean() + * @return the value of this variant as boolean (after possible conversion) + */ + @Deprecated + public boolean toBoolean() { + changeType(Variant.VariantBoolean); + return getBoolean(); + } + + /** + * attempts to return the content of this variant as a double (after + * possible conversion) + * + * @deprecated should be replaced by changeType() followed by getByte() + * @return byte + */ + @Deprecated + public byte toByte() { + changeType(Variant.VariantByte); + return getByte(); + } + + /** + * @deprecated superseded by SafeArray + * @return nothing because this method is not implemented + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public Object toByteArray() { + throw new NotImplementedException("Not implemented"); + } + + /** + * @deprecated superseded by SafeArray + * @return never returns anything + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public Object toCharArray() { + throw new NotImplementedException("Not implemented"); + } + + /** + * @deprecated should be replaced by changeType() followed by getCurrency + * @return the content of this variant as a long representing a monetary + * amount + */ + @Deprecated + public Currency toCurrency() { + changeType(Variant.VariantCurrency); + return getCurrency(); + } + + /** + * @deprecated should use changeType() followed by getDate() + * @return the value of this variant as a date (after possible conversion) + */ + @Deprecated + public double toDate() { + changeType(VariantDate); + return getDate(); + } + + /** + * @return the content of this variant as a Dispatch object (after possible + * conversion) + */ + public Dispatch toDispatch() { + // now make the native call + return toVariantDispatch(); + } + + /** + * @deprecated should call changeType() then getDouble() + * @return the content of this variant as a double (after possible + * conversion) + */ + @Deprecated + public double toDouble() { + changeType(Variant.VariantDouble); + return getDouble(); + } + + /** @return the value of this variant as an enumeration (java style) */ + public native EnumVariant toEnumVariant(); + + /** + * converts to an error type and returns the error + * + * @deprecated should use changeType() followed by getError() + * @return the error as an int (after conversion) + */ + @Deprecated + public int toError() { + changeType(Variant.VariantError); + return getError(); + } + + /** + * attempts to return the contents of this variant as a float (after + * possible conversion) + * + * @deprecated should use changeType() and getFloat() instead + * @return float + */ + @Deprecated + public float toFloat() { + changeType(Variant.VariantFloat); + return getFloat(); + } + + /** + * @deprecated should use changeType() followed by getInt() + * @return the value of this variant as an int (after possible conversion) + */ + @Deprecated + public int toInt() { + changeType(VariantInt); + return getInt(); + } + + /** + * Returns the windows time contained in this Variant as a Java Date + * converts to a date like many of the other toXXX() methods SF 959382. + *

+ * This method added 12/2005 for possible use by jacobgen instead of its + * conversion code + *

+ * This does not convert the data + * + * @deprecated callers should use getDate() + * @return java.util.Date version of this variant if it is a date, otherwise + * null + * + */ + @Deprecated + public Date toJavaDate() { + changeType(Variant.VariantDate); + return getJavaDate(); + } + + /** + * Convert a JACOB Variant value to a Java object (type conversions). + * provided in Sourceforge feature request 959381. See + * JavaVariantConverter..convertVariantTJavaObject(Variant) for more + * information. + * + * @return Corresponding Java object of the type matching the Variant type. + * @throws IllegalStateException + * if no underlying windows data structure + * @throws NotImplementedException + * if unsupported conversion is requested + * @throws JacobException + * if the calculated result was a JacobObject usually as a + * result of error + */ + public Object toJavaObject() throws JacobException { + return VariantUtilities.variantToObject(this); + } + + /** + * Acts a a cover for toDispatch. This primarily exists to support jacobgen. + * + * @deprecated this is a cover for toDispatch(); + * @return Object returned by toDispatch() + * @see Variant#toDispatch() instead + */ + @Deprecated + public Object toObject() { + return toDispatch(); + } + + /** + * By default toSafeArray makes a deep copy due to the fact that this + * Variant owns the embedded SafeArray and will destroy it when it gc's + * calls toSafeArray(true). + * + * @return the object converted to a SafeArray + */ + public SafeArray toSafeArray() { + // verify we haven't been released yet + getvt(); + return toSafeArray(true); + } + + /** + * This lets folk turn into a safe array without a deep copy. Should this + * API be public? + * + * @param deepCopy + * @return SafeArray constructed + */ + public SafeArray toSafeArray(boolean deepCopy) { + // verify we haven't been released yet + getvt(); + return toVariantSafeArray(deepCopy); + } + + /** + * I don't know what this is. Is it some legacy (pre 1.8) thing? + * + * @deprecated + * @return this object as a dispatch object by calling toDispatch() + */ + @Deprecated + public Object toScriptObject() { + return toDispatch(); + } + + /** + * attempts to return the contents of this Variant as a short (after + * possible conversion) + * + * @deprecated callers should use changeType() followed by getShort() + * @return short + */ + @Deprecated + public short toShort() { + this.changeType(Variant.VariantShort); + return getShort(); + } + + /** + * This method now correctly implements java toString() semantics Attempts + * to return the content of this variant as a string + *

    + *
  • "not initialized" if not initialized + *
  • "null" if VariantEmpty, + *
  • "null" if VariantError + *
  • "null" if VariantNull + *
  • the value if we know how to describe one of that type + *
  • three question marks if can't convert + * + * @return String value conversion, + * @throws IllegalStateException + * if there is no underlying windows data structure + */ + @Override + public String toString() { + try { + // see if we are in a legal state + getvt(); + } catch (IllegalStateException ise) { + return ""; + } + if (getvt() == VariantEmpty || getvt() == VariantError + || getvt() == VariantNull) { + return "null"; + } + if (getvt() == VariantString) { + return getString(); + } + try { + Object foo = toJavaObject(); + // rely on java objects to do the right thing + return foo.toString(); + } catch (NotImplementedException nie) { + // some types do not generate a good description yet + return "Description not available for type: " + getvt(); + } + } + + /** + * Exists to support jacobgen. This would be deprecated if it weren't for + * jacobgen + * + * @deprecated superseded by "this" + * @return this same object + */ + @Deprecated + public Variant toVariant() { + return this; + } + + /** + * @deprecated superseded by SafeArray + * @return nothing because this method is not implemented + * @throws com.jacob.com.NotImplementedException + */ + @Deprecated + public Variant[] toVariantArray() { + throw new NotImplementedException("Not implemented"); + } + + /** + * native method used by toDispatch() + * + * @return + */ + private native Dispatch toVariantDispatch(); + + private native SafeArray toVariantSafeArray(boolean deepCopy); + + /* + * ===================================================================== + * + * + * ===================================================================== + */ + + /** + * Clear the content of this variant + */ + public native void VariantClear(); + +} \ No newline at end of file diff --git a/java/src/com/jacob/com/VariantUtilities.java b/java/src/com/jacob/com/VariantUtilities.java new file mode 100644 index 0000000..ae384f0 --- /dev/null +++ b/java/src/com/jacob/com/VariantUtilities.java @@ -0,0 +1,502 @@ +/** + * + */ +package com.jacob.com; + +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.Date; + +/** + * A utility class used to convert between Java objects and Variants + */ +public final class VariantUtilities { + private VariantUtilities() { + // utility class with only static methods don't need constructors + } + + /** + * Populates a variant object from a java object. This method attempts to + * figure out the appropriate Variant type + * + * @param targetVariant + * @param pValueObject + * @param fByRef + */ + protected static void populateVariant(Variant targetVariant, + Object pValueObject, boolean fByRef) { + if (pValueObject == null) { + targetVariant.putEmpty(); + } else if (pValueObject instanceof Integer) { + if (fByRef) { + targetVariant.putIntRef(((Integer) pValueObject).intValue()); + } else { + targetVariant.putInt(((Integer) pValueObject).intValue()); + } + } else if (pValueObject instanceof Short) { + if (fByRef) { + targetVariant.putShortRef(((Short) pValueObject).shortValue()); + } else { + targetVariant.putShort(((Short) pValueObject).shortValue()); + } + } else if (pValueObject instanceof String) { + if (fByRef) { + targetVariant.putStringRef((String) pValueObject); + } else { + targetVariant.putString((String) pValueObject); + } + } else if (pValueObject instanceof Boolean) { + if (fByRef) { + targetVariant.putBooleanRef(((Boolean) pValueObject) + .booleanValue()); + } else { + targetVariant.putBoolean(((Boolean) pValueObject) + .booleanValue()); + } + } else if (pValueObject instanceof Double) { + if (fByRef) { + targetVariant.putDoubleRef(((Double) pValueObject) + .doubleValue()); + } else { + targetVariant.putDouble(((Double) pValueObject).doubleValue()); + } + } else if (pValueObject instanceof Float) { + if (fByRef) { + targetVariant.putFloatRef(((Float) pValueObject).floatValue()); + } else { + targetVariant.putFloat(((Float) pValueObject).floatValue()); + } + } else if (pValueObject instanceof BigDecimal) { + if (fByRef) { + targetVariant.putDecimalRef(((BigDecimal) pValueObject)); + } else { + targetVariant.putDecimal(((BigDecimal) pValueObject)); + } + } else if (pValueObject instanceof Byte) { + if (fByRef) { + targetVariant.putByteRef(((Byte) pValueObject).byteValue()); + } else { + targetVariant.putByte(((Byte) pValueObject).byteValue()); + } + } else if (pValueObject instanceof Date) { + if (fByRef) { + targetVariant.putDateRef((Date) pValueObject); + } else { + targetVariant.putDate((Date) pValueObject); + } + } else if (pValueObject instanceof Long) { + if (fByRef) { + targetVariant.putLongRef(((Long) pValueObject).longValue()); + } else { + targetVariant.putLong(((Long) pValueObject).longValue()); + } + } else if (pValueObject instanceof Currency) { + if (fByRef) { + targetVariant.putCurrencyRef(((Currency) pValueObject)); + } else { + targetVariant.putCurrency(((Currency) pValueObject)); + } + } else if (pValueObject instanceof SafeArray) { + if (fByRef) { + targetVariant.putSafeArrayRef((SafeArray) pValueObject); + } else { + targetVariant.putSafeArray((SafeArray) pValueObject); + } + } else if (pValueObject instanceof Dispatch) { + if (fByRef) { + targetVariant.putDispatchRef((Dispatch) pValueObject); + } else { + targetVariant.putDispatch((Dispatch) pValueObject); + } + } else if (pValueObject instanceof Variant) { + // newly added 1.12-pre6 to support VT_VARIANT + targetVariant.putVariant(pValueObject); + } else { + // sourceforge patch 2171967 + // used to rely on coercion but sometimes crashed VM + throw new NotImplementedException( + "populateVariant() not implemented for " + + pValueObject.getClass()); + } + } + + /** + * Map arguments based on msdn documentation. This method relies on the + * variant constructor except for arrays. + * + * @param objectToBeMadeIntoVariant + * @return Variant that represents the object + */ + protected static Variant objectToVariant(Object objectToBeMadeIntoVariant) { + if (objectToBeMadeIntoVariant == null) { + return new Variant(); + } else if (objectToBeMadeIntoVariant instanceof Variant) { + // if a variant was passed in then be a slacker and just return it + return (Variant) objectToBeMadeIntoVariant; + } else if (objectToBeMadeIntoVariant.getClass().isArray()) { + // automatically convert arrays using reflection + // handle it differently based on the type of array + // added primitive support sourceforge 2762275 + SafeArray sa = null; + int len1 = Array.getLength(objectToBeMadeIntoVariant); + Class componentType = objectToBeMadeIntoVariant.getClass() + .getComponentType(); + + if (componentType.isArray()) { // array of arrays + int max = 0; + for (int i = 0; i < len1; i++) { + Object e1 = Array.get(objectToBeMadeIntoVariant, i); + int len2 = Array.getLength(e1); + if (max < len2) { + max = len2; + } + } + sa = new SafeArray(Variant.VariantVariant, len1, max); + for (int i = 0; i < len1; i++) { + Object e1 = Array.get(objectToBeMadeIntoVariant, i); + for (int j = 0; j < Array.getLength(e1); j++) { + sa.setVariant(i, j, objectToVariant(Array.get(e1, j))); + } + } + } else if (byte.class.equals(componentType)) { + byte[] arr = (byte[]) objectToBeMadeIntoVariant; + sa = new SafeArray(Variant.VariantByte, len1); + for (int i = 0; i < len1; i++) { + sa.setByte(i, arr[i]); + } + } else if (int.class.equals(componentType)) { + int[] arr = (int[]) objectToBeMadeIntoVariant; + sa = new SafeArray(Variant.VariantInt, len1); + for (int i = 0; i < len1; i++) { + sa.setInt(i, arr[i]); + } + } else if (double.class.equals(componentType)) { + double[] arr = (double[]) objectToBeMadeIntoVariant; + sa = new SafeArray(Variant.VariantDouble, len1); + for (int i = 0; i < len1; i++) { + sa.setDouble(i, arr[i]); + } + } else if (long.class.equals(componentType)) { + long[] arr = (long[]) objectToBeMadeIntoVariant; + sa = new SafeArray(Variant.VariantLongInt, len1); + for (int i = 0; i < len1; i++) { + sa.setLong(i, arr[i]); + } + } else { + // array of object + sa = new SafeArray(Variant.VariantVariant, len1); + for (int i = 0; i < len1; i++) { + sa.setVariant(i, objectToVariant(Array.get( + objectToBeMadeIntoVariant, i))); + } + } + Variant returnVariant = new Variant(); + populateVariant(returnVariant, sa, false); + return returnVariant; + } else { + // rely on populateVariant to throw an exception if its an + // invalid type + Variant returnVariant = new Variant(); + populateVariant(returnVariant, objectToBeMadeIntoVariant, false); + return returnVariant; + } + } + + /** + * converts an array of objects into an array of Variants by repeatedly + * calling obj2Variant(Object) + * + * @param arrayOfObjectsToBeConverted + * @return Variant[] + */ + protected static Variant[] objectsToVariants( + Object[] arrayOfObjectsToBeConverted) { + if (arrayOfObjectsToBeConverted instanceof Variant[]) { + // just return the passed in array if it is a Variant array + return (Variant[]) arrayOfObjectsToBeConverted; + } else { + Variant vArg[] = new Variant[arrayOfObjectsToBeConverted.length]; + for (int i = 0; i < arrayOfObjectsToBeConverted.length; i++) { + vArg[i] = objectToVariant(arrayOfObjectsToBeConverted[i]); + } + return vArg; + } + } + + /** + * Convert a JACOB Variant value to a Java object (type conversions). + * provided in Sourceforge feature request 959381. A fix was done to handle + * byRef bug report 1607878. + *

    + * Unlike other toXXX() methods, it does not do a type conversion except for + * special data types (it shouldn't do any!) + *

    + * Converts Variant.VariantArray types to SafeArrays + * + * @return Corresponding Java object of the type matching the Variant type. + * @throws IllegalStateException + * if no underlying windows data structure + * @throws NotImplementedException + * if unsupported conversion is requested + * @throws JacobException + * if the calculated result was a JacobObject usually as a + * result of error + */ + protected static Object variantToObject(Variant sourceData) { + Object result = null; + + short type = sourceData.getvt(); // variant type + + if ((type & Variant.VariantArray) == Variant.VariantArray) { // array + // returned? + SafeArray array = null; + type = (short) (type - Variant.VariantArray); + // From SF Bug 1840487 + // This did call toSafeArray(false) but that meant + // this was the only variantToObject() that didn't have its own + // copy of the data so you would end up with weird run time + // errors after some GC. So now we just get stupid about it and + // always make a copy just like toSafeArray() does. + array = sourceData.toSafeArray(); + result = array; + } else { // non-array object returned + switch (type) { + case Variant.VariantEmpty: // 0 + case Variant.VariantNull: // 1 + break; + case Variant.VariantShort: // 2 + result = new Short(sourceData.getShort()); + break; + case Variant.VariantShort | Variant.VariantByref: // 2 + result = new Short(sourceData.getShortRef()); + break; + case Variant.VariantInt: // 3 + result = new Integer(sourceData.getInt()); + break; + case Variant.VariantInt | Variant.VariantByref: // 3 + result = new Integer(sourceData.getIntRef()); + break; + case Variant.VariantFloat: // 4 + result = new Float(sourceData.getFloat()); + break; + case Variant.VariantFloat | Variant.VariantByref: // 4 + result = new Float(sourceData.getFloatRef()); + break; + case Variant.VariantDouble: // 5 + result = new Double(sourceData.getDouble()); + break; + case Variant.VariantDouble | Variant.VariantByref: // 5 + result = new Double(sourceData.getDoubleRef()); + break; + case Variant.VariantCurrency: // 6 + result = sourceData.getCurrency(); + break; + case Variant.VariantCurrency | Variant.VariantByref: // 6 + result = sourceData.getCurrencyRef(); + break; + case Variant.VariantDate: // 7 + result = sourceData.getJavaDate(); + break; + case Variant.VariantDate | Variant.VariantByref: // 7 + result = sourceData.getJavaDateRef(); + break; + case Variant.VariantString: // 8 + result = sourceData.getString(); + break; + case Variant.VariantString | Variant.VariantByref: // 8 + result = sourceData.getStringRef(); + break; + case Variant.VariantDispatch: // 9 + result = sourceData.getDispatch(); + break; + case Variant.VariantDispatch | Variant.VariantByref: // 9 + result = sourceData.getDispatchRef(); // Can dispatches even + // be byRef? + break; + case Variant.VariantError: // 10 + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantError"); + break; + case Variant.VariantBoolean: // 11 + result = new Boolean(sourceData.getBoolean()); + break; + case Variant.VariantBoolean | Variant.VariantByref: // 11 + result = new Boolean(sourceData.getBooleanRef()); + break; + case Variant.VariantVariant: // 12 they are always by ref + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantVariant without ByRef"); + break; + case Variant.VariantVariant | Variant.VariantByref: // 12 + result = sourceData.getVariant(); + break; + case Variant.VariantObject: // 13 + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantObject"); + break; + case Variant.VariantDecimal: // 14 + result = sourceData.getDecimal(); + break; + case Variant.VariantDecimal | Variant.VariantByref: // 14 + result = sourceData.getDecimalRef(); + break; + case Variant.VariantByte: // 17 + result = new Byte(sourceData.getByte()); + break; + case Variant.VariantByte | Variant.VariantByref: // 17 + result = new Byte(sourceData.getByteRef()); + break; + case Variant.VariantLongInt: // 20 + result = new Long(sourceData.getLong()); + break; + case Variant.VariantLongInt | Variant.VariantByref: // 20 + result = new Long(sourceData.getLongRef()); + break; + case Variant.VariantTypeMask: // 4095 + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantBstrBlob/VariantTypeMask"); + break; + case Variant.VariantArray: // 8192 + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantArray"); + break; + case Variant.VariantByref: // 16384 + result = new NotImplementedException( + "toJavaObject() Not implemented for VariantByref"); + break; + default: + result = new NotImplementedException("Unknown return type: " + + type); + // there was a "return result" here that caused defect 1602118 + // so it was removed + break; + }// switch (type) + + if (result instanceof JacobException) { + throw (JacobException) result; + } + } + + return result; + }// toJava() + + /** + * Verifies that we have a scale 0 <= x <= 28 and now more than 96 bits of + * data. The roundToMSDecimal method will attempt to adjust a BigDecimal to + * pass this set of tests + * + * @param in + * @throws IllegalArgumentException + * if out of bounds + */ + protected static void validateDecimalScaleAndBits(BigDecimal in) { + BigInteger allWordBigInt = in.unscaledValue(); + if (in.scale() > 28) { + // should this cast to a string and call putStringRef()? + throw new IllegalArgumentException( + "VT_DECIMAL only supports a maximum scale of 28 and the passed" + + " in value has a scale of " + in.scale()); + } else if (in.scale() < 0) { + // should this cast to a string and call putStringRef()? + throw new IllegalArgumentException( + "VT_DECIMAL only supports a minimum scale of 0 and the passed" + + " in value has a scale of " + in.scale()); + } else if (allWordBigInt.bitLength() > 12 * 8) { + throw new IllegalArgumentException( + "VT_DECIMAL supports a maximum of " + + 12 + * 8 + + " bits not counting scale and the number passed in has " + + allWordBigInt.bitLength()); + + } else { + // no bounds problem to be handled + } + + } + + /** + * Largest possible number with scale set to 0 + */ + private static final BigDecimal LARGEST_DECIMAL = new BigDecimal( + new BigInteger("ffffffffffffffffffffffff", 16)); + /** + * Smallest possible number with scale set to 0. MS doesn't support negative + * scales like BigDecimal. + */ + private static final BigDecimal SMALLEST_DECIMAL = new BigDecimal( + new BigInteger("ffffffffffffffffffffffff", 16).negate()); + + /** + * Does any validation that couldn't have been fixed by rounding or scale + * modification. + * + * @param in + * The BigDecimal to be validated + * @throws IllegalArgumentException + * if the number is too large or too small or null + */ + protected static void validateDecimalMinMax(BigDecimal in) { + if (in == null) { + throw new IllegalArgumentException( + "null is not a supported Decimal value."); + } else if (LARGEST_DECIMAL.compareTo(in) < 0) { + throw new IllegalArgumentException( + "Value too large for VT_DECIMAL data type:" + in.toString() + + " integer: " + in.toBigInteger().toString(16) + + " scale: " + in.scale()); + } else if (SMALLEST_DECIMAL.compareTo(in) > 0) { + throw new IllegalArgumentException( + "Value too small for VT_DECIMAL data type:" + in.toString() + + " integer: " + in.toBigInteger().toString(16) + + " scale: " + in.scale()); + } + + } + + /** + * Rounds the scale and bit length so that it will pass + * validateDecimalScaleBits(). Developers should call this method if they + * really want MS Decimal and don't want to lose precision. + *

    + * Changing the scale on a number that can fit in an MS Decimal can change + * the number's representation enough that it will round to a number too + * large to be represented by an MS VT_DECIMAL + * + * @param sourceDecimal + * @return BigDecimal a new big decimal that was rounded to fit in an MS + * VT_DECIMAL + */ + public static BigDecimal roundToMSDecimal(BigDecimal sourceDecimal) { + BigInteger sourceDecimalIntComponent = sourceDecimal.unscaledValue(); + BigDecimal destinationDecimal = new BigDecimal( + sourceDecimalIntComponent, sourceDecimal.scale()); + int roundingModel = BigDecimal.ROUND_HALF_UP; + validateDecimalMinMax(destinationDecimal); + // First limit the number of digits and then the precision. + // Try and round to 29 digits because we can sometimes do that + BigInteger allWordBigInt; + allWordBigInt = destinationDecimal.unscaledValue(); + if (allWordBigInt.bitLength() > 96) { + destinationDecimal = destinationDecimal.round(new MathContext(29)); + // see if 29 digits uses more than 96 bits + if (allWordBigInt.bitLength() > 96) { + // Dang. It was over 97 bits so shorten it one more digit to + // stay <= 96 bits + destinationDecimal = destinationDecimal.round(new MathContext( + 28)); + } + } + // the bit manipulations above may change the scale so do it afterwards + // round the scale to the max MS can support + if (destinationDecimal.scale() > 28) { + destinationDecimal = destinationDecimal.setScale(28, roundingModel); + } + if (destinationDecimal.scale() < 0) { + destinationDecimal = destinationDecimal.setScale(0, roundingModel); + } + return destinationDecimal; + } +} diff --git a/java/src/com/jacob/com/VariantViaEvent.java b/java/src/com/jacob/com/VariantViaEvent.java new file mode 100644 index 0000000..696a501 --- /dev/null +++ b/java/src/com/jacob/com/VariantViaEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * a public class to variant that is used to track which variant objects are + * created by event callbacks This is solely used for that purpose. + */ +public class VariantViaEvent extends Variant { + + /** + * Standard constructor used by JNI event handling layer + */ + public VariantViaEvent() { + super(); + } +} diff --git a/java/src/com/jacob/com/WrongThreadException.java b/java/src/com/jacob/com/WrongThreadException.java new file mode 100644 index 0000000..028021b --- /dev/null +++ b/java/src/com/jacob/com/WrongThreadException.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.jacob.com; + +/** + * thrown in util.cpp + */ +public class WrongThreadException extends JacobException { + /** + * identifier generated by Eclipse + */ + private static final long serialVersionUID = 6308780364980228692L; + + /** + * standard 0 arg constructor with no message + * + */ + public WrongThreadException() { + super("No Message Provided."); + } + + /** + * standard constructor with a string message + * + * @param s + */ + public WrongThreadException(String s) { + super(s); + } +} \ No newline at end of file diff --git a/java/src/pm/Main.java b/java/src/pm/Main.java index 5fe0c24..16d5490 100644 --- a/java/src/pm/Main.java +++ b/java/src/pm/Main.java @@ -5,9 +5,11 @@ import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import pm.application.Application; +import pm.application.iTunes.iTunesApplicatie; import pm.application.voorbeeld.VoorbeeldApplication; import pm.device.Device; import pm.device.javainput.extreme3d.Extreme3DDevice; +import pm.device.javainput.rumblepad.RumblepadDevice; import pm.device.jintellitype.JIntellitypeDevice; import pm.device.wiimote.WiimoteDevice; import pm.exception.ActionException; @@ -50,12 +52,13 @@ public class Main { public void start() throws Exception { //add(new ExampleDevice()); - //add(new RumblepadDevice()); - add(new Extreme3DDevice()); + add(new RumblepadDevice()); + //add(new Extreme3DDevice()); add(new JIntellitypeDevice()); - add(new WiimoteDevice()); + //add(new WiimoteDevice()); Application application = new VoorbeeldApplication(); + application = new iTunesApplicatie(); add(application); for (Device device : deviceList) { diff --git a/java/src/pm/application/iTunes/iTunes.java b/java/src/pm/application/iTunes/iTunesApplicatie.java similarity index 86% rename from java/src/pm/application/iTunes/iTunes.java rename to java/src/pm/application/iTunes/iTunesApplicatie.java index 7ac1c32..89e3767 100644 --- a/java/src/pm/application/iTunes/iTunes.java +++ b/java/src/pm/application/iTunes/iTunesApplicatie.java @@ -6,11 +6,11 @@ import com.jacob.activeX.ActiveXComponent; import com.jacob.com.ComThread; import com.jacob.com.Dispatch; -public class iTunes extends Application{ +public class iTunesApplicatie extends Application{ Dispatch iTunesController; - public iTunes() { + public iTunesApplicatie() { connect(); } @@ -44,7 +44,7 @@ public class iTunes extends Application{ } public static void main(String argv[]) throws Exception { - new iTunes(); + new iTunesApplicatie(); } } \ No newline at end of file diff --git a/java/src/pm/device/javainput/JavaInputDevice.java b/java/src/pm/device/javainput/JavaInputDevice.java index 9d65079..db0a22f 100644 --- a/java/src/pm/device/javainput/JavaInputDevice.java +++ b/java/src/pm/device/javainput/JavaInputDevice.java @@ -8,12 +8,9 @@ import de.hardcode.jxinput.event.JXInputDirectionalEvent; import pm.Button; import pm.device.Device; -import pm.device.javainput.extreme3d.Extreme3DButton; -import pm.device.javainput.extreme3d.Extreme3DDirection; import pm.exception.DeviceException; import pm.exception.EventException; import pm.exception.device.JavaInputDeviceNotFoundException; -import pm.exception.event.UnknownDirectionException; import pm.macro.event.Press; import pm.macro.event.Release; @@ -50,7 +47,7 @@ public abstract class JavaInputDevice extends Device { } public void processEvent(JXInputButtonEvent event) throws EventException { - Button button = Extreme3DButton.create(event); + Button button = getButton(event); if (event.getButton().getState()) { System.out.println("Press: " + button); add(new Press(button)); @@ -60,8 +57,8 @@ public abstract class JavaInputDevice extends Device { } } - public void processEvent(JXInputDirectionalEvent event) throws UnknownDirectionException { - Button button = Extreme3DDirection.create(event); + public void processEvent(JXInputDirectionalEvent event) throws EventException { + Button button = getButton(event); if (event.getDirectional().isCentered()) { if (previousDirectionalButton != null) { System.out.println("Release: " + previousDirectionalButton); @@ -73,4 +70,7 @@ public abstract class JavaInputDevice extends Device { previousDirectionalButton = button; } } + + protected abstract Button getButton(JXInputButtonEvent event) throws EventException; + protected abstract Button getButton(JXInputDirectionalEvent event) throws EventException; } diff --git a/java/src/pm/device/javainput/extreme3d/Extreme3DDevice.java b/java/src/pm/device/javainput/extreme3d/Extreme3DDevice.java index e126b3f..914083c 100644 --- a/java/src/pm/device/javainput/extreme3d/Extreme3DDevice.java +++ b/java/src/pm/device/javainput/extreme3d/Extreme3DDevice.java @@ -1,11 +1,16 @@ package pm.device.javainput.extreme3d; +import de.hardcode.jxinput.event.JXInputButtonEvent; +import de.hardcode.jxinput.event.JXInputDirectionalEvent; import pm.Action; +import pm.Button; import pm.Macro; import pm.Target; import pm.device.javainput.JavaInputDevice; import pm.exception.DeviceException; import pm.exception.MacroException; +import pm.exception.event.UnknownButtonException; +import pm.exception.event.UnknownDirectionException; import pm.macro.event.Hold; import pm.macro.event.Press; import pm.macro.event.Release; @@ -34,4 +39,12 @@ public class Extreme3DDevice extends JavaInputDevice { e.printStackTrace(); } } + + protected Button getButton(JXInputButtonEvent event) throws UnknownButtonException { + return Extreme3DButton.create(event); + } + + protected Button getButton(JXInputDirectionalEvent event) throws UnknownDirectionException { + return Extreme3DDirection.create(event); + } } diff --git a/java/src/pm/device/javainput/rumblepad/RumblepadDevice.java b/java/src/pm/device/javainput/rumblepad/RumblepadDevice.java index 984fc3d..abef3bf 100644 --- a/java/src/pm/device/javainput/rumblepad/RumblepadDevice.java +++ b/java/src/pm/device/javainput/rumblepad/RumblepadDevice.java @@ -1,10 +1,16 @@ package pm.device.javainput.rumblepad; +import de.hardcode.jxinput.event.JXInputButtonEvent; +import de.hardcode.jxinput.event.JXInputDirectionalEvent; import pm.Action; +import pm.Button; +import pm.Macro; import pm.Target; import pm.device.javainput.JavaInputDevice; import pm.exception.DeviceException; import pm.exception.MacroException; +import pm.exception.event.UnknownButtonException; +import pm.exception.event.UnknownDirectionException; import pm.macro.event.Press; public class RumblepadDevice extends JavaInputDevice { @@ -18,7 +24,7 @@ public class RumblepadDevice extends JavaInputDevice { public void start() { super.start(); try { - /*add( + add( new Press(RumblepadButton.ONE), Action.PLAY.setTarget(Target.APPLICATION)); add( @@ -26,12 +32,23 @@ public class RumblepadDevice extends JavaInputDevice { Action.PAUSE.setTarget(Target.APPLICATION)); add( new Press(RumblepadButton.THREE), - Action.RESUME.setTarget(Target.APPLICATION));*/ + Action.RESUME.setTarget(Target.APPLICATION)); add( - new Press(RumblepadButton.FOUR), + new Macro( + new Press(RumblepadButton.ONE) + ), Action.EXIT.setTarget(Target.MAIN)); } catch (MacroException e) { e.printStackTrace(); } - } + } + + protected Button getButton(JXInputButtonEvent event) throws UnknownButtonException { + return RumblepadButton.create(event); + } + + protected Button getButton(JXInputDirectionalEvent event) throws UnknownDirectionException { + return RumblepadDirection.create(event); + } + } diff --git a/java/src/pm/device/jintellitype/JIntellitypeDevice.java b/java/src/pm/device/jintellitype/JIntellitypeDevice.java index 777b5e6..c2457aa 100644 --- a/java/src/pm/device/jintellitype/JIntellitypeDevice.java +++ b/java/src/pm/device/jintellitype/JIntellitypeDevice.java @@ -31,10 +31,7 @@ public class JIntellitypeDevice extends Device implements HotkeyListener, Intell jit.addIntellitypeListener(this); try { add( - new Macro( - new Hotkey('r'), - new Hotkey('i'), - new Hotkey('k')), + new Hotkey(HotkeyButton.CTRL, 'x'), Action.EXIT.setTarget(Target.MAIN)); add( new Press(CommandButton.VOLUME_UP), diff --git a/java/src/pm/macro/Event.java b/java/src/pm/macro/Event.java index c27745b..2db1643 100644 --- a/java/src/pm/macro/Event.java +++ b/java/src/pm/macro/Event.java @@ -14,6 +14,6 @@ public abstract class Event { } public boolean equals(Event event) { - return event.getClass().equals(getClass()) && event.getButton().equals(button); // Todo: controleren of equals goed werkt bij buttons van verschillende typen + return event.getClass().equals(getClass()) && event.getButton().equals(button); } }