Added nullability to PortableDeviceApi and tests

nullableenabled
David Hall 2023-09-24 20:16:38 -06:00
parent 718d241007
commit 99e7fa0a78
6 changed files with 8884 additions and 8864 deletions

View File

@ -1,4 +1,5 @@
using static Vanara.PInvoke.Kernel32; #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using static Vanara.PInvoke.Kernel32;
using static Vanara.PInvoke.Ole32; using static Vanara.PInvoke.Ole32;
namespace Vanara.PInvoke; namespace Vanara.PInvoke;
@ -29,62 +30,80 @@ public static partial class PortableDeviceApi
/**************************************************************************** /****************************************************************************
* This section declares WPD defines * This section declares WPD defines
****************************************************************************/ ****************************************************************************/
// WPD specific function number used to construct WPD I/O control codes. Drivers should not use this define directly. /// <summary>WPD specific function number used to construct WPD I/O control codes. Drivers should not use this define directly.</summary>
public const ushort WPD_CONTROL_FUNCTION_GENERIC_MESSAGE = 0x42; public const ushort WPD_CONTROL_FUNCTION_GENERIC_MESSAGE = 0x42;
// Defines WPD specific IOCTL number used by drivers to detect WPD requests that may require READ and WRITE access to the device. /// <summary>
/// Defines WPD specific IOCTL number used by drivers to detect WPD requests that may require READ and WRITE access to the device.
/// </summary>
public static readonly uint IOCTL_WPD_MESSAGE_READWRITE_ACCESS = CTL_CODE(DEVICE_TYPE.FILE_DEVICE_WPD, WPD_CONTROL_FUNCTION_GENERIC_MESSAGE, IOMethod.METHOD_BUFFERED, IOAccess.FILE_READ_ACCESS | IOAccess.FILE_WRITE_ACCESS); public static readonly uint IOCTL_WPD_MESSAGE_READWRITE_ACCESS = CTL_CODE(DEVICE_TYPE.FILE_DEVICE_WPD, WPD_CONTROL_FUNCTION_GENERIC_MESSAGE, IOMethod.METHOD_BUFFERED, IOAccess.FILE_READ_ACCESS | IOAccess.FILE_WRITE_ACCESS);
// Defines WPD specific IOCTL number used by drivers to detect WPD requests that require READ-only access to the device. /// <summary>Defines WPD specific IOCTL number used by drivers to detect WPD requests that require READ-only access to the device.</summary>
public static readonly uint IOCTL_WPD_MESSAGE_READ_ACCESS = CTL_CODE(DEVICE_TYPE.FILE_DEVICE_WPD, WPD_CONTROL_FUNCTION_GENERIC_MESSAGE, IOMethod.METHOD_BUFFERED, IOAccess.FILE_READ_ACCESS); public static readonly uint IOCTL_WPD_MESSAGE_READ_ACCESS = CTL_CODE(DEVICE_TYPE.FILE_DEVICE_WPD, WPD_CONTROL_FUNCTION_GENERIC_MESSAGE, IOMethod.METHOD_BUFFERED, IOAccess.FILE_READ_ACCESS);
// Drivers can use this macro to detect whether the incoming IOCTL is a WPD message or not. /// <summary>Drivers can use this macro to detect whether the incoming IOCTL is a WPD message or not.</summary>
public static bool IS_WPD_IOCTL(uint ControlCode) => ((ControlCode == IOCTL_WPD_MESSAGE_READWRITE_ACCESS) || (ControlCode == IOCTL_WPD_MESSAGE_READ_ACCESS)); public static bool IS_WPD_IOCTL(uint ControlCode) => ((ControlCode == IOCTL_WPD_MESSAGE_READWRITE_ACCESS) || (ControlCode == IOCTL_WPD_MESSAGE_READ_ACCESS));
// Pre-defined ObjectID for the DEVICE object. /// <summary>Pre-defined ObjectID for the DEVICE object.</summary>
public const string WPD_DEVICE_OBJECT_ID = "DEVICE"; public const string WPD_DEVICE_OBJECT_ID = "DEVICE";
// Pre-defined IWMDMDevice for the IWMDRMDeviceApp license/metering APIs. /// <summary>Pre-defined IWMDMDevice for the IWMDRMDeviceApp license/metering APIs.</summary>
public static readonly IntPtr WMDRMDEVICEAPP_USE_WPD_DEVICE_PTR = new(-1); public static readonly IntPtr WMDRMDEVICEAPP_USE_WPD_DEVICE_PTR = new(-1);
// Pre-defined name of a REG_DWORD value that defines the device type, used for representation purposes only. Functional /// <summary>
// characteristics of the device are decided through functional objects. This value can be retrieved using /// Pre-defined name of a REG_DWORD value that defines the device type, used for representation purposes only. Functional characteristics
// IPortableDeviceManager::GetDeviceProperty(...). See WPD_DEVICE_TYPES enumeration for possible values. /// of the device are decided through functional objects. This value can be retrieved using
/// IPortableDeviceManager::GetDeviceProperty(...). See WPD_DEVICE_TYPES enumeration for possible values.
/// </summary>
public const string PORTABLE_DEVICE_TYPE = "PortableDeviceType"; public const string PORTABLE_DEVICE_TYPE = "PortableDeviceType";
// Pre-defined name of a REG_SZ/REG_EXPAND_SZ/REG_MULTI_SZ value that indicates the location of the device icon file or device icon /// <summary>
// resource. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). This /// Pre-defined name of a REG_SZ/REG_EXPAND_SZ/REG_MULTI_SZ value that indicates the location of the device icon file or device icon
// REG_SZ/REG_EXPAND_SZ/REG_MULTI_SZ value is either in the form "file.dll, resourceID" or a full file path to an icon file. e.g.: "x:\file.ico" /// resource. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). This REG_SZ/REG_EXPAND_SZ/REG_MULTI_SZ
/// value is either in the form "file.dll, resourceID" or a full file path to an icon file. e.g.: "x:\file.ico"
/// </summary>
public const string PORTABLE_DEVICE_ICON = "Icons"; public const string PORTABLE_DEVICE_ICON = "Icons";
// Pre-defined name of a REG_DWORD value that indicates the amount of time in milliseconds the WPD Namespace Extension will keep its /// <summary>
// reference to the device open under idle conditions. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). /// Pre-defined name of a REG_DWORD value that indicates the amount of time in milliseconds the WPD Namespace Extension will keep its
/// reference to the device open under idle conditions. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...).
/// </summary>
public const string PORTABLE_DEVICE_NAMESPACE_TIMEOUT = "PortableDeviceNameSpaceTimeout"; public const string PORTABLE_DEVICE_NAMESPACE_TIMEOUT = "PortableDeviceNameSpaceTimeout";
// Pre-defined name of a REG_DWORD value that is used as a flag to indicate whether the device should, or should not, be shown in /// <summary>
// the Explorer view. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Meaning of values are: 0 = /// Pre-defined name of a REG_DWORD value that is used as a flag to indicate whether the device should, or should not, be shown in the
// include, 1 = exclude. 0 is assumed if this value doesn't exist. /// Explorer view. This value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Meaning of values are: 0 = include,
/// 1 = exclude. 0 is assumed if this value doesn't exist.
/// </summary>
public const string PORTABLE_DEVICE_NAMESPACE_EXCLUDE_FROM_SHELL = "PortableDeviceNameSpaceExcludeFromShell"; public const string PORTABLE_DEVICE_NAMESPACE_EXCLUDE_FROM_SHELL = "PortableDeviceNameSpaceExcludeFromShell";
// Pre-defined name of a REG_SZ or REG_MULTI_SZ value containing content type guids that are used indicate for what content types /// <summary>
// the portable device namespace should attempt to automatically generate a thumbnail when placing new content on the device. This /// Pre-defined name of a REG_SZ or REG_MULTI_SZ value containing content type guids that are used indicate for what content types the
// value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Values should be a string representation of a GUID, /// portable device namespace should attempt to automatically generate a thumbnail when placing new content on the device. This value can
// in the form '{00000000-0000-0000-0000-000000000000}'. By default the portable device namespace attempts to automatically generate /// be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Values should be a string representation of a GUID, in the form
// thumbnails for WPD_CONTENT_TYPE_IMAGE, if a device does not want this behavior it can set this value to an empty string. /// '{00000000-0000-0000-0000-000000000000}'. By default the portable device namespace attempts to automatically generate thumbnails for
/// WPD_CONTENT_TYPE_IMAGE, if a device does not want this behavior it can set this value to an empty string.
/// </summary>
public const string PORTABLE_DEVICE_NAMESPACE_THUMBNAIL_CONTENT_TYPES = "PortableDeviceNameSpaceThumbnailContentTypes"; public const string PORTABLE_DEVICE_NAMESPACE_THUMBNAIL_CONTENT_TYPES = "PortableDeviceNameSpaceThumbnailContentTypes";
// Pre-defined name of a REG_DWORD value that indicates whether a Portable Device is a Mass Storage Class (MSC) device. This is used /// <summary>
// to avoid duplication of the device in certain views and scenarios that include both file system and Portable Devices. This value /// Pre-defined name of a REG_DWORD value that indicates whether a Portable Device is a Mass Storage Class (MSC) device. This is used to
// can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Meaning of values are: 0 = device is not mass storage, 1 = /// avoid duplication of the device in certain views and scenarios that include both file system and Portable Devices. This value can be
// device is mass storage. 0 is assumed if this value doesn't exist. /// retrieved using IPortableDeviceManager::GetDeviceProperty(...). Meaning of values are: 0 = device is not mass storage, 1 = device is
/// mass storage. 0 is assumed if this value doesn't exist.
/// </summary>
public const string PORTABLE_DEVICE_IS_MASS_STORAGE = "PortableDeviceIsMassStorage"; public const string PORTABLE_DEVICE_IS_MASS_STORAGE = "PortableDeviceIsMassStorage";
// Pre-defined value identifying the "Windows Media Digital Rights Management 10 for Portable Devices" scheme for protecting /// <summary>
// content. This value can be used by drivers to indicate they support WMDRM10-PD. See WPD_DEVICE_SUPPORTED_DRM_SCHEMES. /// Pre-defined value identifying the "Windows Media Digital Rights Management 10 for Portable Devices" scheme for protecting content.
/// This value can be used by drivers to indicate they support WMDRM10-PD. See WPD_DEVICE_SUPPORTED_DRM_SCHEMES.
/// </summary>
public const string PORTABLE_DEVICE_DRM_SCHEME_WMDRM10_PD = "WMDRM10-PD"; public const string PORTABLE_DEVICE_DRM_SCHEME_WMDRM10_PD = "WMDRM10-PD";
// Pre-defined value identifying the "Portable Device Digital Rights Management" scheme for protecting content. This value can be /// <summary>
// used by drivers to indicate they support PDDRM. See WPD_DEVICE_SUPPORTED_DRM_SCHEMES. /// Pre-defined value identifying the "Portable Device Digital Rights Management" scheme for protecting content. This value can be used
/// by drivers to indicate they support PDDRM. See WPD_DEVICE_SUPPORTED_DRM_SCHEMES.
/// </summary>
public const string PORTABLE_DEVICE_DRM_SCHEME_PDDRM = "PDDRM"; public const string PORTABLE_DEVICE_DRM_SCHEME_PDDRM = "PDDRM";
/**************************************************************************** /****************************************************************************
@ -4687,7 +4706,7 @@ public static partial class PortableDeviceApi
/// <param name="ControlCode">The control code.</param> /// <param name="ControlCode">The control code.</param>
/// <param name="pCommandParams">The <see cref="IPortableDeviceValues"/> instance.</param> /// <param name="pCommandParams">The <see cref="IPortableDeviceValues"/> instance.</param>
/// <returns>S_OK on success; otherwise and error code.</returns> /// <returns>S_OK on success; otherwise and error code.</returns>
public static HRESULT VerifyWpdCommandAccessFromMap(uint ControlCode, IPortableDeviceValues pCommandParams) public static HRESULT VerifyWpdCommandAccessFromMap(uint ControlCode, IPortableDeviceValues? pCommandParams)
{ {
HRESULT hr = HRESULT.S_OK; HRESULT hr = HRESULT.S_OK;
uint dwExpectedControlCode = IOCTL_WPD_MESSAGE_READWRITE_ACCESS; uint dwExpectedControlCode = IOCTL_WPD_MESSAGE_READWRITE_ACCESS;
@ -4737,12 +4756,12 @@ public static partial class PortableDeviceApi
return hr.Succeeded && ControlCode != dwExpectedControlCode ? HRESULT.E_INVALIDARG : hr; return hr.Succeeded && ControlCode != dwExpectedControlCode ? HRESULT.E_INVALIDARG : hr;
} }
private static PROPERTYKEY? GetWPDPKey(string propName) => propName is null ? null : PortableDeviceExtensions.GetKeyFromName(propName); private static PROPERTYKEY? GetWPDPKey(string? propName) => propName is null ? null : PortableDeviceExtensions.GetKeyFromName(propName);
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class WPDCommandAttribute : Attribute public class WPDCommandAttribute : Attribute
{ {
public WPDCommandAttribute(WPD_COMMAND_ACCESS_TYPES access = WPD_COMMAND_ACCESS_TYPES.WPD_COMMAND_ACCESS_READ, string depProp = null) public WPDCommandAttribute(WPD_COMMAND_ACCESS_TYPES access = WPD_COMMAND_ACCESS_TYPES.WPD_COMMAND_ACCESS_READ, string? depProp = null)
{ {
Access = access; Access = access;
AccessDependency = GetWPDPKey(depProp); AccessDependency = GetWPDPKey(depProp);

View File

@ -9,9 +9,9 @@ public static partial class PortableDeviceApi
{ {
private const string Lib_PortableDeviceApi = "PortableDeviceApi.dll"; private const string Lib_PortableDeviceApi = "PortableDeviceApi.dll";
private delegate HRESULT PDMStrArrGet(string[] arr, ref uint cnt); private delegate HRESULT PDMStrArrGet(string[]? arr, ref uint cnt);
private delegate HRESULT PDMStrGet(string devId, StringBuilder str, ref uint sz); private delegate HRESULT PDMStrGet(string devId, StringBuilder? str, ref uint sz);
/// <summary> /// <summary>
/// The <c>IEnumPortableDeviceObjectIDs</c> interface enumerates the objects on a portable device. Get this interface initially by /// The <c>IEnumPortableDeviceObjectIDs</c> interface enumerates the objects on a portable device. Get this interface initially by
@ -332,7 +332,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevice-sendcommand HRESULT // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevice-sendcommand HRESULT
// SendCommand( [in] const DWORD dwFlags, [in] IPortableDeviceValues *pParameters, [out] IPortableDeviceValues **ppResults ); // SendCommand( [in] const DWORD dwFlags, [in] IPortableDeviceValues *pParameters, [out] IPortableDeviceValues **ppResults );
IPortableDeviceValues SendCommand([Optional] UInt32 dwFlags, [In] IPortableDeviceValues pParameters); IPortableDeviceValues SendCommand([Optional] uint dwFlags, [In] IPortableDeviceValues pParameters);
/// <summary>The <c>Content</c> method retrieves an interface that you can use to access objects on a device.</summary> /// <summary>The <c>Content</c> method retrieves an interface that you can use to access objects on a device.</summary>
/// <returns> /// <returns>
@ -391,7 +391,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevice-advise HRESULT // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevice-advise HRESULT
// Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues *pParameters, // Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues *pParameters,
// [out] LPWSTR *ppszCookie ); // [out] LPWSTR *ppszCookie );
void Advise([Optional] uint dwFlags, IPortableDeviceEventCallback pCallback, [Optional] IPortableDeviceValues pParameters, [MarshalAs(UnmanagedType.LPWStr)] out string ppszCookie); void Advise([Optional] uint dwFlags, IPortableDeviceEventCallback pCallback, [Optional] IPortableDeviceValues? pParameters, [MarshalAs(UnmanagedType.LPWStr)] out string ppszCookie);
/// <summary> /// <summary>
/// The <c>Unadvise</c> method unregisters a client from receiving callback notifications. You must call this method if you /// The <c>Unadvise</c> method unregisters a client from receiving callback notifications. You must call this method if you
@ -592,7 +592,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicecapabilities-getfixedpropertyattributes // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicecapabilities-getfixedpropertyattributes
// HRESULT GetFixedPropertyAttributes( [in] REFGUID Format, [in] REFPROPERTYKEY Key, [out] IPortableDeviceValues **ppAttributes ); // HRESULT GetFixedPropertyAttributes( [in] REFGUID Format, [in] REFPROPERTYKEY Key, [out] IPortableDeviceValues **ppAttributes );
IPortableDeviceValues GetFixedPropertyAttributes(in Guid Format, in PROPERTYKEY Key); IPortableDeviceValues? GetFixedPropertyAttributes(in Guid Format, in PROPERTYKEY Key);
/// <summary>The <c>Cancel</c> method cancels a pending request on this interface.</summary> /// <summary>The <c>Cancel</c> method cancels a pending request on this interface.</summary>
/// <remarks> /// <remarks>
@ -653,7 +653,7 @@ public static partial class PortableDeviceApi
// HRESULT EnumObjects( [in] const DWORD dwFlags, [in] LPCWSTR pszParentObjectID, [in] IPortableDeviceValues *pFilter, [out] // HRESULT EnumObjects( [in] const DWORD dwFlags, [in] LPCWSTR pszParentObjectID, [in] IPortableDeviceValues *pFilter, [out]
// IEnumPortableDeviceObjectIDs **ppEnum ); // IEnumPortableDeviceObjectIDs **ppEnum );
IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID, IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID,
[In, Optional] IPortableDeviceValues pFilter); [In, Optional] IPortableDeviceValues? pFilter);
/// <summary> /// <summary>
/// The <c>Properties</c> method retrieves the interface that is required to get or set properties on an object on the device. /// The <c>Properties</c> method retrieves the interface that is required to get or set properties on an object on the device.
@ -906,7 +906,7 @@ public static partial class PortableDeviceApi
// HRESULT EnumObjects( [in] const DWORD dwFlags, [in] LPCWSTR pszParentObjectID, [in] IPortableDeviceValues *pFilter, [out] // HRESULT EnumObjects( [in] const DWORD dwFlags, [in] LPCWSTR pszParentObjectID, [in] IPortableDeviceValues *pFilter, [out]
// IEnumPortableDeviceObjectIDs **ppEnum ); // IEnumPortableDeviceObjectIDs **ppEnum );
new IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID, new IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID,
[In, Optional] IPortableDeviceValues pFilter); [In, Optional] IPortableDeviceValues? pFilter);
/// <summary> /// <summary>
/// The <c>Properties</c> method retrieves the interface that is required to get or set properties on an object on the device. /// The <c>Properties</c> method retrieves the interface that is required to get or set properties on an object on the device.
@ -1293,7 +1293,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceeventcallback-onevent // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceeventcallback-onevent
// HRESULT OnEvent( [in] IPortableDeviceValues *pEventParameters ); // HRESULT OnEvent( [in] IPortableDeviceValues *pEventParameters );
void OnEvent([Optional] IPortableDeviceValues pEventParameters); void OnEvent([Optional] IPortableDeviceValues? pEventParameters);
} }
/// <summary> /// <summary>
@ -1341,7 +1341,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getdevices // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getdevices
// HRESULT GetDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs ); // HRESULT GetDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs );
[PreserveSig] [PreserveSig]
HRESULT GetDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] pPnPDeviceIDs, HRESULT GetDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[]? pPnPDeviceIDs,
ref uint pcPnPDeviceIDs); ref uint pcPnPDeviceIDs);
/// <summary>The <c>RefreshDeviceList</c> method refreshes the list of devices that are connected to the computer.</summary> /// <summary>The <c>RefreshDeviceList</c> method refreshes the list of devices that are connected to the computer.</summary>
@ -1385,7 +1385,7 @@ public static partial class PortableDeviceApi
// HRESULT GetDeviceFriendlyName( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceFriendlyName, [in, out] DWORD // HRESULT GetDeviceFriendlyName( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceFriendlyName, [in, out] DWORD
// *pcchDeviceFriendlyName ); // *pcchDeviceFriendlyName );
[PreserveSig] [PreserveSig]
HRESULT GetDeviceFriendlyName([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pDeviceFriendlyName, HRESULT GetDeviceFriendlyName([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder? pDeviceFriendlyName,
[In, Out] ref uint pcchDeviceFriendlyName); [In, Out] ref uint pcchDeviceFriendlyName);
/// <summary>Retrieves the description of a device.</summary> /// <summary>Retrieves the description of a device.</summary>
@ -1407,7 +1407,7 @@ public static partial class PortableDeviceApi
// HRESULT GetDeviceDescription( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceDescription, [in, out] DWORD // HRESULT GetDeviceDescription( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceDescription, [in, out] DWORD
// *pcchDeviceDescription ); // *pcchDeviceDescription );
[PreserveSig] [PreserveSig]
HRESULT GetDeviceDescription([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pDeviceDescription, HRESULT GetDeviceDescription([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder? pDeviceDescription,
[In, Out] ref uint pcchDeviceDescription); [In, Out] ref uint pcchDeviceDescription);
/// <summary>Retrieves the name of the device manufacturer.</summary> /// <summary>Retrieves the name of the device manufacturer.</summary>
@ -1429,7 +1429,7 @@ public static partial class PortableDeviceApi
// HRESULT GetDeviceManufacturer( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceManufacturer, [in, out] DWORD // HRESULT GetDeviceManufacturer( [in] LPCWSTR pszPnPDeviceID, [in, out] WCHAR *pDeviceManufacturer, [in, out] DWORD
// *pcchDeviceManufacturer ); // *pcchDeviceManufacturer );
[PreserveSig] [PreserveSig]
HRESULT GetDeviceManufacturer([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pDeviceManufacturer, HRESULT GetDeviceManufacturer([In, MarshalAs(UnmanagedType.LPWStr)] string pszPnPDeviceID, [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder? pDeviceManufacturer,
[In, Out] ref uint pcchDeviceManufacturer); [In, Out] ref uint pcchDeviceManufacturer);
/// <summary> /// <summary>
@ -1506,7 +1506,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getprivatedevices // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getprivatedevices
// HRESULT GetPrivateDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs ); // HRESULT GetPrivateDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs );
[PreserveSig] [PreserveSig]
HRESULT GetPrivateDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[] pPnPDeviceIDs, ref uint pcPnPDeviceIDs); HRESULT GetPrivateDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] string[]? pPnPDeviceIDs, ref uint pcPnPDeviceIDs);
} }
/// <summary> /// <summary>
@ -1573,7 +1573,7 @@ public static partial class PortableDeviceApi
/// </returns> /// </returns>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceproperties-getvalues // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceproperties-getvalues
// HRESULT GetValues( [in] LPCWSTR pszObjectID, [in] IPortableDeviceKeyCollection *pKeys, [out] IPortableDeviceValues **ppValues ); // HRESULT GetValues( [in] LPCWSTR pszObjectID, [in] IPortableDeviceKeyCollection *pKeys, [out] IPortableDeviceValues **ppValues );
IPortableDeviceValues GetValues([MarshalAs(UnmanagedType.LPWStr)] string pszObjectID, IPortableDeviceKeyCollection pKeys); IPortableDeviceValues GetValues([MarshalAs(UnmanagedType.LPWStr)] string pszObjectID, IPortableDeviceKeyCollection? pKeys);
/// <summary>The <c>SetValues</c> method adds or modifies one or more properties on a specified object on a device.</summary> /// <summary>The <c>SetValues</c> method adds or modifies one or more properties on a specified object on a device.</summary>
/// <param name="pszObjectID">The object ID of the object to modify. To specify the device, use WPD_DEVICE_OBJECT_ID.</param> /// <param name="pszObjectID">The object ID of the object to modify. To specify the device, use WPD_DEVICE_OBJECT_ID.</param>
@ -1675,7 +1675,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicepropertiesbulk-queuegetvaluesbyobjectlist // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicepropertiesbulk-queuegetvaluesbyobjectlist
// HRESULT QueueGetValuesByObjectList( [in] IPortableDevicePropVariantCollection *pObjectIDs, [in] IPortableDeviceKeyCollection // HRESULT QueueGetValuesByObjectList( [in] IPortableDevicePropVariantCollection *pObjectIDs, [in] IPortableDeviceKeyCollection
// *pKeys, [in] IPortableDevicePropertiesBulkCallback *pCallback, [out] GUID *pContext ); // *pKeys, [in] IPortableDevicePropertiesBulkCallback *pCallback, [out] GUID *pContext );
void QueueGetValuesByObjectList(IPortableDevicePropVariantCollection pObjectIDs, [Optional] IPortableDeviceKeyCollection pKeys, void QueueGetValuesByObjectList(IPortableDevicePropVariantCollection pObjectIDs, [Optional] IPortableDeviceKeyCollection? pKeys,
IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext); IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext);
/// <summary> /// <summary>
@ -1763,7 +1763,7 @@ public static partial class PortableDeviceApi
// *pContext ); // *pContext );
void QueueGetValuesByObjectFormat(in Guid pguidObjectFormat, void QueueGetValuesByObjectFormat(in Guid pguidObjectFormat,
[MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID, uint dwDepth, [MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID, uint dwDepth,
[Optional] IPortableDeviceKeyCollection pKeys, IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext); [Optional] IPortableDeviceKeyCollection? pKeys, IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext);
/// <summary> /// <summary>
/// The <c>QueueSetValuesByObjectList</c> method queues a request to set one or more specified values on one or more specified /// The <c>QueueSetValuesByObjectList</c> method queues a request to set one or more specified values on one or more specified
@ -2166,7 +2166,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservice-advise // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservice-advise
// HRESULT Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues // HRESULT Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues
// *pParameters, [out] LPWSTR *ppszCookie ); // *pParameters, [out] LPWSTR *ppszCookie );
void Advise([In, Optional] uint dwFlags, IPortableDeviceEventCallback pCallback, [In, Optional] IPortableDeviceValues pParameters, void Advise([In, Optional] uint dwFlags, IPortableDeviceEventCallback pCallback, [In, Optional] IPortableDeviceValues? pParameters,
[MarshalAs(UnmanagedType.LPWStr)] out string ppszCookie); [MarshalAs(UnmanagedType.LPWStr)] out string ppszCookie);
/// <summary>The <c>Unadvise</c> method unregisters a service event callback object.</summary> /// <summary>The <c>Unadvise</c> method unregisters a service event callback object.</summary>
@ -2552,7 +2552,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-invoke // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-invoke
// HRESULT Invoke( [in] REFGUID Method, [in] IPortableDeviceValues *pParameters, [in, out] IPortableDeviceValues **ppResults ); // HRESULT Invoke( [in] REFGUID Method, [in] IPortableDeviceValues *pParameters, [in, out] IPortableDeviceValues **ppResults );
void Invoke(in Guid Method, [Optional] IPortableDeviceValues pParameters, out IPortableDeviceValues ppResults); void Invoke(in Guid Method, [Optional] IPortableDeviceValues? pParameters, out IPortableDeviceValues ppResults);
/// <summary>The <c>InvokeAsync</c> method asynchronously invokes a method.</summary> /// <summary>The <c>InvokeAsync</c> method asynchronously invokes a method.</summary>
/// <param name="Method">The method to invoke.</param> /// <param name="Method">The method to invoke.</param>
@ -2577,7 +2577,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-invokeasync // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-invokeasync
// HRESULT InvokeAsync( [in] REFGUID Method, [in] IPortableDeviceValues *pParameters, [in] IPortableDeviceServiceMethodCallback // HRESULT InvokeAsync( [in] REFGUID Method, [in] IPortableDeviceValues *pParameters, [in] IPortableDeviceServiceMethodCallback
// *pCallback ); // *pCallback );
void InvokeAsync(in Guid Method, [Optional] IPortableDeviceValues pParameters, [Optional] IPortableDeviceServiceMethodCallback pCallback); void InvokeAsync(in Guid Method, [Optional] IPortableDeviceValues? pParameters, [Optional] IPortableDeviceServiceMethodCallback? pCallback);
/// <summary>The <c>Cancel</c> method cancels a pending method invocation.</summary> /// <summary>The <c>Cancel</c> method cancels a pending method invocation.</summary>
/// <param name="pCallback"> /// <param name="pCallback">
@ -2595,7 +2595,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-cancel // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-cancel
// HRESULT Cancel( [in] IPortableDeviceServiceMethodCallback *pCallback ); // HRESULT Cancel( [in] IPortableDeviceServiceMethodCallback *pCallback );
void Cancel([Optional] IPortableDeviceServiceMethodCallback pCallback); void Cancel([Optional] IPortableDeviceServiceMethodCallback? pCallback);
} }
/// <summary>Callback interface for implemented by clients for retrieving results of an asynchronous service open.</summary> /// <summary>Callback interface for implemented by clients for retrieving results of an asynchronous service open.</summary>
@ -2664,7 +2664,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getdeviceproperty // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getdeviceproperty
// HRESULT GetDeviceProperty( [in] LPCWSTR pszPnPDeviceID, [in] LPCWSTR pszDevicePropertyName, [in, out] BYTE *pData, [in, out] // HRESULT GetDeviceProperty( [in] LPCWSTR pszPnPDeviceID, [in] LPCWSTR pszDevicePropertyName, [in, out] BYTE *pData, [in, out]
// DWORD *pcbData, [in, out] DWORD *pdwType ); // DWORD *pcbData, [in, out] DWORD *pdwType );
public static T GetDeviceProperty<T>(this IPortableDeviceManager manager, string pszPnPDeviceID, string pszDevicePropertyName) public static T? GetDeviceProperty<T>(this IPortableDeviceManager manager, string pszPnPDeviceID, string pszDevicePropertyName)
{ {
var sz = 0U; var sz = 0U;
manager.GetDeviceProperty(pszPnPDeviceID, pszDevicePropertyName, default, ref sz, out _); manager.GetDeviceProperty(pszPnPDeviceID, pszDevicePropertyName, default, ref sz, out _);
@ -2672,7 +2672,7 @@ public static partial class PortableDeviceApi
return default; return default;
using var mem = new SafeCoTaskMemHandle(sz); using var mem = new SafeCoTaskMemHandle(sz);
manager.GetDeviceProperty(pszPnPDeviceID, pszDevicePropertyName, mem, ref sz, out var type); manager.GetDeviceProperty(pszPnPDeviceID, pszDevicePropertyName, mem, ref sz, out var type);
return (T)type.GetValue(mem, mem.Size); return (T?)type.GetValue(mem, mem.Size);
} }
/// <summary>Retrieves a list of portable devices connected to the computer.</summary> /// <summary>Retrieves a list of portable devices connected to the computer.</summary>
@ -2710,7 +2710,7 @@ public static partial class PortableDeviceApi
if (cnt == 0) if (cnt == 0)
return string.Empty; return string.Empty;
if (hr.Failed && hr != HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER)) if (hr.Failed && hr != HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER))
throw hr.GetException(); throw hr.GetException()!;
var sb = new StringBuilder((int)cnt + 1); var sb = new StringBuilder((int)cnt + 1);
if (cnt > 0) if (cnt > 0)
func(devId, sb, ref cnt).ThrowIfFailed(); func(devId, sb, ref cnt).ThrowIfFailed();
@ -2724,7 +2724,7 @@ public static partial class PortableDeviceApi
if (cnt == 0) if (cnt == 0)
return new string[0]; return new string[0];
if (hr.Failed && hr != HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER)) if (hr.Failed && hr != HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER))
throw hr.GetException(); throw hr.GetException()!;
var devices = new string[cnt]; var devices = new string[cnt];
if (cnt > 0) if (cnt > 0)
func(devices, ref cnt).ThrowIfFailed(); func(devices, ref cnt).ThrowIfFailed();

View File

@ -174,8 +174,8 @@ public static partial class PortableDeviceApi
/// </para> /// </para>
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceconnectapi/nf-portabledeviceconnectapi-iportabledeviceconnector-connect // https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceconnectapi/nf-portabledeviceconnectapi-iportabledeviceconnector-connect
// HRESULT Connect( [in, optional] IConnectionRequestCallback *pCallback ); // HRESULT Connect( [in, optional] IConnectionRequestCallback? *pCallback );
void Connect([Optional] IConnectionRequestCallback pCallback); void Connect([Optional] IConnectionRequestCallback? pCallback);
/// <summary>The <c>Disconnect</c> method sends an asynchronous disconnect request to the MTP/Bluetooth device.</summary> /// <summary>The <c>Disconnect</c> method sends an asynchronous disconnect request to the MTP/Bluetooth device.</summary>
/// <param name="pCallback">A pointer to an IConnectionRequestCallback interface.</param> /// <param name="pCallback">A pointer to an IConnectionRequestCallback interface.</param>

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using static Vanara.PInvoke.Ole32; using static Vanara.PInvoke.Ole32;
@ -19,18 +20,18 @@ public static class PortableDeviceExtensions
/// <param name="parentType">The type in which <paramref name="cmd"/> is defined, if not other than <see cref="Vanara.PInvoke.PortableDeviceApi"/>.</param> /// <param name="parentType">The type in which <paramref name="cmd"/> is defined, if not other than <see cref="Vanara.PInvoke.PortableDeviceApi"/>.</param>
/// <returns>A dictionary containing the result values.</returns> /// <returns>A dictionary containing the result values.</returns>
/// <exception cref="System.InvalidOperationException">Supplied PROPERTYKEY is not a recognized WPD command.</exception> /// <exception cref="System.InvalidOperationException">Supplied PROPERTYKEY is not a recognized WPD command.</exception>
public static IReadOnlyDictionary<PROPERTYKEY, object> ExtractResults(this IPortableDeviceValues results, in PROPERTYKEY cmd, Type parentType = null) public static IReadOnlyDictionary<PROPERTYKEY, object?> ExtractResults(this IPortableDeviceValues results, in PROPERTYKEY cmd, Type? parentType = null)
{ {
if (!cmd.TryGetCommandInfo(out _, out _, out var rAttrs, parentType)) if (!cmd.TryGetCommandInfo(out _, out _, out var rAttrs, parentType))
throw new InvalidOperationException("Supplied PROPERTYKEY is not a recognized WPD command."); throw new InvalidOperationException("Supplied PROPERTYKEY is not a recognized WPD command.");
var ret = new Dictionary<PROPERTYKEY, object>(); var ret = new Dictionary<PROPERTYKEY, object?>();
foreach (var a in rAttrs) foreach (var a in rAttrs)
{ {
PROPVARIANT pv = new(); PROPVARIANT pv = new();
try { pv = results.GetValue(a.Property); } catch { } try { pv = results.GetValue(a.Property); } catch { }
ret.Add(a.Property, pv.Value); ret.Add(a.Property, pv.Value);
} }
return (IReadOnlyDictionary<PROPERTYKEY, object>)ret; return ret;
} }
/// <summary>Sends a command to the device and retrieves the results synchronously.</summary> /// <summary>Sends a command to the device and retrieves the results synchronously.</summary>
@ -38,7 +39,7 @@ public static class PortableDeviceExtensions
/// <param name="cmd">The command's PROPERTYKEY.</param> /// <param name="cmd">The command's PROPERTYKEY.</param>
/// <param name="pkResult">The PROPERTYKEY of the result value to return.</param> /// <param name="pkResult">The PROPERTYKEY of the result value to return.</param>
/// <returns>The value returned in <paramref name="pkResult"/>.</returns> /// <returns>The value returned in <paramref name="pkResult"/>.</returns>
public static object SendCommand(this IPortableDevice device, in PROPERTYKEY cmd, in PROPERTYKEY pkResult) => public static object? SendCommand(this IPortableDevice device, in PROPERTYKEY cmd, in PROPERTYKEY pkResult) =>
device.SendCommand(cmd).GetValue(pkResult).Value; device.SendCommand(cmd).GetValue(pkResult).Value;
/// <summary>Sends a command to the device and retrieves the results synchronously.</summary> /// <summary>Sends a command to the device and retrieves the results synchronously.</summary>
@ -49,7 +50,7 @@ public static class PortableDeviceExtensions
/// cref="IPortableDevice.SendCommand(uint, IPortableDeviceValues)"/>. /// cref="IPortableDevice.SendCommand(uint, IPortableDeviceValues)"/>.
/// </param> /// </param>
/// <returns>The <see cref="IPortableDeviceValues"/> instance returned by <see cref="IPortableDevice.SendCommand(uint, IPortableDeviceValues)"/>.</returns> /// <returns>The <see cref="IPortableDeviceValues"/> instance returned by <see cref="IPortableDevice.SendCommand(uint, IPortableDeviceValues)"/>.</returns>
public static IPortableDeviceValues SendCommand(this IPortableDevice device, in PROPERTYKEY cmd, Action<IPortableDeviceValues> addParams = null) public static IPortableDeviceValues SendCommand(this IPortableDevice device, in PROPERTYKEY cmd, Action<IPortableDeviceValues>? addParams = null)
{ {
IPortableDeviceValues cmdParams = new(); IPortableDeviceValues cmdParams = new();
cmdParams.SetCommandPKey(cmd); cmdParams.SetCommandPKey(cmd);
@ -104,7 +105,7 @@ public static class PortableDeviceExtensions
/// The reflection based lookup is cached so that subsequent lookups are accelerated. As such, expect a slower response the first /// The reflection based lookup is cached so that subsequent lookups are accelerated. As such, expect a slower response the first
/// time this method is called with each unique <paramref name="parentType"/>. /// time this method is called with each unique <paramref name="parentType"/>.
/// </remarks> /// </remarks>
public static bool TryGetCommandInfo(this PROPERTYKEY key, out WPDCommandAttribute cmd, out WPDCommandParamAttribute[] param, out WPDCommandResultAttribute[] result, Type parentType = null) public static bool TryGetCommandInfo(this PROPERTYKEY key, [NotNullWhen(true)] out WPDCommandAttribute? cmd, [NotNullWhen(true)] out WPDCommandParamAttribute[]? param, [NotNullWhen(true)] out WPDCommandResultAttribute[]? result, Type? parentType = null)
{ {
var pi = GetPI(key, parentType); var pi = GetPI(key, parentType);
parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi); parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi);
@ -124,7 +125,7 @@ public static class PortableDeviceExtensions
return false; return false;
} }
internal static PROPERTYKEY? GetKeyFromName(string keyName, Type parentType = null) internal static PROPERTYKEY? GetKeyFromName(string keyName, Type? parentType = null)
{ {
parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi); parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi);
var kv = GetDict(parentType).FirstOrDefault(kv => kv.Value.Name == keyName); var kv = GetDict(parentType).FirstOrDefault(kv => kv.Value.Name == keyName);
@ -135,13 +136,13 @@ public static class PortableDeviceExtensions
{ {
if (!gReversePKLookup.TryGetValue(type, out var dict)) if (!gReversePKLookup.TryGetValue(type, out var dict))
{ {
dict = type.GetProperties(BindStPub).ToDictionary(m => (PROPERTYKEY)m.GetValue(null, null)); dict = type.GetProperties(BindStPub).ToDictionary(m => (PROPERTYKEY)m.GetValue(null, null)!);
gReversePKLookup.Add(type, dict); gReversePKLookup.Add(type, dict);
} }
return dict; return dict;
} }
private static PropertyInfo GetPI(in PROPERTYKEY key, Type parentType = null) private static PropertyInfo? GetPI(in PROPERTYKEY key, Type? parentType = null)
{ {
parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi); parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi);
return GetDict(parentType).TryGetValue(key, out var pi) ? pi : null; return GetDict(parentType).TryGetValue(key, out var pi) ? pi : null;

View File

@ -203,7 +203,7 @@ public static partial class PortableDeviceApi
/// </remarks> /// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/wpd_sdk/iportabledevicevalues-getat HRESULT GetAt( [in] const DWORD index, // https://docs.microsoft.com/en-us/windows/win32/wpd_sdk/iportabledevicevalues-getat HRESULT GetAt( [in] const DWORD index,
// [in, out] PROPERTYKEY *pKey, [in, out] PROPVARIANT *pValue ); // [in, out] PROPERTYKEY *pKey, [in, out] PROPVARIANT *pValue );
void GetAt(uint index, out PROPERTYKEY pKey, [Out] PROPVARIANT pValue); void GetAt(uint index, out PROPERTYKEY pKey, [Out] PROPVARIANT? pValue);
/// <summary>The <c>SetValue</c> method adds a new <c>PROPVARIANT</c> value or overwrites an existing one.</summary> /// <summary>The <c>SetValue</c> method adds a new <c>PROPVARIANT</c> value or overwrites an existing one.</summary>
/// <param name="key">A <c>REFPROPERTYKEY</c> that specifies the item to create or overwrite.</param> /// <param name="key">A <c>REFPROPERTYKEY</c> that specifies the item to create or overwrite.</param>

View File

@ -11,8 +11,10 @@ namespace Vanara.PInvoke.Tests;
[TestFixture] [TestFixture]
public class PortableDeviceApiTests public class PortableDeviceApiTests
{ {
IPortableDevice device = null; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
IPortableDevice device;
IPortableDeviceManager manager; IPortableDeviceManager manager;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
static readonly Ole32.PROPERTYKEY eventNameProp = new(Guid.NewGuid(), 1); static readonly Ole32.PROPERTYKEY eventNameProp = new(Guid.NewGuid(), 1);
[OneTimeSetUp] [OneTimeSetUp]
@ -28,8 +30,6 @@ namespace Vanara.PInvoke.Tests;
public void _TearDown() public void _TearDown()
{ {
device?.Close(); device?.Close();
device = null;
manager = null;
} }
[Test] [Test]
@ -47,10 +47,10 @@ namespace Vanara.PInvoke.Tests;
class EventCallback : IPortableDeviceEventCallback class EventCallback : IPortableDeviceEventCallback
{ {
void IPortableDeviceEventCallback.OnEvent(IPortableDeviceValues pEventParameters) void IPortableDeviceEventCallback.OnEvent(IPortableDeviceValues? pEventParameters)
{ {
var evtName = pEventParameters.GetStringValue(eventNameProp); var evtName = pEventParameters?.GetStringValue(eventNameProp);
if (EventWaitHandle.TryOpenExisting(evtName, out var evt)) if (evtName is not null && EventWaitHandle.TryOpenExisting(evtName, out var evt))
evt.Set(); evt.Set();
} }
} }
@ -106,13 +106,13 @@ namespace Vanara.PInvoke.Tests;
{ {
var caps = device.Capabilities(); var caps = device.Capabilities();
foreach (var catid in caps.GetFunctionalCategories().Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid.Value)) foreach (var catid in caps.GetFunctionalCategories().Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid!.Value))
{ {
TestContext.WriteLine(GetPI(catid, "WPD_FUNCTIONAL_CATEGORY_")?.Name ?? catid.ToString()); TestContext.WriteLine(GetPI(catid, "WPD_FUNCTIONAL_CATEGORY_")?.Name ?? catid.ToString());
foreach (var type in caps.GetSupportedContentTypes(catid).Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid.Value)) foreach (var type in caps.GetSupportedContentTypes(catid).Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid!.Value))
{ {
TestContext.WriteLine(" t: " + (GetPI(type, "WPD_CONTENT_TYPE_")?.Name ?? type.ToString())); TestContext.WriteLine(" t: " + (GetPI(type, "WPD_CONTENT_TYPE_")?.Name ?? type.ToString()));
foreach (var fmt in caps.GetSupportedFormats(type).Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid.Value)) foreach (var fmt in caps.GetSupportedFormats(type).Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid!.Value))
TestContext.WriteLine(" f: " + (GetPI(fmt, "WPD_OBJECT_FORMAT_")?.Name ?? type.ToString())); TestContext.WriteLine(" f: " + (GetPI(fmt, "WPD_OBJECT_FORMAT_")?.Name ?? type.ToString()));
} }
foreach (var obj in caps.GetFunctionalObjects(catid).Enumerate().Where(pv => pv.VarType == VarEnum.VT_LPWSTR).Select(pv => pv.pwszVal)) foreach (var obj in caps.GetFunctionalObjects(catid).Enumerate().Where(pv => pv.VarType == VarEnum.VT_LPWSTR).Select(pv => pv.pwszVal))
@ -173,7 +173,7 @@ namespace Vanara.PInvoke.Tests;
{ {
var caps = device.Capabilities(); var caps = device.Capabilities();
foreach (var evt in caps.GetSupportedEvents().Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid.Value)) foreach (var evt in caps.GetSupportedEvents().Enumerate().Where(pv => pv.VarType == VarEnum.VT_CLSID).Select(pv => pv.puuid!.Value))
{ {
TestContext.WriteLine(GetPI(evt, "WPD_EVENT_")?.Name ?? evt.ToString()); TestContext.WriteLine(GetPI(evt, "WPD_EVENT_")?.Name ?? evt.ToString());
foreach (var opt in caps.GetEventOptions(evt).Enumerate()) foreach (var opt in caps.GetEventOptions(evt).Enumerate())
@ -181,9 +181,9 @@ namespace Vanara.PInvoke.Tests;
} }
} }
private static PropertyInfo GetPI<T>(T t, string prefix) => private static PropertyInfo? GetPI<T>(T t, string prefix) =>
typeof(PortableDeviceApi).GetProperties(BindingFlags.Public | BindingFlags.Static). typeof(PortableDeviceApi).GetProperties(BindingFlags.Public | BindingFlags.Static).
FirstOrDefault(pi => pi.Name.StartsWith(prefix) && pi.PropertyType.Equals(typeof(T)) && t.Equals(pi.GetValue(null))); FirstOrDefault(pi => pi.Name.StartsWith(prefix) && pi.PropertyType.Equals(typeof(T)) && Equals(t, pi.GetValue(null)));
private IPortableDeviceValues GetClientInfo(bool readOnly = true) private IPortableDeviceValues GetClientInfo(bool readOnly = true)
{ {