From d9ed9d4824f049a615c31af3be1101ddedce20c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:30:56 +0000 Subject: [PATCH 1/5] Copy Win32 resources to aggregate executable shims Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> --- .../Microsoft.NETCore.Native.Windows.targets | 19 +- .../Microsoft.NETCore.Native.targets | 1 + .../DumpNativeResources.cs | 255 ++++++++++++++++++ .../HelloExe/HelloExe.cs | 51 ++++ .../HelloExe/HelloExe.csproj | 2 + .../HelloExe/test.res | Bin 0 -> 192 bytes 6 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs create mode 100644 src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets index cff4b2e65291e8..b3c848332c66fe 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets @@ -149,7 +149,7 @@ The .NET Foundation licenses this file to you under the MIT license. @@ -159,7 +159,7 @@ The .NET Foundation licenses this file to you under the MIT license. + DependsOnTargets="LinkNative;GenerateAggregateExecutableShimResFiles"> <_AggregateExecutableReferencePath> @@ -171,6 +171,7 @@ int wmain(int argc, unsigned short** argv) } ]]> /PDB:"%(_AggregateExecutableReferencePath.ShimSymbol)" + "%(_AggregateExecutableReferencePath.ShimResourceFile)" @@ -195,6 +196,18 @@ int wmain(int argc, unsigned short** argv) - + + + + + + + + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index ce0f7292f4c76d..840ce18de4ba69 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -192,6 +192,7 @@ The .NET Foundation licenses this file to you under the MIT license. $(NativeIntermediateOutputPath)%(AssemblyName).aggregateexe$(NativeObjectExt) $(NativeIntermediateOutputPath)%(AssemblyName).aggregateexe.cl.rsp $(NativeIntermediateOutputPath)%(AssemblyName).aggregateexe.link.rsp + $(NativeIntermediateOutputPath)%(AssemblyName).aggregateexe.res $(NativeIntermediateOutputPath)%(AssemblyName).aggregateexe.rsp $(NativeOutputPath)%(AssemblyName)$(NativeExecutableExt) $(NativeOutputPath)%(AssemblyName)$(NativeSymbolExt) diff --git a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs new file mode 100644 index 00000000000000..374a9fd6137819 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs @@ -0,0 +1,255 @@ +// 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.IO; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Text; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Build.Tasks +{ + /// + /// Dumps native Win32 resources in the given assembly into a specified *.res file. + /// + public class DumpNativeResources : Task + { + /// + /// File name of the assembly with Win32 resources to be dumped. + /// + [Required] + public string MainAssembly + { + get; + set; + } + + /// + /// File name into which to dump the Win32 resources. + /// + [Required] + public string ResourceFile + { + get; + set; + } + + public override bool Execute() + { + using (FileStream fs = File.OpenRead(MainAssembly)) + using (PEReader peFile = new PEReader(fs)) + { + DirectoryEntry resourceDirectory = peFile.PEHeaders.PEHeader.ResourceTableDirectory; + if (resourceDirectory.Size != 0 + && peFile.PEHeaders.TryGetDirectoryOffset(resourceDirectory, out int rsrcOffset)) + { + using (var bw = new BinaryWriter(File.OpenWrite(ResourceFile))) + { + ResWriter.WriteResources(peFile, rsrcOffset, resourceDirectory.Size, bw); + } + } + else + { + if (File.Exists(ResourceFile)) + { + try + { + File.Delete(ResourceFile); + } + catch { } + } + } + } + + return true; + } + } + + /// + /// Helper class that converts from a Win32 PE resource directory format to + /// a set of RESOURCEHEADER structures (https://docs.microsoft.com/en-us/windows/desktop/menurc/resourceheader) + /// that form the basis of Win32 RES files. + /// + internal sealed class ResWriter + { + private readonly PEMemoryBlock _memoryBlock; + private readonly PEReader _peReader; + private readonly int _rsrcOffset; + private readonly int _rsrcSize; + private readonly BinaryWriter _bw; + + private object _typeIdOrName; + private object _resourceIdOrName; + private int _languageId; + + private ResWriter(PEMemoryBlock memoryBlock, PEReader peReader, int rsrcOffset, int rsrcSize, BinaryWriter bw) + { + _memoryBlock = memoryBlock; + _peReader = peReader; + _rsrcOffset = rsrcOffset; + _rsrcSize = rsrcSize; + _bw = bw; + } + + public static void WriteResources(PEReader reader, int rsrcOffset, int rsrcSize, BinaryWriter bw) + { + var rw = new ResWriter(reader.GetEntireImage(), reader, rsrcOffset, rsrcSize, bw); + + // First entry is a null resource entry + + bw.Write(new byte[] { + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }); + + rw.DumpDirectory(reader.GetEntireImage().GetReader(rsrcOffset, rsrcSize), 0); + } + + private void DumpDirectory(BlobReader br, int level) + { + // Skip characteristics + br.ReadInt32(); + + // Skip time/date stamp + br.ReadInt32(); + + // Skip time/date stamp + br.ReadInt32(); + + ushort numNamed = br.ReadUInt16(); + ushort numId = br.ReadUInt16(); + + for (int i = 0; i < numNamed + numId; i++) + { + int nameOffsetOrId = br.ReadInt32(); + uint entryTableOrSubdirectoryOffset = br.ReadUInt32(); + + if (i < numNamed) + { + nameOffsetOrId = nameOffsetOrId &= 0x7FFFFFFF; + BlobReader nameReader = _memoryBlock.GetReader(_rsrcOffset + nameOffsetOrId, _rsrcSize - nameOffsetOrId); + ushort nameLength = nameReader.ReadUInt16(); + StringBuilder sb = new StringBuilder(nameLength); + for (int charIndex = 0; charIndex < nameLength; charIndex++) + sb.Append((char)nameReader.ReadUInt16()); + string name = sb.ToString(); + + if (level == 0) + { + _typeIdOrName = name; + } + else if (level == 1) + { + _resourceIdOrName = name; + } + else + throw new BadImageFormatException(); + } + else + { + if (level == 0) + { + _typeIdOrName = nameOffsetOrId; + } + else if (level == 1) + { + _resourceIdOrName = nameOffsetOrId; + } + else if (level == 2) + { + _languageId = nameOffsetOrId; + } + else + throw new BadImageFormatException(); + } + + if (level < 2) + { + if ((entryTableOrSubdirectoryOffset & 0x80000000) == 0) + throw new BadImageFormatException(); + entryTableOrSubdirectoryOffset &= 0x7FFFFFFF; + DumpDirectory(_memoryBlock.GetReader(_rsrcOffset + (int)entryTableOrSubdirectoryOffset, _rsrcSize - (int)entryTableOrSubdirectoryOffset), level + 1); + } + else + { + DumpEntry(_memoryBlock.GetReader(_rsrcOffset + (int)entryTableOrSubdirectoryOffset, _rsrcSize - (int)entryTableOrSubdirectoryOffset)); + } + } + } + + private void DumpEntry(BlobReader br) + { + int dataRva = br.ReadInt32(); + int size = br.ReadInt32(); + + // Skip codepage + br.ReadInt32(); + + // Skip reserved + br.ReadInt32(); + + var ms = new MemoryStream(); + var hdr = new BinaryWriter(ms, System.Text.Encoding.Unicode); + + hdr.Write(size); // DataSize + hdr.Write(0); // HeaderSize + hdr.WriteNameOrId(_typeIdOrName); // TYPE + hdr.WriteNameOrId(_resourceIdOrName); // NAME + + // round up to "DWORD" offset + long curHeaderSize = hdr.BaseStream.Position; + while (curHeaderSize % 4 != 0) + { + hdr.Write((byte)0); + curHeaderSize++; + } + + hdr.Write(0); // DataVersion + hdr.Write((short)0); // MemoryFlags + hdr.Write((ushort)_languageId); // LanguageId + hdr.Write(0); // Version + hdr.Write(0); // Characteristics + + // Patch up HeaderSize + var headerSize = hdr.Seek(0, SeekOrigin.Current); + hdr.Seek(4, SeekOrigin.Begin); + hdr.Write((int)headerSize); + + var hdrData = ms.ToArray(); + + _bw.Write(hdrData); + _bw.Write(_peReader.GetSectionData(dataRva).GetReader().ReadBytes(size)); + + // Make sure we are DWORD aligned + var totalSize = hdrData.Length + size; + while (totalSize % 4 != 0) + { + _bw.Write((byte)0); + totalSize++; + } + + } + } + + internal static class ResourceHelper + { + public static void WriteNameOrId(this BinaryWriter bw, object nameOrId) + { + if (nameOrId is string s) + { + // String + bw.Write(s.ToCharArray()); + bw.Write((short)0); + } + else + { + // Integer + bw.Write((short)-1); + bw.Write((short)(int)nameOrId); + } + } + } +} diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs index 9f476b06021221..87468b58c162ba 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs @@ -2,5 +2,56 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.InteropServices; + +if (OperatingSystem.IsWindows()) +{ + Win32Resources.Validate(); +} Console.WriteLine("Hello from HelloExe"); + +unsafe static class Win32Resources +{ + public static void Validate() + { + nint lib = 0; + + if (GetIntValueFromResource(lib, (ushort*)(nuint)(ushort)10, 0x041B) != 3) + throw new Exception(); + + ReadOnlySpan resName = "funny"; + fixed (char* pResName = resName) + if (GetIntValueFromResource(lib, (ushort*)pResName, 0x041B) != 1) + throw new Exception(); + } + + private static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguage) + { + ushort* RT_RCDATA = (ushort*)(nuint)(ushort)10; + + nint hResInfo = FindResourceExW(hModule, RT_RCDATA, lpName, wLanguage); + if (hResInfo == 0) + throw new Exception("Resource not found"); + + if (SizeofResource(hModule, hResInfo) != 4) + throw new Exception("Wrong size of resource"); + + nint hResData = LoadResource(hModule, hResInfo); + int val = *(int*)LockResource(hResData); + + return val; + } + + [DllImport("kernel32")] + private static extern nint FindResourceExW(nint hModule, ushort* lpType, ushort* lpName, ushort wLanguage); + + [DllImport("kernel32")] + private static extern nint LoadResource(nint hModule, nint hResInfo); + + [DllImport("kernel32")] + private static extern void* LockResource(nint hResData); + + [DllImport("kernel32")] + private static extern uint SizeofResource(nint hModule, nint hResInfo); +} diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj index f1bb752fd9c004..7be315a9be91c0 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj @@ -2,6 +2,8 @@ Exe SharedLibrary + true + test.res diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res new file mode 100644 index 0000000000000000000000000000000000000000..4844d68f3714fcbbd9dfec01716942fdfc02baaf GIT binary patch literal 192 zcmZQzU|>)H;{X347|28cEI^(H5dZ(r#o)#e%HRitkx&%|4ALNJFkl3dAdUhMgVcgB c2q3Fr2J-Qn#|k%(3942BNTZsEPy Date: Thu, 4 Jun 2026 04:31:48 +0000 Subject: [PATCH 2/5] Ensure dumped resource files are truncated Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> --- .../tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs index 374a9fd6137819..74dea8face713b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs +++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs @@ -46,7 +46,7 @@ public override bool Execute() if (resourceDirectory.Size != 0 && peFile.PEHeaders.TryGetDirectoryOffset(resourceDirectory, out int rsrcOffset)) { - using (var bw = new BinaryWriter(File.OpenWrite(ResourceFile))) + using (var bw = new BinaryWriter(File.Create(ResourceFile))) { ResWriter.WriteResources(peFile, rsrcOffset, resourceDirectory.Size, bw); } From 58e189d39de57e764e6fb8918f831bd4bb94c70f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:32:51 +0000 Subject: [PATCH 3/5] Address aggregate resource validation feedback Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> --- .../ILCompiler.Build.Tasks/DumpNativeResources.cs | 8 ++++++-- .../AggregateExecutableLibrary/HelloExe/HelloExe.cs | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs index 74dea8face713b..cec9bfaff1a59e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs +++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs @@ -59,7 +59,11 @@ public override bool Execute() { File.Delete(ResourceFile); } - catch { } + catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) + { + Log.LogErrorFromException(ex); + return false; + } } } } @@ -129,7 +133,7 @@ private void DumpDirectory(BlobReader br, int level) if (i < numNamed) { - nameOffsetOrId = nameOffsetOrId &= 0x7FFFFFFF; + nameOffsetOrId &= 0x7FFFFFFF; BlobReader nameReader = _memoryBlock.GetReader(_rsrcOffset + nameOffsetOrId, _rsrcSize - nameOffsetOrId); ushort nameLength = nameReader.ReadUInt16(); StringBuilder sb = new StringBuilder(nameLength); diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs index 87468b58c162ba..8563fc5392b5a6 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs @@ -17,13 +17,17 @@ public static void Validate() { nint lib = 0; - if (GetIntValueFromResource(lib, (ushort*)(nuint)(ushort)10, 0x041B) != 3) - throw new Exception(); + int resourceValue = GetIntValueFromResource(lib, (ushort*)(nuint)(ushort)10, 0x041B); + if (resourceValue != 3) + throw new Exception($"Expected resource 10 to have value 3, but got {resourceValue}"); ReadOnlySpan resName = "funny"; fixed (char* pResName = resName) - if (GetIntValueFromResource(lib, (ushort*)pResName, 0x041B) != 1) - throw new Exception(); + { + resourceValue = GetIntValueFromResource(lib, (ushort*)pResName, 0x041B); + if (resourceValue != 1) + throw new Exception($"Expected resource 'funny' to have value 1, but got {resourceValue}"); + } } private static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguage) From 683237d3c42aa4967cce8dec5eec3dd88fe554b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:34:15 +0000 Subject: [PATCH 4/5] Always emit aggregate shim resource response input Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> --- .../Microsoft.NETCore.Native.Windows.targets | 2 +- .../DumpNativeResources.cs | 24 ++++++++----------- .../HelloExe/HelloExe.cs | 6 ++--- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets index b3c848332c66fe..a0081669622dfa 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets @@ -171,7 +171,7 @@ int wmain(int argc, unsigned short** argv) } ]]> /PDB:"%(_AggregateExecutableReferencePath.ShimSymbol)" - "%(_AggregateExecutableReferencePath.ShimResourceFile)" + "%(_AggregateExecutableReferencePath.ShimResourceFile)" diff --git a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs index cec9bfaff1a59e..954e835c51ef74 100644 --- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs +++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs @@ -53,17 +53,9 @@ public override bool Execute() } else { - if (File.Exists(ResourceFile)) + using (var bw = new BinaryWriter(File.Create(ResourceFile))) { - try - { - File.Delete(ResourceFile); - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - Log.LogErrorFromException(ex); - return false; - } + ResWriter.WriteEmptyResourceFile(bw); } } } @@ -102,14 +94,18 @@ public static void WriteResources(PEReader reader, int rsrcOffset, int rsrcSize, { var rw = new ResWriter(reader.GetEntireImage(), reader, rsrcOffset, rsrcSize, bw); - // First entry is a null resource entry + WriteEmptyResourceFile(bw); + + rw.DumpDirectory(reader.GetEntireImage().GetReader(rsrcOffset, rsrcSize), 0); + } + public static void WriteEmptyResourceFile(BinaryWriter bw) + { + // First entry is a null resource entry bw.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }); - - rw.DumpDirectory(reader.GetEntireImage().GetReader(rsrcOffset, rsrcSize), 0); } private void DumpDirectory(BlobReader br, int level) @@ -117,7 +113,7 @@ private void DumpDirectory(BlobReader br, int level) // Skip characteristics br.ReadInt32(); - // Skip time/date stamp + // Skip major/minor version br.ReadInt32(); // Skip time/date stamp diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs index 8563fc5392b5a6..6abdf3d2d79b28 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs @@ -15,16 +15,16 @@ unsafe static class Win32Resources { public static void Validate() { - nint lib = 0; + nint currentModule = 0; - int resourceValue = GetIntValueFromResource(lib, (ushort*)(nuint)(ushort)10, 0x041B); + int resourceValue = GetIntValueFromResource(currentModule, (ushort*)(nuint)(ushort)10, 0x041B); if (resourceValue != 3) throw new Exception($"Expected resource 10 to have value 3, but got {resourceValue}"); ReadOnlySpan resName = "funny"; fixed (char* pResName = resName) { - resourceValue = GetIntValueFromResource(lib, (ushort*)pResName, 0x041B); + resourceValue = GetIntValueFromResource(currentModule, (ushort*)pResName, 0x041B); if (resourceValue != 1) throw new Exception($"Expected resource 'funny' to have value 1, but got {resourceValue}"); } From cc09a61162cd2f12ee47f887f944569cf4541db7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 05:06:10 +0000 Subject: [PATCH 5/5] Share Win32 resource test logic Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com> --- .../HelloExe/HelloExe.cs | 52 +----------------- .../HelloExe/HelloExe.csproj | 4 +- .../HelloExe/test.res | Bin 192 -> 0 bytes .../Win32Resources/Win32Resources.cs | 35 +++++++----- 4 files changed, 26 insertions(+), 65 deletions(-) delete mode 100644 src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs index 6abdf3d2d79b28..1f389151291c5a 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.cs @@ -2,60 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Runtime.InteropServices; if (OperatingSystem.IsWindows()) { - Win32Resources.Validate(); + Program.ValidateWin32Resources(); } Console.WriteLine("Hello from HelloExe"); - -unsafe static class Win32Resources -{ - public static void Validate() - { - nint currentModule = 0; - - int resourceValue = GetIntValueFromResource(currentModule, (ushort*)(nuint)(ushort)10, 0x041B); - if (resourceValue != 3) - throw new Exception($"Expected resource 10 to have value 3, but got {resourceValue}"); - - ReadOnlySpan resName = "funny"; - fixed (char* pResName = resName) - { - resourceValue = GetIntValueFromResource(currentModule, (ushort*)pResName, 0x041B); - if (resourceValue != 1) - throw new Exception($"Expected resource 'funny' to have value 1, but got {resourceValue}"); - } - } - - private static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguage) - { - ushort* RT_RCDATA = (ushort*)(nuint)(ushort)10; - - nint hResInfo = FindResourceExW(hModule, RT_RCDATA, lpName, wLanguage); - if (hResInfo == 0) - throw new Exception("Resource not found"); - - if (SizeofResource(hModule, hResInfo) != 4) - throw new Exception("Wrong size of resource"); - - nint hResData = LoadResource(hModule, hResInfo); - int val = *(int*)LockResource(hResData); - - return val; - } - - [DllImport("kernel32")] - private static extern nint FindResourceExW(nint hModule, ushort* lpType, ushort* lpName, ushort wLanguage); - - [DllImport("kernel32")] - private static extern nint LoadResource(nint hModule, nint hResInfo); - - [DllImport("kernel32")] - private static extern void* LockResource(nint hResData); - - [DllImport("kernel32")] - private static extern uint SizeofResource(nint hModule, nint hResInfo); -} diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj index 7be315a9be91c0..24aa9ef2d4b868 100644 --- a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj +++ b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/HelloExe.csproj @@ -3,9 +3,11 @@ Exe SharedLibrary true - test.res + $(DefineConstants);EXCLUDE_WIN32RESOURCES_MAIN + ..\..\SmokeTests\Win32Resources\test.res + diff --git a/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res b/src/tests/nativeaot/AggregateExecutableLibrary/HelloExe/test.res deleted file mode 100644 index 4844d68f3714fcbbd9dfec01716942fdfc02baaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192 zcmZQzU|>)H;{X347|28cEI^(H5dZ(r#o)#e%HRitkx&%|4ALNJFkl3dAdUhMgVcgB c2q3Fr2J-Qn#|k%(3942BNTZsEPy resName = "funny"; - fixed (char* pResName = resName) - if (GetIntValueFromResource(lib, (ushort*)pResName, 0x041B) != 1) + if (GetIntValueFromResource(lib, (ushort*)(nuint)(ushort)10, 0x041B) != 3) throw new Exception(); - return 100; + ReadOnlySpan resName = "funny"; + fixed (char* pResName = resName) + if (GetIntValueFromResource(lib, (ushort*)pResName, 0x041B) != 1) + throw new Exception(); + } - static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguage) + private static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguage) { ushort* RT_RCDATA = (ushort*)(nuint)(ushort)10; @@ -36,14 +45,14 @@ static int GetIntValueFromResource(nint hModule, ushort* lpName, ushort wLanguag } [DllImport("kernel32")] - static extern nint FindResourceExW(nint hModule, ushort* lpType, ushort* lpName, ushort wLanguage); + private static extern nint FindResourceExW(nint hModule, ushort* lpType, ushort* lpName, ushort wLanguage); [DllImport("kernel32")] - static extern nint LoadResource(nint hModule, nint hResInfo); + private static extern nint LoadResource(nint hModule, nint hResInfo); [DllImport("kernel32")] - static extern void* LockResource(nint hResData); + private static extern void* LockResource(nint hResData); [DllImport("kernel32")] - static extern uint SizeofResource(nint hModule, nint hResInfo); + private static extern uint SizeofResource(nint hModule, nint hResInfo); }