diff --git a/src/AdvApi32.Desktop/AdvApi32+SECURITY_INFORMATION.cs b/src/AdvApi32.Desktop/AdvApi32+SECURITY_INFORMATION.cs
new file mode 100644
index 00000000..1514f7b1
--- /dev/null
+++ b/src/AdvApi32.Desktop/AdvApi32+SECURITY_INFORMATION.cs
@@ -0,0 +1,81 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ using System;
+
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class AdvApi32
+ {
+ ///
+ /// Identifies the object-related security information being set or queried.
+ ///
+ [Flags]
+ public enum SECURITY_INFORMATION
+ {
+ ///
+ /// The resource properties of the object being referenced. The resource properties are stored in
+ /// SYSTEM_RESOURCE_ATTRIBUTE_ACE types in the SACL of the security descriptor.
+ ///
+ ///
+ /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:
+ /// This bit flag is not available.
+ ///
+ ATTRIBUTE_SECURITY_INFORMATION,
+
+ ///
+ /// All parts of the security descriptor. This is useful for backup and restore software that needs to preserve
+ /// the entire security descriptor.
+ ///
+ ///
+ /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:
+ /// This bit flag is not available.
+ ///
+ BACKUP_SECURITY_INFORMATION,
+
+ /// The DACL of the object is being referenced.
+ DACL_SECURITY_INFORMATION,
+
+ /// The primary group identifier of the object is being referenced.
+ GROUP_SECURITY_INFORMATION,
+
+ ///
+ /// The mandatory integrity label is being referenced. The mandatory integrity label is an ACE in the SACL of the
+ /// object.
+ ///
+ /// Windows Server 2003 and Windows XP: This bit flag is not available.
+ LABEL_SECURITY_INFORMATION,
+
+ /// The owner identifier of the object is being referenced.
+ OWNER_SECURITY_INFORMATION,
+
+ /// The DACL cannot inherit access control entries (ACEs).
+ PROTECTED_DACL_SECURITY_INFORMATION,
+
+ /// The SACL cannot inherit ACEs.
+ PROTECTED_SACL_SECURITY_INFORMATION,
+
+ /// The SACL of the object is being referenced.
+ SACL_SECURITY_INFORMATION,
+
+ ///
+ /// The Central Access Policy (CAP) identifier applicable on the object that is being referenced. Each CAP
+ /// identifier is stored in a SYSTEM_SCOPED_POLICY_ID_ACE type in the SACL of the SD.
+ ///
+ ///
+ /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:
+ /// This bit flag is not available.
+ ///
+ SCOPE_SECURITY_INFORMATION,
+
+ /// The DACL inherits ACEs from the parent object.
+ UNPROTECTED_DACL_SECURITY_INFORMATION,
+
+ /// The SACL inherits ACEs from the parent object.
+ UNPROTECTED_SACL_SECURITY_INFORMATION
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AdvApi32.Desktop/AdvApi32+TOKEN_ELEVATION_TYPE.cs b/src/AdvApi32.Desktop/AdvApi32+TOKEN_ELEVATION_TYPE.cs
new file mode 100644
index 00000000..3f54f038
--- /dev/null
+++ b/src/AdvApi32.Desktop/AdvApi32+TOKEN_ELEVATION_TYPE.cs
@@ -0,0 +1,35 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class AdvApi32
+ {
+ ///
+ /// Indicates the elevation type of token being queried by the function.
+ ///
+ public enum TOKEN_ELEVATION_TYPE
+ {
+ ///
+ /// Standard user that don't require UAC as he doesn't have any elevated attributes in it's
+ /// security token.
+ ///
+ TokenElevationTypeDefault = 1,
+
+ ///
+ /// Process executing with full elevated rights, either UAC is disable or the process is
+ /// executing in "Run as administrator" mode.
+ ///
+ TokenElevationTypeFull,
+
+ ///
+ /// Process executing under UAC, the current user got some elevated right but they can't
+ /// be used in the process as the token is "split".
+ ///
+ TokenElevationTypeLimited
+ }
+ }
+}
diff --git a/src/AdvApi32.Desktop/AdvApi32+TOKEN_INFORMATION_CLASS.cs b/src/AdvApi32.Desktop/AdvApi32+TOKEN_INFORMATION_CLASS.cs
new file mode 100644
index 00000000..fa8f1cf0
--- /dev/null
+++ b/src/AdvApi32.Desktop/AdvApi32+TOKEN_INFORMATION_CLASS.cs
@@ -0,0 +1,59 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class AdvApi32
+ {
+ ///
+ /// Specify the type of information being assigned to or retrieved from an access token.
+ ///
+ public enum TOKEN_INFORMATION_CLASS
+ {
+ TokenUser = 1,
+ TokenGroups,
+ TokenPrivileges,
+ TokenOwner,
+ TokenPrimaryGroup,
+ TokenDefaultDacl,
+ TokenSource,
+ TokenType,
+ TokenImpersonationLevel,
+ TokenStatistics,
+ TokenRestrictedSids,
+ TokenSessionId,
+ TokenGroupsAndPrivileges,
+ TokenSessionReference,
+ TokenSandBoxInert,
+ TokenAuditPolicy,
+ TokenOrigin,
+ TokenElevationType,
+ TokenLinkedToken,
+ TokenElevation,
+ TokenHasRestrictions,
+ TokenAccessInformation,
+ TokenVirtualizationAllowed,
+ TokenVirtualizationEnabled,
+ TokenIntegrityLevel,
+ TokenUiAccess,
+ TokenMandatoryPolicy,
+ TokenLogonSid,
+ TokenIsAppContainer,
+ TokenCapabilities,
+ TokenAppContainerSid,
+ TokenAppContainerNumber,
+ TokenUserClaimAttributes,
+ TokenDeviceClaimAttributes,
+ TokenRestrictedUserClaimAttributes,
+ TokenRestrictedDeviceClaimAttributes,
+ TokenDeviceGroups,
+ TokenRestrictedDeviceGroups,
+ TokenSecurityAttributes,
+ TokenIsRestricted,
+ MaxTokenInfoClass
+ }
+ }
+}
diff --git a/src/AdvApi32.Desktop/AdvApi32+TokenAccessRights.cs b/src/AdvApi32.Desktop/AdvApi32+TokenAccessRights.cs
new file mode 100644
index 00000000..df381d41
--- /dev/null
+++ b/src/AdvApi32.Desktop/AdvApi32+TokenAccessRights.cs
@@ -0,0 +1,100 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ using System;
+
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class AdvApi32
+ {
+ ///
+ /// The different access rights allowed to access an access token.
+ ///
+ [Flags]
+ public enum TokenAccessRights : uint
+ {
+ /// The right to delete the object.
+ DELETE = 0x00010000,
+
+ ///
+ /// The right to read the information in the object's security descriptor, not including the information in the
+ /// system access control list (SACL).
+ ///
+ READ_CONTROL = 0x00020000,
+
+ /// The right to modify the discretionary access control list (DACL) in the object's security descriptor.
+ WRITE_DAC = 0x00040000,
+
+ /// The right to change the owner in the object's security descriptor.
+ WRITE_OWNER = 0x00080000,
+
+ /// Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.
+ STANDARD_RIGHTS_REQUIRED = 0x000F0000,
+
+ /// Currently defined to equal READ_CONTROL.
+ STANDARD_RIGHTS_READ = READ_CONTROL,
+
+ /// Currently defined to equal READ_CONTROL.
+ STANDARD_RIGHTS_WRITE = READ_CONTROL,
+
+ /// Currently defined to equal READ_CONTROL.
+ STANDARD_RIGHTS_EXECUTE = READ_CONTROL,
+
+ ///
+ /// Required to attach a primary token to a process. The SE_ASSIGNPRIMARYTOKEN_NAME privilege is also required to
+ /// accomplish this task.
+ ///
+ TOKEN_ASSIGN_PRIMARY = 0x0001,
+
+ /// Required to duplicate an access token.
+ TOKEN_DUPLICATE = 0x0002,
+
+ /// Required to attach an impersonation access token to a process.
+ TOKEN_IMPERSONATE = 0x0004,
+
+ /// Required to query an access token.
+ TOKEN_QUERY = 0x0008,
+
+ /// Required to query the source of an access token.
+ TOKEN_QUERY_SOURCE = 0x0010,
+
+ /// Required to enable or disable the privileges in an access token.
+ TOKEN_ADJUST_PRIVILEGES = 0x0020,
+
+ /// Required to adjust the attributes of the groups in an access token.
+ TOKEN_ADJUST_GROUPS = 0x0040,
+
+ /// Required to change the default owner, primary group, or DACL of an access token.
+ TOKEN_ADJUST_DEFAULT = 0x0080,
+
+ /// Required to adjust the session ID of an access token. The SE_TCB_NAME privilege is required.
+ TOKEN_ADJUST_SESSIONID = 0x0100,
+
+ /// Combines STANDARD_RIGHTS_READ and TOKEN_QUERY.
+ TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY,
+
+ /// Combines STANDARD_RIGHTS_WRITE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, and TOKEN_ADJUST_DEFAULT.
+ TOKEN_WRITE = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT,
+
+ /// Required to wait for the process to terminate using the wait functions.
+ ACCESS_SYSTEM_SECURITY = 0x01000000,
+
+ /// Combines STANDARD_RIGHTS_EXECUTE and TOKEN_IMPERSONATE.
+ TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE | TOKEN_IMPERSONATE,
+
+ /// Combines all possible access rights for a token.
+ TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AdvApi32.Desktop/AdvApi32.Desktop.csproj b/src/AdvApi32.Desktop/AdvApi32.Desktop.csproj
index 635923e9..0c1ff765 100644
--- a/src/AdvApi32.Desktop/AdvApi32.Desktop.csproj
+++ b/src/AdvApi32.Desktop/AdvApi32.Desktop.csproj
@@ -39,6 +39,7 @@
+
@@ -57,6 +58,9 @@
+
+
+
diff --git a/src/AdvApi32.Desktop/AdvApi32.Helpers.cs b/src/AdvApi32.Desktop/AdvApi32.Helpers.cs
index 5db926e5..9be8e9e8 100644
--- a/src/AdvApi32.Desktop/AdvApi32.Helpers.cs
+++ b/src/AdvApi32.Desktop/AdvApi32.Helpers.cs
@@ -5,6 +5,8 @@ namespace PInvoke
{
using System;
using System.Runtime.InteropServices;
+ using System.Security.AccessControl;
+ using static Kernel32;
///
/// Methods and nested types that are not strictly P/Invokes but provide
@@ -96,5 +98,119 @@ public static void UninstallService(string serviceName)
}
}
}
+
+ /// Get the elevation type of a token via .
+ ///
+ /// A handle to an access token from which information is retrieved. The handle must have
+ /// TOKEN_QUERY access.
+ ///
+ /// The token elevation type
+ /// is NULL.
+ /// If the call to fails.
+ public static TOKEN_ELEVATION_TYPE GetTokenElevationType(SafeObjectHandle TokenHandle)
+ {
+ if (TokenHandle == null)
+ {
+ throw new ArgumentNullException(nameof(TokenHandle));
+ }
+
+ var elevationType = default(TOKEN_ELEVATION_TYPE);
+
+ bool success;
+ unsafe
+ {
+ uint returnLength;
+ success = GetTokenInformation(
+ TokenHandle,
+ TOKEN_INFORMATION_CLASS.TokenElevationType,
+ &elevationType,
+ (uint)sizeof(TOKEN_ELEVATION_TYPE),
+ out returnLength);
+ }
+
+ if (!success)
+ {
+ throw new Win32Exception();
+ }
+
+ return elevationType;
+ }
+
+ ///
+ /// Retrieves a copy of the security descriptor associated with a service object. You can also use the
+ /// GetNamedSecurityInfo function to retrieve a security descriptor.
+ ///
+ ///
+ /// A handle to the service control manager or the service. Handles to the service control manager
+ /// are returned by the function, and handles to a service are returned by either the
+ /// or function. The handle must have the READ_CONTROL access
+ /// right.
+ ///
+ ///
+ /// A set of bit flags that indicate the type of security information to retrieve. This
+ /// parameter can be a combination of the flags, with the exception that this
+ /// function does not support the value.
+ ///
+ ///
+ /// A copy of the security descriptor of the specified service object. The calling process must have the
+ /// appropriate access to view the specified aspects of the security descriptor of the object.
+ ///
+ /// is NULL.
+ /// If the call to the native method fails fails.
+ public static RawSecurityDescriptor QueryServiceObjectSecurity(SafeServiceHandle hService, SECURITY_INFORMATION dwSecurityInformation)
+ {
+ if (hService == null)
+ {
+ throw new ArgumentNullException(nameof(hService));
+ }
+
+ var securityDescriptor = new byte[0];
+ uint bufSizeNeeded;
+ QueryServiceObjectSecurity(hService, dwSecurityInformation, securityDescriptor, 0, out bufSizeNeeded);
+
+ var lastError = GetLastError();
+ if (lastError != Win32ErrorCode.ERROR_INSUFFICIENT_BUFFER)
+ {
+ throw new Win32Exception(lastError);
+ }
+
+ securityDescriptor = new byte[bufSizeNeeded];
+ var success = QueryServiceObjectSecurity(hService, dwSecurityInformation, securityDescriptor, bufSizeNeeded, out bufSizeNeeded);
+
+ if (!success)
+ {
+ throw new Win32Exception();
+ }
+
+ return new RawSecurityDescriptor(securityDescriptor, 0);
+ }
+
+ /// The SetServiceObjectSecurity function sets the security descriptor of a service object.
+ ///
+ /// A handle to the service. This handle is returned by the or
+ /// function. The access required for this handle depends on the security information
+ /// specified in the parameter.
+ ///
+ ///
+ /// Specifies the components of the security descriptor to set. This parameter can be a
+ /// combination of the following values : ,
+ /// ,
+ /// ,
+ /// . Note that flags not handled by
+ /// SetServiceObjectSecurity will be silently ignored.
+ ///
+ /// The new security information.
+ public static void SetServiceObjectSecurity(
+ SafeServiceHandle hService,
+ SECURITY_INFORMATION dwSecurityInformation,
+ RawSecurityDescriptor lpSecurityDescriptor)
+ {
+ var binaryForm = new byte[lpSecurityDescriptor.BinaryLength];
+ lpSecurityDescriptor.GetBinaryForm(binaryForm, 0);
+ if (!SetServiceObjectSecurity(hService, dwSecurityInformation, binaryForm))
+ {
+ throw new Win32Exception();
+ }
+ }
}
}
diff --git a/src/AdvApi32.Desktop/AdvApi32.cs b/src/AdvApi32.Desktop/AdvApi32.cs
index 55b17ecd..cb11bfaa 100644
--- a/src/AdvApi32.Desktop/AdvApi32.cs
+++ b/src/AdvApi32.Desktop/AdvApi32.cs
@@ -5,6 +5,8 @@ namespace PInvoke
{
using System;
using System.Runtime.InteropServices;
+ using System.Security.AccessControl;
+ using static Kernel32;
///
/// Exported functions from the AdvApi32.dll Windows library
@@ -196,6 +198,160 @@ public static partial class AdvApi32
[DllImport(nameof(AdvApi32), SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool StartService(SafeServiceHandle hService, int dwNumServiceArgs, string lpServiceArgVectors);
+ /// Opens the access token associated with a process.
+ ///
+ /// A handle to the process whose access token is opened. The process must have the
+ /// PROCESS_QUERY_INFORMATION access permission.
+ ///
+ ///
+ /// Specifies an access mask that specifies the requested types of access to the access token.
+ /// These requested access types are compared with the discretionary access control list (DACL) of the token to
+ /// determine which accesses are granted or denied.
+ ///
+ /// A handle that identifies the newly opened access token when the function returns.
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(AdvApi32), SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool OpenProcessToken(
+ IntPtr processHandle,
+ TokenAccessRights desiredAccess,
+ out SafeObjectHandle tokenHandle);
+
+ ///
+ /// The GetTokenInformation function retrieves a specified type of information about an access token. The calling
+ /// process must have appropriate access rights to obtain the information.
+ ///
+ /// To determine if a user is a member of a specific group, use the CheckTokenMembership function. To determine
+ /// group membership for app container tokens, use the CheckTokenMembershipEx function.
+ ///
+ ///
+ ///
+ /// A handle to an access token from which information is retrieved. If TokenInformationClass
+ /// specifies TokenSource, the handle must have TOKEN_QUERY_SOURCE access. For all other TokenInformationClass values,
+ /// the handle must have TOKEN_QUERY access.
+ ///
+ ///
+ /// Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the
+ /// type of information the function retrieves. Any callers who check the TokenIsAppContainer and have it return 0
+ /// should also verify that the caller token is not an identify level impersonation token. If the current token is not
+ /// an app container but is an identity level token, you should return AccessDenied.
+ ///
+ ///
+ /// A pointer to a buffer the function fills with the requested information. The structure
+ /// put into this buffer depends upon the type of information specified by the
+ /// parameter.
+ ///
+ ///
+ /// Specifies the size, in bytes, of the buffer pointed to by the TokenInformation
+ /// parameter. If is NULL, this parameter must be zero.
+ ///
+ ///
+ /// A pointer to a variable that receives the number of bytes needed for the buffer pointed to by the TokenInformation
+ /// parameter. If this value is larger than the value specified in the TokenInformationLength parameter, the function
+ /// fails and stores no data in the buffer.
+ ///
+ /// If the value of the parameter is
+ /// and the token has no default DACL, the function sets
+ /// the variable pointed to by ReturnLength to sizeof(TOKEN_DEFAULT_DACL) and sets the DefaultDacl member of the
+ /// TOKEN_DEFAULT_DACL structure to NULL.
+ ///
+ ///
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(AdvApi32), SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern unsafe bool GetTokenInformation(
+ SafeObjectHandle TokenHandle,
+ TOKEN_INFORMATION_CLASS TokenInformationClass,
+ void* TokenInformation,
+ uint TokenInformationLength,
+ out uint ReturnLength);
+
+ ///
+ /// The QueryServiceObjectSecurity function retrieves a copy of the security descriptor associated with a service
+ /// object. You can also use the GetNamedSecurityInfo function to retrieve a security descriptor.
+ ///
+ ///
+ /// A handle to the service control manager or the service. Handles to the service control manager
+ /// are returned by the function, and handles to a service are returned by either the
+ /// or function. The handle must have the READ_CONTROL access
+ /// right.
+ ///
+ ///
+ /// A set of bit flags that indicate the type of security information to retrieve. This
+ /// parameter can be a combination of the flags, with the exception that this
+ /// function does not support the value.
+ ///
+ ///
+ /// A pointer to a buffer that receives a copy of the security descriptor of the
+ /// specified service object. The calling process must have the appropriate access to view the specified aspects of the
+ /// security descriptor of the object. The SECURITY_DESCRIPTOR structure is returned in self-relative format.
+ ///
+ ///
+ /// The size of the buffer pointed to by the parameter, in
+ /// bytes. The largest size allowed is 8 kilobytes.
+ ///
+ ///
+ /// A pointer to a variable that receives the number of bytes needed to return the requested
+ /// security descriptor information, if the function fails.
+ ///
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(AdvApi32), SetLastError = true)]
+ public static extern bool QueryServiceObjectSecurity(
+ SafeServiceHandle hService,
+ SECURITY_INFORMATION dwSecurityInformation,
+ byte[] lpSecurityDescriptor,
+ uint cbBufSize,
+ out uint pcbBytesNeeded);
+
+ /// The SetServiceObjectSecurity function sets the security descriptor of a service object.
+ ///
+ /// A handle to the service. This handle is returned by the or
+ /// function. The access required for this handle depends on the security information
+ /// specified in the parameter.
+ ///
+ ///
+ /// Specifies the components of the security descriptor to set. This parameter can be a
+ /// combination of the following values : ,
+ /// ,
+ /// ,
+ /// . Note that flags not handled by
+ /// SetServiceObjectSecurity will be silently ignored.
+ ///
+ ///
+ /// A pointer to a SECURITY_DESCRIPTOR structure that contains the new security
+ /// information.
+ ///
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(AdvApi32), SetLastError = true)]
+ public static extern bool SetServiceObjectSecurity(
+ SafeServiceHandle hService,
+ SECURITY_INFORMATION dwSecurityInformation,
+ byte[] lpSecurityDescriptor);
+
///
/// Closes a handle to a service control manager or service object.
///
diff --git a/src/Kernel32.Desktop/Kernel32+SafeLibraryHandle.cs b/src/Kernel32.Desktop/Kernel32+SafeLibraryHandle.cs
new file mode 100644
index 00000000..0edc42a0
--- /dev/null
+++ b/src/Kernel32.Desktop/Kernel32+SafeLibraryHandle.cs
@@ -0,0 +1,46 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Contains the nested type.
+ ///
+ public static partial class Kernel32
+ {
+ ///
+ /// Represents a library handle that can be closed with .
+ ///
+ public class SafeLibraryHandle : SafeHandle
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SafeLibraryHandle()
+ : base(INVALID_HANDLE_VALUE, true)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An object that represents the pre-existing handle to use.
+ /// to reliably release the handle during the finalization
+ /// phase; to prevent reliable release.
+ public SafeLibraryHandle(IntPtr preexistingHandle, bool ownsHandle)
+ : base(INVALID_HANDLE_VALUE, ownsHandle)
+ {
+ this.SetHandle(preexistingHandle);
+ }
+
+ ///
+ public override bool IsInvalid => this.handle == INVALID_HANDLE_VALUE || this.handle == IntPtr.Zero;
+
+ ///
+ protected override bool ReleaseHandle() => FreeLibrary(this.handle);
+ }
+ }
+}
diff --git a/src/Kernel32.Desktop/Kernel32.Desktop.csproj b/src/Kernel32.Desktop/Kernel32.Desktop.csproj
index 9421dae7..c06d92bf 100644
--- a/src/Kernel32.Desktop/Kernel32.Desktop.csproj
+++ b/src/Kernel32.Desktop/Kernel32.Desktop.csproj
@@ -39,6 +39,7 @@
+
diff --git a/src/Kernel32.Desktop/Kernel32.cs b/src/Kernel32.Desktop/Kernel32.cs
index 94dbfb8a..437c0f9a 100644
--- a/src/Kernel32.Desktop/Kernel32.cs
+++ b/src/Kernel32.Desktop/Kernel32.cs
@@ -732,5 +732,67 @@ public static extern bool CreatePipe(
[DllImport(nameof(Kernel32), SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool K32EmptyWorkingSet(SafeObjectHandle hProcess);
+
+ /// Retrieves the window handle used by the console associated with the calling process.
+ ///
+ /// The return value is a handle to the window used by the console associated with the calling process or
+ /// if there is no such associated console.
+ ///
+ [DllImport(nameof(Kernel32))]
+ public static extern IntPtr GetConsoleWindow();
+
+ ///
+ /// Loads the specified module into the address space of the calling process. The specified module may cause other
+ /// modules to be loaded.
+ /// For additional load options, use the LoadLibraryEx function.
+ ///
+ ///
+ /// The name of the module. This can be either a library module (a .dll file) or an executable module (an .exe file).
+ /// The name specified is the file name of the module and is not related to the name stored in the library module
+ /// itself, as specified by the LIBRARY keyword in the module-definition (.def) file.
+ /// If the string specifies a full path, the function searches only that path for the module.
+ ///
+ /// If the string specifies a relative path or a module name without a path, the function uses a standard search
+ /// strategy to find the module.
+ ///
+ ///
+ /// If the function cannot find the module, the function fails. When specifying a path, be sure to use
+ /// backslashes (\), not forward slashes (/).
+ ///
+ ///
+ /// If the string specifies a module name without a path and the file name extension is omitted, the function
+ /// appends the default library extension .dll to the module name. To prevent the function from appending .dll to
+ /// the module name, include a trailing point character (.) in the module name string.
+ ///
+ ///
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(Kernel32), SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern SafeLibraryHandle LoadLibrary(string lpFileName);
+
+ ///
+ /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the
+ /// reference count reaches zero, the module is unloaded from the address space of the calling process and the handle
+ /// is no longer valid.
+ ///
+ ///
+ /// A handle to the loaded library module. The LoadLibrary, LoadLibraryEx, GetModuleHandle, or
+ /// GetModuleHandleEx function returns this handle.
+ ///
+ ///
+ /// If the function succeeds, the return value is a nonzero value.
+ ///
+ /// If the function fails, the return value is zero. To get extended error information, call
+ /// .
+ ///
+ ///
+ [DllImport(nameof(Kernel32), SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool FreeLibrary(IntPtr hModule);
}
}
diff --git a/src/Kernel32.Tests/Kernel32.cs b/src/Kernel32.Tests/Kernel32.cs
index ee1e8af7..06b95495 100644
--- a/src/Kernel32.Tests/Kernel32.cs
+++ b/src/Kernel32.Tests/Kernel32.cs
@@ -659,7 +659,6 @@ public void IsWow64Process_ReturnExpectedValue()
Assert.Equal(expected, actual);
}
-
[Fact]
public void CreatePipe_ReadWrite()
{
@@ -682,4 +681,20 @@ public void K32EmptyWorkingSet_Run()
Assert.True(K32EmptyWorkingSet(pid));
}
}
+
+ [Fact]
+ public void LoadLibrary_And_FreeLibrary()
+ {
+ using (var library = LoadLibrary("kernel32.dll"))
+ {
+ Assert.False(library.IsInvalid);
+ }
+ }
+
+ [Fact]
+ public void GetConsoleWindow_DoesNotThrow()
+ {
+ // No assert possible as the answer depends on the test runner, we only want to know that the method can be called successfully.
+ GetConsoleWindow();
+ }
}