/// <remarks> /// Use only with VBA-supplied <see cref="ITypeInfo"/> which may return a <see cref="VARDESC"/> that do not conform to /// the MS-OAUT in describing the constants. See section 2.2.43 at: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/ae7791d2-4399-4dff-b7c6-b0d4f3dce982 /// /// To further complicate the situation, on 64-bit platform, the <see cref="VARDESC.DESCUNION.oInst"/> is a 32-bit integer whereas /// the <see cref="VARDESC.DESCUNION.lpvarValue"/> is a pointer. On 32-bit platform, the sizes of 2 members are exactly same so no /// problem. But on 64-bit platform, setting the <c>oInst</c>to 0 does not necessarily zero-initialize the entire region. Thus, the /// upper 32-bit part of the <c>lpvarValue</c> can contain garbage which will confound the simple null pointer check. Thus to guard /// against this, we will check the <c>oInst</c> value to see if it's zero. /// /// There is a small but non-zero chance that there might be a valid pointer that happens to be only in high half of the address... /// in that case, it'll be wrong but since VBA is always writing <see cref="VARKIND.VAR_STATIC"/> to the <see cref="VARDESC.varkind"/> /// field. To accommodate this unlikely possibility, we take advantage of VBA's other failure to comply with MS-OAUT specifications: /// None of its constants has a valid member ID. Normally they are assigned <c>MEMBER_NIL</c> which makes them useless for enumeration. To /// accommodate this, the TypeInfoWrapper in Rubberduck.VBEditor project will generate unique member IDs for those constants. Thus, we can use /// the same range to infer that it's a constant assigned by the TypeInfoWrapper. /// </remarks> /// <param name="varDesc">The <see cref="VARDESC"/> from a VBA <see cref="ITypeInfo"/></param> /// <returns>True if this is most likely a constant. False when it's definitely not.</returns> public static bool IsValidVBAConstant(this VARDESC varDesc) { // TODO: Move the function to a better home and avoid duplication of constants (see TypeInfoWrapper) const int _ourConstantsDispatchMemberIDRangeStart = unchecked ((int)0xFEDC0000); const int _ourConstantsDispatchMemberIDRangeBitmaskCheck = unchecked ((int)0xFFFF0000); return((varDesc.memid & _ourConstantsDispatchMemberIDRangeBitmaskCheck) >= _ourConstantsDispatchMemberIDRangeStart && varDesc.varkind == VARKIND.VAR_STATIC && varDesc.desc.oInst != 0); }
/// <summary> /// Helper method for retrieving type attributes for a given type info /// This method needs to also return the native pointer to be released when we're done with our VARDESC. /// It's not really possible to copy everything to a managed struct and then release the ptr immediately /// here, since VARDESCs contain other native pointers we may need to access. /// </summary> internal static void GetVarDescForVarIndex(ITypeInfo typeInfo, int varIndex, out VARDESC varDesc, out IntPtr varDescHandle) { typeInfo.GetVarDesc(varIndex, out IntPtr pVarDesc); // GetVarDesc should never return null, this is just to be safe if (pVarDesc == IntPtr.Zero) { throw new COMException( ResourceUtilities.GetResourceString("ResolveComReference.CannotRetrieveTypeInformation")); } varDesc = (VARDESC)Marshal.PtrToStructure(pVarDesc, typeof(VARDESC)); varDescHandle = pVarDesc; }
public FieldInfo(VARDESC vardesc, ITypeInfo info, IVbaTypeRepository repo) { Name = ComHelper.GetMemberName(info, vardesc); Type = repo.GetVbaType(vardesc.elemdescVar.tdesc, info); IsConstant = ComHelper.IsConstant(vardesc); if (IsConstant) { Value = ComHelper.GetConstantValue(vardesc); } else { // TODO handle other cases here. May need reference to parent type. IsField = true; } }
public void GetVarDesc(int index, out IntPtr ppVarDesc) { // Fail BEFORE allocating the handle to avoid leaks. If the real COM object fails in this method // and doesn't return the handle or clean it up itself there's not much we can do to avoid the leak. _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetVarDesc); ppVarDesc = _memoryHelper.AllocateHandle(Marshal.SizeOf <VARDESC>()); _memoryHelper.EnterSubAllocationScope(ppVarDesc); VARDESC varDesc = new VARDESC(); varDesc.elemdescVar.tdesc = _definedVariables[index].CreateTypeDesc(new IntPtr(index + s_HREF_VARS_OFFSET), _memoryHelper); _memoryHelper.ExitSubAllocationScope(); Marshal.StructureToPtr(varDesc, ppVarDesc, false); }
static void DealWithTypeInfo(UCOMITypeInfo it) { // Get the names from ITypeInfo string name; string docstring; Int32 ctxt; string helpfile; // TypeInfo name it.GetDocumentation(-1, out name, out docstring, out ctxt, out helpfile); IntPtr pa; it.GetTypeAttr(out pa); TYPEATTR ta = (TYPEATTR)Marshal.PtrToStructure(pa, typeof(TYPEATTR)); DealWithName(name, ta.guid); // Deal with funcs for (int i = 0; i < ta.cFuncs; i++) { IntPtr pfd; it.GetFuncDesc(i, out pfd); FUNCDESC fd = (FUNCDESC)Marshal.PtrToStructure(pfd, typeof(FUNCDESC)); it.GetDocumentation(fd.memid, out name, out docstring, out ctxt, out helpfile); DealWithName(name, Guid.Empty); } // Deal with vars for (int i = 0; i < ta.cVars; i++) { IntPtr pvd; it.GetVarDesc(i, out pvd); VARDESC vd = (VARDESC)Marshal.PtrToStructure(pvd, typeof(VARDESC)); it.GetDocumentation(vd.memid, out name, out docstring, out ctxt, out helpfile); DealWithName(name, Guid.Empty); } }
public VarDesc(ITypeInfo typeinfo, int index) { m_typeinfo = typeinfo; m_ipVarDesc = TypeLibResourceManager.GetDaemon().GetVarDesc(typeinfo, index); m_vardesc = (VARDESC)Marshal.PtrToStructure(m_ipVarDesc, typeof(VARDESC)); }
public unsafe int RemoteGetVarDesc(uint index, VARDESC** ppVarDesc, CLEANLOCALSTORAGE* pDummy) { ITypeInfo_vtbl** @this = (ITypeInfo_vtbl**)reference; ITypeInfo_vtbl* vtbl = *@this; if (vtbl == null) throw new InvalidComObjectException(); Delegate genericDelegate = Marshal.GetDelegateForFunctionPointer(vtbl->method_6, typeof(delegate_6)); delegate_6 method = (delegate_6)genericDelegate; return method(@this, index, ppVarDesc, pDummy); }
public unsafe int RemoteBind(char* szName, uint lHashVal, ushort wFlags, ITypeInfo* ppTInfo, DESCKIND* pDescKind, FUNCDESC** ppFuncDesc, VARDESC** ppVarDesc, ITypeComp* ppTypeComp, CLEANLOCALSTORAGE* pDummy) { ITypeComp_vtbl** @this = (ITypeComp_vtbl**)reference; ITypeComp_vtbl* vtbl = *@this; if (vtbl == null) throw new InvalidComObjectException(); Delegate genericDelegate = Marshal.GetDelegateForFunctionPointer(vtbl->method_3, typeof(delegate_3)); delegate_3 method = (delegate_3)genericDelegate; return method(@this, szName, lHashVal, wFlags, ppTInfo, pDescKind, ppFuncDesc, ppVarDesc, ppTypeComp, pDummy); }