Visual C++ 2010 Article: MFC Thumbnail
Preview and Com DLL with Com Interface
|
|
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.
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.
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).
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 tucancode.net.
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.
|