internal static ComMemberInfo MakeComMemberInfo(BasicInfo parent,
                                                        TYPEKIND typeKind,
                                                        UCOMITypeInfo typeInfo,
                                                        int index,
                                                        bool dispatch,
                                                        bool dual)
        {
            IntPtr        funcDescPtr;
            FUNCDESC      funcDesc;
            ComMemberInfo comMemberInfo = null;

            typeInfo.GetFuncDesc(index, out funcDescPtr);
            funcDesc = (FUNCDESC)Marshal.PtrToStructure(funcDescPtr, typeof(FUNCDESC));
            // from http://www.opengroup.org/onlinepubs/009899899/toc.htm
            // Table 25-43:  MEMBERID Format
            //
            // Bits Value
            // 0 - 15 Offset. Any value is permissible.
            // 16 - 21 The nesting level of this type information
            //   in the inheritance hierarchy. For example:
            //   interface mydisp : IDispatch.
            //   The nesting level of IUnknown() is 0,
            //   IDispatch is 1, and MyDisp is 2.
            // 22 - 25 Reserved. Must be zero.
            // 26 - 28 Value of the DISPID.
            // 29 TRUE if this is the member ID for a FUNCDESC; otherwise FALSE.
            // 30 - 31 Must be 01.
            // For a dispatch interface, show only those members that are
            // part of the user's definition, which is bits 16-17 == 2
            // (as above); also only if this is a MEMBERID format (bit 30 on)
            // (some members just use the low order bits and the rest
            // are empty); also show any negative member Id.
            if (!dispatch ||
//				((Int16)funcDesc.memid < 0) ||
                (funcDesc.memid & 0xFFFF) < 0 ||
                (funcDesc.memid & 0x40000000) == 0 ||
                (funcDesc.memid & 0x30000) == 0x20000)
            {
                comMemberInfo = new ComMemberInfo(parent,
                                                  typeKind,
                                                  typeInfo,
                                                  index,
                                                  dispatch,
                                                  funcDesc);
            }
            else
            {
                if (TraceUtil.If(null, TraceLevel.Verbose))
                {
                    Trace.WriteLine("MemberInfo: SKIPPING index: "
                                    + index + " memid: 0x"
                                    + funcDesc.memid.ToString("X"));
                }
            }
            typeInfo.ReleaseFuncDesc(funcDescPtr);
            return(comMemberInfo);
        }
Exemplo n.º 2
0
		internal static ComMemberInfo MakeComMemberInfo(BasicInfo parent,
			TYPEKIND typeKind,
			UCOMITypeInfo typeInfo,
			int index,
			bool dispatch,
			bool dual)
		{
			IntPtr funcDescPtr;
			FUNCDESC funcDesc;
			ComMemberInfo comMemberInfo = null;
			typeInfo.GetFuncDesc(index, out funcDescPtr);
			funcDesc = (FUNCDESC)Marshal.PtrToStructure(funcDescPtr, typeof(FUNCDESC));
			// from http://www.opengroup.org/onlinepubs/009899899/toc.htm
			// Table 25-43:  MEMBERID Format
			//
			// Bits Value
			// 0 - 15 Offset. Any value is permissible.
			// 16 - 21 The nesting level of this type information
			//   in the inheritance hierarchy. For example: 
			//   interface mydisp : IDispatch. 
			//   The nesting level of IUnknown() is 0, 
			//   IDispatch is 1, and MyDisp is 2.
			// 22 - 25 Reserved. Must be zero.
			// 26 - 28 Value of the DISPID.
			// 29 TRUE if this is the member ID for a FUNCDESC; otherwise FALSE.
			// 30 - 31 Must be 01.
			// For a dispatch interface, show only those members that are
			// part of the user's definition, which is bits 16-17 == 2 
			// (as above); also only if this is a MEMBERID format (bit 30 on)
			// (some members just use the low order bits and the rest 
			// are empty); also show any negative member Id.
			if (!dispatch || 
//				((Int16)funcDesc.memid < 0) ||
			    (funcDesc.memid & 0xFFFF) < 0 ||
				(funcDesc.memid & 0x40000000) == 0 ||
				(funcDesc.memid & 0x30000) == 0x20000) {
				comMemberInfo = new ComMemberInfo(parent,
												  typeKind,
												  typeInfo,
												  index,
												  dispatch,
												  funcDesc);
			} else {
				if (TraceUtil.If(null, TraceLevel.Verbose)) {
					Trace.WriteLine("MemberInfo: SKIPPING index: " 
									+ index + " memid: 0x" 
									+ funcDesc.memid.ToString("X"));
				}
			}
			typeInfo.ReleaseFuncDesc(funcDescPtr);
			return comMemberInfo;
		}
Exemplo n.º 3
0
        /// <summary>
        /// Gets parameter information for the given member.
        /// </summary>
        /// <remarks>
        /// Uses the COM ITypeInfo interface to get the information. Does not throw. If it returns false then the out params
        /// will not hold useful information.
        /// </remarks>
        /// <param name="obj"></param>
        /// <param name="memberName"></param>
        /// <param name="callType"></param>
        /// <param name="isBeingCalledWithZeroArgs"></param>
        /// <param name="paramTypes"></param>
        /// <param name="paramFlags"></param>
        /// <param name="endsWithParamArray"></param>
        /// <returns>true if the name refers to a valid member or if no type information is available</returns>
        ///
        internal static bool GetMemberInfo(object obj, ref string memberName, int callType, bool isBeingCalledWithZeroArgs,
                                           out Type[] paramTypes, out PARAMFLAG[] paramFlags, out bool endsWithParamArray)
        {
            // There are some early returns in this method, so we initialize the out params right away. To the caller, if these values
            // come back null it means that the information could not be determined.
            paramTypes         = null;
            paramFlags         = null;
            endsWithParamArray = false;

            int defaultLCID = GetUserDefaultLCID();

            try {
                // Throws in this outer try cause true to be returned. They mean "type info could not be obtained, so the member is not
                // known to be invalid."

                UCOMIDispatch iDisp        = GetIDispatch(obj);
                int           memberDispId = GetMemberDispID(obj, iDisp, ref memberName);
                if (memberDispId == -1)
                {
                    // Name not found by GetIDsOfNames.
                    return(false);
                }

                // If no args are being passed, then we can skip all the machinations below about type info.
                if (isBeingCalledWithZeroArgs)
                {
                    return(true);
                }

                UCOMITypeInfo iTypeInfo = GetITypeInfo(obj, iDisp);
                IntPtr        pFuncDesc;

                // Check to see if the func index for this member name is already cached from a previous call.
                FuncIndexHolder fih = (FuncIndexHolder)Marshal.GetComObjectData(obj, "NETLinkFuncIndex" + memberName);
                if (fih == null)
                {
                    // This will be populated below.
                    fih = new FuncIndexHolder();
                    Marshal.SetComObjectData(obj, "NETLinkFuncIndex" + memberName, fih);
                }
                int funcIndex = -1;
                if (callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_GET)
                {
                    if (fih.funcIndexForCALLTYPE_FIELD_OR_SIMPLE_PROP_GET != -1)
                    {
                        funcIndex = fih.funcIndexForCALLTYPE_FIELD_OR_SIMPLE_PROP_GET;
                    }
                }
                else if (callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_SET || callType == Install.CALLTYPE_PARAM_PROP_SET)
                {
                    if (fih.funcIndexForCALLTYPE_FIELD_OR_ANY_PROP_SET != -1)
                    {
                        funcIndex = fih.funcIndexForCALLTYPE_FIELD_OR_ANY_PROP_SET;
                    }
                }
                else if (callType == Install.CALLTYPE_METHOD || callType == Install.CALLTYPE_PARAM_PROP_GET)
                {
                    // COM objects are treated by M code as if they all have indexers, so calls like obj[1] will
                    // come in as CALLTYPE_PARAM_PROP_GET with a property name of Item. We can just treat these like
                    // method calls.
                    if (fih.funcIndexForCALLTYPE_METHOD != -1)
                    {
                        funcIndex = fih.funcIndexForCALLTYPE_METHOD;
                    }
                }

                // Did not have the func index for this call type cached.
                if (funcIndex == -1)
                {
                    IntPtr pTypeAttr;
                    iTypeInfo.GetTypeAttr(out pTypeAttr);
                    TYPEATTR typeAttr = (TYPEATTR)Marshal.PtrToStructure(pTypeAttr, typeof(TYPEATTR));
                    int      numFuncs = typeAttr.cFuncs;
                    iTypeInfo.ReleaseTypeAttr(pTypeAttr);
                    bool foundDispId = false;
                    for (int thisIndex = 0; thisIndex < numFuncs; thisIndex++)
                    {
                        // Be aware that GetFuncDesc() can (I think) throw a cryptic "Element not found" exception,
                        // such as for a hidden property like (Excel) _Application.ActiveDialog.
                        iTypeInfo.GetFuncDesc(thisIndex, out pFuncDesc);
                        FUNCDESC   funcDesc     = (FUNCDESC)Marshal.PtrToStructure(pFuncDesc, typeof(FUNCDESC));
                        int        thisMemberId = funcDesc.memid;
                        INVOKEKIND invokeKind   = funcDesc.invkind;
                        iTypeInfo.ReleaseFuncDesc(pFuncDesc);
                        if (thisMemberId == memberDispId)
                        {
                            foundDispId = true;
                            // Verify that it is a member of the correct call type.
                            if (callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_GET && invokeKind == INVOKEKIND.INVOKE_PROPERTYGET)
                            {
                                fih.funcIndexForCALLTYPE_FIELD_OR_SIMPLE_PROP_GET = thisIndex;
                                funcIndex = thisIndex;
                                break;
                            }
                            else if ((callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_SET || callType == Install.CALLTYPE_PARAM_PROP_SET) &&
                                     (invokeKind == INVOKEKIND.INVOKE_PROPERTYPUT || invokeKind == INVOKEKIND.INVOKE_PROPERTYPUTREF))
                            {
                                fih.funcIndexForCALLTYPE_FIELD_OR_ANY_PROP_SET = thisIndex;
                                funcIndex = thisIndex;
                                break;
                            }
                            else if ((callType == Install.CALLTYPE_METHOD && (invokeKind == INVOKEKIND.INVOKE_FUNC || invokeKind == INVOKEKIND.INVOKE_PROPERTYGET)) ||
                                     (callType == Install.CALLTYPE_PARAM_PROP_GET && invokeKind == INVOKEKIND.INVOKE_PROPERTYGET))
                            {
                                // Parameterized prop gets, not sets, look like CALLTYPE_METHOD. Also, as discussed in an earlier comment,
                                // indexer notation calls (obj[1]) are supported for all COM objects and come in as CALLTYPE_PARAM_PROP_GET.
                                fih.funcIndexForCALLTYPE_METHOD = thisIndex;
                                funcIndex = thisIndex;
                                break;
                            }
                        }
                    }
                    if (funcIndex == -1)
                    {
                        // We didn't find the member in our search. This can happen in two ways. First, the member might
                        // exist but not be the right call type. For this case we want to return false. Second, we didn't
                        // even find the dispid. This can happen in unusual cases I don't understan An example of this
                        // is the IWebBrowser2 interface obtained by CreateCOMObject["InternetExplorer.Application"].
                        // For this case we want to return true, as if there was no type info at all available, so the
                        // call can still proceed.
                        return(!foundDispId);
                    }
                }

                // If we get to here, we have a valid funcIndex and memberDispId, and the member is of the correct variety
                // that corresponds to how it was called (e.g., it's a method and it was called as such). All that
                // remains is to get the parameter types.

                iTypeInfo.GetFuncDesc(funcIndex, out pFuncDesc);
                try {
                    FUNCDESC funcDesc = (FUNCDESC)Marshal.PtrToStructure(pFuncDesc, typeof(FUNCDESC));
                    Debug.Assert(funcDesc.memid == memberDispId);
                    int paramCount = funcDesc.cParams;
                    // Functions that end with a VB-style ParamArray (a variable-length argument sequence) have -1 for the
                    // cParamsOpt member. It is convenient to treat them specially, hence the 'endsWithParamArray' variable
                    // (which is an out param for this method). The special treatment involves leaving the ParamArray arg off
                    // the list of paramFlags and paramTypes. We just pretend there is one less arg to the function but
                    // record that it ends with a ParamArray. We always know the type of this arg anyway: ByRef Variant[].
                    // To the caller, though, the individual args are sent as a sequence, not packed into an array.
                    endsWithParamArray = funcDesc.cParamsOpt == -1;
                    if (endsWithParamArray)
                    {
                        paramCount--;
                    }
                    paramTypes = new Type[paramCount];
                    paramFlags = new PARAMFLAG[paramCount];
                    IntPtr pElemDescArray = funcDesc.lprgelemdescParam;
                    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
                    {
                        ELEMDESC elemDesc = (ELEMDESC)Marshal.PtrToStructure((IntPtr)(pElemDescArray.ToInt64() +
                                                                                      paramIndex * Marshal.SizeOf(typeof(ELEMDESC))), typeof(ELEMDESC));
                        TYPEDESC typeDesc = elemDesc.tdesc;
                        paramFlags[paramIndex] = elemDesc.desc.paramdesc.wParamFlags;
                        // I think I should never see a retval param here. They have been automatically converted to return types.
                        Debug.Assert((paramFlags[paramIndex] & PARAMFLAG.PARAMFLAG_FRETVAL) == 0);
                        VarEnum variantType = (VarEnum)typeDesc.vt;
                        bool    isArray     = variantType == VarEnum.VT_SAFEARRAY;
                        bool    isPtr       = variantType == VarEnum.VT_PTR;
                        bool    isOut       = (paramFlags[paramIndex] & PARAMFLAG.PARAMFLAG_FOUT) != 0;
                        // VB array params will have isPtr and !isArray, because they are always ByRef (thus ptrs).
                        // In general (always?), out params will be VT_PTR.
                        if (isArray || isPtr)
                        {
                            IntPtr   pElementTypeDesc = typeDesc.lpValue;
                            TYPEDESC elementTypeDesc  = (TYPEDESC)Marshal.PtrToStructure(pElementTypeDesc, typeof(TYPEDESC));
                            variantType = (VarEnum)elementTypeDesc.vt;
                            // If the arg was a ptr to an array (e.g., as in VB objects), do it again to get the element type.
                            if (variantType == VarEnum.VT_SAFEARRAY)
                            {
                                isArray          = true;
                                pElementTypeDesc = elementTypeDesc.lpValue;
                                elementTypeDesc  = (TYPEDESC)Marshal.PtrToStructure(pElementTypeDesc, typeof(TYPEDESC));
                                variantType      = (VarEnum)elementTypeDesc.vt;
                            }
                        }
                        paramTypes[paramIndex] = managedTypeForVariantType(variantType, isArray, isPtr, isOut);
                    }
                } finally {
                    iTypeInfo.ReleaseFuncDesc(pFuncDesc);
                }
                return(true);
            } catch (Exception) {
                return(true);
            }
        }