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 AfxLockTempMapsLocks 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 upwhich 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;
}