A
A
Andrey Ovsyankin2014-02-27 10:01:49
Command line
Andrey Ovsyankin, 2014-02-27 10:01:49

How to properly use ISharedBitmap in c#?

There is a task to get photo thumbnails from the system cache (thumbnails).
Code in C# WPF. The IThumbnailCache COM interface returns a tricky ISharedBitmap that has a lifetime that I don't understand. Here is the code:

public System.Windows.Media.ImageSource GetThumbnail(string imagePath)
        {

            IShellItem shItem;
            Guid iIdIShellItem = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe");
            var hr = SHCreateItemFromParsingName(imagePath, IntPtr.Zero, iIdIShellItem, out shItem);
            if (hr == 0)
            {
                Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
                Guid CLSID_LocalThumbnailCache = new Guid("50EF4544-AC9F-4A8E-B21B-8A26180DB13F");

                var type = Type.GetTypeFromCLSID(CLSID_LocalThumbnailCache);
                var tbCache = (IThumbnailCache)Activator.CreateInstance(type);

                ISharedBitmap bmp = null;
                WTS_CACHEFLAGS cFlags;
                WTS_THUMBNAILID bmpId;
                hr = (int)tbCache.GetThumbnail(shItem, 128, WTS_FLAGS.WTS_EXTRACT, out bmp, out cFlags, out bmpId);
                if (hr == 0)
                {
                    var bmpPtr = IntPtr.Zero;
                    if (bmp.GetSharedBitmap(out bmpPtr) == 0)
                    {
                         SIZE size;
                         bmp.GetSize(out size);
                         var iSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                               bmpPtr, IntPtr.Zero, Int32Rect.Empty,
                               System.Windows.Media.Imaging.BitmapSizeOptions.FromWidthAndHeight(size.cx, size.cy));
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }

            }

            return null;

the call to CreateBitmapSourceFromHBitmap fails with HRESULT: 0x88982F94.
I made a C++/CLI wrapper and returned the HBITMAP obtained by the ISharedBitmap::GetSharedBitmap() method to C#.
Empirically found out that the given HRESULT: 0x88982F94 is issued if ISharedBitmap->Release() is called on the C++ side. That is, if the bitmap is freed, then WPF will throw this exception. However, there is no release for ISharedBitmap in the above code. Why does it seem to be freed by the time CreateBitmapSourceFromHBitmap is called?
How in general life time of the COM objects connected through P/Invoke is regulated?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Andrey Ovsyankin, 2014-02-28
@EvilBeaver

The issue was resolved as follows:
Instead of GetSharedBitmap, I got a bitmap using Detach, which is described in MSDN as "Retrieves the bitmap contained in an ISharedBitmap object, and returns a copy if the contained bitmap resides in shared memory. After calling this method the bitmap is no longer associated with this ISharedBitmap" The resulting "detached" bitmap works as expected, after use I release it via DeleteObject.
I did not understand how to use "shared" bitmap correctly.

M
markeshov, 2014-02-27
@markeshov

Try using Marshal.AddRef and Marshal.Release

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question