| File: ClrDataAppDomain.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Legacy\Microsoft.Diagnostics.DataContractReader.Legacy.csproj (Microsoft.Diagnostics.DataContractReader.Legacy) |
// 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.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataAppDomain : IXCLRDataAppDomain { private const uint DefaultAppDomainId = 1; private readonly Target _target; private readonly TargetPointer _appDomain; private readonly IXCLRDataAppDomain? _legacyImpl; public TargetPointer Address => _appDomain; public ClrDataAppDomain(Target target, TargetPointer appDomain, IXCLRDataAppDomain? legacyImpl) { _target = target; _appDomain = appDomain; _legacyImpl = legacyImpl; } int IXCLRDataAppDomain.GetProcess(DacComNullableByRef<IXCLRDataProcess> process) => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; int IXCLRDataAppDomain.GetName(uint bufLen, uint* nameLen, char* name) { int hr = HResults.S_OK; string friendlyName; try { ILoader loader = _target.Contracts.Loader; friendlyName = loader.GetAppDomainFriendlyName(); } catch (VirtualReadException) { // Match native DAC / SOSDacImpl behavior: fall back to empty string // when the FriendlyName pointer targets unreadable memory. friendlyName = string.Empty; } catch (System.Exception ex) { hr = ex.HResult; friendlyName = string.Empty; } if (hr >= 0) { OutputBufferHelpers.CopyStringToBuffer(name, bufLen, nameLen, friendlyName); // Match native DAC behavior: return S_FALSE when output is truncated. uint requiredLen = (uint)friendlyName.Length + 1; if (name is not null && bufLen > 0 && bufLen < requiredLen) hr = HResults.S_FALSE; } #if DEBUG if (_legacyImpl is not null) { uint nameLenLocal; char[] legacyNameBuf = new char[bufLen > 0 ? bufLen : 1]; int hrLocal; fixed (char* pLegacyName = legacyNameBuf) { hrLocal = _legacyImpl.GetName(bufLen, &nameLenLocal, name is not null ? pLegacyName : null); } Debug.ValidateHResult(hr, hrLocal); if (hr >= 0) { if (nameLen is not null) Debug.Assert(*nameLen == nameLenLocal, $"cDAC: {*nameLen}, DAC: {nameLenLocal}"); if (name is not null && bufLen > 0) { // On truncation (S_FALSE), nameLenLocal is the full required length // which may exceed bufLen. Cap to the actual buffer size. int compareLen = (int)Math.Min(nameLenLocal, bufLen) - 1; if (compareLen > 0) { string dacName = new string(legacyNameBuf, 0, compareLen); string cdacName = new string(name, 0, compareLen); Debug.Assert(dacName == cdacName, $"cDAC: {cdacName}, DAC: {dacName}"); } } } } #endif return hr; } int IXCLRDataAppDomain.GetUniqueID(ulong* id) { int hr = HResults.S_OK; try { if (id is null) throw new ArgumentNullException(nameof(id)); *id = DefaultAppDomainId; } catch (System.Exception ex) { hr = ex.HResult; } #if DEBUG if (_legacyImpl is not null && hr >= 0) { ulong idLocal; int hrLocal = _legacyImpl.GetUniqueID(&idLocal); Debug.ValidateHResult(hr, hrLocal); Debug.Assert(*id == idLocal, $"cDAC: {*id}, DAC: {idLocal}"); } #endif return hr; } int IXCLRDataAppDomain.GetFlags(uint* flags) { int hr = HResults.S_OK; try { if (flags is null) throw new ArgumentNullException(nameof(flags)); // CLRDATA_DOMAIN_DEFAULT = 0 *flags = 0; } catch (System.Exception ex) { hr = ex.HResult; } #if DEBUG if (_legacyImpl is not null && hr >= 0) { uint flagsLocal; int hrLocal = _legacyImpl.GetFlags(&flagsLocal); Debug.ValidateHResult(hr, hrLocal); Debug.Assert(*flags == flagsLocal, $"cDAC: {*flags}, DAC: {flagsLocal}"); } #endif return hr; } int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) { int hr = HResults.S_FALSE; try { if (System.Runtime.InteropServices.ComWrappers.TryGetObject((nint)appDomain, out object? obj) && obj is ClrDataAppDomain other) { hr = _appDomain == other._appDomain ? HResults.S_OK : HResults.S_FALSE; } } catch (System.Exception ex) { hr = ex.HResult; } #if DEBUG if (_legacyImpl is not null) { int hrLocal = _legacyImpl.IsSameObject(appDomain); Debug.Assert(hrLocal == hr, $"cDAC: {hr}, DAC: {hrLocal}"); } #endif return hr; } int IXCLRDataAppDomain.GetManagedObject(DacComNullableByRef<IXCLRDataValue> value) => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; int IXCLRDataAppDomain.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; }