Refactored base handle structures into templates

pull/328/head
dahall 2022-07-21 09:20:46 -06:00
parent 660215dc19
commit 677081358a
5 changed files with 2811 additions and 2283 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<# var classes = new List<(string name, string inheritance, string summaryText)> {
( "HACCEL", "IUserHandle", "Provides a handle to an accelerator table." ),
( "HANDLE", "IHandle", "Provides a generic handle." ),
( "HBITMAP", "IGraphicsObjectHandle", "Provides a handle to a bitmap." ),
( "HBRUSH", "IGraphicsObjectHandle", "Provides a handle to drawing brush." ),
( "HCOLORSPACE", "IGraphicsObjectHandle", "Provides a handle to a color space." ),
( "HCURSOR", "IGraphicsObjectHandle", "Provides a handle to cursor." ),
( "HDC", "IHandle", "Provides a handle to a graphic device context." ),
( "HDESK", "IKernelHandle", "Provides a handle to a desktop." ),
( "HDPA", "IKernelHandle", "Provides a handle to a DPA." ),
( "HDROP", "IShellHandle", "Provides a handle to a Windows drop operation." ),
( "HDSA", "IKernelHandle", "Provides a handle to a DSA." ),
( "HDWP", "IUserHandle", "Provides a handle to a deferred windows position." ),
( "HENHMETAFILE", "IHandle", "Provides a handle to an enhanced metafile." ),
( "HEVENT", "ISyncHandle", "Provides a handle to a sync event." ),
( "HFILE", "ISyncHandle", "Provides a handle to a file." ),
( "HFONT", "IGraphicsObjectHandle", "Provides a handle to a font." ),
( "HGDIOBJ", "IGraphicsObjectHandle", "Provides a handle to a graphic device object." ), // implicit ops from other handles
( "HICON", "IUserHandle", "Provides a handle to an icon." ),
( "HIMAGELIST", "IShellHandle", "Provides a handle to a Windows image list." ),
( "HINSTANCE", "IKernelHandle", "Provides a handle to a module or library instance." ),
( "HKEY", "IKernelHandle", "Provides a handle to a Windows registry key." ),
( "HMENU", "IUserHandle", "Provides a handle to a menu." ),
( "HMETAFILE", "IHandle", "Provides a handle to a metafile." ),
( "HMONITOR", "IKernelHandle", "Provides a handle to a monitor." ),
( "HPALETTE", "IGraphicsObjectHandle", "Provides a handle to a palette." ),
( "HPEN", "IGraphicsObjectHandle", "Provides a handle to a drawing pen." ),
( "HPROCESS", "ISyncHandle", "Provides a handle to a process." ), // implicit Process
( "HPROPSHEET", "IUserHandle", "Provides a handle to a Windows property sheet." ),
( "HPROPSHEETPAGE", "IUserHandle", "Provides a handle to a property sheet page." ),
( "HRGN", "IGraphicsObjectHandle", "Provides a handle to a drawing region." ),
( "HSECTION", "IHandle", "Provides a handle to a file mapping object." ),
( "HTASK", "IHandle", "Provides a handle to a blocking task." ),
( "HTHEME", "IHandle", "Provides a handle to a Windows theme." ),
( "HTHREAD", "ISyncHandle", "Provides a handle to a thread." ),
( "HTHUMBNAIL", "IShellHandle", "Provides a handle to a Windows thumbnail." ),
( "HTOKEN", "IKernelHandle", "Provides a handle to an access token." ),
( "HWINSTA", "IKernelHandle", "Provides a handle to a windows station." ),
( "HWND", "IUserHandle", "Provides a handle to a window or dialog." ), // constants
( "PACE", "ISecurityObject", "Provides a pointer to an access control entry." ),
( "PACL", "ISecurityObject", "Provides a handle to an access control list." ),
( "PSECURITY_DESCRIPTOR", "ISecurityObject", "Provides a handle to a security descriptor." ),
( "PSID", "ISecurityObject", "Provides a handle to a security identifier." ),
}; #>
<# var casts = new Dictionary<string, (string, string, string)> {
{ "HANDLE", ("HANDLE", "SafeHandle", "h.DangerousGetHandle()" ) },
{ "HKEY", ("HKEY", "SafeRegistryHandle", "h.DangerousGetHandle()" ) },
{ "HPROCESS", ("HPROCESS", "Process", "h.Handle" ) },
}; #>
using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Vanara.PInvoke;
<# foreach (var (name, inheritance, summaryText) in classes) { #>
/// <summary><#= summaryText #></summary>
[StructLayout(LayoutKind.Sequential), DebuggerDisplay("{handle}")]
public struct <#= name #> : <#= inheritance #>
{
private readonly IntPtr handle;
/// <summary>Initializes a new instance of the <see cref="<#= name #>"/> struct.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
public <#= name #>(IntPtr preexistingHandle) => handle = preexistingHandle;
/// <summary>Returns an invalid handle by instantiating a <see cref="<#= name #>"/> object with <see cref="IntPtr.Zero"/>.</summary>
public static <#= name #> NULL => new(IntPtr.Zero);
/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
public bool IsNull => handle == IntPtr.Zero;
<# if (name == "HFILE") { #>
/// <summary>Represents an invalid handle.</summary>
public static readonly HFILE INVALID_HANDLE_VALUE = new IntPtr(-1);
/// <summary>Gets a value indicating whether this instance is an invalid handle (INVALID_HANDLE_VALUE).</summary>
public bool IsInvalid => handle == INVALID_HANDLE_VALUE;
/// <summary>Performs an implicit conversion from <see cref="SafeFileHandle"/> to <see cref="HFILE"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator HFILE(SafeFileHandle h) => new(h?.DangerousGetHandle() ?? IntPtr.Zero);
<# } #>
<# if (name == "HWND") { #>
/// <summary>
/// Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost
/// status and is placed at the bottom of all other windows.
/// </summary>
public static HWND HWND_BOTTOM = new IntPtr(1);
/// <summary>
/// Used by <c>SendMessage</c> and <c>PostMessage</c> to send a message to all top-level windows in the system, including disabled or
/// invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
/// </summary>
public static HWND HWND_BROADCAST = new IntPtr(0xffff);
/// <summary>Use as parent in CreateWindow or CreateWindowEx call to indicate a message-only window.</summary>
public static HWND HWND_MESSAGE = new IntPtr(-3);
/// <summary>
/// Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is
/// already a non-topmost window.
/// </summary>
public static HWND HWND_NOTOPMOST = new IntPtr(-2);
/// <summary>Places the window at the top of the Z order.</summary>
public static HWND HWND_TOP = new IntPtr(0);
/// <summary>Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.</summary>
public static HWND HWND_TOPMOST = new IntPtr(-1);
<# } #>
<# if (name == "HKEY") { #>
/// <summary>
/// Registry entries subordinate to this key define types (or classes) of documents and the properties associated with those types.
/// Shell and COM applications use the information stored under this key.
/// </summary>
public static readonly HKEY HKEY_CLASSES_ROOT = new(new IntPtr(unchecked((int)0x80000000)));
/// <summary>
/// Contains information about the current hardware profile of the local computer system. The information under HKEY_CURRENT_CONFIG
/// describes only the differences between the current hardware configuration and the standard configuration. Information about the
/// standard hardware configuration is stored under the Software and System keys of HKEY_LOCAL_MACHINE.
/// </summary>
public static readonly HKEY HKEY_CURRENT_CONFIG = new(new IntPtr(unchecked((int)0x80000005)));
/// <summary>
/// Registry entries subordinate to this key define the preferences of the current user. These preferences include the settings of
/// environment variables, data about program groups, colors, printers, network connections, and application preferences. This key
/// makes it easier to establish the current user's settings; the key maps to the current user's branch in HKEY_USERS. In
/// HKEY_CURRENT_USER, software vendors store the current user-specific preferences to be used within their applications. Microsoft,
/// for example, creates the HKEY_CURRENT_USER\Software\Microsoft key for its applications to use, with each application creating its
/// own subkey under the Microsoft key.
/// </summary>
public static readonly HKEY HKEY_CURRENT_USER = new(new IntPtr(unchecked((int)0x80000001)));
/// <summary></summary>
public static readonly HKEY HKEY_DYN_DATA = new(new IntPtr(unchecked((int)0x80000006)));
/// <summary>
/// Registry entries subordinate to this key define the physical state of the computer, including data about the bus type, system
/// memory, and installed hardware and software. It contains subkeys that hold current configuration data, including Plug and Play
/// information (the Enum branch, which includes a complete list of all hardware that has ever been on the system), network logon
/// preferences, network security information, software-related information (such as server names and the location of the server),
/// and other system information.
/// </summary>
public static readonly HKEY HKEY_LOCAL_MACHINE = new(new IntPtr(unchecked((int)0x80000002)));
/// <summary>
/// Registry entries subordinate to this key allow you to access performance data. The data is not actually stored in the registry;
/// the registry functions cause the system to collect the data from its source.
/// </summary>
public static readonly HKEY HKEY_PERFORMANCE_DATA = new(new IntPtr(unchecked((int)0x80000004)));
/// <summary>
/// Registry entries subordinate to this key define the default user configuration for new users on the local computer and the user
/// configuration for the current user.
/// </summary>
public static readonly HKEY HKEY_USERS = new(new IntPtr(unchecked((int)0x80000003)));
<# } #>
/// <summary>Performs an explicit conversion from <see cref="<#= name #>"/> to <see cref="IntPtr"/>.</summary>
/// <param name="h">The handle.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IntPtr(<#= name #> h) => h.handle;
/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="<#= name #>"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator <#= name #>(IntPtr h) => new(h);
<# if (casts.TryGetValue(name, out var value)) { #>
/// <summary>Performs an implicit conversion from <see cref="<#= value.Item1 #>"/> to <see cref="<#= value.Item2 #>"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator <#= value.Item1 #>(<#= value.Item2 #> h) => new(<#= value.Item3 #>);
<# } #>
<# if (name == "HGDIOBJ") { foreach (var res in classes.Where(r => r.name != "HGDIOBJ" && r.inheritance == "IGraphicsObjectHandle")) {#>
/// <summary>Performs an implicit conversion from <see cref="<#= res.name #>"/> to <see cref="HGDIOBJ"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator HGDIOBJ(<#= res.name #> h) => new((IntPtr)h);
<# } } #>
<# if (name != "HGDIOBJ" && inheritance == "IGraphicsObjectHandle") { #>
/// <summary>Performs an implicit conversion from <see cref="HGDIOBJ"/> to <see cref="<#= name #>"/>.</summary>
/// <param name="h">The pointer to a GDI handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator <#= name #>(HGDIOBJ h) => new((IntPtr)h);
<# } #>
/// <summary>Implements the operator ! which returns <see langword="true"/> if the handle is invalid.</summary>
/// <param name="hMem">The <see cref="<#= name #>"/> instance.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !(<#= name #> hMem) => hMem.IsNull;
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(<#= name #> h1, <#= name #> h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(<#= name #> h1, <#= name #> h2) => h1.Equals(h2);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is <#= name #> h && handle == h.handle;
/// <inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
/// <inheritdoc/>
public IntPtr DangerousGetHandle() => handle;
}
<# } #>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Vanara.PInvoke
{
/// <summary>Base class for all native handles.</summary>
/// <seealso cref="SafeHandleZeroOrMinusOneIsInvalid"/>
/// <seealso cref="IEquatable{T}"/>
/// <seealso cref="IHandle"/>
[DebuggerDisplay("{handle}")]
public abstract class SafeHANDLE : SafeHandleZeroOrMinusOneIsInvalid, IEquatable<SafeHANDLE>, IHandle
{
/// <summary>Initializes a new instance of the <see cref="SafeHANDLE"/> class.</summary>
public SafeHANDLE() : base(true)
{
}
/// <summary>Initializes a new instance of the <see cref="SafeHANDLE"/> class and assigns an existing handle.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
/// <param name="ownsHandle">
/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
/// </param>
protected SafeHANDLE(IntPtr preexistingHandle, bool ownsHandle = true) : base(ownsHandle) => SetHandle(preexistingHandle);
/// <summary>Gets a value indicating whether this instance is null.</summary>
/// <value><c>true</c> if this instance is null; otherwise, <c>false</c>.</value>
public bool IsNull => handle == IntPtr.Zero;
/// <summary>Implements the operator ! which returns <see langword="true"/> if the handle is invalid.</summary>
/// <param name="hMem">The <see cref="SafeHANDLE"/> instance.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !(SafeHANDLE hMem) => hMem.IsInvalid;
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(SafeHANDLE h1, IHandle h2) => !(h1 == h2);
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(SafeHANDLE h1, IntPtr h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(SafeHANDLE h1, IHandle h2) => h1?.Equals(h2) ?? h2 is null;
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(SafeHANDLE h1, IntPtr h2) => h1?.Equals(h2) ?? false;
/// <summary>Determines whether the specified <see cref="SafeHANDLE"/>, is equal to this instance.</summary>
/// <param name="other">The <see cref="SafeHANDLE"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="SafeHANDLE"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public bool Equals(SafeHANDLE other) => ReferenceEquals(this, other) || other is not null && handle == other.handle && IsClosed == other.IsClosed;
/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
public override bool Equals(object obj) => obj switch
{
IHandle ih => handle.Equals(ih.DangerousGetHandle()),
SafeHandle sh => handle.Equals(sh.DangerousGetHandle()),
IntPtr p => handle.Equals(p),
_ => base.Equals(obj),
};
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() => base.GetHashCode();
/// <summary>Releases the ownership of the underlying handle and returns the current handle.</summary>
/// <returns>The value of the current handle.</returns>
public IntPtr ReleaseOwnership()
{
var ret = handle;
SetHandleAsInvalid();
return ret;
}
void X()
{
var classes = new System.Collections.Generic.List<(string name, string inheritance, string summaryText)> {
( "LPSTR", "LPTSTR", "LPWSTR" ),
};
var casts = new System.Collections.Generic.Dictionary<string, (string, string)> {
{ "HANDLE", ("HANDLE", "SafeHandle" ) },
{ "HPROCESS", ("Process", "SafeHandle" ) },
};
foreach (var (name, inheritance, summaryText) in classes)
{
}
}
/// <summary>
/// Internal method that actually releases the handle. This is called by <see cref="ReleaseHandle"/> for valid handles and afterwards
/// zeros the handle.
/// </summary>
/// <returns><c>true</c> to indicate successful release of the handle; <c>false</c> otherwise.</returns>
protected abstract bool InternalReleaseHandle();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
protected override bool ReleaseHandle()
{
if (IsInvalid) return true;
if (!InternalReleaseHandle()) return false;
handle = IntPtr.Zero;
return true;
}
}
}

View File

@ -28,10 +28,33 @@ CharacterSet, CM_DEVCAP, CM_FILE, CM_INSTALL_STATE, CM_REMOVAL_POLICY, CM_RESOUR
</PackageReleaseNotes>
<PackageReadmeFile>pkgreadme.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="Handles\HANDLE.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>HANDLE.tt</DependentUpon>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\Vanara.Core.csproj" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) Or $(TargetFramework.StartsWith('netcore')) Or $(TargetFramework.StartsWith('net5.0')) Or $(TargetFramework.StartsWith('net6.0')) ">
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="Handles\HANDLE.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>HANDLE.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Handles\HANDLE.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>HANDLE.tt</DependentUpon>
</Compile>
</ItemGroup>
</Project>