Compare commits

...

3 Commits

Author SHA1 Message Date
David Hall aefc44abcf Added nullability to VssApi and test 2023-10-21 19:45:24 -06:00
David Hall 8128098af6 Added nullability to WcmApi and test 2023-10-21 08:42:54 -06:00
David Hall f976001980 Added nullability to UserEnv and tests 2023-10-20 18:31:22 -06:00
13 changed files with 126 additions and 111 deletions

View File

@ -1,4 +1,5 @@
using System.Linq;
using Microsoft.Win32.SafeHandles;
using System.Linq;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Kernel32;
@ -144,7 +145,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = false, ExactSpelling = true)]
[PInvokeData("userenv.h", MSDNShortId = "73F5F30F-4083-4D33-B181-31B782AD40D6")]
public static extern HRESULT CreateAppContainerProfile([MarshalAs(UnmanagedType.LPWStr)] string pszAppContainerName, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
[MarshalAs(UnmanagedType.LPWStr)] string pszDescription, [In] SID_AND_ATTRIBUTES[] pCapabilities, uint dwCapabilityCount, out SafeAllocatedSID ppSidAppContainerSid);
[MarshalAs(UnmanagedType.LPWStr)] string pszDescription, [In] SID_AND_ATTRIBUTES[]? pCapabilities, uint dwCapabilityCount, out SafeAllocatedSID ppSidAppContainerSid);
/// <summary>
/// Retrieves the environment variables for the specified user. This block can then be passed to the CreateProcessAsUser function.
@ -189,7 +190,7 @@ public static partial class UserEnv
[PInvokeData("userenv.h", MSDNShortId = "bda8879d-d33a-48f4-8b08-e3a279126a07")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateEnvironmentBlock([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(EnvBlockMarshaler))] out string[] lpEnvironment,
HTOKEN hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
[Optional] HTOKEN hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
/// <summary>
/// Retrieves the environment variables for the specified user. This block can then be passed to the CreateProcessAsUser function.
@ -238,7 +239,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, ExactSpelling = true)]
[PInvokeData("userenv.h", MSDNShortId = "bda8879d-d33a-48f4-8b08-e3a279126a07")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, HTOKEN hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, [Optional] HTOKEN hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
/// <summary>Creates a new user profile.</summary>
/// <param name="pszUserSid">
@ -481,7 +482,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("userenv.h", MSDNShortId = "d32fa6c8-035a-4c84-b210-5366f21b6c17")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ExpandEnvironmentStringsForUser(HTOKEN hToken, string lpSrc, StringBuilder lpDest, uint dwSize);
public static extern bool ExpandEnvironmentStringsForUser([Optional] HTOKEN hToken, string lpSrc, StringBuilder lpDest, uint dwSize);
/// <summary>The <c>FreeGPOList</c> function frees the specified list of GPOs.</summary>
/// <param name="pGPOList">
@ -532,7 +533,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("userenv.h", MSDNShortId = "bd08947a-df57-4dd9-b9ba-a01b315bfdf1")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetAllUsersProfileDirectory(StringBuilder lpProfileDir, ref uint lpcchSize);
public static extern bool GetAllUsersProfileDirectory(StringBuilder? lpProfileDir, ref uint lpcchSize);
/// <summary>Gets the path of the local app data folder for the specified app container.</summary>
/// <param name="pszAppContainerSid">A pointer to the SID of the app container.</param>
@ -608,7 +609,7 @@ public static partial class UserEnv
// GetAppContainerRegistryLocation( REGSAM desiredAccess, PHKEY phAppContainerKey );
[DllImport(Lib.Userenv, SetLastError = false, ExactSpelling = true)]
[PInvokeData("userenv.h", MSDNShortId = "DAD7EC07-D57D-40F5-AA99-AD7579910294")]
public static extern HRESULT GetAppContainerRegistryLocation(REGSAM desiredAccess, out HKEY phAppContainerKey);
public static extern HRESULT GetAppContainerRegistryLocation(REGSAM desiredAccess, out SafeRegistryHandle phAppContainerKey);
/// <summary>The <c>GetAppliedGPOList</c> function retrieves the list of GPOs applied for the specified user or computer.</summary>
/// <param name="dwFlags">
@ -714,7 +715,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("userenv.h", MSDNShortId = "14ff99cb-838a-442b-9f51-414bd7c0a2ef")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetDefaultUserProfileDirectory(StringBuilder lpProfileDir, ref uint lpcchSize);
public static extern bool GetDefaultUserProfileDirectory(StringBuilder? lpProfileDir, ref uint lpcchSize);
/// <summary>
/// The <c>GetGPOList</c> function retrieves the list of GPOs for the specified user or computer. This function can be called in two
@ -912,7 +913,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("userenv.h", MSDNShortId = "e21411fa-f7e1-4944-93ce-7d9314d79fbf")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetProfilesDirectory(StringBuilder lpProfileDir, ref uint lpcchSize);
public static extern bool GetProfilesDirectory(StringBuilder? lpProfileDir, ref uint lpcchSize);
/// <summary>Retrieves the type of profile loaded for the current user.</summary>
/// <param name="dwFlags">
@ -990,7 +991,7 @@ public static partial class UserEnv
[DllImport(Lib.Userenv, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("userenv.h", MSDNShortId = "b5de762d-c9ee-42b0-bce0-e74bcc9c78f0")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetUserProfileDirectory(HTOKEN hToken, StringBuilder lpProfileDir, ref uint lpcchSize);
public static extern bool GetUserProfileDirectory(HTOKEN hToken, StringBuilder? lpProfileDir, ref uint lpcchSize);
/// <summary>
/// The <c>LeaveCriticalPolicySection</c> function resumes the background application of policy. This function closes the handle to
@ -1560,7 +1561,7 @@ public static partial class UserEnv
/// <para>A pointer to the name of the user. This member is used as the base name of the directory in which to store a new profile.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpUserName;
public string? lpUserName;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
@ -1571,14 +1572,14 @@ public static partial class UserEnv
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpProfilePath;
public string? lpProfilePath;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
/// <para>A pointer to the default user profile path. This member can be <c>NULL</c>.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDefaultPath;
public string? lpDefaultPath;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
@ -1592,7 +1593,7 @@ public static partial class UserEnv
/// <para>Not used, set to <c>NULL</c>.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpPolicyPath;
public string? lpPolicyPath;
/// <summary>
/// <para>Type: <c>HANDLE</c></para>
@ -1603,12 +1604,13 @@ public static partial class UserEnv
/// <summary>Initializes a new instance of the <see cref="PROFILEINFO"/> struct.</summary>
/// <param name="userName">Name of the user.</param>
/// <param name="allowUI">If set to <see langword="false"/>, prevents the display of profile error messages..</param>
public PROFILEINFO(string userName, bool allowUI = true)
public PROFILEINFO(string? userName, bool allowUI = true)
{
dwSize = Default.dwSize;
dwFlags = allowUI ? 0 : ProfileInfoFlags.PI_NOUI;
lpUserName = userName;
lpProfilePath = lpDefaultPath = lpServerName = lpPolicyPath = null;
lpProfilePath = lpDefaultPath = lpPolicyPath = null;
lpServerName = "";
hProfile = HKEY.NULL;
}

View File

@ -96,7 +96,8 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(MSBuildThisFileDirectory)..\VssApiMgd\bin\$(Configuration)\$(TargetFramework)</AdditionalUsingDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
</ClCompile>
@ -109,7 +110,8 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(MSBuildThisFileDirectory)..\VssApiMgd\bin\$(Configuration)\$(TargetFramework)</AdditionalUsingDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
</ClCompile>
@ -122,7 +124,8 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(MSBuildThisFileDirectory)..\VssApiMgd\bin\$(Configuration)\$(TargetFramework)</AdditionalUsingDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
</ClCompile>
@ -141,7 +144,8 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(MSBuildThisFileDirectory)..\VssApiMgd\bin\$(Configuration)\$(TargetFramework)</AdditionalUsingDirectories>
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
</ClCompile>
@ -156,7 +160,7 @@
</CustomBuildStep>-->
</ItemDefinitionGroup>
<ItemGroup>
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="6.4.0">
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="6.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@ -190,6 +194,9 @@
<ItemGroup>
<ProjectReference Include="..\VssApiMgd\Vanara.PInvoke.VssApiMgd.csproj">
<Project>{39aedd51-c627-41b9-96d3-44f481ed4e7c}</Project>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<!--<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>false</LinkLibraryDependencies>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>-->

View File

@ -336,27 +336,27 @@ public struct VDS_LUN_INFORMATION
/// value is zero.
/// </summary>
[MarshalAs(UnmanagedType.LPStr)]
public string m_szVendorId;
public string? m_szVendorId;
/// <summary>
/// Pointer to the LUN product identifier, typically a model number; a zero-terminated, human-readable string. For devices that have
/// no product identifier, the value is zero.
/// </summary>
[MarshalAs(UnmanagedType.LPStr)]
public string m_szProductId;
public string? m_szProductId;
/// <summary>
/// Pointer to the LUN product revision; a zero-terminated, human-readable string. For devices that have no product revision, the
/// value is zero.
/// </summary>
[MarshalAs(UnmanagedType.LPStr)]
public string m_szProductRevision;
public string? m_szProductRevision;
/// <summary>
/// Pointer to the LUN serial number; a zero-terminated, human-readable string. For devices that have no serial number, the value is zero.
/// </summary>
[MarshalAs(UnmanagedType.LPStr)]
public string m_szSerialNumber;
public string? m_szSerialNumber;
/// <summary>
/// The signature of the LUN. For disks that use the Master Boot Record (MBR) partitioning structure, the first 32 bits of the GUID

View File

@ -144,5 +144,4 @@ public interface IVssAdminEx : IVssAdmin
/// <summary>CLSID_VSSCoordinator.</summary>
[ComImport, Guid("E579AB5F-1CC4-44b4-BED9-DE0991FF0623"), ClassInterface(ClassInterfaceType.None)]
public class VSSCoordinator
{ }
public class VSSCoordinator { }

View File

@ -468,7 +468,7 @@ public interface IVssBackupComponents
/// </param>
// https://docs.microsoft.com/en-us/windows/win32/api/vsbackup/nf-vsbackup-ivssbackupcomponentsex3-addsnapshottorecoveryset HRESULT
// AddSnapshotToRecoverySet( [in] VSS_ID snapshotId, [in] DWORD dwFlags, [in, optional] VSS_PWSZ pwszDestinationVolume );
void AddSnapshotToRecoverySet(Guid snapshotId, [Optional] uint dwFlags, string pwszDestinationVolume = default);
void AddSnapshotToRecoverySet(Guid snapshotId, [Optional] uint dwFlags, string? pwszDestinationVolume = default);
/// <summary>The <c>AddToSnapshotSet</c> method adds an original volume or original remote file share to the shadow copy set.</summary>
/// <param name="pwszVolumeName">
@ -528,7 +528,7 @@ public interface IVssBackupComponents
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/vsbackup/nf-vsbackup-ivssbackupcomponents-addtosnapshotset HRESULT
// AddToSnapshotSet( [in] VSS_PWSZ pwszVolumeName, [in] VSS_ID ProviderId, [out] VSS_ID *pidSnapshot );
Guid AddToSnapshotSet(string pwszVolumeName, Guid ProviderId);
Guid AddToSnapshotSet(string pwszVolumeName, [Optional] Guid ProviderId);
/// <summary>
/// The <c>BackupComplete</c> method causes VSS to generate a <c>BackupComplete</c> event, which signals writers that the backup
@ -1049,7 +1049,7 @@ public interface IVssBackupComponents
/// <para>This method cannot be called for a virtual hard disk (VHD) that is nested inside another VHD.</para>
/// <para><c>Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP:</c> VHDs are not supported.</para>
/// </remarks>
bool IsVolumeSupported(Guid ProviderId, string pwszVolumeName);
bool IsVolumeSupported([Optional] Guid ProviderId, string pwszVolumeName);
/// <summary>
/// The <c>PostRestore</c> method will cause VSS to generate a <c>PostRestore</c> event, signaling writers that the current restore
@ -1158,7 +1158,7 @@ public interface IVssBackupComponents
// https://docs.microsoft.com/en-us/windows/win32/api/vsbackup/nf-vsbackup-ivssbackupcomponents-query HRESULT Query( [in] VSS_ID
// QueriedObjectId, [in] VSS_OBJECT_TYPE eQueriedObjectType, [in] VSS_OBJECT_TYPE eReturnedObjectsType, [out] IVssEnumObject
// **ppEnum );
IVssEnumObject Query(Guid QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType, VSS_OBJECT_TYPE eReturnedObjectsType);
IVssEnumObject Query([Optional] Guid QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType, VSS_OBJECT_TYPE eReturnedObjectsType);
/// <summary>
/// The <c>QueryRevertStatus</c> method returns an IVssAsync interface pointer that can be used to determine the status of the
@ -2085,7 +2085,7 @@ public interface IVssExamineWriterMetadata
// https://docs.microsoft.com/en-us/windows/win32/api/vsbackup/nf-vsbackup-ivssexaminewritermetadata-getrestoremethod HRESULT
// GetRestoreMethod( [out] VSS_RESTOREMETHOD_ENUM *pMethod, [out] BSTR *pbstrService, [out] BSTR *pbstrUserProcedure, [out]
// VSS_WRITERRESTORE_ENUM *pwriterRestore, [out] bool *pbRebootRequired, [out] UINT *pcMappings );
void GetRestoreMethod(out VSS_RESTOREMETHOD_ENUM pMethod, out string pbstrService, out string pbstrUserProcedure,
void GetRestoreMethod(out VSS_RESTOREMETHOD_ENUM pMethod, out string? pbstrService, out string? pbstrUserProcedure,
out VSS_WRITERRESTORE_ENUM pwriterRestore, out bool pbRebootRequired, out uint pcMappings);
/// <summary>
@ -2213,13 +2213,13 @@ public struct VSS_COMPONENTINFO
/// <para>A logical path can be <see langword="null"/>.</para>
/// <para>There are no restrictions on the characters that can appear in a non- <see langword="null"/> logical path.</para>
/// </summary>
public string bstrLogicalPath;
public string? bstrLogicalPath;
/// <summary>A string containing the name of the component. A component name string cannot be <see langword="null"/>.</summary>
public string bstrComponentName;
/// <summary>A string containing the description of the component. A caption string can be <see langword="null"/>.</summary>
public string bstrCaption;
public string? bstrCaption;
/// <summary>
/// <para>
@ -2228,7 +2228,7 @@ public struct VSS_COMPONENTINFO
/// </para>
/// <para>If the writer that created the component did not choose to specify an icon, <c>pbIcon</c> is <see langword="null"/>.</para>
/// </summary>
public byte[] pbIcon;
public byte[]? pbIcon;
/// <summary>
/// <para>
@ -2365,7 +2365,7 @@ public struct VssWriterStatus
/// The address of a variable that receives the application failure message that the writer passed for the wszApplicationMessage
/// parameter of the SetWriterFailureEx method. This parameter is optional and can be NULL.
/// </summary>
public string pbstrApplicationMessage;
public string? pbstrApplicationMessage;
/// <summary>The address of a caller-allocated variable that receives a string containing the name of the specified writer.</summary>
public string pbstrWriter;

View File

@ -960,9 +960,9 @@ public struct VSS_MGMT_OBJECT_PROP : IDisposable
[StructLayout(LayoutKind.Sequential)]
public struct VSS_MGMT_OBJECT_UNION
{
internal InteropServices.StrPtrUni szOne;
internal StrPtrUni szOne;
internal InteropServices.StrPtrUni szTwo;
internal StrPtrUni szTwo;
internal long lOne;
@ -971,13 +971,13 @@ public struct VSS_MGMT_OBJECT_UNION
internal long lThree;
/// <summary>The structure specifies an original volume object as a VSS_VOLUME_PROP structure (section 2.2.3.7).</summary>
public VSS_VOLUME_PROP Vol => new() { m_pwszVolumeName = szOne, m_pwszVolumeDisplayName = szTwo };
public VSS_VOLUME_PROP Vol => new() { m_pwszVolumeName = (string?)szOne ?? "", m_pwszVolumeDisplayName = (string?)szTwo ?? ""};
/// <summary>The structure specifies a shadow copy storage volume as a VSS_DIFF_VOLUME_PROP structure.</summary>
public VSS_DIFF_VOLUME_PROP DiffVol => new() { m_pwszVolumeName = szOne, m_pwszVolumeDisplayName = szTwo, m_llVolumeFreeSpace = lOne, m_llVolumeTotalSpace = lTwo };
public VSS_DIFF_VOLUME_PROP DiffVol => new() { m_pwszVolumeName = (string?)szOne ?? "", m_pwszVolumeDisplayName = (string?)szTwo ?? "", m_llVolumeFreeSpace = lOne, m_llVolumeTotalSpace = lTwo };
/// <summary>The structure specifies a shadow copy storage object as a VSS_DIFF_AREA_PROP.</summary>
public VSS_DIFF_AREA_PROP DiffArea => new() { m_pwszVolumeName = szOne, m_pwszDiffAreaVolumeName = szTwo, m_llMaximumDiffSpace = lOne, m_llAllocatedDiffSpace = lTwo, m_llUsedDiffSpace = lThree };
public VSS_DIFF_AREA_PROP DiffArea => new() { m_pwszVolumeName = (string?)szOne ?? "", m_pwszDiffAreaVolumeName = (string?)szTwo ?? "", m_llMaximumDiffSpace = lOne, m_llAllocatedDiffSpace = lTwo, m_llUsedDiffSpace = lThree };
}
/// <summary>The <c>VSS_VOLUME_PROP</c> structure contains the properties of a shadow copy source volume.</summary>

View File

@ -1537,7 +1537,7 @@ public interface IVssProviderNotifications
// https://docs.microsoft.com/en-us/windows/win32/api/vsprov/nf-vsprov-ivssprovidernotifications-onload HRESULT OnLoad( [in]
// IUnknown *pCallback );
[PreserveSig]
HRESULT OnLoad([In, Optional, MarshalAs(UnmanagedType.IUnknown)] object pCallback);
HRESULT OnLoad([In, Optional, MarshalAs(UnmanagedType.IUnknown)] object? pCallback);
/// <summary>The <c>OnUnload</c> method notifies the provider to prepare to be unloaded.</summary>
/// <param name="bForceUnload">If <c>TRUE</c>, the provider must prepare to be released.</param>

View File

@ -1548,7 +1548,7 @@ public interface IVssComponent
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/vswriter/nf-vswriter-ivsscomponentex2-setfailure HRESULT SetFailure( [in]
// HRESULT hr, [in] HRESULT hrApplication, [in] LPCWSTR wszApplicationMessage, [in] DWORD dwReserved );
void SetFailure(HRESULT hr, HRESULT hrApplication, [Optional] string? wszApplicationMessage);
void SetFailure(HRESULT hr, [Optional] HRESULT hrApplication, [Optional] string? wszApplicationMessage);
}
/// <summary>
@ -1678,9 +1678,9 @@ public interface IVssCreateExpressWriterMetadata
// AddComponent( [in] VSS_COMPONENT_TYPE ct, [in] LPCWSTR wszLogicalPath, [in] LPCWSTR wszComponentName, [in] LPCWSTR wszCaption,
// [in] const BYTE *pbIcon, [in] UINT cbIcon, [in] bool bRestoreMetadata, [in] bool bNotifyOnBackupComplete, [in] bool bSelectable,
// [in] bool bSelectableForRestore, [in] DWORD dwComponentFlags );
void AddComponent(VSS_COMPONENT_TYPE ct, [MarshalAs(UnmanagedType.LPWStr)] string wszLogicalPath,
[MarshalAs(UnmanagedType.LPWStr)] string wszComponentName, [MarshalAs(UnmanagedType.LPWStr)] string wszCaption,
IntPtr pbIcon, uint cbIcon, bool bRestoreMetadata, bool bNotifyOnBackupComplete, bool bSelectable, bool bSelectableForRestore = false,
void AddComponent(VSS_COMPONENT_TYPE ct, [MarshalAs(UnmanagedType.LPWStr)] string? wszLogicalPath,
[MarshalAs(UnmanagedType.LPWStr)] string wszComponentName, [MarshalAs(UnmanagedType.LPWStr)] string? wszCaption,
[Optional] IntPtr pbIcon, uint cbIcon, bool bRestoreMetadata, bool bNotifyOnBackupComplete, bool bSelectable, bool bSelectableForRestore = false,
VSS_COMPONENT_FLAGS dwComponentFlags = 0);
/// <summary>Adds a file set (a specified file or files) to a specified file group component for an express writer.</summary>
@ -1727,9 +1727,9 @@ public interface IVssCreateExpressWriterMetadata
// https://docs.microsoft.com/en-us/windows/win32/api/vswriter/nf-vswriter-ivsscreateexpresswritermetadata-addfilestofilegroup
// HRESULT AddFilesToFileGroup( [in] LPCWSTR wszLogicalPath, [in] LPCWSTR wszGroupName, [in] LPCWSTR wszPath, [in] LPCWSTR
// wszFilespec, [in] bool bRecursive, [in] LPCWSTR wszAlternateLocation, [in] DWORD dwBackupTypeMask );
void AddFilesToFileGroup([MarshalAs(UnmanagedType.LPWStr)] string wszLogicalPath, [MarshalAs(UnmanagedType.LPWStr)] string wszGroupName,
void AddFilesToFileGroup([MarshalAs(UnmanagedType.LPWStr)] string? wszLogicalPath, [MarshalAs(UnmanagedType.LPWStr)] string wszGroupName,
[MarshalAs(UnmanagedType.LPWStr)] string wszPath, [MarshalAs(UnmanagedType.LPWStr)] string wszFilespec, bool bRecursive,
[MarshalAs(UnmanagedType.LPWStr)] string wszAlternateLocation,
[MarshalAs(UnmanagedType.LPWStr)] string? wszAlternateLocation = null,
VSS_FILE_SPEC_BACKUP_TYPE dwBackupTypeMask = VSS_FILE_SPEC_BACKUP_TYPE.VSS_FSBT_ALL_BACKUP_REQUIRED | VSS_FILE_SPEC_BACKUP_TYPE.VSS_FSBT_ALL_SNAPSHOT_REQUIRED);
/// <summary>Specifies how an express writer's data is to be restored.</summary>
@ -1790,8 +1790,8 @@ public interface IVssCreateExpressWriterMetadata
// https://docs.microsoft.com/en-us/windows/win32/api/vswriter/nf-vswriter-ivsscreateexpresswritermetadata-setrestoremethod HRESULT
// SetRestoreMethod( [in] VSS_RESTOREMETHOD_ENUM method, [in] LPCWSTR wszService, [in] LPCWSTR wszUserProcedure, [in]
// VSS_WRITERRESTORE_ENUM writerRestore, [in] bool bRebootRequired );
void SetRestoreMethod(VSS_RESTOREMETHOD_ENUM method, [MarshalAs(UnmanagedType.LPWStr)] string wszService,
[MarshalAs(UnmanagedType.LPWStr)] string wszUserProcedure, VSS_WRITERRESTORE_ENUM writerRestore, bool bRebootRequired);
void SetRestoreMethod(VSS_RESTOREMETHOD_ENUM method, [MarshalAs(UnmanagedType.LPWStr)] string? wszService,
[MarshalAs(UnmanagedType.LPWStr)] string? wszUserProcedure, VSS_WRITERRESTORE_ENUM writerRestore, bool bRebootRequired);
/// <summary>
/// Allows an express writer to indicate that a component it manages has an explicit writer-component dependency; that is, another
@ -2070,7 +2070,7 @@ public interface IVssCreateWriterMetadata
// AddComponent( [in] VSS_COMPONENT_TYPE ct, [in] LPCWSTR wszLogicalPath, [in] LPCWSTR wszComponentName, [in] LPCWSTR wszCaption,
// [in] const BYTE *pbIcon, [in] UINT cbIcon, [in] bool bRestoreMetadata, [in] bool bNotifyOnBackupComplete, [in] bool bSelectable,
// [in] bool bSelectableForRestore, [in] DWORD dwComponentFlags );
void AddComponent(VSS_COMPONENT_TYPE ct, [Optional] string? wszLogicalPath, string wszComponentName, [Optional] string? wszCaption, byte[] pbIcon,
void AddComponent(VSS_COMPONENT_TYPE ct, [Optional] string? wszLogicalPath, string wszComponentName, [Optional] string? wszCaption, byte[]? pbIcon,
bool bRestoreMetadata, bool bNotifyOnBackupComplete, bool bSelectable, bool bSelectableForRestore = false,
VSS_COMPONENT_FLAGS dwComponentFlags = 0);
@ -2822,7 +2822,7 @@ public interface IVssWMFiledesc
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/vswriter/nf-vswriter-ivsswmfiledesc-getalternatelocation HRESULT
// GetAlternateLocation( [out] BSTR *pbstrAlternateLocation );
string AlternateLocation { get; }
string? AlternateLocation { get; }
/// <summary>
/// The <c>GetBackupTypeMask</c> method returns the file backup specification for the files specified by the current file descriptor
@ -3219,7 +3219,7 @@ public struct VssPartialFile
/// </para>
/// <para>If additional metadata is not required, this value can be <c>NULL</c>.</para>
/// </summary>
public string Metadata;
public string? Metadata;
/// <summary>
/// <para>String containing the path of the file involved in partial file operations.</para>
@ -3241,7 +3241,7 @@ public struct VssPartialFile
/// </para>
/// <para>Specifying the partial file support range is required, and this value cannot be <c>NULL</c>.</para>
/// </summary>
public string Ranges;
public string? Ranges;
}
/// <summary>

View File

@ -309,7 +309,7 @@ public static partial class WcmApi
// *pInterface, LPCWSTR strProfileName, WCM_PROPERTY Property, PVOID pReserved, PDWORD pdwDataSize, PBYTE *ppData );
[DllImport(Lib.Wcmapi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("wcmapi.h", MSDNShortId = "07c0993e-2892-4908-be3f-d24210ccc300")]
public static extern Win32Error WcmQueryProperty([Optional] IntPtr pInterface, [Optional] IntPtr strProfileName,
public static extern Win32Error WcmQueryProperty([Optional] IntPtr pInterface, [Optional, MarshalAs(UnmanagedType.LPWStr)] string? strProfileName,
WCM_PROPERTY Property, [Optional] IntPtr pReserved, out uint pdwDataSize, out SafeWcmMemory ppData);
/// <summary>The <c>WcmQueryProperty</c> function retrieves the value of a specified WCM property.</summary>
@ -375,30 +375,22 @@ public static partial class WcmApi
/// </list>
/// </remarks>
[PInvokeData("wcmapi.h", MSDNShortId = "07c0993e-2892-4908-be3f-d24210ccc300")]
public static Win32Error WcmQueryProperty<T>(WCM_PROPERTY Property, [Optional] Guid? pInterface, [Optional] string? strProfileName, out T ppData)
public static Win32Error WcmQueryProperty<T>(WCM_PROPERTY Property, [Optional] Guid? pInterface, [Optional] string? strProfileName, out T? ppData)
{
ppData = default;
if (!CorrespondingTypeAttribute.CanGet(Property, typeof(T)))
return Win32Error.ERROR_DATATYPE_MISMATCH;
SafeWcmMemory mem;
uint sz;
Win32Error res;
if (pInterface.HasValue)
res = WcmQueryProperty(pInterface.Value, strProfileName, Property, default, out sz, out mem);
else
res = WcmQueryProperty(IntPtr.Zero, IntPtr.Zero, Property, default, out sz, out mem);
using (mem)
SafeCoTaskMemStruct<Guid> pi = pInterface;
var res = WcmQueryProperty(pi, strProfileName, Property, default, out var sz, out var mem);
if (res.Succeeded)
{
if (res.Succeeded)
{
if (typeof(T).IsValueType)
ppData = mem.ToStructure<T>(sz);
else if (typeof(T) == typeof(string))
ppData = (T)(object)mem.ToString(sz);
else
return Win32Error.ERROR_DATATYPE_MISMATCH;
}
if (typeof(T).IsValueType)
ppData = mem.ToStructure<T>(sz);
else if (typeof(T) == typeof(string))
ppData = (T?)(object?)mem.ToString(sz);
else
return Win32Error.ERROR_DATATYPE_MISMATCH;
}
return res;
}
@ -868,7 +860,7 @@ public static partial class WcmApi
/// <para>Information about each profile.</para>
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public WCM_PROFILE_INFO[] ProfileInfo;
public WCM_PROFILE_INFO[] ProfileInfo = new WCM_PROFILE_INFO[1];
}
/// <summary>The <c>WCM_TIME_INTERVAL</c> structure defines a time interval.</summary>
@ -957,7 +949,7 @@ public static partial class WcmApi
/// <summary>Converts this memory to a string value.</summary>
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory.</param>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public string ToString(SizeT allocatedBytes) => StringHelper.GetString(handle, CharSet.Unicode, allocatedBytes);
public string? ToString(SizeT allocatedBytes) => StringHelper.GetString(handle, CharSet.Unicode, allocatedBytes);
/// <summary>
/// Marshals data from an unmanaged block of memory to a newly allocated managed object of the type specified by a generic type parameter.
@ -965,7 +957,7 @@ public static partial class WcmApi
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory.</param>
/// <returns>A managed object that contains the requested data.</returns>
public T ToStructure<T>(SizeT allocatedBytes = default) => handle.ToStructure<T>(allocatedBytes);
public T? ToStructure<T>(SizeT allocatedBytes = default) => handle.ToStructure<T>(allocatedBytes);
/// <summary>Performs an implicit conversion from <see cref="SafeWcmMemory"/> to <see cref="IntPtr"/>.</summary>
/// <param name="mem">The memory.</param>
@ -995,6 +987,6 @@ public static partial class WcmApi
IntPtr ICustomMarshaler.MarshalManagedToNative(object ManagedObj) => throw new NotImplementedException();
object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData) => typeof(T) == typeof(string) ? StringHelper.GetString(pNativeData, CharSet.Unicode) : (object)pNativeData.ToStructure<T>();
object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData) => (typeof(T) == typeof(string) ? (object?)StringHelper.GetString(pNativeData, CharSet.Unicode) : pNativeData.ToStructure<T>()) ?? new object();
}
}

View File

@ -58,10 +58,10 @@ public partial class UserEnvTests
Assert.That(CreateProfile(curSid.ToString("D"), curSid.ToString("N"), sb, (uint)sb.Length), ResultIs.Failure);
Assert.That(LogonUser(localAcct, ".", localAcctPwd, LogonUserType.LOGON32_LOGON_INTERACTIVE, LogonUserProvider.LOGON32_PROVIDER_DEFAULT, out var hTok), ResultIs.Successful);
using var id = new System.Security.Principal.WindowsIdentity(hTok.DangerousGetHandle());
using System.Security.Principal.WindowsIdentity id = new(hTok.DangerousGetHandle());
try
{
Assert.That(CreateProfile(id.User.Value, localAcct, sb, (uint)sb.Capacity), ResultIs.Successful);
Assert.That(CreateProfile(id.User!.Value, localAcct, sb, (uint)sb.Capacity), ResultIs.Successful);
var pi = new PROFILEINFO(localAcct);
Assert.That(LoadUserProfile(hTok, ref pi), ResultIs.Successful);
@ -69,7 +69,7 @@ public partial class UserEnvTests
}
finally
{
Assert.That(DeleteProfile(id.User.Value), ResultIs.Successful);
Assert.That(DeleteProfile(id.User!.Value), ResultIs.Successful);
hTok.Dispose();
}
}
@ -110,7 +110,7 @@ public partial class UserEnvTests
[Test]
public void GetAppContainerRegistryLocationTest()
{
Assert.That(GetAppContainerRegistryLocation(REGSAM.KEY_ALL_ACCESS, out var hKey), ResultIs.Successful);
Assert.That(GetAppContainerRegistryLocation(REGSAM.KEY_READ, out var hKey), ResultIs.Successful);
Assert.That(hKey, ResultIs.ValidHandle);
}
[Test]
@ -118,14 +118,14 @@ public partial class UserEnvTests
{
var guid = new Guid("{35378EAC-683F-11D2-A89A-00C04FBBCFA2}");
Assert.That(GetAppliedGPOList(0, default, default, guid, out GROUP_POLICY_OBJECT[] gpos), ResultIs.Successful);
Assert.That(gpos, Is.Not.Empty);
Assert.That(gpos, Has.Length.GreaterThan(0));
}
[Test]
public void GetAppliedGPOListTest2()
{
var guid = new Guid("{35378EAC-683F-11D2-A89A-00C04FBBCFA2}");
Assert.That(GetAppliedGPOList(0, default, default, guid, out IntPtr ptr), ResultIs.Successful);
var guid = new Guid("{e437bc1c-aa7d-11d2-a382-00c04f991e27}"); // {35378EAC-683F-11D2-A89A-00C04FBBCFA2}");
Assert.That(GetAppliedGPOList(GPO_LIST_FLAG.GPO_LIST_FLAG_MACHINE, default, default, guid, out IntPtr ptr), ResultIs.Successful);
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
Assert.That(FreeGPOList(ptr), ResultIs.Successful);
}

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net6.0-windows</TargetFramework>
<AssemblyName>UnitTest.PInvoke.VssApi</AssemblyName>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>

View File

@ -10,7 +10,9 @@ namespace Vanara.PInvoke.Tests;
public class VssApiTests
{
static readonly Guid ProviderId = new("{b5946137-7b9f-4925-af80-51abd60b20d5}");
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
string[] vols;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
[OneTimeSetUp]
public void _Setup()
@ -33,28 +35,39 @@ public class VssApiTests
foreach (var vol in vols)
{
TestContext.WriteLine($"Volume: {vol}");
var enumMgr = diffmgr.QueryDiffAreasForVolume(vol);
foreach (var prop in enumMgr.Enumerate())
try
{
switch (prop.Type)
var enumMgr = diffmgr.QueryDiffAreasForVolume(vol);
foreach (var prop in enumMgr.Enumerate())
{
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_UNKNOWN:
TestContext.WriteLine(" Unknown");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_VOLUME:
TestContext.WriteLine($" Volume: {prop.Obj.Vol.m_pwszVolumeDisplayName} ({prop.Obj.Vol.m_pwszVolumeName})");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_DIFF_VOLUME:
TestContext.WriteLine($" DiffVol: {prop.Obj.DiffVol.m_pwszVolumeDisplayName} ({prop.Obj.DiffVol.m_pwszVolumeName}) {prop.Obj.DiffVol.m_llVolumeTotalSpace}:{prop.Obj.DiffVol.m_llVolumeFreeSpace}");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_DIFF_AREA:
TestContext.WriteLine($" DiffAera: {prop.Obj.DiffArea.m_pwszDiffAreaVolumeName} ({prop.Obj.DiffArea.m_pwszVolumeName}) {prop.Obj.DiffArea.m_llMaximumDiffSpace}:{prop.Obj.DiffArea.m_llAllocatedDiffSpace}:{prop.Obj.DiffArea.m_llUsedDiffSpace}");
break;
default:
break;
switch (prop.Type)
{
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_UNKNOWN:
TestContext.WriteLine(" Unknown");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_VOLUME:
TestContext.WriteLine($" Volume: {prop.Obj.Vol.m_pwszVolumeDisplayName} ({prop.Obj.Vol.m_pwszVolumeName})");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_DIFF_VOLUME:
TestContext.WriteLine($" DiffVol: {prop.Obj.DiffVol.m_pwszVolumeDisplayName} ({prop.Obj.DiffVol.m_pwszVolumeName}) {prop.Obj.DiffVol.m_llVolumeTotalSpace}:{prop.Obj.DiffVol.m_llVolumeFreeSpace}");
break;
case VSS_MGMT_OBJECT_TYPE.VSS_MGMT_OBJECT_DIFF_AREA:
TestContext.WriteLine($" DiffAera: {prop.Obj.DiffArea.m_pwszDiffAreaVolumeName} ({prop.Obj.DiffArea.m_pwszVolumeName}) {prop.Obj.DiffArea.m_llMaximumDiffSpace}:{prop.Obj.DiffArea.m_llAllocatedDiffSpace}:{prop.Obj.DiffArea.m_llUsedDiffSpace}");
break;
default:
break;
}
prop.Dispose();
}
prop.Dispose();
}
catch { }
}
}
[Test]
public void Test()
{
Assert.That(VssFactory.CreateVssBackupComponents(out IVssBackupComponents vss), ResultIs.Successful);
vss.InitializeForBackup();
}
}

View File

@ -8,10 +8,12 @@ namespace WcmApi;
public class Tests
{
private bool? conn;
private SafeHWLANSESSION hWlan = null;
private bool? conn = null;
private Guid? intf;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private SafeHWLANSESSION hWlan;
private string profName;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private Guid PrimaryInterface
{
@ -50,9 +52,9 @@ public class Tests
{
if (!conn.HasValue)
{
var g = PrimaryInterface;
_ = PrimaryInterface;
}
return conn.Value;
return conn.GetValueOrDefault();
}
}
@ -77,15 +79,15 @@ public class Tests
if (t is null) Assert.Pass($"{e} ignored.");
TestContext.WriteLine($"{e}");
uint sz;
SafeWcmMemory data;
SafeWcmMemory? data;
var global = e.ToString().Contains("_global_");
if (global)
Assert.That(WcmQueryProperty(IntPtr.Zero, IntPtr.Zero, e, default, out sz, out data), ResultIs.Successful);
Assert.That(WcmQueryProperty(IntPtr.Zero, default, e, default, out sz, out data), ResultIs.Successful);
else
Assert.That(WcmQueryProperty(PrimaryInterface, ProfileName, e, default, out sz, out data), ResultIs.Successful);
if (data != null && !data.IsInvalid)
if (data is not null && !data.IsInvalid)
{
data.DangerousGetHandle().Convert(sz, t).WriteValues();
data.DangerousGetHandle().Convert(sz, t)?.WriteValues();
//t = CorrespondingTypeAttribute.GetCorrespondingTypes(e, CorrespondingAction.Set).FirstOrDefault();
//if (t is null) Assert.Pass($"Set {e} ignored.");
//if (global)