diff --git a/Rapr/DSEForm.cs b/Rapr/DSEForm.cs index 82f6318b..b6f66503 100644 --- a/Rapr/DSEForm.cs +++ b/Rapr/DSEForm.cs @@ -1215,7 +1215,7 @@ private void UpdateCheckedItemSize() foreach (DriverStoreEntry item in checkedObjects) { - totalSize += item.DriverSize; + totalSize += Math.Max(item.DriverSize, 0); driverList.Add($"{item.DriverPublishedName} - {item.DriverFolderName} - {DriverStoreEntry.GetBytesReadable(item.DriverSize)}"); } diff --git a/Rapr/DSEFormHelper.cs b/Rapr/DSEFormHelper.cs index d89b084e..8f3c23a0 100644 --- a/Rapr/DSEFormHelper.cs +++ b/Rapr/DSEFormHelper.cs @@ -62,24 +62,40 @@ private static string GetFinalPathName(string path) StringBuilder finalPath = new StringBuilder(512); int result = SafeNativeMethods.GetFinalPathNameByHandle(handle, finalPath, finalPath.Capacity, 0); - if (result < 0) + if (result > finalPath.Capacity) { - throw new Win32Exception(Marshal.GetLastWin32Error()); + // The buffer was too small; result is the size needed. + finalPath.Capacity = result; + result = SafeNativeMethods.GetFinalPathNameByHandle(handle, finalPath, finalPath.Capacity, 0); } - // Remove the "\\?\" prefix - const string PathPrefix = @"\\?\"; - string finalPathString = finalPath.ToString(); - - if (finalPath.Length > PathPrefix.Length && finalPathString.StartsWith(PathPrefix)) + if (result == 0 || result > finalPath.Capacity) { - finalPathString = finalPathString.Substring(PathPrefix.Length); + throw new Win32Exception(Marshal.GetLastWin32Error()); } - return finalPathString; + return RemoveExtendedPathPrefix(finalPath.ToString()); } } + internal static string RemoveExtendedPathPrefix(string path) + { + const string UncPrefix = @"\\?\UNC\"; + const string PathPrefix = @"\\?\"; + + if (path.StartsWith(UncPrefix, StringComparison.OrdinalIgnoreCase)) + { + return @"\\" + path.Substring(UncPrefix.Length); + } + + if (path.StartsWith(PathPrefix, StringComparison.Ordinal)) + { + return path.Substring(PathPrefix.Length); + } + + return path; + } + public static bool IsRunAsAdmin { get; } = IsRunAsAdministrator(); private static bool IsRunAsAdministrator() diff --git a/Rapr/Utils/DriverStoreEntry.cs b/Rapr/Utils/DriverStoreEntry.cs index 91f80d2b..51522820 100644 --- a/Rapr/Utils/DriverStoreEntry.cs +++ b/Rapr/Utils/DriverStoreEntry.cs @@ -297,6 +297,17 @@ public string[] GetFieldValues() // The default format is "0.### XB", e.g. "4 KB" or "1.4 GB" public static string GetBytesReadable(long i) { + // A negative size means it couldn't be determined (see DriverStoreRepository). + if (i < 0) + { + return string.Empty; + } + + if (i == 0) + { + return "0 KB"; + } + // Get absolute value long absolute_i = (i < 0 ? -i : i); diff --git a/Rapr/Utils/PNPUtil.cs b/Rapr/Utils/PNPUtil.cs index 4f97e3bd..184fa382 100644 --- a/Rapr/Utils/PNPUtil.cs +++ b/Rapr/Utils/PNPUtil.cs @@ -115,7 +115,7 @@ public static List ParsePnpUtilEnumerateResult(string pnpUtilO else if (currentLine.Length == 0) { // Blank line means the end of an driver entry. - if (!driverStoreEntry.Equals(default(DriverStoreEntry))) + if (!string.IsNullOrEmpty(driverStoreEntry.DriverPublishedName)) { driverStoreEntries.Add(driverStoreEntry); driverStoreEntry = new DriverStoreEntry(); diff --git a/RaprTests/DSEFormHelperTests.cs b/RaprTests/DSEFormHelperTests.cs new file mode 100644 index 00000000..2802dae1 --- /dev/null +++ b/RaprTests/DSEFormHelperTests.cs @@ -0,0 +1,25 @@ +using System; +using System.Reflection; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Rapr.Tests +{ + [TestClass] + public class DSEFormHelperTests + { + private static readonly Func RemoveExtendedPathPrefix = + (Func)typeof(DSEFormHelper) + .GetMethod("RemoveExtendedPathPrefix", BindingFlags.Static | BindingFlags.NonPublic) + .CreateDelegate(typeof(Func)); + + [TestMethod] + [DataRow(@"\\?\C:\Tools\Rapr.exe", @"C:\Tools\Rapr.exe")] + [DataRow(@"\\?\UNC\server\share\Rapr.exe", @"\\server\share\Rapr.exe")] + [DataRow(@"C:\Tools\Rapr.exe", @"C:\Tools\Rapr.exe")] + public void ExtendedPathPrefixIsRemoved(string path, string expected) + { + Assert.AreEqual(expected, RemoveExtendedPathPrefix(path)); + } + } +} diff --git a/RaprTests/DriverStoreEntryTests.cs b/RaprTests/DriverStoreEntryTests.cs index 8586a481..7a1f2370 100644 --- a/RaprTests/DriverStoreEntryTests.cs +++ b/RaprTests/DriverStoreEntryTests.cs @@ -46,6 +46,16 @@ public void InstallDateKeepsNull() Assert.IsNull(entry.InstallDate); } + [TestMethod] + [DataRow(-1L, "")] + [DataRow(0L, "0 KB")] + [DataRow(1L, "1 KB")] + [DataRow(2048L, "2 KB")] + public void UnknownAndEmptySizesAreNotShownAsOneKilobyte(long size, string expected) + { + Assert.AreEqual(expected, DriverStoreEntry.GetBytesReadable(size)); + } + [TestMethod] public void DriverDateIsTruncatedToTheDayItDisplays() { diff --git a/RaprTests/Utils/PNPUtilTests.cs b/RaprTests/Utils/PNPUtilTests.cs index 8a52f99f..7af6f8c9 100644 --- a/RaprTests/Utils/PNPUtilTests.cs +++ b/RaprTests/Utils/PNPUtilTests.cs @@ -1033,6 +1033,35 @@ public void ParseEnglishPnpUtilEnumerateResultWithMissingLineTest() Assert.AreEqual("Microsoft Windows Hardware Compatibility Publisher", entries[1].DriverSignerName); } + [TestMethod()] + public void ConsecutiveBlankLinesDoNotAddEmptyEntries() + { + string output = string.Join("\r\n", new[] + { + "Microsoft PnP Utility", + "", + "Published name : oem4.inf", + "Driver package provider : Microsoft", + "Class : Human Interface Devices", + "Driver date and version : 11/06/2015 9.9.114.0", + "Signer name : Microsoft Windows Hardware Compatibility Publisher", + "", + "", + "Published name : oem18.inf", + "Driver package provider : Intel", + "Class : System devices", + "Driver date and version : 12/17/2012 9.0.0.1287", + "Signer name : Microsoft Windows Hardware Compatibility Publisher", + "", + }); + + List entries = PnpUtil.ParsePnpUtilEnumerateResult(output); + + Assert.HasCount(2, entries); + Assert.AreEqual("oem4.inf", entries[0].DriverPublishedName); + Assert.AreEqual("oem18.inf", entries[1].DriverPublishedName); + } + [TestMethod()] public void ParseChinesePnpUtilEnumerateResultTest() {