Click here to Skip to main content
Click here to Skip to main content

Create Thumbnail Extractor objects for your MFC document types

By , 21 Nov 2002
 

Sample thumbnail images for scribbles

Introduction

Thumbnail views is a nice feature of Windows Explorer. However, little is known about how to create shell thumbnail extensions for custom documents. I was developing a medical image visualisation software and wanted this feature for the DICOM (medical) images that the software can load. After searching the Web i finally found a relevant article in the MSDN magazine: More Windows 2000 UI Goodies: Extending Explorer Views by Customizing Hypertext Template Files.  The articles covers this topic and includes a simple image extractor for icon files.  After creating my DICOM image extractor (i can give it upon request) i created also an image extractor shell extension for Scribble (MFC tutorial) documents and specifically for Scribble Step 5. I tried to write the code in an objected oriented way which promotes reuse (i am a "fun" of the OO "guru" Paul Dilascia, author of the MSDN mag). Finally, i converted the scribble image extractor project to a Custom AppWizard so that you can easily generate the sceleton code of an image extractor for your MFC documents. The figure above shows the thumbnail view of a folder containing a medical file and also my precious scribbles :)

CScribbleExtractor COM object 

The MFC-based thumbnail extension for Scribble (ThumbScb project) has been created as an MFC regular DLL. After the AppWizard i added an ATL object to the project. The object was coded to implement the two interfaces needed: IPersistFile to know about the file currently selected in the shell, and IExtractImage2 (derived from IExtractImage) to access the document and return a bitmap that renders its content.

// ScribbleExtractor.h
class ATL_NO_VTABLE CScribbleExtractor :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CScribbleExtractor, &CLSID_ScribbleExtractor>,
    public IPersistFile,
    public IExtractImage2
{
public: ...

// ScribbleExtractor.cpp
// IExtractImage::Extract
HRESULT CScribbleExtractor::Extract(HBITMAP* phBmpThumbnail)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    theApp.LoadDoc(m_szFile);
    m_hPreview = theApp.CreateThumbnail(m_bmSize);
    *phBmpThumbnail = m_hPreview;
    return NOERROR;
}
...
// Code for other interface functions is omitted since it is boiterblate.

CExtractImageApp generic application class

As you can see, the COM object delegates document loading and thumbnail generation to the main application object. This is convenient because the CWinApp-derived class can determine the supported document types and create corresponding document objects via the document manager mechanism. In order to reuse as much code as possible i implemented the LoadDoc and CreateThumbnail functions in a generic CWinApp-derived class named CExtractImageApp. The first is implemented with generic MFC code. The helper function CanOpenDocument returns an appropriate document template that can create a document object to serve the file. The document object is dynamically created and then the content of the file is loaded from disk.  Loading code is mainly copy-pasted from the MFC OnOpenDocument function.

// Load document. This function is responsible for opening the document
// and setting m_pOpenDoc to the document loaded.
BOOL CExtractImageApp::LoadDoc(LPCTSTR lpFileName)
{
    ASSERT(lpFileName!=NULL);
    CString sFileName = lpFileName;
    CDocTemplate* pDocTemplate = CanOpenDocument(sFileName); // helper function 
                                                             // defined above
    if (pDocTemplate) {
        if(!m_pDoc) {
            m_pDoc = pDocTemplate->CreateNewDocument();
            m_pDoc->m_bAutoDelete = TRUE;
        }
        if (m_pDoc)
        {
            // load content of file, code taken from MFC OnOpenDocument and modified
            CFileException fe;
            CFile* pFile = m_pDoc->GetFile(sFileName,    CFile::modeRead, &fe);
            if (pFile == NULL)
                return FALSE;

            m_pDoc->DeleteContents();
            CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
            loadArchive.m_pDocument = m_pDoc;
            loadArchive.m_bForceFlat = FALSE;
            try
            {
                if (pFile->GetLength() != 0)
                    m_pDoc->Serialize(loadArchive);     // load me
                loadArchive.Close();
                m_pDoc->ReleaseFile(pFile, FALSE);
            }
            catch(CException *e)
            {
                //e->ReportError();
                m_pDoc->ReleaseFile(pFile, TRUE);
                m_pDoc->DeleteContents();   // remove failed contents
                e->Delete();
                return FALSE;
            }
            return TRUE;
            //delete pDoc;
        }
    }
    return FALSE;
}

The CreateThumbnail function creates the thumbnail bitmap and draws the document content on it. It is essentially a template function because it calls the GetDocSize and OnDraw functions that are pure virtual (must be implemented by the derived class). Drawing is done in isotropic mapping to match document dimensions with thumbnail dimensions. The minus sign in SetViewportExt is used to define a cartesian coordinate system (y-axis values increase from bottom to top).

HBITMAP CExtractImageApp::CreateThumbnail(const SIZE bmSize)
{
    HBITMAP hThumb; CBitmap bmpThumb;
    if(!m_pDoc) return NULL;

    CSize bmDocSize = GetDocSize(); // derived class knows it
    // Create memory DC, create a color bitmap, and draw on it
    CDC memdc;
    memdc.CreateCompatibleDC(NULL);
    bmpThumb.CreateBitmap(bmSize.cx,bmSize.cy,3,8,NULL);
    CBitmap* pOldBm = memdc.SelectObject(&bmpThumb);

    memdc.PatBlt(0,0,bmSize.cx,bmSize.cy,WHITENESS);
    memdc.SetMapMode(MM_ISOTROPIC);
    memdc.SetViewportExt(bmSize.cx,-bmSize.cy);
    memdc.SetWindowExt(bmDocSize.cx,bmDocSize.cy);
    OnDraw(&memdc); //let the derived class to handle it
    memdc.SelectObject(pOldBm);
    hThumb = (HBITMAP)bmpThumb.Detach();
    return hThumb;
}

Derived application class

In the main application class derived from CExtractImageApp, the above mentioned pure virtual functions are implemented by calling the respective functions of the already loaded document. Before this, I have to downcast the CDocument m_pDoc pointer to a CScribbleDoc pointer. If you have multiple document classes you can use the CObject::IsKindOf function to find the kind of document class m_pDoc points to. In the InitInstance function i add a template for the scribble document type.  CMDIChildWnd and CView are MFC classes, while CScribbleDoc is a simplified version of the original scribble document class. The only functions that CScribbleDoc  is required to implement for this project are the Serialize function called during document loading and the  GetDocSize and OnDraw functions called during thumbnail creation. Normally, OnDraw function belongs to the CScribbleView class but here there is no need for doc/view architecture. To simplify implementation i copied OnDraw from CScribbleView. In the first line i replaced GetDocument() with this

//thumbscb.cpp
BOOL CThumbScbApp::InitInstance()
{
    if (!InitATL())
        return FALSE;
    // Create document template
    AddDocTemplate(new CMultiDocTemplate(IDR_SCRIBBTYPE,
        RUNTIME_CLASS(CScribbleDoc),RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CView)));

    return CWinApp::InitInstance();
}

void CThumbScbApp::OnDraw(CDC *pDC)
{
    CScribbleDoc *mydoc = (CScribbleDoc *)m_pDoc;
    mydoc->OnDraw(pDC);
}

CSize CThumbScbApp::GetDocSize()
{
    CScribbleDoc *mydoc = (CScribbleDoc *)m_pDoc;
    return mydoc->GetDocSize();
}

// scribdoc.cpp
void CScribbleDoc::OnDraw(CDC* pDC)
{
    CScribbleDoc* pDoc = this; //GetDocument();
    ASSERT_VALID(pDoc);
    ...

How to debug

Debugging shell extensions is difficult. I have created a COM object (ThumbExtract project) that uses shell interfaces to get an IExtractImage for a file and then creates a bitmap. In the same folder you 'll find small VB6 EXE project called TestThumbExtract that references the ThumbExtract object. An instance of this test application is shown below. Click the button to select a file and a large thumbnail for that file will appear in the picture box. You can debug your shell extension by setting the TestThumbExtract.exe as the 'Executable for debug session' in Project/Settings/Debug. 

TestThumbExtract application

Thumbnail Project Wizard

Since code changes for a new thumbnail shell extension project are few, i made a custom AppWizard (ThumbWiz project) based on the ThumbScb project. The compiled wizard DLL is named ThumbWiz.awx and you must copy it to "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Template" folder. An entry named "Thumbnail Project Wizard" appears then in the New Project dialog. The wizard has a custom step which askes your object's name (e.g. Scribble) and the file extensions supported (if you want to support many extensions separate them with commas). The names of the application class, the document class and the COM class created, are based on the object name you give. Also, for each file extension a new document template is created in InitInstance. New GUIDs are automatically generated. The sceleton code includes TODO comments indicating where to add the needed details. In CThumbWizAppWiz::CustomizeProject i customize the project settings (specifically the MIDL settings) and also create a post-build step to register the object. Registry entries under the file extension keys are created so that the system can determine what object to load for each file extension. Be careful not to replace the entries for well known types (like .jpg) because no backup of registry entries is taken.

Conclusion

Creating thumbnail shell extensions for your MFC document types should be very easy now (i hope :). With this article, my thumbnail-PhD comes to an end !! Visit my homepage for other free tools and programs.

History

5 Oct 2002 - updated source code

22 Nov 2002 - updated source code

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Philipos Sakellaropoulos
Web Developer
Greece Greece
Member
Software developer and Microsoft Trainer, Athens, Greece (MCT, MCSD.net, MCSE 2003, MCDBA 2000,MCTS, MCITP, MCIPD).

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNeed Help for thumbnail viewermemberMember 777802423 Mar '11 - 0:11 
QuestionCalling ThumbExtract from VC++ 2008membermjweaver1130 Dec '10 - 10:46 
QuestionWizard for VS 2008 or VS 2003memberKnalph12 Jul '10 - 21:49 
GeneralDICOM Image ExtractormemberCPrakash25 Jun '08 - 2:18 
GeneralPort of project to Vista - problem with registration scriptmemberFrater Fire17 Apr '08 - 2:40 
QuestionCaching?memberlinearblue1 Apr '08 - 7:58 
QuestionMulti-threaded? [modified]memberlinearblue1 Apr '08 - 7:49 
GeneralWindows Vistamemberthe_gorilla14 Mar '08 - 16:11 
GeneralWOWWWWmemberthe_gorilla8 Mar '08 - 15:38 
GeneralSuperbmemberSteve_Harris11 Dec '07 - 1:46 
GeneralNeed Scribble.exe source code. Urgent!memberpeipeishu18 Sep '06 - 8:24 
Generalget the thumbnail after the file is savedmemberpeipeishu11 Sep '06 - 11:21 
NewsMSDN Mag Article movedmemberRowland Shaw29 Dec '05 - 1:50 
GeneralReturn code from GetLocation()sussmeringue26 May '05 - 1:57 
GeneralIRunnableTasksussAnonymous16 Apr '05 - 6:33 
GeneralDICOMmemberasp-12315 Jan '05 - 22:19 
GeneralDICOM3memberYves26 Oct '04 - 20:01 
QuestionUrgent Help--VIEW-DICOM ?membernavaneetha200318 Sep '04 - 3:32 
GeneralC2504 error with VC7memberAndyCLon16 Mar '04 - 15:49 
GeneralRefresh and repeated thumbnails fixedmemberCedrick Collomb15 Jan '04 - 3:21 
GeneralMemory Leaks in the codesussMoe1028 Dec '03 - 22:52 
GeneralRe: Memory Leaks in the codesussMoe1029 Dec '03 - 1:46 
GeneralRe: Memory Leaks in the codememberAshwin Rao5 May '04 - 7:15 
GeneralProgramming style of ThumbExtractmemberAlexander Gräf26 Nov '03 - 6:33 
QuestionDimensions Preview?memberDalroi24 Nov '03 - 13:10 
GeneralDoesn't work in VC7membersysop@HAL9K.com15 Jul '03 - 9:49 
GeneralRe: Doesn't work in VC7memberHeywood24 Jul '03 - 5:11 
QuestionWindows Picture and Fax Viewer?memberGreggman7 Jul '03 - 6:39 
AnswerRe: Windows Picture and Fax Viewer?memberRahul Nimbalkar8 Jul '03 - 3:20 
Generalneed urgeent heelp philipos-pmemberBanerjeeP19 Jun '03 - 3:46 
Generalneed urgeent heelp philiposmemberBanerjeeP19 Jun '03 - 3:45 
Questionhow to use dicom3memberlzp18 Jun '03 - 22:38 
GeneralNeed urgent help ---Philips!!!memberbanerjep5 Jun '03 - 3:34 
GeneralRe: Need urgent help ---Philips!!!memberPhilipos Sakellaropoulos5 Jun '03 - 6:44 
GeneralThumbnail SupportmemberBanerjeeP3 Jun '03 - 23:17 
GeneralA Basic Questionsussvikramj221130 May '03 - 1:31 
GeneralRe: A Basic Questionsussvikramj221130 May '03 - 3:16 
QuestionQuality of Thumbnail?memberTaewon Lee18 Apr '03 - 1:27 
QuestionCan I use this source to produce Word / Exel / PowerPoint thumbnails ?memberDominik Lebar17 Mar '03 - 3:59 
QuestionThumbnail of size 0 bytes ??membervikramj9 Mar '03 - 20:18 
GeneralAnother ExamplememberGreggman2 Feb '03 - 2:13 
GeneralRe: Another ExamplesussAnonymous25 Feb '03 - 0:55 
QuestionCan not build Unicode Buildmembervikramj6 Jan '03 - 22:20 
AnswerRe: Can not build Unicode BuildmemberPhilipos Sakellaropoulos7 Jan '03 - 3:43 
GeneralRe: Can not build Unicode Buildmembervikramj9 Jan '03 - 3:17 
GeneralRe: Can not build Unicode Buildmembersysop@HAL9K.com16 Jul '03 - 5:06 
QuestionCan not compile anythingmemberCedrick Collomb17 Dec '02 - 5:31 
AnswerRe: Can not compile anythingmemberPhilipos Sakellaropoulos17 Dec '02 - 6:17 
GeneralRe: Can not compile anythingmemberCedrick Collomb17 Dec '02 - 6:22 
GeneralRe: Can not compile anythingsussAnonymous25 Feb '03 - 0:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 22 Nov 2002
Article Copyright 2002 by Philipos Sakellaropoulos
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid