diff --git a/Assets/AppIcon.ico b/Assets/AppIcon.ico
new file mode 100644
index 0000000..e8dd43d
Binary files /dev/null and b/Assets/AppIcon.ico differ
diff --git a/Assets/AppIconMaster.png b/Assets/AppIconMaster.png
new file mode 100644
index 0000000..b1a0953
Binary files /dev/null and b/Assets/AppIconMaster.png differ
diff --git a/Assets/LockScreenLogo.scale-200.png b/Assets/LockScreenLogo.scale-200.png
index 7440f0d..6f4be11 100644
Binary files a/Assets/LockScreenLogo.scale-200.png and b/Assets/LockScreenLogo.scale-200.png differ
diff --git a/Assets/SplashScreen.scale-200.png b/Assets/SplashScreen.scale-200.png
index 32f486a..a9a1efd 100644
Binary files a/Assets/SplashScreen.scale-200.png and b/Assets/SplashScreen.scale-200.png differ
diff --git a/Assets/Square150x150Logo.scale-200.png b/Assets/Square150x150Logo.scale-200.png
index 53ee377..e326039 100644
Binary files a/Assets/Square150x150Logo.scale-200.png and b/Assets/Square150x150Logo.scale-200.png differ
diff --git a/Assets/Square44x44Logo.scale-200.png b/Assets/Square44x44Logo.scale-200.png
index f713bba..1848ba7 100644
Binary files a/Assets/Square44x44Logo.scale-200.png and b/Assets/Square44x44Logo.scale-200.png differ
diff --git a/Assets/Square44x44Logo.targetsize-16_altform-unplated.png b/Assets/Square44x44Logo.targetsize-16_altform-unplated.png
new file mode 100644
index 0000000..2b18109
Binary files /dev/null and b/Assets/Square44x44Logo.targetsize-16_altform-unplated.png differ
diff --git a/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
index dc9f5be..e24210d 100644
Binary files a/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and b/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/Assets/Square44x44Logo.targetsize-256_altform-unplated.png b/Assets/Square44x44Logo.targetsize-256_altform-unplated.png
new file mode 100644
index 0000000..b579fe3
Binary files /dev/null and b/Assets/Square44x44Logo.targetsize-256_altform-unplated.png differ
diff --git a/Assets/Square44x44Logo.targetsize-32_altform-unplated.png b/Assets/Square44x44Logo.targetsize-32_altform-unplated.png
new file mode 100644
index 0000000..635fc2e
Binary files /dev/null and b/Assets/Square44x44Logo.targetsize-32_altform-unplated.png differ
diff --git a/Assets/Square44x44Logo.targetsize-48_altform-unplated.png b/Assets/Square44x44Logo.targetsize-48_altform-unplated.png
new file mode 100644
index 0000000..6f4be11
Binary files /dev/null and b/Assets/Square44x44Logo.targetsize-48_altform-unplated.png differ
diff --git a/Assets/StoreLogo.png b/Assets/StoreLogo.png
index a4586f2..43c8c51 100644
Binary files a/Assets/StoreLogo.png and b/Assets/StoreLogo.png differ
diff --git a/Assets/Wide310x150Logo.scale-200.png b/Assets/Wide310x150Logo.scale-200.png
index 8b4a5d0..a73775c 100644
Binary files a/Assets/Wide310x150Logo.scale-200.png and b/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MBN_STOCK_WEBVIEW.LegacyParityApp.csproj b/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MBN_STOCK_WEBVIEW.LegacyParityApp.csproj
index d529662..0fd5c11 100644
--- a/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MBN_STOCK_WEBVIEW.LegacyParityApp.csproj
+++ b/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MBN_STOCK_WEBVIEW.LegacyParityApp.csproj
@@ -18,6 +18,7 @@
win-x64
win-x64
app.manifest
+ ..\..\Assets\AppIcon.ico
false
false
0.1.0
@@ -75,10 +76,18 @@
+
+ PreserveNewest
+ PreserveNewest
+
+
+
+
+
diff --git a/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MainWindow.xaml.cs b/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MainWindow.xaml.cs
index 01f82f0..9695605 100644
--- a/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MainWindow.xaml.cs
+++ b/src/MBN_STOCK_WEBVIEW.LegacyParityApp/MainWindow.xaml.cs
@@ -257,6 +257,11 @@ public sealed partial class MainWindow : Window
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
var appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.Title = "V-Stock 증권정보송출시스템 for 매일경제TV (26.03.26)";
+ var iconPath = Path.Combine(AppContext.BaseDirectory, "Assets", "AppIcon.ico");
+ if (File.Exists(iconPath))
+ {
+ appWindow.SetIcon(iconPath);
+ }
if (appWindow.Presenter is OverlappedPresenter presenter)
{
diff --git a/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyAppIconContractTests.cs b/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyAppIconContractTests.cs
new file mode 100644
index 0000000..a0e7f30
--- /dev/null
+++ b/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyAppIconContractTests.cs
@@ -0,0 +1,124 @@
+using System.Buffers.Binary;
+
+namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
+
+public sealed class LegacyAppIconContractTests
+{
+ private static readonly string RepositoryRoot = FindRepositoryRoot();
+ private static readonly string AssetsRoot = Path.Combine(RepositoryRoot, "Assets");
+ private static readonly string AppRoot = Path.Combine(
+ RepositoryRoot,
+ "src",
+ "MBN_STOCK_WEBVIEW.LegacyParityApp");
+
+ public static TheoryData PackagePngAssets => new()
+ {
+ { "LockScreenLogo.scale-200.png", 48, 48 },
+ { "SplashScreen.scale-200.png", 1240, 600 },
+ { "Square150x150Logo.scale-200.png", 300, 300 },
+ { "Square44x44Logo.scale-200.png", 88, 88 },
+ { "Square44x44Logo.targetsize-16_altform-unplated.png", 16, 16 },
+ { "Square44x44Logo.targetsize-24_altform-unplated.png", 24, 24 },
+ { "Square44x44Logo.targetsize-32_altform-unplated.png", 32, 32 },
+ { "Square44x44Logo.targetsize-48_altform-unplated.png", 48, 48 },
+ { "Square44x44Logo.targetsize-256_altform-unplated.png", 256, 256 },
+ { "StoreLogo.png", 50, 50 },
+ { "Wide310x150Logo.scale-200.png", 620, 300 }
+ };
+
+ [Theory]
+ [MemberData(nameof(PackagePngAssets))]
+ public void PackageIconsAreExactRgbaPngAssets(string fileName, int width, int height)
+ {
+ var bytes = File.ReadAllBytes(Path.Combine(AssetsRoot, fileName));
+
+ Assert.True(
+ bytes.Length > Math.Max(500, (width * height) / 10),
+ $"{fileName} still resembles an unrendered placeholder asset.");
+ Assert.Equal(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 }, bytes[..8]);
+ Assert.Equal("IHDR", System.Text.Encoding.ASCII.GetString(bytes, 12, 4));
+ Assert.Equal(width, BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(16, 4)));
+ Assert.Equal(height, BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(20, 4)));
+ Assert.Equal(8, bytes[24]);
+ Assert.Equal(6, bytes[25]);
+ }
+
+ [Fact]
+ public void ExecutableIconContainsEveryRequiredWindowsSize()
+ {
+ var bytes = File.ReadAllBytes(Path.Combine(AssetsRoot, "AppIcon.ico"));
+ Assert.True(bytes.Length > 1000);
+ Assert.Equal((ushort)0, BinaryPrimitives.ReadUInt16LittleEndian(bytes.AsSpan(0, 2)));
+ Assert.Equal((ushort)1, BinaryPrimitives.ReadUInt16LittleEndian(bytes.AsSpan(2, 2)));
+ var count = BinaryPrimitives.ReadUInt16LittleEndian(bytes.AsSpan(4, 2));
+ Assert.Equal(6, count);
+
+ var sizes = new List();
+ for (var index = 0; index < count; index++)
+ {
+ var width = bytes[6 + (index * 16)];
+ var height = bytes[7 + (index * 16)];
+ Assert.Equal(width, height);
+ sizes.Add(width == 0 ? 256 : width);
+ }
+
+ Assert.Equal(new[] { 16, 24, 32, 48, 64, 256 }, sizes.Order());
+ }
+
+ [Fact]
+ public void ProjectAndWindowUseTheSharedIconWithoutPackagingTheMasterArtwork()
+ {
+ var project = File.ReadAllText(Path.Combine(
+ AppRoot,
+ "MBN_STOCK_WEBVIEW.LegacyParityApp.csproj"));
+ var window = File.ReadAllText(Path.Combine(AppRoot, "MainWindow.xaml.cs"));
+ var manifest = File.ReadAllText(Path.Combine(AppRoot, "Package.appxmanifest"));
+
+ Assert.Contains("..\\..\\Assets\\AppIcon.ico",
+ project,
+ StringComparison.Ordinal);
+ Assert.Contains("Link=\"Assets\\AppIcon.ico\"", project, StringComparison.Ordinal);
+ foreach (var targetSize in new[] { 16, 24, 32, 48, 256 })
+ {
+ Assert.Contains(
+ $"Square44x44Logo.targetsize-{targetSize}_altform-unplated.png",
+ project,
+ StringComparison.Ordinal);
+ }
+
+ Assert.DoesNotContain("AppIconMaster.png", project, StringComparison.Ordinal);
+ Assert.Contains(
+ "Path.Combine(AppContext.BaseDirectory, \"Assets\", \"AppIcon.ico\")",
+ window,
+ StringComparison.Ordinal);
+ Assert.Contains("appWindow.SetIcon(iconPath)", window, StringComparison.Ordinal);
+ Assert.Contains("Square150x150Logo=\"Assets\\Square150x150Logo.png\"",
+ manifest,
+ StringComparison.Ordinal);
+ Assert.Contains("Square44x44Logo=\"Assets\\Square44x44Logo.png\"",
+ manifest,
+ StringComparison.Ordinal);
+ Assert.Contains("Wide310x150Logo=\"Assets\\Wide310x150Logo.png\"",
+ manifest,
+ StringComparison.Ordinal);
+ Assert.Contains("",
+ manifest,
+ StringComparison.Ordinal);
+ }
+
+ private static string FindRepositoryRoot()
+ {
+ var directory = new DirectoryInfo(AppContext.BaseDirectory);
+ while (directory is not null)
+ {
+ if (File.Exists(Path.Combine(directory.FullName, "MBN_STOCK_WEBVIEW.sln")))
+ {
+ return directory.FullName;
+ }
+
+ directory = directory.Parent;
+ }
+
+ throw new DirectoryNotFoundException("Repository root could not be located.");
+ }
+}