📄 variant.java
字号:
/*
* Variant.java -
*
* This file is part of the Jawin Project: http://jawinproject.sourceforge.net/
*
* Please consult the LICENSE file in the project root directory,
* or at the project site before using this software.
*/
/* $Id: Variant.java,v 1.9 2004/07/31 21:20:05 arosii_moa Exp $ */
package org.jawin;
import java.io.IOException;
import java.util.Date;
import org.jawin.constants.VarTypes;
import org.jawin.constants.WellKnownGUIDs;
import org.jawin.io.DateUtil;
import org.jawin.io.LittleEndianInputStream;
import org.jawin.io.LittleEndianOutputStream;
import org.jawin.win32.SAFEARRAY;
/**
* The Jawin equivalent of the Windows Variant type.
* <br><br>
* <b>Important:</b> VERY expensive to instantiate in terms of memory.
* <br><br>
* Contains also some intrinsics static methods for marshalling.
*
* @version $Revision: 1.9 $
* @author Stuart Halloway, http://www.relevancellc.com/halloway/weblog/<br>
* Morten Andersen, arosii_moa (at) users.sourceforge.net
*/
public class Variant {
public static final int SIZEOF = 16;
public int vt;
public byte bVal; // VT_UI1.
public short iVal; // VT_I2.
public int lVal; // VT_I4.
public float fltVal; // VT_R4.
public double dblVal; // VT_R8.
public boolean boolVal; // VT_BOOL.
public int scode; // VT_ERROR.
public long cyVal; // VT_CY.
public double date; // VT_DATE. - use the DateUtil's to read/write this
public String bstrVal; // VT_BSTR.
// public DECIMAL [] pdecVal // VT_BYREF|VT_DECIMAL.
public IUnknown punkVal; // VT_UNKNOWN.
public DispatchPtr pdispVal; // VT_DISPATCH.
public SAFEARRAY[] parray; // VT_ARRAY|*.
public byte[] pbVal; // VT_BYREF|VT_UI1.
public short[] piVal; // VT_BYREF|VT_I2.
public int[] plVal; // VT_BYREF|VT_I4.
public float[] pfltVal; // VT_BYREF|VT_R4.
public double[] pdblVal; // VT_BYREF|VT_R8.
public boolean[] pboolVal; // VT_BYREF|VT_BOOL.
public int[] pscode; // VT_BYREF|VT_ERROR.
public long[] pcyVal; // VT_BYREF|VT_CY.
public double[] pdate; // VT_BYREF|VT_DATE.
public String pbstrVal; // VT_BYREF|VT_BSTR.
public IUnknown[] ppunkVal; // VT_BYREF|VT_UNKNOWN.
public DispatchPtr[] ppdispVal; // VT_BYREF|VT_DISPATCH.
public SAFEARRAY[][] pparray; // VT_ARRAY|*.
public Variant[] pvarVal; // VT_BYREF|VT_VARIANT.
public COMPtr byref; // Generic ByRef.
public byte cVal; // VT_I1.
public short uiVal; // VT_UI2.
public int ulVal; // VT_UI4.
public int intVal; // VT_INT.
public int uintVal; // VT_UINT.
public byte[] pcVal; // VT_BYREF|VT_I1.
public short[] puiVal; // VT_BYREF|VT_UI2.
public int[] pulVal; // VT_BYREF|VT_UI4.
public int[] pintVal; // VT_BYREF|VT_INT.
public int[] puintVal; //VT_BYREF|VT_UINT.
public long llVal; // VT_I8
public long ullVal; // VT_UI8
/**
* placeholder class for <code>VT_BYREF</code> objects (mostly [out] or [in, out]-parameters).
* Any object that should be marshalled as a <code>VT_BYREF|*<code>-type
* should be wrapped in a ByrefHolder-object before being passed to
* {@link Variant#writeObject(Object, LittleEndianOutputStream) writeObject()}.
* <br><br>
* If one of the {@link DispatchPtr#invokeN(String, Object[]) DispatchPtr.invoke()}
* methods are used, the result will automatically be marshalled into the ByrefHolder
* object when the invoke call returns. The caller could then retrive the
* result by calling {@link #getRef()}.
*
* @version $Revision: 1.9 $
* @author Morten Andersen, arosii_moa (at) users.sourceforge.net
*/
public static class ByrefHolder {
private Object ref;
/**
* construct a ByrefHolder holding a reference to the
* ref object. Please notice that to be marshalled into the
* correct VT-type, one must supply an object of the correct type
* (even if it is only an [out]-parameter).
* <br><br>
* Eg. if calling a method with a signature like:
* <pre> [out]SAFEARRAY(int) *pLongArray</pre>
* one should create a ByrefHolder like:
* <pre> ByrefHolder holder = new ByrefHolder(new int[0]);</pre>
*
* @param ref the object to marshal as a <code>VT_BYREF|*</code>-type.
* If <code>null</code> the ByrefHolder will be marshalled
* as <code>VT_NULL</code>.
*/
public ByrefHolder(Object ref) {
this.ref = ref;
}
/**
* return the referenced object.
*/
public Object getRef() {
return ref;
}
/**
* set the referenced object.
*/
public void setRef(Object ref) {
this.ref = ref;
}
}
/**
* marshall an object onto an output stream. The object will be marshalled
* following these rules (please notice that primitive types should be
* wrapped in their wrapper types, eg. <code>int</code> should be <code>Integer</code> -
* this should not usually be done for arrays though, see below):
* <ul>
* <li><b><code>null</code>:</b> will be marshalled to <code>VT_NULL</code></li>
* <li><b><code>instanceof {@link ByrefHolder}</code>:</b> will be marshalled
* as the base type + <code>VT_BYREF</code>.</li>
* <li><b>array-types:</b> will be marshalled as the base type
* + <code>VT_ARRAY</code> (and <code>VT_BYREF</code> if
* the array was wrapped in a {@link ByrefHolder}).</li>
* <li><b><code>Byte</code>:</b> will be marshalled as <code>VT_UI1</code>.</li>
* <li><b><code>Short</code>:</b> will be marshalled as <code>VT_I2</code>.</li>
* <li><b><code>Integer</code>:</b> will be marshalled as <code>VT_I4</code>.</li>
* <li><b><code>Long</code>:</b> will be marshalled as <code>VT_I8</code>.</li>
* <li><b><code>Float</code>:</b> will be marshalled as <code>VT_R4</code>.</li>
* <li><b><code>Double</code>:</b> will be marshalled as <code>VT_R8</code>.</li>
* <li><b><code>instanceof Date</code>:</b> will be marshalled as <code>VT_DATE</code> and
* will be converted using {@link DateUtil#getWin32Date(java.util.Date)}.</li>
* <li><b><code>Boolean</code>:</b> will be marshalled as <code>VT_BOOL</code>.</li>
* <li><b><code>String</code>:</b> will be marshalled as <code>VT_BSTR</code>.</li>
* <li><b><code>instanceof {@link Variant}</code>:</b> will be marshalled as a <code>VT_VARIANT</code> using
* the value of the {@link #vt}-property. Please note that <code>VT_VARIANT</code>
* MUST be combined with <code>VT_BYREF</code>.</li>
* <li><b><code>instanceof {@link DispatchPtr}</code>:</b> will be marshalled as
* <code>VT_DISPATCH</code>.</li>
* <li><b><code>instanceof {@link UnknownPtr}</code>:</b> will be marshalled as
* <code>VT_UNKNOWN</code>.</li>
* </ul>
* If none of the rules match, a COMException will be thrown.
* <br><br>
* Notice that the IDispatch coercion mechanism handles scenarios where the
* <code>VT_TYPE</code> of the parameters is a not a 100% fit to a method
* signature. Therefore there should not be any problems by calling eg. a
* method requering <code>unsigned int's</code> with either a Long or an Integer.
* <br><br>
* <b>Arrays:</b> If writing an array, the primitive types should generally be used
* and not the wrapper classes. Eg.
* <pre> var = new int[]{ 7, 9, 13 };</pre>
* is correct, whereas
* <pre> var = new Integer[]{ new Integer(7) , new Integer(9) , new Integer(13) };</pre>
* is not.
* <br><br>
* One should consult the section on array-marshalling in docs/jawinuserguide_dispatch.html
* for how the different Java-arrays are marshalled.
* <br><br>
* Arrays of objects will be written as an <code>VT_VARIANT|VT_ARRAY</code> where
* each element will be written following the rules mentioned above.
* <br><br>
* For this reason it is also believed that multidimensional arrays will be
* marshalled into a SafeArray on the native side containing other SafeArrays
* and NOT multidimensional SafeArrays (TODO: This has not been tested and
* should be verified, and perhaps the code should be instrumentable, so it
* can be controlled to map multidimensional java-arrays into multimensional SafeArrays
* on the native side).
* <br><br>
* The marshalling code is the "inverse" of the native code in the method
* deserializeVariant() in Transform.cpp
*
* @param var the object to write to the stream.
* @param leos the stream the object should be written to.
* @throws COMException if the object can not be marshalled due to
* invalid type or due to IOExceptions on the stream.
*/
public static void writeObject(Object var, LittleEndianOutputStream leos) throws COMException {
int appendVt = 0;
try {
if (var == null) {
leos.writeShort(VarTypes.VT_NULL);
return;
}
if (var instanceof ByrefHolder) {
var = ((ByrefHolder)var).ref;
if (var == null) {
leos.writeShort(VarTypes.VT_NULL);
return;
}
appendVt = VarTypes.VT_BYREF;
}
Class cls = var.getClass();
if (cls.isArray()) {
writeArray(var, appendVt, leos);
return;
}
if (cls == Byte.class) {
leos.writeShort(VarTypes.VT_UI1 | appendVt);
leos.writeByte(((Byte)var).byteValue());
} else if (cls == Short.class) {
leos.writeShort(VarTypes.VT_I2 | appendVt);
leos.writeShort(((Short) var).shortValue());
} else if (cls == Integer.class) {
leos.writeShort(VarTypes.VT_I4 | appendVt);
leos.writeInt(((Integer) var).intValue());
} else if (cls == Long.class) {
leos.writeShort(VarTypes.VT_I8 | appendVt);
leos.writeLong(((Long) var).longValue());
} else if (cls == Float.class) {
leos.writeShort(VarTypes.VT_R4 | appendVt);
leos.writeFloat(((Float) var).floatValue());
} else if (cls == Double.class) {
leos.writeShort(VarTypes.VT_R8 | appendVt);
leos.writeDouble(((Double) var).doubleValue());
} else if (var instanceof Date) {
leos.writeShort(VarTypes.VT_DATE | appendVt);
leos.writeDouble(DateUtil.getWin32Date((Date) var));
} else if (cls == Boolean.class) {
leos.writeShort(VarTypes.VT_BOOL | appendVt);
leos.writeBoolean(((Boolean) var).booleanValue());
} else if (cls == String.class) {
leos.writeShort(VarTypes.VT_BSTR | appendVt);
leos.writeStringUnicode((String) var);
} else if (var instanceof Variant) {
leos.writeShort(VarTypes.VT_VARIANT | appendVt);
writeVariant((Variant) var, leos);
} else if (var instanceof DispatchPtr) {
leos.writeShort(VarTypes.VT_DISPATCH | appendVt);
DispatchPtr dp = (DispatchPtr) var;
leos.writeInt(DispatchPtr.IID_TOKEN);
leos.writeInt(dp.getPeer());
leos.writeInt(dp.getUnknown());
} else if (var instanceof UnknownPtr) {
leos.writeShort(VarTypes.VT_UNKNOWN | appendVt);
UnknownPtr up = (UnknownPtr)var;
leos.writeInt(UnknownPtr.IID_TOKEN);
leos.writeInt(up.getPeer());
leos.writeInt(up.getUnknown());
} else {
throw new COMException("Type cannot be marshalled to variant: " + cls);
}
} catch (IOException ioe) {
throw new COMException(ioe);
}
}
private static void writeVariant(Variant var, LittleEndianOutputStream leos) throws COMException, IOException {
leos.writeShort(var.vt);
switch (var.vt) {
// the 1 byte integral types
case VarTypes.VT_I1:
leos.writeByte(var.cVal);
break;
case VarTypes.VT_UI1:
leos.writeByte(var.bVal);
break;
// the 2 byte integral types
case VarTypes.VT_I2:
leos.writeShort(var.iVal);
break;
case VarTypes.VT_UI2:
leos.writeShort(var.uiVal);
break;
// the 4 byte integral types
case VarTypes.VT_I4:
leos.writeInt(var.lVal);
break;
case VarTypes.VT_UI4:
leos.writeInt(var.ulVal);
break;
case VarTypes.VT_INT:
leos.writeInt(var.intVal);
break;
case VarTypes.VT_UINT:
leos.writeInt(var.uintVal);
break;
// the 8 byte integral types
case VarTypes.VT_I8:
leos.writeLong(var.llVal);
break;
case VarTypes.VT_UI8:
leos.writeLong(var.ullVal);
break;
case VarTypes.VT_CY:
leos.writeLong(var.cyVal);
// the 4 byte float types
case VarTypes.VT_R4:
leos.writeFloat(var.fltVal);
break;
// the 4 byte double types
case VarTypes.VT_R8:
leos.writeDouble(var.dblVal);
break;
case VarTypes.VT_DATE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -