Enhance MFC Applications with Preview and Thumbnail Support

Introduction

Visual C++ 2010 adds the ability to simply implement Thumbnail and Preview support for Microsoft Foundation Classes (MFC) projects with a registered file extension. The file extension is a critical part of the Thumbnail and Preview support, as the COM DLL that handles the rendering of both thumbnails and previews is mapped by file extension. Figure 1 shows a file displayed in Windows Explorer with both a Thumbnail and Preview display rendered.


Figure 1. Thumbnail and Preview Display in Windows Explorer

Despite the similar functions of thumbnail and preview handling, the actual implementation of the COM interfaces to support the functionality is very different. Thumbnail support is similar to MFC-provided Search functionality covered in a previous article, with a method added to the CDocument-derived class in a project that handles the thumbnail rendering. The Document class is shared between two separate projects when thumbnail support is selected in the application wizard (the application wizard settings are shown in Figure 2) - the standard MFC application project that generate the main executable, and an ATL DLL project that produces a COM DLL that is loaded by Windows to generate the thumbnail for a project. The MFC AppWizard will also generate ATL Registrar Scripts (*.rgs) that will correctly register the COM DLL and associate it with the file extension for thumbnail rendering.


Figure 2. AppWizard Settings with Thumbnail and Preview Support

Conditional compilation directives mean that the thumbnail generation code is not actually included in the main executable. The default implementation for the thumbnail-rendering method generated by the AppWizard is:

  void CXXXDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
  {
   // Modify this code to draw the document's data
   dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));
  
   CString strText = _T("TODO: implement thumbnail drawing here");
   LOGFONT lf;
  
   CFont* pDefaultGUIFont = CFont::FromHandle(
    (HFONT) GetStockObject(DEFAULT_GUI_FONT));
   pDefaultGUIFont->GetLogFont(&lf);
   lf.lfHeight = 36;
  
   CFont fontDraw;
   fontDraw.CreateFontIndirect(&lf);
  
   CFont* pOldFont = dc.SelectObject(&fontDraw);
   dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
   dc.SelectObject(pOldFont);
  }

The COM interface required for thumbnail support is IThumbnailProvider, and this has a single method called GetThumbnail that requires implementation. GetThumbnail is implemented within the MFC CDocument class, and after some device context preparation code, CDocument::GetThumbnail will call through to the virtual OnDrawThumbnail method that is shown above. Windows Vista and Windows 7 supports thumbnails of up to 256 by 256 pixels, so there is actually a quite large rendering area available in some circumstances. By default, Windows will not render the thumbnail for a document below a size of 20 by 20 pixels, but this can be customized by a registry entry at HKEY_CLASSES_ROOT | .fileextension | ThumbnailCutoff. ThumbnailCutoff is a DWORD, with cut-off size ranging from 0 (32x32) to 3 (16x16).

Enhance MFC Applications with Preview and Thumbnail Support

As OnDrawThumbnail is implemented directly in the Document class of an MFC project, ready access to all of the member variables that are loaded and stored through CArchive handling is available, and changing the "TODO: implement thumbnail drawing here" string to something meaningful based on the data stored in a file will generally be an easy task.

Despite the ease of implementing thumbnail support, it makes sense mostly for applications that store some type of graphical data. Looking at the Office line of products, the document centric Excel and Word don't implement thumbnail support, while the more graphical Powerpoint does. Following a similar pattern of thumbnail support makes sense, rather than simply implementing the feature because MFC now makes it so easy.

In contrast to the limited rendering space available in thumbnails, the Windows Preview pane offers a significantly larger surface to render the contents of a file, and a much richer display of contents is generally required. The difference in display richness has led to a very different implementation of Preview support in MFC. In contrast to the Document-housed Thumbnail support, Preview support is implemented by creating a CView-derived instance in the ATL COM handler DLL and using the OnDraw method to render a full version of the files contents. With Search and Thumbnail handler support, the CDocument-derived class is the only one that is shared between the application and the handler projects, but with Preview support the CView- derived class also needs to be shared between projects.

Re-using the Views drawing and event-handling logic for Preview support means that choosing to implement a Preview handler is generally a more complex undertaking, and one that requires more significant thought and planning. The AppWizard-generated code will disable context menu support in the View, but standard event handling such as responding to mouse clicks will still be available. The ability to respond to user input is critical, as this is often necessary for a user to navigate through the View, and as the window that the view is rendered to is a standard window, any changes made in response to user-input are captured and rendered just as they would be when the View is part of a standard application. This means that it is possible for a user to modify the data displayed in the view, but as there is no mechanism exposed to save the contents of the modified document back to the file (it is a 'preview' window after all), edits are lost once the user selected a different file to preview or Windows Explorer is closed.

There are two ways to implement read-only behavior in the preview window - CDocument has a public m_bPreviewHandlerMode variable that can be used to detect if a Document has been created for Preview handling (similarly m_bGetThumbnailMode and m_bSearchMode can be used for Thumbnail and Windows Search detection respectively). This can be used to implement conditional logic in event handlers:

   if (!GetDocument()->m_bPreviewHandlerMode){
     //logic to modify application's state here
    }
 

Another approach is the use of conditional compilation logic to remove the View-modifying code from the View class when it is compiled as part of the ATL Preview handler project. SHARED_HANDLERS is defined for the ATL project but not for the MFC application project, allowing code of the form below to be used to disable the ability to edit a file in the preview pane:

  #ifndef SHARED_HANDLERS
    //logic to modify application's state here
  #endif

Document and Preview support build on the core strength of MFC in making interaction with Windows features easier. Hand-implementation of the various COM interfaces required to support Thumbnail and Preview support, and structuring a project in a way that these features can be accommodated without code duplication, can be an extremely tedious and long software engineering challenge. For simple cases, MFC collapses this challenge to simply ticking a box when the AppWizard is run, but as Preview support is implemented with standard OnDraw functionality, some planning and testing to ensure correct Preview behavior is achieved needs to occur.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • In this webinar, IDC featured speaker Steve Conway, Vice President of High Performance Computing, will present an update on the global x86 HPC cluster market. The presentation will include IDC's five-year forecast for the medium- to large-scale technical computing and data analysis emerging markets by systems, processors and application middleware. Cray's featured speaker, John Lee, Vice President of Cray Cluster Advanced Technology Systems, will present the new Cray® CS400™ cluster series based on …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds