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

GetHandler<IStream> hangs after getting property from ShellItem #49

Closed
tim-fernico opened this issue May 7, 2019 · 7 comments
Closed

Comments

@tim-fernico
Copy link

After getting a ShellItem for a file, I get the MIMEType property followed by opening the file using GetHandler. The app hangs on the call to GetHandler

If I new a ShellItem (from a PIDL) for the properties call and new another ShellItem for the GetHandler it works fine

What code is involved
Calling ShellItem.GetHandler after ShellItem.Properties.TryGetValue

Expected behavior
GetHandler should return an IStream

using (var shellItem = new ShellItem(this.SelectedItem.pidl))
{
    if (!shellItem.IsFolder)
    {
            if (shellItem.Properties.TryGetValue<string>(PROPERTYKEY.System.MIMEType, out var val))
            {
                System.Diagnostics.Trace.WriteLine(val);
            }
        }

        // calling this after the properties hangs - don't know why
        var storage = shellItem.GetHandler<IStream>(BHID.BHID_Stream);
        try
        {
            // IStreamStream  wraps IStream with a .NET Stream
            using (var stream = new IStreamStream(storage))
            using (var sr = new StreamReader(stream))
            {
                System.Diagnostics.Trace.WriteLine($"{shellItem.FileSystemPath} ({stream.Length})");
            }
        }
        finally
        {
            Marshal.ReleaseComObject(storage);
        }
    }
}
@dahall
Copy link
Owner

dahall commented May 7, 2019

I'm wondering if this has to do with using the same IBindCtxt twice. Does it hang if you call GetHandler and then get the property?

@dahall
Copy link
Owner

dahall commented May 7, 2019

I liked the idea of a COM IStream wrapper so I did some searching for IStreamStream but couldn't find an implementation, so I wrote my own. You'll find it in the next release as Vanara.InteropServices.ComStream. I answered the last question I sent. No, it only happens in the order you mentioned. I'm recreating your code in native C++ to see if the problem is there too. I'll let you know my findings.

@dahall
Copy link
Owner

dahall commented May 7, 2019

Well, I ran the following code and it works just fine so the problem is somewhere deep in my library. I'll keep looking for the problem.

HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
   IShellItem2* pshi2;
   hr = SHCreateItemFromParsingName(L"C:\\Temp\\Holes.mp4", NULL, IID_PPV_ARGS(&pshi2));
   if (SUCCEEDED(hr))
   {
      PROPVARIANT pv = { 0 };
      hr = pshi2->GetProperty(PKEY_MIMEType, &pv);
      PropVariantClear(&pv);

      LPBC ppbc;
      hr = CreateBindCtx(0, &ppbc);
      if (SUCCEEDED(hr))
      {
         IStream* pstream;
         hr = pshi2->BindToHandler(ppbc, BHID_Stream, IID_PPV_ARGS(&pstream));
         if (SUCCEEDED(hr))
            pstream->Release();
         ppbc->Release();
      }

      pshi2->Release();
   }
   CoUninitialize();
}

@tim-fernico
Copy link
Author

Does it hang if you call GetHandler and then get the property?

It works fine calling GetHandler before the property.

@dahall
Copy link
Owner

dahall commented May 8, 2019

Found the problem: It turns out that if you call IShellItem2::GetPropertyStore to get an IPropertyStore object, it holds the file open for the lifetime of that object. Since the Properties on ShellItem holds a reference to that object once created, it means that after calling it, no other operations that require file access (like binding to an IStream) can be called. So, I'm looking at alternatives that will likely require some significant rewriting of the logic. It will take some time. Sorry.

As a work around (though a little hacky) you can use the methods on IShellItem2 to get properties without locking the file. Below is a snippet.

if (!shellItem.IsFolder)
   Console.WriteLine(((IShellItem2)shellItem.IShellItem).GetString(PROPERTYKEY.System.MIMEType));

Besides GetString, there are similar methods for retrieving a variety of types. See the docs for IShellItem2.

dahall added a commit that referenced this issue May 9, 2019
…t holding onto the IPropertyStore interface so as to prevent a lock condition on the ShellItem (#49). So I had to change some of the protected methods to support the change.
@dahall
Copy link
Owner

dahall commented May 9, 2019

It wasn't so hard a change after all. I have it working in the posted version of the library. I will release later this week after further testing.

@dahall dahall closed this as completed May 9, 2019
@dahall
Copy link
Owner

dahall commented May 13, 2019

Package 2.3.8 with the changes has been published.

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