diff --git a/PInvoke/Kernel32/PathCch.cs b/PInvoke/Kernel32/PathCch.cs
index 2ff89cb9..8bc374ab 100644
--- a/PInvoke/Kernel32/PathCch.cs
+++ b/PInvoke/Kernel32/PathCch.cs
@@ -332,6 +332,54 @@ namespace Vanara.PInvoke
[PInvokeData("pathcch.h", MSDNShortId = "89adf45f-f16d-49d1-9e76-b57b73b4d4c3")]
public static extern HRESULT PathCchAddBackslashEx(StringBuilder pszPath, SizeT cchPath, out IntPtr ppszEnd, out SizeT pcchRemaining);
+ ///
+ ///
+ /// Adds a backslash to the end of a string to create the correct syntax for a path. If the source path already has a trailing
+ /// backslash, no backslash will be added.
+ ///
+ ///
+ /// This function differs from PathCchAddBackslash in that it can return a pointer to the new end of the string and report the number
+ /// of unused characters remaining in the buffer.
+ ///
+ /// This function differs from PathAddBackslash in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
+ ///
+ /// Note This function, or PathCchAddBackslashEx, should be used in place of PathAddBackslash to prevent the
+ /// possibility of a buffer overrun.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to the path string. When this function returns successfully, the buffer contains the string with the appended
+ /// backslash. This value should not be NULL.
+ ///
+ ///
+ ///
+ /// The size of the buffer pointed to by pszPath, in characters.
+ ///
+ ///
+ ///
+ /// A value that, when this function returns successfully, receives the address of a pointer to the terminating null character at the
+ /// end of the string.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to a value that, when this function returns successfully, is set to the number of unused characters in the destination
+ /// buffer, including the terminating null character.
+ ///
+ ///
+ ///
+ ///
+ /// This function returns S_OK if the function was successful, S_FALSE if the path string already ends in a backslash, or an error
+ /// code otherwise.
+ ///
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/pathcch/nf-pathcch-pathcchaddbackslashex HRESULT PathCchAddBackslashEx( PWSTR
+ // pszPath, SizeT cchPath, PWSTR *ppszEnd, SizeT *pcchRemaining );
+ [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [PInvokeData("pathcch.h", MSDNShortId = "89adf45f-f16d-49d1-9e76-b57b73b4d4c3")]
+ public static extern HRESULT PathCchAddBackslashEx(IntPtr pszPath, SizeT cchPath, out IntPtr ppszEnd, out SizeT pcchRemaining);
+
///
/// Adds a file name extension to a path string.
/// This function differs from PathAddExtension in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
@@ -1028,6 +1076,35 @@ namespace Vanara.PInvoke
[PInvokeData("pathcch.h", MSDNShortId = "dac6cf02-7b53-449c-b788-4a7b6d1622ed")]
public static extern HRESULT PathCchFindExtension(string pszPath, SizeT cchPath, out IntPtr ppszExt);
+ ///
+ ///
+ /// Searches a path to find its file name extension, such as ".exe" or ".ini". This function does not search for a specific
+ /// extension; it searches for the presence of any extension.
+ ///
+ /// This function differs from PathFindExtension in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
+ /// Note This function should be used in place of PathFindExtension to prevent the possibility of a buffer overrun.
+ ///
+ ///
+ /// A pointer to the path to search.
+ ///
+ ///
+ /// The size of the buffer pointed to by pszPath, in characters.
+ ///
+ ///
+ ///
+ /// The address of a pointer that, when this function returns successfully, points to the "." character that precedes the extension
+ /// within pszPath. If no extension is found, it points to the string's terminating null character.
+ ///
+ ///
+ ///
+ /// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/pathcch/nf-pathcch-pathcchfindextension HRESULT PathCchFindExtension( PCWSTR
+ // pszPath, SizeT cchPath, PCWSTR *ppszExt );
+ [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [PInvokeData("pathcch.h", MSDNShortId = "dac6cf02-7b53-449c-b788-4a7b6d1622ed")]
+ public static extern HRESULT PathCchFindExtension(IntPtr pszPath, SizeT cchPath, out IntPtr ppszExt);
+
///
/// Determines whether a path string refers to the root of a volume.
/// This function differs from PathIsRoot in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
@@ -1238,6 +1315,55 @@ namespace Vanara.PInvoke
[PInvokeData("pathcch.h", MSDNShortId = "250c2faa-94bb-42c1-97d4-37f8f59dbde6")]
public static extern HRESULT PathCchRemoveBackslashEx(StringBuilder pszPath, SizeT cchPath, out IntPtr ppszEnd, out SizeT pcchRemaining);
+ ///
+ /// Removes the trailing backslash from the end of a path string.
+ ///
+ /// This function differs from PathCchRemoveBackslash in that it can return a pointer to the new end of the string and report the
+ /// number of unused characters remaining in the buffer.
+ ///
+ /// This function differs from PathRemoveBackslash in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
+ ///
+ /// Note This function, or PathCchRemoveBackslash, should be used in place of PathRemoveBackslash to prevent the possibility
+ /// of a buffer overrun.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to the path string. When this function returns successfully, the string contains the path with any trailing backslash
+ /// removed. If no trailing backslash was found, the string is unchanged.
+ ///
+ ///
+ ///
+ /// The size of the buffer pointed to by pszPath, in characters.
+ ///
+ ///
+ ///
+ /// A value that, when this function returns successfully, receives the address of a pointer to end of the new string. If the string
+ /// is a root path such as "C:", the pointer points to the backslash; otherwise the pointer points to the string's terminating null character.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to a value that, when this function returns successfully, receives the number of unused characters in the destination
+ /// buffer, including the terminating null character. If the string is a root path such as "C:", this count includes the backslash in
+ /// that string.
+ ///
+ ///
+ ///
+ ///
+ /// This function returns S_OK if the function was successful, S_FALSE if the string was a root path or if no backslash was found, or
+ /// an error code otherwise.
+ ///
+ ///
+ ///
+ /// This function will not remove the backslash from a root path string, such as "C:".
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/pathcch/nf-pathcch-pathcchremovebackslashex HRESULT PathCchRemoveBackslashEx(
+ // PWSTR pszPath, SizeT cchPath, PWSTR *ppszEnd, SizeT *pcchRemaining );
+ [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [PInvokeData("pathcch.h", MSDNShortId = "250c2faa-94bb-42c1-97d4-37f8f59dbde6")]
+ public static extern HRESULT PathCchRemoveBackslashEx(IntPtr pszPath, SizeT cchPath, out IntPtr ppszEnd, out SizeT pcchRemaining);
+
///
/// Removes the file name extension from a path, if one is present.
/// This function differs from PathRemoveExtension in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
@@ -1375,6 +1501,32 @@ namespace Vanara.PInvoke
[PInvokeData("pathcch.h", MSDNShortId = "187bc49e-c5ae-42b8-acbd-a765f871d73b")]
public static extern HRESULT PathCchSkipRoot(string pszPath, out IntPtr ppszRootEnd);
+ ///
+ ///
+ /// Retrieves a pointer to the first character in a path following the drive letter or Universal Naming Convention (UNC) server/share
+ /// path elements.
+ ///
+ /// This function differs from PathSkipRoot in that it accepts paths with "\", "\?" and "\?\UNC" prefixes.
+ ///
+ ///
+ /// A pointer to the path string.
+ ///
+ ///
+ ///
+ /// The address of a pointer that, when this function returns successfully, points to the first character in a path following the
+ /// drive letter or UNC server/share path elements. If the path consists of only a root, this value will point to the string's
+ /// terminating null character.
+ ///
+ ///
+ ///
+ /// If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/pathcch/nf-pathcch-pathcchskiproot HRESULT PathCchSkipRoot( PCWSTR pszPath,
+ // PCWSTR *ppszRootEnd );
+ [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [PInvokeData("pathcch.h", MSDNShortId = "187bc49e-c5ae-42b8-acbd-a765f871d73b")]
+ public static extern HRESULT PathCchSkipRoot(IntPtr pszPath, out IntPtr ppszRootEnd);
+
///
/// Removes the "\?" prefix, if present, from a file path.
///
@@ -1465,6 +1617,29 @@ namespace Vanara.PInvoke
[DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
[PInvokeData("pathcch.h", MSDNShortId = "3b2a4158-63ec-49eb-a031-7493d02f2caa")]
[return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool PathIsUNCEx(string pszPath, ref StringBuilder ppszServer);
+ public static extern bool PathIsUNCEx(string pszPath, out IntPtr ppszServer);
+
+ ///
+ /// Determines if a path string is a valid Universal Naming Convention (UNC) path, as opposed to a path based on a drive letter.
+ /// This function differs from PathIsUNC in that it also allows you to extract the name of the server from the path.
+ ///
+ ///
+ /// A pointer to the path string.
+ ///
+ ///
+ ///
+ /// A pointer to a string that, when this function returns successfully, receives the server portion of the UNC path. This value can
+ /// be NULL if you don't need this information.
+ ///
+ ///
+ ///
+ /// Returns TRUE if the string is a valid UNC path; otherwise, FALSE.
+ ///
+ // https://docs.microsoft.com/en-us/windows/desktop/api/pathcch/nf-pathcch-pathisuncex BOOL PathIsUNCEx( PCWSTR pszPath, PCWSTR
+ // *ppszServer );
+ [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
+ [PInvokeData("pathcch.h", MSDNShortId = "3b2a4158-63ec-49eb-a031-7493d02f2caa")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool PathIsUNCEx(IntPtr pszPath, out IntPtr ppszServer);
}
}
\ No newline at end of file
diff --git a/UnitTests/PInvoke/Kernel32/PathCchTests.cs b/UnitTests/PInvoke/Kernel32/PathCchTests.cs
new file mode 100644
index 00000000..5ea89a0a
--- /dev/null
+++ b/UnitTests/PInvoke/Kernel32/PathCchTests.cs
@@ -0,0 +1,253 @@
+using NUnit.Framework;
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using Vanara.Extensions;
+using Vanara.InteropServices;
+using static Vanara.PInvoke.AdvApi32;
+using static Vanara.PInvoke.Kernel32;
+
+namespace Vanara.PInvoke.Tests
+{
+ [TestFixture]
+ public class PathCchTests
+ {
+ [Test]
+ public void PathAllocCanonicalizeTest()
+ {
+ Assert.That(PathAllocCanonicalize(@"C:\name_1\.\name_2\..\name_3", PATHCCH_OPTIONS.PATHCCH_NONE, out var ret), Is.EqualTo((HRESULT)0));
+ Assert.That(ret, Is.EqualTo(@"C:\name_1\name_3"));
+ }
+
+ [Test]
+ public void LocalStringMarshalerTest()
+ {
+ var originalByteCount = GC.GetTotalMemory(true);
+ for (int i = 0; i < 5000; i++)
+ {
+ PathAllocCanonicalize(@"C:\name_1\.\name_2\..\name_3", PATHCCH_OPTIONS.PATHCCH_NONE, out var ret);
+ Assert.That(ret, Is.EqualTo(@"C:\name_1\name_3"));
+ }
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+ var finalByteCount = GC.GetTotalMemory(true);
+ Assert.That(Math.Abs(finalByteCount - originalByteCount), Is.LessThan(2000));
+ }
+
+ [Test]
+ public void PathAllocCombineTest()
+ {
+ Assert.That(PathAllocCombine(@"C:\name_1\.\name_2\..", @"name_3", PATHCCH_OPTIONS.PATHCCH_NONE, out var ret), Is.EqualTo((HRESULT)0));
+ Assert.That(ret, Is.EqualTo(@"C:\name_1\name_3"));
+ }
+
+ [Test]
+ public void PathCchAddBackslashTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\", 100);
+ Assert.That(PathCchAddBackslash(sb, sb.Capacity), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+
+ sb = new StringBuilder(@"C:\Temp", 100);
+ Assert.That(PathCchAddBackslash(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+ }
+
+ [Test]
+ public void PathCchAddBackslashExTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\", 64);
+ Assert.That(PathCchAddBackslashEx(sb, sb.Capacity, out var end, out var rem), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+ Assert.That(end, Is.Not.EqualTo(IntPtr.Zero));
+ Assert.That(rem, Is.LessThan(60));
+
+ sb = new StringBuilder(@"C:\Temp", 64);
+ Assert.That(PathCchAddBackslashEx(sb, sb.Capacity, out end, out rem), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+ Assert.That(rem, Is.LessThan(60));
+ }
+
+ [Test]
+ public void PathCchAddBackslashExTest2()
+ {
+ var sb = new SafeCoTaskMemString(@"C:\Temp\", 64);
+ Assert.That(PathCchAddBackslashEx((IntPtr)sb, sb.Capacity, out var end, out var rem), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+ Assert.That(end, Is.EqualTo(sb.DangerousGetHandle().Offset(sb.Length * 2)));
+
+ sb = new SafeCoTaskMemString(@"C:\Temp", 64);
+ Assert.That(PathCchAddBackslashEx((IntPtr)sb, sb.Size, out end, out rem), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\"));
+ Assert.That(end, Is.EqualTo(sb.DangerousGetHandle().Offset(sb.Length * 2)));
+ }
+
+ [Test]
+ public void PathCchAddExtensionTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\Dog", 64);
+ Assert.That(PathCchAddExtension(sb, sb.Capacity, "txt"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\Dog.txt"));
+ }
+
+ [Test]
+ public void PathCchAppendTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\Dog", 64);
+ Assert.That(PathCchAppend(sb, sb.Capacity, "txt"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\Dog\txt"));
+ }
+
+ [Test]
+ public void PathCchAppendExTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\Dog", 64);
+ Assert.That(PathCchAppendEx(sb, sb.Capacity, "txt", PATHCCH_OPTIONS.PATHCCH_ENSURE_TRAILING_SLASH), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\Dog\txt\"));
+ }
+
+ [Test]
+ public void PathCchCanonicalizeTest()
+ {
+ var sb = new StringBuilder(64);
+ Assert.That(PathCchCanonicalize(sb, sb.Capacity, @"C:\name_1\.\name_2\..\name_3"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\name_1\name_3"));
+ }
+
+ [Test]
+ public void PathCchCanonicalizeExTest()
+ {
+ var sb = new StringBuilder(64);
+ Assert.That(PathCchCanonicalizeEx(sb, sb.Capacity, @"C:\name_1\.\name_2\..\name_3", PATHCCH_OPTIONS.PATHCCH_ENSURE_TRAILING_SLASH), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\name_1\name_3\"));
+ }
+
+ [Test]
+ public void PathCchCombineTest()
+ {
+ var sb = new StringBuilder(64);
+ Assert.That(PathCchCombine(sb, sb.Capacity, @"C:\name_1\.\name_2\..", @"name_3"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\name_1\name_3"));
+ }
+
+ [Test]
+ public void PathCchCombineExTest()
+ {
+ var sb = new StringBuilder(64);
+ Assert.That(PathCchCombineEx(sb, sb.Capacity, @"C:\name_1\.\name_2\..", @"name_3", PATHCCH_OPTIONS.PATHCCH_ENSURE_TRAILING_SLASH), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\name_1\name_3\"));
+ }
+
+ [Test]
+ public void PathCchFindExtensionTest()
+ {
+ var sb = new SafeCoTaskMemString(@"C:\Temp\dog.txt", 64);
+ Assert.That(PathCchFindExtension((IntPtr)sb, sb.Capacity, out var ptr), Is.EqualTo((HRESULT)0));
+ Assert.That(ptr, Is.EqualTo(sb.DangerousGetHandle().Offset(22)));
+ }
+
+ [Test]
+ public void PathCchIsRootTest()
+ {
+ Assert.That(PathCchIsRoot(@"C:\"), Is.True);
+ }
+
+ [Test]
+ public void PathCchRemoveBackslashTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\", 64);
+ Assert.That(PathCchRemoveBackslash(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp"));
+
+ sb = new StringBuilder(@"C:\Temp", 64);
+ Assert.That(PathCchRemoveBackslash(sb, sb.Capacity), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp"));
+ }
+
+ [Test]
+ public void PathCchRemoveBackslashExTest()
+ {
+ var sb = new SafeCoTaskMemString(@"C:\Temp\", 64);
+ Assert.That(PathCchRemoveBackslashEx((IntPtr)sb, sb.Capacity, out var end, out var rem), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp"));
+ Assert.That(end, Is.EqualTo(sb.DangerousGetHandle().Offset(14)));
+
+ sb = new SafeCoTaskMemString(@"C:\Temp", 64);
+ Assert.That(PathCchRemoveBackslashEx((IntPtr)sb, sb.Capacity, out end, out rem), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp"));
+ Assert.That(end, Is.EqualTo(sb.DangerousGetHandle().Offset(14)));
+ }
+
+ [Test]
+ public void PathCchRemoveExtensionTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\dog.txt", 64);
+ Assert.That(PathCchRemoveExtension(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\dog"));
+
+ sb = new StringBuilder(@"C:\Temp\dog", 64);
+ Assert.That(PathCchRemoveExtension(sb, sb.Capacity), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\dog"));
+ }
+
+ [Test]
+ public void PathCchRemoveFileSpecTest()
+ {
+ var sb = new StringBuilder(@"C:\foo\bar.txt", 64);
+ Assert.That(PathCchRemoveFileSpec(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\foo"));
+ }
+
+ [Test]
+ public void PathCchRenameExtensionTest()
+ {
+ var sb = new StringBuilder(@"C:\Temp\dog.txt", 64);
+ Assert.That(PathCchRenameExtension(sb, sb.Capacity, "doc"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\dog.doc"));
+
+ sb = new StringBuilder(@"C:\Temp\dog", 64);
+ Assert.That(PathCchRenameExtension(sb, sb.Capacity, "txt"), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\Temp\dog.txt"));
+ }
+
+ [Test]
+ public void PathCchSkipRootTest()
+ {
+ var sb = new SafeCoTaskMemString(@"C:\Temp\", 64);
+ Assert.That(PathCchSkipRoot((IntPtr)sb, out var end), Is.EqualTo((HRESULT)0));
+ Assert.That(end, Is.EqualTo(sb.DangerousGetHandle().Offset(6)));
+ }
+
+ [Test]
+ public void PathCchStripPrefixTest()
+ {
+ var sb = new StringBuilder(@"\\?\C:\foo\bar.txt", 64);
+ Assert.That(PathCchStripPrefix(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\foo\bar.txt"));
+
+ sb = new StringBuilder(@"C:\foo\bar.txt", 64);
+ Assert.That(PathCchStripPrefix(sb, sb.Capacity), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\foo\bar.txt"));
+ }
+
+ [Test]
+ public void PathCchStripToRootTest()
+ {
+ var sb = new StringBuilder(@"C:\foo\bar.txt", 64);
+ Assert.That(PathCchStripToRoot(sb, sb.Capacity), Is.EqualTo((HRESULT)0));
+ Assert.That(sb.ToString(), Is.EqualTo(@"C:\"));
+
+ sb = new StringBuilder(@"\\path1\path2", 64);
+ Assert.That(PathCchStripToRoot(sb, sb.Capacity), Is.EqualTo((HRESULT)HRESULT.S_FALSE));
+ Assert.That(sb.ToString(), Is.EqualTo(@"\\path1\path2"));
+ }
+
+ [Test]
+ public void PathIsUNCExTest()
+ {
+ Assert.That(PathIsUNCEx(@"\\path1\path2\path3", out var svr), Is.True);
+ Assert.That(Marshal.PtrToStringUni(svr), Is.EqualTo(@"path1\path2\path3"));
+ }
+ }
+}
\ No newline at end of file