home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
barstat.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
19KB
|
761 lines
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_CORE3_SEG
#pragma code_seg(AFX_CORE3_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// CStatusBar creation, etc
#define SBPF_UPDATE 0x0001 // pending update of text
struct AFX_STATUSPANE
{
UINT nID; // IDC of indicator: 0 => normal text area
int cxText; // width of string area in pixels
// on both sides there is a 3 pixel gap and
// a one pixel border, making a pane 6 pixels wider
UINT nStyle; // style flags (SBPS_*)
UINT nFlags; // state flags (SBPF_*)
CString strText; // text in the pane
};
inline AFX_STATUSPANE* CStatusBar::_GetPanePtr(int nIndex) const
{
ASSERT((nIndex >= 0 && nIndex < m_nCount) || m_nCount == 0);
return ((AFX_STATUSPANE*)m_pData) + nIndex;
}
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
#define CX_PANE_BORDER 6 // 3 pixels on each side of each pane
CStatusBar::CStatusBar()
{
// setup default border/margin depending on type of system
m_cyTopBorder = 2;
if (afxData.bWin4)
{
m_cxLeftBorder = 0;
m_cxRightBorder = 0;
m_cyBottomBorder = 0;
}
else
{
m_cxLeftBorder = 2;
m_cxRightBorder = 2;
m_cyBottomBorder = 1;
}
// minimum height set with SB_SETMINHEIGHT is cached
m_nMinHeight = 0;
}
CStatusBar::~CStatusBar()
{
AllocElements(0, 0); // destroys existing elements
}
BOOL CStatusBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
return CreateEx(pParentWnd, 0, dwStyle, nID);
}
BOOL CStatusBar::CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle, DWORD dwStyle, UINT nID)
{
ASSERT_VALID(pParentWnd); // must have a parent
// save the style (some of these style bits are MFC specific)
m_dwStyle = (dwStyle & CBRS_ALL);
// translate MFC style bits to windows style bits
dwStyle &= ~CBRS_ALL;
dwStyle |= CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;
if (pParentWnd->GetStyle() & WS_THICKFRAME)
dwStyle |= SBARS_SIZEGRIP;
dwStyle |= dwCtrlStyle;
// initialize common controls
VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
// create the HWND
CRect rect; rect.SetRectEmpty();
return CWnd::Create(STATUSCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
}
BOOL CStatusBar::PreCreateWindow(CREATESTRUCT& cs)
{
// in Win4, status bars do not have a border at all, since it is
// provided by the client area.
if (afxData.bWin4 &&
(m_dwStyle & (CBRS_ALIGN_ANY|CBRS_BORDER_ANY)) == CBRS_BOTTOM)
{
m_dwStyle &= ~(CBRS_BORDER_ANY|CBRS_BORDER_3D);
}
return CControlBar::PreCreateWindow(cs);
}
BOOL CStatusBar::SetIndicators(const UINT* lpIDArray, int nIDCount)
{
ASSERT_VALID(this);
ASSERT(nIDCount >= 1); // must be at least one of them
ASSERT(lpIDArray == NULL ||
AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
ASSERT(::IsWindow(m_hWnd));
// first allocate array for panes and copy initial data
if (!AllocElements(nIDCount, sizeof(AFX_STATUSPANE)))
return FALSE;
ASSERT(nIDCount == m_nCount);
// copy initial data from indicator array
BOOL bResult = TRUE;
if (lpIDArray != NULL)
{
HFONT hFont = (HFONT)SendMessage(WM_GETFONT);
CClientDC dcScreen(NULL);
HGDIOBJ hOldFont = NULL;
if (hFont != NULL)
hOldFont = dcScreen.SelectObject(hFont);
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < nIDCount; i++)
{
pSBP->nID = *lpIDArray++;
pSBP->nFlags |= SBPF_UPDATE;
if (pSBP->nID != 0)
{
if (!pSBP->strText.LoadString(pSBP->nID))
{
TRACE1("Warning: failed to load indicator string 0x%04X.\n",
pSBP->nID);
bResult = FALSE;
break;
}
pSBP->cxText = dcScreen.GetTextExtent(pSBP->strText).cx;
ASSERT(pSBP->cxText >= 0);
if (!SetPaneText(i, pSBP->strText, FALSE))
{
bResult = FALSE;
break;
}
}
else
{
// no indicator (must access via index)
// default to 1/4 the screen width (first pane is stretchy)
pSBP->cxText = ::GetSystemMetrics(SM_CXSCREEN)/4;
if (i == 0)
pSBP->nStyle |= (SBPS_STRETCH | SBPS_NOBORDERS);
}
++pSBP;
}
if (hOldFont != NULL)
dcScreen.SelectObject(hOldFont);
}
UpdateAllPanes(TRUE, TRUE);
return bResult;
}
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
// destruct old elements
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
pSBP->strText.~CString();
++pSBP;
}
// allocate new elements
if (!CControlBar::AllocElements(nElements, cbElement))
return FALSE;
// construct new elements
pSBP = _GetPanePtr(0);
for (i = 0; i < m_nCount; i++)
{
memcpy(&pSBP->strText, &afxEmptyString, sizeof(CString));
++pSBP;
}
return TRUE;
}
void CStatusBar::CalcInsideRect(CRect& rect, BOOL bHorz) const
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
ASSERT(bHorz); // vertical status bar not supported
// subtract standard CControlBar borders
CControlBar::CalcInsideRect(rect, bHorz);
// subtract size grip if present
if ((GetStyle() & SBARS_SIZEGRIP) && !::IsZoomed(::GetParent(m_hWnd)))
{
// get border metrics from common control
int rgBorders[3];
CStatusBar* pBar = (CStatusBar*)this;
pBar->DefWindowProc(SB_GETBORDERS, 0, (LPARAM)&rgBorders);
// size grip uses a border + size of scrollbar + cx border
rect.right -= rgBorders[0] + ::GetSystemMetrics(SM_CXVSCROLL) +
::GetSystemMetrics(SM_CXBORDER) * 2;
}
}
void CStatusBar::UpdateAllPanes(BOOL bUpdateRects, BOOL bUpdateText)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
// update the status pane locations
if (bUpdateRects)
{
// get border information and client work area
CRect rect; GetWindowRect(rect);
rect.OffsetRect(-rect.left, -rect.top);
CalcInsideRect(rect, TRUE);
int rgBorders[3];
VERIFY((BOOL)DefWindowProc(SB_GETBORDERS, 0, (LPARAM)&rgBorders));
// determine extra space for stretchy pane
int cxExtra = rect.Width() + rgBorders[2];
int nStretchyCount = 0;
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
if (pSBP->nStyle & SBPS_STRETCH)
++nStretchyCount;
cxExtra -= (pSBP->cxText+CX_PANE_BORDER + rgBorders[2]);
++pSBP;
}
// determine right edge of each pane
int* rgRights = (int*)_alloca(m_nCount * sizeof(int));
int right = rgBorders[0];
pSBP = _GetPanePtr(0);
for (i = 0; i < m_nCount; i++)
{
// determine size of the pane
ASSERT(pSBP->cxText >= 0);
right += pSBP->cxText+CX_PANE_BORDER;
if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
{
ASSERT(nStretchyCount != 0);
int cxAddExtra = cxExtra / nStretchyCount;
right += cxAddExtra;
--nStretchyCount;
cxExtra -= cxAddExtra;
}
rgRights[i] = right;
// next pane
++pSBP;
right += rgBorders[2];
}
// set new right edges for all panes
DefWindowProc(SB_SETPARTS, m_nCount, (LPARAM)rgRights);
}
// update text in the status panes if specified
if (bUpdateText)
{
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
if (pSBP->nFlags & SBPF_UPDATE)
SetPaneText(i, pSBP->strText);
++pSBP;
}
}
}
#ifdef AFX_CORE3_SEG
#pragma code_seg(AFX_CORE3_SEG)
#endif
/////////////////////////////////////////////////////////////////////////////
// CStatusBar attribute access
int CStatusBar::CommandToIndex(UINT nIDFind) const
{
ASSERT_VALID(this);
if (m_nCount <= 0)
return -1;
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++, pSBP++)
if (pSBP->nID == nIDFind)
return i;
return -1;
}
UINT CStatusBar::GetItemID(int nIndex) const
{
ASSERT_VALID(this);
return _GetPanePtr(nIndex)->nID;
}
void CStatusBar::GetItemRect(int nIndex, LPRECT lpRect) const
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
CStatusBar* pBar = (CStatusBar*)this;
if (!pBar->DefWindowProc(SB_GETRECT, nIndex, (LPARAM)lpRect))
::SetRectEmpty(lpRect);
}
UINT CStatusBar::GetPaneStyle(int nIndex) const
{
return _GetPanePtr(nIndex)->nStyle;
}
void CStatusBar::SetPaneStyle(int nIndex, UINT nStyle)
{
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
if (pSBP->nStyle != nStyle)
{
// if the pane is changing SBPS_STRETCH, then...
if ((pSBP->nStyle ^ nStyle) & SBPS_STRETCH)
{
// ... we need to re-layout the panes
pSBP->nStyle = nStyle;
UpdateAllPanes(TRUE, FALSE);
}
// use SetPaneText, since it updates the style and text
pSBP->nStyle = nStyle;
pSBP->nFlags |= SBPF_UPDATE;
SetPaneText(nIndex, pSBP->strText);
}
}
void CStatusBar::GetPaneInfo(int nIndex, UINT& nID, UINT& nStyle,
int& cxWidth) const
{
ASSERT_VALID(this);
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
nID = pSBP->nID;
nStyle = pSBP->nStyle;
cxWidth = pSBP->cxText;
}
void CStatusBar::SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth)
{
ASSERT_VALID(this);
BOOL bChanged = FALSE;
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
pSBP->nID = nID;
if (pSBP->nStyle != nStyle)
{
if ((pSBP->nStyle ^ nStyle) & SBPS_STRETCH)
bChanged = TRUE;
else
{
pSBP->nStyle = nStyle;
pSBP->nFlags |= SBPF_UPDATE;
SetPaneText(nIndex, pSBP->strText);
}
pSBP->nStyle = nStyle;
}
if (cxWidth != pSBP->cxText)
{
// change width of one pane -> invalidate the entire status bar
pSBP->cxText = cxWidth;
bChanged = TRUE;
}
if (bChanged)
UpdateAllPanes(TRUE, FALSE);
}
void CStatusBar::GetPaneText(int nIndex, CString& s) const
{
ASSERT_VALID(this);
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
s = pSBP->strText;
}
CString CStatusBar::GetPaneText(int nIndex) const
{
ASSERT_VALID(this);
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
return pSBP->strText;
}
BOOL CStatusBar::SetPaneText(int nIndex, LPCTSTR lpszNewText, BOOL bUpdate)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
if (!(pSBP->nFlags & SBPF_UPDATE) &&
((lpszNewText == NULL && pSBP->strText.IsEmpty()) ||
(lpszNewText != NULL && pSBP->strText.Compare(lpszNewText) == 0)))
{
// nothing to change
return TRUE;
}
TRY
{
if (lpszNewText != NULL)
pSBP->strText = lpszNewText;
else
pSBP->strText.Empty();
}
CATCH_ALL(e)
{
// Note: DELETE_EXCEPTION(e) not required
return FALSE;
}
END_CATCH_ALL
if (!bUpdate)
{
// can't update now, wait until later
pSBP->nFlags |= SBPF_UPDATE;
return TRUE;
}
pSBP->nFlags &= ~SBPF_UPDATE;
DefWindowProc(SB_SETTEXT, ((WORD)pSBP->nStyle)|nIndex,
(pSBP->nStyle & SBPS_DISABLED) ? NULL :
(LPARAM)(LPCTSTR)pSBP->strText);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CStatusBar implementation
CSize CStatusBar::CalcFixedLayout(BOOL, BOOL bHorz)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
// determinme size of font being used by the status bar
TEXTMETRIC tm;
{
CClientDC dc(NULL);
HFONT hFont = (HFONT)SendMessage(WM_GETFONT);
HGDIOBJ hOldFont = NULL;
if (hFont != NULL)
hOldFont = dc.SelectObject(hFont);
VERIFY(dc.GetTextMetrics(&tm));
if (hOldFont != NULL)
dc.SelectObject(hOldFont);
}
// get border information
CRect rect; rect.SetRectEmpty();
CalcInsideRect(rect, bHorz);
int rgBorders[3];
DefWindowProc(SB_GETBORDERS, 0, (LPARAM)&rgBorders);
// determine size, including borders
CSize size;
size.cx = 32767;
size.cy = tm.tmHeight - tm.tmInternalLeading - 1
+ rgBorders[1] * 2 + ::GetSystemMetrics(SM_CYBORDER) * 2
- rect.Height();
if (size.cy < m_nMinHeight)
size.cy = m_nMinHeight;
return size;
}
/////////////////////////////////////////////////////////////////////////////
// CStatusBar message handlers
BEGIN_MESSAGE_MAP(CStatusBar, CControlBar)
//{{AFX_MSG_MAP(CStatusBar)
ON_WM_NCHITTEST()
ON_WM_NCPAINT()
ON_WM_PAINT()
ON_WM_NCCALCSIZE()
ON_WM_SIZE()
ON_WM_WINDOWPOSCHANGING()
ON_MESSAGE(WM_SETTEXT, OnSetText)
ON_MESSAGE(WM_GETTEXT, OnGetText)
ON_MESSAGE(WM_GETTEXTLENGTH, OnGetTextLength)
ON_MESSAGE(SB_SETMINHEIGHT, OnSetMinHeight)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
UINT CStatusBar::OnNcHitTest(CPoint)
{
UINT nResult = (UINT)Default();
if (nResult == HTBOTTOMRIGHT)
return HTBOTTOMRIGHT;
else
return HTCLIENT;
}
void CStatusBar::OnNcCalcSize(BOOL /*bCalcValidRects*/, NCCALCSIZE_PARAMS* lpncsp)
{
// calculate border space (will add to top/bottom, subtract from right/bottom)
CRect rect; rect.SetRectEmpty();
CControlBar::CalcInsideRect(rect, TRUE);
ASSERT(rect.top >= 2);
// adjust non-client area for border space
lpncsp->rgrc[0].left += rect.left;
lpncsp->rgrc[0].top += rect.top - 2;
lpncsp->rgrc[0].right += rect.right;
lpncsp->rgrc[0].bottom += rect.bottom;
}
void CStatusBar::OnBarStyleChange(DWORD dwOldStyle, DWORD dwNewStyle)
{
if (m_hWnd != NULL &&
((dwOldStyle & CBRS_BORDER_ANY) != (dwNewStyle & CBRS_BORDER_ANY)))
{
// recalc non-client area when border styles change
SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME);
}
}
void CStatusBar::OnNcPaint()
{
EraseNonClient();
}
// Derived class is responsible for implementing all of these handlers
// for owner/self draw controls.
void CStatusBar::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE);
}
BOOL CStatusBar::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (message != WM_DRAWITEM)
return CWnd::OnChildNotify(message, wParam, lParam, pResult);
ASSERT(pResult == NULL);
UNUSED(pResult); // unused in release builds
DrawItem((LPDRAWITEMSTRUCT)lParam);
return TRUE;
}
void CStatusBar::OnPaint()
{
UpdateAllPanes(FALSE, TRUE);
Default();
}
void CStatusBar::OnSize(UINT nType, int cx, int cy)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
CControlBar::OnSize(nType, cx, cy);
// need to adjust pane right edges (because of stretchy pane)
UpdateAllPanes(TRUE, FALSE);
}
void CStatusBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
{
// not necessary to invalidate the borders
DWORD dwStyle = m_dwStyle;
m_dwStyle &= ~(CBRS_BORDER_ANY);
CControlBar::OnWindowPosChanging(lpWndPos);
m_dwStyle = dwStyle;
}
LRESULT CStatusBar::OnSetText(WPARAM, LPARAM lParam)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
int nIndex = CommandToIndex(0);
if (nIndex < 0)
return -1;
return SetPaneText(nIndex, (LPCTSTR)lParam) ? 0 : -1;
}
LRESULT CStatusBar::OnGetText(WPARAM wParam, LPARAM lParam)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
int nMaxLen = (int)wParam;
if (nMaxLen == 0)
return 0; // nothing copied
LPTSTR lpszDest = (LPTSTR)lParam;
int nLen = 0;
int nIndex = CommandToIndex(0); // use pane with ID zero
if (nIndex >= 0)
{
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
nLen = pSBP->strText.GetLength();
if (nLen > nMaxLen)
nLen = nMaxLen - 1; // number of characters to copy (less term.)
memcpy(lpszDest, (LPCTSTR)pSBP->strText, nLen*sizeof(TCHAR));
}
lpszDest[nLen] = '\0';
return nLen+1; // number of bytes copied
}
LRESULT CStatusBar::OnGetTextLength(WPARAM, LPARAM)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
int nLen = 0;
int nIndex = CommandToIndex(0); // use pane with ID zero
if (nIndex >= 0)
{
AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
nLen = pSBP->strText.GetLength();
}
return nLen;
}
LRESULT CStatusBar::OnSetMinHeight(WPARAM wParam, LPARAM)
{
LRESULT lResult = Default();
m_nMinHeight = wParam;
return lResult;
}
/////////////////////////////////////////////////////////////////////////////
// CStatusBar idle update through CStatusCmdUI class
class CStatusCmdUI : public CCmdUI // class private to this file!
{
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetText(LPCTSTR lpszText);
};
void CStatusCmdUI::Enable(BOOL bOn)
{
m_bEnableChanged = TRUE;
CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
ASSERT(pStatusBar != NULL);
ASSERT_KINDOF(CStatusBar, pStatusBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pStatusBar->GetPaneStyle(m_nIndex) & ~SBPS_DISABLED;
if (!bOn)
nNewStyle |= SBPS_DISABLED;
pStatusBar->SetPaneStyle(m_nIndex, nNewStyle);
}
void CStatusCmdUI::SetCheck(int nCheck) // "checking" will pop out the text
{
CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
ASSERT(pStatusBar != NULL);
ASSERT_KINDOF(CStatusBar, pStatusBar);
ASSERT(m_nIndex < m_nIndexMax);
UINT nNewStyle = pStatusBar->GetPaneStyle(m_nIndex) & ~SBPS_POPOUT;
if (nCheck != 0)
nNewStyle |= SBPS_POPOUT;
pStatusBar->SetPaneStyle(m_nIndex, nNewStyle);
}
void CStatusCmdUI::SetText(LPCTSTR lpszText)
{
CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
ASSERT(pStatusBar != NULL);
ASSERT_KINDOF(CStatusBar, pStatusBar);
ASSERT(m_nIndex < m_nIndexMax);
pStatusBar->SetPaneText(m_nIndex, lpszText);
}
void CStatusBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CStatusCmdUI state;
state.m_pOther = this;
state.m_nIndexMax = (UINT)m_nCount;
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = _GetPanePtr(state.m_nIndex)->nID;
// allow the statusbar itself to have update handlers
if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
continue;
// allow target (owner) to handle the remaining updates
state.DoUpdate(pTarget, FALSE);
}
// update the dialog controls added to the status bar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}
/////////////////////////////////////////////////////////////////////////////
// CStatusBar diagnostics
#ifdef _DEBUG
void CStatusBar::AssertValid() const
{
CControlBar::AssertValid();
}
void CStatusBar::Dump(CDumpContext& dc) const
{
CControlBar::Dump(dc);
if (dc.GetDepth() > 0)
{
for (int i = 0; i < m_nCount; i++)
{
dc << "\nstatus pane[" << i << "] = {";
dc << "\n\tnID = " << _GetPanePtr(i)->nID;
dc << "\n\tnStyle = " << _GetPanePtr(i)->nStyle;
dc << "\n\tcxText = " << _GetPanePtr(i)->cxText;
dc << "\n\tstrText = " << _GetPanePtr(i)->strText;
dc << "\n\t}";
}
}
dc << "\n";
}
#endif //_DEBUG
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNAMIC(CStatusBar, CControlBar)
/////////////////////////////////////////////////////////////////////////////