| File: ComHost\TypeLibReader.cs | Web Access |
| Project: src\runtime\src\installer\managed\Microsoft.NET.HostModel\Microsoft.NET.HostModel.csproj (Microsoft.NET.HostModel) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Buffers.Binary; namespace Microsoft.NET.HostModel.ComHost { /// <summary> /// Reads data from a COM Type Library file based on the official implementation in the Win32 function LoadTypeLib. /// We do the reading ourselves instead of calling into the OS so we don't have to worry about the type library's /// dependencies being discoverable on disk. /// </summary> internal sealed class TypeLibReader { private readonly byte[] tlbBytes; public TypeLibReader(byte[] tlbBytes) { this.tlbBytes = tlbBytes; } private const int OffsetOfGuidOffset = sizeof(int) * 2; private const int SizeOfGuidOffset = sizeof(int); private const int OffsetOfMajorVersion = OffsetOfGuidOffset + SizeOfGuidOffset + sizeof(int) * 2 + sizeof(ushort) * 2; private const int SizeOfMajorVersion = sizeof(ushort); private const int OffsetOfMinorVersion = OffsetOfMajorVersion + SizeOfMajorVersion; private const int SizeOfMinorVersion = sizeof(ushort); private const int OffsetOfTypeInfosCount = OffsetOfMinorVersion + SizeOfMinorVersion + sizeof(int); private const int SizeOfTypeInfosCount = sizeof(int); private const int OffsetOfTablesStart = OffsetOfTypeInfosCount + SizeOfTypeInfosCount + sizeof(int) * 12; private const int NumTablesToSkip = 5; private const int SizeOfTableHeader = sizeof(int) * 4; private static Guid FindGuid(ReadOnlySpan<byte> fileContents) { checked { int typelibGuidEntryOffset = (int)BinaryPrimitives.ReadUInt32LittleEndian(fileContents.Slice(OffsetOfGuidOffset)); int infoRefsOffsetCount = (int)BinaryPrimitives.ReadUInt32LittleEndian(fileContents.Slice(OffsetOfTypeInfosCount)); int infoBytes = infoRefsOffsetCount * SizeOfTypeInfosCount; int guidTableOffset = OffsetOfTablesStart + infoBytes + SizeOfTableHeader * NumTablesToSkip; int fileOffset = (int)BinaryPrimitives.ReadUInt32LittleEndian(fileContents.Slice(guidTableOffset)); return new Guid(fileContents.Slice(fileOffset + typelibGuidEntryOffset, 16).ToArray()); } } public bool TryReadTypeLibGuidAndVersion(out Guid typelibId, out Version version) { typelibId = default; version = default; try { var span = new ReadOnlySpan<byte>(tlbBytes); typelibId = FindGuid(span); ushort majorVer = BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(OffsetOfMajorVersion)); ushort minorVer = BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(OffsetOfMinorVersion)); version = new Version(majorVer, minorVer); return true; } catch (System.OverflowException) { return false; } catch (System.IndexOutOfRangeException) { return false; } } } }