using System; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; using static Vanara.PInvoke.SetupAPI; namespace Vanara.PInvoke { /// Items from the CfgMgr32.dll public static partial class CfgMgr32 { /// /// Provides a device with backing in the registry and allows the caller to then make calls to Software Device API functions with /// the hSwDevice handle. /// /// The handle for the software device. /// An HRESULT that indicates if the enumeration of the software device was successful. /// The context that was optionally supplied by the client app to SwDeviceCreate. /// The device instance ID that PnP assigned to the device. /// None /// /// /// The operating system calls the SW_DEVICE_CREATE_CALLBACK callback function after PnP enumerates the device. After the /// callback function is called, the device has backing in the registry and calls to Software Device API functions can be made by /// using the hSwDevice handle. You can also use other APIs that work with devices for the device that is created. /// /// /// PnP enumeration of a device is the first step that a device undergoes. After PnP enumeration of the device, the device only has /// registry backing, and you can set properties against the device. Just because PnP enumerated the device, the device hasn't /// started yet, and no driver for the device has registered or enabled interfaces yet. In many cases, we recommend that apps wait /// for device-interface arrival if they want to use the device. /// /// /// Note The callback function supplies the device instance ID for the created device. We recommend that callers of the /// Software Device API not try to guess at or construct the device instance ID themselves; always use the value provided by the /// callback function. /// /// /// The callback function will execute on an arbitrary thread-pool thread. Client apps can perform as much work as needed in the /// callback function. /// /// /// In Windows 8, you can't call SwDeviceClose inside the callback function. Doing so will cause a deadlock. Be careful of releasing /// a ref counted object that will call SwDeviceClose when its destructor runs. In Windows 8.1, this restriction is lifted, /// and you can call SwDeviceClose inside the callback function. /// /// Always check the HRESULT that is passed to CreateResult to make sure PnP was able to enumerate the device. /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nc-swdevice-sw_device_create_callback SW_DEVICE_CREATE_CALLBACK // SwDeviceCreateCallback; void SwDeviceCreateCallback( HSWDEVICE hSwDevice, HRESULT CreateResult, PVOID pContext, PCWSTR // pszDeviceInstanceId ) {...} [UnmanagedFunctionPointer(CallingConvention.Winapi)] [PInvokeData("swdevice.h", MSDNShortId = "NC:swdevice.SW_DEVICE_CREATE_CALLBACK")] public delegate void SW_DEVICE_CREATE_CALLBACK([In] HSWDEVICE hSwDevice, HRESULT CreateResult, [In, Optional] IntPtr pContext, [Optional, MarshalAs(UnmanagedType.LPWStr)] string pszDeviceInstanceId); /// Specifies capabilities of the software device. [PInvokeData("swdevicedef.h", MSDNShortId = "NS:swdevicedef._SW_DEVICE_CREATE_INFO")] [Flags] public enum SW_DEVICE_CAPABILITIES { /// No capabilities have been specified. SWDeviceCapabilitiesNone = 0x00000000, /// /// This bit specifies that the device is removable from its parent. Setting this flag is equivalent to a bus driver setting the /// Removable member of the DEVICE_CAPABILTIES structure for a PDO. /// SWDeviceCapabilitiesRemovable = 0x00000001, /// /// This bit suppresses UI that would normally be shown during installation. Setting this flag is equivalent to a bus driver /// setting the SilentInstall member of the DEVICE_CAPABILTIES structure for a PDO. /// SWDeviceCapabilitiesSilentInstall = 0x00000002, /// /// This bit prevents the device from being displayed in some UI. Setting this flag is equivalent to a bus driver setting the /// NoDisplayInUI member of the DEVICE_CAPABILTIES structure for a PDO. /// SWDeviceCapabilitiesNoDisplayInUI = 0x00000004, /// /// Specify this bit when the client wants a driver to be loaded on the device and when this driver is required for correct /// function of the client’s feature. When this bit is specified, at least one of pszzHardwareIds or pszzCompatibleIds must be /// filled in. If this bit is specified and if a driver can't be found, the device shows a yellow bang in Device Manager to /// indicate that the device has a problem, and Troubleshooters flag this as a device with a problem. Setting this bit is /// equivalent to a bus driver not setting the RawDeviceOK member of the DEVICE_CAPABILTIES structure for a PDO. When this bit /// is specified, the driver owns creating interfaces for the device, and you can't call SwDeviceInterfaceRegister for the device. /// SWDeviceCapabilitiesDriverRequired = 0x00000008 } /// Indicates the current lifetime value for the software device. [PInvokeData("swdevicedef.h")] public enum SW_DEVICE_LIFETIME { /// /// Indicates that the lifetime of the software device is determined by the lifetime of the handle that is associated with the /// software device. As long as the handle is open, the software device is enumerated by PnP. /// SWDeviceLifetimeHandle, /// Indicates that the lifetime of the software device is tied to the lifetime of its parent. SWDeviceLifetimeParentPresent, } /// Closes the software device handle. When the handle is closed, PnP will initiate the process of removing the device. /// The HSWDEVICE handle to close. /// None /// /// /// After SwDeviceClose returns, the operating system is guaranteed to not call the SW_DEVICE_CREATE_CALLBACK callback /// function, and any calls to Software Device API functions that were in progress are guaranteed to have completed. /// /// You can call SwDeviceClose at any time even if the callback function hasn't been called yet. /// /// In Windows 8, you can't call SwDeviceClose inside the SW_DEVICE_CREATE_CALLBACK callback function. Doing so will cause a /// deadlock. Be careful of releasing a ref counted object that will call SwDeviceClose when its destructor runs. In Windows /// 8.1, this restriction is lifted, and you can call SwDeviceClose inside the callback function. /// /// /// By calling SwDeviceClose, you initiate the process of removing a device from PnP. The call to SwDeviceClose /// returns before this removal is complete. But you can safely call SwDeviceCreate immediately after SwDeviceClose. The new /// create will be queued until the previous removal processing completes, and then the device will be re-created. /// /// /// PnP removal makes the device "Not present." PnP removal of a device is the same us unplugging a USB device. All the persisted /// property state for the device remains in memory. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdeviceclose void SwDeviceClose( HSWDEVICE hSwDevice ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceClose")] public static extern void SwDeviceClose(HSWDEVICE hSwDevice); /// Initiates the enumeration of a software device. /// /// A string that names the enumerator of the software device. Choose a name that represents the component that enumerates the devices. /// /// /// A string that specifies the device instance ID of the device that is the parent of the software device. /// /// This can be HTREE\ROOT\0, but we recommend to keep children of the root device to a minimum. We also recommend that the /// preferred parent of a software device be a real device that the software device is extending the functionality for. In /// situations where a software device doesn't have such a natural parent, create a device as a child of the root that can collect /// all the software devices that a component will enumerate; then, enumerate the actual software devices as children of this device /// grouping node. This keeps the children of the root device to a manageable number. /// /// /// A pointer to a SW_DEVICE_CREATE_INFO structure that describes info that PnP uses to create the device. /// The number of DEVPROPERTY structures in the pProperties array. /// /// An optional array of DEVPROPERTY structures. These properties are set on the device after it is created but before a /// notification that the device has been created are sent. For more info, see Remarks. This pointer can be NULL. /// /// /// The SW_DEVICE_CREATE_CALLBACK callback function that the operating system calls after PnP enumerates the device. /// /// /// An optional client context that the operating system passes to the callback function. This pointer can be NULL. /// /// /// A pointer to a variable that receives the HSWDEVICE handle that represents the device. Call SwDeviceClose to close this /// handle after the client app wants PnP to remove the device. /// /// /// S_OK is returned if device enumeration was successfully initiated. This does not mean that the device has been successfully /// enumerated. Check the CreateResult parameter of the SW_DEVICE_CREATE_CALLBACK callback function to determine if the device was /// successfully enumerated. /// /// /// SwDeviceCreate returns a handle that represents the device. After this handle is closed, PnP will remove the device. /// The calling process must have Administrator access in order to initiate the enumeration of a software device. /// /// PnP forms the device instance ID of a software device as "SWD<pszEnumeratorName><pszInstanceId>," but this /// string might change or PnP might decorate the name. Always get the device instance ID from the callback function. /// /// /// There is a subtle difference between properties that are set as part of a SwDeviceCreate call and properties that are /// later set by calling SwDevicePropertySet. Properties that are set as part of SwDeviceCreate are stored in memory; if the /// device is uninstalled or a null driver wipes out the property stores, these properties are written out again by the Software /// Device API feature when PnP re-enumerates the devices. This is all transparent to the client. Properties that are set using /// SwDevicePropertySet after the enumeration don't persist in memory. But, if you set a property by using /// SwDeviceCreate, you can update the value with SwDevicePropertySet, and this update is applied to the in-memory /// value as well as the persisted store. /// /// /// We recommend that all properties be specified as part of the call to SwDeviceCreate when possible and that these /// properties be specified for every call to SwDeviceCreate. /// /// /// Note The operating system might possibly call SW_DEVICE_CREATE_CALLBACK before the call to SwDeviceCreate returns. /// For this reason, the software device handle for the device is supplied as a parameter to the callback function. /// /// /// You can create a software device as the child of a parent that is not present at the time. PnP will enumerate the software /// device after the parent becomes present. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicecreate HRESULT SwDeviceCreate( PCWSTR // pszEnumeratorName, PCWSTR pszParentDeviceInstance, const SW_DEVICE_CREATE_INFO *pCreateInfo, ULONG cPropertyCount, const // DEVPROPERTY *pProperties, SW_DEVICE_CREATE_CALLBACK pCallback, PVOID pContext, PHSWDEVICE phSwDevice ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceCreate")] public static extern HRESULT SwDeviceCreate([MarshalAs(UnmanagedType.LPWStr)] string pszEnumeratorName, [MarshalAs(UnmanagedType.LPWStr)] string pszParentDeviceInstance, in SW_DEVICE_CREATE_INFO pCreateInfo, uint cPropertyCount, [In, Optional, MarshalAs(UnmanagedType.LPArray)] DEVPROPERTY[] pProperties, SW_DEVICE_CREATE_CALLBACK pCallback, [In, Optional] IntPtr pContext, out SafeHSWDEVICE phSwDevice); /// Gets the lifetime of a software device. /// The HSWDEVICE handle to the software device to retrieve. /// /// /// A pointer to a variable that receives a SW_DEVICE_LIFETIME-typed value that indicates the current lifetime value for the /// software device. Here are possible values: /// /// /// /// Value /// Meaning /// /// /// SWDeviceLifetimeHandle /// /// Indicates that the lifetime of the software device is determined by the lifetime of the handle that is associated with the /// software device. As long as the handle is open, the software device is enumerated by PnP. /// /// /// /// SWDeviceLifetimeParentPresent /// Indicates that the lifetime of the software device is tied to the lifetime of its parent. /// /// /// /// S_OK is returned if SwDeviceSetLifetime successfully retrieved the lifetime. // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicegetlifetime HRESULT SwDeviceGetLifetime( // HSWDEVICE hSwDevice, PSW_DEVICE_LIFETIME pLifetime ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceGetLifetime")] public static extern HRESULT SwDeviceGetLifetime(HSWDEVICE hSwDevice, out SW_DEVICE_LIFETIME pLifetime); /// Sets properties on a software device interface. /// The HSWDEVICE handle to the software device of the interface to set properties for. /// A string that identifies the interface to set properties on. /// The number of DEVPROPERTY structures in the pProperties array. /// An array of DEVPROPERTY structures containing the properties to set on the interface. /// /// S_OK is returned if SwDeviceInterfacePropertySet successfully set the properties on the interface; otherwise, an /// appropriate error value. /// /// /// /// Typically, only the operating system and Administrators of the computer can set properties on an interface, but the creator of a /// device can call SwDeviceInterfacePropertySet to set properties on an interface for that device even if the creator isn't /// the operating system or an Administrator. /// /// /// You can call SwDeviceInterfacePropertySet only after the operating system has called your client app's /// SW_DEVICE_CREATE_CALLBACK callback function to notify the client app that device enumeration completed. /// /// /// There is a subtle difference between properties that are set as part of a SwDeviceInterfaceRegister call and properties that are /// later set by calling SwDeviceInterfacePropertySet. Properties that are set as part of SwDeviceInterfaceRegister /// are stored in memory; if the device is uninstalled or a null driver wipes out the property stores, these properties are written /// out again by the Software Device API feature when PnP re-enumerates the devices. This is all transparent to the client. /// Properties that are set using SwDeviceInterfacePropertySet after the enumeration don't persist in memory. But, if you set /// a property by using SwDeviceInterfaceRegister, you can update the value with SwDeviceInterfacePropertySet, and /// this update is applied to the in-memory value as well as the persisted store. /// /// You can use SwDeviceInterfacePropertySet only to set properties in the operating system store for the interface. /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdeviceinterfacepropertyset HRESULT // SwDeviceInterfacePropertySet( HSWDEVICE hSwDevice, PCWSTR pszDeviceInterfaceId, ULONG cPropertyCount, const DEVPROPERTY // *pProperties ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceInterfacePropertySet")] public static extern HRESULT SwDeviceInterfacePropertySet(HSWDEVICE hSwDevice, [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceInterfaceId, uint cPropertyCount, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] DEVPROPERTY[] pProperties); /// Registers a device interface for a software device and optionally sets properties on that interface. /// The HSWDEVICE handle to the software device to register a device interface for. /// A pointer to the interface class GUID that names the contract that this interface implements. /// /// An optional reference string that differentiates multiple interfaces of the same class for this device. This pointer can be NULL. /// /// The number of DEVPROPERTY structures in the pProperties array. /// /// An optional array of DEVPROPERTY structures for the properties to set on the interface. This pointer can be NULL. /// /// Set these properties on the interface after it is created but before a notification that the interface has been created are /// sent. For more info, see Remarks. This pointer can be NULL. /// /// /// /// A Boolean value that indicates whether to either enable or disable the interface. TRUE to enable; FALSE to disable. /// /// /// A pointer to a variable that receives a pointer to the device interface ID for the interface. The caller must free this value /// with SwMemFree. This value can be NULL if the client app doesn't need to retrieve the name. /// /// /// S_OK is returned if SwDeviceInterfaceRegister successfully registered the interface; otherwise, an appropriate error value. /// /// /// /// You can call SwDeviceInterfaceRegister only after the operating system has called your client app's /// SW_DEVICE_CREATE_CALLBACK callback function to notify the client app that device enumeration completed. /// /// /// You can't call SwDeviceInterfaceRegister for software devices that specify the SWDeviceCapabilitiesDriverRequired capability. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdeviceinterfaceregister HRESULT // SwDeviceInterfaceRegister( HSWDEVICE hSwDevice, const GUID *pInterfaceClassGuid, PCWSTR pszReferenceString, ULONG cPropertyCount, // const DEVPROPERTY *pProperties, BOOL fEnabled, PWSTR *ppszDeviceInterfaceId ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceInterfaceRegister")] public static extern HRESULT SwDeviceInterfaceRegister(HSWDEVICE hSwDevice, in Guid pInterfaceClassGuid, [Optional, MarshalAs(UnmanagedType.LPWStr)] string pszReferenceString, uint cPropertyCount, [In, Optional, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] DEVPROPERTY[] pProperties, [MarshalAs(UnmanagedType.Bool)] bool fEnabled, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SwMemMarshaler))] out string ppszDeviceInterfaceId); /// Enables or disables a device interface for a software device. /// The HSWDEVICE handle to the software device to register a device interface for. /// A string that identifies the interface to enable or disable. /// /// A Boolean value that indicates whether to either enable or disable the interface. TRUE to enable; FALSE to disable. /// /// /// S_OK is returned if SwDeviceInterfaceSetState successfully enabled or disabled the interface; otherwise, an appropriate /// error value. /// /// /// /// You can call SwDeviceInterfaceSetState only after the operating system has called your client app's /// SW_DEVICE_CREATE_CALLBACK callback function to notify the client app that device enumeration completed. /// /// /// You can only use SwDeviceInterfaceSetState to manage interfaces that were previously registered with /// SwDeviceInterfaceRegister against the software device that hSwDevice represents. /// /// /// Client apps use SwDeviceInterfaceSetState to manage the state that they want the interface to have. The software device /// changes the actual interface state as needed. For example, a client app disables and re-enables the interface if the device is /// re-enumerated for any reason. The state always tries to reflect the client app’s required state. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdeviceinterfacesetstate HRESULT // SwDeviceInterfaceSetState( HSWDEVICE hSwDevice, PCWSTR pszDeviceInterfaceId, BOOL fEnabled ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceInterfaceSetState")] public static extern HRESULT SwDeviceInterfaceSetState(HSWDEVICE hSwDevice, [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceInterfaceId, [MarshalAs(UnmanagedType.Bool)] bool fEnabled); /// Sets properties on a software device. /// The HSWDEVICE handle to the software device to set properties for. /// The number of DEVPROPERTY structures in the pProperties array. /// An array of DEVPROPERTY structures containing the properties to set. /// /// S_OK is returned if SwDevicePropertySet successfully set the properties; otherwise, an appropriate error value. /// /// /// /// Typically, only the operating system and Administrators of the computer can set properties on a device, but the creator of a /// device can call SwDevicePropertySet to set properties on that device even if it isn't the operating system or an Administrator. /// /// /// You can call SwDevicePropertySet only after the operating system has called your client app's SW_DEVICE_CREATE_CALLBACK /// callback function to notify the client app that device enumeration completed. /// /// /// There is a subtle difference between properties that are set as part of a SwDeviceCreate call and properties that are later set /// by calling SwDevicePropertySet. Properties that are set as part of SwDeviceCreate are stored in memory; if the /// device is uninstalled or a null driver wipes out the property stores, these properties are written out again by the Software /// Device API feature when PnP re-enumerates the devices. This is all transparent to the client. Properties that are set using /// SwDevicePropertySet after the enumeration don't persist in memory. But, if you set a property by using /// SwDeviceCreate, you can update the value with SwDevicePropertySet, and this update is applied to the in-memory /// value as well as the persisted store. /// /// You can use SwDevicePropertySet only to set properties in the operating system store for the device. /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicepropertyset HRESULT SwDevicePropertySet( // HSWDEVICE hSwDevice, ULONG cPropertyCount, const DEVPROPERTY *pProperties ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDevicePropertySet")] public static extern HRESULT SwDevicePropertySet(HSWDEVICE hSwDevice, uint cPropertyCount, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] DEVPROPERTY[] pProperties); /// Manages the lifetime of a software device. /// The HSWDEVICE handle to the software device to manage. /// /// /// A SW_DEVICE_LIFETIME-typed value that indicates the new lifetime value for the software device. Here are possible values: /// /// /// /// Value /// Meaning /// /// /// SWDeviceLifetimeHandle /// /// Indicates that the lifetime of the software device is determined by the lifetime of the handle that is associated with the /// software device. As long as the handle is open, the software device is enumerated by PnP. /// /// /// /// SWDeviceLifetimeParentPresent /// Indicates that the lifetime of the software device is tied to the lifetime of its parent. /// /// /// /// S_OK is returned if SwDeviceSetLifetime successfully updated the lifetime. /// /// /// After a software device is initially created by calling SwDeviceCreate, its default lifetime is set to /// SwDeviceLifetimeHandle. When a software device has a lifetime of SwDeviceLifetimeHandle, PnP stops enumerating the /// device after the device's handle is closed. /// /// /// You can use SwDeviceSetLifetime to set the lifetime of the software device to SwDeviceLifetimeParentPresent. The /// lifetime of the software device is then tied to the lifetime of the closest non-software device parent. The creator of the /// software device can then close the handle to the software device and the device will still be enumerated. This can be useful for /// services that manage software devices but want to idle stop. /// /// /// A client app can only call SwDeviceSetLifetime after it has received a call to its SW_DEVICE_CREATE_CALLBACK callback /// function that is associated with its call to SwDeviceCreate. /// /// /// When a client app calls SwDeviceCreate for a software device that was previously marked for /// SwDeviceLifetimeParentPresent, SwDeviceCreate succeeds if there are no open software device handles for the device /// (only one handle can be open for a device). A client app can then regain control over a persistent software device for the /// purposes of updating properties and interfaces or changing the lifetime. /// /// /// If the client app specifies info in SW_DEVICE_CREATE_INFO that is different form a previous enumeration, the device might stop /// being enumerated and immediately re-enumerated to apply the changes. The operating system reports only some properties when PnP /// enumerates the device. /// /// /// To uninstall a software device with a lifetime of SwDeviceLifetimeParentPresent, we recommend that you change the /// lifetime back to SwDeviceLifetimeHandle before the device is uninstalled. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swdevicesetlifetime HRESULT SwDeviceSetLifetime( // HSWDEVICE hSwDevice, SW_DEVICE_LIFETIME Lifetime ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwDeviceSetLifetime")] public static extern HRESULT SwDeviceSetLifetime(HSWDEVICE hSwDevice, SW_DEVICE_LIFETIME Lifetime); /// Frees memory that other Software Device API functions allocated. /// A pointer to the block of memory to free. /// None // https://docs.microsoft.com/en-us/windows/win32/api/swdevice/nf-swdevice-swmemfree void SwMemFree( PVOID pMem ); [DllImport(Lib_Cfgmgr32, SetLastError = false, ExactSpelling = true)] [PInvokeData("swdevice.h", MSDNShortId = "NF:swdevice.SwMemFree")] public static extern void SwMemFree(IntPtr pMem); /// Provides a handle to a software device. [StructLayout(LayoutKind.Sequential)] public struct HSWDEVICE : IHandle { private readonly IntPtr handle; /// Initializes a new instance of the struct. /// An object that represents the pre-existing handle to use. public HSWDEVICE(IntPtr preexistingHandle) => handle = preexistingHandle; /// Returns an invalid handle by instantiating a object with . public static HSWDEVICE NULL => new(IntPtr.Zero); /// Gets a value indicating whether this instance is a null handle. public bool IsNull => handle == IntPtr.Zero; /// Performs an explicit conversion from to . /// The handle. /// The result of the conversion. public static explicit operator IntPtr(HSWDEVICE h) => h.handle; /// Performs an implicit conversion from to . /// The pointer to a handle. /// The result of the conversion. public static implicit operator HSWDEVICE(IntPtr h) => new(h); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(HSWDEVICE h1, HSWDEVICE h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(HSWDEVICE h1, HSWDEVICE h2) => h1.Equals(h2); /// public override bool Equals(object obj) => obj is HSWDEVICE h && handle == h.handle; /// public override int GetHashCode() => handle.GetHashCode(); /// public IntPtr DangerousGetHandle() => handle; } /// Describes info that PnP uses to create the software device. /// /// You can only specify this info at creation time, and you can't later call the Software Device API to modify this info, by /// setting properties, for example. /// // https://docs.microsoft.com/en-us/windows/win32/api/swdevicedef/ns-swdevicedef-sw_device_create_info typedef struct // _SW_DEVICE_CREATE_INFO { ULONG cbSize; PCWSTR pszInstanceId; PCZZWSTR pszzHardwareIds; PCZZWSTR pszzCompatibleIds; const GUID // *pContainerId; ULONG CapabilityFlags; PCWSTR pszDeviceDescription; PCWSTR pszDeviceLocation; const SECURITY_DESCRIPTOR // *pSecurityDescriptor; } SW_DEVICE_CREATE_INFO, *PSW_DEVICE_CREATE_INFO; [PInvokeData("swdevicedef.h", MSDNShortId = "NS:swdevicedef._SW_DEVICE_CREATE_INFO")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SW_DEVICE_CREATE_INFO { /// The size in bytes of this structure. Use it as a version field. Initialize it to sizeof(SW_DEVICE_CREATE_INFO). public uint cbSize; /// /// A string that represents the instance ID portion of the device instance ID. This value is used for IRP_MN_QUERY_ID /// BusQueryInstanceID. 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. /// [MarshalAs(UnmanagedType.LPWStr)] public string pszInstanceId; /// /// A list of strings for the hardware IDs for the software device. This value is used for IRP_MN_QUERY_ID /// BusQueryHardwareIDs. If a client expects a driver or device metadata to bind to the device, the client specifies /// hardware IDs. /// //[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))] //public string[] pszzHardwareIds; public IntPtr pszzHardwareIds; /// /// A list of strings for the compatible IDs for the software device. This value is used for IRP_MN_QUERY_ID /// BusQueryCompatibleIDs. If a client expects a class driver to load, the client specifies compatible IDs that match the /// class driver. If a driver isn't needed, we recommend to specify a compatible ID to classify the type of software device. In /// 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. /// //[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler))] //public string[] pszzCompatibleIds; public IntPtr pszzCompatibleIds; /// /// 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 /// BusQueryContainerIDs. For typical situations, we recommend to set this member to NULL and use the /// SWDeviceCapabilitiesRemovable flag to control whether the device inherits the parent's container ID or if PnP assigns /// a new random container ID. If the client needs to explicitly control the container ID, specify a GUID in the variable /// that this member points to. /// public GuidPtr pContainerId; /// /// /// A combination of SW_DEVICE_CAPABILITIES values that are combined by using a bitwise OR operation. The resulting value /// specifies capabilities of the software device. The capability that you can specify when you create a software device are a /// subset of the capabilities that a bus driver can specify by using the DEVICE_CAPABILTIES structure. Only capabilities /// that make sense to allow changing for a software only device are supported. The rest receive appropriate default values. /// Here are possible values: /// /// /// /// Value /// Meaning /// /// /// SWDeviceCapabilitiesNone 0x00000000 /// No capabilities have been specified. /// /// /// SWDeviceCapabilitiesRemovable 0x00000001 /// /// This bit specifies that the device is removable from its parent. Setting this flag is equivalent to a bus driver setting the /// Removable member of the DEVICE_CAPABILTIES structure for a PDO. /// /// /// /// SWDeviceCapabilitiesSilentInstall 0x00000002 /// /// This bit suppresses UI that would normally be shown during installation. Setting this flag is equivalent to a bus driver /// setting the SilentInstall member of the DEVICE_CAPABILTIES structure for a PDO. /// /// /// /// SWDeviceCapabilitiesNoDisplayInUI 0x00000004 /// /// This bit prevents the device from being displayed in some UI. Setting this flag is equivalent to a bus driver setting the /// NoDisplayInUI member of the DEVICE_CAPABILTIES structure for a PDO. /// /// /// /// SWDeviceCapabilitiesDriverRequired 0x00000008 /// /// Specify this bit when the client wants a driver to be loaded on the device and when this driver is required for correct /// function of the client’s feature. When this bit is specified, at least one of pszzHardwareIds or pszzCompatibleIds must be /// filled in. If this bit is specified and if a driver can't be found, the device shows a yellow bang in Device Manager to /// indicate that the device has a problem, and Troubleshooters flag this as a device with a problem. Setting this bit is /// equivalent to a bus driver not setting the RawDeviceOK member of the DEVICE_CAPABILTIES structure for a PDO. When this bit /// is specified, the driver owns creating interfaces for the device, and you can't call SwDeviceInterfaceRegister for the device. /// /// /// /// public SW_DEVICE_CAPABILITIES CapabilityFlags; /// /// /// A string that contains the text that is displayed for the device name in the UI. This value is used for /// IRP_MN_QUERY_DEVICE_TEXT DeviceTextDescription. /// /// Note /// /// When an INF is matched against the device, the name from the INF overrides this name unless steps are taken to preserve this name. /// /// We recommend that this string be a reference to a localizable resource. For the syntax of referencing resources, see DEVPROP_TYPE_STRING_INDIRECT. /// /// [MarshalAs(UnmanagedType.LPWStr)] public string pszDeviceDescription; /// /// /// A string that contains the text that is displayed for the device location in the UI. This value is used for /// IRP_MN_QUERY_DEVICE_TEXT DeviceTextLocationInformation. /// /// Note Specifying a location is uncommon. /// [MarshalAs(UnmanagedType.LPWStr)] public string pszDeviceLocation; /// /// A pointer to a SECURITY_DESCRIPTOR structure that contains the security information associated with the software device. If /// this member is NULL, the I/O Manager assigns the default security descriptor to the device. If a custom security /// descriptor is needed, specify a self-relative security descriptor. /// public PSECURITY_DESCRIPTOR pSecurityDescriptor; } /// Provides a for that is disposed using . public class SafeHSWDEVICE : SafeHANDLE { /// Initializes a new instance of the class and assigns an existing handle. /// An object that represents the pre-existing handle to use. /// /// to reliably release the handle during the finalization phase; otherwise, (not recommended). /// public SafeHSWDEVICE(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } /// Initializes a new instance of the class. private SafeHSWDEVICE() : base() { } /// Performs an implicit conversion from to . /// The safe handle instance. /// The result of the conversion. public static implicit operator HSWDEVICE(SafeHSWDEVICE h) => h.handle; /// protected override bool InternalReleaseHandle() { SwDeviceClose(handle); return true; } } internal class SwMemMarshaler : ICustomMarshaler { public static ICustomMarshaler GetInstance() => new SwMemMarshaler(); void ICustomMarshaler.CleanUpManagedData(object ManagedObj) => throw new NotImplementedException(); void ICustomMarshaler.CleanUpNativeData(IntPtr pNativeData) => SwMemFree(pNativeData); int ICustomMarshaler.GetNativeDataSize() => -1; IntPtr ICustomMarshaler.MarshalManagedToNative(object ManagedObj) => throw new NotImplementedException(); object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData) => StringHelper.GetString(pNativeData, CharSet.Unicode); } } }