|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using System.Globalization;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit
{
public class ResourceTests : CSharpTestBase
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary([In] IntPtr hFile);
[ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.TestExecutionNeedsDesktopTypes)]
public void DefaultVersionResource()
{
string source = @"
public class Maine
{
public static void Main()
{
}
}
";
var c1 = CreateCompilation(source, assemblyName: "Win32VerNoAttrs", options: TestOptions.ReleaseExe);
var exe = Temp.CreateFile();
using (FileStream output = exe.Open())
{
c1.Emit(output, win32Resources: c1.CreateDefaultWin32Resources(true, false, null, null));
}
c1 = null;
//Open as data
IntPtr lib = IntPtr.Zero;
string versionData;
string mftData;
try
{
lib = LoadLibraryEx(exe.Path, IntPtr.Zero, 0x00000002);
if (lib == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
//the manifest and version primitives are tested elsewhere. This is to test that the default
//values are passed to the primitives that assemble the resources.
uint size;
IntPtr versionRsrc = Win32Res.GetResource(lib, "#1", "#16", out size);
versionData = Win32Res.VersionResourceToXml(versionRsrc);
uint mftSize;
IntPtr mftRsrc = Win32Res.GetResource(lib, "#1", "#24", out mftSize);
mftData = Win32Res.ManifestResourceToXml(mftRsrc, mftSize);
}
finally
{
if (lib != IntPtr.Zero)
{
FreeLibrary(lib);
}
}
string expected =
@"<?xml version=""1.0"" encoding=""utf-16""?>
<VersionResource Size=""612"">
<VS_FIXEDFILEINFO FileVersionMS=""00000000"" FileVersionLS=""00000000"" ProductVersionMS=""00000000"" ProductVersionLS=""00000000"" />
<KeyValuePair Key=""FileDescription"" Value="" "" />
<KeyValuePair Key=""FileVersion"" Value=""0.0.0.0"" />
<KeyValuePair Key=""InternalName"" Value=""Win32VerNoAttrs.exe"" />
<KeyValuePair Key=""LegalCopyright"" Value="" "" />
<KeyValuePair Key=""OriginalFilename"" Value=""Win32VerNoAttrs.exe"" />
<KeyValuePair Key=""ProductVersion"" Value=""0.0.0.0"" />
<KeyValuePair Key=""Assembly Version"" Value=""0.0.0.0"" />
</VersionResource>";
Assert.Equal(expected, versionData);
expected = @"<?xml version=""1.0"" encoding=""utf-16""?>
<ManifestResource Size=""490"">
<Contents><![CDATA[<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<assembly xmlns=""urn:schemas-microsoft-com:asm.v1"" manifestVersion=""1.0"">
<assemblyIdentity version=""1.0.0.0"" name=""MyApplication.app""/>
<trustInfo xmlns=""urn:schemas-microsoft-com:asm.v2"">
<security>
<requestedPrivileges xmlns=""urn:schemas-microsoft-com:asm.v3"">
<requestedExecutionLevel level=""asInvoker"" uiAccess=""false""/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>]]></Contents>
</ManifestResource>";
Assert.Equal(expected, mftData);
//look at the same data through the FileVersion API.
//If the codepage and resource language information is not
//written correctly into the internal resource directory of
//the PE, then GetVersionInfo will fail to find the FileVersionInfo.
//Once upon a time in Roslyn, the codepage and lang info was not written correctly.
var fileVer = FileVersionInfo.GetVersionInfo(exe.Path);
Assert.Equal(" ", fileVer.LegalCopyright);
}
[ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.TestExecutionNeedsDesktopTypes)]
public void ResourcesInCoff()
{
//this is to test that resources coming from a COFF can be added to a binary.
string source = @"
class C
{
}
";
var c1 = CreateCompilation(source, assemblyName: "Win32WithCoff", options: TestOptions.ReleaseDll);
var exe = Temp.CreateFile();
using (FileStream output = exe.Open())
{
var memStream = new MemoryStream(TestResources.General.nativeCOFFResources);
c1.Emit(output, win32Resources: memStream);
}
c1 = null;
//Open as data
IntPtr lib = IntPtr.Zero;
string versionData;
try
{
lib = LoadLibraryEx(exe.Path, IntPtr.Zero, 0x00000002);
if (lib == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
//the manifest and version primitives are tested elsewhere. This is to test that the resources
//we expect are present. Also need to check that the actual contents of at least one of the resources
//is good. That tests our processing of the relocations.
uint size;
IntPtr versionRsrc = Win32Res.GetResource(lib, "#1", "#16", out size);
versionData = Win32Res.VersionResourceToXml(versionRsrc);
uint stringTableSize;
IntPtr stringTable = Win32Res.GetResource(lib, "#1", "#6", out stringTableSize);
Assert.NotEqual(default, stringTable);
uint elevenSize;
IntPtr elevenRsrc = Win32Res.GetResource(lib, "#1", "#11", out elevenSize);
Assert.NotEqual(default, elevenRsrc);
uint wevtSize;
IntPtr wevtRsrc = Win32Res.GetResource(lib, "#1", "WEVT_TEMPLATE", out wevtSize);
Assert.NotEqual(default, wevtRsrc);
}
finally
{
if (lib != IntPtr.Zero)
{
FreeLibrary(lib);
}
}
string expected =
@"<?xml version=""1.0"" encoding=""utf-16""?>
<VersionResource Size=""1104"">
<VS_FIXEDFILEINFO FileVersionMS=""000b0000"" FileVersionLS=""eacc0000"" ProductVersionMS=""000b0000"" ProductVersionLS=""eacc0000"" />
<KeyValuePair Key=""CompanyName"" Value=""Microsoft Corporation"" />
<KeyValuePair Key=""FileDescription"" Value=""Team Foundation Server Object Model"" />
<KeyValuePair Key=""FileVersion"" Value=""11.0.60108.0 built by: TOOLSET_ROSLYN(GNAMBOO-DEV-GNAMBOO)"" />
<KeyValuePair Key=""InternalName"" Value=""Microsoft.TeamFoundation.Framework.Server.dll"" />
<KeyValuePair Key=""LegalCopyright"" Value=""© Microsoft Corporation. All rights reserved."" />
<KeyValuePair Key=""OriginalFilename"" Value=""Microsoft.TeamFoundation.Framework.Server.dll"" />
<KeyValuePair Key=""ProductName"" Value=""Microsoft® Visual Studio® 2012"" />
<KeyValuePair Key=""ProductVersion"" Value=""11.0.60108.0"" />
</VersionResource>";
Assert.Equal(expected, versionData);
//look at the same data through the FileVersion API.
//If the codepage and resource language information is not
//written correctly into the internal resource directory of
//the PE, then GetVersionInfo will fail to find the FileVersionInfo.
//Once upon a time in Roslyn, the codepage and lang info was not written correctly.
var fileVer = FileVersionInfo.GetVersionInfo(exe.Path);
Assert.Equal("Microsoft Corporation", fileVer.CompanyName);
}
[Fact]
public void FaultyResourceDataProvider()
{
var c1 = CreateCompilation("");
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("r2", "file", () => { throw new Exception("bad stuff"); }, false)
});
result.Diagnostics.Verify(
// error CS1566: Error reading resource 'file' -- 'bad stuff'
Diagnostic(ErrorCode.ERR_CantReadResource).WithArguments("file", "bad stuff")
);
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("r2", "file", () => null, false)
});
result.Diagnostics.Verify(
// error CS1566: Error reading resource 'file' -- 'Resource data provider should return non-null stream'
Diagnostic(ErrorCode.ERR_CantReadResource).WithArguments("file", CodeAnalysisResources.ResourceDataProviderShouldReturnNonNullStream)
);
}
[WorkItem(543501, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543501")]
[Fact]
public void CS1508_DuplicateManifestResourceIdentifier()
{
var c1 = CreateCompilation("");
Func<Stream> dataProvider = () => new MemoryStream(new byte[] { });
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true),
new ResourceDescription("A", "y.goo", dataProvider, true)
});
result.Diagnostics.Verify(
// error CS1508: Resource identifier 'A' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("A")
);
}
[WorkItem(543501, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543501")]
[Fact]
public void CS1508_DuplicateManifestResourceIdentifier_EmbeddedResource()
{
var c1 = CreateCompilation("");
Func<Stream> dataProvider = () => new MemoryStream(new byte[] { });
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", dataProvider, true),
new ResourceDescription("A", null, dataProvider, true, isEmbedded: true, checkArgs: true)
});
result.Diagnostics.Verify(
// error CS1508: Resource identifier 'A' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("A")
);
// file name ignored for embedded manifest resources
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true, isEmbedded: true, checkArgs: true),
new ResourceDescription("A", "x.goo", dataProvider, true, isEmbedded: false, checkArgs: true)
});
result.Diagnostics.Verify(
// error CS1508: Resource identifier 'A' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("A")
);
}
[WorkItem(543501, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543501")]
[Fact]
public void CS7041_DuplicateManifestResourceFileName()
{
var c1 = CSharpCompilation.Create("goo", references: new[] { MscorlibRef }, options: TestOptions.ReleaseDll);
Func<Stream> dataProvider = () => new MemoryStream(new byte[] { });
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true),
new ResourceDescription("B", "x.goo", dataProvider, true)
});
result.Diagnostics.Verify(
// error CS7041: Each linked resource and module must have a unique filename. Filename 'x.goo' is specified more than once in this assembly
Diagnostic(ErrorCode.ERR_ResourceFileNameNotUnique).WithArguments("x.goo")
);
}
[WorkItem(543501, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543501")]
[Fact]
public void NoDuplicateManifestResourceFileNameDiagnosticForEmbeddedResources()
{
var c1 = CreateCompilation("");
Func<Stream> dataProvider = () => new MemoryStream(new byte[] { });
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", dataProvider, true),
new ResourceDescription("B", null, dataProvider, true, isEmbedded: true, checkArgs: true)
});
result.Diagnostics.Verify();
// file name ignored for embedded manifest resources
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true, isEmbedded: true, checkArgs: true),
new ResourceDescription("B", "x.goo", dataProvider, true, isEmbedded: false, checkArgs: true)
});
result.Diagnostics.Verify();
}
[WorkItem(543501, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543501"), WorkItem(546297, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546297")]
[Fact]
public void CS1508_CS7041_DuplicateManifestResourceDiagnostics()
{
var c1 = CreateCompilation("");
Func<Stream> dataProvider = () => new MemoryStream(new byte[] { });
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true),
new ResourceDescription("A", "x.goo", dataProvider, true)
});
result.Diagnostics.Verify(
// error CS1508: Resource identifier 'A' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("A"),
// error CS7041: Each linked resource and module must have a unique filename. Filename 'x.goo' is specified more than once in this assembly
Diagnostic(ErrorCode.ERR_ResourceFileNameNotUnique).WithArguments("x.goo")
);
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "x.goo", dataProvider, true),
new ResourceDescription("B", "x.goo", dataProvider, true),
new ResourceDescription("B", "y.goo", dataProvider, true)
});
result.Diagnostics.Verify(
// error CS7041: Each linked resource and module must have a unique filename. Filename 'x.goo' is specified more than once in this assembly
Diagnostic(ErrorCode.ERR_ResourceFileNameNotUnique).WithArguments("x.goo"),
// error CS1508: Resource identifier 'B' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("B")
);
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "goo.dll", dataProvider, true),
});
//make sure there's no problem when the name of the primary module conflicts with a file name of an added resource.
result.Diagnostics.Verify();
var netModule1 = TestReferences.SymbolsTests.netModule.netModule1;
c1 = CreateCompilation("", references: new[] { netModule1 });
result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("A", "netmodule1.netmodule", dataProvider, true),
});
// Native compiler gives CS0013 (FTL_MetadataEmitFailure) at Emit stage
result.Diagnostics.Verify(
// error CS7041: Each linked resource and module must have a unique filename. Filename 'netmodule1.netmodule' is specified more than once in this assembly
Diagnostic(ErrorCode.ERR_ResourceFileNameNotUnique).WithArguments("netModule1.netmodule")
);
}
#if NET472
[ConditionalFact(typeof(DesktopOnly))]
public void AddManagedResource()
{
string source = @"public class C { static public void Main() {} }";
// Do not name the compilation, a unique guid is used as a name by default. It prevents conflicts with other assemblies loaded via Assembly.ReflectionOnlyLoad.
var c1 = CreateCompilation(source);
var resourceFileName = "RoslynResourceFile.goo";
var output = new MemoryStream();
const string r1Name = "some.dotted.NAME";
const string r2Name = "another.DoTtEd.NAME";
var arrayOfEmbeddedData = new byte[] { 1, 2, 3, 4, 5 };
var resourceFileData = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = c1.Emit(output, manifestResources:
new ResourceDescription[]
{
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), true),
new ResourceDescription(r2Name, resourceFileName, () => new MemoryStream(resourceFileData), false)
});
Assert.True(result.Success);
var assembly = Assembly.ReflectionOnlyLoad(output.ToArray());
string[] resourceNames = assembly.GetManifestResourceNames();
Assert.Equal(2, resourceNames.Length);
var rInfo = assembly.GetManifestResourceInfo(r1Name);
Assert.Equal(ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile, rInfo.ResourceLocation);
var rData = assembly.GetManifestResourceStream(r1Name);
var rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(arrayOfEmbeddedData, rBytes);
rInfo = assembly.GetManifestResourceInfo(r2Name);
Assert.Equal(resourceFileName, rInfo.FileName);
c1 = null;
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void AddResourceToModule()
{
bool metadataOnly = false;
Func<Compilation, Stream, ResourceDescription[], CodeAnalysis.Emit.EmitResult> emit;
emit = (c, s, r) => c.Emit(s, manifestResources: r, options: new EmitOptions(metadataOnly: metadataOnly));
var sourceTree = SyntaxFactory.ParseSyntaxTree("");
// Do not name the compilation, a unique guid is used as a name by default. It prevents conflicts with other assemblies loaded via Assembly.ReflectionOnlyLoad.
var c1 = CSharpCompilation.Create(
Guid.NewGuid().ToString(),
new[] { sourceTree },
new[] { MscorlibRef },
TestOptions.ReleaseModule);
var resourceFileName = "RoslynResourceFile.goo";
var output = new MemoryStream();
const string r1Name = "some.dotted.NAME";
const string r2Name = "another.DoTtEd.NAME";
var arrayOfEmbeddedData = new byte[] { 1, 2, 3, 4, 5 };
var resourceFileData = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = emit(c1, output,
new ResourceDescription[]
{
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), true),
new ResourceDescription(r2Name, resourceFileName, () => new MemoryStream(resourceFileData), false)
});
Assert.False(result.Success);
Assert.NotEmpty(result.Diagnostics.Where(x => x.Code == (int)ErrorCode.ERR_CantRefResource));
result = emit(c1, output,
new ResourceDescription[]
{
new ResourceDescription(r2Name, resourceFileName, () => new MemoryStream(resourceFileData), false),
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), true)
});
Assert.False(result.Success);
Assert.NotEmpty(result.Diagnostics.Where(x => x.Code == (int)ErrorCode.ERR_CantRefResource));
result = emit(c1, output,
new ResourceDescription[]
{
new ResourceDescription(r2Name, resourceFileName, () => new MemoryStream(resourceFileData), false)
});
Assert.False(result.Success);
Assert.NotEmpty(result.Diagnostics.Where(x => x.Code == (int)ErrorCode.ERR_CantRefResource));
var c_mod1 = CSharpCompilation.Create(
Guid.NewGuid().ToString(),
new[] { sourceTree },
new[] { MscorlibRef },
TestOptions.ReleaseModule);
var output_mod1 = new MemoryStream();
result = emit(c_mod1, output_mod1,
new ResourceDescription[]
{
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), true)
});
Assert.True(result.Success);
var mod1 = ModuleMetadata.CreateFromImage(output_mod1.ToImmutable());
var ref_mod1 = mod1.GetReference();
Assert.Equal(ManifestResourceAttributes.Public, mod1.Module.GetEmbeddedResourcesOrThrow()[0].Attributes);
{
var c2 = CreateCompilation(sourceTree, new[] { ref_mod1 }, TestOptions.ReleaseDll);
var output2 = new MemoryStream();
var result2 = c2.Emit(output2);
Assert.True(result2.Success);
var assembly = System.Reflection.Assembly.ReflectionOnlyLoad(output2.ToArray());
assembly.ModuleResolve += (object sender, ResolveEventArgs e) =>
{
if (e.Name.Equals(c_mod1.SourceModule.Name))
{
return assembly.LoadModule(e.Name, output_mod1.ToArray());
}
return null;
};
string[] resourceNames = assembly.GetManifestResourceNames();
Assert.Equal(1, resourceNames.Length);
var rInfo = assembly.GetManifestResourceInfo(r1Name);
Assert.Equal(System.Reflection.ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod1.SourceModule.Name, rInfo.FileName);
var rData = assembly.GetManifestResourceStream(r1Name);
var rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(arrayOfEmbeddedData, rBytes);
}
var c_mod2 = CSharpCompilation.Create(
Guid.NewGuid().ToString(),
new[] { sourceTree },
new[] { MscorlibRef },
TestOptions.ReleaseModule);
var output_mod2 = new MemoryStream();
result = emit(c_mod2, output_mod2,
new ResourceDescription[]
{
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), true),
new ResourceDescription(r2Name, () => new MemoryStream(resourceFileData), true)
});
Assert.True(result.Success);
var ref_mod2 = ModuleMetadata.CreateFromImage(output_mod2.ToImmutable()).GetReference();
{
var c3 = CreateCompilation(sourceTree, new[] { ref_mod2 }, TestOptions.ReleaseDll);
var output3 = new MemoryStream();
var result3 = c3.Emit(output3);
Assert.True(result3.Success);
var assembly = Assembly.ReflectionOnlyLoad(output3.ToArray());
assembly.ModuleResolve += (object sender, ResolveEventArgs e) =>
{
if (e.Name.Equals(c_mod2.SourceModule.Name))
{
return assembly.LoadModule(e.Name, output_mod2.ToArray());
}
return null;
};
string[] resourceNames = assembly.GetManifestResourceNames();
Assert.Equal(2, resourceNames.Length);
var rInfo = assembly.GetManifestResourceInfo(r1Name);
Assert.Equal(ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod2.SourceModule.Name, rInfo.FileName);
var rData = assembly.GetManifestResourceStream(r1Name);
var rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(arrayOfEmbeddedData, rBytes);
rInfo = assembly.GetManifestResourceInfo(r2Name);
Assert.Equal(ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod2.SourceModule.Name, rInfo.FileName);
rData = assembly.GetManifestResourceStream(r2Name);
rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(resourceFileData, rBytes);
}
var c_mod3 = CSharpCompilation.Create(
Guid.NewGuid().ToString(),
new[] { sourceTree },
new[] { MscorlibRef },
TestOptions.ReleaseModule);
var output_mod3 = new MemoryStream();
result = emit(c_mod3, output_mod3,
new ResourceDescription[]
{
new ResourceDescription(r2Name, () => new MemoryStream(resourceFileData), false)
});
Assert.True(result.Success);
var mod3 = ModuleMetadata.CreateFromImage(output_mod3.ToImmutable());
var ref_mod3 = mod3.GetReference();
Assert.Equal(ManifestResourceAttributes.Private, mod3.Module.GetEmbeddedResourcesOrThrow()[0].Attributes);
{
var c4 = CreateCompilation(sourceTree, new[] { ref_mod3 }, TestOptions.ReleaseDll);
var output4 = new MemoryStream();
var result4 = c4.Emit(output4, manifestResources:
new ResourceDescription[]
{
new ResourceDescription(r1Name, () => new MemoryStream(arrayOfEmbeddedData), false)
});
Assert.True(result4.Success);
var assembly = System.Reflection.Assembly.ReflectionOnlyLoad(output4.ToArray());
assembly.ModuleResolve += (object sender, ResolveEventArgs e) =>
{
if (e.Name.Equals(c_mod3.SourceModule.Name))
{
return assembly.LoadModule(e.Name, output_mod3.ToArray());
}
return null;
};
string[] resourceNames = assembly.GetManifestResourceNames();
Assert.Equal(2, resourceNames.Length);
var rInfo = assembly.GetManifestResourceInfo(r1Name);
Assert.Equal(ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile, rInfo.ResourceLocation);
var rData = assembly.GetManifestResourceStream(r1Name);
var rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(arrayOfEmbeddedData, rBytes);
rInfo = assembly.GetManifestResourceInfo(r2Name);
Assert.Equal(ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod3.SourceModule.Name, rInfo.FileName);
rData = assembly.GetManifestResourceStream(r2Name);
rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(resourceFileData, rBytes);
}
{
var c5 = CreateCompilation(sourceTree, new[] { ref_mod1, ref_mod3 }, TestOptions.ReleaseDll);
var output5 = new MemoryStream();
var result5 = emit(c5, output5, null);
Assert.True(result5.Success);
var assembly = Assembly.ReflectionOnlyLoad(output5.ToArray());
assembly.ModuleResolve += (object sender, ResolveEventArgs e) =>
{
if (e.Name.Equals(c_mod1.SourceModule.Name))
{
return assembly.LoadModule(e.Name, output_mod1.ToArray());
}
else if (e.Name.Equals(c_mod3.SourceModule.Name))
{
return assembly.LoadModule(e.Name, output_mod3.ToArray());
}
return null;
};
string[] resourceNames = assembly.GetManifestResourceNames();
Assert.Equal(2, resourceNames.Length);
var rInfo = assembly.GetManifestResourceInfo(r1Name);
Assert.Equal(ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod1.SourceModule.Name, rInfo.FileName);
var rData = assembly.GetManifestResourceStream(r1Name);
var rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(arrayOfEmbeddedData, rBytes);
rInfo = assembly.GetManifestResourceInfo(r2Name);
Assert.Equal(ResourceLocation.Embedded, rInfo.ResourceLocation);
Assert.Equal(c_mod3.SourceModule.Name, rInfo.FileName);
rData = assembly.GetManifestResourceStream(r2Name);
rBytes = new byte[rData.Length];
rData.Read(rBytes, 0, (int)rData.Length);
Assert.Equal(resourceFileData, rBytes);
}
{
var c6 = CreateCompilation(sourceTree, new[] { ref_mod1, ref_mod2 }, TestOptions.ReleaseDll);
var output6 = new MemoryStream();
var result6 = emit(c6, output6, null);
if (metadataOnly)
{
Assert.True(result6.Success);
}
else
{
Assert.False(result6.Success);
result6.Diagnostics.Verify(
// error CS1508: Resource identifier 'some.dotted.NAME' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("some.dotted.NAME")
);
}
result6 = emit(c6, output6,
new ResourceDescription[]
{
new ResourceDescription(r2Name, () => new MemoryStream(resourceFileData), false)
});
if (metadataOnly)
{
Assert.True(result6.Success);
}
else
{
Assert.False(result6.Success);
result6.Diagnostics.Verify(
// error CS1508: Resource identifier 'some.dotted.NAME' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("some.dotted.NAME"),
// error CS1508: Resource identifier 'another.DoTtEd.NAME' has already been used in this assembly
Diagnostic(ErrorCode.ERR_ResourceNotUnique).WithArguments("another.DoTtEd.NAME")
);
}
c6 = CreateCompilation(sourceTree, new[] { ref_mod1, ref_mod2 }, TestOptions.ReleaseModule);
result6 = emit(c6, output6,
new ResourceDescription[]
{
new ResourceDescription(r2Name, () => new MemoryStream(resourceFileData), false)
});
Assert.True(result6.Success);
}
}
#endif
[Fact]
public void AddManagedLinkedResourceFail()
{
string source = @"
public class Maine
{
static public void Main()
{
}
}
";
var c1 = CreateCompilation(source);
var output = new MemoryStream();
const string r2Name = "another.DoTtEd.NAME";
var result = c1.Emit(output, manifestResources:
new ResourceDescription[]
{
new ResourceDescription(r2Name, "nonExistent", () => { throw new NotSupportedException("error in data provider"); }, false)
});
Assert.False(result.Success);
Assert.Equal((int)ErrorCode.ERR_CantReadResource, result.Diagnostics.ToArray()[0].Code);
}
[Fact]
public void AddManagedEmbeddedResourceFail()
{
string source = @"
public class Maine
{
static public void Main()
{
}
}
";
var c1 = CreateCompilation(source);
var output = new MemoryStream();
const string r2Name = "another.DoTtEd.NAME";
var result = c1.Emit(output, manifestResources:
new ResourceDescription[]
{
new ResourceDescription(r2Name, () => null, true),
});
Assert.False(result.Success);
Assert.Equal((int)ErrorCode.ERR_CantReadResource, result.Diagnostics.ToArray()[0].Code);
}
[ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.TestExecutionNeedsDesktopTypes)]
public void ResourceWithAttrSettings()
{
string source = @"
[assembly: System.Reflection.AssemblyVersion(""1.2.3.4"")]
[assembly: System.Reflection.AssemblyFileVersion(""5.6.7.8"")]
[assembly: System.Reflection.AssemblyTitle(""One Hundred Years of Solitude"")]
[assembly: System.Reflection.AssemblyDescription(""A classic of magical realist literature"")]
[assembly: System.Reflection.AssemblyCompany(""MossBrain"")]
[assembly: System.Reflection.AssemblyProduct(""Sound Cannon"")]
[assembly: System.Reflection.AssemblyCopyright(""circle C"")]
[assembly: System.Reflection.AssemblyTrademark(""circle R"")]
[assembly: System.Reflection.AssemblyInformationalVersion(""1.2.3garbage"")]
public class Maine
{
public static void Main()
{
}
}
";
var c1 = CreateCompilation(source, assemblyName: "Win32VerAttrs", options: TestOptions.ReleaseExe);
var exeFile = Temp.CreateFile();
using (FileStream output = exeFile.Open())
{
c1.Emit(output, win32Resources: c1.CreateDefaultWin32Resources(true, false, null, null));
}
c1 = null;
string versionData;
//Open as data
IntPtr lib = IntPtr.Zero;
try
{
lib = LoadLibraryEx(exeFile.Path, IntPtr.Zero, 0x00000002);
Assert.True(lib != IntPtr.Zero, String.Format("LoadLibrary failed with HResult: {0:X}", +Marshal.GetLastWin32Error()));
//the manifest and version primitives are tested elsewhere. This is to test that the default
//values are passed to the primitives that assemble the resources.
uint size;
IntPtr versionRsrc = Win32Res.GetResource(lib, "#1", "#16", out size);
versionData = Win32Res.VersionResourceToXml(versionRsrc);
}
finally
{
if (lib != IntPtr.Zero)
{
FreeLibrary(lib);
}
}
string expected =
@"<?xml version=""1.0"" encoding=""utf-16""?>
<VersionResource Size=""964"">
<VS_FIXEDFILEINFO FileVersionMS=""00050006"" FileVersionLS=""00070008"" ProductVersionMS=""00010002"" ProductVersionLS=""00030000"" />
<KeyValuePair Key=""Comments"" Value=""A classic of magical realist literature"" />
<KeyValuePair Key=""CompanyName"" Value=""MossBrain"" />
<KeyValuePair Key=""FileDescription"" Value=""One Hundred Years of Solitude"" />
<KeyValuePair Key=""FileVersion"" Value=""5.6.7.8"" />
<KeyValuePair Key=""InternalName"" Value=""Win32VerAttrs.exe"" />
<KeyValuePair Key=""LegalCopyright"" Value=""circle C"" />
<KeyValuePair Key=""LegalTrademarks"" Value=""circle R"" />
<KeyValuePair Key=""OriginalFilename"" Value=""Win32VerAttrs.exe"" />
<KeyValuePair Key=""ProductName"" Value=""Sound Cannon"" />
<KeyValuePair Key=""ProductVersion"" Value=""1.2.3garbage"" />
<KeyValuePair Key=""Assembly Version"" Value=""1.2.3.4"" />
</VersionResource>";
Assert.Equal(expected, versionData);
}
[Fact]
public void ResourceProviderStreamGivesBadLength()
{
var backingStream = new MemoryStream(new byte[] { 1, 2, 3, 4 });
var stream = new TestStream(
canRead: true,
canSeek: true,
readFunc: backingStream.Read,
length: 6, // Lie about the length (> backingStream.Length)
getPosition: () => backingStream.Position);
var c1 = CreateCompilation("");
using (new EnsureEnglishUICulture())
{
var result = c1.Emit(new MemoryStream(), manifestResources:
new[]
{
new ResourceDescription("res", () => stream, false)
});
result.Diagnostics.Verify(
// error CS1566: Error reading resource 'res' -- 'Resource stream ended at 4 bytes, expected 6 bytes.'
Diagnostic(ErrorCode.ERR_CantReadResource).WithArguments("res", "Resource stream ended at 4 bytes, expected 6 bytes.").WithLocation(1, 1));
}
}
}
}
|