diff --git a/PInvoke/Shared/Handles/HANDLE.cs b/PInvoke/Shared/Handles/HANDLE.cs
index 73d47b8e..8835f97b 100644
--- a/PInvoke/Shared/Handles/HANDLE.cs
+++ b/PInvoke/Shared/Handles/HANDLE.cs
@@ -1,10 +1,11 @@
using Microsoft.Win32.SafeHandles;
+using System.ComponentModel;
using System.Diagnostics;
namespace Vanara.PInvoke;
/// Provides a handle to an accelerator table.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HACCEL : IUserHandle
{
private readonly IntPtr handle;
@@ -57,7 +58,7 @@ public readonly struct HACCEL : IUserHandle
}
/// Provides a generic handle.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HANDLE : IHandle
{
private readonly IntPtr handle;
@@ -115,7 +116,7 @@ public readonly struct HANDLE : IHandle
}
/// Provides a handle to a bitmap.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HBITMAP : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -173,7 +174,7 @@ public readonly struct HBITMAP : IGraphicsObjectHandle
}
/// Provides a handle to drawing brush.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HBRUSH : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -231,7 +232,7 @@ public readonly struct HBRUSH : IGraphicsObjectHandle
}
/// Provides a handle to a color space.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HCOLORSPACE : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -289,7 +290,7 @@ public readonly struct HCOLORSPACE : IGraphicsObjectHandle
}
/// Provides a handle to cursor.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HCURSOR : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -347,7 +348,7 @@ public readonly struct HCURSOR : IGraphicsObjectHandle
}
/// Provides a handle to a graphic device context.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDC : IHandle
{
private readonly IntPtr handle;
@@ -400,7 +401,7 @@ public readonly struct HDC : IHandle
}
/// Provides a handle to a desktop.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDESK : IKernelHandle
{
private readonly IntPtr handle;
@@ -453,7 +454,7 @@ public readonly struct HDESK : IKernelHandle
}
/// Provides a handle to a DPA.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDPA : IKernelHandle
{
private readonly IntPtr handle;
@@ -506,7 +507,7 @@ public readonly struct HDPA : IKernelHandle
}
/// Provides a handle to a Windows drop operation.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDROP : IShellHandle
{
private readonly IntPtr handle;
@@ -559,7 +560,7 @@ public readonly struct HDROP : IShellHandle
}
/// Provides a handle to a DSA.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDSA : IKernelHandle
{
private readonly IntPtr handle;
@@ -612,7 +613,7 @@ public readonly struct HDSA : IKernelHandle
}
/// Provides a handle to a deferred windows position.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HDWP : IUserHandle
{
private readonly IntPtr handle;
@@ -665,7 +666,7 @@ public readonly struct HDWP : IUserHandle
}
/// Provides a handle to an enhanced metafile.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HENHMETAFILE : IHandle
{
private readonly IntPtr handle;
@@ -718,7 +719,7 @@ public readonly struct HENHMETAFILE : IHandle
}
/// Provides a handle to a sync event.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HEVENT : ISyncHandle
{
private readonly IntPtr handle;
@@ -771,7 +772,7 @@ public readonly struct HEVENT : ISyncHandle
}
/// Provides a handle to a file.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HFILE : ISyncHandle
{
private readonly IntPtr handle;
@@ -835,7 +836,7 @@ public readonly struct HFILE : ISyncHandle
}
/// Provides a handle to a font.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HFONT : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -893,7 +894,7 @@ public readonly struct HFONT : IGraphicsObjectHandle
}
/// Provides a handle to a graphic device object.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HGDIOBJ : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -986,7 +987,7 @@ public readonly struct HGDIOBJ : IGraphicsObjectHandle
}
/// Provides a handle to an icon.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HICON : IUserHandle
{
private readonly IntPtr handle;
@@ -1039,7 +1040,7 @@ public readonly struct HICON : IUserHandle
}
/// Provides a handle to a Windows image list.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HIMAGELIST : IShellHandle
{
private readonly IntPtr handle;
@@ -1092,7 +1093,7 @@ public readonly struct HIMAGELIST : IShellHandle
}
/// Provides a handle to a module or library instance.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HINSTANCE : IKernelHandle
{
private readonly IntPtr handle;
@@ -1145,7 +1146,7 @@ public readonly struct HINSTANCE : IKernelHandle
}
/// Provides a handle to a Windows registry key.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HKEY : IKernelHandle
{
private readonly IntPtr handle;
@@ -1250,7 +1251,7 @@ public readonly struct HKEY : IKernelHandle
}
/// Provides a handle to a menu.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HMENU : IUserHandle
{
private readonly IntPtr handle;
@@ -1303,7 +1304,7 @@ public readonly struct HMENU : IUserHandle
}
/// Provides a handle to a metafile.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HMETAFILE : IHandle
{
private readonly IntPtr handle;
@@ -1356,7 +1357,7 @@ public readonly struct HMETAFILE : IHandle
}
/// Provides a handle to a monitor.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HMONITOR : IKernelHandle
{
private readonly IntPtr handle;
@@ -1409,7 +1410,7 @@ public readonly struct HMONITOR : IKernelHandle
}
/// Provides a handle to a palette.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HPALETTE : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -1467,7 +1468,7 @@ public readonly struct HPALETTE : IGraphicsObjectHandle
}
/// Provides a handle to a drawing pen.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HPEN : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -1525,7 +1526,7 @@ public readonly struct HPEN : IGraphicsObjectHandle
}
/// Provides a handle to a process.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HPROCESS : ISyncHandle
{
private readonly IntPtr handle;
@@ -1583,7 +1584,7 @@ public readonly struct HPROCESS : ISyncHandle
}
/// Provides a handle to a Windows property sheet.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HPROPSHEET : IUserHandle
{
private readonly IntPtr handle;
@@ -1636,7 +1637,7 @@ public readonly struct HPROPSHEET : IUserHandle
}
/// Provides a handle to a property sheet page.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HPROPSHEETPAGE : IUserHandle
{
private readonly IntPtr handle;
@@ -1689,7 +1690,7 @@ public readonly struct HPROPSHEETPAGE : IUserHandle
}
/// Provides a handle to a drawing region.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HRGN : IGraphicsObjectHandle
{
private readonly IntPtr handle;
@@ -1747,7 +1748,7 @@ public readonly struct HRGN : IGraphicsObjectHandle
}
/// Provides a handle to a file mapping object.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HSECTION : IHandle
{
private readonly IntPtr handle;
@@ -1800,7 +1801,7 @@ public readonly struct HSECTION : IHandle
}
/// Provides a handle to a blocking task.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HTASK : IHandle
{
private readonly IntPtr handle;
@@ -1853,7 +1854,7 @@ public readonly struct HTASK : IHandle
}
/// Provides a handle to a Windows theme.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HTHEME : IHandle
{
private readonly IntPtr handle;
@@ -1906,7 +1907,7 @@ public readonly struct HTHEME : IHandle
}
/// Provides a handle to a thread.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HTHREAD : ISyncHandle
{
private readonly IntPtr handle;
@@ -1959,7 +1960,7 @@ public readonly struct HTHREAD : ISyncHandle
}
/// Provides a handle to a Windows thumbnail.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HTHUMBNAIL : IShellHandle
{
private readonly IntPtr handle;
@@ -2012,7 +2013,7 @@ public readonly struct HTHUMBNAIL : IShellHandle
}
/// Provides a handle to an access token.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HTOKEN : IKernelHandle
{
private readonly IntPtr handle;
@@ -2065,7 +2066,7 @@ public readonly struct HTOKEN : IKernelHandle
}
/// Provides a handle to a windows station.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HWINSTA : IKernelHandle
{
private readonly IntPtr handle;
@@ -2118,7 +2119,7 @@ public readonly struct HWINSTA : IKernelHandle
}
/// Provides a handle to a window or dialog.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct HWND : IUserHandle
{
private readonly IntPtr handle;
@@ -2198,7 +2199,7 @@ public readonly struct HWND : IUserHandle
}
/// Provides a pointer to an access control entry.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct PACE : ISecurityObject
{
private readonly IntPtr handle;
@@ -2251,7 +2252,7 @@ public readonly struct PACE : ISecurityObject
}
/// Provides a handle to an access control list.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct PACL : ISecurityObject
{
private readonly IntPtr handle;
@@ -2304,7 +2305,7 @@ public readonly struct PACL : ISecurityObject
}
/// Provides a handle to a security descriptor.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct PSECURITY_DESCRIPTOR : ISecurityObject
{
private readonly IntPtr handle;
@@ -2357,7 +2358,7 @@ public readonly struct PSECURITY_DESCRIPTOR : ISecurityObject
}
/// Provides a handle to a security identifier.
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct PSID : ISecurityObject
{
private readonly IntPtr handle;
diff --git a/PInvoke/Shared/Handles/HANDLE.tt b/PInvoke/Shared/Handles/HANDLE.tt
index fc6e728e..c7ac7ccb 100644
--- a/PInvoke/Shared/Handles/HANDLE.tt
+++ b/PInvoke/Shared/Handles/HANDLE.tt
@@ -54,13 +54,14 @@
{ "HPROCESS", ("HPROCESS", "Process", "h.Handle" ) },
}; #>
using Microsoft.Win32.SafeHandles;
+using System.ComponentModel;
using System.Diagnostics;
namespace Vanara.PInvoke;
<# foreach (var (name, inheritance, summaryText) in classes) { #>
/// <#= summaryText #>
-[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
+[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}"), TypeConverter(typeof(HANDLEConverter))]
public readonly struct <#= name #> : <#= inheritance #>
{
private readonly IntPtr handle;
diff --git a/PInvoke/Shared/Handles/HANDLEConverter.cs b/PInvoke/Shared/Handles/HANDLEConverter.cs
new file mode 100644
index 00000000..0eb150e9
--- /dev/null
+++ b/PInvoke/Shared/Handles/HANDLEConverter.cs
@@ -0,0 +1,41 @@
+using System.ComponentModel;
+using System.Globalization;
+using Vanara.Extensions.Reflection;
+
+namespace Vanara.PInvoke;
+
+/// Converts a handle to a string or an integer and vice versa. The string representation is the handle value as an integer.
+///
+public class HANDLEConverter : TypeConverter
+{
+ ///
+ public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => sourceType == typeof(string) || sourceType == typeof(int) ||
+ sourceType == typeof(int) || sourceType.InheritsFrom() || base.CanConvertFrom(context, sourceType);
+
+ ///
+ public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) => value switch
+ {
+ null => IntPtr.Zero,
+ string s => s.ToLower(culture).Trim() == "null" ? IntPtr.Zero : new IntPtr(long.Parse(s)),
+ int i => new IntPtr(i),
+ IHandle h => h.DangerousGetHandle(),
+ _ => base.ConvertFrom(context, culture, value)
+ };
+
+ ///
+ public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
+ {
+ value ??= HANDLE.NULL;
+ if (destinationType == typeof(string))
+ {
+ if (value is IHandle h)
+ return SVal(h.DangerousGetHandle().ToInt64());
+ if (value is IConvertible c)
+ return SVal(c.ToInt64(culture));
+ try { return SVal(((IntPtr)value).ToInt64()); } catch { }
+ }
+ return base.ConvertTo(context, culture, value, destinationType);
+
+ static string SVal(long v) => v == 0 ? "NULL" : v.ToString();
+ }
+}
\ No newline at end of file