File: MS\Internal\AppModel\ShellProvider.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
// Interfaces and enums are taken from ShObjIdl.idl
 
namespace MS.Internal.AppModel
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using System.Security;
    using System.Text;
    using MS.Win32;
    using MS.Internal.Interop;
 
    // Some COM interfaces and Win32 structures are already declared in the framework.
    // Interesting ones to remember in System.Runtime.InteropServices.ComTypes are:
    using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
    using IPersistFile = System.Runtime.InteropServices.ComTypes.IPersistFile;
    using IStream = System.Runtime.InteropServices.ComTypes.IStream;
 
    #region Structs
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct COMDLG_FILTERSPEC
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pszName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pszSpec;
    }
 
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    internal struct PKEY
    {
        /// <summary>fmtid</summary>
        private readonly Guid _fmtid;
        /// <summary>pid</summary>
        private readonly uint _pid;
 
        private PKEY(Guid fmtid, uint pid)
        {
            _fmtid = fmtid;
            _pid = pid;
        }
 
        /// <summary>PKEY_Title</summary>
        public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2);
        /// <summary>PKEY_AppUserModel_ID</summary>
        public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
        /// <summary>PKEY_AppUserModel_IsDestListSeparator</summary>
        public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6);
        /// <summary>PKEY_AppUserModel_RelaunchCommand</summary>
        public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2);
        /// <summary>PKEY_AppUserModel_RelaunchDisplayNameResource</summary>
        public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4);
        /// <summary>PKEY_AppUserModel_RelaunchIconResource</summary>
        public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3);
    }
 
    [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
    internal struct THUMBBUTTON
    {
        /// <summary>
        /// WPARAM value for a THUMBBUTTON being clicked.
        /// </summary>
        public const int THBN_CLICKED = 0x1800;
 
        public THB dwMask;
        public uint iId;
        public uint iBitmap;
        public IntPtr hIcon;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szTip;
        public THBF dwFlags;
    }
 
    #endregion
 
    #region Interfaces
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.EnumIdList),
    ]
    internal interface IEnumIDList
    {
        [PreserveSig()]
        HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched);
        [PreserveSig()]
        HRESULT Skip(uint celt);
        void Reset();
        [return: MarshalAs(UnmanagedType.Interface)]
        IEnumIDList Clone();
    }
 
    /// <summary>Unknown Object Array</summary>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ObjectArray),
    ]
    internal interface IObjectArray
    {
        uint GetCount();
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object GetAt([In] uint uiIndex, [In] ref Guid riid);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ObjectArray),
    ]
    interface IObjectCollection : IObjectArray
    {
        #region IObjectArray redeclarations
        new uint GetCount();
        [return: MarshalAs(UnmanagedType.IUnknown)]
        new object GetAt([In] uint uiIndex, [In] ref Guid riid);
        #endregion
 
        void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk);
        void AddFromArray(IObjectArray poaSource);
        void RemoveObjectAt(uint uiIndex);
        void Clear();
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.PropertyStore)
    ]
    internal interface IPropertyStore
    {
        uint GetCount();
        PKEY GetAt(uint iProp);
 
        void GetValue([In] ref PKEY pkey, [In, Out] PROPVARIANT pv);
 
        void SetValue([In] ref PKEY pkey, PROPVARIANT pv);
 
        void Commit();
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ShellFolder),
    ]
    internal interface IShellFolder
    {
        void ParseDisplayName(
            IntPtr hwnd,
            IBindCtx pbc,
            [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
            [In, Out] ref int pchEaten,
            out IntPtr ppidl,
            [In, Out] ref uint pdwAttributes);
 
        IEnumIDList EnumObjects(
            IntPtr hwnd,
            SHCONTF grfFlags);
 
        // returns an instance of a sub-folder which is specified by the IDList (pidl).
        // IShellFolder or derived interfaces
        [return: MarshalAs(UnmanagedType.Interface)]
        object BindToObject(
            IntPtr pidl,
            IBindCtx pbc,
            [In] ref Guid riid);
 
        // produces the same result as BindToObject()
        [return: MarshalAs(UnmanagedType.Interface)]
        object BindToStorage(IntPtr pidl, IBindCtx pbc, [In] ref Guid riid);
 
        // compares two IDLists and returns the result. The shell
        // explorer always passes 0 as lParam, which indicates 'sort by name'.
        // It should return 0 (as CODE of the scode), if two id indicates the
        // same object; negative value if pidl1 should be placed before pidl2;
        // positive value if pidl2 should be placed before pidl1.
        // use the macro ResultFromShort() to extract the result comparison
        // it deals with the casting and type conversion issues for you
        [PreserveSig]
        HRESULT CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
 
        // creates a view object of the folder itself. The view
        // object is a difference instance from the shell folder object.
        // 'hwndOwner' can be used  as the owner window of its dialog box or
        // menu during the lifetime of the view object.
        // This member function should always create a new
        // instance which has only one reference count. The explorer may create
        // more than one instances of view object from one shell folder object
        // and treat them as separate instances.
        // returns IShellView derived interface
        [return: MarshalAs(UnmanagedType.Interface)]
        object CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid);
 
        // returns the attributes of specified objects in that
        // folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only
        // simple IDLists. The explorer initializes *prgfInOut with a set of
        // flags to be evaluated. The shell folder may optimize the operation
        // by not returning unspecified flags.
        void GetAttributesOf(
            uint cidl,
            IntPtr apidl,
            [In, Out] ref SFGAO rgfInOut);
 
        // creates a UI object to be used for specified objects.
        // The shell explorer passes either IID_IDataObject (for transfer operation)
        // or IID_IContextMenu (for context menu operation) as riid
        // and many other interfaces
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetUIObjectOf(
            IntPtr hwndOwner,
            uint cidl,
            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 1)] IntPtr apidl,
            [In] ref Guid riid,
            [In, Out] ref uint rgfReserved);
 
        // returns the display name of the specified object.
        // If the ID contains the display name (in the locale character set),
        // it returns the offset to the name. Otherwise, it returns a pointer
        // to the display name string (UNICODE), which is allocated by the
        // task allocator, or fills in a buffer.
        // use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different
        // forms of the STRRET structure
        void GetDisplayNameOf(IntPtr pidl, SHGDN uFlags, out IntPtr pName);
 
        // sets the display name of the specified object.
        // If it changes the ID as well, it returns the new ID which is
        // alocated by the task allocator.
        void SetNameOf(IntPtr hwnd,
            IntPtr pidl,
            [MarshalAs(UnmanagedType.LPWStr)] string pszName,
            SHGDN uFlags,
            out IntPtr ppidlOut);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ShellItem),
    ]
    internal interface IShellItem
    {
        [return: MarshalAs(UnmanagedType.Interface)]
        object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid);
 
        IShellItem GetParent();
 
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetDisplayName(SIGDN sigdnName);
 
        uint GetAttributes(SFGAO sfgaoMask);
 
        int Compare(IShellItem psi, SICHINT hint);
    }
 
    /// <summary>
    /// Shell Namespace helper 2
    /// </summary>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ShellItem2),
    ]
    interface IShellItem2 : IShellItem
    {
        #region IShellItem redeclarations
        [return: MarshalAs(UnmanagedType.Interface)]
        new object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid);
        new IShellItem GetParent();
        [return: MarshalAs(UnmanagedType.LPWStr)]
        new string GetDisplayName(SIGDN sigdnName);
        new SFGAO GetAttributes(SFGAO sfgaoMask);
        new int Compare(IShellItem psi, SICHINT hint);
        #endregion
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyStore(
            GPS flags,
            [In] ref Guid riid);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyStoreWithCreateObject(
            GPS flags,
            [MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject,   // factory for low-rights creation of type ICreateObject
            [In] ref Guid riid);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyStoreForKeys(
            IntPtr rgKeys,
            uint cKeys,
            GPS flags,
            [In] ref Guid riid);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyDescriptionList(
            IntPtr keyType,
            [In] ref Guid riid);
 
        // Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist.
        void Update(IBindCtx pbc);
 
        void GetProperty(IntPtr key, [In, Out] PROPVARIANT pv);
 
        Guid GetCLSID(IntPtr key);
 
        FILETIME GetFileTime(IntPtr key);
 
        int GetInt32(IntPtr key);
 
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetString(IntPtr key);
 
        uint GetUInt32(IntPtr key);
 
        ulong GetUInt64(IntPtr key);
 
        [return: MarshalAs(UnmanagedType.Bool)]
        bool GetBool(IntPtr key);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ShellItemArray),
    ]
    internal interface IShellItemArray
    {
        [return: MarshalAs(UnmanagedType.Interface)]
        object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyStore(int flags, [In] ref Guid riid);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid);
 
        uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask);
 
        uint GetCount();
 
        IShellItem GetItemAt(uint dwIndex);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object EnumItems();
    }
 
    [
        ComImport,
        InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ShellLink),
    ]
    internal interface IShellLinkW
    {
        void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATAW pfd, SLGP fFlags);
        IntPtr GetIDList();
        void SetIDList(IntPtr pidl);
        void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName);
        void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
        void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
        void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
        void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
        short GetHotKey();
        void SetHotKey(short wHotKey);
        uint GetShowCmd();
        void SetShowCmd(uint iShowCmd);
        void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
        void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
        void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
        void Resolve(IntPtr hwnd, uint fFlags);
        void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.FileDialogEvents),
    ]
    internal interface IFileDialogEvents
    {
        [PreserveSig]
        HRESULT OnFileOk(IFileDialog pfd);
 
        [PreserveSig]
        HRESULT OnFolderChanging(IFileDialog pfd, IShellItem psiFolder);
 
        [PreserveSig]
        HRESULT OnFolderChange(IFileDialog pfd);
 
        [PreserveSig]
        HRESULT OnSelectionChange(IFileDialog pfd);
 
        [PreserveSig]
        HRESULT OnShareViolation(IFileDialog pfd, IShellItem psi, out FDESVR pResponse);
 
        [PreserveSig]
        HRESULT OnTypeChange(IFileDialog pfd);
 
        [PreserveSig]
        HRESULT OnOverwrite(IFileDialog pfd, IShellItem psi, out FDEOR pResponse);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ModalWindow),
    ]
    internal interface IModalWindow
    {
        [PreserveSig]
        HRESULT Show(IntPtr parent);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.FileDialog),
    ]
    internal interface IFileDialog : IModalWindow
    {
        #region IModalWindow redeclarations
        [PreserveSig]
        new HRESULT Show(IntPtr parent);
        #endregion
 
        void SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec);
 
        void SetFileTypeIndex(uint iFileType);
 
        uint GetFileTypeIndex();
 
        uint Advise(IFileDialogEvents pfde);
 
        void Unadvise(uint dwCookie);
 
        void SetOptions(FOS fos);
 
        FOS GetOptions();
 
        void SetDefaultFolder(IShellItem psi);
 
        void SetFolder(IShellItem psi);
 
        IShellItem GetFolder();
 
        IShellItem GetCurrentSelection();
 
        void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
 
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetFileName();
 
        void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
 
        void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
 
        void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
 
        IShellItem GetResult();
 
        void AddPlace(IShellItem psi, FDAP alignment);
 
        void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
 
        void Close([MarshalAs(UnmanagedType.Error)] int hr);
 
        void SetClientGuid([In] ref Guid guid);
 
        void ClearClientData();
 
        void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.FileDialog2),
    ]
    internal interface IFileDialog2 : IFileDialog
    {
        #region IFileDialog redeclarations
        #region IModalWindow redeclarations
        [PreserveSig]
        new HRESULT Show(IntPtr parent);
        #endregion
 
        new void SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec);
 
        new void SetFileTypeIndex(uint iFileType);
 
        new uint GetFileTypeIndex();
 
        new uint Advise(IFileDialogEvents pfde);
 
        new void Unadvise(uint dwCookie);
 
        new void SetOptions(FOS fos);
 
        new FOS GetOptions();
 
        new void SetDefaultFolder(IShellItem psi);
 
        new void SetFolder(IShellItem psi);
 
        new IShellItem GetFolder();
 
        new IShellItem GetCurrentSelection();
 
        new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
 
        [return: MarshalAs(UnmanagedType.LPWStr)]
        new string GetFileName();
 
        new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
 
        new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
 
        new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
 
        new IShellItem GetResult();
 
        new void AddPlace(IShellItem psi, FDAP alignment);
 
        new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
 
        new void Close([MarshalAs(UnmanagedType.Error)] int hr);
 
        new void SetClientGuid([In] ref Guid guid);
 
        new void ClearClientData();
 
        new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
        #endregion
 
        void SetCancelButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
 
        void SetNavigationRoot(IShellItem psi);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.FileOpenDialog),
    ]
    internal interface IFileOpenDialog : IFileDialog
    {
        #region IFileDialog redeclarations
 
        #region IModalDialog redeclarations
        [PreserveSig]
        new HRESULT Show(IntPtr parent);
        #endregion
 
        new void SetFileTypes(uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);
        new void SetFileTypeIndex(uint iFileType);
        new uint GetFileTypeIndex();
        new uint Advise(IFileDialogEvents pfde);
        new void Unadvise(uint dwCookie);
        new void SetOptions(FOS fos);
        new FOS GetOptions();
        new void SetDefaultFolder(IShellItem psi);
        new void SetFolder(IShellItem psi);
        new IShellItem GetFolder();
        new IShellItem GetCurrentSelection();
        new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        [return: MarshalAs(UnmanagedType.LPWStr)]
        new void GetFileName();
        new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
        new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
        new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
        new IShellItem GetResult();
        new void AddPlace(IShellItem psi, FDAP fdcp);
        new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
        new void Close([MarshalAs(UnmanagedType.Error)] int hr);
        new void SetClientGuid([In] ref Guid guid);
        new void ClearClientData();
        new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
 
        #endregion
 
        IShellItemArray GetResults();
 
        IShellItemArray GetSelectedItems();
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.FileSaveDialog),
    ]
    internal interface IFileSaveDialog : IFileDialog
    {
        #region IFileDialog redeclarations
 
        #region IModalDialog redeclarations
        [PreserveSig]
        new HRESULT Show(IntPtr parent);
        #endregion
 
        new void SetFileTypes(uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);
        new void SetFileTypeIndex(uint iFileType);
        new uint GetFileTypeIndex();
        new uint Advise(IFileDialogEvents pfde);
        new void Unadvise(uint dwCookie);
        new void SetOptions(FOS fos);
        new FOS GetOptions();
        new void SetDefaultFolder(IShellItem psi);
        new void SetFolder(IShellItem psi);
        new IShellItem GetFolder();
        new IShellItem GetCurrentSelection();
        new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        [return: MarshalAs(UnmanagedType.LPWStr)]
        new void GetFileName();
        new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
        new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
        new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
        new IShellItem GetResult();
        new void AddPlace(IShellItem psi, FDAP fdcp);
        new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
        new void Close([MarshalAs(UnmanagedType.Error)] int hr);
        new void SetClientGuid([In] ref Guid guid);
        new void ClearClientData();
        new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
 
        #endregion
 
        void SetSaveAsItem(IShellItem psi);
 
        void SetProperties([In, MarshalAs(UnmanagedType.Interface)] object pStore);
 
        void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] object pList, [In] int fAppendDefault);
 
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetProperties();
 
        void ApplyProperties(IShellItem psi, [MarshalAs(UnmanagedType.Interface)] object pStore, [In] ref IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] object pSink);
    }
 
    // Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document.
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ApplicationDestinations)
    ]
    internal interface IApplicationDestinations
    {
        // Set the App User Model ID for the application removing destinations from its list.  If an AppID is not provided 
        // via this method, the system will use a heuristically determined ID.  This method must be called before
        // RemoveDestination or RemoveAllDestinations.
        void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
 
        // Remove an IShellItem or an IShellLink from the automatic destination list
        void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk);
 
        // Clear the frequent and recent destination lists for this application.
        void RemoveAllDestinations();
    }
 
    /// <summary>
    /// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs
    /// </summary>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ApplicationDocumentLists)
    ]
    internal interface IApplicationDocumentLists
    {
        /// <summary>
        /// Set the App User Model ID for the application retrieving this list.  If an AppID is not provided via this method,
        /// the system will use a heuristically determined ID.  This method must be called before GetList. 
        /// </summary>
        /// <param name="pszAppID">App Id.</param>
        void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
 
        /// <summary>
        /// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks. 
        /// Items may appear in both the frequent and recent lists.  
        /// </summary>
        /// <param name="listtype">Which of the known list types to retrieve</param>
        /// <param name="cItemsDesired">The number of items desired.</param>
        /// <param name="riid">The interface Id that the return value should be queried for.</param>
        /// <returns>A COM object based on the IID passed for the riid parameter.</returns>
        [return: MarshalAs(UnmanagedType.IUnknown)]
        object GetList(ADLT listtype, uint cItemsDesired, [In] ref Guid riid);
    }
 
    // Custom Destination List
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.CustomDestinationList)
    ]
    internal interface ICustomDestinationList
    {
        void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
 
        // Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations
        [return: MarshalAs(UnmanagedType.Interface)]
        object BeginList(out uint pcMaxSlots, [In] ref Guid riid);
 
        // PreserveSig because this will return custom errors when attempting to add unregistered ShellItems.
        // Can't readily detect that case without just trying to append it.
        [PreserveSig]
        HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa);
        void AppendKnownCategory(KDC category);
        [PreserveSig]
        HRESULT AddUserTasks(IObjectArray poa);
        void CommitList();
 
        // Retrieve IObjectCollection of IShellItems
        [return: MarshalAs(UnmanagedType.Interface)]
        object GetRemovedDestinations([In] ref Guid riid);
        void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
        void AbortList();
    }
 
    /// <summary>
    /// Provides access to the App User Model ID on objects supporting this value.
    /// </summary>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ObjectWithAppUserModelId)
    ]
    internal interface IObjectWithAppUserModelId
    {
        void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetAppID();
    };
 
    /// <summary>
    /// Provides access to the ProgID associated with an object 
    /// </summary>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.ObjectWithProgId)
    ]
    internal interface IObjectWithProgId
    {
        void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID);
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetProgID();
    };
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.TaskbarList),
    ]
    internal interface ITaskbarList
    {
        /// <summary>
        /// This function must be called first to validate use of other members.
        /// </summary>
        [PreserveSig]
        HRESULT HrInit();
 
        /// <summary>
        /// This function adds a tab for hwnd to the taskbar.
        /// </summary>
        /// <param name="hwnd">The HWND for which to add the tab.</param>
        void AddTab(IntPtr hwnd);
 
        /// <summary>
        /// This function deletes a tab for hwnd from the taskbar.
        /// </summary>
        /// <param name="hwnd">The HWND for which the tab is to be deleted.</param>
        void DeleteTab(IntPtr hwnd);
 
        /// <summary>
        /// This function activates the tab associated with hwnd on the taskbar.
        /// </summary>
        /// <param name="hwnd">The HWND for which the tab is to be activated.</param>
        void ActivateTab(IntPtr hwnd);
 
        /// <summary>
        /// This function marks hwnd in the taskbar as the active tab.
        /// </summary>
        /// <param name="hwnd">The HWND to activate.</param>
        void SetActiveAlt(IntPtr hwnd);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.TaskbarList2),
    ]
    internal interface ITaskbarList2 : ITaskbarList
    {
        #region ITaskbarList redeclaration
        new void HrInit();
        new void AddTab(IntPtr hwnd);
        new void DeleteTab(IntPtr hwnd);
        new void ActivateTab(IntPtr hwnd);
        new void SetActiveAlt(IntPtr hwnd);
        #endregion
 
        /// <summary>
        /// Marks a window as full-screen.
        /// </summary>
        /// <param name="hwnd">The handle of the window to be marked.</param>
        /// <param name="fFullscreen">A Boolean value marking the desired full-screen status of the window.</param>
        /// <remarks>
        /// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar
        /// is moved to the bottom of the z-order when this window is active.  Setting the value of fFullscreen to false
        /// removes the full-screen marking, but <i>does not</i> cause the Shell to treat the window as though it were
        /// definitely not full-screen.  With a false fFullscreen value, the Shell depends on its automatic detection facility
        /// to specify how the window should be treated, possibly still flagging the window as full-screen.
        /// </remarks>
        void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
    }
 
    /// <remarks>
    /// Methods on this interface are marked as PreserveSig because the implementation inconsistently
    /// surfaces errors in Explorer.  Many of these methods are implemented by posting messages
    /// to the desktop window, but if explorer is not running or currently busy then we get back
    /// error codes that must be handled by the caller.
    /// </remarks>
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.TaskbarList3),
    ]
    internal interface ITaskbarList3 : ITaskbarList2
    {
        #region ITaskbarList2 redeclaration
 
        #region ITaskbarList redeclaration
        new void HrInit();
        new void AddTab(IntPtr hwnd);
        new void DeleteTab(IntPtr hwnd);
        new void ActivateTab(IntPtr hwnd);
        new void SetActiveAlt(IntPtr hwnd);
        #endregion
 
        new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
 
        #endregion
 
        [PreserveSig]
        HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal);
 
        [PreserveSig]
        HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags);
 
        [PreserveSig]
        HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);
 
        [PreserveSig]
        HRESULT UnregisterTab(IntPtr hwndTab);
 
        [PreserveSig]
        HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);
 
        [PreserveSig]
        HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved);
 
        [PreserveSig]
        HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);
 
        [PreserveSig]
        HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);
 
        [PreserveSig]
        HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl);
 
        [PreserveSig]
        HRESULT SetOverlayIcon(IntPtr hwnd, NativeMethods.IconHandle hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);
 
        [PreserveSig]
        HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip);
 
        // Using RefRECT to making passing NULL possible.  Removes clipping from the HWND.
        [PreserveSig]
        HRESULT SetThumbnailClip(IntPtr hwnd, NativeMethods.RefRECT prcClip);
    }
 
    [
        ComImport,
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid(IID.TaskbarList3),
    ]
    internal interface ITaskbarList4 : ITaskbarList3
    {
        #region ITaskbarList3 redeclaration
 
        #region ITaskbarList2 redeclaration
 
        #region ITaskbarList redeclaration
        new void HrInit();
        new void AddTab(IntPtr hwnd);
        new void DeleteTab(IntPtr hwnd);
        new void ActivateTab(IntPtr hwnd);
        new void SetActiveAlt(IntPtr hwnd);
        #endregion
 
        new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
 
        #endregion
 
        [PreserveSig] new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal);
        [PreserveSig] new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags);
        [PreserveSig] new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);
        [PreserveSig] new HRESULT UnregisterTab(IntPtr hwndTab);
        [PreserveSig] new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);
        [PreserveSig] new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved);
        [PreserveSig] new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);
        [PreserveSig] new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);
        [PreserveSig] new HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl);
        [PreserveSig] new HRESULT SetOverlayIcon(IntPtr hwnd, NativeMethods.IconHandle hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);
        [PreserveSig] new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip);
        [PreserveSig] new HRESULT SetThumbnailClip(IntPtr hwnd, NativeMethods.RefRECT prcClip);
 
        #endregion
 
        [PreserveSig]
        HRESULT SetTabProperties(IntPtr hwndTab, STPF stpFlags);
    }
 
    #endregion
 
    /// <remarks>
    /// Methods in this class will only work on Vista and above.
    /// </remarks>
    internal static class ShellUtil
    {
        public static string GetPathFromShellItem(IShellItem item)
        {
            return item.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING);
        }
 
        public static string GetPathForKnownFolder(Guid knownFolder)
        {
            if (knownFolder == default(Guid))
            {
                return null;
            }
 
            var pathBuilder = new StringBuilder(NativeMethods.MAX_PATH);
            HRESULT hr = NativeMethods2.SHGetFolderPathEx(ref knownFolder, 0, IntPtr.Zero, pathBuilder, (uint)pathBuilder.Capacity);
            // If we failed to find a path for the known folder then just ignore it.
            return hr.Succeeded
                ? pathBuilder.ToString()
                : null;
        }
 
        public static IShellItem2 GetShellItemForPath(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                // Internal function.  Should have verified this before calling if we cared.
                return null;
            }
 
            Guid iidShellItem2 = new Guid(IID.ShellItem2);
            object unk;
            HRESULT hr = NativeMethods2.SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk);
 
            // Silently absorb errors such as ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND.
            // Let others pass through
            if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND)
            {
                hr = HRESULT.S_OK;
                unk = null;
            }
 
            hr.ThrowIfFailed();
 
            return (IShellItem2)unk;
        }
    }
 
    internal static class NativeMethods2
    {
        [DllImport(ExternDll.Shell32, EntryPoint = "SHAddToRecentDocs")]
        private static extern void SHAddToRecentDocsString(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv);
 
        // This overload is required.  There's a cast in the Shell code that causes the wrong vtbl to be used
        // if we let the marshaller convert the parameter to an IUnknown.
        [DllImport(ExternDll.Shell32, EntryPoint = "SHAddToRecentDocs")]
        private static extern void SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv);
 
        internal static void SHAddToRecentDocs(string path)
        {
            SHAddToRecentDocsString(SHARD.PATHW, path);
        }
 
        // Win7 only.
        internal static void SHAddToRecentDocs(IShellLinkW shellLink)
        {
            SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink);
        }
 
        // Vista only
        [DllImport(ExternDll.Shell32)]
        internal static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv);
 
        // Vista only.  Also inconsistently doced on MSDN.  It was available in some versions of the SDK, and it mentioned on several pages, but isn't specifically doced.
        [DllImport(ExternDll.Shell32)]
        internal static extern HRESULT SHGetFolderPathEx([In] ref Guid rfid, KF_FLAG dwFlags, [In, Optional] IntPtr hToken, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath, uint cchPath);
 
        /// <summary>
        /// Sets the User Model AppID for the current process, enabling Windows to retrieve this ID
        /// </summary>
        /// <param name="AppID"></param>
        [DllImport(ExternDll.Shell32, PreserveSig = false)]
        internal static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
 
        /// <summary>
        /// Retrieves the User Model AppID that has been explicitly set for the current process via SetCurrentProcessExplicitAppUserModelID
        /// </summary>
        /// <param name="AppID"></param>
        [DllImport(ExternDll.Shell32)]
        internal static extern HRESULT GetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] out string AppID);
    }
}