mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
358 lines
14 KiB
C#
358 lines
14 KiB
C#
/********************************************************************++
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
--********************************************************************/
|
|
|
|
using System.Runtime.InteropServices;
|
|
using System.Management.Automation.ComInterop;
|
|
using System.Text;
|
|
using System.Collections.ObjectModel;
|
|
using COM = System.Runtime.InteropServices.ComTypes;
|
|
|
|
// Stops compiler from warning about unknown warnings. Prefast warning numbers are not recognized by C# compiler
|
|
#pragma warning disable 1634, 1691
|
|
|
|
namespace System.Management.Automation
|
|
{
|
|
/// <summary>
|
|
/// Defines a utility class that is used by COM adapter.
|
|
/// </summary>
|
|
internal class ComUtil
|
|
{
|
|
// HResult error code '-2147352573' - Member not found.
|
|
internal const int DISP_E_MEMBERNOTFOUND = unchecked((int)0x80020003);
|
|
// HResult error code '-2147352570' - Unknown Name.
|
|
internal const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006);
|
|
// HResult error code '-2147319765' - Element not found.
|
|
internal const int TYPE_E_ELEMENTNOTFOUND = unchecked((int)0x8002802b);
|
|
|
|
/// <summary>
|
|
/// Gets Method Signature from FuncDesc describing the method.
|
|
/// </summary>
|
|
/// <param name="typeinfo">ITypeInfo interface of the object</param>
|
|
/// <param name="funcdesc">FuncDesc which defines the method</param>
|
|
/// <param name="isPropertyPut">True if this is a property put; these properties take their return type from their first parameter</param>
|
|
/// <returns>signature of the method</returns>
|
|
internal static string GetMethodSignatureFromFuncDesc(COM.ITypeInfo typeinfo, COM.FUNCDESC funcdesc, bool isPropertyPut)
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
string name = GetNameFromFuncDesc(typeinfo, funcdesc);
|
|
|
|
if (!isPropertyPut)
|
|
{
|
|
//First get the string for return type.
|
|
string retstring = GetStringFromTypeDesc(typeinfo, funcdesc.elemdescFunc.tdesc);
|
|
builder.Append(retstring + " ");
|
|
}
|
|
|
|
//Append the function name
|
|
builder.Append(name);
|
|
builder.Append(" (");
|
|
|
|
IntPtr ElementDescriptionArrayPtr = funcdesc.lprgelemdescParam;
|
|
int ElementDescriptionSize = Marshal.SizeOf<COM.ELEMDESC>();
|
|
|
|
for (int i = 0; i < funcdesc.cParams; i++)
|
|
{
|
|
COM.ELEMDESC ElementDescription;
|
|
int ElementDescriptionArrayByteOffset;
|
|
IntPtr ElementDescriptionPointer;
|
|
|
|
ElementDescription = new COM.ELEMDESC();
|
|
ElementDescriptionArrayByteOffset = i * ElementDescriptionSize;
|
|
|
|
//Disable PRefast warning for converting to int32 and converting back into intptr.
|
|
//Code below takes into account 32 bit vs 64 bit conversions
|
|
#pragma warning disable 56515
|
|
if (IntPtr.Size == 4)
|
|
{
|
|
ElementDescriptionPointer = (IntPtr)(ElementDescriptionArrayPtr.ToInt32() + ElementDescriptionArrayByteOffset);
|
|
}
|
|
else
|
|
{
|
|
ElementDescriptionPointer = (IntPtr)(ElementDescriptionArrayPtr.ToInt64() + ElementDescriptionArrayByteOffset);
|
|
}
|
|
#pragma warning restore 56515
|
|
|
|
ElementDescription = Marshal.PtrToStructure<COM.ELEMDESC>(ElementDescriptionPointer);
|
|
|
|
string paramstring = GetStringFromTypeDesc(typeinfo, ElementDescription.tdesc);
|
|
|
|
if (i == 0 && isPropertyPut) // use the type of the first argument as the return type
|
|
{
|
|
builder.Insert(0, paramstring + " ");
|
|
}
|
|
else
|
|
{
|
|
builder.Append(paramstring);
|
|
|
|
if (i < funcdesc.cParams - 1)
|
|
{
|
|
builder.Append(", ");
|
|
}
|
|
}
|
|
}
|
|
builder.Append(")");
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the name of the method or property defined by funcdesc
|
|
/// </summary>
|
|
/// <param name="typeinfo">ITypeInfo interface of the type</param>
|
|
/// <param name="funcdesc">FuncDesc of property of method</param>
|
|
/// <returns>name of the method or property</returns>
|
|
internal static string GetNameFromFuncDesc(COM.ITypeInfo typeinfo, COM.FUNCDESC funcdesc)
|
|
{
|
|
//Get the method or property name.
|
|
String strName, strDoc, strHelp;
|
|
int id;
|
|
typeinfo.GetDocumentation(funcdesc.memid, out strName, out strDoc, out id, out strHelp);
|
|
return strName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the name of the custom type defined in the type library
|
|
/// </summary>
|
|
/// <param name="typeinfo">ITypeInfo interface of the type</param>
|
|
/// <param name="refptr">reference to the custom type</param>
|
|
/// <returns>name of the custom type</returns>
|
|
private static string GetStringFromCustomType(COM.ITypeInfo typeinfo, IntPtr refptr)
|
|
{
|
|
COM.ITypeInfo custtypeinfo;
|
|
int reftype = unchecked((int)(long)refptr); // note that we cast to long first to prevent overflows; this cast is OK since we are only interested in the lower word
|
|
|
|
typeinfo.GetRefTypeInfo(reftype, out custtypeinfo);
|
|
|
|
if (custtypeinfo != null)
|
|
{
|
|
String strName, strDoc, strHelp;
|
|
int id;
|
|
custtypeinfo.GetDocumentation(-1, out strName, out strDoc, out id, out strHelp);
|
|
return strName;
|
|
}
|
|
return "UnknownCustomtype";
|
|
}
|
|
|
|
// Disable obsolete warning about VarEnum in CoreCLR
|
|
#pragma warning disable 618
|
|
|
|
/// <summary>
|
|
/// This function gets a string representation of the Type Descriptor
|
|
/// This is used in generating signature for Properties and Methods.
|
|
/// </summary>
|
|
/// <param name="typeinfo">Reference to the type info to which the type descriptor belongs</param>
|
|
/// <param name="typedesc">reference to type descriptor which is being converted to string from</param>
|
|
/// <returns>string representation of the type descriptor</returns>
|
|
private static string GetStringFromTypeDesc(COM.ITypeInfo typeinfo, COM.TYPEDESC typedesc)
|
|
{
|
|
if ((VarEnum)typedesc.vt == VarEnum.VT_PTR)
|
|
{
|
|
COM.TYPEDESC refdesc = Marshal.PtrToStructure<COM.TYPEDESC>(typedesc.lpValue);
|
|
return GetStringFromTypeDesc(typeinfo, refdesc);
|
|
}
|
|
|
|
if ((VarEnum)typedesc.vt == VarEnum.VT_SAFEARRAY)
|
|
{
|
|
COM.TYPEDESC refdesc = Marshal.PtrToStructure<COM.TYPEDESC>(typedesc.lpValue);
|
|
return "SAFEARRAY(" + GetStringFromTypeDesc(typeinfo, refdesc) + ")";
|
|
}
|
|
|
|
if ((VarEnum)typedesc.vt == VarEnum.VT_USERDEFINED)
|
|
{
|
|
return GetStringFromCustomType(typeinfo, typedesc.lpValue);
|
|
}
|
|
|
|
switch ((VarEnum)typedesc.vt)
|
|
{
|
|
case VarEnum.VT_I1:
|
|
return "char";
|
|
|
|
case VarEnum.VT_I2:
|
|
return "short";
|
|
|
|
case VarEnum.VT_I4:
|
|
case VarEnum.VT_INT:
|
|
case VarEnum.VT_HRESULT:
|
|
return "int";
|
|
|
|
case VarEnum.VT_I8:
|
|
return "int64";
|
|
|
|
case VarEnum.VT_R4:
|
|
return "float";
|
|
|
|
case VarEnum.VT_R8:
|
|
return "double";
|
|
|
|
case VarEnum.VT_UI1:
|
|
return "byte";
|
|
|
|
case VarEnum.VT_UI2:
|
|
return "ushort";
|
|
|
|
case VarEnum.VT_UI4:
|
|
case VarEnum.VT_UINT:
|
|
return "uint";
|
|
|
|
case VarEnum.VT_UI8:
|
|
return "uint64";
|
|
|
|
case VarEnum.VT_BSTR:
|
|
case VarEnum.VT_LPSTR:
|
|
case VarEnum.VT_LPWSTR:
|
|
return "string";
|
|
|
|
case VarEnum.VT_DATE:
|
|
return "Date";
|
|
|
|
case VarEnum.VT_BOOL:
|
|
return "bool";
|
|
|
|
case VarEnum.VT_CY:
|
|
return "currency";
|
|
|
|
case VarEnum.VT_DECIMAL:
|
|
return "decimal";
|
|
|
|
case VarEnum.VT_CLSID:
|
|
return "clsid";
|
|
|
|
case VarEnum.VT_DISPATCH:
|
|
return "IDispatch";
|
|
|
|
case VarEnum.VT_UNKNOWN:
|
|
return "IUnknown";
|
|
|
|
case VarEnum.VT_VARIANT:
|
|
return "Variant";
|
|
|
|
case VarEnum.VT_VOID:
|
|
return "void";
|
|
|
|
case VarEnum.VT_ARRAY:
|
|
return "object[]";
|
|
|
|
case VarEnum.VT_EMPTY:
|
|
return "";
|
|
|
|
default:
|
|
return "Unknown!";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine .net type for the given type descriptor
|
|
/// </summary>
|
|
/// <param name="typedesc">COM type descriptor to convert</param>
|
|
/// <returns>type represented by the typedesc</returns>
|
|
internal static Type GetTypeFromTypeDesc(COM.TYPEDESC typedesc)
|
|
{
|
|
VarEnum vt = (VarEnum)typedesc.vt;
|
|
return VarEnumSelector.GetTypeForVarEnum(vt);
|
|
}
|
|
|
|
#pragma warning restore 618
|
|
|
|
/// <summary>
|
|
/// Converts a FuncDesc out of GetFuncDesc into a MethodInformation
|
|
/// </summary>
|
|
private static ComMethodInformation GetMethodInformation(COM.FUNCDESC funcdesc, bool skipLastParameter)
|
|
{
|
|
Type returntype = GetTypeFromTypeDesc(funcdesc.elemdescFunc.tdesc);
|
|
ParameterInformation[] parameters = GetParameterInformation(funcdesc, skipLastParameter);
|
|
bool hasOptional = false;
|
|
foreach (ParameterInformation p in parameters)
|
|
{
|
|
if (p.isOptional)
|
|
{
|
|
hasOptional = true;
|
|
break;
|
|
}
|
|
}
|
|
return new ComMethodInformation(false, hasOptional, parameters, returntype, funcdesc.memid, funcdesc.invkind);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtains the parameter information for a given FuncDesc
|
|
/// </summary>
|
|
internal static ParameterInformation[] GetParameterInformation(COM.FUNCDESC funcdesc, bool skipLastParameter)
|
|
{
|
|
int cParams = funcdesc.cParams;
|
|
if (skipLastParameter)
|
|
{
|
|
Diagnostics.Assert(cParams > 0, "skipLastParameter is only true for property setters where there is at least one parameter");
|
|
cParams--;
|
|
}
|
|
ParameterInformation[] parameters = new ParameterInformation[cParams];
|
|
|
|
IntPtr ElementDescriptionArrayPtr = funcdesc.lprgelemdescParam;
|
|
int ElementDescriptionSize = Marshal.SizeOf<COM.ELEMDESC>();
|
|
|
|
for (int i = 0; i < cParams; i++)
|
|
{
|
|
COM.ELEMDESC ElementDescription;
|
|
int ElementDescriptionArrayByteOffset;
|
|
IntPtr ElementDescriptionPointer;
|
|
bool fOptional = false;
|
|
|
|
ElementDescription = new COM.ELEMDESC();
|
|
ElementDescriptionArrayByteOffset = i * ElementDescriptionSize;
|
|
//Disable PRefast warning for converting to int32 and converting back into intptr.
|
|
//Code below takes into account 32 bit vs 64 bit conversions
|
|
#pragma warning disable 56515
|
|
|
|
if (IntPtr.Size == 4)
|
|
{
|
|
ElementDescriptionPointer = (IntPtr)(ElementDescriptionArrayPtr.ToInt32() + ElementDescriptionArrayByteOffset);
|
|
}
|
|
else
|
|
{
|
|
ElementDescriptionPointer = (IntPtr)(ElementDescriptionArrayPtr.ToInt64() + ElementDescriptionArrayByteOffset);
|
|
}
|
|
|
|
#pragma warning enable 56515
|
|
|
|
ElementDescription = Marshal.PtrToStructure<COM.ELEMDESC>(ElementDescriptionPointer);
|
|
|
|
//get the type of parameter
|
|
Type type = ComUtil.GetTypeFromTypeDesc(ElementDescription.tdesc);
|
|
Object defaultvalue = null;
|
|
|
|
//check is this parameter is optional.
|
|
if ((ElementDescription.desc.paramdesc.wParamFlags & COM.PARAMFLAG.PARAMFLAG_FOPT) != 0)
|
|
{
|
|
fOptional = true;
|
|
defaultvalue = Type.Missing;
|
|
}
|
|
|
|
bool fByRef = (ElementDescription.desc.paramdesc.wParamFlags & COM.PARAMFLAG.PARAMFLAG_FOUT) != 0;
|
|
parameters[i] = new ParameterInformation(type, fOptional, defaultvalue, fByRef);
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a MethodBase[] into a MethodInformation[]
|
|
/// </summary>
|
|
/// <returns>the ComMethodInformation[] corresponding to methods</returns>
|
|
internal static ComMethodInformation[] GetMethodInformationArray(COM.ITypeInfo typeInfo, Collection<int> methods, bool skipLastParameters)
|
|
{
|
|
int methodCount = methods.Count;
|
|
int count = 0;
|
|
ComMethodInformation[] returnValue = new ComMethodInformation[methodCount];
|
|
|
|
foreach (int index in methods)
|
|
{
|
|
IntPtr pFuncDesc;
|
|
typeInfo.GetFuncDesc(index, out pFuncDesc);
|
|
COM.FUNCDESC funcdesc = Marshal.PtrToStructure<COM.FUNCDESC>(pFuncDesc);
|
|
returnValue[count++] = ComUtil.GetMethodInformation(funcdesc, skipLastParameters);
|
|
typeInfo.ReleaseFuncDesc(pFuncDesc);
|
|
}
|
|
return returnValue;
|
|
}
|
|
}
|
|
} |