Completed work on CldApi with unit tests

pull/119/head
dahall 2020-05-01 15:26:16 -06:00
parent eca7516d87
commit 1efa3a860a
4 changed files with 468 additions and 257 deletions

View File

@ -377,7 +377,7 @@ namespace Vanara.PInvoke
// InfoBuffer, DWORD InfoBufferLength, PDWORD ReturnedLength ); // InfoBuffer, DWORD InfoBufferLength, PDWORD ReturnedLength );
[DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)] [DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfapi.h", MSDNShortId = "B7FE94BC-DC59-407D-85A6-9657E38975AB")] [PInvokeData("cfapi.h", MSDNShortId = "B7FE94BC-DC59-407D-85A6-9657E38975AB")]
public static extern HRESULT CfGetPlaceholderRangeInfo(HFILE FileHandle, CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass, long StartingOffset, long Length, [Out] IntPtr InfoBuffer, uint InfoBufferLength, ref uint ReturnedLength); public static extern HRESULT CfGetPlaceholderRangeInfo(HFILE FileHandle, CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass, long StartingOffset, long Length, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
/// <summary>Gets a set of placeholder states based on the FileAttributes and ReparseTag values of the file.</summary> /// <summary>Gets a set of placeholder states based on the FileAttributes and ReparseTag values of the file.</summary>
/// <param name="FileAttributes">The file attribute information.</param> /// <param name="FileAttributes">The file attribute information.</param>
@ -679,7 +679,7 @@ namespace Vanara.PInvoke
// FileHandle, CF_TRANSFER_KEY *TransferKey ); // FileHandle, CF_TRANSFER_KEY *TransferKey );
[DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)] [DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)]
[PInvokeData("cfapi.h", MSDNShortId = "53B40C34-EB1F-445B-B1B3-B539C2FADECE")] [PInvokeData("cfapi.h", MSDNShortId = "53B40C34-EB1F-445B-B1B3-B539C2FADECE")]
public static extern void CfReleaseTransferKey(HFILE FileHandle, out CF_TRANSFER_KEY TransferKey); public static extern void CfReleaseTransferKey(HFILE FileHandle, in CF_TRANSFER_KEY TransferKey);
/// <summary>Allows a sync provider to report progress out-of-band.</summary> /// <summary>Allows a sync provider to report progress out-of-band.</summary>
/// <param name="ConnectionKey">A connection key representing a communication channel with the sync filter.</param> /// <param name="ConnectionKey">A connection key representing a communication channel with the sync filter.</param>

View File

@ -147,7 +147,7 @@ namespace Vanara.PInvoke
CF_CALLBACK_FETCH_DATA_FLAG_RECOVERY = 1, CF_CALLBACK_FETCH_DATA_FLAG_RECOVERY = 1,
/// <summary> /// <summary>
/// Note This value is new for Windows 10, version 1803.Flag to be used if the callback is invoked as a result of a call to CfHydratePlaceholder. /// Note This value is new for Windows 10, version 1803. Flag to be used if the callback is invoked as a result of a call to CfHydratePlaceholder.
/// </summary> /// </summary>
CF_CALLBACK_FETCH_DATA_FLAG_EXPLICIT_HYDRATION = 2, CF_CALLBACK_FETCH_DATA_FLAG_EXPLICIT_HYDRATION = 2,
} }
@ -1342,51 +1342,53 @@ namespace Vanara.PInvoke
// CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags; } DeleteCompletion; struct { CF_CALLBACK_RENAME_FLAGS Flags; PCWSTR TargetPath; } // CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags; } DeleteCompletion; struct { CF_CALLBACK_RENAME_FLAGS Flags; PCWSTR TargetPath; }
// Rename; struct { CF_CALLBACK_RENAME_COMPLETION_FLAGS Flags; PCWSTR SourcePath; } RenameCompletion; } DUMMYUNIONNAME; } CF_CALLBACK_PARAMETERS; // Rename; struct { CF_CALLBACK_RENAME_COMPLETION_FLAGS Flags; PCWSTR SourcePath; } RenameCompletion; } DUMMYUNIONNAME; } CF_CALLBACK_PARAMETERS;
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS public struct CF_CALLBACK_PARAMETERS
{ {
/// <summary/> /// <summary/>
public uint ParamSize; public uint ParamSize;
private uint pad;
/// <summary/> /// <summary/>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)]
public byte[] Content; public byte[] Content;
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_CANCEL Cancel => GetParam<CF_CALLBACK_PARAMETERS_CANCEL>(); public CANCEL Cancel => GetParam<CANCEL>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_FETCHDATA FetchData => GetParam<CF_CALLBACK_PARAMETERS_FETCHDATA>(); public FETCHDATA FetchData => GetParam<FETCHDATA>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_VALIDATEDATA ValidateData => GetParam<CF_CALLBACK_PARAMETERS_VALIDATEDATA>(); public VALIDATEDATA ValidateData => GetParam<VALIDATEDATA>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS FetchPlaceholders => GetParam<CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS>(); public FETCHPLACEHOLDERS FetchPlaceholders => GetParam<FETCHPLACEHOLDERS>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_OPENCOMPLETION OpenCompletion => GetParam<CF_CALLBACK_PARAMETERS_OPENCOMPLETION>(); public OPENCOMPLETION OpenCompletion => GetParam<OPENCOMPLETION>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_CLOSECOMPLETION CloseCompletion => GetParam<CF_CALLBACK_PARAMETERS_CLOSECOMPLETION>(); public CLOSECOMPLETION CloseCompletion => GetParam<CLOSECOMPLETION>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_DEHYDRATE Dehydrate => GetParam<CF_CALLBACK_PARAMETERS_DEHYDRATE>(); public DEHYDRATE Dehydrate => GetParam<DEHYDRATE>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION DehydrateCompletion => GetParam<CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION>(); public DEHYDRATECOMPLETION DehydrateCompletion => GetParam<DEHYDRATECOMPLETION>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_DELETE Delete => GetParam<CF_CALLBACK_PARAMETERS_DELETE>(); public DELETE Delete => GetParam<DELETE>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_DELETECOMPLETION DeleteCompletion => GetParam<CF_CALLBACK_PARAMETERS_DELETECOMPLETION>(); public DELETECOMPLETION DeleteCompletion => GetParam<DELETECOMPLETION>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_RENAME Rename => GetParam<CF_CALLBACK_PARAMETERS_RENAME>(); public RENAME Rename => GetParam<RENAME>();
/// <summary/> /// <summary/>
public CF_CALLBACK_PARAMETERS_RENAMECOMPLETION RenameCompletion => GetParam<CF_CALLBACK_PARAMETERS_RENAMECOMPLETION>(); public RENAMECOMPLETION RenameCompletion => GetParam<RENAMECOMPLETION>();
/// <summary>Gets the parameter value for this structure.</summary> /// <summary>Gets the parameter value for this structure.</summary>
/// <typeparam name="T">The type of the structure to retrieve.</typeparam> /// <typeparam name="T">The type of the structure to retrieve.</typeparam>
@ -1396,180 +1398,180 @@ namespace Vanara.PInvoke
using var ptr = new SafeHGlobalHandle(Content); using var ptr = new SafeHGlobalHandle(Content);
return ptr.ToStructure<T>(); return ptr.ToStructure<T>();
} }
}
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct CF_CALLBACK_PARAMETERS_CANCEL public struct CANCEL
{
/// <summary>Cancel data flags.</summary>
public CF_CALLBACK_CANCEL_FLAGS Flags;
/// <summary/>
public CANCELFETCHDATA FetchData;
/// <summary/>
[StructLayout(LayoutKind.Sequential)]
public struct CANCELFETCHDATA
{ {
/// <summary>Offset, in bytes, for specifying the range of data.</summary> /// <summary>Cancel data flags.</summary>
public long FileOffset; public CF_CALLBACK_CANCEL_FLAGS Flags;
/// <summary>Length of the data in bytes.</summary> /// <summary/>
public long Length; public CANCELFETCHDATA FetchData;
/// <summary/>
[StructLayout(LayoutKind.Sequential)]
public struct CANCELFETCHDATA
{
/// <summary>Offset, in bytes, for specifying the range of data.</summary>
public long FileOffset;
/// <summary>Length of the data in bytes.</summary>
public long Length;
}
} }
}
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_CLOSECOMPLETION public struct CLOSECOMPLETION
{ {
/// <summary>Placeholder close completion flags.</summary> /// <summary>Placeholder close completion flags.</summary>
public CF_CALLBACK_CLOSE_COMPLETION_FLAGS Flags; public CF_CALLBACK_CLOSE_COMPLETION_FLAGS Flags;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_DEHYDRATE public struct DEHYDRATE
{ {
/// <summary>Placeholder dehydration flags.</summary> /// <summary>Placeholder dehydration flags.</summary>
public CF_CALLBACK_DEHYDRATE_FLAGS Flags; public CF_CALLBACK_DEHYDRATE_FLAGS Flags;
/// <summary/> /// <summary/>
public CF_CALLBACK_DEHYDRATION_REASON Reason; public CF_CALLBACK_DEHYDRATION_REASON Reason;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION public struct DEHYDRATECOMPLETION
{ {
/// <summary/> /// <summary/>
public CF_CALLBACK_DEHYDRATE_COMPLETION_FLAGS Flags; public CF_CALLBACK_DEHYDRATE_COMPLETION_FLAGS Flags;
/// <summary/> /// <summary/>
public CF_CALLBACK_DEHYDRATION_REASON Reason; public CF_CALLBACK_DEHYDRATION_REASON Reason;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_DELETE public struct DELETE
{ {
/// <summary>Placeholder deletion flags.</summary> /// <summary>Placeholder deletion flags.</summary>
public CF_CALLBACK_DELETE_FLAGS Flags; public CF_CALLBACK_DELETE_FLAGS Flags;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 4)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_DELETECOMPLETION public struct DELETECOMPLETION
{ {
/// <summary>Placeholder deletion complete flags.</summary> /// <summary>Placeholder deletion complete flags.</summary>
public CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags; public CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 56)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_FETCHDATA public struct FETCHDATA
{ {
/// <summary>Fetch data flags.</summary> /// <summary>Fetch data flags.</summary>
public CF_CALLBACK_FETCH_DATA_FLAGS Flags; public CF_CALLBACK_FETCH_DATA_FLAGS Flags;
/// <summary>Offset, in bytes, for specifying the required range of data.</summary> /// <summary>Offset, in bytes, for specifying the required range of data.</summary>
public long RequiredFileOffset; public long RequiredFileOffset;
/// <summary>Length of the required data to retrieve, in bytes.</summary> /// <summary>Length of the required data to retrieve, in bytes.</summary>
public long RequiredLength; public long RequiredLength;
/// <summary> /// <summary>
/// Offset, in bytes, of a broader piece of data to provide to a sync provider. This is optional and can be used if the sync /// Offset, in bytes, of a broader piece of data to provide to a sync provider. This is optional and can be used if the sync
/// provider prefers to work with larger segments of data. /// provider prefers to work with larger segments of data.
/// </summary> /// </summary>
public long OptionalFileOffset; public long OptionalFileOffset;
/// <summary> /// <summary>
/// Length, in bytes, of a broader piece of data to provide to a sync provider. This is optional and can be used if the sync /// Length, in bytes, of a broader piece of data to provide to a sync provider. This is optional and can be used if the sync
/// provider prefers to work with larger segments of data. /// provider prefers to work with larger segments of data.
/// </summary> /// </summary>
public long OptionalLength; public long OptionalLength;
/// <summary/> /// <summary/>
public long LastDehydrationTime; public long LastDehydrationTime;
/// <summary/> /// <summary/>
public CF_CALLBACK_DEHYDRATION_REASON LastDehydrationReason; public CF_CALLBACK_DEHYDRATION_REASON LastDehydrationReason;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS public struct FETCHPLACEHOLDERS
{ {
/// <summary>Flags for fetching placeholder metadata.</summary> /// <summary>Flags for fetching placeholder metadata.</summary>
public CF_CALLBACK_FETCH_PLACEHOLDERS_FLAGS Flags; public CF_CALLBACK_FETCH_PLACEHOLDERS_FLAGS Flags;
/// <summary> /// <summary>
/// A standard Windows file pattern which may contain wildcard characters (?, *). All placeholders information matching the /// A standard Windows file pattern which may contain wildcard characters (?, *). All placeholders information matching the
/// pattern must be transferred, but not necessarily in one-shot, as a minimum requirement. Alternatively, a sync provider may /// pattern must be transferred, but not necessarily in one-shot, as a minimum requirement. Alternatively, a sync provider may
/// choose to not transfer placeholders matching the pattern. /// choose to not transfer placeholders matching the pattern.
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.LPWStr)] [MarshalAs(UnmanagedType.LPWStr)]
public string Pattern; public string Pattern;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_OPENCOMPLETION public struct OPENCOMPLETION
{ {
/// <summary>Placeholder open completion flags.</summary> /// <summary>Placeholder open completion flags.</summary>
public CF_CALLBACK_OPEN_COMPLETION_FLAGS Flags; public CF_CALLBACK_OPEN_COMPLETION_FLAGS Flags;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_RENAME public struct RENAME
{ {
/// <summary>Rename placeholder flags.</summary> /// <summary>Rename placeholder flags.</summary>
public CF_CALLBACK_RENAME_FLAGS Flags; public CF_CALLBACK_RENAME_FLAGS Flags;
/// <summary>The full rename/move target path relative to the volume.</summary> /// <summary>The full rename/move target path relative to the volume.</summary>
[MarshalAs(UnmanagedType.LPWStr)] [MarshalAs(UnmanagedType.LPWStr)]
public string TargetPath; public string TargetPath;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_RENAMECOMPLETION public struct RENAMECOMPLETION
{ {
/// <summary>Rename completion placeholder flags.</summary> /// <summary>Rename completion placeholder flags.</summary>
public CF_CALLBACK_RENAME_COMPLETION_FLAGS Flags; public CF_CALLBACK_RENAME_COMPLETION_FLAGS Flags;
/// <summary>The full source link path relative to the volume.</summary> /// <summary>The full source link path relative to the volume.</summary>
[MarshalAs(UnmanagedType.LPWStr)] [MarshalAs(UnmanagedType.LPWStr)]
public string SourcePath; public string SourcePath;
} }
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary> /// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")] [PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
[StructLayout(LayoutKind.Sequential, Pack = 8)] [StructLayout(LayoutKind.Sequential)]
public struct CF_CALLBACK_PARAMETERS_VALIDATEDATA public struct VALIDATEDATA
{ {
/// <summary>Data validation flags.</summary> /// <summary>Data validation flags.</summary>
public CF_CALLBACK_VALIDATE_DATA_FLAGS Flags; public CF_CALLBACK_VALIDATE_DATA_FLAGS Flags;
/// <summary>Offset, in bytes, for specifying the range of data to validate.</summary> /// <summary>Offset, in bytes, for specifying the range of data to validate.</summary>
public long RequiredFileOffset; public long RequiredFileOffset;
/// <summary>Length, in bytes, of the data to validate.</summary> /// <summary>Length, in bytes, of the data to validate.</summary>
public long RequiredLength; public long RequiredLength;
}
} }
/// <summary>The callbacks to be registered by the sync provider.</summary> /// <summary>The callbacks to be registered by the sync provider.</summary>
@ -1721,13 +1723,83 @@ namespace Vanara.PInvoke
// FileIdentityLength; } AckDehydrate; struct { CF_OPERATION_ACK_RENAME_FLAGS Flags; NTSTATUS CompletionStatus; } AckRename; struct // FileIdentityLength; } AckDehydrate; struct { CF_OPERATION_ACK_RENAME_FLAGS Flags; NTSTATUS CompletionStatus; } AckRename; struct
// { CF_OPERATION_ACK_DELETE_FLAGS Flags; NTSTATUS CompletionStatus; } AckDelete; } DUMMYUNIONNAME; } CF_OPERATION_PARAMETERS; // { CF_OPERATION_ACK_DELETE_FLAGS Flags; NTSTATUS CompletionStatus; } AckDelete; } DUMMYUNIONNAME; } CF_OPERATION_PARAMETERS;
[PInvokeData("cfapi.h", MSDNShortId = "668C682E-47C2-41BC-A4F9-AA2F2B516F54")] [PInvokeData("cfapi.h", MSDNShortId = "668C682E-47C2-41BC-A4F9-AA2F2B516F54")]
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Sequential)]
public struct CF_OPERATION_PARAMETERS public struct CF_OPERATION_PARAMETERS
{ {
/// <summary/> /// <summary/>
[FieldOffset(0)]
public uint ParamSize; public uint ParamSize;
// Yes, this is strange, but needed to deal with struct size changing based on pointer size (40/48).
private uint pad4_8;
private ulong pad8_16;
private ulong pad16_24;
private ulong pad24_32;
private IntPtr padp1;
private IntPtr padp2;
/// <summary/>
public TRANSFERDATA TransferData { get => GetParam<TRANSFERDATA>(); set => SetParam(value); }
/// <summary/>
public RETRIEVEDATA RetrieveData { get => GetParam<RETRIEVEDATA>(); set => SetParam(value); }
/// <summary/>
public ACKDATA AckData { get => GetParam<ACKDATA>(); set => SetParam(value); }
/// <summary/>
public RESTARTHYDRATION RestartHydration { get => GetParam<RESTARTHYDRATION>(); set => SetParam(value); }
/// <summary/>
public TRANSFERPLACEHOLDERS TransferPlaceholders { get => GetParam<TRANSFERPLACEHOLDERS>(); set => SetParam(value); }
/// <summary/>
public ACKDEHYDRATE AckDehydrate { get => GetParam<ACKDEHYDRATE>(); set => SetParam(value); }
/// <summary/>
public ACKRENAME AckRename { get => GetParam<ACKRENAME>(); set => SetParam(value); }
/// <summary/>
public ACKDELETE AckDelete { get => GetParam<ACKDELETE>(); set => SetParam(value); }
/// <summary>Gets the parameter value for this structure.</summary>
/// <typeparam name="T">The type of the structure to retrieve.</typeparam>
/// <returns>The requested structure.</returns>
public unsafe T GetParam<T>() where T : struct
{
using var ptr = new PinnedObject(this);
return ((IntPtr)ptr).ToStructure<T>(Marshal.SizeOf(typeof(CF_OPERATION_PARAMETERS)), 8);
}
/// <summary>Sets the parameter value for this structure.</summary>
/// <typeparam name="T">The type of the structure to set.</typeparam>
/// <param name="value">The value to set.</param>
public void SetParam<T>(T value) where T : struct
{
unsafe
{
fixed (ulong* p = &pad8_16)
{
((IntPtr)(void*)p).Write(value, 0, Marshal.SizeOf(typeof(CF_OPERATION_PARAMETERS)) - 8);
}
}
}
/// <summary>Creates a CF_OPERATION_PARAMETERS instance with the specified parameter value.</summary>
/// <typeparam name="T">The parameter type.</typeparam>
/// <param name="paramValue">The parameter value.</param>
/// <returns>A CF_OPERATION_PARAMETERS instance initialized with <paramref name="paramValue"/> and the correct ParamSize.</returns>
public static CF_OPERATION_PARAMETERS Create<T>(T paramValue = default) where T : struct
{
var op = new CF_OPERATION_PARAMETERS { ParamSize = CF_SIZE_OF_OP_PARAM<T>() };
op.SetParam(paramValue);
return op;
}
/// <summary>Gets the size value used in ParamSize given a specific parameter type.</summary>
/// <typeparam name="T">The parameter type.</typeparam>
/// <returns>The size of the structure.</returns>
public static uint CF_SIZE_OF_OP_PARAM<T>() where T : struct => (uint)(Marshal.OffsetOf(typeof(CF_OPERATION_PARAMETERS), nameof(pad8_16)).ToInt32() + Marshal.SizeOf(typeof(T)));
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct TRANSFERDATA public struct TRANSFERDATA
@ -1748,10 +1820,6 @@ namespace Vanara.PInvoke
public long Length; public long Length;
} }
/// <summary/>
[FieldOffset(4)]
public TRANSFERDATA TransferData;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct RETRIEVEDATA public struct RETRIEVEDATA
@ -1772,10 +1840,6 @@ namespace Vanara.PInvoke
public long ReturnedLength; public long ReturnedLength;
} }
/// <summary/>
[FieldOffset(4)]
public RETRIEVEDATA RetrieveData;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct ACKDATA public struct ACKDATA
@ -1796,10 +1860,6 @@ namespace Vanara.PInvoke
public long Length; public long Length;
} }
/// <summary/>
[FieldOffset(4)]
public ACKDATA AckData;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct RESTARTHYDRATION public struct RESTARTHYDRATION
@ -1817,10 +1877,6 @@ namespace Vanara.PInvoke
public uint FileIdentityLength; public uint FileIdentityLength;
} }
/// <summary/>
[FieldOffset(4)]
public RESTARTHYDRATION RestartHydration;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct TRANSFERPLACEHOLDERS public struct TRANSFERPLACEHOLDERS
@ -1844,10 +1900,6 @@ namespace Vanara.PInvoke
public uint EntriesProcessed; public uint EntriesProcessed;
} }
/// <summary/>
[FieldOffset(4)]
public TRANSFERPLACEHOLDERS TransferPlaceholders;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct ACKDEHYDRATE public struct ACKDEHYDRATE
@ -1865,10 +1917,6 @@ namespace Vanara.PInvoke
public uint FileIdentityLength; public uint FileIdentityLength;
} }
/// <summary/>
[FieldOffset(4)]
public ACKDEHYDRATE AckDehydrate;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct ACKRENAME public struct ACKRENAME
@ -1880,10 +1928,6 @@ namespace Vanara.PInvoke
public NTStatus CompletionStatus; public NTStatus CompletionStatus;
} }
/// <summary/>
[FieldOffset(4)]
public ACKRENAME AckRename;
/// <summary/> /// <summary/>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct ACKDELETE public struct ACKDELETE
@ -1894,10 +1938,6 @@ namespace Vanara.PInvoke
/// <summary>The completion status of the operation.</summary> /// <summary>The completion status of the operation.</summary>
public NTStatus CompletionStatus; public NTStatus CompletionStatus;
} }
/// <summary/>
[FieldOffset(4)]
public ACKDELETE AckDelete;
} }
/// <summary>Basic placeholder information.</summary> /// <summary>Basic placeholder information.</summary>

View File

@ -2,9 +2,13 @@ using ICSharpCode.Decompiler.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Vanara.Extensions;
using Vanara.InteropServices; using Vanara.InteropServices;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using static Vanara.PInvoke.CldApi; using static Vanara.PInvoke.CldApi;
@ -32,6 +36,16 @@ namespace Vanara.PInvoke.Tests
try try
{ {
using var csp = new CloudSyncProvider(destDirPath, "TestSync"); using var csp = new CloudSyncProvider(destDirPath, "TestSync");
csp.Status = CF_SYNC_PROVIDER_STATUS.CF_PROVIDER_STATUS_IDLE;
csp.Status.WriteValues();
const string desc = "SyncStatus is good.";
uint descLen = (uint)(desc.Length + 1) * 2;
var ss = new CF_SYNC_STATUS { StructSize = (uint)Marshal.SizeOf<CF_SYNC_STATUS>() + descLen, Code = 1, DescriptionLength = descLen };
var mem = new SafeHGlobalHandle(Marshal.SizeOf<CF_SYNC_STATUS>() + descLen);
mem.Write(ss);
StringHelper.Write(desc, ((IntPtr)mem).Offset(Marshal.SizeOf<CF_SYNC_STATUS>()), out _, true, CharSet.Unicode, descLen);
Assert.That(CfReportSyncStatus(destDirPath, mem), ResultIs.Successful);
} }
finally finally
{ {
@ -43,28 +57,86 @@ namespace Vanara.PInvoke.Tests
public void CfCreatePlaceholdersTest() public void CfCreatePlaceholdersTest()
{ {
const string dest = "CfDest"; const string dest = "CfDest";
const string fname = "test.bmp";
var destDirPath = SetupTempDir(dest); var destDirPath = SetupTempDir(dest);
var fpath = Path.Combine(destDirPath, fname);
try try
{ {
using var csp = new CloudSyncProvider(destDirPath, "TestSync"); var tokSrc = new CancellationTokenSource();
var token = tokSrc.Token;
var task = Task.Run(() =>
{
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
csp.CancelFetchData += (s, e) => { TestContext.WriteLine($"CancelFetchData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.CancelFetchData += ShowInfo;
csp.CancelFetchPlaceholders += (s, e) => { TestContext.WriteLine($"CancelFetchPlaceholders: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.CancelFetchPlaceholders += ShowInfo;
csp.FetchData += (s, e) => { TestContext.WriteLine($"FetchData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.FetchData += ShowInfo;
csp.FetchPlaceholders += (s, e) => { TestContext.WriteLine($"FetchPlaceholders: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.FetchPlaceholders += ShowInfo;
csp.NotifyDehydrate += (s, e) => { TestContext.WriteLine($"NotifyDehydrate: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyDehydrate += ShowInfo;
csp.NotifyDehydrateCompletion += (s, e) => { TestContext.WriteLine($"NotifyDehydrateCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyDehydrateCompletion += ShowInfo;
csp.NotifyDelete += (s, e) => { TestContext.WriteLine($"NotifyDelete: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyDelete += ShowInfo;
csp.NotifyDeleteCompletion += (s, e) => { TestContext.WriteLine($"NotifyDeleteCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyDeleteCompletion += ShowInfo;
csp.NotifyFileCloseCompletion += (s, e) => { TestContext.WriteLine($"NotifyFileCloseCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyFileCloseCompletion += ShowInfo;
csp.NotifyFileOpenCompletion += (s, e) => { TestContext.WriteLine($"NotifyFileOpenCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyFileOpenCompletion += ShowInfo;
csp.NotifyRename += (s, e) => { TestContext.WriteLine($"NotifyRename: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyRename += ShowInfo;
csp.NotifyRenameCompletion += (s, e) => { TestContext.WriteLine($"NotifyRenameCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.NotifyRenameCompletion += ShowInfo;
csp.ValidateData += (s, e) => { TestContext.WriteLine($"ValidateData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); }; csp.ValidateData += ShowInfo;
csp.CreatePlaceholderFromFile("test.bmp", new FileInfo(TestCaseSources.BmpFile), true); var origFileInfo = new FileInfo(TestCaseSources.BmpFile);
Assert.That(File.Exists(Path.Combine(destDirPath, "test.bmp")), Is.True); csp.CreatePlaceholderFromFile(fname, origFileInfo, true);
Assert.That(new FileInfo(Path.Combine(destDirPath, "test.bmp")).Length, Is.EqualTo(new FileInfo(TestCaseSources.BmpFile).Length)); Assert.That(File.Exists(fpath), Is.True);
Assert.That(new FileInfo(fpath).Length, Is.EqualTo(origFileInfo.Length));
Debug.WriteLine("CSP is running...................................\n");
while (!token.IsCancellationRequested) { Thread.Sleep(100); }
static void ShowInfo<T>(object s, CloudSyncCallbackArgs<T> e) where T : struct
{
Debug.WriteLine($"\n{typeof(T).Name}: {e.NormalizedPath ?? "(null)"}, {e.FileSize}\n" +
Newtonsoft.Json.JsonConvert.SerializeObject(e.ParamData, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter()));
if (typeof(T) == typeof(CF_CALLBACK_PARAMETERS.RENAME))
{
e.OperationType = CF_OPERATION_TYPE.CF_OPERATION_TYPE_ACK_RENAME;
e.OpParam = CF_OPERATION_PARAMETERS.Create(new CF_OPERATION_PARAMETERS.ACKRENAME());
}
else if (typeof(T) == typeof(CF_CALLBACK_PARAMETERS.DEHYDRATE))
{
e.OperationType = CF_OPERATION_TYPE.CF_OPERATION_TYPE_ACK_DEHYDRATE;
e.OpParam = CF_OPERATION_PARAMETERS.Create(new CF_OPERATION_PARAMETERS.ACKDEHYDRATE());
}
else if (typeof(T) == typeof(CF_CALLBACK_PARAMETERS.DELETE))
{
e.OperationType = CF_OPERATION_TYPE.CF_OPERATION_TYPE_ACK_DELETE;
e.OpParam = CF_OPERATION_PARAMETERS.Create(new CF_OPERATION_PARAMETERS.ACKDELETE());
}
else if (typeof(T) == typeof(CF_CALLBACK_PARAMETERS.FETCHDATA))
{
var opInfo = e.MakeOpInfo(CF_OPERATION_TYPE.CF_OPERATION_TYPE_TRANSFER_DATA);
using var buf = new PinnedObject(File.ReadAllBytes(TestCaseSources.BmpFile));
var opParam = CF_OPERATION_PARAMETERS.Create(new CF_OPERATION_PARAMETERS.TRANSFERDATA { Buffer = buf, Length = new FileInfo(TestCaseSources.BmpFile).Length });
var hr = CfExecute(opInfo, ref opParam);
if (hr.Failed) Debug.WriteLine("CfExecute for transfer failed: " + hr.FormatMessage());
hr = CfReportProviderProgress(e.ConnectionKey, e.TransferKey, 100, 100);
if (hr.Failed) Debug.WriteLine("CfReportProviderProgress for transfer failed: " + hr.FormatMessage());
}
}
}, tokSrc.Token);
Thread.Sleep(5000); // Let CSP get loaded
using var hFile = GetHFILE(fpath);
Assert.That(CfHydratePlaceholder(hFile, 0, -1, 0), ResultIs.Successful);
Assert.That(CfGetCorrelationVector(hFile, out var cv), ResultIs.Successful);
using var buf = new SafeHGlobalHandle(128);
Assert.That(CfGetPlaceholderRangeInfo(hFile, CF_PLACEHOLDER_RANGE_INFO_CLASS.CF_PLACEHOLDER_RANGE_INFO_ONDISK, 0, buf.Size, buf, buf.Size, out var rngLen), ResultIs.Successful);
Assert.That(CfGetTransferKey(hFile, out var txKey), ResultIs.Successful);
Assert.That(() => CfReleaseTransferKey(hFile, txKey), Throws.Nothing);
Assert.That(CfDehydratePlaceholder(hFile, 0, -1, 0), ResultIs.Successful);
Thread.Sleep(2000); // Wait for user interaction
tokSrc.Cancel();
task.Wait();
//CfGetPlaceholderRangeInfo(hFile, CF_PLACEHOLDER_RANGE_INFO_CLASS.CF_PLACEHOLDER_RANGE_INFO_ONDISK, 0, ) //CfGetPlaceholderRangeInfo(hFile, CF_PLACEHOLDER_RANGE_INFO_CLASS.CF_PLACEHOLDER_RANGE_INFO_ONDISK, 0, )
//Assert.That(CfHydratePlaceholder(hFile, 0, -1, CF_HYDRATE_FLAGS.CF_HYDRATE_FLAG_NONE), ResultIs.Successful); //Assert.That(CfHydratePlaceholder(hFile, 0, -1, CF_HYDRATE_FLAGS.CF_HYDRATE_FLAG_NONE), ResultIs.Successful);
@ -128,6 +200,55 @@ namespace Vanara.PInvoke.Tests
} }
} }
[Test]
public void CfSetInSyncStateTest()
{
const string dest = "CfDest";
var destDirPath = SetupTempDir(dest);
try
{
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
csp.CreatePlaceholderFromFile("test.bmp", new FileInfo(TestCaseSources.BmpFile), true);
var destFile = Path.Combine(destDirPath, "test.bmp");
Assert.That(File.Exists(destFile), Is.True);
using var hFile = GetHFILE(destFile);
var usn = 0;
Assert.That(CfSetInSyncState(hFile, CF_IN_SYNC_STATE.CF_IN_SYNC_STATE_IN_SYNC, CF_SET_IN_SYNC_FLAGS.CF_SET_IN_SYNC_FLAG_NONE, ref usn), ResultIs.Successful);
Assert.That(CfSetPinState(hFile, CF_PIN_STATE.CF_PIN_STATE_PINNED, CF_SET_PIN_FLAGS.CF_SET_PIN_FLAG_NONE), ResultIs.Successful);
}
finally
{
DeleteTempDir(dest);
}
}
[Test]
public void CfGetPlaceholderStateFromAttributeTagTest()
{
const string dest = "CfDest";
var destDirPath = SetupTempDir(dest);
try
{
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
var destFile = CopyFile(TestCaseSources.WordDoc, destDirPath);
Assert.That(() => csp.ConvertToPlaceholder(destFile), Throws.Nothing);
using var hFile = GetHFILE(destFile);
Kernel32.FILE_ATTRIBUTE_TAG_INFO info = default;
Assert.That(() => info = Kernel32.GetFileInformationByHandleEx<Kernel32.FILE_ATTRIBUTE_TAG_INFO>(hFile, Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileAttributeTagInfo), Throws.Nothing);
info.WriteValues();
CfGetPlaceholderStateFromAttributeTag(info.FileAttributes, info.ReparseTag).WriteValues();
using var mem = SafeHGlobalHandle.CreateFromStructure(info);
CfGetPlaceholderStateFromFileInfo(mem, Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileAttributeTagInfo).WriteValues();
}
finally
{
DeleteTempDir(dest);
}
}
[Test] [Test]
public void CfGetPlatformInfoTest() public void CfGetPlatformInfoTest()
{ {
@ -166,6 +287,9 @@ namespace Vanara.PInvoke.Tests
{ {
Assert.That(CfOpenFileWithOplock(TestCaseSources.SmallFile, CF_OPEN_FILE_FLAGS.CF_OPEN_FILE_FLAG_EXCLUSIVE, out var handle), ResultIs.Successful); Assert.That(CfOpenFileWithOplock(TestCaseSources.SmallFile, CF_OPEN_FILE_FLAGS.CF_OPEN_FILE_FLAG_EXCLUSIVE, out var handle), ResultIs.Successful);
Assert.That(handle, ResultIs.ValidHandle); Assert.That(handle, ResultIs.ValidHandle);
Assert.That(CfReferenceProtectedHandle(handle), ResultIs.Successful);
Assert.That(CfGetWin32HandleFromProtectedHandle(handle), ResultIs.ValidHandle);
Assert.That(() => CfReleaseProtectedHandle(handle), Throws.Nothing);
Assert.That(() => handle.Dispose(), Throws.Nothing); Assert.That(() => handle.Dispose(), Throws.Nothing);
} }
} }

View File

@ -1,7 +1,9 @@
using System; using ICSharpCode.Decompiler.IL;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal; using System.Security.Principal;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -20,6 +22,7 @@ namespace Vanara.PInvoke.Tests
{ {
public CloudSyncCallbackArgs(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) public CloudSyncCallbackArgs(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters)
{ {
//System.Diagnostics.Debug.WriteLine($"CloudSyncCallbackArgs<{typeof(T).Name}> : {string.Join(" ", CallbackParameters.Content.Select(b => b.ToString("X2")))}");
ConnectionKey = CallbackInfo.ConnectionKey; ConnectionKey = CallbackInfo.ConnectionKey;
CallbackContext = CallbackInfo.CallbackContext; CallbackContext = CallbackInfo.CallbackContext;
VolumeGuidName = CallbackInfo.VolumeGuidName; VolumeGuidName = CallbackInfo.VolumeGuidName;
@ -33,10 +36,11 @@ namespace Vanara.PInvoke.Tests
NormalizedPath = CallbackInfo.NormalizedPath; NormalizedPath = CallbackInfo.NormalizedPath;
TransferKey = CallbackInfo.TransferKey; TransferKey = CallbackInfo.TransferKey;
PriorityHint = CallbackInfo.PriorityHint; PriorityHint = CallbackInfo.PriorityHint;
CorrelationVector = CallbackInfo.CorrelationVector.ToNullableStructure<CORRELATION_VECTOR>(); pCorrelationVector = CallbackInfo.CorrelationVector;
ProcessInfo = CallbackInfo.ProcessInfo.ToNullableStructure<CF_PROCESS_INFO>(); ProcessInfo = CallbackInfo.ProcessInfo.ToNullableStructure<CF_PROCESS_INFO>();
RequestKey = CallbackInfo.RequestKey; RequestKey = CallbackInfo.RequestKey;
ParamData = CallbackParameters.GetParam<T>(); try { ParamData = CallbackParameters.GetParam<T>(); } catch { }
//catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"{ex.Message}"); }
} }
/// <summary>points to an opaque blob that the sync provider provides at the sync root connect time.</summary> /// <summary>points to an opaque blob that the sync provider provides at the sync root connect time.</summary>
@ -46,7 +50,10 @@ namespace Vanara.PInvoke.Tests
public CF_CONNECTION_KEY ConnectionKey { get; } public CF_CONNECTION_KEY ConnectionKey { get; }
/// <summary>An optional correlation vector.</summary> /// <summary>An optional correlation vector.</summary>
public CORRELATION_VECTOR? CorrelationVector { get; } public IntPtr pCorrelationVector { get; }
/// <summary>An optional correlation vector.</summary>
public CORRELATION_VECTOR? CorrelationVector => pCorrelationVector.ToNullableStructure<CORRELATION_VECTOR>();
/// <summary>A 64 bit file system maintained, volume-wide unique ID of the placeholder file/directory to be serviced.</summary> /// <summary>A 64 bit file system maintained, volume-wide unique ID of the placeholder file/directory to be serviced.</summary>
public long FileId { get; } public long FileId { get; }
@ -66,6 +73,9 @@ namespace Vanara.PInvoke.Tests
/// <summary>Contains callback specific parameters for this action.</summary> /// <summary>Contains callback specific parameters for this action.</summary>
public T ParamData { get; } public T ParamData { get; }
/// <summary>Parameters of an operation on a placeholder file or folder.</summary>
public CF_OPERATION_PARAMETERS? OpParam { get; set; }
/// <summary> /// <summary>
/// A numeric scale given to the sync provider to describe the relative priority of one fetch compared to another fetch, in order to /// A numeric scale given to the sync provider to describe the relative priority of one fetch compared to another fetch, in order to
/// provide the most responsive experience to the user. The values range from 0 (lowest possible priority) to 15 (highest possible priority). /// provide the most responsive experience to the user. The values range from 0 (lowest possible priority) to 15 (highest possible priority).
@ -95,11 +105,40 @@ namespace Vanara.PInvoke.Tests
/// <summary>DOS drive letter of the volume in the form of “X:” where X is the drive letter.</summary> /// <summary>DOS drive letter of the volume in the form of “X:” where X is the drive letter.</summary>
public string VolumeDosName { get; } public string VolumeDosName { get; }
/// <summary>GUID name of the volume on which the placeholder file/directory to be serviced resides. It is in the form: “\?\Volume{GUID}”.</summary> /// <summary>GUID name of the volume on which the placeholder file/directory to be serviced resides. It is in the form: "\?\Volume{GUID}".</summary>
public string VolumeGuidName { get; } public string VolumeGuidName { get; }
/// <summary>The serial number of the volume.</summary> /// <summary>The serial number of the volume.</summary>
public uint VolumeSerialNumber { get; } public uint VolumeSerialNumber { get; }
/// <summary>The type of operation performed.</summary>
public CF_OPERATION_TYPE OperationType { get; set; }
/// <summary>
/// <note>This member is new for Windows 10, version 1803.</note>
/// <para>The current sync status of the platform.</para>
/// <para>
/// The platform queries this information upon any failed operations on a cloud file placeholder. If a structure is available, the
/// platform will use the information provided to construct a more meaningful and actionable message to the user. The platform will
/// keep this information on the file until the last handle on it goes away. If <see langword="null"/>, the platform will clear the
/// previously set sync status, if there is one.
/// </para>
/// </summary>
public IntPtr SyncStatus { get; set; }
/// <summary>Makes a CF_OPERATION_INFO instance from the properties.</summary>
/// <param name="opType">Type of the operation to set.</param>
/// <returns>A CF_OPERATION_INFO instance.</returns>
public CF_OPERATION_INFO MakeOpInfo(CF_OPERATION_TYPE opType, IntPtr syncStatus = default) => new CF_OPERATION_INFO
{
StructSize = (uint)Marshal.SizeOf<CF_OPERATION_INFO>(),
Type = opType,
ConnectionKey = ConnectionKey,
TransferKey = TransferKey,
CorrelationVector = pCorrelationVector,
RequestKey = RequestKey,
SyncStatus = syncStatus
};
} }
public class PlaceHolderDirectoryInfo : PlaceholderInfo public class PlaceHolderDirectoryInfo : PlaceholderInfo
@ -197,31 +236,31 @@ namespace Vanara.PInvoke.Tests
ConnectSyncRootTransferCallbacks(); ConnectSyncRootTransferCallbacks();
} }
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CANCEL>> CancelFetchData; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.CANCEL>> CancelFetchData;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CANCEL>> CancelFetchPlaceholders; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.CANCEL>> CancelFetchPlaceholders;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_FETCHDATA>> FetchData; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.FETCHDATA>> FetchData;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS>> FetchPlaceholders; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.FETCHPLACEHOLDERS>> FetchPlaceholders;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DEHYDRATE>> NotifyDehydrate; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.DEHYDRATE>> NotifyDehydrate;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION>> NotifyDehydrateCompletion; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.DEHYDRATECOMPLETION>> NotifyDehydrateCompletion;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DELETE>> NotifyDelete; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.DELETE>> NotifyDelete;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DELETECOMPLETION>> NotifyDeleteCompletion; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.DELETECOMPLETION>> NotifyDeleteCompletion;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CLOSECOMPLETION>> NotifyFileCloseCompletion; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.CLOSECOMPLETION>> NotifyFileCloseCompletion;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_OPENCOMPLETION>> NotifyFileOpenCompletion; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.OPENCOMPLETION>> NotifyFileOpenCompletion;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_RENAME>> NotifyRename; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.RENAME>> NotifyRename;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_RENAMECOMPLETION>> NotifyRenameCompletion; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.RENAMECOMPLETION>> NotifyRenameCompletion;
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_VALIDATEDATA>> ValidateData; public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS.VALIDATEDATA>> ValidateData;
public string DisplayName { get; } public string DisplayName { get; }
@ -231,6 +270,12 @@ namespace Vanara.PInvoke.Tests
public Uri RecycleBinUri { get; } public Uri RecycleBinUri { get; }
public CF_SYNC_PROVIDER_STATUS Status
{
get => CfQuerySyncProviderStatus(key.Value, out var stat).Succeeded ? stat : CF_SYNC_PROVIDER_STATUS.CF_PROVIDER_STATUS_ERROR;
set => CfUpdateSyncProviderStatus(key.Value, value);
}
public string SyncRootId { get; } public string SyncRootId { get; }
public string SyncRootPath { get; } public string SyncRootPath { get; }
@ -341,44 +386,46 @@ namespace Vanara.PInvoke.Tests
UnregisterWithShell(); UnregisterWithShell();
} }
protected virtual void OnCancelFetchData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnCancelFetchData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(CancelFetchData, CallbackInfo, CallbackParameters);
CancelFetchData?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CANCEL>(CallbackInfo, CallbackParameters));
protected virtual void OnCancelFetchPlaceholders(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnCancelFetchPlaceholders(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(CancelFetchPlaceholders, CallbackInfo, CallbackParameters);
CancelFetchPlaceholders?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CANCEL>(CallbackInfo, CallbackParameters));
protected virtual void OnFetchData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnFetchData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(FetchData, CallbackInfo, CallbackParameters);
FetchData?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_FETCHDATA>(CallbackInfo, CallbackParameters));
protected virtual void OnFetchPlaceholders(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnFetchPlaceholders(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(FetchPlaceholders, CallbackInfo, CallbackParameters);
FetchPlaceholders?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyDehydrate(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyDehydrate(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyDehydrate, CallbackInfo, CallbackParameters);
NotifyDehydrate?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DEHYDRATE>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyDehydrateCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyDehydrateCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyDehydrateCompletion, CallbackInfo, CallbackParameters);
NotifyDehydrateCompletion?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyDelete(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyDelete(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyDelete, CallbackInfo, CallbackParameters);
NotifyDelete?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DELETE>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyDeleteCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyDeleteCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyDeleteCompletion, CallbackInfo, CallbackParameters);
NotifyDeleteCompletion?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_DELETECOMPLETION>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyFileCloseCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyFileCloseCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyFileCloseCompletion, CallbackInfo, CallbackParameters);
NotifyFileCloseCompletion?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_CLOSECOMPLETION>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyFileOpenCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyFileOpenCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyFileOpenCompletion, CallbackInfo, CallbackParameters);
NotifyFileOpenCompletion?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_OPENCOMPLETION>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyRename(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyRename(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyRename, CallbackInfo, CallbackParameters);
NotifyRename?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_RENAME>(CallbackInfo, CallbackParameters));
protected virtual void OnNotifyRenameCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnNotifyRenameCompletion(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(NotifyRenameCompletion, CallbackInfo, CallbackParameters);
NotifyRenameCompletion?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_RENAMECOMPLETION>(CallbackInfo, CallbackParameters));
protected virtual void OnValidateData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => protected virtual void OnValidateData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) => HandleEvent(ValidateData, CallbackInfo, CallbackParameters);
ValidateData?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_VALIDATEDATA>(CallbackInfo, CallbackParameters));
protected virtual void HandleEvent<T>(EventHandler<CloudSyncCallbackArgs<T>> handler, in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters) where T : struct
{
if (handler != null)
{
var args = new CloudSyncCallbackArgs<T>(CallbackInfo, CallbackParameters);
handler.Invoke(this, args);
if (args.OperationType != 0 && args.OpParam.HasValue)
{
var opInfo = args.MakeOpInfo(args.OperationType, args.SyncStatus);
var opParam = args.OpParam.Value;
CfExecute(opInfo, ref opParam).ThrowIfFailed();
}
}
}
private static void AddFolderToSearchIndexer(string folder) private static void AddFolderToSearchIndexer(string folder)
{ {