Skip to content

Commit

Permalink
Update samples added for PersistedAssemblyBuilder (#44086)
Browse files Browse the repository at this point in the history
  • Loading branch information
steveharter authored Dec 27, 2024
1 parent aeeb516 commit 9c423c0
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
Expand All @@ -13,11 +15,12 @@ public static void Main()
{
SetEntryPoint();
SetResource();
ReadResource();
}
// <Snippet1>
public static void SetEntryPoint()
{
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), typeof(object).Assembly);
PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly);
TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
// ...
MethodBuilder entryPoint = tb.DefineMethod("Main", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
Expand All @@ -27,50 +30,93 @@ public static void SetEntryPoint()
tb.CreateType();

MetadataBuilder metadataBuilder = ab.GenerateMetadata(out BlobBuilder ilStream, out BlobBuilder fieldData);
PEHeaderBuilder peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage);

ManagedPEBuilder peBuilder = new ManagedPEBuilder(
header: peHeaderBuilder,
ManagedPEBuilder peBuilder = new(
header: PEHeaderBuilder.CreateExecutableHeader(),
metadataRootBuilder: new MetadataRootBuilder(metadataBuilder),
ilStream: ilStream,
mappedFieldData: fieldData,
entryPoint: MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken));

BlobBuilder peBlob = new BlobBuilder();
BlobBuilder peBlob = new();
peBuilder.Serialize(peBlob);

// in case saving to a file:
using var fileStream = new FileStream("MyAssembly.exe", FileMode.Create, FileAccess.Write);
// Create the executable:
using FileStream fileStream = new("MyAssembly.exe", FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(fileStream);
}
// </Snippet1>
// <Snippet2>
public static void SetResource()
{
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), typeof(object).Assembly);
PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly);
ab.DefineDynamicModule("MyModule");
MetadataBuilder metadata = ab.GenerateMetadata(out BlobBuilder ilStream, out _);

using MemoryStream stream = new MemoryStream();
ResourceWriter myResourceWriter = new ResourceWriter(stream);
using MemoryStream stream = new();
ResourceWriter myResourceWriter = new(stream);
myResourceWriter.AddResource("AddResource 1", "First added resource");
myResourceWriter.AddResource("AddResource 2", "Second added resource");
myResourceWriter.AddResource("AddResource 3", "Third added resource");
myResourceWriter.Close();
BlobBuilder resourceBlob = new BlobBuilder();
resourceBlob.WriteBytes(stream.ToArray());
metadata.AddManifestResource(ManifestResourceAttributes.Public, metadata.GetOrAddString("MyResource"), default, (uint)resourceBlob.Count);

ManagedPEBuilder peBuilder = new ManagedPEBuilder(
header: new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll),
byte[] data = stream.ToArray();
BlobBuilder resourceBlob = new();
resourceBlob.WriteInt32(data.Length);
resourceBlob.WriteBytes(data);

metadata.AddManifestResource(
ManifestResourceAttributes.Public,
metadata.GetOrAddString("MyResource.resources"),
implementation: default,
offset: 0);

ManagedPEBuilder peBuilder = new(
header: PEHeaderBuilder.CreateLibraryHeader(),
metadataRootBuilder: new MetadataRootBuilder(metadata),
ilStream: ilStream,
managedResources: resourceBlob);

BlobBuilder blob = new BlobBuilder();
BlobBuilder blob = new();
peBuilder.Serialize(blob);
using var fileStream = new FileStream("MyAssemblyWithResource.dll", FileMode.Create, FileAccess.Write);

// Create the assembly:
using FileStream fileStream = new("MyAssemblyWithResource.dll", FileMode.Create, FileAccess.Write);
blob.WriteContentTo(fileStream);
}
// </Snippet2>
// <Snippet3>
public static void ReadResource()
{
Assembly readAssembly = Assembly.LoadFile(Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"MyAssemblyWithResource.dll"));

// Use ResourceManager.GetString() to read the resources.
ResourceManager rm = new("MyResource", readAssembly);
Console.WriteLine("Using ResourceManager.GetString():");
Console.WriteLine($"{rm.GetString("AddResource 1", CultureInfo.InvariantCulture)}");
Console.WriteLine($"{rm.GetString("AddResource 2", CultureInfo.InvariantCulture)}");
Console.WriteLine($"{rm.GetString("AddResource 3", CultureInfo.InvariantCulture)}");

// Use ResourceSet to enumerate the resources.
Console.WriteLine();
Console.WriteLine("Using ResourceSet:");
ResourceSet resourceSet = rm.GetResourceSet(CultureInfo.InvariantCulture, createIfNotExists: true, tryParents: false);
foreach (DictionaryEntry entry in resourceSet)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}

// Use ResourceReader to enumerate the resources.
Console.WriteLine();
Console.WriteLine("Using ResourceReader:");
using Stream stream = readAssembly.GetManifestResourceStream("MyResource.resources")!;
using ResourceReader reader = new(stream);
foreach (DictionaryEntry entry in reader)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
}
// </Snippet3>
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ The following example shows how to create resources and attach it to the assembl

:::code language="csharp" source="./snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/GenerateMetadataSnippets.cs" id="Snippet2":::

The following example shows how to read resources from the created assembly.

:::code language="csharp" source="./snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/GenerateMetadataSnippets.cs" id="Snippet3":::

> [!NOTE]
> The metadata tokens for all members are populated on the <xref:System.Reflection.Emit.AssemblyBuilder.Save%2A> operation. Don't use the tokens of a generated type and its members before saving, as they'll have default values or throw exceptions. It's safe to use tokens for types that are referenced, not generated.
>
Expand Down

0 comments on commit 9c423c0

Please sign in to comment.