From 9234ef4acfd6702cce7f564d570d65dee43ce0d1 Mon Sep 17 00:00:00 2001 From: Talic Date: Tue, 25 Jun 2024 00:13:51 +0300 Subject: [PATCH] refactoring, catch error and display warning for bad layout file, remove WMP reference, correctly add custom watch rooms --- .../SotnRandoTools.RandoTracker.Tests.csproj | 3 +- .../InitializeItemsShould.cs | 18 +-- .../TrackerTests/ConstructorShould.cs | 2 +- .../SotnRandoTools.Services.Tests.csproj | 1 + .../src/Configuration/TrackerConfig.cs | 6 - .../src/Panels/AutotrackerSettingsPanel.cs | 14 ++- .../src/Properties/launchSettings.json | 3 +- .../Interfaces/ITrackerRenderer.cs | 2 +- .../src/RandoTracker/Models/Location.cs | 8 +- SotnRandoTools/src/RandoTracker/Tracker.cs | 109 ++++++++++++------ .../src/RandoTracker/TrackerRendererGDI.cs | 18 +-- .../src/Services/NotificationService.cs | 15 ++- SotnRandoTools/src/SotnRandoTools.csproj | 24 ++-- 13 files changed, 133 insertions(+), 90 deletions(-) diff --git a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests.csproj b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests.csproj index b7f24f2..468e52e 100644 --- a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests.csproj +++ b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests.csproj @@ -1,9 +1,10 @@ - + net48 false + diff --git a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerRendererGDITests/InitializeItemsShould.cs b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerRendererGDITests/InitializeItemsShould.cs index f3bf571..587be15 100644 --- a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerRendererGDITests/InitializeItemsShould.cs +++ b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerRendererGDITests/InitializeItemsShould.cs @@ -16,9 +16,9 @@ public void ThrowArgumentNullException_WhenRelicsArgumentIsNull() //Arrange var mockedFormGraphics = Substitute.For(); var mockedToolConfig = Substitute.For(); - List testRelics = new List(); - List testProgressionItems = new List(); - List testThrustSwords = new List(); + TrackerRelic[] testRelics = new TrackerRelic[1]; + Item[] testProgressionItems = new Item[1]; + Item[] testThrustSwords = new Item[1]; //Act TrackerRendererGDI trackerGraphicsEngine = new TrackerRendererGDI(mockedFormGraphics, mockedToolConfig); //Assert @@ -31,9 +31,9 @@ public void ThrowArgumentNullException_WhenProgressionItemsArgumentIsNull() //Arrange var mockedFormGraphics = Substitute.For(); var mockedToolConfig = Substitute.For(); - List testRelics = new List(); - List testProgressionItems = new List(); - List testThrustSwords = new List(); + TrackerRelic[] testRelics = new TrackerRelic[1]; + Item[] testProgressionItems = new Item[1]; + Item[] testThrustSwords = new Item[1]; //Act TrackerRendererGDI trackerGraphicsEngine = new TrackerRendererGDI(mockedFormGraphics, mockedToolConfig); //Assert @@ -46,9 +46,9 @@ public void ThrowArgumentNullException_WhenThrustSwordsArgumentIsNull() //Arrange var mockedFormGraphics = Substitute.For(); var mockedToolConfig = Substitute.For(); - List testRelics = new List(); - List testProgressionItems = new List(); - List testThrustSwords = new List(); + TrackerRelic[] testRelics = new TrackerRelic[1]; + Item[] testProgressionItems = new Item[1]; + Item[] testThrustSwords = new Item[1]; //Act TrackerRendererGDI trackerGraphicsEngine = new TrackerRendererGDI(mockedFormGraphics, mockedToolConfig); //Assert diff --git a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerTests/ConstructorShould.cs b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerTests/ConstructorShould.cs index 60ddaa7..01bbaa8 100644 --- a/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerTests/ConstructorShould.cs +++ b/SotnRandoTools/SotnRandoTools.UnitTests/RandoTracker.Tests/SotnRandoTools.RandoTracker.Tests/TrackerTests/ConstructorShould.cs @@ -92,7 +92,7 @@ public void ReturnsAnInstance_WhenParametersAreNotNull() mockedToolConfig.Tracker.UseOverlay = false; mockedToolConfig.Tracker.EnableAutosplitter = false; mockedGraphicsEngine - .When(g => g.InitializeItems(Arg.Any>(), Arg.Any>(), Arg.Any>())) + .When(g => g.InitializeItems(Arg.Any(), Arg.Any(), Arg.Any< Models.Item[]>())) .Do(x => { }); mockedGraphicsEngine .When(g => g.CalculateGrid(Arg.Any(), Arg.Any())) diff --git a/SotnRandoTools/SotnRandoTools.UnitTests/Services.Tests/SotnRandoTools.Services.Tests/SotnRandoTools.Services.Tests.csproj b/SotnRandoTools/SotnRandoTools.UnitTests/Services.Tests/SotnRandoTools.Services.Tests/SotnRandoTools.Services.Tests.csproj index 31fa5e6..226c8cb 100644 --- a/SotnRandoTools/SotnRandoTools.UnitTests/Services.Tests/SotnRandoTools.Services.Tests/SotnRandoTools.Services.Tests.csproj +++ b/SotnRandoTools/SotnRandoTools.UnitTests/Services.Tests/SotnRandoTools.Services.Tests/SotnRandoTools.Services.Tests.csproj @@ -4,6 +4,7 @@ net48 false + diff --git a/SotnRandoTools/src/Configuration/TrackerConfig.cs b/SotnRandoTools/src/Configuration/TrackerConfig.cs index 65cf74f..48ce885 100644 --- a/SotnRandoTools/src/Configuration/TrackerConfig.cs +++ b/SotnRandoTools/src/Configuration/TrackerConfig.cs @@ -67,11 +67,6 @@ public override object ReadJson( else { return TrackerConfig.GetDefaultOverlay(); - //throw new Exception( - // string.Format( - // "Unexpected token parsing binary. " - // + "Expected StartArray, got {0}.", - // reader.TokenType)); } } @@ -186,7 +181,6 @@ public void LoadOverlayLayout(string path) if (File.Exists(path)) { string layoutJson = File.ReadAllText(path); - byte[] layout = JsonConvert.DeserializeObject(layoutJson, new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, MissingMemberHandling = MissingMemberHandling.Ignore }); diff --git a/SotnRandoTools/src/Panels/AutotrackerSettingsPanel.cs b/SotnRandoTools/src/Panels/AutotrackerSettingsPanel.cs index 1aa6eec..9c94f67 100644 --- a/SotnRandoTools/src/Panels/AutotrackerSettingsPanel.cs +++ b/SotnRandoTools/src/Panels/AutotrackerSettingsPanel.cs @@ -182,7 +182,19 @@ private void saveLayoutButton_Click(object sender, EventArgs e) private void openLayoutDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e) { - toolConfig.Tracker.LoadOverlayLayout(openLayoutDialog.FileName); + try + { + toolConfig.Tracker.LoadOverlayLayout(openLayoutDialog.FileName); + } + catch (Exception) + { + string message = "Unsupported or outdated file format!"; + string caption = "Unsupported or outdated file format!"; + MessageBoxButtons buttons = MessageBoxButtons.OK; + DialogResult result; + + result = MessageBox.Show(message, caption, buttons); + } } private void saveLayoutDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e) diff --git a/SotnRandoTools/src/Properties/launchSettings.json b/SotnRandoTools/src/Properties/launchSettings.json index 3c962e8..053c291 100644 --- a/SotnRandoTools/src/Properties/launchSettings.json +++ b/SotnRandoTools/src/Properties/launchSettings.json @@ -4,7 +4,8 @@ "commandName": "Executable", "executablePath": "D:\\Programming\\SotnRandoTools\\SotnRandoTools\\BizHawk\\EmuHawk.exe", "commandLineArgs": "--open-ext-tool-dll=SotnRandoTools", - "workingDirectory": "D:\\Programming\\SotnRandoTools\\SotnRandoTools\\BizHawk" + "workingDirectory": "D:\\Programming\\SotnRandoTools\\SotnRandoTools\\BizHawk", + "nativeDebugging": false } } } \ No newline at end of file diff --git a/SotnRandoTools/src/RandoTracker/Interfaces/ITrackerRenderer.cs b/SotnRandoTools/src/RandoTracker/Interfaces/ITrackerRenderer.cs index efe53de..3b33a0e 100644 --- a/SotnRandoTools/src/RandoTracker/Interfaces/ITrackerRenderer.cs +++ b/SotnRandoTools/src/RandoTracker/Interfaces/ITrackerRenderer.cs @@ -12,6 +12,6 @@ internal interface ITrackerRenderer void CalculateGrid(int width, int height); void Render(); void ChangeGraphics(IGraphics formGraphics); - void InitializeItems(List relics, List progressionItems, List thrustSwords); + void InitializeItems(Models.TrackerRelic[] relics, Item[] progressionItems, Item[] thrustSwords); } } \ No newline at end of file diff --git a/SotnRandoTools/src/RandoTracker/Models/Location.cs b/SotnRandoTools/src/RandoTracker/Models/Location.cs index 6b689d5..32386af 100644 --- a/SotnRandoTools/src/RandoTracker/Models/Location.cs +++ b/SotnRandoTools/src/RandoTracker/Models/Location.cs @@ -6,8 +6,8 @@ internal sealed class Location { public Location() { - Locks = new List(); - OutOfLogicLocks = new List(); + Locks = new List(); + OutOfLogicLocks = new List(); Rooms = new List(); WatchIndecies = new List(); AvailabilityColor = MapColor.Unavailable; @@ -30,8 +30,8 @@ public Location() public bool Visited { get; set; } public int X { get; set; } public int Y { get; set; } - public List? Locks { get; set; } - public List? OutOfLogicLocks { get; set; } + public List? Locks { get; set; } + public List? OutOfLogicLocks { get; set; } public List WatchIndecies { get; set; } public List? Rooms { get; set; } } diff --git a/SotnRandoTools/src/RandoTracker/Tracker.cs b/SotnRandoTools/src/RandoTracker/Tracker.cs index cb66006..0cce998 100644 --- a/SotnRandoTools/src/RandoTracker/Tracker.cs +++ b/SotnRandoTools/src/RandoTracker/Tracker.cs @@ -360,7 +360,7 @@ internal sealed class Tracker new Room { WatchIndex = 81, Values = new int[] { 0x10 }}, }}, }; - private readonly List relics = new List + private readonly TrackerRelic[] relics = new TrackerRelic[] { new TrackerRelic { Name = "SoulOfBat", Progression = true}, new TrackerRelic { Name = "FireOfBat", Progression = false}, @@ -393,14 +393,14 @@ internal sealed class Tracker new TrackerRelic { Name = "RingOfVlad", Progression = true}, new TrackerRelic { Name = "EyeOfVlad", Progression = true} }; - private readonly List progressionItems = new List + private readonly Item[] progressionItems = new Item[] { new Item { Name = "GoldRing", Value = 72 }, new Item { Name = "SilverRing", Value = 73 }, new Item { Name = "SpikeBreaker", Value = 14 }, new Item { Name = "HolyGlasses", Value = 34 } }; - private readonly List thrustSwords = new List + private readonly Item[] thrustSwords = new Item[] { new Item { Name = "Estoc", Value = 95 }, new Item { Name = "Claymore", Value = 98 }, @@ -448,14 +448,6 @@ internal sealed class Tracker { "spikebreaker", 2 }, { "holyglasses", 3 }, }; - private readonly Dictionary swordToIndex = new Dictionary - { - { "estoc", 0 }, - { "claymore", 1 }, - { "flamberge", 2 }, - { "zweihander", 3 }, - { "obsidiansword", 4 }, - }; private readonly HashSet VanillaPresets = new HashSet { "adventure", @@ -732,6 +724,7 @@ private bool LoadExtension(string extensionFilePath) foreach (ExtensionLocation location in extension.Locations) { Location? customLocation = locations.Where(x => x.Name == location.Name).FirstOrDefault(); + int locationIndex = 0; if (customLocation is null) { @@ -743,6 +736,8 @@ private bool LoadExtension(string extensionFilePath) SecondCastle = location.SecondCastle, CustomExtension = true }; + locations.Add(customLocation); + locationIndex = locations.Count - 1; } else { @@ -756,7 +751,7 @@ private bool LoadExtension(string extensionFilePath) { customLocation.CustomExtension = true; } - continue; + locationIndex = locations.IndexOf(customLocation); } int roomCounter = 0; @@ -774,9 +769,8 @@ private bool LoadExtension(string extensionFilePath) customLocation.WatchIndecies.Add(watchlistService.SafeLocationWatches.Count - 1); customLocation.Rooms.Add(customRoom); watchToRoom[watchlistService.SafeLocationWatches.Count - 1] = roomCounter - 1; - watchToLocation[watchlistService.SafeLocationWatches.Count - 1] = locations.Count; + watchToLocation[watchlistService.SafeLocationWatches.Count - 1] = locationIndex; } - locations.Add(customLocation); } return true; } @@ -860,13 +854,34 @@ private void LoadLocks(string presetFilePath, bool outOfLogic = false, bool over } } } + + int[] mappedLockSet = new int[newLockSet.Length]; + + for (int i = 0; i < newLockSet.Length; i++) + { + if (relicToIndex.ContainsKey(newLockSet[i])) + { + mappedLockSet[i] = relicToIndex[newLockSet[i]]; + + } + else if (itemToIndex.ContainsKey(newLockSet[i])) + { + mappedLockSet[i] = 100 + itemToIndex[newLockSet[i]]; + + } + else if (newLockSet[i] == "thrustsword") + { + mappedLockSet[i] = 200; + } + } + if (outOfLogic) { - trackerLocation.OutOfLogicLocks.Add(newLockSet); + trackerLocation.OutOfLogicLocks.Add(mappedLockSet); } else { - trackerLocation.Locks.Add(newLockSet); + trackerLocation.Locks.Add(mappedLockSet); } } } @@ -896,7 +911,27 @@ private void LoadLocks(string presetFilePath, bool outOfLogic = false, bool over } } - trackerLocation.OutOfLogicLocks.Add(newLockSet); + int[] mappedLockSet = new int[newLockSet.Length]; + + for (int i = 0; i < newLockSet.Length; i++) + { + if (relicToIndex.ContainsKey(newLockSet[i])) + { + mappedLockSet[i] = relicToIndex[newLockSet[i]]; + + } + else if (itemToIndex.ContainsKey(newLockSet[i])) + { + mappedLockSet[i] = 100 + itemToIndex[newLockSet[i]]; + + } + else if (newLockSet[i] == "thrustsword") + { + mappedLockSet[i] = 200; + } + } + + trackerLocation.OutOfLogicLocks.Add(mappedLockSet); } } @@ -1040,7 +1075,7 @@ private bool UpdateProgressionItems() } watchlistService.ProgressionItemWatches.ClearChangeCounts(); - for (int i = 0; i < progressionItems.Count; i++) + for (int i = 0; i < progressionItems.Length; i++) { switch (i) { @@ -1107,7 +1142,7 @@ private bool UpdateThrustSwords() } watchlistService.ThrustSwordWatches.ClearChangeCounts(); - for (int i = 0; i < thrustSwords.Count; i++) + for (int i = 0; i < thrustSwords.Length; i++) { thrustSwords[i].Equipped = (sotnApi.AlucardApi.RightHand == thrustSwords[i].Value); @@ -1410,26 +1445,28 @@ private void CheckReachability() } } - private bool TrackedObjectStatus(string name) + private bool TrackedObjectStatus(int index) { - if (relicToIndex.ContainsKey(name)) + if (index == 200) { - TrackerRelic relic = relics[relicToIndex[name]]; - return relic.Collected; + for (int i = 0; i < thrustSwords.Length; i++) + { + if (thrustSwords[i].Collected) + { + return true; + } + } } - if (name == "holyglasses" && secondCastle) + else if (index < 100) { - return true; + TrackerRelic relic = relics[index]; + return relic.Collected; } - if (itemToIndex.ContainsKey(name)) + else { - Item progressionItem = progressionItems[itemToIndex[name]]; + Item progressionItem = progressionItems[index - 100]; return progressionItem.Status; } - if (name == "thrustsword" && swordToIndex.ContainsKey(name)) - { - return true; - } return false; } @@ -1445,13 +1482,13 @@ private void UpdateOverlay() private int EncodeItems() { int itemsNumber = 0; - for (int i = 0; i < progressionItems.Count + 1; i++) + for (int i = 0; i < progressionItems.Length + 1; i++) { - if (i < progressionItems.Count && progressionItems[i].Status) + if (i < progressionItems.Length && progressionItems[i].Status) { itemsNumber |= (int) Math.Pow(2, i); } - else if (i == progressionItems.Count) + else if (i == progressionItems.Length) { foreach (var sword in thrustSwords) { @@ -1470,7 +1507,7 @@ private int EncodeItems() private int EncodeRelics() { int relicsNumber = 0; - for (int i = 0; i < relics.Count; i++) + for (int i = 0; i < relics.Length; i++) { if (relics[i].Collected) { @@ -1557,7 +1594,7 @@ public void SaveReplay() } replayPath = Paths.ReplaysPath + replayPath + ".sotnr"; - byte[] replayBytes = new byte[2 + (replayLenght * 4) + ((relics.Count + progressionItems.Count + 1) * 4)]; + byte[] replayBytes = new byte[2 + (replayLenght * 4) + ((relics.Length + progressionItems.Length + 1) * 4)]; int replayIndex = 0; byte[] finalTimeSecondsBytes = BitConverter.GetBytes((ushort) finalTime.TotalSeconds); diff --git a/SotnRandoTools/src/RandoTracker/TrackerRendererGDI.cs b/SotnRandoTools/src/RandoTracker/TrackerRendererGDI.cs index 5de1ecf..1a7345a 100644 --- a/SotnRandoTools/src/RandoTracker/TrackerRendererGDI.cs +++ b/SotnRandoTools/src/RandoTracker/TrackerRendererGDI.cs @@ -26,9 +26,9 @@ internal sealed class TrackerRendererGDI : ITrackerRenderer private IGraphics formGraphics; private readonly IToolConfig toolConfig; - private List? relics; - private List? progressionItems; - private List? thrustSwords; + private TrackerRelic[]? relics; + private Item[]? progressionItems; + private Item[]? thrustSwords; private Bitmap texture; private Bitmap greyscaleTexture; @@ -51,7 +51,7 @@ public TrackerRendererGDI(IGraphics formGraphics, IToolConfig toolConfig) public bool Refreshed { get; set; } public string SeedInfo { get; set; } - public void InitializeItems(List relics, List progressionItems, List thrustSwords) + public void InitializeItems(TrackerRelic[] relics, Item[] progressionItems, Item[] thrustSwords) { if (relics is null) throw new ArgumentNullException(nameof(relics)); if (progressionItems is null) throw new ArgumentNullException(nameof(progressionItems)); @@ -207,7 +207,7 @@ private void GridRender() normalRelicCount++; } Item? thrustSword = null; - for (int i = 0; i < thrustSwords.Count; i++) + for (int i = 0; i < thrustSwords.Length; i++) { if (thrustSwords[i].Status) { @@ -219,13 +219,13 @@ private void GridRender() if (vladProgression) { - for (int i = 25; i < relics.Count; i++) + for (int i = 25; i < relics.Length; i++) { formGraphics.DrawImage(relics[i].Collected ? texture : greyscaleTexture, vladRelicSlots[i - 25], 20 * i, 0, ImageSize, ImageSize, GraphicsUnit.Pixel); } } - for (int i = 0; i < progressionItems.Count; i++) + for (int i = 0; i < progressionItems.Length; i++) { formGraphics.DrawImage(progressionItems[i].Status ? texture : greyscaleTexture, progressionItemSlots[i], 600 + 20 * i, 0, ImageSize, ImageSize, GraphicsUnit.Pixel); } @@ -252,7 +252,7 @@ private void CollectedRender() if (vladProgression) { int vladRelicCount = 0; - for (int i = 25; i < relics.Count; i++) + for (int i = 25; i < relics.Length; i++) { if (relics[i].Collected) { @@ -263,7 +263,7 @@ private void CollectedRender() } int progressionItemCount = 0; - for (int i = 0; i < progressionItems.Count; i++) + for (int i = 0; i < progressionItems.Length; i++) { if (progressionItems[i].Status) { diff --git a/SotnRandoTools/src/Services/NotificationService.cs b/SotnRandoTools/src/Services/NotificationService.cs index 6b510a9..290db18 100644 --- a/SotnRandoTools/src/Services/NotificationService.cs +++ b/SotnRandoTools/src/Services/NotificationService.cs @@ -4,10 +4,14 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Media; +using System.Threading.Tasks; using System.Windows.Forms; +using System.Windows.Media; using BizHawk.Client.Common; using SotnRandoTools.Configuration.Interfaces; using SotnRandoTools.Constants; +using Color = System.Drawing.Color; namespace SotnRandoTools.Services { @@ -18,7 +22,6 @@ internal sealed class NotificationService : INotificationService private const int MessageDurationFast = 60; private const int MapOffsetX = 16; private const int MapOffsetY = 20; - private Color WallColor = Color.FromArgb(192, 192, 192); private readonly IGuiApi guiApi; private readonly IToolConfig toolConfig; @@ -26,9 +29,7 @@ internal sealed class NotificationService : INotificationService private int scale; private Image textbox; -#if WIN - private System.Windows.Media.MediaPlayer audioPlayer = new(); -#endif + private MediaPlayer audioPlayer = new(); private Queue messageQueue = new(); private int messageFrames = 0; private bool updated = false; @@ -42,9 +43,8 @@ public NotificationService(IToolConfig toolConfig, IGuiApi guiApi, IEmuClientApi overlaySocketServer = new OverlaySocketServer(toolConfig); scale = clientAPI.GetWindowSize(); ResizeImages(); -#if WIN + audioPlayer.Volume = (double) toolConfig.Coop.Volume / 10F; -#endif } public double Volume @@ -60,7 +60,7 @@ public double Volume public void PlayAlert(string url) { if (String.IsNullOrEmpty(url)) throw new ArgumentNullException(nameof(url)); -#if WIN + try { audioPlayer.Dispatcher.Invoke(() => @@ -76,7 +76,6 @@ public void PlayAlert(string url) { Console.WriteLine(e.Message); } -#endif } public void AddMessage(string message) diff --git a/SotnRandoTools/src/SotnRandoTools.csproj b/SotnRandoTools/src/SotnRandoTools.csproj index e6eb03b..c33ee90 100644 --- a/SotnRandoTools/src/SotnRandoTools.csproj +++ b/SotnRandoTools/src/SotnRandoTools.csproj @@ -11,7 +11,7 @@ Library false 5.0 - 1.7.1 + 1.7.2 A collection of tools to enhance the experience of playing the SotN randomizer. https://taliczealot.github.io/#/projects/sotnrandotools @@ -22,12 +22,21 @@ True portable + + True + portable + True portable - $(DefineConstants);WIN $(DefineConstants);GDI + + True + portable + $(DefineConstants);WIN + $(DefineConstants);GDI + @@ -38,17 +47,6 @@ - - - 0 - 1 - 6bf52a50-394a-11d3-b153-00c04f79faa6 - 0 - tlbimp - false - true - -