Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Undocumented Corner


Dr. Dobb's Journal October 1997: Undocumented Corner

Mini MFC Revealed

Scot is a cofounder of Stingray Software. He can be contacted at [email protected]. George is a senior computer scientist with DevelopMentor and can be contacted at [email protected]. They are the coauthors of MFC Internals (Addison-Wesley, 1996).


Sidebar: Why Start with MFC 4.2?

It has been over a year since a major release of MFC, so imagine our excitement when we heard that Visual C++ for Windows CE (a Visual C++ 5.0 add-in) includes its own unique version of MFC. We also heard several rumors that indicated there were some really interesting new classes and that the footprint for Mini MFC would be extremely small compared to regular MFC.

We immediately ordered a copy, installed it, and were initially disappointed to see that the MFC Version flag was set to 0x420, or 4.2. This indicates that the MFC that ships with Visual C++ for Windows CE is actually the same release that shipped with Visual C++ 4.2, because Visual C++ 5.0 ships with a slightly improved MFC 4.21 (the .01 represents IntelliMouse support and a couple of bug fixes).

We investigated the rumor about the footprint of this MFC being smaller and checked the Intel DLL size and were shocked to find out that the Mini MFC release DLL is a minuscule 290 KB. Why were we shocked? On a good day, the normal (now known as "chubby") MFC release DLL for MFC 4.21 is a whopping 920 KB (not counting OLE DLLs).

In addition to the dramatically smaller footprint, we also discovered that Mini MFC has some interesting new classes that could pop up in a future version of the normal MFC.

In this edition of "Undocumented Corner," we'll dissect Mini MFC to find out how Microsoft made the release build smaller than the normal DLL and we'll look at the new features introduced in this version of MFC. Even if you don't plan on writing the next killer Windows CE application, we think that you'll find some of the items in Mini MFC interesting -- especially if you've been hoping for a "light MFC" like we have.

Putting MFC on a Diet

Why is the Mini MFC DLL so small? The main reason is that Windows CE is a subset of the Win32 API and the 1.0 release does not include support for OLE/ActiveX, ISAPI, ODBC, DAO, and MAPI. These parts of the Win32 API were excluded because Windows CE has to fit in such a small hardware space. Other parts of the Win32 API, such as MDI, aren't in the Windows CE SDK because there isn't any graphical user interface equivalent in the hand-held computer world. Other parts of Win32 are excluded, like printing and the find/replace common dialog, because they haven't been ported over yet.

Windows CE also has a different common control DLL that doesn't have toolbars or statusbars. Instead, it has something called a "command bar."

Figure 1 shows what would happen if you were to take the standard MFC hierarchy chart and prune out all of the classes that deal with functionality not found on the Windows CE platform. The grayed-out classes represent those that are found in regular MFC, but not in the Mini MFC. This trims MFC down considerably and accounts for the substantially smaller footprint of the Mini MFC.

How did Microsoft go about miniaturizing MFC? By looking at the Mini MFC source code provided with Visual C++ for Windows CE, and we determined that Microsoft started with a copy of MFC 4.2, then used one of the following #ifdefs to prune MFC:

  • _WIN32_WCE, which is used to mark sections of MFC that are different because of differences in the Windows CE implementation of Win32 and Win32. For example, some calls to the registry under Windows CE are more rigid, therefore Mini MFC has to be sure to check error codes and test arguments more diligently.
  • _WIN32_WCE_EMULATION, which turns off functionality not available in the Visual C++ emulation version of Windows CE. For example, the emulator (used for debugging and testing on your NT system before downloading to a Windows CE device) does not support the Windows CE help system. When compiled for the emulator, this flag will turn off that functionality to avoid an exception in the Intel x86 Windows CE emulation engine.
  • WCE_NO_CTRLBARS, which turns off control bars (MFC toolbars, statusbars, dockbars, and the like)
  • WCE_NO_OLE, which turns off all OLE code in MFC.
  • WCE_NO_FINDREPLACE, which turns off all references to the Find/Replace dialog.
  • WCE_NO_UNSUP_CMNCTRLS, which turns off certain common controls that are not supported on Windows CE, such as the Win32 toolbar common control, statusbar control, and others.
  • WCE_NO_UNSUP_CMNDLGS, which turns off the color common dialog (Windows CE does not support colors in the current release).
  • WCE_NO_MAPI, which turns off MAPI.
  • WCE_NO_PRINTING, which turns off all printing functionality in MFC.
  • WCE_BUG01, which is used to work around bugs in the Windows CE SDK discovered while porting MFC.

Keep in mind that MFC -- with over 175,000 lines of code -- is a relatively large body of source code. Performing this wholesale #ifdefing out of major chunks of MFC functionality must have taken a considerable amount of time; in fact, there are over 900 WCE ifdefs used throughout the Mini MFC source and headers.

In cases where entire files are not needed in the Mini MFC, Microsoft has apparently excluded the files from the build instead of #ifdefing out the entire file. Unfortunately, the makefiles for Mini MFC are not provided so we cannot verify this.

How Microsoft reduced the size of MFC for Mini MFC is a very interesting question if you're writing applications for Windows CE, but why would it be interesting if you aren't?

Creative Applications of Mini MFC

One of the biggest problems with MFC is that it has become bloated over its many releases. Each release added functionality and deepened the MFC tree to the point that, eventually, the DLL grew to 1 MB in size. In the early '90s, this didn't matter because you could just throw the DLL on a CD-ROM and install it into the system directory.

That has all changed in the last couple of years because of the Internet. With the popularity of the Internet, many MFC developers became interested in creating MFC-based ActiveX controls and COM objects that could be downloaded via the Internet, then executed inside of the user's web browser. This technique is enticing because all you have to do to web enable your MFC code is wrap it in an ActiveX control and deploy it.

Unfortunately, any ActiveX control written in MFC needs to carry around that 1-MB MFC DLL and Internet users tend to get anxious waiting for that much data to trickle across a modem (even when compressed). Microsoft responded by creating the ActiveX Template Library (ATL), which lets you create lightweight ActiveX controls (and COM objects).

One reason ATL is so lightweight is that it provides virtually no user-interface code and, instead, implements just the basic COM interfaces needed for an ActiveX control. To have your ActiveX control, you have to either write the user-interface code in raw SDK (remember those giant case statements?) or use ATL and MFC together -- but this defeats the whole purpose of using ATL, because once you use MFC, the MFC DLL becomes a ball and chain.

The ideal situation would be if you could use ATL to implement the COM interfaces for an ActiveX control, then mix in a lightweight version of MFC -- a version without the deadweight of MAPI, ODBC, DAO, and OLE (you're using ATL for that). This approach would give you the best of both worlds -- a lightweight MFC-based ActiveX control that lets you leverage existing MFC code and paradigms like the document/view architecture.

Are you thinking what we're thinking? Why couldn't you take Mini MFC and compile it under the normal Visual C++ -- making sure to exclude files you don't need and to turn on/off appropriate #ifdefs -- to create a custom lightweight version of the MFC DLL that could then be mixed in with ATL? By keeping the OLE, MAPI, DAO, and ODBC portions of MFC turned off, you could easily achieve an MFC DLL that was around 400 KB. This could compress to around 200 KB, which is much more reasonable than regular MFC. We will investigate this idea (you're welcome to try, too) and report our findings to you in a future column. It's not clear if it would be more efficient to port your MFC drawing code to raw SDK or to figure out how to use Mini MFC with ATL; we think that the Mini MFC and ATL route should be easier.

Before you start, be warned that Microsoft clearly doesn't want us to do this, or they would have provided a Mini MFC long before now -- so proceed at your own risk. The wcecomp.h header file lists all of the #ifdefs turned on for Mini MFC and even details what files have been left out for you.

What is a Command Bar?

While digging around Mini MFC we discovered a class that we hadn't heard of before, CCommandBar. The class is declared in cmdbar.h and implemented in cmdbar.cpp. Listing One is CCommandBar's declaration.

Command bars (in the Windows CE sense) are comprised of a unified menu and toolbar. Figure 2 shows a Windows CE application with a circled command bar. In fact, this concept of a unified menu/toolbar is popular in many of Microsoft's latest applications including the Office suite. Could the inclusion of a CCommandBar class in Mini MFC be a harbinger of a new feature in a future release of the regular MFC?

On the Windows CE platform, the command-bar control replaces the toolbar and statusbar, so the implementation of CCommandBar calls into the Windows CE common control DLL. The documentation does advise you to use CCommandBar instead of CMenu, and several convenience functions that live in CFrameWnd are provided to help you convert existing MFC applications to use the new command bars.

Other Points of Interest

In addition to the small footprint and CCommandBar, we found a couple of other interesting nuggets inside Mini MFC.

Earlier we mentioned the WCE_BUG01 ifdef. This ifdef appears in relatively cryptic spots in Mini MFC. It's not clear what "bug" this ifdef works around, but we did find this comment, which indicates there is (or was) a bug in Windows CE that dealt with thread local storage and local processes:

// By defining WCE_BUG01 then the // original implementations of the

// CThreadLocal and CProcessLocal// class templates will be used.

// NOTE: If this bug reappears, // then do *not* define WCE_BUG01.

Finally, if you are interested in doing some Windows CE programming, Microsoft created several utility functions that are used to implement some missing Win32 functions or to map the differences between the Windows 95/NT version of the functions and the Windows CE functions. These functions are declared in WCEXTRN.H and implemented in WCEHND.CPP, WCESCRL.CPP, and WCE.CPP. Listing Two is a partial listing of the functions.

While Mini MFC has many interesting undocumented implementation details, we believe that its reduced footprint is its most important contribution to the world of MFC programming. In our next column, we'll switch gears and pry into undocumented areas of Microsoft's latest tools for Java developers.


Listing One

class CCommandBar {protected:
    HWND      m_hWndParent;
    CWnd*     m_pParentWnd;
    HINSTANCE m_hInst;
    int       m_iCBHeight;
public:
    HWND      m_hCommandBar;
    HMENU     m_hMenu;
    HWND      m_hComboBox;
    CCommandBar();
    ~CCommandBar();
    HWND  Create( HWND hWndParent );
    HWND  Reset();
    HMENU InsertMenu( LPCTSTR lpszMenuName );
    HMENU InsertMenu( UINT uiResourceID )
        { return InsertMenu( MAKEINTRESOURCE(uiResourceID) ); }
    HWND  InsertComboBox( int iWidth );
    BOOL  InsertButtons( TBBUTTON arTBButtons[], UINT uiNButtons, 
                             int iToolbarBitmapID=-1, int iNImages=0 );
    BOOL  AddBitmap( int iNImages, int iToolbarBitmapID );
    BOOL  AddComboBoxString( UINT uiStringResourceID, long lItemData=0 );
    BOOL  AddComboBoxString( LPCTSTR szString, long lItemData=0 );
    int   GetComboCount() const;
    int   GetComboCurSel() const;
    int   SetComboCurSel( int nSelect );
    BOOL  AddAdornments( DWORD dwFlags );  
// CMDBAR_HELP (WM_HELP) and/or CMDBAR_OK (WM_COMMAND, IDOK)
    int   GetHeight()  { return (int)m_iCBHeight; }
};

Back to Article

Listing Two

//  Windows Helpers that live in WCEHND.CPPextern HWND WINAPI    wce_GetTopWindow( HWND hWnd );
extern HWND WINAPI    wce_GetNextWindow(HWND hWnd, UINT nDirection);
extern BOOL WINAPI    wce_RedrawWindow(HWND hWnd, 
CONST RECT *lprcUpdate, 
HRGN hrgnUpdate, UINT flags);
extern HWND WINAPI    wce_GetDesktopWindow(VOID);
extern BOOL           wce_ScrollWindow(HWND hWnd, 
int xAmount, int yAmount, 
LPCRECT lpRect, LPCRECT lpClipRect);


</p>
//  ScrollBar Helpers  (WCESCRL.CPP)


</p>
extern int  WINAPI    wce_GetScrollPos( HWND hWnd, int nBar);
extern BOOL WINAPI    wce_GetScrollRange( HWND hWnd, int nBar, 
                                        LPINT lpMinPos, LPINT lpMaxPos);
//////////////////////////////////////////////////////////////////////////
//  Miscellaneous  (WCE.CPP)
//////////////////////////////////////////////////////////////////////////
extern DWORD          wce_GetVersion();
extern FARPROC        wce_GetProcAddress( HMODULE hModule, LPCSTR lpProcName);
extern LONG WINAPI    wce_SendDlgItemMessageW(HWND hDlg, 
                      int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam);
extern UINT WINAPI    wce_IsDlgButtonChecked(HWND hDlg, int nIDButton);
extern BOOL  WINAPI   wce_IsIconic( HWND hWnd );
extern BOOL           wce_BegAttach( HWND hWnd );
extern void           wce_EndAttach();
extern HLOCAL         wce_ReAlloc( HLOCAL hMem, UINT uBytes, 
UINT uFlags );
extern HWND           wce_CreateModelessDialog( LPCTSTR lpszResName,
                                   HWND hwndParent, DLGPROC lpfnHook );
extern HWND           wce_GetInternalHWND( HWND hWnd );
extern BOOL           PegHelp( LPCWSTR lpszHelpPath );
extern void AFX_CDECL wce_Trace( LPCTSTR lpszFormat, ...);
extern HMODULE        wce_LoadLibraryA( LPCSTR lpLibFileName );
extern void*          wce_expand( void* pvMemBlock, size_t iSize );
extern LPVOID         GlobalLock( HGLOBAL  hMem );
extern BOOL           GlobalUnlock( HGLOBAL  hMem );
extern HGLOBAL        GlobalHandle( LPCVOID pMem );
extern UINT           GlobalFlags( HGLOBAL  hMem );


</p>
// see WINCORE.CPP
extern LRESULT CALLBACK wce_DefWindowProc(HWND hWnd, UINT nMsg, 
WPARAM wParam, LPARAM lParam);
// see DLGFR.CPP
extern HWND             wce_FindText( LPFINDREPLACE lpfr );
// see DLGFR.CPP
extern HWND             wce_ReplaceText(LPFINDREPLACE lpfr);

Back to Article

DDJ


Copyright © 1997, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.