dahall / Vanara

A set of .NET libraries for Windows implementing PInvoke calls to many native Windows APIs with supporting wrappers.
MIT License
1.79k stars 193 forks source link

ShellItemPropertyStore do not update even if the property has already changed #407

Closed zhuxb711 closed 4 months ago

zhuxb711 commented 1 year ago

Describe the bug and how to reproduce

Make sure the application is running before you unlock the Bitlocker on D:\

  1. Check the BitlockerState: should be 6 -> Actual: 6
  2. Unlock the bitlocker: should not be 6 -> Actual: 6
  3. Lock it again: should be 6 -> Actual: 6

It will not change until you restart the application

What code is involved

// D:\\ is locked by bitlocker
using (ShellItem Item = new ShellItem("D:\\"))
using (ShellItemPropertyStore PropertyStore = Item.Properties)
{
    if (PropertyStore.TryGetValue(ReadOnlyPropertyStore.GetPropertyKeyFromName("System.Volume.BitLockerProtection"), out object RawObject))
    {
        if (int.TryParse(Convert.ToString(RawObject), out int BitlockerState))
        {
            // BitlockerState == 6 -> Locked
            // BitlockerState != 6 -> Unlocked or NoEncryption
        }
    }
}

Expected behavior ShellItemPropertyStore should change itself once Windows modify the property of the file/folder

Screenshots

dahall commented 1 year ago

First of all, you should use using on the ShellItemPropertyStore -- it is disposed with ShellItem. Try the following and let me know if it works (I haven't tried it, but it should work):

// D:\\ is locked by bitlocker
using (ShellItem Item = new ShellItem("D:\\"))
{
    ShellItemPropertyStore PropertyStore = Item.Properties;
    PropertyStore.ReadOnly = false;
    PropertyStore.Temporary = false;
    if  (PropertyStore["System.Volume.BitLockerProtection"] != 6)
        throw new Exception();
    PropertyStore["System.Volume.BitLockerProtection"] = 1;
    if  (PropertyStore["System.Volume.BitLockerProtection"] != 1)
        throw new Exception();
    PropertyStore["System.Volume.BitLockerProtection"] = 6;
    if  (PropertyStore["System.Volume.BitLockerProtection"] != 6)
        throw new Exception();
}
zhuxb711 commented 1 year ago

There are something misunderstanding. I lock the drive through Bitlocker manager panel in Windows rather than assign the value directly to the property. At that situation, this property would not change itself unless the process restarted.

I haven't tested your solution but I don't think this issue related to the disposal of ShellItemPropertyStore. I ran the same code again after the drive unlocked/locked.

dahall commented 1 year ago

Please try my code then without setting the BitLocker property, especially setting the ReadOnly and Temporary properties as shown, to see if your scenario works.

dahall commented 1 year ago

Any success?

zhuxb711 commented 1 year ago

I could not test the code as it threw InvalidCastException

            using (ShellItem Item = new ShellItem("D:\\"))
            {
                Item.Properties.ReadOnly = false;
                Item.Properties.Temporary = false;

                //InvalidCastException threw here
                if (Item.Properties.TryGetValue(ReadOnlyPropertyStore.GetPropertyKeyFromName("System.Volume.BitLockerProtection"), out object RawObject))
                {
                    if (int.TryParse(Convert.ToString(RawObject), out int BitlockerState))
                    {
                        return BitlockerState;
                    }
                }
            }

StackTrace

at Vanara.PInvoke.Shell32.IShellItem2.GetPropertyStore(GETPROPERTYSTOREFLAGS flags, Guid& riid)
at Vanara.Windows.Shell.ShellItemPropertyStore.GetIPropertyStore()
at Vanara.Windows.Shell.ReadOnlyPropertyStore.Run[T](Func`2 action)
at Vanara.Windows.Shell.ReadOnlyPropertyStore.TryGetValue[TVal](PROPERTYKEY key, TVal& value)
at Vanara.Windows.Shell.ReadOnlyPropertyStore.TryGetValue(PROPERTYKEY key, Object& value)

The exception was thew here:

https://github.com/dahall/Vanara/blob/743519e762496e0fc54f009f00fafe4e18fa015c/Windows.Shell.Common/ShellProperties/ShellItemPropertyStore.cs#L147C47-L147C47

dahall commented 4 months ago

Sorry for the long wait, but I found the problem. This code works:


using ShellItem Item = new("C:\\");
//Item.Properties.ReadOnly = false; // This is the problem!!
Item.Properties.Temporary = false;

if (Item.Properties.TryGetValue<int>(ReadOnlyPropertyStore.GetPropertyKeyFromName("System.Volume.BitLockerProtection"), out int BitlockerState))
{
   // Do something with value
}