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;
namespace Vanara.PInvoke;
@ -29,62 +30,80 @@ public static partial class PortableDeviceApi
/****************************************************************************
* 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;
// 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);
// 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);
// 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));
// Pre-defined ObjectID for the DEVICE object.
/// <summary>Pre-defined ObjectID for the DEVICE object.</summary>
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);
// Pre-defined name of a REG_DWORD value that defines the device type, used for representation purposes only. Functional
// characteristics 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>
/// Pre-defined name of a REG_DWORD value that defines the device type, used for representation purposes only. Functional characteristics
/// 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";
// 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
// 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>
/// 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
/// 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";
// 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>
/// 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";
// 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 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>
/// 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
/// 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";
// 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 portable device namespace should attempt to automatically generate a thumbnail when placing new content on the device. This
// value can be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Values should be a string representation of a GUID,
// in the form '{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>
/// 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
/// portable device namespace should attempt to automatically generate a thumbnail when placing new content on the device. This value can
/// be retrieved using IPortableDeviceManager::GetDeviceProperty(...). Values should be a string representation of a GUID, in the form
/// '{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";
// 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 avoid duplication of the device in certain views and scenarios that include both file system and Portable Devices. This value
// can be 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>
/// 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
/// avoid duplication of the device in certain views and scenarios that include both file system and Portable Devices. This value can be
/// 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";
// 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>
/// 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";
// 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>
/// 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";
/****************************************************************************
@ -4687,7 +4706,7 @@ public static partial class PortableDeviceApi
/// <param name="ControlCode">The control code.</param>
/// <param name="pCommandParams">The <see cref="IPortableDeviceValues"/> instance.</param>
/// <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;
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;
}
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)]
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;
AccessDependency = GetWPDPKey(depProp);

View File

@ -9,9 +9,9 @@ public static partial class PortableDeviceApi
{
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>
/// 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>
// 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 );
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>
/// <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
// Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues *pParameters,
// [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>
/// 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>
// 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 );
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>
/// <remarks>
@ -653,7 +653,7 @@ public static partial class PortableDeviceApi
// HRESULT EnumObjects( [in] const DWORD dwFlags, [in] LPCWSTR pszParentObjectID, [in] IPortableDeviceValues *pFilter, [out]
// IEnumPortableDeviceObjectIDs **ppEnum );
IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID,
[In, Optional] IPortableDeviceValues pFilter);
[In, Optional] IPortableDeviceValues? pFilter);
/// <summary>
/// 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]
// IEnumPortableDeviceObjectIDs **ppEnum );
new IEnumPortableDeviceObjectIDs EnumObjects([Optional] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID,
[In, Optional] IPortableDeviceValues pFilter);
[In, Optional] IPortableDeviceValues? pFilter);
/// <summary>
/// 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>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceeventcallback-onevent
// HRESULT OnEvent( [in] IPortableDeviceValues *pEventParameters );
void OnEvent([Optional] IPortableDeviceValues pEventParameters);
void OnEvent([Optional] IPortableDeviceValues? pEventParameters);
}
/// <summary>
@ -1341,7 +1341,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getdevices
// HRESULT GetDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs );
[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);
/// <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
// *pcchDeviceFriendlyName );
[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);
/// <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
// *pcchDeviceDescription );
[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);
/// <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
// *pcchDeviceManufacturer );
[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);
/// <summary>
@ -1506,7 +1506,7 @@ public static partial class PortableDeviceApi
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledevicemanager-getprivatedevices
// HRESULT GetPrivateDevices( [in, out] LPWSTR *pPnPDeviceIDs, [in, out] DWORD *pcPnPDeviceIDs );
[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>
@ -1573,7 +1573,7 @@ public static partial class PortableDeviceApi
/// </returns>
// 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 );
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>
/// <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
// HRESULT QueueGetValuesByObjectList( [in] IPortableDevicePropVariantCollection *pObjectIDs, [in] IPortableDeviceKeyCollection
// *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);
/// <summary>
@ -1763,7 +1763,7 @@ public static partial class PortableDeviceApi
// *pContext );
void QueueGetValuesByObjectFormat(in Guid pguidObjectFormat,
[MarshalAs(UnmanagedType.LPWStr)] string pszParentObjectID, uint dwDepth,
[Optional] IPortableDeviceKeyCollection pKeys, IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext);
[Optional] IPortableDeviceKeyCollection? pKeys, IPortableDevicePropertiesBulkCallback pCallback, out Guid pContext);
/// <summary>
/// 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
// HRESULT Advise( [in] const DWORD dwFlags, [in] IPortableDeviceEventCallback *pCallback, [in] IPortableDeviceValues
// *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);
/// <summary>The <c>Unadvise</c> method unregisters a service event callback object.</summary>
@ -2552,7 +2552,7 @@ public static partial class PortableDeviceApi
/// </remarks>
// 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 );
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>
/// <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
// HRESULT InvokeAsync( [in] REFGUID Method, [in] IPortableDeviceValues *pParameters, [in] IPortableDeviceServiceMethodCallback
// *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>
/// <param name="pCallback">
@ -2595,7 +2595,7 @@ public static partial class PortableDeviceApi
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceapi/nf-portabledeviceapi-iportabledeviceservicemethods-cancel
// 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>
@ -2664,7 +2664,7 @@ public static partial class PortableDeviceApi
// 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]
// 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;
manager.GetDeviceProperty(pszPnPDeviceID, pszDevicePropertyName, default, ref sz, out _);
@ -2672,7 +2672,7 @@ public static partial class PortableDeviceApi
return default;
using var mem = new SafeCoTaskMemHandle(sz);
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>
@ -2710,7 +2710,7 @@ public static partial class PortableDeviceApi
if (cnt == 0)
return string.Empty;
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);
if (cnt > 0)
func(devId, sb, ref cnt).ThrowIfFailed();
@ -2724,7 +2724,7 @@ public static partial class PortableDeviceApi
if (cnt == 0)
return new string[0];
if (hr.Failed && hr != HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER))
throw hr.GetException();
throw hr.GetException()!;
var devices = new string[cnt];
if (cnt > 0)
func(devices, ref cnt).ThrowIfFailed();

View File

@ -174,8 +174,8 @@ public static partial class PortableDeviceApi
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/portabledeviceconnectapi/nf-portabledeviceconnectapi-iportabledeviceconnector-connect
// HRESULT Connect( [in, optional] IConnectionRequestCallback *pCallback );
void Connect([Optional] IConnectionRequestCallback pCallback);
// HRESULT Connect( [in, 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>
/// <param name="pCallback">A pointer to an IConnectionRequestCallback interface.</param>

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
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>
/// <returns>A dictionary containing the result values.</returns>
/// <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))
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)
{
PROPVARIANT pv = new();
try { pv = results.GetValue(a.Property); } catch { }
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>
@ -38,7 +39,7 @@ public static class PortableDeviceExtensions
/// <param name="cmd">The command's PROPERTYKEY.</param>
/// <param name="pkResult">The PROPERTYKEY of the result value to return.</param>
/// <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;
/// <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)"/>.
/// </param>
/// <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();
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
/// time this method is called with each unique <paramref name="parentType"/>.
/// </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);
parentType ??= typeof(Vanara.PInvoke.PortableDeviceApi);
@ -124,7 +125,7 @@ public static class PortableDeviceExtensions
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);
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))
{
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);
}
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);
return GetDict(parentType).TryGetValue(key, out var pi) ? pi : null;

View File

@ -203,7 +203,7 @@ public static partial class PortableDeviceApi
/// </remarks>
// 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 );
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>
/// <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]
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;
#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);
[OneTimeSetUp]
@ -28,8 +30,6 @@ namespace Vanara.PInvoke.Tests;
public void _TearDown()
{
device?.Close();
device = null;
manager = null;
}
[Test]
@ -47,10 +47,10 @@ namespace Vanara.PInvoke.Tests;
class EventCallback : IPortableDeviceEventCallback
{
void IPortableDeviceEventCallback.OnEvent(IPortableDeviceValues pEventParameters)
void IPortableDeviceEventCallback.OnEvent(IPortableDeviceValues? pEventParameters)
{
var evtName = pEventParameters.GetStringValue(eventNameProp);
if (EventWaitHandle.TryOpenExisting(evtName, out var evt))
var evtName = pEventParameters?.GetStringValue(eventNameProp);
if (evtName is not null && EventWaitHandle.TryOpenExisting(evtName, out var evt))
evt.Set();
}
}
@ -106,13 +106,13 @@ namespace Vanara.PInvoke.Tests;
{
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());
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()));
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()));
}
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();
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());
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).
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)
{