mirror of https://github.com/dahall/Vanara.git
Committed work in progress on cldapi.dll
parent
854ab9536d
commit
ed51271853
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Vanara.InteropServices;
|
||||||
using static Vanara.PInvoke.Kernel32;
|
using static Vanara.PInvoke.Kernel32;
|
||||||
|
|
||||||
namespace Vanara.PInvoke
|
namespace Vanara.PInvoke
|
||||||
|
@ -12,7 +13,9 @@ namespace Vanara.PInvoke
|
||||||
/// <param name="CallbackInfo">The callback information.</param>
|
/// <param name="CallbackInfo">The callback information.</param>
|
||||||
/// <param name="CallbackParameters">The callback parameters.</param>
|
/// <param name="CallbackParameters">The callback parameters.</param>
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||||
public delegate void CF_CALLBACK(in CF_CALLBACK_INFO CallbackInfo, IntPtr CallbackParameters);
|
public delegate void CF_CALLBACK(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters);
|
||||||
|
|
||||||
|
private delegate HRESULT GetInfoFunc<TParam, TEnum>(TParam p1, TEnum InfoClass, IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength) where TEnum : Enum;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes the file or directory handle returned by CfOpenFileWithOplock. This should not be used with standard Win32 file handles,
|
/// Closes the file or directory handle returned by CfOpenFileWithOplock. This should not be used with standard Win32 file handles,
|
||||||
|
@ -176,6 +179,35 @@ namespace Vanara.PInvoke
|
||||||
public static unsafe extern HRESULT CfConvertToPlaceholder(HFILE FileHandle, [In, Optional] IntPtr FileIdentity, uint FileIdentityLength, CF_CONVERT_FLAGS ConvertFlags,
|
public static unsafe extern HRESULT CfConvertToPlaceholder(HFILE FileHandle, [In, Optional] IntPtr FileIdentity, uint FileIdentityLength, CF_CONVERT_FLAGS ConvertFlags,
|
||||||
[Out, Optional] int* ConvertUsn, [In, Out, Optional] NativeOverlapped* Overlapped);
|
[Out, Optional] int* ConvertUsn, [In, Out, Optional] NativeOverlapped* Overlapped);
|
||||||
|
|
||||||
|
/// <summary>Creates one or more new placeholder files or directories under a sync root tree.</summary>
|
||||||
|
/// <param name="BaseDirectoryPath">Local directory path under which placeholders are created.</param>
|
||||||
|
/// <param name="PlaceholderArray">
|
||||||
|
/// On successful creation, the PlaceholderArray contains the final USN value and a STATUS_OK message. On return, this array
|
||||||
|
/// contains an HRESULT value describing whether the placeholder was created or not.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="PlaceholderCount">The count of placeholders in the PlaceholderArray.</param>
|
||||||
|
/// <param name="CreateFlags">Flags for configuring the creation of a placeholder.</param>
|
||||||
|
/// <param name="EntriesProcessed">The number of entries processed, including failed entries.</param>
|
||||||
|
/// <returns>If this function succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Creating a placeholder with this function is preferred compared to creating a new file with CreateFile and then converting it to
|
||||||
|
/// a placeholder with CfConvertToPlaceholder; both for efficiency and because it eliminates the time window where the file is not a
|
||||||
|
/// placeholder. The function can also create multiple files or directories in a batch, which can also be more efficient.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This function is useful when performing an initial sync of files or directories from the cloud down to the client, or when
|
||||||
|
/// syncing down a newly created single file or directory from the cloud.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/nf-cfapi-cfcreateplaceholders HRESULT CfCreatePlaceholders( LPCWSTR
|
||||||
|
// BaseDirectoryPath, CF_PLACEHOLDER_CREATE_INFO *PlaceholderArray, DWORD PlaceholderCount, CF_CREATE_FLAGS CreateFlags, PDWORD
|
||||||
|
// EntriesProcessed );
|
||||||
|
[DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)]
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "96A6F62E-7F14-40B5-AB57-260DC9B1DF89")]
|
||||||
|
public static extern HRESULT CfCreatePlaceholders([MarshalAs(UnmanagedType.LPWStr)] string BaseDirectoryPath, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] CF_PLACEHOLDER_CREATE_INFO[] PlaceholderArray,
|
||||||
|
uint PlaceholderCount, CF_CREATE_FLAGS CreateFlags, out uint EntriesProcessed);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dehydrates a placeholder file by ensuring that the specified byte range is not present on-disk in the placeholder. This is valid
|
/// Dehydrates a placeholder file by ensuring that the specified byte range is not present on-disk in the placeholder. This is valid
|
||||||
/// for files only.
|
/// for files only.
|
||||||
|
@ -248,35 +280,6 @@ namespace Vanara.PInvoke
|
||||||
[PInvokeData("CfApi.h")]
|
[PInvokeData("CfApi.h")]
|
||||||
public static unsafe extern HRESULT CfDehydratePlaceholder(HFILE FileHandle, long StartingOffset, long Length, CF_DEHYDRATE_FLAGS DehydrateFlags, [In, Out] NativeOverlapped* Overlapped);
|
public static unsafe extern HRESULT CfDehydratePlaceholder(HFILE FileHandle, long StartingOffset, long Length, CF_DEHYDRATE_FLAGS DehydrateFlags, [In, Out] NativeOverlapped* Overlapped);
|
||||||
|
|
||||||
/// <summary>Creates one or more new placeholder files or directories under a sync root tree.</summary>
|
|
||||||
/// <param name="BaseDirectoryPath">Local directory path under which placeholders are created.</param>
|
|
||||||
/// <param name="PlaceholderArray">
|
|
||||||
/// On successful creation, the PlaceholderArray contains the final USN value and a STATUS_OK message. On return, this array
|
|
||||||
/// contains an HRESULT value describing whether the placeholder was created or not.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="PlaceholderCount">The count of placeholders in the PlaceholderArray.</param>
|
|
||||||
/// <param name="CreateFlags">Flags for configuring the creation of a placeholder.</param>
|
|
||||||
/// <param name="EntriesProcessed">The number of entries processed, including failed entries.</param>
|
|
||||||
/// <returns>If this function succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// Creating a placeholder with this function is preferred compared to creating a new file with CreateFile and then converting it to
|
|
||||||
/// a placeholder with CfConvertToPlaceholder; both for efficiency and because it eliminates the time window where the file is not a
|
|
||||||
/// placeholder. The function can also create multiple files or directories in a batch, which can also be more efficient.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// This function is useful when performing an initial sync of files or directories from the cloud down to the client, or when
|
|
||||||
/// syncing down a newly created single file or directory from the cloud.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/nf-cfapi-cfcreateplaceholders HRESULT CfCreatePlaceholders( LPCWSTR
|
|
||||||
// BaseDirectoryPath, CF_PLACEHOLDER_CREATE_INFO *PlaceholderArray, DWORD PlaceholderCount, CF_CREATE_FLAGS CreateFlags, PDWORD
|
|
||||||
// EntriesProcessed );
|
|
||||||
[DllImport(Lib.CldApi, SetLastError = false, ExactSpelling = true)]
|
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "96A6F62E-7F14-40B5-AB57-260DC9B1DF89")]
|
|
||||||
public static extern HRESULT CfCreatePlaceholders([MarshalAs(UnmanagedType.LPWStr)] string BaseDirectoryPath, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] CF_PLACEHOLDER_CREATE_INFO[] PlaceholderArray,
|
|
||||||
uint PlaceholderCount, CF_CREATE_FLAGS CreateFlags, out uint EntriesProcessed);
|
|
||||||
|
|
||||||
/// <summary>Disconnects a communication channel created by CfConnectSyncRoot.</summary>
|
/// <summary>Disconnects a communication channel created by CfConnectSyncRoot.</summary>
|
||||||
/// <param name="ConnectionKey">The connection key returned from CfConnectSyncRoot that is now used to disconnect the sync root.</param>
|
/// <param name="ConnectionKey">The connection key returned from CfConnectSyncRoot that is now used to disconnect the sync root.</param>
|
||||||
/// <returns>If this function succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
|
/// <returns>If this function succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
|
||||||
|
@ -349,6 +352,13 @@ namespace Vanara.PInvoke
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "D82269CF-8056-46CF-9832-AAE8767A854B")]
|
[PInvokeData("cfapi.h", MSDNShortId = "D82269CF-8056-46CF-9832-AAE8767A854B")]
|
||||||
public static extern HRESULT CfGetPlaceholderInfo(HFILE FileHandle, CF_PLACEHOLDER_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
public static extern HRESULT CfGetPlaceholderInfo(HFILE FileHandle, CF_PLACEHOLDER_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
||||||
|
|
||||||
|
/// <summary>Gets various characteristics of a placeholder file or folder.</summary>
|
||||||
|
/// <typeparam name="T">The type of information to retrieve.</typeparam>
|
||||||
|
/// <param name="FileHandle">A handle to the placeholder whose information will be queried.</param>
|
||||||
|
/// <returns>The requested information.</returns>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "D82269CF-8056-46CF-9832-AAE8767A854B")]
|
||||||
|
public static T CfGetPlaceholderInfo<T>(HFILE FileHandle) where T : struct => GetInfo<T, CF_PLACEHOLDER_INFO_CLASS, HFILE>(CfGetPlaceholderInfo, FileHandle);
|
||||||
|
|
||||||
/// <summary>Gets range information about a placeholder file or folder.</summary>
|
/// <summary>Gets range information about a placeholder file or folder.</summary>
|
||||||
/// <param name="FileHandle">The handle of the placeholder file to be queried.</param>
|
/// <param name="FileHandle">The handle of the placeholder file to be queried.</param>
|
||||||
/// <param name="InfoClass">Types of the range of placeholder data.</param>
|
/// <param name="InfoClass">Types of the range of placeholder data.</param>
|
||||||
|
@ -440,6 +450,13 @@ namespace Vanara.PInvoke
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "EC96CB4E-6BCE-49D9-9CDA-A24A9303B5CF")]
|
[PInvokeData("cfapi.h", MSDNShortId = "EC96CB4E-6BCE-49D9-9CDA-A24A9303B5CF")]
|
||||||
public static extern HRESULT CfGetSyncRootInfoByHandle(HFILE FileHandle, CF_SYNC_ROOT_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
public static extern HRESULT CfGetSyncRootInfoByHandle(HFILE FileHandle, CF_SYNC_ROOT_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
||||||
|
|
||||||
|
/// <summary>Gets various characteristics of the sync root containing a given file specified by a file handle.</summary>
|
||||||
|
/// <typeparam name="T">The type of information to retrieve.</typeparam>
|
||||||
|
/// <param name="FileHandle">Handle of the file under the sync root whose information is to be queried.</param>
|
||||||
|
/// <returns>The requested sync root information.</returns>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "EC96CB4E-6BCE-49D9-9CDA-A24A9303B5CF")]
|
||||||
|
public static T CfGetSyncRootInfoByHandle<T>(HFILE FileHandle) where T : struct => GetInfo<T, CF_SYNC_ROOT_INFO_CLASS, HFILE>(CfGetSyncRootInfoByHandle, FileHandle);
|
||||||
|
|
||||||
/// <summary>Gets various sync root information given a file under the sync root.</summary>
|
/// <summary>Gets various sync root information given a file under the sync root.</summary>
|
||||||
/// <param name="FilePath">A fully qualified path to a file whose sync root information is to be queried</param>
|
/// <param name="FilePath">A fully qualified path to a file whose sync root information is to be queried</param>
|
||||||
/// <param name="InfoClass">Types of sync root information.</param>
|
/// <param name="InfoClass">Types of sync root information.</param>
|
||||||
|
@ -455,6 +472,14 @@ namespace Vanara.PInvoke
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "0FEEF910-3545-4D94-BFF9-88AEE084F454")]
|
[PInvokeData("cfapi.h", MSDNShortId = "0FEEF910-3545-4D94-BFF9-88AEE084F454")]
|
||||||
public static extern HRESULT CfGetSyncRootInfoByPath([MarshalAs(UnmanagedType.LPWStr)] string FilePath, CF_SYNC_ROOT_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
public static extern HRESULT CfGetSyncRootInfoByPath([MarshalAs(UnmanagedType.LPWStr)] string FilePath, CF_SYNC_ROOT_INFO_CLASS InfoClass, [Out] IntPtr InfoBuffer, uint InfoBufferLength, out uint ReturnedLength);
|
||||||
|
|
||||||
|
/// <summary>Gets various sync root information given a file under the sync root.</summary>
|
||||||
|
/// <typeparam name="T">The type of information to retrieve.</typeparam>
|
||||||
|
/// <param name="FilePath">A fully qualified path to a file whose sync root information is to be queried</param>
|
||||||
|
/// <returns>The requested sync root information.</returns>
|
||||||
|
/// <exception cref="ArgumentException">Supplied type parameter is not supported. - T</exception>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "0FEEF910-3545-4D94-BFF9-88AEE084F454")]
|
||||||
|
public static T CfGetSyncRootInfoByPath<T>(string FilePath) where T : struct => GetInfo<T, CF_SYNC_ROOT_INFO_CLASS, string>(CfGetSyncRootInfoByPath, FilePath);
|
||||||
|
|
||||||
/// <summary>Initiates a transfer of data into a placeholder file or folder.</summary>
|
/// <summary>Initiates a transfer of data into a placeholder file or folder.</summary>
|
||||||
/// <param name="FileHandle">The file handle of the placeholder.</param>
|
/// <param name="FileHandle">The file handle of the placeholder.</param>
|
||||||
/// <param name="TransferKey">An opaque handle to the placeholder to be serviced.</param>
|
/// <param name="TransferKey">An opaque handle to the placeholder to be serviced.</param>
|
||||||
|
@ -1084,6 +1109,21 @@ namespace Vanara.PInvoke
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "E0CB6CA2-439A-4919-95EF-B519ABBBB085")]
|
[PInvokeData("cfapi.h", MSDNShortId = "E0CB6CA2-439A-4919-95EF-B519ABBBB085")]
|
||||||
public static extern HRESULT CfUpdateSyncProviderStatus(CF_CONNECTION_KEY ConnectionKey, CF_SYNC_PROVIDER_STATUS ProviderStatus);
|
public static extern HRESULT CfUpdateSyncProviderStatus(CF_CONNECTION_KEY ConnectionKey, CF_SYNC_PROVIDER_STATUS ProviderStatus);
|
||||||
|
|
||||||
|
private static T GetInfo<T, TEnum, TParam>(GetInfoFunc<TParam, TEnum> func, TParam firstParam) where TEnum : struct, Enum where T : struct
|
||||||
|
{
|
||||||
|
if (!CorrespondingTypeAttribute.CanGet<TEnum>(typeof(T), out var infoClass))
|
||||||
|
throw new ArgumentException("Supplied type parameter is not supported.", nameof(T));
|
||||||
|
using var mem = SafeHGlobalHandle.CreateFromStructure<T>();
|
||||||
|
var hr = func(firstParam, infoClass, mem, mem.Size, out var len);
|
||||||
|
while (hr == (HRESULT)(Win32Error)Win32Error.ERROR_MORE_DATA && mem.Size < 1024 * 32)
|
||||||
|
{
|
||||||
|
mem.Size = len * 4;
|
||||||
|
hr = func(firstParam, infoClass, mem, mem.Size, out len);
|
||||||
|
}
|
||||||
|
hr.ThrowIfFailed();
|
||||||
|
return mem.ToStructure<T>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Provides a handle to a CF opened file.</summary>
|
/// <summary>Provides a handle to a CF opened file.</summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct HCFFILE : IHandle
|
public struct HCFFILE : IHandle
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Vanara.Extensions;
|
||||||
using Vanara.InteropServices;
|
using Vanara.InteropServices;
|
||||||
using static Vanara.PInvoke.Kernel32;
|
using static Vanara.PInvoke.Kernel32;
|
||||||
|
|
||||||
|
@ -904,9 +905,11 @@ namespace Vanara.PInvoke
|
||||||
public enum CF_PLACEHOLDER_INFO_CLASS
|
public enum CF_PLACEHOLDER_INFO_CLASS
|
||||||
{
|
{
|
||||||
/// <summary>Basic placeholder information. See CF_PLACEHOLDER_BASIC_INFO.</summary>
|
/// <summary>Basic placeholder information. See CF_PLACEHOLDER_BASIC_INFO.</summary>
|
||||||
|
[CorrespondingType(typeof(CF_PLACEHOLDER_BASIC_INFO), CorrespondingAction.Get)]
|
||||||
CF_PLACEHOLDER_INFO_BASIC,
|
CF_PLACEHOLDER_INFO_BASIC,
|
||||||
|
|
||||||
/// <summary>Standard placeholder information. See CF_PLACEHOLDER_STANDARD_INFO.</summary>
|
/// <summary>Standard placeholder information. See CF_PLACEHOLDER_STANDARD_INFO.</summary>
|
||||||
|
[CorrespondingType(typeof(CF_PLACEHOLDER_STANDARD_INFO), CorrespondingAction.Get)]
|
||||||
CF_PLACEHOLDER_INFO_STANDARD,
|
CF_PLACEHOLDER_INFO_STANDARD,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,12 +1148,15 @@ namespace Vanara.PInvoke
|
||||||
public enum CF_SYNC_ROOT_INFO_CLASS
|
public enum CF_SYNC_ROOT_INFO_CLASS
|
||||||
{
|
{
|
||||||
/// <summary>Basic sync root information. See CF_SYNC_ROOT_BASIC_INFO.</summary>
|
/// <summary>Basic sync root information. See CF_SYNC_ROOT_BASIC_INFO.</summary>
|
||||||
|
[CorrespondingType(typeof(CF_SYNC_ROOT_BASIC_INFO), CorrespondingAction.Get)]
|
||||||
CF_SYNC_ROOT_INFO_BASIC,
|
CF_SYNC_ROOT_INFO_BASIC,
|
||||||
|
|
||||||
/// <summary>Standard sync root information. See CF_SYNC_ROOT_STANDARD_INFO.</summary>
|
/// <summary>Standard sync root information. See CF_SYNC_ROOT_STANDARD_INFO.</summary>
|
||||||
|
[CorrespondingType(typeof(CF_SYNC_ROOT_STANDARD_INFO), CorrespondingAction.Get)]
|
||||||
CF_SYNC_ROOT_INFO_STANDARD,
|
CF_SYNC_ROOT_INFO_STANDARD,
|
||||||
|
|
||||||
/// <summary>Sync root provider information. See CF_SYNC_ROOT_PROVIDER_INFO.</summary>
|
/// <summary>Sync root provider information. See CF_SYNC_ROOT_PROVIDER_INFO.</summary>
|
||||||
|
[CorrespondingType(typeof(CF_SYNC_ROOT_PROVIDER_INFO), CorrespondingAction.Get)]
|
||||||
CF_SYNC_ROOT_INFO_PROVIDER,
|
CF_SYNC_ROOT_INFO_PROVIDER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1336,20 +1342,30 @@ 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.Explicit)]
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
public struct CF_CALLBACK_PARAMETERS
|
public struct CF_CALLBACK_PARAMETERS
|
||||||
{
|
{
|
||||||
/// <summary/>
|
/// <summary/>
|
||||||
[FieldOffset(0)]
|
|
||||||
public uint ParamSize;
|
public uint ParamSize;
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary/>
|
||||||
[FieldOffset(4)]
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)]
|
||||||
public CANCEL Cancel;
|
public byte[] Content;
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Gets the parameter value for this structure.</summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
/// <typeparam name="T">The type of the structure to retrieve.</typeparam>
|
||||||
public struct CANCEL
|
/// <returns>The requested structure.</returns>
|
||||||
|
public T GetParam<T>() where T : struct
|
||||||
|
{
|
||||||
|
using var ptr = new SafeHGlobalHandle(Content);
|
||||||
|
return ptr.ToStructure<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_CANCEL
|
||||||
{
|
{
|
||||||
/// <summary>Cancel data flags.</summary>
|
/// <summary>Cancel data flags.</summary>
|
||||||
public CF_CALLBACK_CANCEL_FLAGS Flags;
|
public CF_CALLBACK_CANCEL_FLAGS Flags;
|
||||||
|
@ -1369,13 +1385,61 @@ namespace Vanara.PInvoke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[FieldOffset(4)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public FETCHDATA FetchData;
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_CLOSECOMPLETION
|
||||||
|
{
|
||||||
|
/// <summary>Placeholder close completion flags.</summary>
|
||||||
|
public CF_CALLBACK_CLOSE_COMPLETION_FLAGS Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_DEHYDRATE
|
||||||
|
{
|
||||||
|
/// <summary>Placeholder dehydration flags.</summary>
|
||||||
|
public CF_CALLBACK_DEHYDRATE_FLAGS Flags;
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary/>
|
||||||
|
public CF_CALLBACK_DEHYDRATION_REASON Reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct FETCHDATA
|
public struct CF_CALLBACK_PARAMETERS_DEHYDRATECOMPLETION
|
||||||
|
{
|
||||||
|
/// <summary/>
|
||||||
|
public CF_CALLBACK_DEHYDRATE_COMPLETION_FLAGS Flags;
|
||||||
|
|
||||||
|
/// <summary/>
|
||||||
|
public CF_CALLBACK_DEHYDRATION_REASON Reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_DELETE
|
||||||
|
{
|
||||||
|
/// <summary>Placeholder deletion flags.</summary>
|
||||||
|
public CF_CALLBACK_DELETE_FLAGS Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_DELETECOMPLETION
|
||||||
|
{
|
||||||
|
/// <summary>Placeholder deletion complete flags.</summary>
|
||||||
|
public CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 56)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_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;
|
||||||
|
@ -1405,125 +1469,36 @@ namespace Vanara.PInvoke
|
||||||
public CF_CALLBACK_DEHYDRATION_REASON LastDehydrationReason;
|
public CF_CALLBACK_DEHYDRATION_REASON LastDehydrationReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public struct VALIDATEDATA
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
{
|
public struct CF_CALLBACK_PARAMETERS_FETCHPLACEHOLDERS
|
||||||
/// <summary>Data validation flags.</summary>
|
|
||||||
public CF_CALLBACK_VALIDATE_DATA_FLAGS Flags;
|
|
||||||
|
|
||||||
/// <summary>Offset, in bytes, for specifying the range of data to validate.</summary>
|
|
||||||
public long RequiredFileOffset;
|
|
||||||
|
|
||||||
/// <summary>Length, in bytes, of the data to validate.</summary>
|
|
||||||
public long RequiredLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public VALIDATEDATA ValidateData;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
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
|
/// A standard Windows file pattern which may contain wildcard characters (‘?’, ‘*’). All placeholders information matching the
|
||||||
/// the pattern must be transferred, but not necessarily in one-shot, as a minimum requirement. Alternatively, a sync
|
/// pattern must be transferred, but not necessarily in one-shot, as a minimum requirement. Alternatively, a sync provider may
|
||||||
/// 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/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[FieldOffset(4)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public FETCHPLACEHOLDERS FetchPlaceholders;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct OPENCOMPLETION
|
public struct CF_CALLBACK_PARAMETERS_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/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[FieldOffset(4)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public OPENCOMPLETION OpenCompletion;
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_RENAME
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct CLOSECOMPLETION
|
|
||||||
{
|
|
||||||
/// <summary>Placeholder close completion flags.</summary>
|
|
||||||
public CF_CALLBACK_CLOSE_COMPLETION_FLAGS Flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public CLOSECOMPLETION CloseCompletion;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct DEHYDRATE
|
|
||||||
{
|
|
||||||
/// <summary>Placeholder dehydration flags.</summary>
|
|
||||||
public CF_CALLBACK_DEHYDRATE_FLAGS Flags;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
public CF_CALLBACK_DEHYDRATION_REASON Reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public DEHYDRATE Dehydrate;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct DEHYDRATECOMPLETION
|
|
||||||
{
|
|
||||||
/// <summary/>
|
|
||||||
public CF_CALLBACK_DEHYDRATE_COMPLETION_FLAGS Flags;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
public CF_CALLBACK_DEHYDRATION_REASON Reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public DEHYDRATECOMPLETION DehydrateCompletion;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct DELETE
|
|
||||||
{
|
|
||||||
/// <summary>Placeholder deletion flags.</summary>
|
|
||||||
public CF_CALLBACK_DELETE_FLAGS Flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public DELETE Delete;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct DELETECOMPLETION
|
|
||||||
{
|
|
||||||
/// <summary>Placeholder deletion complete flags.</summary>
|
|
||||||
public CF_CALLBACK_DELETE_COMPLETION_FLAGS Flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[FieldOffset(4)]
|
|
||||||
public DELETECOMPLETION DeleteCompletion;
|
|
||||||
|
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
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;
|
||||||
|
@ -1533,13 +1508,10 @@ namespace Vanara.PInvoke
|
||||||
public string TargetPath;
|
public string TargetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[FieldOffset(4)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public RENAME Rename;
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_RENAMECOMPLETION
|
||||||
/// <summary/>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
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;
|
||||||
|
@ -1549,9 +1521,19 @@ namespace Vanara.PInvoke
|
||||||
public string SourcePath;
|
public string SourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary/>
|
/// <summary>Contains callback specific parameters such as file offset, length, flags, etc.</summary>
|
||||||
[FieldOffset(4)]
|
[PInvokeData("cfapi.h", MSDNShortId = "FA403E9E-5EFA-4285-9619-614DB0044FFB")]
|
||||||
public RENAMECOMPLETION RenameCompletion;
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
public struct CF_CALLBACK_PARAMETERS_VALIDATEDATA
|
||||||
|
{
|
||||||
|
/// <summary>Data validation flags.</summary>
|
||||||
|
public CF_CALLBACK_VALIDATE_DATA_FLAGS Flags;
|
||||||
|
|
||||||
|
/// <summary>Offset, in bytes, for specifying the range of data to validate.</summary>
|
||||||
|
public long RequiredFileOffset;
|
||||||
|
|
||||||
|
/// <summary>Length, in bytes, of the data to validate.</summary>
|
||||||
|
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>
|
||||||
|
@ -1590,6 +1572,20 @@ namespace Vanara.PInvoke
|
||||||
private long Internal;
|
private long Internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Specifies a range of data in a placeholder file.</summary>
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/ns-cfapi-cf_file_range typedef struct CF_FILE_RANGE { LARGE_INTEGER
|
||||||
|
// StartingOffset; LARGE_INTEGER Length; } CF_FILE_RANGE;
|
||||||
|
[PInvokeData("cfapi.h", MSDNShortId = "DAE43446-725E-490B-AE1B-EA6CB31F4358")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CF_FILE_RANGE
|
||||||
|
{
|
||||||
|
/// <summary>The offset of the starting point of the data.</summary>
|
||||||
|
public long StartingOffset;
|
||||||
|
|
||||||
|
/// <summary>The length of the data, in bytes.</summary>
|
||||||
|
public long Length;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>A structure to describe the location and range of data in a file.</summary>
|
/// <summary>A structure to describe the location and range of data in a file.</summary>
|
||||||
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/mt844616(v=vs.85) typedef struct __CF_FILE_RANGE_BUFFER
|
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/mt844616(v=vs.85) typedef struct __CF_FILE_RANGE_BUFFER
|
||||||
// { LARGE_INTEGER FileOffset; LARGE_INTEGER Length; } CF_FILE_RANGE_BUFFER;
|
// { LARGE_INTEGER FileOffset; LARGE_INTEGER Length; } CF_FILE_RANGE_BUFFER;
|
||||||
|
@ -1868,20 +1864,6 @@ namespace Vanara.PInvoke
|
||||||
public ACKDELETE AckDelete;
|
public ACKDELETE AckDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Specifies a range of data in a placeholder file.</summary>
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/ns-cfapi-cf_file_range
|
|
||||||
// typedef struct CF_FILE_RANGE { LARGE_INTEGER StartingOffset; LARGE_INTEGER Length; } CF_FILE_RANGE;
|
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "DAE43446-725E-490B-AE1B-EA6CB31F4358")]
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct CF_FILE_RANGE
|
|
||||||
{
|
|
||||||
/// <summary>The offset of the starting point of the data.</summary>
|
|
||||||
public int StartingOffset;
|
|
||||||
|
|
||||||
/// <summary>The length of the data, in bytes.</summary>
|
|
||||||
public int Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Basic placeholder information.</summary>
|
/// <summary>Basic placeholder information.</summary>
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/ns-cfapi-cf_placeholder_basic_info typedef struct
|
// https://docs.microsoft.com/en-us/windows/win32/api/cfapi/ns-cfapi-cf_placeholder_basic_info typedef struct
|
||||||
// CF_PLACEHOLDER_BASIC_INFO { CF_PIN_STATE PinState; CF_IN_SYNC_STATE InSyncState; LARGE_INTEGER FileId; LARGE_INTEGER
|
// CF_PLACEHOLDER_BASIC_INFO { CF_PIN_STATE PinState; CF_IN_SYNC_STATE InSyncState; LARGE_INTEGER FileId; LARGE_INTEGER
|
||||||
|
@ -2147,7 +2129,7 @@ namespace Vanara.PInvoke
|
||||||
public struct CF_SYNC_ROOT_BASIC_INFO
|
public struct CF_SYNC_ROOT_BASIC_INFO
|
||||||
{
|
{
|
||||||
/// <summary>The file ID of the sync root.</summary>
|
/// <summary>The file ID of the sync root.</summary>
|
||||||
public int SyncRootFileId;
|
public long SyncRootFileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sync root provider information.</summary>
|
/// <summary>Sync root provider information.</summary>
|
||||||
|
@ -2180,11 +2162,11 @@ namespace Vanara.PInvoke
|
||||||
// SyncRootIdentityLength; BYTE SyncRootIdentity[1]; } CF_SYNC_ROOT_STANDARD_INFO;
|
// SyncRootIdentityLength; BYTE SyncRootIdentity[1]; } CF_SYNC_ROOT_STANDARD_INFO;
|
||||||
[PInvokeData("cfapi.h", MSDNShortId = "17E409FB-2997-432C-977F-BEBF53068B42")]
|
[PInvokeData("cfapi.h", MSDNShortId = "17E409FB-2997-432C-977F-BEBF53068B42")]
|
||||||
[VanaraMarshaler(typeof(SafeAnysizeStructMarshaler<CF_SYNC_ROOT_STANDARD_INFO>), nameof(SyncRootIdentityLength))]
|
[VanaraMarshaler(typeof(SafeAnysizeStructMarshaler<CF_SYNC_ROOT_STANDARD_INFO>), nameof(SyncRootIdentityLength))]
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
public struct CF_SYNC_ROOT_STANDARD_INFO
|
public struct CF_SYNC_ROOT_STANDARD_INFO
|
||||||
{
|
{
|
||||||
/// <summary>File ID of the sync root.</summary>
|
/// <summary>File ID of the sync root.</summary>
|
||||||
public int SyncRootFileId;
|
public long SyncRootFileId;
|
||||||
|
|
||||||
/// <summary>Hydration policy of the sync root.</summary>
|
/// <summary>Hydration policy of the sync root.</summary>
|
||||||
public CF_HYDRATION_POLICY HydrationPolicy;
|
public CF_HYDRATION_POLICY HydrationPolicy;
|
||||||
|
|
|
@ -46,6 +46,10 @@
|
||||||
<Project>{842d436f-598c-47d7-b5aa-12399f8ccfe9}</Project>
|
<Project>{842d436f-598c-47d7-b5aa-12399f8ccfe9}</Project>
|
||||||
<Name>Vanara.PInvoke.Kernel32</Name>
|
<Name>Vanara.PInvoke.Kernel32</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\PInvoke\SearchApi\Vanara.PInvoke.SearchApi.csproj">
|
||||||
|
<Project>{07cd630d-a4bd-45cb-bf1b-90e981f4de81}</Project>
|
||||||
|
<Name>Vanara.PInvoke.SearchApi</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\..\PInvoke\Shared\Vanara.PInvoke.Shared.csproj">
|
<ProjectReference Include="..\..\..\PInvoke\Shared\Vanara.PInvoke.Shared.csproj">
|
||||||
<Project>{a5e519e9-feba-4fe3-93a5-b8269bef72f4}</Project>
|
<Project>{a5e519e9-feba-4fe3-93a5-b8269bef72f4}</Project>
|
||||||
<Name>Vanara.PInvoke.Shared</Name>
|
<Name>Vanara.PInvoke.Shared</Name>
|
||||||
|
@ -56,6 +60,9 @@
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Windows.SDK.Contracts">
|
||||||
|
<Version>10.0.18362.2005</Version>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="NUnit">
|
<PackageReference Include="NUnit">
|
||||||
<Version>3.12.0</Version>
|
<Version>3.12.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -68,6 +75,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CldApiTests.cs" />
|
<Compile Include="CldApiTests.cs" />
|
||||||
|
<Compile Include="CloudSyncProvider.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
|
|
@ -1,17 +1,166 @@
|
||||||
using Microsoft.Win32.SafeHandles;
|
using ICSharpCode.Decompiler.TypeSystem;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
using Vanara.Extensions;
|
|
||||||
using Vanara.InteropServices;
|
using Vanara.InteropServices;
|
||||||
|
using Windows.Storage.Streams;
|
||||||
using static Vanara.PInvoke.CldApi;
|
using static Vanara.PInvoke.CldApi;
|
||||||
|
|
||||||
namespace Vanara.PInvoke.Tests
|
namespace Vanara.PInvoke.Tests
|
||||||
{
|
{
|
||||||
public class CldApiTests
|
public class CldApiTests
|
||||||
{
|
{
|
||||||
|
private static readonly string syncRootPath = Environment.GetEnvironmentVariable("OneDrive");
|
||||||
|
//private const string tempSubDir = "CfSource";
|
||||||
|
|
||||||
|
private static string SetupTempDir(string subDir) => Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), subDir)).FullName;
|
||||||
|
|
||||||
|
private static void DeleteTempDir(string subDir)
|
||||||
|
{
|
||||||
|
var dirInfo = new DirectoryInfo(Path.Combine(Path.GetTempPath(), subDir));
|
||||||
|
if (dirInfo.Exists) dirInfo.Delete(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfConnectSyncRootTest()
|
||||||
|
{
|
||||||
|
const string dest = "CfDest";
|
||||||
|
var destDirPath = SetupTempDir(dest);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteTempDir(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfCreatePlaceholdersTest()
|
||||||
|
{
|
||||||
|
const string dest = "CfDest";
|
||||||
|
var destDirPath = SetupTempDir(dest);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
|
||||||
|
|
||||||
|
csp.CancelFetchData += (s, e) => { TestContext.WriteLine($"CancelFetchData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.CancelFetchPlaceholders += (s, e) => { TestContext.WriteLine($"CancelFetchPlaceholders: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.FetchData += (s, e) => { TestContext.WriteLine($"FetchData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.FetchPlaceholders += (s, e) => { TestContext.WriteLine($"FetchPlaceholders: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyDehydrate += (s, e) => { TestContext.WriteLine($"NotifyDehydrate: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyDehydrateCompletion += (s, e) => { TestContext.WriteLine($"NotifyDehydrateCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyDelete += (s, e) => { TestContext.WriteLine($"NotifyDelete: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyDeleteCompletion += (s, e) => { TestContext.WriteLine($"NotifyDeleteCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyFileCloseCompletion += (s, e) => { TestContext.WriteLine($"NotifyFileCloseCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyFileOpenCompletion += (s, e) => { TestContext.WriteLine($"NotifyFileOpenCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyRename += (s, e) => { TestContext.WriteLine($"NotifyRename: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.NotifyRenameCompletion += (s, e) => { TestContext.WriteLine($"NotifyRenameCompletion: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
csp.ValidateData += (s, e) => { TestContext.WriteLine($"ValidateData: {e.NormalizedPath}, {e.FileSize}"); e.ParamData.WriteValues(); };
|
||||||
|
|
||||||
|
csp.CreatePlaceholderFromFile("test.bmp", new FileInfo(TestCaseSources.BmpFile), true);
|
||||||
|
Assert.That(File.Exists(Path.Combine(destDirPath, "test.bmp")), Is.True);
|
||||||
|
Assert.That(new FileInfo(Path.Combine(destDirPath, "test.bmp")).Length, Is.EqualTo(new FileInfo(TestCaseSources.BmpFile).Length));
|
||||||
|
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteTempDir(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CopyFile(string src, string destDir)
|
||||||
|
{
|
||||||
|
var destFile = Path.Combine(destDir, Path.GetFileName(src));
|
||||||
|
File.Copy(src, destFile);
|
||||||
|
Assert.That(File.Exists(destFile), Is.True);
|
||||||
|
return destFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Kernel32.SafeHFILE GetHFILE(string path) => Kernel32.CreateFile(path, Kernel32.FileAccess.FILE_READ_ATTRIBUTES, FileShare.Read, null, FileMode.Open, 0);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfGetPlaceholderInfoTest()
|
||||||
|
{
|
||||||
|
const string dest = "CfDest";
|
||||||
|
var destDirPath = SetupTempDir(dest);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var csp = new CloudSyncProvider(destDirPath, "TestSync");
|
||||||
|
|
||||||
|
// Copy in file and convert to placeholder
|
||||||
|
var destFile = CopyFile(TestCaseSources.WordDoc, destDirPath);
|
||||||
|
Assert.That(() => csp.ConvertToPlaceholder(destFile), Throws.Nothing);
|
||||||
|
|
||||||
|
using var hFile = GetHFILE(destFile);
|
||||||
|
Assert.That(() => CfGetPlaceholderInfo<CF_PLACEHOLDER_BASIC_INFO>(hFile).WriteValues(), Throws.Nothing);
|
||||||
|
Assert.That(() => CfGetPlaceholderInfo<CF_PLACEHOLDER_STANDARD_INFO>(hFile).WriteValues(), Throws.Nothing);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteTempDir(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfGetPlaceholderStateFromFindDataTest()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
Assert.That(File.Exists(Path.Combine(destDirPath, "test.bmp")), Is.True);
|
||||||
|
|
||||||
|
Kernel32.FindFirstFile(Path.Combine(destDirPath, "test.bmp"), out var findData).Dispose();
|
||||||
|
CfGetPlaceholderStateFromFindData(findData).WriteValues();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteTempDir(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfGetPlatformInfoTest()
|
||||||
|
{
|
||||||
|
Assert.That(CfGetPlatformInfo(out var info), ResultIs.Successful);
|
||||||
|
info.WriteValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfGetSyncRootInfoByHandleTest()
|
||||||
|
{
|
||||||
|
using var hFile = GetHFILE(new DirectoryInfo(syncRootPath).EnumerateFiles("*.*").First().FullName);
|
||||||
|
Assert.That(hFile, ResultIs.ValidHandle);
|
||||||
|
using (var mem = SafeHGlobalHandle.CreateFromStructure<CF_SYNC_ROOT_BASIC_INFO>())
|
||||||
|
{
|
||||||
|
Assert.That(CfGetSyncRootInfoByHandle(hFile, CF_SYNC_ROOT_INFO_CLASS.CF_SYNC_ROOT_INFO_BASIC, mem, mem.Size, out var len), ResultIs.Successful);
|
||||||
|
mem.ToStructure<CF_SYNC_ROOT_BASIC_INFO>().WriteValues();
|
||||||
|
}
|
||||||
|
Assert.That(() => CfGetSyncRootInfoByHandle<CF_SYNC_ROOT_PROVIDER_INFO>(hFile).WriteValues(), Throws.Nothing);
|
||||||
|
Assert.That(() => CfGetSyncRootInfoByHandle<CF_SYNC_ROOT_STANDARD_INFO>(hFile).WriteValues(), Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CfGetSyncRootInfoByPathTest()
|
||||||
|
{
|
||||||
|
using (var mem = SafeHGlobalHandle.CreateFromStructure<CF_SYNC_ROOT_BASIC_INFO>())
|
||||||
|
{
|
||||||
|
Assert.That(CfGetSyncRootInfoByPath(syncRootPath, CF_SYNC_ROOT_INFO_CLASS.CF_SYNC_ROOT_INFO_BASIC, mem, mem.Size, out var len), ResultIs.Successful);
|
||||||
|
mem.ToStructure<CF_SYNC_ROOT_BASIC_INFO>().WriteValues();
|
||||||
|
}
|
||||||
|
Assert.That(() => CfGetSyncRootInfoByPath<CF_SYNC_ROOT_PROVIDER_INFO>(syncRootPath).WriteValues(), Throws.Nothing);
|
||||||
|
Assert.That(() => CfGetSyncRootInfoByPath<CF_SYNC_ROOT_STANDARD_INFO>(syncRootPath).WriteValues(), Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void CfOpenFileWithOplockTest()
|
public void CfOpenFileWithOplockTest()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,458 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Vanara.Extensions;
|
||||||
|
using Vanara.InteropServices;
|
||||||
|
using Windows.Security.Cryptography;
|
||||||
|
using Windows.Storage;
|
||||||
|
using Windows.Storage.Provider;
|
||||||
|
using static Vanara.PInvoke.CldApi;
|
||||||
|
using static Vanara.PInvoke.Kernel32;
|
||||||
|
using static Vanara.PInvoke.SearchApi;
|
||||||
|
|
||||||
|
namespace Vanara.PInvoke.Tests
|
||||||
|
{
|
||||||
|
public class CloudSyncCallbackArgs<T> : EventArgs where T : struct
|
||||||
|
{
|
||||||
|
public CloudSyncCallbackArgs(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS CallbackParameters)
|
||||||
|
{
|
||||||
|
ConnectionKey = CallbackInfo.ConnectionKey;
|
||||||
|
CallbackContext = CallbackInfo.CallbackContext;
|
||||||
|
VolumeGuidName = CallbackInfo.VolumeGuidName;
|
||||||
|
VolumeDosName = CallbackInfo.VolumeDosName;
|
||||||
|
VolumeSerialNumber = CallbackInfo.VolumeSerialNumber;
|
||||||
|
SyncRootFileId = CallbackInfo.SyncRootFileId;
|
||||||
|
SyncRootIdentity = new SafeHGlobalHandle(CallbackInfo.SyncRootIdentity, CallbackInfo.SyncRootIdentityLength, false);
|
||||||
|
FileId = CallbackInfo.FileId;
|
||||||
|
FileSize = CallbackInfo.FileSize;
|
||||||
|
FileIdentity = new SafeHGlobalHandle(CallbackInfo.FileIdentity, CallbackInfo.FileIdentityLength, false);
|
||||||
|
NormalizedPath = CallbackInfo.NormalizedPath;
|
||||||
|
TransferKey = CallbackInfo.TransferKey;
|
||||||
|
PriorityHint = CallbackInfo.PriorityHint;
|
||||||
|
CorrelationVector = CallbackInfo.CorrelationVector.ToNullableStructure<CORRELATION_VECTOR>();
|
||||||
|
ProcessInfo = CallbackInfo.ProcessInfo.ToNullableStructure<CF_PROCESS_INFO>();
|
||||||
|
RequestKey = CallbackInfo.RequestKey;
|
||||||
|
ParamData = CallbackParameters.GetParam<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>points to an opaque blob that the sync provider provides at the sync root connect time.</summary>
|
||||||
|
public IntPtr CallbackContext { get; }
|
||||||
|
|
||||||
|
/// <summary>An opaque handle created by CfConnectSyncRoot for a sync root managed by the sync provider.</summary>
|
||||||
|
public CF_CONNECTION_KEY ConnectionKey { get; }
|
||||||
|
|
||||||
|
/// <summary>An optional correlation vector.</summary>
|
||||||
|
public CORRELATION_VECTOR? CorrelationVector { get; }
|
||||||
|
|
||||||
|
/// <summary>A 64 bit file system maintained, volume-wide unique ID of the placeholder file/directory to be serviced.</summary>
|
||||||
|
public long FileId { get; }
|
||||||
|
|
||||||
|
/// <summary>Points to the opaque blob that the sync provider provides at the placeholder creation/conversion/update time.</summary>
|
||||||
|
public SafeAllocatedMemoryHandle FileIdentity { get; }
|
||||||
|
|
||||||
|
/// <summary>The logical size of the placeholder file to be serviced. It is always 0 if the subject of the callback is a directory.</summary>
|
||||||
|
public long FileSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The absolute path of the placeholder file/directory to be serviced on the volume identified by VolumeGuidName/VolumeDosName. It
|
||||||
|
/// starts from the root directory of the volume. See the Remarks section for more details.
|
||||||
|
/// </summary>
|
||||||
|
public string NormalizedPath { get; }
|
||||||
|
|
||||||
|
/// <summary>Contains callback specific parameters for this action.</summary>
|
||||||
|
public T ParamData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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).
|
||||||
|
/// </summary>
|
||||||
|
public byte PriorityHint { get; }
|
||||||
|
|
||||||
|
/// <summary>Points to a structure that contains the information about the user process that triggers this callback.</summary>
|
||||||
|
public CF_PROCESS_INFO? ProcessInfo { get; }
|
||||||
|
|
||||||
|
/// <summary/>
|
||||||
|
public CF_REQUEST_KEY RequestKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 64 bit file system maintained volume-wide unique ID of the sync root under which the placeholder file/directory to be serviced resides.
|
||||||
|
/// </summary>
|
||||||
|
public long SyncRootFileId { get; }
|
||||||
|
|
||||||
|
/// <summary>Points to the opaque blob provided by the sync provider at the sync root registration time.</summary>
|
||||||
|
public SafeAllocatedMemoryHandle SyncRootIdentity { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An opaque handle to the placeholder file/directory to be serviced. The sync provider must pass it back to the CfExecute call in
|
||||||
|
/// order to perform the desired operation on the file/directory.
|
||||||
|
/// </summary>
|
||||||
|
public CF_TRANSFER_KEY TransferKey { get; }
|
||||||
|
|
||||||
|
/// <summary>DOS drive letter of the volume in the form of “X:” where X is the drive letter.</summary>
|
||||||
|
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>
|
||||||
|
public string VolumeGuidName { get; }
|
||||||
|
|
||||||
|
/// <summary>The serial number of the volume.</summary>
|
||||||
|
public uint VolumeSerialNumber { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlaceHolderDirectoryInfo : PlaceholderInfo
|
||||||
|
{
|
||||||
|
/// <summary>The newly created child placeholder directory is considered to have all of its children present locally.</summary>
|
||||||
|
public bool DisableOnDemandPopulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlaceHolderFileInfo : PlaceholderInfo
|
||||||
|
{
|
||||||
|
/// <summary>The size of the file, in bytes.</summary>
|
||||||
|
public long FileSize;
|
||||||
|
|
||||||
|
/// <summary>The newly created placeholder is marked as in-sync. Applicable to both placeholder files and directories.</summary>
|
||||||
|
public bool InSync;
|
||||||
|
|
||||||
|
public static PlaceHolderFileInfo CreateFromFile(FileInfo fileInfo, bool inSync = true, string relativeFilePath = null)
|
||||||
|
{
|
||||||
|
return new PlaceHolderFileInfo
|
||||||
|
{
|
||||||
|
ChangeTime = fileInfo.LastWriteTime,
|
||||||
|
CreationTime = fileInfo.CreationTime,
|
||||||
|
FileAttributes = fileInfo.Attributes,
|
||||||
|
FileSize = fileInfo.Length,
|
||||||
|
LastAccessTime = fileInfo.LastAccessTime,
|
||||||
|
LastWriteTime = fileInfo.LastWriteTime,
|
||||||
|
RelativePath = relativeFilePath ?? fileInfo.FullName,
|
||||||
|
InSync = inSync,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class PlaceholderInfo
|
||||||
|
{
|
||||||
|
/// <summary>The time the file was changed in FILETIME format.</summary>
|
||||||
|
public DateTime ChangeTime;
|
||||||
|
|
||||||
|
/// <summary>The final USN value after create actions are performed.</summary>
|
||||||
|
public int CreateUsn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time the file was created in FILETIME format, which is a 64-bit value representing the number of 100-nanosecond intervals
|
||||||
|
/// since January 1, 1601 (UTC).
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreationTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file attributes. For a list of attributes, see File Attribute Constants. If this is set to 0 in a <c>FILE_BASIC_INFO</c>
|
||||||
|
/// structure passed to SetFileInformationByHandle then none of the attributes are changed.
|
||||||
|
/// </summary>
|
||||||
|
public System.IO.FileAttributes FileAttributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A user mode buffer containing file information supplied by the sync provider. This is required for files (not for directories).
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr FileIdentity;
|
||||||
|
|
||||||
|
/// <summary>Length, in bytes, of the <c>FileIdentity</c>.</summary>
|
||||||
|
public uint FileIdentityLength;
|
||||||
|
|
||||||
|
/// <summary>The time the file was last accessed in FILETIME format.</summary>
|
||||||
|
public DateTime LastAccessTime;
|
||||||
|
|
||||||
|
/// <summary>The time the file was last written to in FILETIME format.</summary>
|
||||||
|
public DateTime LastWriteTime;
|
||||||
|
|
||||||
|
/// <summary>The name of the child placeholder file or directory to be created.</summary>
|
||||||
|
public string RelativePath;
|
||||||
|
|
||||||
|
/// <summary>The result of placeholder creation. On successful creation, the value is: STATUS_OK.</summary>
|
||||||
|
public HRESULT Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CloudSyncProvider : IDisposable
|
||||||
|
{
|
||||||
|
private const string MSSEARCH_INDEX = "SystemIndex";
|
||||||
|
|
||||||
|
private CF_CONNECTION_KEY? key = null;
|
||||||
|
|
||||||
|
public CloudSyncProvider(string syncRootPath, string name, string iconResource = ",0", Version version = null, IEnumerable<(string name, int id)> customProperties = null)
|
||||||
|
{
|
||||||
|
if (name.Contains(" "))
|
||||||
|
throw new ArgumentException("Name cannot have spaces.", nameof(name));
|
||||||
|
if (!Directory.Exists(syncRootPath))
|
||||||
|
Directory.CreateDirectory(syncRootPath);
|
||||||
|
SyncRootPath = syncRootPath;
|
||||||
|
DisplayName = name;
|
||||||
|
IconResource = iconResource;
|
||||||
|
RecycleBinUri = new Uri($"http://{name.ToLower()}.test.com/recyclebin");
|
||||||
|
SyncRootId = $"{name}!{WindowsIdentity.GetCurrent().User}!{Environment.UserName}";
|
||||||
|
Version = version ?? new Version(1, 0);
|
||||||
|
PropertyDefinitions = customProperties?.Select(t => new StorageProviderItemPropertyDefinition { DisplayNameResource = t.name, Id = t.id }).ToList();
|
||||||
|
if (!IsSyncRoot(syncRootPath))
|
||||||
|
Mount();
|
||||||
|
ConnectSyncRootTransferCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
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_FETCHDATA>> FetchData;
|
||||||
|
|
||||||
|
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_DEHYDRATECOMPLETION>> NotifyDehydrateCompletion;
|
||||||
|
|
||||||
|
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_CLOSECOMPLETION>> NotifyFileCloseCompletion;
|
||||||
|
|
||||||
|
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_RENAMECOMPLETION>> NotifyRenameCompletion;
|
||||||
|
|
||||||
|
public event EventHandler<CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_VALIDATEDATA>> ValidateData;
|
||||||
|
|
||||||
|
public string DisplayName { get; }
|
||||||
|
|
||||||
|
public string IconResource { get; }
|
||||||
|
|
||||||
|
public IEnumerable<StorageProviderItemPropertyDefinition> PropertyDefinitions { get; }
|
||||||
|
|
||||||
|
public Uri RecycleBinUri { get; }
|
||||||
|
|
||||||
|
public string SyncRootId { get; }
|
||||||
|
|
||||||
|
public string SyncRootPath { get; }
|
||||||
|
|
||||||
|
public Version Version { get; }
|
||||||
|
|
||||||
|
public static bool IsSyncRoot(string syncRootPath)
|
||||||
|
{
|
||||||
|
using var mem = SafeHGlobalHandle.CreateFromStructure<CF_SYNC_ROOT_BASIC_INFO>();
|
||||||
|
return CfGetSyncRootInfoByPath(syncRootPath, CF_SYNC_ROOT_INFO_CLASS.CF_SYNC_ROOT_INFO_BASIC, mem, mem.Size, out var len).Succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ConvertToPlaceholder(string relativeFilePath, bool inSync = true, bool dehydrate = false, IntPtr fileIdentity = default, uint fileIdentityLength = 0)
|
||||||
|
{
|
||||||
|
using var hFile = CreateFile(Path.Combine(SyncRootPath, relativeFilePath), Kernel32.FileAccess.FILE_READ_ATTRIBUTES, FileShare.Read, null, FileMode.Open, 0);
|
||||||
|
return ConvertToPlaceholder(hFile, inSync, dehydrate, fileIdentity, fileIdentityLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ConvertToPlaceholder(HFILE fileHandle, bool inSync = true, bool dehydrate = false, IntPtr fileIdentity = default, uint fileIdentityLength = 0)
|
||||||
|
{
|
||||||
|
var flags = (inSync ? CF_CONVERT_FLAGS.CF_CONVERT_FLAG_MARK_IN_SYNC : 0) | (dehydrate ? CF_CONVERT_FLAGS.CF_CONVERT_FLAG_DEHYDRATE : 0);
|
||||||
|
CfConvertToPlaceholder(fileHandle, fileIdentity, fileIdentityLength, flags, out var usn).ThrowIfFailed();
|
||||||
|
return usn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CreatePlaceholderFromFile(string relativeFilePath, FileInfo fileInfo, bool inSync = true)
|
||||||
|
{
|
||||||
|
using var pRelativeName = new SafeCoTaskMemString(relativeFilePath);
|
||||||
|
var ph = new PlaceholderInfo[] { PlaceHolderFileInfo.CreateFromFile(fileInfo, inSync, relativeFilePath) };
|
||||||
|
ph[0].FileIdentity = pRelativeName;
|
||||||
|
ph[0].FileIdentityLength = pRelativeName.Size;
|
||||||
|
if (CreatePlaceholders(ph) != 1)
|
||||||
|
throw ph[0].Result.GetException();
|
||||||
|
return ph[0].CreateUsn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CreatePlaceholders(IList<PlaceholderInfo> placeholders)
|
||||||
|
{
|
||||||
|
var entries = new CF_PLACEHOLDER_CREATE_INFO[placeholders.Count];
|
||||||
|
for (int i = 0; i < placeholders.Count; i++)
|
||||||
|
{
|
||||||
|
var ph = placeholders[i];
|
||||||
|
var flags = ph is PlaceHolderFileInfo phf && phf.InSync ? CF_PLACEHOLDER_CREATE_FLAGS.CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC : CF_PLACEHOLDER_CREATE_FLAGS.CF_PLACEHOLDER_CREATE_FLAG_NONE;
|
||||||
|
if (ph is PlaceHolderDirectoryInfo phd && phd.DisableOnDemandPopulation)
|
||||||
|
flags |= CF_PLACEHOLDER_CREATE_FLAGS.CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION;
|
||||||
|
entries[i] = new CF_PLACEHOLDER_CREATE_INFO
|
||||||
|
{
|
||||||
|
FileIdentity = ph.FileIdentity,
|
||||||
|
FileIdentityLength = ph.FileIdentityLength,
|
||||||
|
RelativeFileName = ph.RelativePath,
|
||||||
|
Flags = flags,
|
||||||
|
FsMetadata = new CF_FS_METADATA
|
||||||
|
{
|
||||||
|
FileSize = (ph as PlaceHolderFileInfo)?.FileSize ?? 0,
|
||||||
|
BasicInfo = new FILE_BASIC_INFO
|
||||||
|
{
|
||||||
|
FileAttributes = (FileFlagsAndAttributes)ph.FileAttributes,
|
||||||
|
CreationTime = ph.CreationTime.ToFileTimeStruct(),
|
||||||
|
LastWriteTime = ph.LastWriteTime.ToFileTimeStruct(),
|
||||||
|
LastAccessTime = ph.LastAccessTime.ToFileTimeStruct(),
|
||||||
|
ChangeTime = ph.LastWriteTime.ToFileTimeStruct(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
CfCreatePlaceholders(SyncRootPath, entries, (uint)entries.Length, CF_CREATE_FLAGS.CF_CREATE_FLAG_NONE, out var done);
|
||||||
|
for (int i = 0; i < entries.Length; i++)
|
||||||
|
{
|
||||||
|
placeholders[i].CreateUsn = entries[i].CreateUsn;
|
||||||
|
placeholders[i].Result = entries[i].Result;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// var prop = new StorageProviderItemProperty
|
||||||
|
// {
|
||||||
|
// Id = 1,
|
||||||
|
// Value = "Value1",
|
||||||
|
// // This icon is just for the sample. You should provide your own branded icon here
|
||||||
|
// IconResource = "shell32.dll,-44"
|
||||||
|
// };
|
||||||
|
|
||||||
|
// Console.Write("Applying custom state for {0}\n", relativeFilePath); Utilities.ApplyCustomStateToPlaceholderFile(destPath,
|
||||||
|
// relativeFilePath, prop);
|
||||||
|
|
||||||
|
// if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
|
||||||
|
// {
|
||||||
|
// Create(syncRootPath, relativeFilePath, destPath);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// // to_hresult() will eat the exception if it is a result of check_hresult, otherwise the exception will get rethrown and
|
||||||
|
// // this method will crash out as it should
|
||||||
|
// Console.Write("Failed to set custom state on {0} with {1:X8}\n", relativeFilePath, ex.HResult);
|
||||||
|
// // Eating it here lets other files still get a chance. Not worth crashing the sample, but certainly noteworthy for
|
||||||
|
// // production code
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!key.HasValue) return;
|
||||||
|
CfDisconnectSyncRoot(key.Value).ThrowIfFailed();
|
||||||
|
key = null;
|
||||||
|
UnregisterWithShell();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnCancelFetchData(in CF_CALLBACK_INFO CallbackInfo, in CF_CALLBACK_PARAMETERS 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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
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) =>
|
||||||
|
ValidateData?.Invoke(this, new CloudSyncCallbackArgs<CF_CALLBACK_PARAMETERS_VALIDATEDATA>(CallbackInfo, CallbackParameters));
|
||||||
|
|
||||||
|
private static void AddFolderToSearchIndexer(string folder)
|
||||||
|
{
|
||||||
|
var url = "file:///" + folder;
|
||||||
|
|
||||||
|
using var searchManager = ComReleaserFactory.Create(new ISearchManager());
|
||||||
|
using var searchCatalogManager = ComReleaserFactory.Create(searchManager.Item.GetCatalog(MSSEARCH_INDEX));
|
||||||
|
using var searchCrawlScopeManager = ComReleaserFactory.Create(searchCatalogManager.Item.GetCrawlScopeManager());
|
||||||
|
searchCrawlScopeManager.Item.AddDefaultScopeRule(url, true, FOLLOW_FLAGS.FF_INDEXCOMPLEXURLS);
|
||||||
|
searchCrawlScopeManager.Item.SaveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConnectSyncRootTransferCallbacks()
|
||||||
|
{
|
||||||
|
CF_CALLBACK_REGISTRATION[] callbackTable =
|
||||||
|
{
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_CANCEL_FETCH_DATA, Callback = OnCancelFetchData },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_CANCEL_FETCH_PLACEHOLDERS, Callback = OnCancelFetchPlaceholders },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_FETCH_DATA, Callback = OnFetchData },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS, Callback = OnFetchPlaceholders },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_DEHYDRATE, Callback = OnNotifyDehydrate },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_DEHYDRATE_COMPLETION, Callback = OnNotifyDehydrateCompletion },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_DELETE, Callback = OnNotifyDelete },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_DELETE_COMPLETION, Callback = OnNotifyDeleteCompletion },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_FILE_CLOSE_COMPLETION, Callback = OnNotifyFileCloseCompletion },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_FILE_OPEN_COMPLETION, Callback = OnNotifyFileOpenCompletion },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_RENAME, Callback = OnNotifyRename },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_NOTIFY_RENAME_COMPLETION, Callback = OnNotifyRenameCompletion },
|
||||||
|
new CF_CALLBACK_REGISTRATION { Type = CF_CALLBACK_TYPE.CF_CALLBACK_TYPE_VALIDATE_DATA, Callback = OnValidateData },
|
||||||
|
CF_CALLBACK_REGISTRATION.CF_CALLBACK_REGISTRATION_END
|
||||||
|
};
|
||||||
|
|
||||||
|
CfConnectSyncRoot(SyncRootPath, callbackTable, default, CF_CONNECT_FLAGS.CF_CONNECT_FLAG_NONE, out var ckey).ThrowIfFailed();
|
||||||
|
key = ckey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Mount()
|
||||||
|
{
|
||||||
|
AddFolderToSearchIndexer(SyncRootPath);
|
||||||
|
RegisterWithShell().Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RegisterWithShell()
|
||||||
|
{
|
||||||
|
var info = new StorageProviderSyncRootInfo
|
||||||
|
{
|
||||||
|
Context = CryptographicBuffer.ConvertStringToBinary(SyncRootId, BinaryStringEncoding.Utf8),
|
||||||
|
DisplayNameResource = DisplayName,
|
||||||
|
HardlinkPolicy = StorageProviderHardlinkPolicy.None,
|
||||||
|
HydrationPolicy = StorageProviderHydrationPolicy.Full,
|
||||||
|
HydrationPolicyModifier = StorageProviderHydrationPolicyModifier.None,
|
||||||
|
IconResource = IconResource,
|
||||||
|
Id = SyncRootId,
|
||||||
|
InSyncPolicy = StorageProviderInSyncPolicy.FileCreationTime | StorageProviderInSyncPolicy.DirectoryCreationTime,
|
||||||
|
Path = await StorageFolder.GetFolderFromPathAsync(SyncRootPath),
|
||||||
|
PopulationPolicy = StorageProviderPopulationPolicy.AlwaysFull,
|
||||||
|
RecycleBinUri = RecycleBinUri,
|
||||||
|
ShowSiblingsAsGroup = false,
|
||||||
|
Version = Version.ToString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (PropertyDefinitions != null)
|
||||||
|
foreach (var pd in PropertyDefinitions)
|
||||||
|
info.StorageProviderItemPropertyDefinitions.Add(pd);
|
||||||
|
|
||||||
|
StorageProviderSyncRootManager.Register(info);
|
||||||
|
|
||||||
|
// Give the cache some time to invalidate
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnregisterWithShell()
|
||||||
|
{
|
||||||
|
StorageProviderSyncRootManager.Unregister(SyncRootId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue