/********************************************************************++ 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 { /// /// Defines a utility class that is used by COM adapter. /// 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); /// /// Gets Method Signature from FuncDesc describing the method. /// /// ITypeInfo interface of the object /// FuncDesc which defines the method /// True if this is a property put; these properties take their return type from their first paramenter /// signature of the method 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 = ClrFacade.SizeOf(); 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 = ClrFacade.PtrToStructure(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(); } /// /// Gets the name of the method or property defined by funcdesc /// /// ITypeInfo interface of the type /// FuncDesc of property of method /// name of the method or property 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; } /// /// Gets the name of the custom type defined in the type library /// /// ITypeInfo interface of the type /// reference to the custom type /// name of the custom type 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 /// /// This function gets a string representation of the Type Descriptor /// This is used in generating signature for Properties and Methods. /// /// Reference to the type info to which the type descriptor belongs /// reference to type descriptor which is being converted to string from /// string representation of the type descriptor private static string GetStringFromTypeDesc(COM.ITypeInfo typeinfo, COM.TYPEDESC typedesc) { if ((VarEnum)typedesc.vt == VarEnum.VT_PTR) { COM.TYPEDESC refdesc = ClrFacade.PtrToStructure(typedesc.lpValue); return GetStringFromTypeDesc(typeinfo, refdesc); } if ((VarEnum)typedesc.vt == VarEnum.VT_SAFEARRAY) { COM.TYPEDESC refdesc = ClrFacade.PtrToStructure(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!"; } } /// /// Determine .net type for the given type descriptor /// /// COM type descriptor to convert /// type represented by the typedesc internal static Type GetTypeFromTypeDesc(COM.TYPEDESC typedesc) { VarEnum vt = (VarEnum)typedesc.vt; return VarEnumSelector.GetTypeForVarEnum(vt); } #pragma warning restore 618 /// /// Converts a FuncDesc out of GetFuncDesc into a MethodInformation /// 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); } /// /// Obtains the parameter information for a given FuncDesc /// 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 = ClrFacade.SizeOf(); 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 = ClrFacade.PtrToStructure(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; } /// /// Converts a MethodBase[] into a MethodInformation[] /// /// the ComMethodInformation[] corresponding to methods internal static ComMethodInformation[] GetMethodInformationArray(COM.ITypeInfo typeInfo, Collection 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 = ClrFacade.PtrToStructure(pFuncDesc); returnValue[count++] = ComUtil.GetMethodInformation(funcdesc, skipLastParameters); typeInfo.ReleaseFuncDesc(pFuncDesc); } return returnValue; } } }