diff --git a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs index d6f50cde4297..68818902b786 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs @@ -253,5 +253,9 @@ public static Assembly GetEntryAssembly() GetEntryAssembly(JitHelpers.GetObjectHandleOnStack(ref entryAssembly)); return entryAssembly; } + + // Exists to faciliate code sharing between CoreCLR and CoreRT. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal bool IsRuntimeImplemented() => this is RuntimeAssembly; } } diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 3035117b9e53..14929d660983 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -335,7 +335,7 @@ internal static RuntimeAssembly InternalLoadAssemblyName( bool throwOnFileNotFound, IntPtr ptrLoadContextBinder = default) { - return InternalLoadAssemblyName(assemblyRef, reqAssembly, ref stackMark, IntPtr.Zero, true /*throwOnError*/, ptrLoadContextBinder); + return InternalLoadAssemblyName(assemblyRef, reqAssembly, ref stackMark, IntPtr.Zero, throwOnFileNotFound, ptrLoadContextBinder); } internal static RuntimeAssembly InternalLoadAssemblyName( @@ -646,15 +646,13 @@ public override Assembly GetSatelliteAssembly(CultureInfo culture, Version versi if (culture == null) throw new ArgumentNullException(nameof(culture)); - string name = GetSimpleName() + ".resources"; - return InternalGetSatelliteAssembly(name, culture, version, true); + return InternalGetSatelliteAssembly(culture, version, true); } [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod - internal RuntimeAssembly InternalGetSatelliteAssembly(string name, - CultureInfo culture, - Version version, - bool throwOnFileNotFound) + internal Assembly InternalGetSatelliteAssembly(CultureInfo culture, + Version version, + bool throwOnFileNotFound) { // This stack crawl mark is never used because the requesting assembly is explicitly specified, // so the value could be anything. @@ -670,13 +668,18 @@ internal RuntimeAssembly InternalGetSatelliteAssembly(string name, an.Version = version; an.CultureInfo = culture; - an.Name = name; + an.Name = GetSimpleName() + ".resources"; RuntimeAssembly retAssembly = nLoad(an, null, this, ref stackMark, IntPtr.Zero, throwOnFileNotFound); - if (retAssembly == this || (retAssembly == null && throwOnFileNotFound)) + if (retAssembly == this) + { + retAssembly = null; + } + + if (retAssembly == null && throwOnFileNotFound) { throw new FileNotFoundException(string.Format(culture, SR.IO_FileNotFound_FileName, an.Name)); } diff --git a/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs b/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs index 42b601336a55..26a601a34ab1 100644 --- a/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs +++ b/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs @@ -58,7 +58,7 @@ public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary UltimateResourceFallbackLocation.Satellite) { @@ -228,7 +226,7 @@ internal ResourceSet CreateResourceSet(Stream store, Assembly assembly) // resMgrHeaderVersion is older than this ResMgr version. // We should add in backwards compatibility support here. - throw new NotSupportedException(SR.Format(SR.NotSupported_ObsoleteResourcesFile, _mediator.MainAssembly.GetSimpleName())); + throw new NotSupportedException(SR.Format(SR.NotSupported_ObsoleteResourcesFile, _mediator.MainAssembly.GetName().Name)); } store.Position = startPos; @@ -306,7 +304,7 @@ internal ResourceSet CreateResourceSet(Stream store, Assembly assembly) } } - private Stream GetManifestResourceStream(RuntimeAssembly satellite, string fileName) + private Stream GetManifestResourceStream(Assembly satellite, string fileName) { Debug.Assert(satellite != null, "satellite shouldn't be null; check caller"); Debug.Assert(fileName != null, "fileName shouldn't be null; check caller"); @@ -323,8 +321,8 @@ private Stream GetManifestResourceStream(RuntimeAssembly satellite, string fileN // Looks up a .resources file in the assembly manifest using // case-insensitive lookup rules. Yes, this is slow. The metadata // dev lead refuses to make all assembly manifest resource lookups case-insensitive, - // even optionally case-insensitive. - private Stream CaseInsensitiveManifestResourceStreamLookup(RuntimeAssembly satellite, string name) + // even optionally case-insensitive. + private Stream CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name) { Debug.Assert(satellite != null, "satellite shouldn't be null; check caller"); Debug.Assert(name != null, "name shouldn't be null; check caller"); @@ -360,7 +358,7 @@ private Stream CaseInsensitiveManifestResourceStreamLookup(RuntimeAssembly satel return satellite.GetManifestResourceStream(canonicalName); } - private RuntimeAssembly GetSatelliteAssembly(CultureInfo lookForCulture) + private Assembly GetSatelliteAssembly(CultureInfo lookForCulture) { if (!_mediator.LookedForSatelliteContractVersion) { @@ -368,8 +366,7 @@ private RuntimeAssembly GetSatelliteAssembly(CultureInfo lookForCulture) _mediator.LookedForSatelliteContractVersion = true; } - RuntimeAssembly satellite = null; - string satAssemblyName = GetSatelliteAssemblyName(); + Assembly satellite = null; // Look up the satellite assembly, but don't let problems // like a partially signed satellite assembly stop us from @@ -377,7 +374,7 @@ private RuntimeAssembly GetSatelliteAssembly(CultureInfo lookForCulture) // Yet also somehow log this error for a developer. try { - satellite = _mediator.MainAssembly.InternalGetSatelliteAssembly(satAssemblyName, lookForCulture, _mediator.SatelliteContractVersion, false); + satellite = InternalGetSatelliteAssembly(_mediator.MainAssembly, lookForCulture, _mediator.SatelliteContractVersion); } // Jun 08: for cases other than ACCESS_DENIED, we'll assert instead of throw to give release builds more opportunity to fallback. @@ -390,14 +387,14 @@ private RuntimeAssembly GetSatelliteAssembly(CultureInfo lookForCulture) int hr = fle._HResult; if (hr != Win32Marshal.MakeHRFromErrorCode(Interop.Errors.ERROR_ACCESS_DENIED)) { - Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + " with error code 0x" + hr.ToString("X", CultureInfo.InvariantCulture) + Environment.NewLine + "Exception: " + fle); + Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetName().Version.ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetName().Name + " with error code 0x" + hr.ToString("X", CultureInfo.InvariantCulture) + Environment.NewLine + "Exception: " + fle); } } // Don't throw for zero-length satellite assemblies, for compat with v1 catch (BadImageFormatException bife) { - Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + Environment.NewLine + "Exception: " + bife); + Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetName().Version.ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetName().Name + Environment.NewLine + "Exception: " + bife); } return satellite; @@ -436,24 +433,15 @@ private bool CanUseDefaultResourceClasses(string readerTypeName, string resSetTy return true; } - private string GetSatelliteAssemblyName() - { - string satAssemblyName = _mediator.MainAssembly.GetSimpleName(); - satAssemblyName += ".resources"; - return satAssemblyName; - } - private void HandleSatelliteMissing() { - string satAssemName = _mediator.MainAssembly.GetSimpleName() + ".resources.dll"; + string satAssemName = _mediator.MainAssembly.GetName().Name + ".resources.dll"; if (_mediator.SatelliteContractVersion != null) { satAssemName += ", Version=" + _mediator.SatelliteContractVersion.ToString(); } - AssemblyName an = new AssemblyName(); - an.SetPublicKey(_mediator.MainAssembly.GetPublicKey()); - byte[] token = an.GetPublicKeyToken(); + byte[] token = _mediator.MainAssembly.GetName().GetPublicKeyToken(); int iLen = token.Length; StringBuilder publicKeyTok = new StringBuilder(iLen * 2); @@ -489,11 +477,26 @@ private void HandleResourceStreamMissing(string fileName) if (_mediator.LocationInfo != null && _mediator.LocationInfo.Namespace != null) resName = _mediator.LocationInfo.Namespace + Type.Delimiter; resName += fileName; - throw new MissingManifestResourceException(SR.Format(SR.MissingManifestResource_NoNeutralAsm, resName, _mediator.MainAssembly.GetSimpleName())); + throw new MissingManifestResourceException(SR.Format(SR.MissingManifestResource_NoNeutralAsm, resName, _mediator.MainAssembly.GetName().Name)); + } + + // Internal version of GetSatelliteAssembly that avoids throwing FileNotFoundException + private static Assembly InternalGetSatelliteAssembly(Assembly mainAssembly, + CultureInfo culture, + Version version) + { + return ((RuntimeAssembly)mainAssembly).InternalGetSatelliteAssembly(culture, version, throwOnFileNotFound: false); } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetNeutralResourcesLanguageAttribute(RuntimeAssembly assemblyHandle, StringHandleOnStack cultureName, out short fallbackLocation); + private static extern bool GetNeutralResourcesLanguageAttribute(RuntimeAssembly assemblyHandle, StringHandleOnStack cultureName, out short fallbackLocation); + + private static bool GetNeutralResourcesLanguageAttribute(Assembly assemblyHandle, ref string cultureName, out short fallbackLocation) + { + return GetNeutralResourcesLanguageAttribute(((RuntimeAssembly)assemblyHandle).GetNativeHandle(), + JitHelpers.GetStringHandleOnStack(ref cultureName), + out fallbackLocation); + } } } diff --git a/src/System.Private.CoreLib/src/System/Resources/ResourceManager.cs b/src/System.Private.CoreLib/src/System/Resources/ResourceManager.cs index 69d8e5fc505a..aefe94eb628d 100644 --- a/src/System.Private.CoreLib/src/System/Resources/ResourceManager.cs +++ b/src/System.Private.CoreLib/src/System/Resources/ResourceManager.cs @@ -221,11 +221,9 @@ public ResourceManager(string baseName, Assembly assembly) { if (null == baseName) throw new ArgumentNullException(nameof(baseName)); - if (null == assembly) throw new ArgumentNullException(nameof(assembly)); - - if (!(assembly is RuntimeAssembly)) + if (!assembly.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); MainAssembly = assembly; @@ -242,8 +240,7 @@ public ResourceManager(string baseName, Assembly assembly, Type usingResourceSet throw new ArgumentNullException(nameof(baseName)); if (null == assembly) throw new ArgumentNullException(nameof(assembly)); - - if (!(assembly is RuntimeAssembly)) + if (!assembly.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); MainAssembly = assembly; @@ -260,8 +257,7 @@ public ResourceManager(Type resourceSource) { if (null == resourceSource) throw new ArgumentNullException(nameof(resourceSource)); - - if (!(resourceSource is RuntimeType)) + if (!resourceSource.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeType); _locationInfo = resourceSource; @@ -664,7 +660,7 @@ internal static WindowsRuntimeResourceManagerBase GetWinRTResourceManager() // // b) For any other non-FX assembly, we will use the modern resource manager with the premise that app package // contains the PRI resources. - private bool ShouldUseSatelliteAssemblyResourceLookupUnderAppX(RuntimeAssembly resourcesAssembly) + private bool ShouldUseSatelliteAssemblyResourceLookupUnderAppX(Assembly resourcesAssembly) { bool fUseSatelliteAssemblyResourceLookupUnderAppX = typeof(object).Assembly == resourcesAssembly; @@ -706,11 +702,9 @@ private void SetAppXConfiguration() bool bUsingSatelliteAssembliesUnderAppX = false; - RuntimeAssembly resourcesAssembly = (RuntimeAssembly)MainAssembly; - - if (resourcesAssembly != null) + if (MainAssembly != null) { - if (resourcesAssembly != typeof(object).Assembly) // We are not loading resources for mscorlib + if (MainAssembly != typeof(object).Assembly) // We are not loading resources for mscorlib { if (ApplicationModel.IsUap) { @@ -731,7 +725,7 @@ private void SetAppXConfiguration() if (!bUsingSatelliteAssembliesUnderAppX) { - _bUsingModernResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(resourcesAssembly); + _bUsingModernResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(MainAssembly); if (_bUsingModernResourceManagement) { @@ -749,7 +743,7 @@ private void SetAppXConfiguration() try { - _PRIonAppXInitialized = _WinRTResourceManager.Initialize(resourcesAssembly.Location, reswFilename, out _PRIExceptionInfo); + _PRIonAppXInitialized = _WinRTResourceManager.Initialize(MainAssembly.Location, reswFilename, out _PRIExceptionInfo); // Note that _PRIExceptionInfo might be null - this is OK. // In that case we will just throw the generic // MissingManifestResource_NoPRIresources exception. @@ -801,7 +795,7 @@ private void SetAppXConfiguration() } } } - // resourcesAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly. + // MainAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly. // However for the sake of 100% backwards compatibility on Win7 and below, we must leave // _bUsingModernResourceManagement as false. #endif // FEATURE_APPX @@ -1069,9 +1063,9 @@ internal UltimateResourceFallbackLocation FallbackLoc set { _rm._fallbackLoc = value; } } - internal RuntimeAssembly MainAssembly + internal Assembly MainAssembly { - get { return (RuntimeAssembly)_rm.MainAssembly; } + get { return _rm.MainAssembly; } } // this is weird because we have BaseNameField accessor above, but we're sticking