using System.Collections.Generic;
using System.ComponentModel;
using Vanara.PInvoke;
using static Vanara.PInvoke.Ole32;
using static Vanara.PInvoke.PropSys;
namespace Vanara.Windows.Shell;
/// A property store for a .
///
public sealed class ShellItemPropertyStore : PropertyStore
{
/// The shell item
private ShellItem shellItem;
/// The flags.
private GETPROPERTYSTOREFLAGS flags = GETPROPERTYSTOREFLAGS.GPS_BESTEFFORT;
/// Initializes a new instance of the class.
/// The ShellItem instance.
/// The optional property changed handler.
internal ShellItemPropertyStore(ShellItem item, PropertyChangedEventHandler? propChangedHandler = null)
{
//item.ThrowIfNoShellItem2();
shellItem = item;
if (propChangedHandler != null)
PropertyChanged += propChangedHandler;
}
///
/// Gets or sets the ICreateObject used instead of CoCreateInstance to create an instance of the property handler associated with
/// the Shell item on which this method is called. If this value is set, will be ignored.
///
/// The creator object.
[DefaultValue(null)]
public ICreateObject? Creator { get; set; }
/// Gets or sets a value indicating whether to include slow properties.
/// true if including slow properties; otherwise, false.
[DefaultValue(false)]
public bool IncludeSlow
{
get => flags.IsFlagSet(GETPROPERTYSTOREFLAGS.GPS_OPENSLOWITEM);
set
{
if (IncludeSlow == value) return;
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_OPENSLOWITEM, value);
if (value)
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_TEMPORARY | GETPROPERTYSTOREFLAGS.GPS_FASTPROPERTIESONLY, false);
}
}
/// Gets a value indicating whether the is read-only.
public override bool IsReadOnly => ReadOnly;
/// Gets or sets a value indicating whether to include only properties directly from the property handler.
/// true if no inherited properties; otherwise, false.
[DefaultValue(false)]
public bool NoInheritedProperties
{
get => flags.IsFlagSet(GETPROPERTYSTOREFLAGS.GPS_HANDLERPROPERTIESONLY);
set
{
if (NoInheritedProperties == value) return;
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_HANDLERPROPERTIESONLY, value);
if (value)
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_TEMPORARY | GETPROPERTYSTOREFLAGS.GPS_BESTEFFORT | GETPROPERTYSTOREFLAGS.GPS_FASTPROPERTIESONLY, false);
}
}
///
/// Gets or sets a set of properties used to filter the property store. This value can be . This value will be
/// ignored if is also set.
///
/// The list of properties used to filter.
[DefaultValue(null)]
public PROPERTYKEY[]? PropertyFilter { get; set; }
/// Gets or sets a value indicating whether properties can be read and written.
/// true if properties are read/write; otherwise, false.
[DefaultValue(true)]
public bool ReadOnly
{
get => !flags.IsFlagSet(GETPROPERTYSTOREFLAGS.GPS_READWRITE);
set
{
if (ReadOnly == value) return;
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_READWRITE, !value);
if (!value)
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_DELAYCREATION | GETPROPERTYSTOREFLAGS.GPS_TEMPORARY | GETPROPERTYSTOREFLAGS.GPS_BESTEFFORT | GETPROPERTYSTOREFLAGS.GPS_FASTPROPERTIESONLY, false);
else
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_HANDLERPROPERTIESONLY);
}
}
///
/// Gets or sets a value indicating whether this provides a writable store, with no initial
/// properties, that exists for the lifetime of the Shell item instance; basically, a property bag attached to the item instance.
///
/// true if temporary; otherwise, false.
[DefaultValue(false)]
public bool Temporary
{
get => flags.IsFlagSet(GETPROPERTYSTOREFLAGS.GPS_TEMPORARY);
set
{
if (Temporary == value) return;
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_TEMPORARY, value);
if (value)
{
flags = GETPROPERTYSTOREFLAGS.GPS_TEMPORARY;
ReadOnly = false;
}
else
{
flags = flags.SetFlags(GETPROPERTYSTOREFLAGS.GPS_TEMPORARY, false);
}
}
}
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public override void Dispose()
{
base.Dispose();
GC.SuppressFinalize(this);
}
/// Gets the CLSID of a supplied property key.
/// The property key.
/// The CLSID related to the property key.
public Guid GetCLSID(PROPERTYKEY propertyKey) => shellItem?.iShellItem2?.GetCLSID(propertyKey) ?? Guid.Empty;
/// The IPropertyStore instance. This can be null.
protected override IPropertyStore? GetIPropertyStore()
{
if (shellItem is ShellLink lnk)
return (IPropertyStore)lnk.link;
try
{
if (Creator != null)
return shellItem?.iShellItem2?.GetPropertyStoreWithCreateObject(flags, Creator, typeof(IPropertyStore).GUID);
if (PropertyFilter != null && PropertyFilter.Length > 0)
return shellItem?.iShellItem2?.GetPropertyStoreForKeys(PropertyFilter, (uint)PropertyFilter.Length, flags, typeof(IPropertyStore).GUID);
return shellItem?.iShellItem2?.GetPropertyStore(flags, typeof(IPropertyStore).GUID);
}
catch (COMException comex) when (comex.ErrorCode == HRESULT.E_FAIL)
{
throw new InvalidOperationException($"The ShellItem does not support a property store with the flags: {flags}", comex);
}
}
}