Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read-only ShellItemPropertyStore throws System.Runtime.InteropServices.COMException - GPS_BESTEFFORT flag resolves issue #378

Closed
matthijsr opened this issue Mar 3, 2023 · 3 comments

Comments

@matthijsr
Copy link

matthijsr commented Mar 3, 2023

Describe the bug and how to reproduce

Sometimes, attempting to retrieve a property from a ShellItem will result in a System.Runtime.InteropServices.COMException.
(Using ShellItem.Properties.GetValueOrDefault)

I've noticed this happening with .exe files most often (e.g., reading the items in a WinPython or Adobe Acrobat Reader install directory), though it's not consistent and I haven't been able to find the common thread between them.

No current configuration of ShellItemPropertyStore seems to resolve the issue. However, creating a read-only PropertyStore with the GPS_BESTEFFORT flag (instead of the current GPS_DEFAULT) does work.

What code is involved

https://github.com/dahall/Vanara/blob/master/Windows.Shell.Common/ShellProperties/ShellItemPropertyStore.cs

For comparison, the following code results in a COMException* when tested against certain files (for instance, AdobeGenuineSlimInstaller.exe from an Acrobat Reader DC installation):

    public static IDictionary<string, string> GetProperties1(string path)
    {
        var result = new Dictionary<string, string>();

        using var item = new ShellItem(path);
        using var propertyDescriptions = item.GetPropertyDescriptionList();
        foreach (var description in propertyDescriptions.Where(description => item.Properties.ContainsKey(description.PropertyKey)))
        {
            var key = description.CanonicalName;
            var value = item.Properties.GetValueOrDefault(description.PropertyKey)?.ToString();
            if (!string.IsNullOrEmpty(value))
            {
                result.Add(key, value);
            }
        }

        return result;
    }

Whereas this does not:

    public static IDictionary<string, string> GetProperties2(string path)
    {
        var result = new Dictionary<string, string>();

        using var item = new ShellItem(path);
        using var propertyDescriptions = item.GetPropertyDescriptionList();

        var propertyStore = ((IShellItem2)item.IShellItem).GetPropertyStore(GETPROPERTYSTOREFLAGS.GPS_BESTEFFORT, typeof(IPropertyStore).GUID);

        foreach (var description in propertyDescriptions)
        {
            var key = description.CanonicalName;

            using var pv = new PROPVARIANT();
            propertyStore.GetValue(description.PropertyKey, pv);
            var value = description.FormatForDisplay(pv, PROPDESC_FORMAT_FLAGS.PDFF_DEFAULT);

            if (key != null && !string.IsNullOrEmpty(value))
            {
                result.Add(key, value);
            }
        }

        Marshal.ReleaseComObject(propertyStore);

        return result;
    }

*The specific exception is:

System.Runtime.InteropServices.COMException : The specified resource type cannot be found in the image file. (0x80070715)
Stack Trace:
     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.get_Keys()
     at Vanara.Windows.Shell.ReadOnlyPropertyStore.ContainsKey(PROPERTYKEY key)

Expected behavior

The intention of this code was to replace a PowerShell script which performed ShellFolder.GetDetailsOf calls.
GetDetailsOf would consistently succeed, where ShellItem.Properties would throw an exception.

I would prefer ShellItemPropertyStore to safely retrieve properties, or at least provide a means of setting the GPS_BESTEFFORT flag without also setting ReadOnly to false.

@dahall
Copy link
Owner

dahall commented Mar 7, 2023

Since you have this running, would you mind testing the following?

using var item = new ShellItem(path);
using var propertyDescriptions = item.GetPropertyDescriptionList();
propertyDescriptions.ReadOnly = false;
foreach (var description in ...

@matthijsr
Copy link
Author

I'm assuming you mean:

        using var item = new ShellItem(path);
        using var propertyDescriptions = item.GetPropertyDescriptionList();
        item.Properties.ReadOnly = false;
        foreach (var description in ...

Since there's no ReadOnly property on PropertyDescriptionList*.

This throws:

System.Runtime.InteropServices.COMException : Access Denied. (0x80030005 (STG_E_ACCESSDENIED))
Stack Trace:
     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.get_Keys()
     at Vanara.Windows.Shell.ReadOnlyPropertyStore.ContainsKey(PROPERTYKEY key)

For that same file.

*(That's on me, really. Sorry for the slightly wonky example using keys from PropertyDescriptionList to access the ShellItemPropertyStore - I was working backwards from some other attempts at resolving the issue when I wrote that example.)

Some other things I've tried:

  1. The property filter lists in PROPERTYKEY.System.PropList. None worked.
  2. Putting a try-catch block around each Get to see if specific keys were triggering the issue (this is where the roundabout PropertyDescriptionList solution came from). But it seems to be all-or-nothing for this specific issue.

@dahall
Copy link
Owner

dahall commented Mar 8, 2023

I made a change to ShellItemPropertyStore so it defaults to GPS_BESTEFFORT instead of GPS_DEFAULT and it now works with your first example w/o exceptions.

dahall added a commit that referenced this issue Mar 8, 2023
@dahall dahall closed this as completed Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants