How can I check local OneDrive folder is in sync?

前端 未结 2 711
一向
一向 2021-01-05 07:37

I need to be able to check if the local OneDrive folder is in sync/up to date.

Can I check this by looking at any of the file/folder properties(in C# code) Without u

相关标签:
2条回答
  • 2021-01-05 08:09

    I was stuck with that and tought to check the main folder Icon.

    EDITED

    The point is to extract the synced folder icon and get the overlay CLSID.

    You first need a class to extract the info you need :

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    
    
    namespace MyApp.Classes
    {
        public class ExtractIconInfo
        {
            [Flags]
            private enum SHGFI : uint
            {
                SHGFI_ICON = 0x000000100,
                SHGFI_DISPLAYNAME = 0x000000200,
                SHGFI_TYPENAME = 0x000000400,
                SHGFI_ATTRIBUTES = 0x000000800,
                SHGFI_ICONLOCATION = 0x000001000,
                SHGFI_EXETYPE = 0x000002000,
                SHGFI_SYSICONINDEX = 0x000004000,
                SHGFI_LINKOVERLAY = 0x000008000,
                SHGFI_SELECTED = 0x000010000,
                SHGFI_ATTR_SPECIFIED = 0x000020000,
                SHGFI_LARGEICON = 0x000000000,
                SHGFI_SMALLICON = 0x000000001,
                SHGFI_OPENICON = 0x000000002,
                SHGFI_SHELLICONSIZE = 0x000000004,
                SHGFI_PIDL = 0x000000008,
                SHGFI_USEFILEATTRIBUTES = 0x000000010,
                SHGFI_ADDOVERLAYS = 0x000000020,
                SHGFI_OVERLAYINDEX = 0x000000040
            }
    
            [Flags]
            private enum FileAttributes : uint
            {
                Readonly = 0x00000001,
                Hidden = 0x00000002,
                System = 0x00000004,
                Directory = 0x00000010,
                Archive = 0x00000020,
                Device = 0x00000040,
                Normal = 0x00000080,
                Temporary = 0x00000100,
                SparseFile = 0x00000200,
                ReparsePoint = 0x00000400,
                Compressed = 0x00000800,
                Offline = 0x00001000,
                NotContentIndexed = 0x00002000,
                Encrypted = 0x00004000,
                Virtual = 0x00010000
            }
    
            [Flags]
            public enum ISIOI : uint
            {
                ISIOI_ICONFILE = 0x00000001,
                ISIOI_ICONINDEX = 0x00000002
            }
    
            private SortedDictionary<string, Guid> ShellIconOverlayIdentifiers;
    
            public string IconName { get; private set; }
            public Icon Icon { get; private set; }
            public int IconOverlayIndex { get; private set; }
            public Guid IconOverlayGuid { get; private set; }
    
            public ExtractIconInfo(FileInfo fi)
            {
                ExtractIcon(fi.FullName, false);
            }
            public ExtractIconInfo(DirectoryInfo di)
            {
                ExtractIcon(di.FullName, true);
            }
            public ExtractIconInfo(string path, bool isFolder)
            {
                ExtractIcon(path, isFolder);
            }
    
            [ComVisible(false)]
            [ComImport]
            [Guid("0C6C4200-C589-11D0-999A-00C04FD655E1")]
            [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            private interface IShellIconOverlayIdentifier
            {
                [PreserveSig]
                int IsMemberOf([MarshalAs(UnmanagedType.LPWStr)] string path, uint attributes);
                [PreserveSig]
                int GetOverlayInfo([MarshalAs(UnmanagedType.LPWStr)] string iconFileBuffer, int iconFileBufferSize, out int iconIndex, out uint flags);
                [PreserveSig]
                int GetPriority(out int priority);
            }
    
            [StructLayout(LayoutKind.Sequential)]
            private struct SHFILEINFO
            {
                internal IntPtr hIcon;
                internal int iIcon;
                internal uint dwAttributes;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                internal string szDisplayName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
                internal string szTypeName;
            };
    
            [DllImport("shell32.dll")]
            private static extern IntPtr SHGetFileInfo(
                string pszPath,
                uint dwFileAttributes,
                ref SHFILEINFO psfi,
                uint cbSizeFileInfo,
                uint uFlags
            );
    
            [DllImport("shell32.dll")]
            private static extern int SHGetIconOverlayIndex(
                string pszIconPath,
                int iIconIndex
            );
    
            [DllImport("user32.dll")]
            public static extern int DestroyIcon(IntPtr hIcon);
    
            private void ExtractIcon(string path, bool isFolder)
            {
                SHFILEINFO shIconInfo = new SHFILEINFO();
                SHGetFileInfo(path, isFolder ? (uint)FileAttributes.Directory : (uint)FileAttributes.Normal, ref shIconInfo, (uint)Marshal.SizeOf(shIconInfo), (uint)SHGFI.SHGFI_ICON | (uint)SHGFI.SHGFI_LARGEICON | (uint)SHGFI.SHGFI_DISPLAYNAME | (uint)SHGFI.SHGFI_ADDOVERLAYS | (uint)SHGFI.SHGFI_OVERLAYINDEX);
                Icon = (Icon)Icon.FromHandle(shIconInfo.hIcon).Clone();
                IconName = shIconInfo.szDisplayName;
                IconOverlayIndex = (shIconInfo.iIcon >> 24) & 0xFF;
                GetOverlayIconGuid();
    
                DestroyIcon(shIconInfo.hIcon);
            }
    
            private void GetOverlayIconGuid()
            {
                IconOverlayGuid = Guid.Empty;
                GetRegistryShellIconOverlayIdentifiers();
                foreach (string key in ShellIconOverlayIdentifiers.Keys)
                {
                    string AIconFileName = string.Empty;
                    int AIconIndex = 0;
                    Guid value = ShellIconOverlayIdentifiers[key];
                    GetOverlayIconInfo(value, out AIconFileName, out AIconIndex);
                    if (SHGetIconOverlayIndex(AIconFileName, AIconIndex) == IconOverlayIndex)
                        IconOverlayGuid = value;
                }
            }
    
            private void GetOverlayIconInfo(Guid CLSID, out string path, out int index)
            {
                try
                {
                    path = new string(' ', 256);
                    uint flags = 0;
                    IShellIconOverlayIdentifier SHIOI = Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID, true), true) as IShellIconOverlayIdentifier;
                    SHIOI.GetOverlayInfo(path, path.Length, out index, out flags);
                    Marshal.ReleaseComObject(SHIOI);
    
                    if ((flags & (uint)ISIOI.ISIOI_ICONFILE) != 0)
                    {
                        if ((flags & (uint)ISIOI.ISIOI_ICONINDEX) == 0) index = 0;
                    }
                    else
                    {
                        path = string.Empty;
                        index = 0;
                    }
                    path = path.Substring(0, path.IndexOf('\0'));
                }
                catch
                {
                    path = string.Empty;
                    index = 0;
                }
            }
    
            private void GetRegistryShellIconOverlayIdentifiers()
            {
                ShellIconOverlayIdentifiers = new SortedDictionary<string, Guid>();
    
                using (RegistryKey key32 = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, Environment.MachineName, RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers"))
                    foreach (string subKey in key32.GetSubKeyNames())
                    {
                        Guid value = Guid.Parse((string)key32.OpenSubKey(subKey).GetValue(null));
                        if (!ShellIconOverlayIdentifiers.ContainsKey(subKey))
                            ShellIconOverlayIdentifiers.Add(subKey, value);
                    }
    
                using (RegistryKey key64 = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, Environment.MachineName, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers"))
                    foreach (string subKey in key64.GetSubKeyNames())
                    {
                        Guid value = Guid.Parse((string)key64.OpenSubKey(subKey).GetValue(null));
                        if (!ShellIconOverlayIdentifiers.ContainsKey(subKey))
                            ShellIconOverlayIdentifiers.Add(subKey, value);
                    }
            }
        }
    }
    

    The relevant info here is IconOverlayGuid.

    Then compare :

    public enum SyncStatus { Off, Unknown, Syncing, Synced, SharedSyncing, SharedSynced, Error }
    
    private SyncStatus CheckIfSync(DirectoryInfo di)
    {
        ExtractIconInfo IcoInfo = new ExtractIconInfo(di);
        if (IcoInfo != null)
        {
            if (IcoInfo.IconOverlayGuid == Guid.Empty) return SyncStatus.Off;
            else if (IcoInfo.IconOverlayGuid == new Guid("{BBACC218-34EA-4666-9D7A-C78F2274A524}")) return SyncStatus.Error;
            else if (IcoInfo.IconOverlayGuid == new Guid("{F241C880-6982-4CE5-8CF7-7085BA96DA5A}")) return SyncStatus.Synced;
            else if (IcoInfo.IconOverlayGuid == new Guid("{A0396A93-DC06-4AEF-BEE9-95FFCCAEF20E}")) return SyncStatus.Syncing;
            else if (IcoInfo.IconOverlayGuid == new Guid("{5AB7172C-9C11-405C-8DD5-AF20F3606282}")) return SyncStatus.SharedSynced;
            else if (IcoInfo.IconOverlayGuid == new Guid("{A78ED123-AB77-406B-9962-2A5D9D2F7F30}")) return SyncStatus.SharedSyncing;
            else return SyncStatus.Unknown;
        }
        else return SyncStatus.Unknown;
    }
    

    The Overlay Icons are stored in FileSyncShell.dll. Their CLSID are stored in the registry : HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers and HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers.

    • OneDrive1 : Sync in error
    • OneDrive2 : Synced Shared
    • OneDrive3 : Syncing Shared
    • OneDrive4 : Synced
    • OneDrive5 : Syncing

    Hope that helps !

    (I spent way too much time on that one, but I learned a lot !)

    0 讨论(0)
  • 2021-01-05 08:09

    Probably comparing the LastModifiedDateTime.

    ...Drive.Root.ItemWithPath(file).Request().GetAsync()).FileSystemInfo.LastModifiedDateTime
    
    0 讨论(0)
提交回复
热议问题