using System.Runtime.InteropServices; using Explorer.Domain; namespace Explorer.Windows; public static partial class CloudFilesNative { public const uint PlaceholderNone = 0; public const uint Placeholder = 0x1; public const uint PlaceholderSyncRoot = 0x2; public const uint PlaceholderInSync = 0x8; public const uint PlaceholderPartial = 0x10; public const uint PlaceholderPartiallyOnDisk = 0x20; public const uint PlaceholderInvalid = 0xFFFFFFFF; public const int PinUnspecified = 0; public const int PinPinned = 1; public const int PinUnpinned = 2; public const int PinExcluded = 3; public const int PinInherit = 4; public static nint OpenNoRecall(string path) => NativeMethods.CreateFile( PathRules.ToExtended(path), NativeMethods.FileReadAttributes, NativeMethods.FileShareRead | NativeMethods.FileShareWrite | NativeMethods.FileShareDelete, 0, NativeMethods.OpenExisting, NativeMethods.SafeOpenFlags, 0); public static bool IsInvalid(nint handle) => handle == nint.Zero || handle == new nint(-1); public static long? TryGetAllocatedSize(string path) { var handle = OpenNoRecall(path); if (IsInvalid(handle)) { return null; } try { return TryGetAllocatedSize(handle); } finally { NativeMethods.CloseHandle(handle); } } public static long? TryGetAllocatedSize(nint handle) { var size = Marshal.SizeOf(); var buffer = Marshal.AllocHGlobal(size); try { if (!NativeMethods.GetFileInformationByHandleEx(handle, NativeMethods.FileStandardInfo, buffer, (uint)size)) { return null; } var info = Marshal.PtrToStructure(buffer); return info.AllocationSize; } catch { return null; } finally { Marshal.FreeHGlobal(buffer); } } public static uint? TryGetPlaceholderState(int attributes, int reparseTag) { try { return CfGetPlaceholderStateFromAttributeTag((uint)attributes, (uint)reparseTag); } catch (DllNotFoundException) { return null; } catch (EntryPointNotFoundException) { return null; } } public static bool TrySetPinState(string path, int pinState) { var handle = OpenNoRecall(path); if (IsInvalid(handle)) { return false; } try { return CfSetPinState(handle, pinState, 0, nint.Zero) == 0; } catch (DllNotFoundException) { return false; } catch (EntryPointNotFoundException) { return false; } finally { NativeMethods.CloseHandle(handle); } } public static bool IsCloudSyncRoot(string path) { try { uint returned = 0; var hr = CfGetSyncRootInfoByPath(path, 0, nint.Zero, 0, ref returned); const int insufficientBuffer = unchecked((int)0x8007007A); return hr == 0 || (hr == insufficientBuffer && returned > 0); } catch (DllNotFoundException) { return false; } catch (EntryPointNotFoundException) { return false; } catch { return false; } } [LibraryImport("cldapi.dll")] private static partial uint CfGetPlaceholderStateFromAttributeTag(uint fileAttributes, uint reparseTag); [DllImport("cldapi.dll", ExactSpelling = true)] private static extern int CfSetPinState(nint fileHandle, int pinState, uint pinFlags, nint overlapped); [DllImport("cldapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int CfGetSyncRootInfoByPath(string filePath, int infoClass, nint infoBuffer, uint infoBufferLength, ref uint returnedLength); [StructLayout(LayoutKind.Sequential)] private struct FileStandardInfo { public long AllocationSize; public long EndOfFile; public uint NumberOfLinks; public byte DeletePending; public byte Directory; } }