Figure 1   Handle Map Functions


static CWnd* CWnd::FromHandle(HWND hWnd) 
Returns a pointer to the CWnd for given HWND. Will create a temporary object on-the-fly if necessary. Guaranteed to return a non-NULL CWnd (assuming the HWND is valid).
static CWnd* CWnd::FromHandlePermanent(HWND hWnd)
Returns a pointer to the CWnd for given HWND, only if the CWnd already exists in the permanent map. Otherwise, returns NULL.
void PASCAL CWnd::SendMessageToDescendants(HWND hWnd,  
         UINT message, WPARAM wParam, LPARAM lParam,
         BOOL bDeep, BOOL bOnlyPerm)
This useful function sends a message to a window and all its descendants. The last argument controls whether the message is sent to permanent objects only, or to all windows.
void AfxLockTempMaps
Locks temporary maps in memory. Advanced; see the MFC source file winhand.cpp for more info.
BOOL AfxUnlockTempMaps(BOOL bDelete)
Unlocks temporary maps. Advanced; see the MFC source file winhand.cpp for more info.


Figure 2   ChandleMap


 ////////////////
 // This is the class MFC uses to implement a handle map.
 // It holds both permanent and temporary objects. The module thread
 // state (see below) holds a pointer to each map for windows, menus,
 // device contexts, GDI objects, and image lists. In other words, the
 // map is a thread-global. Actual definition is in mfc\src\winhand_.h
 // 
 class CHandleMap {
 private:
    CMapPtrToPtr m_permanentMap;  // permanent 
    CMapPtrToPtr m_temporaryMap;  // temporary
    CRuntimeClass*  m_pClass;     // e.g. CWnd
    size_t m_nOffset;             // offset of handles in obj
    int m_nHandles;               // 1 or 2 (for CDC)
 
 public:
    CHandleMap(CRuntimeClass* pClass, size_t nOffset, int nHandles = 1);
    ~CHandleMap()
       { DeleteTemp(); }
 
    CObject* FromHandle(HANDLE h);
    void DeleteTemp();
    void SetPermanent(HANDLE h, CObject* permOb);
    void RemoveHandle(HANDLE h);
    CObject* LookupPermanent(HANDLE h);
    CObject* LookupTemporary(HANDLE h);
    friend class CWinThread;
 };
 
 
 ////////////////
 // This is the module thread state, which holds all sorts
 // of information about a thread. I've only shown the maps here.
 // Actual definition is in mfc\include\afxstat__.h
 //
 class AFX_MODULE_THREAD_STATE : public CNoTrackObject {
 public:
 •
 •
 •
   // temporary/permanent map state
    DWORD m_nTempMapLock;           // if not 0, temp maps locked
    CHandleMap* m_pmapHWND;
    CHandleMap* m_pmapHMENU;
    CHandleMap* m_pmapHDC;
    CHandleMap* m_pmapHGDIOBJ;
    CHandleMap* m_pmapHIMAGELIST;
 •
 •
 •
};

Figure 3   ViewMaps.cpp


 ////////////////////////////////////////////////////////////////
 // VIEWMAPS 1997 Microsoft Systems Journal. 
 // If this program works, it was written by Paul DiLascia.
 // If not, I don't know who wrote it.
 //
 // VIEWMAPS displays the permanent and temporary window maps as TRACE output.
 // Compiles with VC++ 5.0 or later under Windows 95.
 
 #include "StdAfx.h"
 #include "resource.h"       // main symbols
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #undef THIS_FILE
 static char THIS_FILE[] = __FILE__;
 #endif
 
 //////////////////
 // Vanilla MFC app
 //
 class CMyApp : public CWinApp {
 public:
    DECLARE_DYNAMIC(CMyApp)
    CMyApp();
    virtual BOOL InitInstance();
 protected:
    afx_msg void OnAppAbout();
    afx_msg void OnDump();
    afx_msg void OnDumpAll();
    DECLARE_MESSAGE_MAP()
 };
 
 ////////////////
 // Standard MFC main frame window
 //
 class CMainFrame : public CFrameWnd {
 public:
    DECLARE_DYNCREATE(CMainFrame)
    CMainFrame();
    virtual ~CMainFrame();
 protected:
    CStatusBar  m_wndStatusBar;
    CToolBar    m_wndToolBar;
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    DECLARE_MESSAGE_MAP()
 };
 
 ////////////////////////////////////////////////////////////////
 // CMyApp
 //
 BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
    ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
    ON_COMMAND(ID_DUMP,      OnDump)
    ON_COMMAND(ID_DUMP_ALL,  OnDumpAll)
 END_MESSAGE_MAP()
 
 IMPLEMENT_DYNAMIC(CMyApp, CWinApp)
 
 CMyApp::CMyApp()
 {
 }
 
 CMyApp theApp;
 
 BOOL CMyApp::InitInstance()
 {
 #ifdef NEVER
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
       IDR_MAINFRAME,
       RUNTIME_CLASS(CMyDoc),
       RUNTIME_CLASS(CMainFrame),       // main SDI frame window
       RUNTIME_CLASS(CMyView));
    AddDocTemplate(pDocTemplate);
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
    return ProcessShellCommand(cmdInfo);
 #endif 
 
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
       return FALSE;
    pMainFrame->ShowWindow(m_nCmdShow);
    pMainFrame->UpdateWindow();
    m_pMainWnd = pMainFrame;
 
    return TRUE;
 }
 
 void CMyApp::OnAppAbout()
 {
    CDialog(IDD_ABOUTBOX).DoModal();
 }
 
 //////////////////
 // This is the handle map that MFC uses for all Windows objects that have MFC
 // counterparts, like windows, menus, and GDI drawing objects (pen, font, etc.)
 // This definition is copied from the MFC source file winhand_.h, and must
 // exactly match that definition.
 //
 class CMyHandleMap {
 private:                   // implementation
    CMyHandleMap();         // constructor private: never constructed
 public:
    CMapPtrToPtr m_permanentMap;
    CMapPtrToPtr m_temporaryMap;
    CRuntimeClass*  m_pClass;
    // Following are not used by me--MFC uses for HDC's
    size_t m_nOffset;       // offset of handles in the object
    int m_nHandles;         // 1 or 2 (for CDC)
 };
 
 //////////////////
 // Dump the contents of a map (permanent or temporary)
 //
 static void DumpMap(CMapPtrToPtr& map, LPCTSTR lpszTitle)
 {
    TRACE(lpszTitle);
    void *key, *val;
 
    // Loop for each window in the map
    //
    POSITION pos = map.GetStartPosition();
    if (pos==NULL) {
       TRACE("   (empty)\n");
    } else {
       while (pos!=NULL) {
          map.GetNextAssoc(pos, key, val);
          CWnd* pWnd = (CWnd*)val;
          HWND hwnd = pWnd->GetSafeHwnd();
          ASSERT_VALID(pWnd);
 
          // Get window title
          //
          CString sTitle;
          pWnd->GetWindowText(sTitle);
 
          // Get window class name
          //
          char classname[256]="";
          if (hwnd)
             GetClassName(hwnd, classname, sizeof(classname));
 
          // Display window's runtime class, HWND, class name, and title
          //
          TRACE("   %s[0x%04x,\"%s\",\"%s\"]\n", 
                pWnd->GetRuntimeClass()->m_lpszClassName,
                hwnd, classname, (LPCTSTR)sTitle);
       }
    }
 }
 
 //////////////////
 // Handle Dump command:
 // Show contents of permanent and temporary maps.
 //
 void CMyApp::OnDump()
 {
    AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
    CMyHandleMap* pMap = (CMyHandleMap*)pState->m_pmapHWND;
    ASSERT(pMap);
    DumpMap(pMap->m_permanentMap, "Permanent map:\n");
    DumpMap(pMap->m_temporaryMap, "Temporary map:\n");
 }
 
 //////////////////
 // Handle Dump All command:
 // Like Dump, but first get CWnd's for all toplevel windows.
 //
 void CMyApp::OnDumpAll()
 {
    for (CWnd* pw = CWnd::GetDesktopWindow()->GetTopWindow();
         pw;
         pw=pw->GetNextWindow()) {
 
       // Do nothing: The CWnds will stay in the temporary map until
       // the next idle cycle cleans them up—which happens after my function
       // returns at the earliest.
    }
    OnDump();
 }
 
 ////////////////////////////////////////////////////////////////
 // CMainFrame
 //
 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_CREATE()
 END_MESSAGE_MAP()
 
 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
 
 static UINT indicators[] = {
    ID_SEPARATOR,           // status line indicator
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
 };
 
 CMainFrame::CMainFrame()
 {
 }
 
 CMainFrame::~CMainFrame()
 {
 }
 
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
       return -1;
    
    if (!m_wndToolBar.Create(this) ||
       !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) {
       TRACE0("Failed to create toolbar\n");
       return -1;      // fail to create
    }
 
    if (!m_wndStatusBar.Create(this) ||
       !m_wndStatusBar.SetIndicators(indicators,
         sizeof(indicators)/sizeof(UINT))) {
       TRACE0("Failed to create status bar\n");
       return -1;      // fail to create
    }
 
    // TODO: Remove this if you don't want tool tips or a resizeable toolbar
    m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
       CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
 
    return 0;
 }