|
|
|
date: Tue, 1 Apr 2008 09:03:02 -0700,
group: microsoft.public.platformsdk.shell
back
Windows XP thumbnail shell extension
I'm working on a thumbnail extractor shell extension for a custom file type
(Windows XP only, i.e., we don't have Vista boxes and can't use the new
thumbnail providers). For testing, I've registered an extension for a bogus
file type and created a file with that type, but the test files are just
renamed .bmp files. The basic mechanism in my prototype seems to work OK,
except that the test thumbnail that I extract from the .bmp file and that the
shell displays appears to be somewhat lower resolution than the thumbnail
that the .bmp file type's own thumbnail extractor (which doesn't actually
appear to be registered as an actual "ShellEx" itself) gets from the same
file.
In theory, the thumbnail for my bogus file type should look the same as the
thrumbnail produced by the .bmp file since it's actually pulling the bitmap
from the same data. My extractor prototype appears to produce a thumbnail of
the correct size and same scale, and has the same colors, but it appears
somewhat "coarser" or "splotchier" than the thumbnail the shell produces for
the .bmp.
The preview pane in the "Details" view mode was a different story -- the
preview produced by my prototype was stretched very tall, even though I was
using the size passed in by GetLocation to scale it.
As an additional test, I wired up the "tridentimageextractor" built-in
extractor, and it appeared to also produce a somewhat lower resolution
thumbnail than whatever is actually handling .bmp files these days. (The
built-in didn't have the same vertical distortion in the Details mode
preview, however.)
Finally, I created a test .bmp file at exactly 96 x 96 resolution, and when
renamed, the thumbnails that my prototype and the tridentimageextractor
produce look almost the same as the .bmp thumbnail. This also fixed the
vertical distortion problem for the preview item in the Details view.
Short of forcing the original images we use for thumbnails to always be
96x96, I can't find a really straightforward example of doing shell extension
thumbnail extractors from an actual bitmap (pre-Vista) anywhere . (The only
complete example I've found is on CodeProject for the MFC Scribble example,
but it's bound up with reusing the wrapped GDI objects from the MFC doc/view
implementation of the original app. The only examples I've found on MSDN are
a couple of Dino Esposito's shell extension articles from (way) back issues
of MSDN Magazine, and in the very simple thumbnail examples he gave to
illustrate the facility, he just grabbed an existing resource icon.)
I've pieced the following code together from various sources. Oddly, and
maybe this is a clue, I get the same thumbnail image result with the
non-96x96 original bitmaps if I just Detach() the bitmap from the CImage and
don't even attempt the scaling. (Uses Visual Studio 2008 ATL. The m_bmSize
width/height member is stored from the preceding IExtractImage GetLocation
call's 'const SIZE *prgSize' parameter which is supposed to suggest the size.
m_szFile is the pathname that comes from the IPersistFile::Load call.)
STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{
CImage ciTheImage;
ciTheImage.Load(m_szFile);
HDC hmemDC = CreateCompatibleDC(NULL);
SetStretchBltMode(hmemDC, HALFTONE);
SetBrushOrgEx (hmemDC, 0, 0, NULL);
HBITMAP hmemBM = CreateCompatibleBitmap (hmemDC, m_bmSize.cx,
m_bmSize.cy );
SelectObject (hmemDC, hmemBM);
ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy, HALFTONE);
*phBmpThumbnail = ciTheImage.Detach();
DeleteDC(hmemDC);
DeleteObject(hmemBM);
return NOERROR;
}
date: Tue, 1 Apr 2008 09:03:02 -0700
author: linearred
Re: Windows XP thumbnail shell extension
Hi Jim,
I was using SRCCOPY originally - not sure where I picked up the idea that I
could try HALFTONE. SRCCOPY doesn't have any effect on the image, and I
just changed it back to verify that. I think this goes back to the
observation that if I completely skip all the scaling steps and just load
the image from the file and then just detach() the bitmap and give it to the
shell, I get the same results. It's as if the StretchBlt here has no effect
at all, or at least not on the bitmap it returns the handle to.
Thanks.
"Jim Barry" wrote in message
news:%23E0seONlIHA.5396@TK2MSFTNGP04.phx.gbl...
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy, HALFTONE);
Hmmm, that last parameter is supposed to be a ROP code, i.e. SRCCOPY. I'm
surprised you're seeing anything on the screen at all.
--
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 12:53:46 -0500
author: linearred
Re: Windows XP thumbnail shell extension
Thanks for the suggestion, Dean.
"Dean Earley" wrote in message
news:eJYZtxJlIHA.5080@TK2MSFTNGP02.phx.gbl...
> Jim Barry wrote:
>> linearred wrote:
>>> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
>>> HALFTONE);
>>
>> StretchBlt uses a very low quality scaling algorithm. To get decent
>> results you need to use something like GDI+ (which is what the built-in
>> thumbnailer uses).
>
> By default...
> You can use SetStretchBltMode which significantly improves quality, but
> also slows it down, btu this may not be a problem for you.
> When I was doing it several hundred times a second, it was an issue :)
>
> --
> Dean Earley (dean.earley@icode.co.uk)
> i-Catcher Development Team
>
> iCode Systems
date: Wed, 2 Apr 2008 12:54:17 -0500
author: linearred
Re: Windows XP thumbnail shell extension
Hi Jim,
Thanks for the suggestion. I found two different approaches to doing this
with GDI+ but I can't get either to work.
Using GetThumbnailImage:
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Image imgTheImage(m_szFile, FALSE);
Bitmap *pbmScaledBitmap =
(Bitmap*)imgTheImage.GetThumbnailImage(m_bmSize.cx, m_bmSize.cy, NULL,
NULL);
Color cBackgroundColor(255, 255, 255);
pbmScaledBitmap->GetHBITMAP(cBackgroundColor, phBmpThumbnail);
Gdiplus::GdiplusShutdown(gdiplusToken);
------------
Using DrawImage:
Image imgSourceImage(m_szFile, FALSE);
Bitmap bmScaledBitmap(m_bmSize.cx, m_bmSize.cy,
imgSourceImage.GetPixelFormat());
Graphics gGraphicSurface(&bmScaledBitmap);
gGraphicSurface.SetSmoothingMode(SmoothingModeHighQuality);
gGraphicSurface.SetInterpolationMode(InterpolationModeHighQualityBicubic);
Image *pimgSourceImage = &imgSourceImage;
gGraphicSurface.DrawImage(pimgSourceImage, 0, 0, m_bmSize.cx, m_bmSize.cy);
Color cBackgroundColor(255, 255, 255);
HBITMAP phbmScaledBitmap;
bmScaledBitmap.GetHBITMAP(cBackgroundColor, &phbmScaledBitmap);
phBmpThumbnail = &phbmScaledBitmap;
Gdiplus::GdiplusShutdown(gdiplusToken);
The actual GDI+ calls all appear to return "OK", but both approaches get
access violations that appear to be in the Image destructor after the
function ends. I'm not real familliar with what these things are supposed
to look like underneath the pointers, but it also looks like maybe the
bitmap handle isn't really getting loaded.
By the way -- you wouldn't happen to know if the shell extension actually
needs to call the GDIplus Startup and Shutdown methods, would you?
Thanks for the help.
"Jim Barry" wrote in message
news:eQoAT2BlIHA.5088@TK2MSFTNGP02.phx.gbl...
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
> HALFTONE);
StretchBlt uses a very low quality scaling algorithm. To get decent results
you need to use something like GDI+ (which is what the built-in thumbnailer
uses).
--
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 13:01:43 -0500
author: linearred
Re: Windows XP thumbnail shell extension
Hi Jim --
Thanks for the tip! Just wrapping the GDI+ scaling code in the block like
you suggested fixed the destructor access violations.
I have two implementations that don't crash, but they still produce the same
coarse image when the image has to be scaled (relative to what the .bmp
thumbnails look like for the same data), and each has its own scaling
glitches when the folder View is set to "Details" and they have to produce
the 150x100 preview image that appears in the lower left of the folder
frame. (On the two XP boxes I use, GetLocation also asks for 32 bit color
in the Details preview image, as opposed to the 24 bit 96x96 image requested
in the "Thumbnails" View mode.)
Now that it doesn't crash : ) , I'll play around with the smoothing and
other settings on the Graphics object to see if I can improve the rendering.
(Note - the additional block doesn't seem to be necessary if the Graphics
object isn't created.)
STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Bitmap *pbmOriginal = Bitmap::FromFile(m_szFile);
Color bgColor(255, 255, 255);
pbmOriginal->GetHBITMAP(bgColor, phBmpThumbnail);
Gdiplus::GdiplusShutdown(gdiplusToken);
return NOERROR;
}
STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
{
Bitmap bmOriginal(m_szFile, FALSE);
Bitmap bmScaledBitmap(m_bmSize.cx, m_bmSize.cy,
bmOriginal.GetPixelFormat());
Graphics gGraphics(&bmScaledBitmap);
gGraphics.DrawImage(&bmOriginal, 0, 0, m_bmSize.cx, m_bmSize.cy);
Color bgColor(255, 255, 255);
bmScaledBitmap.GetHBITMAP(bgColor, phBmpThumbnail);
}
Gdiplus::GdiplusShutdown(gdiplusToken);
return NOERROR;
}
"Jim Barry" wrote in message
news:uTh8U8ZlIHA.2368@TK2MSFTNGP03.phx.gbl...
linearred wrote:
> The actual GDI+ calls all appear to return "OK", but both approaches
> get access violations that appear to be in the Image destructor after
> the function ends.
You mustn't shut down GDI+ until you have completely finished with it, and
this includes the destructors of any GDI+ objects you have created. For a
"one off" use of GDI+, you can make sure the destructors run first by
introducing a new scope:
GdiplusStartup(...);
{
// Do stuff
}
GdiplusShutdown(...);
In a shell extension, you could call GdiplusStartup when your extension
object is created and GdiplusShutdown when it is destroyed.
--
Jim Barry, Microsoft MVP
date: Thu, 3 Apr 2008 12:17:50 -0500
author: BW noway
|
|