Final update on CfgMgr32 functions

pull/229/head
dahall 2021-05-05 20:34:12 -06:00
parent 56de5f0c91
commit 27c00f8281
6 changed files with 828 additions and 172 deletions

View File

@ -2,6 +2,7 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.SetupAPI;
@ -359,6 +360,14 @@ namespace Vanara.PInvoke
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CONFLICT_DETAILS
{
/// <summary>Initializes a new instance of the <see cref="CONFLICT_DETAILS"/> struct with the size and mask set.</summary>
/// <param name="mask">The mask of items to retrieve.</param>
public CONFLICT_DETAILS(CM_CDMASK mask) : this()
{
CD_ulSize = (uint)Marshal.SizeOf(typeof(CONFLICT_DETAILS));
CD_ulMask = mask;
}
/// <summary>Size, in bytes, of the CONFLICT_DETAILS structure.</summary>
public uint CD_ulSize;
@ -434,9 +443,6 @@ namespace Vanara.PInvoke
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260 /*MAX_PATH*/)]
public string CD_szDescription;
/// <summary>Gets a default value for the structure with the size field set.</summary>
public static readonly CONFLICT_DETAILS Default = new() { CD_ulSize = (uint)Marshal.SizeOf(typeof(CONFLICT_DETAILS)) };
}
/// <summary>

View File

@ -1743,6 +1743,55 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Free_Res_Des")]
public static extern CONFIGRET CM_Free_Res_Des(out SafeRES_DES prdResDes, RES_DES rdResDes, uint ulFlags = 0);
/// <summary>The <c>CM_Free_Res_Des</c> function removes a resource descriptor from a logical configuration on the local machine.</summary>
/// <param name="prdResDes">
/// Caller-supplied location to receive a handle to the configuration's previous resource descriptor. This parameter can be
/// <c>NULL</c>. For more information, see the following <c>Remarks</c> section.
/// </param>
/// <param name="rdResDes">
/// <para>
/// Caller-supplied handle to the resource descriptor to be removed. This handle must have been previously obtained by calling one
/// of the following functions:
/// </para>
/// <para>CM_Add_Res_Des</para>
/// <para>CM_Add_Res_Des_Ex</para>
/// <para>CM_Get_Next_Res_Des</para>
/// <para>CM_Get_Next_Res_Des_Ex</para>
/// <para>CM_Modify_Res_Des</para>
/// <para>CM_Modify_Res_Des_Ex</para>
/// </param>
/// <param name="ulFlags">Not used, must be zero.</param>
/// <returns>
/// <para>
/// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in Cfgmgr32.h.
/// </para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Free_Res_Des</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario. To
/// request information about the hardware resources on a local machine it is necessary implement an architecture-native version of
/// the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// Resource descriptors for each configuration are stored in an array. If you specify an address for prdResDes, then
/// <c>CM_Free_Res_Des</c> returns a handle to the resource descriptor that was previous, in the array, to the one removed. If the
/// handle specified by rdResDes represents the resource descriptor located first in the array, then prdResDes receives a handle to
/// the logical configuration.
/// </para>
/// <para>
/// Note that calling <c>CM_Free_Res_Des</c> frees the resource descriptor, but not the descriptor's handle. To free the handle,
/// call <c>CM_Free_Res_Des_Handle</c>.
/// </para>
/// <para>
/// Callers of this function must have <c>SeLoadDriverPrivilege</c>. (Privileges are described in the Microsoft Windows SDK documentation.)
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_free_res_des CMAPI CONFIGRET CM_Free_Res_Des( PRES_DES
// prdResDes, RES_DES rdResDes, ULONG ulFlags );
[DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Free_Res_Des")]
public static extern CONFIGRET CM_Free_Res_Des([In, Optional] IntPtr prdResDes, RES_DES rdResDes, uint ulFlags = 0);
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Free_Res_Des instead.]</para>
/// <para>
@ -1808,6 +1857,71 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Free_Res_Des_Ex")]
public static extern CONFIGRET CM_Free_Res_Des_Ex(out SafeRES_DES prdResDes, RES_DES rdResDes, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Free_Res_Des instead.]</para>
/// <para>
/// The <c>CM_Free_Res_Des_Ex</c> function removes a resource descriptor from a logical configuration on either a local or a remote machine.
/// </para>
/// </summary>
/// <param name="prdResDes">
/// Caller-supplied location to receive a handle to the configuration's previous resource descriptor. This parameter can be
/// <c>NULL</c>. For more information, see the following <c>Remarks</c> section.
/// </param>
/// <param name="rdResDes">
/// <para>
/// Caller-supplied handle to the resource descriptor to be removed. This handle must have been previously obtained by calling one
/// of the following functions:
/// </para>
/// <para>CM_Add_Res_Des</para>
/// <para>CM_Add_Res_Des_Ex</para>
/// <para>CM_Get_Next_Res_Des</para>
/// <para>CM_Get_Next_Res_Des_Ex</para>
/// <para>CM_Modify_Res_Des</para>
/// <para>CM_Modify_Res_Des_Ex</para>
/// </param>
/// <param name="ulFlags">Not used, must be zero.</param>
/// <param name="hMachine">
/// <para>Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.</para>
/// <para>
/// <c>Note</c> Using this function to access remote machines is not supported beginning with Windows 8 and Windows Server 2012, as
/// this functionality has been removed.
/// </para>
/// </param>
/// <returns>
/// <para>
/// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in Cfgmgr32.h.
/// </para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Free_Res_Des_Ex</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario. To
/// request information about the hardware resources on a local machine it is necessary implement an architecture-native version of
/// the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// Resource descriptors for each configuration are stored in an array. If you specify an address for prdResDes, then
/// <c>CM_Free_Res_Des</c> returns a handle to the resource descriptor that was previous, in the array, to the one removed. If the
/// handle specified by rdResDes represents the resource descriptor located first in the array, then prdResDes receives a handle to
/// the logical configuration.
/// </para>
/// <para>
/// Note that calling <c>CM_Free_Res_Des_Ex</c> frees the resource descriptor, but not the descriptor's handle. To free the handle,
/// call <c>CM_Free_Res_Des_Handle_Ex</c>.
/// </para>
/// <para>
/// Callers of this function must have <c>SeLoadDriverPrivilege</c>. (Privileges are described in the Microsoft Windows SDK documentation.)
/// </para>
/// <para>
/// Functionality to access remote machines has been removed in Windows 8 and Windows Server 2012 and later operating systems thus
/// you cannot access remote machines when running on these versions of Windows.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_free_res_des_ex CMAPI CONFIGRET CM_Free_Res_Des_Ex(
// PRES_DES prdResDes, RES_DES rdResDes, ULONG ulFlags, HMACHINE hMachine );
[DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Free_Res_Des_Ex")]
public static extern CONFIGRET CM_Free_Res_Des_Ex([In, Optional] IntPtr prdResDes, RES_DES rdResDes, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// The <c>CM_Free_Res_Des_Handle</c> function invalidates a resource description handle and frees its associated memory allocation.
/// </summary>
@ -2289,7 +2403,7 @@ namespace Vanara.PInvoke
// ulFlags, HMACHINE hMachine );
[DllImport(Lib_Cfgmgr32, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Class_Registry_PropertyW")]
public static extern CONFIGRET CM_Get_Class_Registry_Property(in Guid ClassGuid, CM_DRP ulProperty, out REG_VALUE_TYPE pulRegDataType, [Out, Optional] IntPtr Buffer,
public static extern CONFIGRET CM_Get_Class_Registry_Property(in Guid ClassGuid, CM_CRP ulProperty, out REG_VALUE_TYPE pulRegDataType, [Out, Optional] IntPtr Buffer,
ref uint pulLength, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>

View File

@ -1,4 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@ -356,7 +358,9 @@ namespace Vanara.PInvoke
CM_PROB_GUEST_ASSIGNMENT_FAILED = 0x00000039,
}
/// <summary>configuration flags</summary>
/// <summary>Configuration flags</summary>
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_HW_Prof_FlagsA")]
[Flags]
public enum CSCONFIGFLAG
{
/// <summary>The device instance is disabled in the specified hardware profile.</summary>
@ -367,9 +371,6 @@ namespace Vanara.PInvoke
/// <summary>The device cannot be started in the specified hardware profile.</summary>
CSCONFIGFLAG_DO_NOT_START = 4,
/// <summary>Bitwise OR of the other CSCONFIGFLAG_Xxx flags.</summary>
CSCONFIGFLAG_BITS = 7,
}
/// <summary>
@ -1575,6 +1576,68 @@ namespace Vanara.PInvoke
public static extern CONFIGRET CM_Get_HW_Prof_Flags_Ex([MarshalAs(UnmanagedType.LPTStr)] string pDeviceID, uint ulHardwareProfile, out CSCONFIGFLAG pulValue,
[In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// The <c>CM_Get_Log_Conf_List</c> function obtains the logical configurations, of a specified configuration type, associated with
/// a specified device instance on the local machine.
/// </summary>
/// <param name="dnDevInst">Caller-supplied device instance handle that is bound to the local machine.</param>
/// <param name="ulFlags">
/// <para>
/// Caller-supplied flag value indicating the type of logical configuration being requested. One of the flags in the following table
/// must be specified.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Configuration Type Flags</term>
/// <term>Definitions</term>
/// </listheader>
/// <item>
/// <term>BASIC_LOG_CONF</term>
/// <term>The caller is requesting basic configuration information.</term>
/// </item>
/// <item>
/// <term>FILTERED_LOG_CONF</term>
/// <term>The caller is requesting filtered configuration information.</term>
/// </item>
/// <item>
/// <term>ALLOC_LOG_CONF</term>
/// <term>The caller is requesting allocated configuration information.</term>
/// </item>
/// <item>
/// <term>BOOT_LOG_CONF</term>
/// <term>The caller is requesting boot configuration information.</term>
/// </item>
/// <item>
/// <term>FORCED_LOG_CONF</term>
/// <term>The caller is requesting forced configuration information.</term>
/// </item>
/// <item>
/// <term>OVERRIDE_LOG_CONF</term>
/// <term>The caller is requesting override configuration information.</term>
/// </item>
/// </list>
/// </param>
/// <returns>
/// <para>A sequence of safe handles to a logical configurations.</para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Get_First_Log_Conf</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario.
/// To request information about the hardware resources on a local machine it is necessary implement an architecture-native version
/// of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_First_Log_Conf")]
public static IEnumerable<SafeLOG_CONF> CM_Get_Log_Conf_List(uint dnDevInst, LOG_CONF_FLAG ulFlags)
{
CONFIGRET ret = CM_Get_First_Log_Conf(out var lc, dnDevInst, ulFlags);
if (ret == CONFIGRET.CR_NO_MORE_LOG_CONF)
yield break;
ret.ThrowIfFailed();
yield return lc;
while ((ret = CM_Get_Next_Log_Conf(out lc, lc)) == CONFIGRET.CR_SUCCESS)
yield return lc;
if (ret != CONFIGRET.CR_NO_MORE_LOG_CONF) ret.ThrowIfFailed();
}
/// <summary>
/// The <c>CM_Get_Log_Conf_Priority</c> function obtains the configuration priority of a specified logical configuration on the
/// local machine.
@ -1937,6 +2000,54 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Next_Res_Des")]
public static extern CONFIGRET CM_Get_Next_Res_Des(out SafeRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, out RESOURCEID pResourceID, uint ulFlags = 0);
/// <summary>
/// The <c>CM_Get_Next_Res_Des</c> function obtains a handle to the next resource descriptor, of a specified resource type, for a
/// logical configuration on the local machine.
/// </summary>
/// <param name="prdResDes">Pointer to a location to receive a resource descriptor handle.</param>
/// <param name="rdResDes">
/// Caller-supplied handle to either a resource descriptor or a logical configuration. For more information, see the following
/// <c>Remarks</c> section.
/// </param>
/// <param name="ForResource">
/// Caller-supplied resource type identifier, indicating the type of resource descriptor being requested. This must be one of the
/// <c>ResType_</c>-prefixed constants defined in Cfgmgr32.h.
/// </param>
/// <param name="pResourceID">
/// Pointer to a location to receive a resource type identifier, if ForResource specifies <c>ResType_All</c>. For any other
/// ForResource value, callers should set this to <c>NULL</c>.
/// </param>
/// <param name="ulFlags">Not used, must be zero.</param>
/// <returns>
/// <para>
/// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in Cfgmgr32.h.
/// </para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Get_Next_Res_Des</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario.
/// To request information about the hardware resources on a local machine it is necessary implement an architecture-native version
/// of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// To enumerate a logical configuration's resource descriptors, begin by calling <c>CM_Get_Next_Res_Des</c> with the logical
/// configuration's handle as the argument for rdResDes. This obtains a handle to the first resource descriptor of the type
/// specified by ForResource. Then for each subsequent call to <c>CM_Get_Next_Res_Des</c>, specify the most recently obtained
/// descriptor handle as the argument for rdResDes. Repeat until the function returns CR_NO_MORE_RES_DES.
/// </para>
/// <para>To retrieve the information stored in a resource descriptor, call CM_Get_Res_Des_Data.</para>
/// <para>To modify the information stored in a resource descriptor, call CM_Modify_Res_Des.</para>
/// <para>
/// Callers of <c>CM_Get_Next_Res_Des</c> must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it is
/// no longer needed.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_get_next_res_des CMAPI CONFIGRET CM_Get_Next_Res_Des(
// PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, PRESOURCEID pResourceID, ULONG ulFlags );
[DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Next_Res_Des")]
public static extern CONFIGRET CM_Get_Next_Res_Des(out SafeRES_DES prdResDes, LOG_CONF rdResDes, RESOURCEID ForResource, out RESOURCEID pResourceID, uint ulFlags = 0);
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Get_Next_Res_Des instead.]</para>
/// <para>
@ -2000,6 +2111,69 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Next_Res_Des_Ex")]
public static extern CONFIGRET CM_Get_Next_Res_Des_Ex(out SafeRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, out RESOURCEID pResourceID, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Get_Next_Res_Des instead.]</para>
/// <para>
/// The <c>CM_Get_Next_Res_Des_Ex</c> function obtains a handle to the next resource descriptor, of a specified resource type, for a
/// logical configuration on a local or a remote machine.
/// </para>
/// </summary>
/// <param name="prdResDes">Pointer to a location to receive a resource descriptor handle.</param>
/// <param name="rdResDes">
/// Caller-supplied handle to either a resource descriptor or a logical configuration. For more information, see the following
/// <c>Remarks</c> section.
/// </param>
/// <param name="ForResource">
/// Caller-supplied resource type identifier, indicating the type of resource descriptor being requested. This must be one of the
/// ResType_-prefixed constants defined in Cfgmgr32.h.
/// </param>
/// <param name="pResourceID">
/// Pointer to a location to receive a resource type identifier, if ForResource specifies <c>ResType_All</c>. For any other
/// ForResource value, callers should set this to <c>NULL</c>.
/// </param>
/// <param name="ulFlags">Not used, must be zero.</param>
/// <param name="hMachine">
/// <para>Caller-supplied machine handle, obtained from a previous call to CM_Connect_Machine.</para>
/// <para>
/// <c>Note</c> Using this function to access remote machines is not supported beginning with Windows 8 and Windows Server 2012, as
/// this functionality has been removed.
/// </para>
/// </param>
/// <returns>
/// <para>
/// If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in Cfgmgr32.h.
/// </para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Get_Next_Res_Des_Ex</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64
/// scenario. To request information about the hardware resources on a local machine it is necessary implement an
/// architecture-native version of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// To enumerate a logical configuration's resource descriptors, begin by calling <c>CM_Get_Next_Res_Des_Ex</c> with the logical
/// configuration's handle as the argument for rdResDes. This obtains a handle to the first resource descriptor of the type
/// specified by ForResource. Then for each subsequent call to <c>CM_Get_Next_Res_Des_Ex</c>, specify the most recently obtained
/// descriptor handle as the argument for rdResDes. Repeat until the function returns CR_NO_MORE_RES_DES.
/// </para>
/// <para>To retrieve the information stored in a resource descriptor, call CM_Get_Res_Des_Data_Ex.</para>
/// <para>To modify the information stored in a resource descriptor, call CM_Modify_Res_Des_Ex.</para>
/// <para>
/// Callers of <c>CM_Get_Next_Res_Des_Ex</c> must call CM_Free_Res_Des_Handle to deallocate the resource descriptor handle, after it
/// is no longer needed.
/// </para>
/// <para>
/// Functionality to access remote machines has been removed in Windows 8 and Windows Server 2012 and later operating systems thus
/// you cannot access remote machines when running on these versions of Windows.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_get_next_res_des_ex CMAPI CONFIGRET
// CM_Get_Next_Res_Des_Ex( PRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ForResource, PRESOURCEID pResourceID, ULONG ulFlags,
// HMACHINE hMachine );
[DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Next_Res_Des_Ex")]
public static extern CONFIGRET CM_Get_Next_Res_Des_Ex(out SafeRES_DES prdResDes, LOG_CONF rdResDes, RESOURCEID ForResource, out RESOURCEID pResourceID, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Get_Parent instead.]</para>
/// <para>
@ -2064,6 +2238,30 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Res_Des_Data")]
public static extern CONFIGRET CM_Get_Res_Des_Data(RES_DES rdResDes, [Out] IntPtr Buffer, uint BufferLen, uint ulFlags = 0);
/// <summary>
/// The <c>CM_Get_Res_Des_Data</c> function retrieves the information stored in a resource descriptor on the local machine.
/// </summary>
/// <typeparam name="T">The type of the data to retrieve.</typeparam>
/// <param name="rdResDes">Caller-supplied handle to a resource descriptor, obtained by a previous call to CM_Get_Next_Res_Des.</param>
/// <returns>
/// <para>
/// Returns the structure specified in as the contents of the resource descriptor.
/// </para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Get_Res_Des_Data</c> throws CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario.
/// To request information about the hardware resources on a local machine it is necessary implement an architecture-native version
/// of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Res_Des_Data")]
public static T CM_Get_Res_Des_Data<T>(RES_DES rdResDes) where T : struct
{
CM_Get_Res_Des_Data_Size(out var size, rdResDes).ThrowIfFailed();
using var mem = new SafeCoTaskMemHandle(size);
CM_Get_Res_Des_Data(rdResDes, mem, size).ThrowIfFailed();
return mem.ToStructure<T>();
}
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Get_Res_Des_Data instead.]</para>
/// <para>
@ -2184,6 +2382,38 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Res_Des_Data_Size_Ex")]
public static extern CONFIGRET CM_Get_Res_Des_Data_Size_Ex(out uint pulSize, RES_DES rdResDes, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// The <c>CM_Get_Next_Res_Des</c> function obtains a handle to the next resource descriptor, of a specified resource type, for a
/// logical configuration on the local machine.
/// </summary>
/// <param name="lcLogConf">Handle to a logical configuration.</param>
/// <param name="ForResource">
/// Caller-supplied resource type identifier, indicating the type of resource descriptor being requested. This must be one of the
/// <c>ResType_</c>-prefixed constants defined in Cfgmgr32.h.
/// </param>
/// <returns>A sequence of resource descriptor handles and their associated resource type identifiers.</returns>
/// <remarks>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Get_Next_Res_Des</c> returns CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario.
/// To request information about the hardware resources on a local machine it is necessary implement an architecture-native version
/// of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// <para>To retrieve the information stored in a resource descriptor, call CM_Get_Res_Des_Data.</para>
/// <para>To modify the information stored in a resource descriptor, call CM_Modify_Res_Des.</para>
/// </remarks>
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Get_Next_Res_Des")]
public static IEnumerable<(SafeRES_DES prdResDes, RESOURCEID pResourceID)> CM_Get_Res_Des_List([In] LOG_CONF lcLogConf, RESOURCEID ForResource = RESOURCEID.ResType_All)
{
CONFIGRET ret = CM_Get_Next_Res_Des(out var rd, lcLogConf, ForResource, out var resId);
if (ret == CONFIGRET.CR_NO_MORE_RES_DES)
yield break;
ret.ThrowIfFailed();
yield return (rd, resId);
while ((ret = CM_Get_Next_Res_Des(out rd, rd, ForResource, out resId)) == CONFIGRET.CR_SUCCESS)
yield return (rd, resId);
if (ret != CONFIGRET.CR_NO_MORE_RES_DES) ret.ThrowIfFailed();
}
/// <summary>
/// The <c>CM_Get_Resource_Conflict_Count</c> function obtains the number of conflicts contained in a specified resource conflict list.
/// </summary>

View File

@ -2,6 +2,7 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.SetupAPI;
@ -1103,6 +1104,58 @@ namespace Vanara.PInvoke
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Modify_Res_Des")]
public static extern CONFIGRET CM_Modify_Res_Des(out SafeRES_DES prdResDes, RES_DES rdResDes, RESOURCEID ResourceID, [In] IntPtr ResourceData, uint ResourceLen, uint ulFlags = 0);
/// <summary>The <c>CM_Modify_Res_Des</c> function modifies a specified resource descriptor on the local machine.</summary>
/// <typeparam name="T">The type of the data.</typeparam>
/// <param name="rdResDes">
/// <para>
/// Caller-supplied handle to the resource descriptor to be modified. This handle must have been previously obtained by calling one
/// of the following functions:
/// </para>
/// <para>CM_Add_Res_Des</para>
/// <para>CM_Add_Res_Des_Ex</para>
/// <para>CM_Get_Next_Res_Des</para>
/// <para>CM_Get_Next_Res_Des_Ex</para>
/// <para><c>CM_Modify_Res_Des</c></para>
/// <para>CM_Modify_Res_Des_Ex</para>
/// </param>
/// <param name="data">
/// Caller-supplied pointer to a resource descriptor, which can be one of the structures listed under the CM_Add_Res_Des function's
/// description of ResourceData.
/// </param>
/// <param name="ResourceID">
/// Caller-supplied resource type identifier. This must be one of the <c>ResType_</c>-prefixed constants defined in Cfgmgr32.h.
/// </param>
/// <returns>
/// <para>A handle to the modified resource descriptor.</para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Modify_Res_Des</c> throws CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario. To
/// request information about the hardware resources on a local machine it is necessary implement an architecture-native version of
/// the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <exception cref="ArgumentException">Unable to determine RESOURCEID from type. - T</exception>
/// <remarks>
/// <para>
/// The caller-supplied resource descriptor data replaces the existing data. The values specified for ResourceID and ResourceLen do
/// not have to match the existing resource descriptor.
/// </para>
/// <para>
/// If the value specified for ResourceID is <c>ResType_ClassSpecific</c>, then the specified resource descriptor must be the last
/// one associated with the logical configuration.
/// </para>
/// <para>
/// Callers of this function must have <c>SeLoadDriverPrivilege</c>. (Privileges are described in the Microsoft Windows SDK documentation.)
/// </para>
/// </remarks>
public static SafeRES_DES CM_Modify_Res_Des<T>(RES_DES rdResDes, T data, RESOURCEID ResourceID = 0) where T : struct
{
if (ResourceID == 0 && !CorrespondingTypeAttribute.CanSet<T, RESOURCEID>(out ResourceID))
throw new ArgumentException("Unable to determine RESOURCEID from type.", nameof(T));
using var mem = new SafeAnysizeStruct<T>(data);
CM_Modify_Res_Des(out var hRD, rdResDes, ResourceID, mem, mem.Size).ThrowIfFailed();
return hRD;
}
/// <summary>
/// <para>[Beginning with Windows 8 and Windows Server 2012, this function has been deprecated. Please use CM_Modify_Res_Des instead.]</para>
/// <para>The <c>CM_Modify_Res_Des_Ex</c> function modifies a specified resource descriptor on a local or a remote machine.</para>
@ -1684,8 +1737,53 @@ namespace Vanara.PInvoke
// ULONG ResourceLen, ULONG ulFlags, HMACHINE hMachine );
[DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Query_Resource_Conflict_List")]
public static extern CONFIGRET CM_Query_Resource_Conflict_List(out SafeCONFLICT_LIST pclConflictList, uint dnDevInst, RESOURCEID ResourceID, IntPtr ResourceData,
uint ResourceLen, uint ulFlags, [In, Optional] HMACHINE hMachine);
public static extern CONFIGRET CM_Query_Resource_Conflict_List(out SafeCONFLICT_LIST pclConflictList, uint dnDevInst, RESOURCEID ResourceID, [In] IntPtr ResourceData,
uint ResourceLen, [In, Optional] uint ulFlags, [In, Optional] HMACHINE hMachine);
/// <summary>
/// The <c>CM_Query_Resource_Conflict_List</c> function identifies device instances having resource requirements that conflict with
/// a specified device instance's resource description.
/// </summary>
/// <typeparam name="T">The type of the supplied data.</typeparam>
/// <param name="dnDevInst">Caller-supplied device instance handle that is bound to the machine handle supplied by hMachine.</param>
/// <param name="data">
/// Caller-supplied pointer to a resource descriptor, which can be one of the structures listed under the CM_Add_Res_Des function's
/// description of ResourceData.
/// </param>
/// <param name="ResourceID">
/// Caller-supplied resource type identifier. If <c>0</c>, then the <see cref="RESOURCEID"/> is determined by <typeparamref name="T"/>.
/// </param>
/// <returns>
/// <para>A handle to a conflict list.</para>
/// <para>
/// <c>Note</c> Starting with Windows 8, <c>CM_Query_Resource_Conflict_List</c> throws CR_CALL_NOT_IMPLEMENTED when used in a Wow64
/// scenario. To request information about the hardware resources on a local machine it is necessary implement an
/// architecture-native version of the application using the hardware resource APIs. For example: An AMD64 application for AMD64 systems.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// When calling <c>CM_Query_Resource_Conflict_List</c>, specify a device instance handle and resource descriptor. (Resource
/// descriptors for existing device nodes can be obtained by calling CM_Get_Res_Des_Data.) These parameters indicate the specific
/// resources you'd like a specific device to use. The resulting conflict list identifies devices that use the same resources, along
/// with resources reserved by the machine.
/// </para>
/// <para>
/// After calling <c>CM_Query_Resource_Conflict_List</c>, an application can call CM_Get_Resource_Conflict_Count to determine the
/// number of conflicts contained in the resource conflict list. (The number of conflicts can be zero.) Then the application can
/// call CM_Get_Resource_Conflict_Details for each entry in the conflict list.
/// </para>
/// <para>For information about using device instance handles that are bound to a local or a remote machine, see CM_Get_Child_Ex.</para>
/// </remarks>
[PInvokeData("cfgmgr32.h", MSDNShortId = "NF:cfgmgr32.CM_Query_Resource_Conflict_List")]
public static SafeCONFLICT_LIST CM_Query_Resource_Conflict_List<T>(uint dnDevInst, T data, RESOURCEID ResourceID = 0) where T : struct
{
if (ResourceID == 0 && !CorrespondingTypeAttribute.CanSet<T, RESOURCEID>(out ResourceID))
throw new ArgumentException("Unable to determine RESOURCEID from type.", nameof(T));
using var mem = new SafeAnysizeStruct<T>(data);
CM_Query_Resource_Conflict_List(out var hcl, dnDevInst, ResourceID, mem, mem.Size).ThrowIfFailed();
return hcl;
}
/// <summary>
/// The <c>CM_Reenumerate_DevNode</c> function enumerates the devices identified by a specified device node and all of its children.

View File

@ -522,6 +522,7 @@ namespace Vanara.PInvoke
/// <c>BusQueryInstanceID</c>. Because all software devices are considered "UniqueId" devices, this string must be a unique name
/// for all devices on this software device enumerator. For more info, see Instance IDs.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string pszInstanceId;
/// <summary>
@ -529,8 +530,9 @@ namespace Vanara.PInvoke
/// <c>BusQueryHardwareIDs</c>. If a client expects a driver or device metadata to bind to the device, the client specifies
/// hardware IDs.
/// </summary>
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))]
public string[] pszzHardwareIds;
//[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))]
//public string[] pszzHardwareIds;
public IntPtr pszzHardwareIds;
/// <summary>
/// A list of strings for the compatible IDs for the software device. This value is used for IRP_MN_QUERY_ID
@ -539,8 +541,9 @@ namespace Vanara.PInvoke
/// addition to the compatible IDs specified in this member, SWD\Generic and possibly SWD\GenericRaw will always be added as the
/// least specific compatible IDs.
/// </summary>
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))]
public string[] pszzCompatibleIds;
//[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))]
//public string[] pszzCompatibleIds;
public IntPtr pszzCompatibleIds;
/// <summary>
/// A value that is used to control the base container ID for the software device. This value will be used for IRP_MN_QUERY_ID
@ -616,6 +619,7 @@ namespace Vanara.PInvoke
/// We recommend that this string be a reference to a localizable resource. For the syntax of referencing resources, see DEVPROP_TYPE_STRING_INDIRECT.
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string pszDeviceDescription;
/// <summary>
@ -625,6 +629,7 @@ namespace Vanara.PInvoke
/// </para>
/// <para><c>Note</c> Specifying a location is uncommon.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string pszDeviceLocation;
/// <summary>

View File

@ -4,8 +4,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
@ -19,89 +17,93 @@ namespace Vanara.PInvoke.Tests
{
private static readonly Guid devguid = GUID_DEVCLASS_DISKDRIVE;
private static readonly Lazy<uint> leaf = new(() => GetFirstLeaf(root.Value));
private static readonly Lazy<uint> node = new(() => LocateNode(@"USB\ROOT_HUB30\4&3490C39&0&0"));
private static readonly Lazy<uint> node = new(() => LocateNode(@"SWD\PRINTENUM\WSD-F442E38C-F139-42D3-BCCC-A3653929E4B7")); //@"USB\ROOT_HUB30\4&3490C39&0&0"));
private static readonly Lazy<uint> root = new(() => LocateNode());
private ElevPriv priv;
public static uint LeafId => leaf.Value;
public static uint NodeId => node.Value;
public static uint RootId => root.Value;
private static uint LocateNode(string devId = null)
{
CM_Locate_DevNode(out var di, devId, CM_LOCATE_DEVNODE.CM_LOCATE_DEVNODE_NORMAL).ThrowIfFailed();
return di;
}
[OneTimeSetUp]
public void _Setup()
{
priv = new ElevPriv("SeLoadDriverPrivilege");
}
public void _Setup() => priv = new ElevPriv("SeLoadDriverPrivilege");
[OneTimeTearDown]
public void _TearDown()
{
priv?.Dispose();
}
public void _TearDown() => priv?.Dispose();
[Test]
public void StructSizeTest() => TestContext.Write(string.Join("\n", TestHelper.GetNestedStructSizes(typeof(CfgMgr32))));
public void ClassesWithInterfacesTest()
{
foreach (System.Reflection.FieldInfo fi in typeof(SetupAPI).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).
Where(fi => fi.FieldType == typeof(Guid) && fi.Name.StartsWith("GUID_DEVINTERFACE_")))
{
CONFIGRET ret = CM_Get_Device_Interface_List_Size(out var len, (Guid)fi.GetValue(null), default, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (ret == CONFIGRET.CR_SUCCESS && len > 2)
TestContext.WriteLine($"{fi.Name}={len}");
}
}
[Test]
public void CM_Add_Empty_Log_ConfTest()
{
Assert.That(CM_Add_Empty_Log_Conf(out SafeLOG_CONF hConf, LeafId, PRIORITY.LCPRI_NORMAL, LOG_CONF_FLAG.BASIC_LOG_CONF), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(() => hConf.Dispose(), Throws.Nothing);
Assert.That(CM_Add_Empty_Log_Conf(out SafeLOG_CONF hConf, NodeId, PRIORITY.LCPRI_NORMAL, LOG_CONF_FLAG.BASIC_LOG_CONF), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
Assert.That(CM_Get_Log_Conf_Priority(hConf, out PRIORITY p), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(PRIORITY.LCPRI_NORMAL, Is.EqualTo(p));
}
finally
{
Assert.That(CM_Free_Log_Conf(hConf), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(() => hConf.Dispose(), Throws.Nothing);
}
}
[Test]
public void CM_Add_Res_DesTest()
{
Assert.That(CM_Add_Empty_Log_Conf(out var BootLC1, NodeId, PRIORITY.LCPRI_NORMAL, LOG_CONF_FLAG.BOOT_LOG_CONF), Is.EqualTo(CONFIGRET.CR_SUCCESS));
var memRes = new MEM_RESOURCE
Assert.That(CM_Add_Empty_Log_Conf(out SafeLOG_CONF BootLC1, NodeId, PRIORITY.LCPRI_BOOTCONFIG, LOG_CONF_FLAG.BOOT_LOG_CONF | LOG_CONF_FLAG.PRIORITY_EQUAL_FIRST), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
MEM_Header = new MEM_DES
{
MD_Count = 2,
MD_Type = MType_Range,
MD_Alloc_Base = 0xD8000,
MD_Alloc_End = 0xD9000,
MD_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MD_Reserved = 0
},
MEM_Data = new MEM_RANGE[]
{
new MEM_RANGE
{
MR_Align = 8, //?
MR_nBytes = 4096,
MR_Min = 0xD8000,
MR_Max = 0xDC000,
MR_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MR_Reserved = 0
},
MEM_RESOURCE memRes = MakeResource();
new MEM_RANGE
{
MR_Align = 8, //?
MR_nBytes = 4096,
MR_Min = 0xE0000,
MR_Max = 0xE4000,
MR_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MR_Reserved = 0
}
SafeRES_DES hRD = null;
Assert.That(() => hRD = CM_Add_Res_Des(BootLC1, memRes), Throws.Nothing);
try
{
var list = new (SafeRES_DES prdResDes, RESOURCEID pResourceID)[0];
Assert.That(() => list = CM_Get_Res_Des_List(BootLC1).ToArray(), Throws.Nothing);
Assert.That(list, Is.Not.Empty);
Assert.That(list[0].pResourceID, Is.EqualTo(RESOURCEID.ResType_Mem));
MEM_RESOURCE retMemRes = default;
Assert.That(() => retMemRes = CM_Get_Res_Des_Data<MEM_RESOURCE>(list[0].prdResDes), Throws.Nothing);
Assert.That(retMemRes.MEM_Data.Length, Is.EqualTo(memRes.MEM_Data.Length));
memRes.MEM_Data[0].MR_Min = 0xDA00;
memRes.MEM_Data[0].MR_Max = 0xDE00;
Assert.That(() => hRD = CM_Modify_Res_Des(list[0].prdResDes, memRes), Throws.Nothing);
}
};
finally
{
CM_Free_Res_Des(IntPtr.Zero, hRD);
hRD?.Dispose();
}
}
finally
{
CM_Free_Log_Conf(BootLC1);
BootLC1.Dispose();
}
}
SafeRES_DES hRD = null;
Assert.That(() => hRD = CM_Add_Res_Des(BootLC1, memRes), Throws.Nothing);
hRD?.Dispose();
BootLC1.Dispose();
[Test]
public void CM_Clear_Log_Conf_List()
{
var lc = new SafeLOG_CONF[0];
Assert.That(() => lc = CM_Get_Log_Conf_List(NodeId, LOG_CONF_FLAG.BOOT_LOG_CONF).ToArray(), Throws.Nothing);
foreach (SafeLOG_CONF l in lc)
CM_Free_Log_Conf(l);
}
[Test]
@ -114,8 +116,8 @@ namespace Vanara.PInvoke.Tests
[Test]
public void CM_Enable_DevNodeTest()
{
Assert.That(CM_Disable_DevNode(LeafId), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(CM_Enable_DevNode(LeafId), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(CM_Disable_DevNode(NodeId), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(CM_Enable_DevNode(NodeId), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
[Test]
@ -160,19 +162,6 @@ namespace Vanara.PInvoke.Tests
}
}
[Test]
public void CM_Get_Class_PropertyTest()
{
var cls = devguid;
var pkey = DEVPKEY_DeviceClass_IconPath;
var sz = 0U;
Assert.That(CM_Get_Class_Property(cls, pkey, out var dpType, default, ref sz, CM_CLASS_PROPERTY.CM_CLASS_PROPERTY_INSTALLER), Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
using var mem = new SafeCoTaskMemHandle(sz * StringHelper.GetCharSize());
Assert.That(CM_Get_Class_Property(cls, pkey, out _, mem, ref sz, CM_CLASS_PROPERTY.CM_CLASS_PROPERTY_INSTALLER), Is.EqualTo(CONFIGRET.CR_SUCCESS));
TestContext.WriteLine($"{cls}: Type={dpType}, Size={sz}");
mem.ToStringEnum().WriteValues();
}
[Test]
public void CM_Get_Class_Property_KeysTest()
{
@ -184,28 +173,57 @@ namespace Vanara.PInvoke.Tests
}
[Test]
public void CM_Get_Class_Registry_PropertyTest()
public void CM_GetSet_Class_PropertyTest()
{
var cls = devguid;
var prop = CM_DRP.CM_DRP_CAPABILITIES;
Guid cls = devguid;
DEVPROPKEY pkey = DEVPKEY_DeviceClass_IconPath;
// Get value
var sz = 0U;
Assert.That(CM_Get_Class_Registry_Property(cls, prop, out var dpType, default, ref sz), Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
using var mem = new SafeCoTaskMemHandle(sz * StringHelper.GetCharSize());
Assert.That(CM_Get_Class_Registry_Property(cls, prop, out _, mem, ref sz), Is.EqualTo(CONFIGRET.CR_SUCCESS));
TestContext.WriteLine($"{cls}: Type={dpType}, Size={sz}");
TestContext.Write(mem.Dump);
Assert.That(CM_Get_Class_Property(cls, pkey, out DEVPROPTYPE dpType, default, ref sz, CM_CLASS_PROPERTY.CM_CLASS_PROPERTY_INSTALLER), Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
var strings = new string[0];
using (var mem = new SafeCoTaskMemHandle(sz * StringHelper.GetCharSize()))
{
Assert.That(CM_Get_Class_Property(cls, pkey, out _, mem, ref sz, CM_CLASS_PROPERTY.CM_CLASS_PROPERTY_INSTALLER), Is.EqualTo(CONFIGRET.CR_SUCCESS));
TestContext.WriteLine($"{cls}: Type={dpType}, Size={sz}");
strings = mem.ToStringEnum().ToArray();
strings.WriteValues();
}
// Set bogus value
using (var mem = SafeCoTaskMemHandle.CreateFromStringList(new[] { "A", "B" }))
{
Assert.That(CM_Set_Class_Property(devguid, pkey, DEVPROPTYPE.DEVPROP_TYPE_STRING_LIST, mem, mem.Size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
// Reset correct value
using (var mem = SafeCoTaskMemHandle.CreateFromStringList(strings))
{
Assert.That(CM_Set_Class_Property(devguid, pkey, DEVPROPTYPE.DEVPROP_TYPE_STRING_LIST, mem, mem.Size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
}
[Test]
public void CM_Get_Device_IDTest()
public void CM_GetSet_Class_Registry_PropertyTest()
{
var di = RootId;
Assert.That(CM_Get_Device_ID_Size(out var len, di), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(len, Is.Not.Zero);
var sb = new StringBuilder((int)len+1);
Assert.That(CM_Get_Device_ID(di, sb, len+1), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(sb.Length, Is.Not.Zero);
TestContext.Write($"ID: {di} ({sb})");
Guid cls = devguid;
CM_CRP prop = CM_CRP.CM_CRP_CHARACTERISTICS;
var sz = 0U;
Assert.That(CM_Get_Class_Registry_Property(cls, prop, out _, default, ref sz), Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
uint val = 0;
using (var mem = new SafeCoTaskMemHandle(sz * StringHelper.GetCharSize()))
{
Assert.That(CM_Get_Class_Registry_Property(cls, prop, out REG_VALUE_TYPE dpType, mem, ref sz), Is.EqualTo(CONFIGRET.CR_SUCCESS));
TestContext.WriteLine($"{cls}: Type={dpType}, Size={sz}");
TestContext.Write(val = (uint)dpType.GetValue(mem, mem.Size));
}
using (var mem = SafeCoTaskMemHandle.CreateFromStructure(val > 0 ? 0U : 256))
Assert.That(CM_Set_Class_Registry_Property(cls, prop, mem, mem.Size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
using (var mem = SafeCoTaskMemHandle.CreateFromStructure(val))
Assert.That(CM_Set_Class_Registry_Property(cls, prop, mem, mem.Size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
[Test]
@ -217,99 +235,131 @@ namespace Vanara.PInvoke.Tests
TestContext.Write(string.Join("\n", mem.ToStringEnum()));
}
[Test]
public void CM_Get_Device_IDTest()
{
var di = RootId;
Assert.That(CM_Get_Device_ID_Size(out var len, di), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(len, Is.Not.Zero);
var sb = new StringBuilder((int)len + 1);
Assert.That(CM_Get_Device_ID(di, sb, len + 1), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(sb.Length, Is.Not.Zero);
TestContext.Write($"ID: {di} ({sb})");
}
[Test]
public void CM_Get_Device_Interface_AliasTest()
{
//Assert.That(CM_Get_Device_Interface_Alias(), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
public void ClassesWithInterfacesTest()
[Test]
public void CM_Get_Device_Interface_PropertiesTest() => Assert.That(() =>
{
foreach (var fi in typeof(SetupAPI).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).
Where(fi => fi.FieldType == typeof(Guid) && fi.Name.StartsWith("GUID_DEVINTERFACE_")))
foreach (var devInt in CM_Get_Device_Interface_List(GUID_DEVINTERFACE_NET, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
var ret = CM_Get_Device_Interface_List_Size(out var len, (Guid)fi.GetValue(null), default, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (ret == CONFIGRET.CR_SUCCESS && len > 2)
TestContext.WriteLine($"{fi.Name}={len}");
TestContext.WriteLine(devInt);
uint size = 0;
CONFIGRET ret = CM_Get_Device_Interface_Property_Keys(devInt, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
var keys = new DEVPROPKEY[size];
Assert.That(CM_Get_Device_Interface_Property_Keys(devInt, keys, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
foreach (DEVPROPKEY key in keys)
{
TestContext.Write($" {key} ({(key.TryGetReadOnly(out var ro) ? (ro ? "R" : "RW") : "?")}): ");
size = 0;
ret = CM_Get_Device_Interface_Property(devInt, key, out DEVPROPTYPE pType, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
using var mem = new SafeCoTaskMemHandle((int)size);
Assert.That(CM_Get_Device_Interface_Property(devInt, key, out _, mem, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
var o = pType.GetObject(mem);
TestContext.WriteLine(o is null ? "(null)" : (o.GetType().IsArray ? string.Join(", ", ((Array)o).Cast<object>()) : (o is string s ? $"\"{s}\"" : o)));
}
catch { TestContext.WriteLine($"{pType} CONVERSION FAILED ({mem.Size})"); }
}
}
}, Throws.Nothing);
[Test]
public void CM_Set_Device_Interface_PropertyTest()
{
var devInt = CM_Get_Device_Interface_List(GUID_DEVINTERFACE_VOLUME, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT).First();
DEVPROPKEY pkey = DEVPKEY_DeviceInterface_FriendlyName;
using var mem = new SafeCoTaskMemString(256, System.Runtime.InteropServices.CharSet.Auto);
uint sz = mem.Size;
Assert.That(CM_Get_Device_Interface_Property(devInt, pkey, out var dpt, mem, ref sz), Is.EqualTo(CONFIGRET.CR_SUCCESS).Or.EqualTo(CONFIGRET.CR_NO_SUCH_VALUE));
var orig = mem.ToString();
mem.Set("DUMMY_VALUE$$");
Assert.That(CM_Set_Device_Interface_Property(devInt, pkey, DEVPROPTYPE.DEVPROP_TYPE_STRING, mem, (uint)((mem.Length + 1) * StringHelper.GetCharSize())), Is.EqualTo(CONFIGRET.CR_SUCCESS));
if (string.IsNullOrEmpty(orig))
Assert.That(CM_Set_Device_Interface_Property(devInt, pkey, DEVPROPTYPE.DEVPROP_TYPE_STRING, IntPtr.Zero, 0), Is.EqualTo(CONFIGRET.CR_SUCCESS));
else
{
mem.Set(orig);
Assert.That(CM_Set_Device_Interface_Property(devInt, pkey, DEVPROPTYPE.DEVPROP_TYPE_STRING, mem, (uint)((mem.Length + 1) * StringHelper.GetCharSize())), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
}
[Test]
public void CM_Get_Device_Interface_PropertiesTest()
public void CM_Set_DevNode_PropertyTest()
{
Assert.That(() =>
var devInt = NodeId;
var pkey = DEVPKEY_DeviceInterface_Enabled;
unsafe
{
foreach (var devInt in CM_Get_Device_Interface_List(GUID_DEVINTERFACE_VOLUME, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
TestContext.WriteLine(devInt);
uint size = 0;
var ret = CM_Get_Device_Interface_Property_Keys(devInt, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
var keys = new DEVPROPKEY[size];
Assert.That(CM_Get_Device_Interface_Property_Keys(devInt, keys, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
foreach (var key in keys)
{
TestContext.Write($" {key}: ");
size = 0;
ret = CM_Get_Device_Interface_Property(devInt, key, out DEVPROPTYPE pType, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
using var mem = new SafeCoTaskMemHandle((int)size);
Assert.That(CM_Get_Device_Interface_Property(devInt, key, out _, mem, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
var o = pType.GetObject(mem);
TestContext.WriteLine(o is null ? "(null)" : (o.GetType().IsArray ? string.Join(", ", ((Array)o).Cast<object>()) : (o is string s ? $"\"{s}\"" : o)));
} catch { TestContext.WriteLine($"{pType} CONVERSION FAILED ({mem.Size})"); }
}
}
}, Throws.Nothing);
byte boolVal = 0;
uint sz = 1;
Assert.That(CM_Get_DevNode_Property(devInt, pkey, out var dpt, (IntPtr)(&boolVal), ref sz), Is.EqualTo(CONFIGRET.CR_SUCCESS));
byte newBoolVal = boolVal == 0 ? (byte)1 : (byte)0;
Assert.That(CM_Set_DevNode_Property(devInt, pkey, dpt, (IntPtr)(&newBoolVal), 1), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(CM_Set_DevNode_Property(devInt, pkey, dpt, (IntPtr)(&boolVal), 1), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
}
[Test]
public void CM_Get_DevNode_PropertiesTest()
public void CM_Get_DevNode_PropertiesTest() => Assert.That(() =>
{
Assert.That(() =>
foreach (var devId in CM_Get_Device_ID_List())
{
foreach (var devId in CM_Get_Device_ID_List())
{
if (CM_Locate_DevNode(out var devInst, devId) != CONFIGRET.CR_SUCCESS)
continue;
TestContext.WriteLine($"{devId} ({devInst})");
if (CM_Locate_DevNode(out var devInst, devId) != CONFIGRET.CR_SUCCESS)
continue;
TestContext.WriteLine($"{devId} ({devInst})");
uint size = 0;
var ret = CM_Get_DevNode_Property_Keys(devInst, default, ref size);
uint size = 0;
CONFIGRET ret = CM_Get_DevNode_Property_Keys(devInst, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
var keys = new DEVPROPKEY[size];
Assert.That(CM_Get_DevNode_Property_Keys(devInst, keys, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
foreach (DEVPROPKEY key in keys)
{
TestContext.Write($" {key}: ");
size = 0;
ret = CM_Get_DevNode_Property(devInst, key, out DEVPROPTYPE pType, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
var keys = new DEVPROPKEY[size];
Assert.That(CM_Get_DevNode_Property_Keys(devInst, keys, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
foreach (var key in keys)
using var mem = new SafeCoTaskMemHandle((int)size);
Assert.That(CM_Get_DevNode_Property(devInst, key, out _, mem, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
TestContext.Write($" {key}: ");
size = 0;
ret = CM_Get_DevNode_Property(devInst, key, out DEVPROPTYPE pType, default, ref size);
if (ret == CONFIGRET.CR_NO_SUCH_VALUE) continue;
Assert.That(ret, Is.EqualTo(CONFIGRET.CR_BUFFER_SMALL));
Assert.That(size, Is.GreaterThan(0));
using var mem = new SafeCoTaskMemHandle((int)size);
Assert.That(CM_Get_DevNode_Property(devInst, key, out _, mem, ref size), Is.EqualTo(CONFIGRET.CR_SUCCESS));
try
{
var o = pType.GetObject(mem);
TestContext.WriteLine(o is null ? "(null)" : (o.GetType().IsArray ? string.Join(", ", ((Array)o).Cast<object>()) : (o is string s ? $"\"{s}\"" : o)));
}
catch { TestContext.WriteLine($"{pType} CONVERSION FAILED ({mem.Size})"); }
var o = pType.GetObject(mem);
TestContext.WriteLine(o is null ? "(null)" : (o.GetType().IsArray ? string.Join(", ", ((Array)o).Cast<object>()) : (o is string s ? $"\"{s}\"" : o)));
}
catch { TestContext.WriteLine($"{pType} CONVERSION FAILED ({mem.Size})"); }
}
}, Throws.Nothing);
}
}
}, Throws.Nothing);
[Test]
public void CM_Get_DevNode_Registry_PropertyTest()
@ -334,6 +384,69 @@ namespace Vanara.PInvoke.Tests
TestContext.Write($"{stat} : {prob}");
}
[Test]
public void CM_Get_HW_Prof_FlagsTest()
{
Assert.That(CM_Get_HW_Prof_Flags(@"USB\ROOT_HUB30\4&3490C39&0&0", 0, out CSCONFIGFLAG cf), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(cf & (CSCONFIGFLAG.CSCONFIGFLAG_DISABLED | CSCONFIGFLAG.CSCONFIGFLAG_DO_NOT_CREATE | CSCONFIGFLAG.CSCONFIGFLAG_DO_NOT_START), Is.Not.Zero);
}
//[Test]
//public void CM_Get_Log_Conf_ListTest()
//{
// //Assert.That(CM_Add_Empty_Log_Conf(out SafeLOG_CONF hConf, NodeId, PRIORITY.LCPRI_NORMAL, LOG_CONF_FLAG.BASIC_LOG_CONF), Is.EqualTo(CONFIGRET.CR_SUCCESS));
// //using (hConf)
// {
// var lc = new SafeLOG_CONF[0];
// Assert.That(() => lc = CM_Get_Log_Conf_List(NodeId, LOG_CONF_FLAG.BOOT_LOG_CONF).ToArray(), Throws.Nothing);
// Assert.That(lc.Length, Is.GreaterThanOrEqualTo(1));
// Assert.That(() => { foreach (var l in lc) l.Dispose(); }, Throws.Nothing);
// }
//}
//[Test]
//public void CM_Get_Log_Conf_PriorityTest()
//{
// Assert.That(CM_Add_Empty_Log_Conf(out SafeLOG_CONF hConf, NodeId, PRIORITY.LCPRI_NORMAL, LOG_CONF_FLAG.BASIC_LOG_CONF), Is.EqualTo(CONFIGRET.CR_SUCCESS));
// using (hConf)
// {
// using var lc = CM_Get_Log_Conf_List(NodeId, LOG_CONF_FLAG.BASIC_LOG_CONF).First();
// Assert.That(CM_Get_Log_Conf_Priority(lc, out var p), Is.EqualTo(CONFIGRET.CR_SUCCESS));
// Assert.IsTrue(Enum.IsDefined(typeof(PRIORITY), p));
// }
//}
[Test]
public void CM_Get_Resource_Conflict_DetailsTest()
{
SafeCONFLICT_LIST hcl = null;
MEM_RESOURCE memRes = MakeResource();
Assert.That(() => hcl = CM_Query_Resource_Conflict_List(NodeId, memRes), Throws.Nothing);
try
{
Assert.That(CM_Get_Resource_Conflict_Count(hcl, out var count), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(count, Is.GreaterThan(0));
CONFLICT_DETAILS det = new(CM_CDMASK.CM_CDMASK_DESCRIPTION | CM_CDMASK.CM_CDMASK_DEVINST | CM_CDMASK.CM_CDMASK_FLAGS | CM_CDMASK.CM_CDMASK_RESDES);
Assert.That(CM_Get_Resource_Conflict_Details(hcl, 0, ref det), ResultIs.Successful);
Assert.That(det.CD_dnDevInst, Is.Not.Zero);
Assert.That(det.CD_szDescription, Is.Not.Null);
det.WriteValues();
}
finally
{
hcl?.Dispose();
}
}
[Test]
public void CM_Is_Dock_Station_PresentTest()
{
Assert.That(CM_Is_Dock_Station_Present(out var present), Is.EqualTo(CONFIGRET.CR_SUCCESS));
TestContext.Write($"Dock present={present}");
}
[Test]
public void CM_Is_Version_AvailableTest() => Assert.That(CM_Is_Version_Available(0x0501), Is.True);
[Test]
public void CM_Locate_DevNodeTest()
{
@ -341,9 +454,55 @@ namespace Vanara.PInvoke.Tests
Assert.That(di, Is.Not.Zero);
}
[Test]
public void CM_Open_Class_KeyTest()
{
Assert.That(CM_Open_Class_Key(GUID_DEVCLASS_USB, null, AdvApi32.REGSAM.KEY_READ, REGDISPOSITION.RegDisposition_OpenExisting,
out var hReg, CM_OPEN_CLASS_KEY.CM_OPEN_CLASS_KEY_INSTALLER), Is.EqualTo(CONFIGRET.CR_SUCCESS));
Assert.That(hReg, ResultIs.ValidHandle);
hReg.Dispose();
}
[Test]
public void CM_Open_Device_Interface_KeyTest()
{
var devInf = CM_Get_Device_Interface_List(GUID_DEVINTERFACE_USB_DEVICE, CM_GET_DEVICE_INTERFACE_LIST.CM_GET_DEVICE_INTERFACE_LIST_PRESENT).First();
Assert.That(CM_Open_Device_Interface_Key(devInf, AdvApi32.REGSAM.KEY_READ, REGDISPOSITION.RegDisposition_OpenExisting,
out var hReg), Is.EqualTo(CONFIGRET.CR_SUCCESS).Or.EqualTo(CONFIGRET.CR_NO_SUCH_REGISTRY_KEY));
//Assert.That(hReg, ResultIs.ValidHandle);
hReg?.Dispose();
}
[Test]
public void CM_Open_DevNode_KeyTest()
{
Assert.That(CM_Open_DevNode_Key(NodeId, AdvApi32.REGSAM.KEY_READ, 0, REGDISPOSITION.RegDisposition_OpenExisting, out var hReg, CM_REGISTRY.CM_REGISTRY_USER),
Is.EqualTo(CONFIGRET.CR_SUCCESS).Or.EqualTo(CONFIGRET.CR_NO_SUCH_REGISTRY_KEY));
hReg?.Dispose();
}
[Test]
public void CM_Query_And_Remove_SubTreeTest()
{
//Assert.That(CM_Query_And_Remove_SubTree(LeafId, out var veto, null, 0, CM_REMOVE.), ResultIs.Successful);
}
[Test]
public void CM_Reenumerate_DevNodeTest() => Assert.That(CM_Reenumerate_DevNode(RootId, CM_REENUMERATE.CM_REENUMERATE_SYNCHRONOUS), Is.EqualTo(CONFIGRET.CR_SUCCESS));
[Test]
public void CM_Request_Device_EjectTest()
{
var sb = new StringBuilder(260);
Assert.That(CM_Request_Device_Eject(NodeId, out var veto, sb, (uint)sb.Capacity), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
[Test]
public void CM_Request_Eject_PCTest()
{
Assert.That(CM_Request_Eject_PC(), Is.EqualTo(CONFIGRET.CR_SUCCESS));
}
[Test]
public void RegisterAllInterfacesTest()
{
@ -354,6 +513,9 @@ namespace Vanara.PInvoke.Tests
GC.KeepAlive(callback);
}
[Test]
public void StructSizeTest() => TestContext.Write(string.Join("\n", TestHelper.GetNestedStructSizes(typeof(CfgMgr32))));
private static IEnumerable<uint> CM_GetChildren(uint dnDevInst)
{
CONFIGRET ret = CM_Get_Child(out var di, dnDevInst);
@ -375,6 +537,47 @@ namespace Vanara.PInvoke.Tests
return ret == CONFIGRET.CR_NO_SUCH_DEVNODE ? di : throw ret.GetException();
}
private static uint LocateNode(string devId = null)
{
CM_Locate_DevNode(out var di, devId, CM_LOCATE_DEVNODE.CM_LOCATE_DEVNODE_NORMAL).ThrowIfFailed();
return di;
}
private static MEM_RESOURCE MakeResource() => new()
{
MEM_Header = new MEM_DES
{
MD_Count = 2,
MD_Type = MType_Range,
MD_Alloc_Base = 0xD8000,
MD_Alloc_End = 0xD9000,
MD_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MD_Reserved = 0
},
MEM_Data = new MEM_RANGE[]
{
new MEM_RANGE
{
MR_Align = 8, //?
MR_nBytes = 4096,
MR_Min = 0xD8000,
MR_Max = 0xDC000,
MR_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MR_Reserved = 0
},
new MEM_RANGE
{
MR_Align = 8, //?
MR_nBytes = 4096,
MR_Min = 0xE0000,
MR_Max = 0xE4000,
MR_Flags = MEM_DES_FLAGS.fMD_ROM | MEM_DES_FLAGS.fMD_32 | MEM_DES_FLAGS.fMD_ReadAllowed,
MR_Reserved = 0
}
}
};
private Win32Error Notification(HCMNOTIFICATION notify, IntPtr context, CM_NOTIFY_ACTION action, in CM_NOTIFY_EVENT_DATA eventData, uint eventDataSize)
{
switch (eventData.FilterType)