mirror of https://github.com/dahall/Vanara.git
* Derived SafeCoTaskMemString from base class SafeMemString derived from SafeMemHandle<T>.
* BREAKING CHANGE: Removed CharCapacity and made Capacity show char allocation. Size (from parent) shows byte capacity. Mimics StringBuilder.pull/60/head
parent
f4110f89d5
commit
7ce7b96209
|
@ -11,13 +11,14 @@ namespace Vanara.Extensions
|
|||
{
|
||||
/// <summary>Allocates a block of memory allocated from the unmanaged COM task allocator sufficient to hold the number of specified characters.</summary>
|
||||
/// <param name="count">The number of characters, inclusive of the null terminator.</param>
|
||||
/// <param name="memAllocator">The method used to allocate the memory.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <returns>The address of the block of memory allocated.</returns>
|
||||
public static IntPtr AllocChars(uint count, CharSet charSet = CharSet.Auto)
|
||||
public static IntPtr AllocChars(uint count, Func<int, IntPtr> memAllocator, CharSet charSet = CharSet.Auto)
|
||||
{
|
||||
if (count == 0) return IntPtr.Zero;
|
||||
var sz = GetCharSize(charSet);
|
||||
var ptr = Marshal.AllocCoTaskMem((int)count * sz);
|
||||
var ptr = memAllocator((int)count * sz);
|
||||
if (count > 0)
|
||||
{
|
||||
if (sz == 1)
|
||||
|
@ -28,6 +29,12 @@ namespace Vanara.Extensions
|
|||
return ptr;
|
||||
}
|
||||
|
||||
/// <summary>Allocates a block of memory allocated from the unmanaged COM task allocator sufficient to hold the number of specified characters.</summary>
|
||||
/// <param name="count">The number of characters, inclusive of the null terminator.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <returns>The address of the block of memory allocated.</returns>
|
||||
public static IntPtr AllocChars(uint count, CharSet charSet = CharSet.Auto) => AllocChars(count, Marshal.AllocCoTaskMem, charSet);
|
||||
|
||||
/// <summary>Copies the contents of a managed <see cref="SecureString"/> object to a block of memory allocated from the unmanaged COM task allocator.</summary>
|
||||
/// <param name="s">The managed object to copy.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
|
@ -45,10 +52,19 @@ namespace Vanara.Extensions
|
|||
/// <param name="charSet">The character set.</param>
|
||||
/// <param name="memAllocator">The method used to allocate the memory.</param>
|
||||
/// <returns>The address, in unmanaged memory, where the <paramref name="s"/> parameter was copied to, or 0 if a null object was supplied.</returns>
|
||||
public static IntPtr AllocSecureString(SecureString s, CharSet charSet, Func<int, IntPtr> memAllocator)
|
||||
public static IntPtr AllocSecureString(SecureString s, CharSet charSet, Func<int, IntPtr> memAllocator) => AllocSecureString(s, charSet, memAllocator, out _);
|
||||
|
||||
/// <summary>Copies the contents of a managed <see cref="SecureString"/> object to a block of memory allocated from a supplied allocation method.</summary>
|
||||
/// <param name="s">The managed object to copy.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <param name="memAllocator">The method used to allocate the memory.</param>
|
||||
/// <param name="allocatedBytes">Returns the number of allocated bytes for the string.</param>
|
||||
/// <returns>The address, in unmanaged memory, where the <paramref name="s"/> parameter was copied to, or 0 if a null object was supplied.</returns>
|
||||
public static IntPtr AllocSecureString(SecureString s, CharSet charSet, Func<int, IntPtr> memAllocator, out int allocatedBytes)
|
||||
{
|
||||
allocatedBytes = 0;
|
||||
if (s == null) return IntPtr.Zero;
|
||||
var chSz = StringHelper.GetCharSize(charSet);
|
||||
var chSz = GetCharSize(charSet);
|
||||
var encoding = chSz == 2 ? System.Text.Encoding.Unicode : System.Text.Encoding.ASCII;
|
||||
var hMem = AllocSecureString(s, charSet);
|
||||
var str = chSz == 2 ? Marshal.PtrToStringUni(hMem) : Marshal.PtrToStringAnsi(hMem);
|
||||
|
@ -57,6 +73,7 @@ namespace Vanara.Extensions
|
|||
var b = encoding.GetBytes(str);
|
||||
var p = memAllocator(b.Length);
|
||||
Marshal.Copy(b, 0, p, b.Length);
|
||||
allocatedBytes = b.Length;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,96 +1,53 @@
|
|||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Vanara.Extensions;
|
||||
|
||||
namespace Vanara.InteropServices
|
||||
{
|
||||
/// <summary>Safely handles an unmanaged memory allocated Unicode string.</summary>
|
||||
/// <seealso cref="Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid"/>
|
||||
public class SafeCoTaskMemString : SafeHandleZeroOrMinusOneIsInvalid
|
||||
public class SafeCoTaskMemString : SafeMemString<CoTaskMemoryMethods>
|
||||
{
|
||||
private readonly CharSet chSet = CharSet.Unicode;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeCoTaskMemString"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <param name="ownsHandle"><c>true</c> to reliably release the handle during finalization; <c>false</c> to prevent it.</param>
|
||||
public SafeCoTaskMemString(string s, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : this(StringHelper.AllocString(s, charSet), charSet, ownsHandle)
|
||||
public SafeCoTaskMemString(string s, CharSet charSet = CharSet.Unicode) : base(s, charSet)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeCoTaskMemString"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="capacity">The size of the buffer in characters.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
public SafeCoTaskMemString(string s, int capacity, CharSet charSet = CharSet.Unicode) : base(s, capacity, charSet)
|
||||
{
|
||||
Capacity = StringHelper.GetByteCount(s, true, charSet);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeCoTaskMemString"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
public SafeCoTaskMemString(SecureString s, CharSet charSet = CharSet.Unicode) : this(StringHelper.AllocSecureString(s, charSet), charSet)
|
||||
public SafeCoTaskMemString(SecureString s, CharSet charSet = CharSet.Unicode) : base(s, charSet)
|
||||
{
|
||||
Capacity = s == null ? 0 : StringHelper.GetCharSize(charSet) * (s.Length + 1);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeCoTaskMemString"/> class.</summary>
|
||||
/// <param name="charLen">The size of the buffer in characters, including the null character terminator.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
public SafeCoTaskMemString(int charLen, CharSet charSet = CharSet.Unicode) : this(StringHelper.AllocChars((uint)charLen, charSet), charSet)
|
||||
public SafeCoTaskMemString(int charLen, CharSet charSet = CharSet.Unicode) : base(charLen, charSet)
|
||||
{
|
||||
Capacity = charLen * StringHelper.GetCharSize(charSet);
|
||||
}
|
||||
|
||||
/// <summary>Prevents a default instance of the <see cref="SafeCoTaskMemString"/> class from being created.</summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
private SafeCoTaskMemString() : base(true) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeCoTaskMemString"/> class.</summary>
|
||||
/// <param name="ptr">The PTR.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <param name="ownsHandle"><c>true</c> to reliably release the handle during finalization; <c>false</c> to prevent it.</param>
|
||||
[ExcludeFromCodeCoverage]
|
||||
private SafeCoTaskMemString(IntPtr ptr, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : base(ownsHandle)
|
||||
private SafeCoTaskMemString(IntPtr ptr, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : base(ptr, charSet, ownsHandle)
|
||||
{
|
||||
chSet = charSet;
|
||||
SetHandle(ptr);
|
||||
}
|
||||
|
||||
/// <summary>Represents a <c>null</c> value. Used primarily for comparrison.</summary>
|
||||
/// <value>A null value.</value>
|
||||
public static SafeCoTaskMemString Null => new SafeCoTaskMemString(IntPtr.Zero, CharSet.Unicode, false);
|
||||
|
||||
/// <summary>Gets the number of allocated bytes or -1 if the size is unknown (for example if it is holding a <see cref="SecureString"/>.</summary>
|
||||
/// <value>The number of allocated bytes.</value>
|
||||
public int Capacity { get; } = -1;
|
||||
|
||||
/// <summary>Gets the number of allocated characters or -1 if the size is unknown (for example if it is holding a <see cref="SecureString"/>.</summary>
|
||||
/// <value>The number of characters bytes.</value>
|
||||
public int CharCapacity => Capacity == -1 ? -1 : Capacity / StringHelper.GetCharSize(chSet);
|
||||
|
||||
/// <summary>Returns the value of the <see cref="SafeHandle.handle"/> field.</summary>
|
||||
/// <param name="s">The <see cref="SafeCoTaskMemString"/> instance.</param>
|
||||
/// <returns>
|
||||
/// An <see cref="IntPtr"/> representing the value of the handle field. If the handle has been marked invalid with
|
||||
/// <see cref="SafeHandle.SetHandleAsInvalid"/>, this method still returns the original handle value, which can be a stale value.
|
||||
/// </returns>
|
||||
public static explicit operator IntPtr(SafeCoTaskMemString s) => s.DangerousGetHandle();
|
||||
|
||||
/// <summary>Returns the string value held by a <see cref="SafeCoTaskMemString"/>.</summary>
|
||||
/// <param name="s">The <see cref="SafeCoTaskMemString"/> instance.</param>
|
||||
/// <returns>A <see cref="System.String"/> value held by the <see cref="SafeCoTaskMemString"/> or <c>null</c> if the handle or value is invalid.</returns>
|
||||
public static implicit operator string(SafeCoTaskMemString s) => s?.ToString();
|
||||
|
||||
/// <summary>Returns the string value held by this instance.</summary>
|
||||
/// <returns>A <see cref="System.String"/> value held by this instance or <c>null</c> if the handle is invalid.</returns>
|
||||
public override string ToString() => IsInvalid ? null : StringHelper.GetString(handle, chSet);
|
||||
|
||||
/// <summary>When overridden in a derived class, executes the code required to free the handle.</summary>
|
||||
/// <returns>
|
||||
/// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a
|
||||
/// releaseHandleFailed MDA Managed Debugging Assistant.
|
||||
/// </returns>
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
StringHelper.FreeString(handle, chSet);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Vanara.Extensions;
|
||||
|
||||
namespace Vanara.InteropServices
|
||||
{
|
||||
/// <summary>Base abstract class for a string handler based on <see cref="SafeMemoryHandle{TMem}"/>.</summary>
|
||||
/// <typeparam name="TMem">The type of the memory.</typeparam>
|
||||
/// <seealso cref="Vanara.InteropServices.SafeMemoryHandle{TMem}"/>
|
||||
public abstract class SafeMemString<TMem> : SafeMemoryHandle<TMem> where TMem : IMemoryMethods, new()
|
||||
{
|
||||
private readonly CharSet chSet = CharSet.Unicode;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
protected SafeMemString(string s, CharSet charSet = CharSet.Unicode) : this(s, s is null ? 0 : s.Length + 1, charSet)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="capacity">The capacity of the buffer, in characters.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
protected SafeMemString(string s, int capacity, CharSet charSet = CharSet.Unicode) : this(capacity, charSet)
|
||||
{
|
||||
StringHelper.Write(s, handle, out _, true, charSet, Size);
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
|
||||
/// <param name="s">The string value.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
protected SafeMemString(SecureString s, CharSet charSet = CharSet.Unicode) : this(IntPtr.Zero, charSet)
|
||||
{
|
||||
SetHandle(StringHelper.AllocSecureString(s, charSet, mm.AllocMem, out var sz));
|
||||
base.sz = sz;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
|
||||
/// <param name="charLen">The size of the buffer in characters, including the null character terminator.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
protected SafeMemString(int charLen, CharSet charSet = CharSet.Unicode) : base(charLen * StringHelper.GetCharSize(charSet))
|
||||
{
|
||||
chSet = charSet;
|
||||
}
|
||||
|
||||
/// <summary>Prevents a default instance of the <see cref="SafeMemString{TMem}"/> class from being created.</summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
protected SafeMemString() : base(0) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMemString{TMem}"/> class.</summary>
|
||||
/// <param name="ptr">The PTR.</param>
|
||||
/// <param name="charSet">The character set.</param>
|
||||
/// <param name="ownsHandle"><c>true</c> to reliably release the handle during finalization; <c>false</c> to prevent it.</param>
|
||||
[ExcludeFromCodeCoverage]
|
||||
protected SafeMemString(IntPtr ptr, CharSet charSet = CharSet.Unicode, bool ownsHandle = true) : base(ptr, 0, ownsHandle)
|
||||
{
|
||||
chSet = charSet;
|
||||
}
|
||||
|
||||
/// <summary>Gets the number of allocated characters or 0 if the size is unknown (for example if it is holding a <see cref="SecureString"/>.</summary>
|
||||
/// <value>The number of allocated characters.</value>
|
||||
public int Capacity => Size / StringHelper.GetCharSize(chSet);
|
||||
|
||||
/// <summary>Gets the number of characters in the current <see cref="SafeMemString{TMem}"/> object.</summary>
|
||||
public int Length => ToString().Length;
|
||||
|
||||
/// <summary>Returns the value of the <see cref="SafeHandle.handle"/> field.</summary>
|
||||
/// <param name="s">The <see cref="SafeMemString{TMem}"/> instance.</param>
|
||||
/// <returns>
|
||||
/// An <see cref="IntPtr"/> representing the value of the handle field. If the handle has been marked invalid with
|
||||
/// <see cref="SafeHandle.SetHandleAsInvalid"/>, this method still returns the original handle value, which can be a stale value.
|
||||
/// </returns>
|
||||
public static explicit operator IntPtr(SafeMemString<TMem> s) => s.DangerousGetHandle();
|
||||
|
||||
/// <summary>Returns the string value held by a <see cref="SafeMemString{TMem}"/>.</summary>
|
||||
/// <param name="s">The <see cref="SafeMemString{TMem}"/> instance.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> value held by the <see cref="SafeMemString{TMem}"/> or <c>null</c> if the handle or value is invalid.
|
||||
/// </returns>
|
||||
public static implicit operator string(SafeMemString<TMem> s) => s?.ToString();
|
||||
|
||||
/// <summary>Returns the string value held by this instance.</summary>
|
||||
/// <returns>A <see cref="System.String"/> value held by this instance or <c>null</c> if the handle is invalid.</returns>
|
||||
public override string ToString() => IsInvalid ? null : StringHelper.GetString(handle, chSet, Size);
|
||||
}
|
||||
}
|
|
@ -69,9 +69,9 @@ namespace Vanara.Security
|
|||
var pUserName = new SafeCoTaskMemString(CRED_MAX_USERNAME_LENGTH);
|
||||
var pDomainName = new SafeCoTaskMemString(CRED_MAX_USERNAME_LENGTH);
|
||||
var pPassword = new SafeCoTaskMemString(CREDUI_MAX_PASSWORD_LENGTH);
|
||||
var userNameSize = pUserName.CharCapacity;
|
||||
var domainNameSize = pDomainName.CharCapacity;
|
||||
var passwordSize = pPassword.CharCapacity;
|
||||
var userNameSize = pUserName.Capacity;
|
||||
var domainNameSize = pDomainName.Capacity;
|
||||
var passwordSize = pPassword.Capacity;
|
||||
|
||||
if (!CredUnPackAuthenticationBuffer(decryptProtectedCredentials ? CredPackFlags.CRED_PACK_PROTECTED_CREDENTIALS : 0x0, DangerousHandle, Size,
|
||||
(IntPtr)pUserName, ref userNameSize, (IntPtr)pDomainName, ref domainNameSize, (IntPtr)pPassword, ref passwordSize))
|
||||
|
|
|
@ -849,12 +849,12 @@ namespace Vanara.Windows.Shell
|
|||
var result = new StringBuilder(512);
|
||||
if (!SHGetPathFromIDList(PIDL, result))
|
||||
throw new ArgumentException();
|
||||
return new SafeCoTaskMemString(result.ToString(), CharSet.Unicode, false);
|
||||
return new SafeCoTaskMemString(result.ToString(), CharSet.Unicode);
|
||||
}
|
||||
|
||||
var parentFolder = InternalGetParent().GetIShellFolder();
|
||||
var child = PIDL.LastId;
|
||||
return new SafeCoTaskMemString(parentFolder.GetDisplayNameOf(child, (SHGDNF)((int)sigdnName & 0xffff)), CharSet.Unicode, false);
|
||||
return new SafeCoTaskMemString(parentFolder.GetDisplayNameOf(child, (SHGDNF)((int)sigdnName & 0xffff)), CharSet.Unicode);
|
||||
}
|
||||
|
||||
public IShellItem GetParent()
|
||||
|
|
Loading…
Reference in New Issue