1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Microsoft Public License. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Microsoft Public License, please send an email to
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if !SILVERLIGHT // ComObject
using System;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using Marshal = System.Runtime.InteropServices.Marshal;
using VarEnum = System.Runtime.InteropServices.VarEnum;
namespace Microsoft.Scripting.ComInterop {
/// <summary>
/// The parameter description of a method defined in a type library
/// </summary>
public class ComParamDesc {
# region private fields
private readonly bool _isOut; // is an output parameter?
private readonly bool _isOpt; // is an optional parameter?
private readonly bool _byRef; // is a reference or pointer parameter?
private readonly bool _isArray;
private readonly VarEnum _vt;
private readonly string _name;
private readonly Type _type;
private readonly object _defaultValue;
# endregion
# region ctor
/// <summary>
/// Creates a representation for the paramter of a COM method
/// </summary>
internal ComParamDesc(ref ELEMDESC elemDesc, string name) {
// Ensure _defaultValue is set to DBNull.Value regardless of whether or not the
// default value is extracted from the parameter description. Failure to do so
// yields a runtime exception in the ToString() function.
_defaultValue = DBNull.Value;
if (!String.IsNullOrEmpty(name)) {
// This is a parameter, not a return value
this._isOut = (elemDesc.desc.paramdesc.wParamFlags & PARAMFLAG.PARAMFLAG_FOUT) != 0;
this._isOpt = (elemDesc.desc.paramdesc.wParamFlags & PARAMFLAG.PARAMFLAG_FOPT) != 0;
// TODO: The PARAMDESCEX struct has a memory issue that needs to be resolved. For now, we ignore it.
//_defaultValue = PARAMDESCEX.GetDefaultValue(ref elemDesc.desc.paramdesc);
}
_name = name;
_vt = (VarEnum)elemDesc.tdesc.vt;
TYPEDESC typeDesc = elemDesc.tdesc;
while (true) {
if (_vt == VarEnum.VT_PTR) {
this._byRef = true;
} else if (_vt == VarEnum.VT_ARRAY) {
this._isArray = true;
} else {
break;
}
TYPEDESC childTypeDesc = (TYPEDESC)Marshal.PtrToStructure(typeDesc.lpValue, typeof(TYPEDESC));
_vt = (VarEnum)childTypeDesc.vt;
typeDesc = childTypeDesc;
}
VarEnum vtWithoutByref = _vt;
if ((_vt & VarEnum.VT_BYREF) != 0) {
vtWithoutByref = (_vt & ~VarEnum.VT_BYREF);
_byRef = true;
}
_type = GetTypeForVarEnum(vtWithoutByref);
}
/// <summary>
/// Creates a representation for the return value of a COM method
/// TODO: Return values should be represented by a different type
/// </summary>
internal ComParamDesc(ref ELEMDESC elemDesc)
: this(ref elemDesc, String.Empty) {
}
//internal struct PARAMDESCEX {
// private ulong _cByte;
// private Variant _varDefaultValue;
// internal void Dummy() {
// _cByte = 0;
// throw Error.MethodShouldNotBeCalled();
// }
// internal static object GetDefaultValue(ref PARAMDESC paramdesc) {
// if ((paramdesc.wParamFlags & PARAMFLAG.PARAMFLAG_FHASDEFAULT) == 0) {
// return DBNull.Value;
// }
// PARAMDESCEX varValue = (PARAMDESCEX)Marshal.PtrToStructure(paramdesc.lpVarValue, typeof(PARAMDESCEX));
// if (varValue._cByte != (ulong)(Marshal.SizeOf((typeof(PARAMDESCEX))))) {
// throw Error.DefaultValueCannotBeRead();
// }
// return varValue._varDefaultValue.ToObject();
// }
//}
private static Type GetTypeForVarEnum(VarEnum vt) {
Type type;
switch (vt) {
// VarEnums which can be used in VARIANTs, but which cannot occur in a TYPEDESC
case VarEnum.VT_EMPTY:
case VarEnum.VT_NULL:
case VarEnum.VT_RECORD:
throw new InvalidOperationException(string.Format("Unexpected VarEnum {0}.", vt));
// VarEnums which are not used in VARIANTs, but which can occur in a TYPEDESC
case VarEnum.VT_VOID:
type = null;
break;
#if DISABLE // TODO: WTypes.h indicates that these cannot be used in VARIANTs, but Type.InvokeMember seems to allow it
case VarEnum.VT_I8:
case VarEnum.UI8:
#endif
case VarEnum.VT_HRESULT:
type = typeof(int);
break;
case ((VarEnum)37): // VT_INT_PTR:
case VarEnum.VT_PTR:
type = typeof(IntPtr);
break;
case ((VarEnum)38): // VT_UINT_PTR:
type = typeof(UIntPtr);
break;
case VarEnum.VT_SAFEARRAY:
case VarEnum.VT_CARRAY:
type = typeof(Array);
break;
case VarEnum.VT_LPSTR:
case VarEnum.VT_LPWSTR:
type = typeof(string);
break;
case VarEnum.VT_USERDEFINED:
type = typeof(object);
break;
// For VarEnums that can be used in VARIANTs and well as TYPEDESCs, just use VarEnumSelector
default:
type = VarEnumSelector.GetManagedMarshalType(vt);
break;
}
return type;
}
public override string ToString() {
StringBuilder result = new StringBuilder();
if (_isOpt) {
result.Append("[Optional] ");
}
if (_isOut) {
result.Append("[out]");
}
result.Append(_type.Name);
if (_isArray) {
result.Append("[]");
}
if (_byRef) {
result.Append("&");
}
result.Append(" ");
result.Append(_name);
if (_defaultValue != DBNull.Value) {
result.Append("=");
result.Append(_defaultValue.ToString());
}
return result.ToString();
}
# endregion
# region properties
public bool IsOut {
get { return _isOut; }
}
public bool IsOptional {
get { return _isOpt; }
}
public bool ByReference {
get { return _byRef; }
}
public bool IsArray {
get { return _isArray; }
}
public Type ParameterType {
get {
return _type;
}
}
/// <summary>
/// DBNull.Value if there is no default value
/// </summary>
internal object DefaultValue {
get {
return _defaultValue;
}
}
# endregion
}
}
#endif
|