mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
567 lines
15 KiB
567 lines
15 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992 Microsoft Corporation
|
|
// All rights reserved.
|
|
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and Microsoft
|
|
// QuickHelp and/or WinHelp documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
#include "afximpl.h"
|
|
#include "afxpriv.h"
|
|
#ifdef AFX_CORE3_SEG
|
|
#pragma code_seg(AFX_CORE3_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDataExchange member functions (contructor is in wincore.cpp for swap tuning)
|
|
|
|
HWND CDataExchange::PrepareEditCtrl(int nIDC)
|
|
{
|
|
HWND hWndCtrl = PrepareCtrl(nIDC);
|
|
ASSERT(hWndCtrl != NULL);
|
|
m_bEditLastControl = TRUE;
|
|
return hWndCtrl;
|
|
}
|
|
|
|
HWND CDataExchange::PrepareCtrl(int nIDC)
|
|
{
|
|
ASSERT(nIDC != 0);
|
|
ASSERT(nIDC != -1); // not allowed
|
|
HWND hWndCtrl = ::GetDlgItem(m_pDlgWnd->m_hWnd, nIDC);
|
|
if (hWndCtrl == NULL)
|
|
{
|
|
TRACE1("Error: no data exchange control with ID 0x%04X.\n", nIDC);
|
|
ASSERT(FALSE);
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
m_hWndLastControl = hWndCtrl;
|
|
m_bEditLastControl = FALSE; // not an edit item by default
|
|
ASSERT(hWndCtrl != NULL); // never return NULL handle
|
|
return hWndCtrl;
|
|
}
|
|
|
|
void CDataExchange::Fail()
|
|
{
|
|
if (!m_bSaveAndValidate)
|
|
{
|
|
TRACE0("Warning: CDataExchange::Fail called when not validating.\n");
|
|
// throw the exception anyway
|
|
}
|
|
else if (m_hWndLastControl != NULL)
|
|
{
|
|
// restore focus and selection to offending field
|
|
::SetFocus(m_hWndLastControl);
|
|
if (m_bEditLastControl) // select edit item
|
|
::SendMessage(m_hWndLastControl, EM_SETSEL, 0, -1);
|
|
}
|
|
else
|
|
{
|
|
TRACE0("Error: fail validation with no control to restore focus to.\n");
|
|
// do nothing more
|
|
}
|
|
|
|
AfxThrowUserException();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Notes for implementing dialog data exchange and validation procs:
|
|
// * always start with PrepareCtrl or PrepareEditCtrl
|
|
// * always start with 'pDX->m_bSaveAndValidate' check
|
|
// * pDX->Fail() will throw an exception - so be prepared
|
|
// * avoid creating temporary HWNDs for dialog controls - i.e.
|
|
// use HWNDs for child elements
|
|
// * validation procs should only act if 'm_bSaveAndValidate'
|
|
// * use the suffices:
|
|
// DDX_ = exchange proc
|
|
// DDV_ = validation proc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// only supports '%d', '%u', '%ld' and '%lu'
|
|
static BOOL AFXAPI AfxSimpleScanf(LPCTSTR lpszText,
|
|
LPCTSTR lpszFormat, va_list pData)
|
|
{
|
|
ASSERT(lpszText != NULL);
|
|
ASSERT(lpszFormat != NULL);
|
|
|
|
ASSERT(*lpszFormat == '%');
|
|
lpszFormat++; // skip '%'
|
|
|
|
BOOL bLong = FALSE;
|
|
if (*lpszFormat == 'l')
|
|
{
|
|
bLong = TRUE;
|
|
lpszFormat++;
|
|
}
|
|
|
|
ASSERT(*lpszFormat == 'd' || *lpszFormat == 'u' || *lpszFormat == 'x');
|
|
ASSERT(lpszFormat[1] == '\0');
|
|
|
|
while (*lpszText == ' ' || *lpszText == '\t')
|
|
lpszText++;
|
|
TCHAR chFirst = lpszText[0];
|
|
long l, l2;
|
|
if (*lpszFormat == 'd')
|
|
{
|
|
// signed
|
|
l = _tcstol(lpszText, (LPTSTR*)&lpszText, 10);
|
|
l2 = (int)l;
|
|
}
|
|
else
|
|
if (*lpszFormat == 'u')
|
|
{
|
|
// unsigned
|
|
l = (long)_tcstoul(lpszText, (LPTSTR*)&lpszText, 10);
|
|
l2 = (unsigned int)l;
|
|
}
|
|
else
|
|
{
|
|
// hex
|
|
l = (long)_tcstoul(lpszText, (LPTSTR*)&lpszText, 16);
|
|
l2 = (unsigned int)l;
|
|
}
|
|
if (l == 0 && chFirst != '0')
|
|
return FALSE; // could not convert
|
|
|
|
while (*lpszText == ' ' || *lpszText == '\t')
|
|
lpszText++;
|
|
if (*lpszText != '\0')
|
|
return FALSE; // not terminated properly
|
|
|
|
if (bLong)
|
|
*va_arg(pData, long*) = l;
|
|
else if (l == l2)
|
|
*va_arg(pData, int*) = (int)l;
|
|
else
|
|
return FALSE; // too big for int
|
|
|
|
// all ok
|
|
return TRUE;
|
|
}
|
|
|
|
static void DDX_TextWithFormat(CDataExchange* pDX, int nIDC,
|
|
LPCTSTR lpszFormat, UINT nIDPrompt, ...)
|
|
|
|
// only supports windows output formats - no floating point
|
|
{
|
|
va_list pData;
|
|
va_start(pData, nIDPrompt);
|
|
|
|
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
|
|
TCHAR szT[32];
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
// the following works for %d, %u, %ld, %lu
|
|
::GetWindowText(hWndCtrl, szT, _countof(szT));
|
|
if (!AfxSimpleScanf(szT, lpszFormat, pData))
|
|
{
|
|
AfxMessageBox(nIDPrompt);
|
|
pDX->Fail(); // throws exception
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wvsprintf(szT, lpszFormat, pData);
|
|
// does not support floating point numbers - see dlgfloat.cpp
|
|
AfxSetWindowText(hWndCtrl, szT);
|
|
}
|
|
|
|
va_end(pData);
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Simple formatting to text item
|
|
/*
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, BYTE& value)
|
|
{
|
|
int n = (int)value;
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%u"), AFX_IDP_PARSE_BYTE, &n);
|
|
if (n > 255)
|
|
{
|
|
AfxMessageBox(AFX_IDP_PARSE_BYTE);
|
|
pDX->Fail(); // throws exception
|
|
}
|
|
value = (BYTE)n;
|
|
}
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%u"), AFX_IDP_PARSE_BYTE, n);
|
|
}
|
|
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, int& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate)
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%d"), AFX_IDP_PARSE_INT, &value);
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%d"), AFX_IDP_PARSE_INT, value);
|
|
}
|
|
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, UINT& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate)
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%u"), AFX_IDP_PARSE_UINT, &value);
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%u"), AFX_IDP_PARSE_UINT, value);
|
|
}
|
|
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, long& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate)
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%ld"), AFX_IDP_PARSE_INT, &value);
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%ld"), AFX_IDP_PARSE_INT, value);
|
|
}
|
|
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, DWORD& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate)
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%lu"), AFX_IDP_PARSE_UINT, &value);
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%lu"), AFX_IDP_PARSE_UINT, value);
|
|
}
|
|
|
|
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
int nLen = ::GetWindowTextLength(hWndCtrl);
|
|
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
|
|
value.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
AfxSetWindowText(hWndCtrl, value);
|
|
}
|
|
}
|
|
*/
|
|
void AFXAPI DDX_TexttoHex(CDataExchange* pDX, int nIDC, DWORD& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate)
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%lx"), AFX_IDP_PARSE_INT, &value);
|
|
else
|
|
DDX_TextWithFormat(pDX, nIDC, _T("%lx"), AFX_IDP_PARSE_INT, value);
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Data exchange for special control
|
|
|
|
void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
value = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
|
|
ASSERT(value >= 0 && value <= 2);
|
|
}
|
|
else
|
|
{
|
|
if (value < 0 || value > 2)
|
|
{
|
|
value = 0; // default to off
|
|
TRACE1("Warning: dialog data checkbox value (%d) out of range.\n",
|
|
value);
|
|
}
|
|
::SendMessage(hWndCtrl, BM_SETCHECK, (WPARAM)value, 0L);
|
|
}
|
|
}
|
|
|
|
void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value)
|
|
// must be first in a group of auto radio buttons
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
|
|
ASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
|
|
ASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
|
|
|
|
if (pDX->m_bSaveAndValidate)
|
|
value = -1; // value if none found
|
|
|
|
// walk all children in group
|
|
int iButton = 0;
|
|
do
|
|
{
|
|
if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
|
|
{
|
|
// control in group is a radio button
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
if (::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
|
|
{
|
|
ASSERT(value == -1); // only set once
|
|
value = iButton;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// select button
|
|
::SendMessage(hWndCtrl, BM_SETCHECK, (iButton == value), 0L);
|
|
}
|
|
iButton++;
|
|
}
|
|
else
|
|
{
|
|
TRACE0("Warning: skipping non-radio button in group.\n");
|
|
}
|
|
hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
|
|
|
|
} while (hWndCtrl != NULL &&
|
|
!(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Listboxes, comboboxes
|
|
|
|
void AFXAPI DDX_LBString(CDataExchange* pDX, int nIDC, CString& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
int nIndex = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L);
|
|
if (nIndex != -1)
|
|
{
|
|
int nLen = (int)::SendMessage(hWndCtrl, LB_GETTEXTLEN, nIndex, 0L);
|
|
::SendMessage(hWndCtrl, LB_GETTEXT, nIndex,
|
|
(LPARAM)(LPVOID)value.GetBufferSetLength(nLen));
|
|
}
|
|
else
|
|
{
|
|
// no selection
|
|
value.Empty();
|
|
}
|
|
value.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
// set current selection based on data string
|
|
if (::SendMessage(hWndCtrl, LB_SELECTSTRING, (WPARAM)-1,
|
|
(LPARAM)(LPCTSTR)value) == LB_ERR)
|
|
{
|
|
// no selection match
|
|
TRACE0("Warning: no listbox item selected.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void AFXAPI DDX_LBStringExact(CDataExchange* pDX, int nIDC, CString& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
DDX_LBString(pDX, nIDC, value);
|
|
}
|
|
else
|
|
{
|
|
// set current selection based on data string
|
|
int i = (int)::SendMessage(hWndCtrl, LB_FINDSTRINGEXACT, (WPARAM)-1,
|
|
(LPARAM)(LPCTSTR)value);
|
|
if (i < 0)
|
|
{
|
|
// no selection match
|
|
TRACE0("Warning: no listbox item selected.\n");
|
|
}
|
|
else
|
|
{
|
|
// select it
|
|
SendMessage(hWndCtrl, LB_SETCURSEL, i, 0L);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AFXAPI DDX_CBString(CDataExchange* pDX, int nIDC, CString& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
// just get current edit item text (or drop list static)
|
|
int nLen = ::GetWindowTextLength(hWndCtrl);
|
|
if (nLen != -1)
|
|
{
|
|
// get known length
|
|
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
|
|
}
|
|
else
|
|
{
|
|
// for drop lists GetWindowTextLength does not work - assume
|
|
// max of 255 characters
|
|
::GetWindowText(hWndCtrl, value.GetBuffer(255), 255+1);
|
|
}
|
|
value.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
// set current selection based on model string
|
|
if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1,
|
|
(LPARAM)(LPCTSTR)value) == CB_ERR)
|
|
{
|
|
// just set the edit text (will be ignored if DROPDOWNLIST)
|
|
AfxSetWindowText(hWndCtrl, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AFXAPI DDX_CBStringExact(CDataExchange* pDX, int nIDC, CString& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
DDX_CBString(pDX, nIDC, value);
|
|
}
|
|
else
|
|
{
|
|
// set current selection based on data string
|
|
int i = (int)::SendMessage(hWndCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1,
|
|
(LPARAM)(LPCTSTR)value);
|
|
if (i < 0)
|
|
{
|
|
// no selection match
|
|
TRACE0("Warning: no combobox item selected.\n");
|
|
}
|
|
else
|
|
{
|
|
// select it
|
|
SendMessage(hWndCtrl, CB_SETCURSEL, i, 0L);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AFXAPI DDX_LBIndex(CDataExchange* pDX, int nIDC, int& index)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
index = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L);
|
|
else
|
|
::SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)index, 0L);
|
|
}
|
|
|
|
void AFXAPI DDX_CBIndex(CDataExchange* pDX, int nIDC, int& index)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
index = (int)::SendMessage(hWndCtrl, CB_GETCURSEL, 0, 0L);
|
|
else
|
|
::SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)index, 0L);
|
|
}
|
|
|
|
void AFXAPI DDX_Scroll(CDataExchange* pDX, int nIDC, int& value)
|
|
{
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (pDX->m_bSaveAndValidate)
|
|
value = GetScrollPos(hWndCtrl, SB_CTL);
|
|
else
|
|
SetScrollPos(hWndCtrl, SB_CTL, value, TRUE);
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Range Dialog Data Validation
|
|
|
|
static void AFXAPI FailMinMaxWithFormat(CDataExchange* pDX,
|
|
long minVal, long maxVal, LPCTSTR lpszFormat, UINT nIDPrompt)
|
|
// error string must have '%1' and '%2' strings for min and max values
|
|
// wsprintf formatting uses long values (format should be '%ld' or '%lu')
|
|
{
|
|
ASSERT(lpszFormat != NULL);
|
|
|
|
if (!pDX->m_bSaveAndValidate)
|
|
{
|
|
TRACE0("Warning: initial dialog data is out of range.\n");
|
|
return; // don't stop now
|
|
}
|
|
TCHAR szMin[32];
|
|
TCHAR szMax[32];
|
|
wsprintf(szMin, lpszFormat, minVal);
|
|
wsprintf(szMax, lpszFormat, maxVal);
|
|
CString prompt;
|
|
AfxFormatString2(prompt, nIDPrompt, szMin, szMax);
|
|
AfxMessageBox(prompt, MB_ICONEXCLAMATION, nIDPrompt);
|
|
prompt.Empty(); // exception prep
|
|
pDX->Fail();
|
|
}
|
|
|
|
//NOTE: don't use overloaded function names to avoid type ambiguities
|
|
void AFXAPI DDV_MinMaxByte(CDataExchange* pDX, BYTE value, BYTE minVal, BYTE maxVal)
|
|
{
|
|
ASSERT(minVal <= maxVal);
|
|
if (value < minVal || value > maxVal)
|
|
FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%u"),
|
|
AFX_IDP_PARSE_INT_RANGE);
|
|
}
|
|
|
|
void AFXAPI DDV_MinMaxInt(CDataExchange* pDX, int value, int minVal, int maxVal)
|
|
{
|
|
ASSERT(minVal <= maxVal);
|
|
if (value < minVal || value > maxVal)
|
|
FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%ld"),
|
|
AFX_IDP_PARSE_INT_RANGE);
|
|
}
|
|
|
|
void AFXAPI DDV_MinMaxLong(CDataExchange* pDX, long value, long minVal, long maxVal)
|
|
{
|
|
ASSERT(minVal <= maxVal);
|
|
if (value < minVal || value > maxVal)
|
|
FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%ld"),
|
|
AFX_IDP_PARSE_INT_RANGE);
|
|
}
|
|
|
|
void AFXAPI DDV_MinMaxUInt(CDataExchange* pDX, UINT value, UINT minVal, UINT maxVal)
|
|
{
|
|
ASSERT(minVal <= maxVal);
|
|
if (value < minVal || value > maxVal)
|
|
FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%lu"),
|
|
AFX_IDP_PARSE_INT_RANGE);
|
|
}
|
|
|
|
void AFXAPI DDV_MinMaxDWord(CDataExchange* pDX, DWORD value, DWORD minVal, DWORD maxVal)
|
|
{
|
|
ASSERT(minVal <= maxVal);
|
|
if (value < minVal || value > maxVal)
|
|
FailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%lu"),
|
|
AFX_IDP_PARSE_INT_RANGE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Max Chars Dialog Data Validation
|
|
|
|
void AFXAPI DDV_MaxChars(CDataExchange* pDX, CString const& value, int nChars)
|
|
{
|
|
ASSERT(nChars >= 1); // allow them something
|
|
if (pDX->m_bSaveAndValidate && value.GetLength() > nChars)
|
|
{
|
|
TCHAR szT[32];
|
|
wsprintf(szT, _T("%d"), nChars);
|
|
CString prompt;
|
|
AfxFormatString1(prompt, AFX_IDP_PARSE_STRING_SIZE, szT);
|
|
AfxMessageBox(prompt, MB_ICONEXCLAMATION, AFX_IDP_PARSE_STRING_SIZE);
|
|
prompt.Empty(); // exception prep
|
|
pDX->Fail();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Special DDX_ proc for subclassing controls
|
|
|
|
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
|
|
{
|
|
if (rControl.m_hWnd == NULL) // not subclassed yet
|
|
{
|
|
ASSERT(!pDX->m_bSaveAndValidate);
|
|
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
|
|
if (!rControl.SubclassWindow(hWndCtrl))
|
|
{
|
|
ASSERT(FALSE); // possibly trying to subclass twice?
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|