// ==========================================================================
// Class Implementation : COXAdvancedAssert
// ==========================================================================
// Source file OXAdvancedAssert.cpp
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
#include "stdafx.h"
#ifndef __AdvancedAssert_h__
#error In order to use Advanced Asserts "OXAdvancedAssert.h" must be included in stdafx.h
#endif
#include "OXAdvancedAssertMail.h" // SendMail()
#include "UTBStrOp.h"
#include "UTB64Bit.h"
#ifdef AFX_DBG1_SEG
#pragma code_seg(AFX_DBG1_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__ ;
#endif
#ifndef szNULL
#define szNULL _T("")
#endif // szNULL
#ifndef szCRLF
#define szCRLF _T("\r\n")
#endif // szCRLF
#ifdef _UNICODE
#define _tcstombsz wcstombsz
#else
#define _tcstombsz strncpy
#endif
#include "UTBStrOp.h"
// v9.3 - update 04 fixes for ASSERT in unicode builds- AAW 2009-03-29
// Determine number of elements in an array (not bytes)
#ifndef _countof
#define _countof(array) (sizeof(array)/sizeof(array[0]))
#endif // _countof
// END AAW
/////////////////////////////////////////////////////////////////////////////
// Advanced Assert Send state
static BOOL g_bEnableAssertSend = TRUE ;
static char g_szEmailAddress[128] = BETA_EMAIL_ADDRESS ; // Must not be a Unicode string.
static CString g_csAssertNote1= OX_ADVANCEDASSERT_NOTE1;
static CString g_csAssertNote2= OX_ADVANCEDASSERT_NOTE2;
BOOL AppGetAssertSendState()
{
return g_bEnableAssertSend ;
}
BOOL AppSetAssertSendState(BOOL bEnable/*=TRUE*/)
{
BOOL bOldState = g_bEnableAssertSend ;
g_bEnableAssertSend = bEnable ;
return bOldState ;
}
LPCSTR AppGetAssertEmailAddress()
{
return g_szEmailAddress ;
}
CString AppSetAssertEmailAddress(CString csEmailAddress)
{
CString csOldEmailAddress ( g_szEmailAddress ) ;
// v9.3 - update 04 fixes for ASSERT in unicode builds- AAW 2009-03-29
#ifdef _UNICODE
::WideCharToMultiByte(CP_ACP, 0, csEmailAddress,csEmailAddress.GetLength()+1, g_szEmailAddress, 128, NULL, NULL);
#else
UTBStr::strncpy(g_szEmailAddress, _countof(g_szEmailAddress), csEmailAddress, __min(csEmailAddress.GetLength()+1, _countof(g_szEmailAddress)) ) ;
#endif
// END AAW
return csOldEmailAddress ;
}
CString AppGetAssertNote1()
{
return g_csAssertNote1 ;
}
CString AppSetAssertNote1(CString csNote)
{
CString csOldNote ( g_csAssertNote1 ) ;
g_csAssertNote1 = csNote ;
return csOldNote ;
}
CString AppGetAssertNote2()
{
return g_csAssertNote2 ;
}
CString AppSetAssertNote2(CString csNote)
{
CString csOldNote ( g_csAssertNote2 ) ;
g_csAssertNote2 = csNote ;
return csOldNote ;
}
// If this is not a debug or a beta version, then don't use any of this code.
#if defined(_DEBUG) || defined(BETA) // entire file
/////////////////////////////////////////////////////////////////////////////
// Advanced Assert dialog
#define IDD_ADVANCED_ASSERTS 100
#define IDC_MESSAGE 101
#define IDC_SEND 102
#define IDC_NOTE1 103
#define IDC_NOTE2 104
#ifndef _WIN32
typedef char wchar_t ;
#endif
#pragma pack(2)
typedef struct _tagSDialogFontTemplate
{
WORD wFontSize ;
wchar_t szFontName[14] ;
} SDialogFontTemplate;
typedef struct _tagSDialogTemplate
{
DLGTEMPLATE header ;
wchar_t szMenu ; // Align on WORD boundry.
wchar_t szClass ;
wchar_t szTitle ;
SDialogFontTemplate font ;
WORD wUnused ; // Help it to align. Interesting that it does not align automatically.
} SDialogTemplate;
typedef struct _tagSDialogItemTemplate
{
DLGITEMTEMPLATE item ;
wchar_t szOrdinal ; // Align on WORD boundry.
wchar_t szClass ;
wchar_t szTitle ;
// Creation data falls on a DWORD boundry.
} SDialogItemTemplate;
#pragma pack()
// Align on 4-byte boundry.
#pragma pack(4)
typedef struct _tagSAdvancedAssertDialogTemplate
{
SDialogTemplate header ;
SDialogItemTemplate itemSend ;
DWORD dwCreationDataSend ; // Align on DWORD boundry.
SDialogItemTemplate itemNote1 ;
DWORD dwCreationDataNote1 ;
SDialogItemTemplate itemNote2 ;
DWORD dwCreationDataNote2 ;
SDialogItemTemplate itemMessage ;
DWORD dwCreationDataMessage ;
SDialogItemTemplate itemAbort ;
DWORD dwCreationDataAbort ;
SDialogItemTemplate itemRetry ;
DWORD dwCreationDataRetry ;
SDialogItemTemplate itemIgnore ;
DWORD dwCreationDataIgnore ;
} SAdvancedAssertDialogTemplate;
#pragma pack()
const DWORD DS_ADVANCED_DIALOG = WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_SETFONT ;
const DWORD WS_ADVANCED_BUTTON = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON ;
const DWORD WS_ADVANCED_TEXT = WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_CENTER | ES_MULTILINE | ES_READONLY | WS_VSCROLL ;
const DWORD WS_ADVANCED_STATIC = WS_CHILD | WS_VISIBLE | WS_GROUP | SS_LEFT ;
const WORD CL_BUTTON = 0x0080 ;
const WORD CL_EDIT = 0x0081 ;
const WORD CL_STATIC = 0x0082 ;
const WORD CL_LISTBOX = 0x0083 ;
const WORD CL_SCROLLBAR = 0x0084 ;
const WORD CL_COMBOBOX = 0x0085 ;
static SAdvancedAssertDialogTemplate dlgAdvancedAssertTemplate =
{
#ifdef _WIN32
{ { DS_ADVANCED_DIALOG, 0, 7, 0, 0, 292, 126, }, 0, 0, 0, { 8, L"MS Sans Serif" } }, // header
#else
{ { DS_ADVANCED_DIALOG, 0, 7, 0, 0, 292, 126, }, 0, 0, 0, { 8, "MS Sans Serif" } }, // header. Not UNICODE because not WIN32
#endif
{ { WS_ADVANCED_BUTTON, 0, 220, 105, 50, 14, IDC_SEND }, 0xFFFF, CL_BUTTON, 0 }, 0, // itemSend
{ { WS_ADVANCED_STATIC, 0, 24, 7, 243, 21, IDC_NOTE1 }, 0xFFFF, CL_STATIC, 0 }, 0, // itemNote1
{ { WS_ADVANCED_STATIC, 0, 24, 28, 243, 21, IDC_NOTE2 }, 0xFFFF, CL_STATIC, 0 }, 0, // itemNote2
{ { WS_ADVANCED_TEXT , 0, 22, 52, 247, 48, IDC_MESSAGE }, 0xFFFF, CL_EDIT , 0 }, 0, // itemMessage
{ { WS_ADVANCED_BUTTON, 0, 22, 105, 50, 14, IDABORT }, 0xFFFF, CL_BUTTON, 0 }, 0, // itemAbort
{ { WS_ADVANCED_BUTTON, 0, 88, 105, 50, 14, IDRETRY }, 0xFFFF, CL_BUTTON, 0 }, 0, // itemRetry
{ { WS_ADVANCED_BUTTON, 0, 154, 105, 50, 14, IDIGNORE }, 0xFFFF, CL_BUTTON, 0 }, 0, // itemIgnore
} ;
typedef struct _tagSAdvancedAssertData
{
LPCTSTR pszMessage ;
BOOL bEnableSend ;
} SAdvancedAssertData;
BOOL FAR PASCAL AdvancedAssertDlgProc(HWND hDlg, UINT nMessage,
WPARAM wParam, LPARAM lParam)
{
switch ( nMessage )
{
case WM_INITDIALOG:
{
// Set the text here so that the dialog structure can be kept simple.
// Obviously, No attempt has been make to internationalize this code.
::SetWindowText ( hDlg, _T("Assertion Failed!") ) ;
::SetDlgItemText( hDlg, IDABORT , _T("&Abort" ) ) ;
::SetDlgItemText( hDlg, IDRETRY , _T("&Retry" ) ) ;
::SetDlgItemText( hDlg, IDIGNORE , _T("&Ignore" ) ) ;
::SetDlgItemText( hDlg, IDC_SEND , _T("&Send Mail") ) ;
::SetDlgItemText( hDlg, IDC_NOTE1, g_csAssertNote1 ) ;
::SetDlgItemText( hDlg, IDC_NOTE2, g_csAssertNote2 ) ;
SAdvancedAssertData* pData = (SAdvancedAssertData*) lParam ;
ASSERT( pData); // Careful, we are already inside an assert.
LPCTSTR pszMessage = pData->pszMessage ;
::SetDlgItemText ( hDlg, IDC_MESSAGE, pszMessage ) ;
#ifndef _DEBUG
HWND hwndRetry = ::GetDlgItem ( hDlg, IDRETRY ) ;
::EnableWindow ( hwndRetry, FALSE ) ;
#endif
HWND hwndSendEmail = ::GetDlgItem ( hDlg, IDC_SEND ) ;
::EnableWindow ( hwndSendEmail, pData->bEnableSend ) ;
// Setting the selection does not work.
// Try setting focus to the send email button first.
::SendDlgItemMessage ( hDlg, IDC_MESSAGE, EM_SETSEL, 0, 0 ) ;
return TRUE ;
}
case WM_COMMAND:
{
switch ( wParam )
{
case IDCANCEL: // Escape
wParam = IDIGNORE ;
case IDABORT:
case IDRETRY:
case IDIGNORE:
case IDC_SEND:
::EndDialog ( hDlg, wParam ) ;
return TRUE ;
}
break ;
}
}
return FALSE ;
}
/////////////////////////////////////////////////////////////////////////////
// Advanced Assert function
#define MAX_MSG 4096
#ifdef _WIN32
LONG lAdvancedAssertBusy = -1 ;
LONG lAdvancedAssertReallyBusy = -1 ;
BOOL (AFXAPI* afxAssertFailedLine)(LPCSTR, int) ;
#ifndef _DEBUG
AFX_DATA BOOL afxTraceEnabled=FALSE ;
#else
#ifdef _AFXDLL
extern __declspec(dllimport) AFX_DATA BOOL afxTraceEnabled ;
#else
extern AFX_DATA BOOL afxTraceEnabled ;
#endif // _AFXDLL
#endif // _DEBUG
#else
int NEAR nAdvancedIgnoreAssertCount = 0 ;
LONG NEAR lAdvancedAssertBusy = -1 ;
HWND PASCAL _AfxGetSafeOwner(CWnd* pParent) ;
void AfxDebugBreak()
{
_asm { int 3 } ;
}
#endif
// v9.3 - update 04 fixes for ASSERT in unicode builds- AAW 2009-03-29
// - strings have been changed back or converted back to char instead of TCHAR where appropriate,
// - some wsprintfs are now %hs as well.
// Note: file names are still ANSI strings (filenames rarely need UNICODE)
BOOL AFXAPI AdvancedAssertFailedLine(LPCSTR lpszCondition, LPCSTR lpszFileName, int nLine)
{
#ifdef _WIN32
#ifdef _DEBUG
BOOL bUseCrtDebug=FALSE ;
if ( bUseCrtDebug )
{
// This little bit of code was taken directly from the MFC sources.
// It is placed here just as a reference.
// we remove WM_QUIT because if it is in the queue then the message box won't display
MSG msg ;
BOOL bQuit = PeekMessage ( &msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE ) ;
BOOL bResult = _CrtDbgReport ( _CRT_ASSERT, lpszFileName, nLine, NULL, lpszCondition ) ;
if ( bQuit )
PostQuitMessage ( (int)msg.wParam ) ;
return bResult ;
}
#endif
// handle the (hopefully rare) case of AfxGetAllocState ASSERT
if ( ::InterlockedIncrement(&lAdvancedAssertReallyBusy) > 0 )
{
TCHAR szMessage[MAX_MSG ]=szNULL ;
TCHAR szExeName[_MAX_PATH]=szNULL ;
if ( !GetModuleFileName(NULL, szExeName, _MAX_PATH) )
UTBStr::tcscpy ( szExeName, _MAX_PATH, _T("<program name unknown>") ) ;
// assume the debugger or auxiliary port
// Keep the trace down to one line.
wsprintf ( szMessage, _T("ASSERT( %hs ); Assertion Failed: %s: File %hs, Line %d\n"), lpszCondition, szExeName, lpszFileName, nLine ) ;
::OutputDebugString ( szMessage ) ;
::InterlockedDecrement ( &lAdvancedAssertReallyBusy ) ;
// assert w/in assert (examine call stack to determine first one)
AfxDebugBreak() ;
return FALSE ;
}
// check for special hook function (for testing diagnostics)
::InterlockedDecrement ( &lAdvancedAssertReallyBusy ) ;
if ( afxAssertFailedLine != NULL )
return (*afxAssertFailedLine)(lpszFileName, nLine) ;
TCHAR szMessage[MAX_MSG ]=szNULL ; // Separate message because of potential interlock problem.
TCHAR szExeName[_MAX_PATH]=szNULL ;
if ( !GetModuleFileName(NULL, szExeName, _MAX_PATH) )
UTBStr::tcscpy ( szExeName, _MAX_PATH, _T("<program name unknown>") ) ;
if ( afxTraceEnabled )
{
// assume the debugger or auxiliary port
// output into MacsBug looks better if it's done in one string,
// since MacsBug always breaks the line after each output
// Keep the trace down to one line.
wsprintf ( szMessage, _T("ASSERT( %hs ); Assertion Failed: %s: File %hs, Line %d\n"), lpszCondition, szExeName, lpszFileName, nLine ) ;
::OutputDebugString ( szMessage ) ;
}
if ( ::InterlockedIncrement ( &lAdvancedAssertBusy) > 0 )
{
::InterlockedDecrement ( &lAdvancedAssertBusy ) ;
// assert within assert (examine call stack to determine first one)
AfxDebugBreak() ;
return FALSE ;
}
// active popup window for the current thread
HWND hwndParent = ::GetActiveWindow() ;
if ( hwndParent != NULL )
hwndParent = ::GetLastActivePopup ( hwndParent ) ;
// Separate the assertion from the file and line info when displaying in a message box.
wsprintf ( szMessage, _T("Condition: ASSERT( %hs ); ") szCRLF _T("Program:%s ") szCRLF _T("File: %hs ") szCRLF _T("Line: %d"), lpszCondition, szExeName, lpszFileName, nLine ) ;
// we remove WM_QUIT because if it is in the queue then the message box
// won't display
MSG msg ;
BOOL bQuit = ::PeekMessage ( &msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE ) ;
// display the assert
SAdvancedAssertData dataAssert ;
dataAssert.pszMessage = szMessage ;
dataAssert.bEnableSend = g_bEnableAssertSend ;
// The dialog template must be aligned on a 4-byte boundry.
LPVOID lpvSend = &dlgAdvancedAssertTemplate.itemSend ;
LPVOID lpvNote1 = &dlgAdvancedAssertTemplate.itemNote1 ;
LPVOID lpvNote2 = &dlgAdvancedAssertTemplate.itemNote2 ;
LPVOID lpvMessage = &dlgAdvancedAssertTemplate.itemMessage ;
LPVOID lpvAbort = &dlgAdvancedAssertTemplate.itemAbort ;
LPVOID lpvRetry = &dlgAdvancedAssertTemplate.itemRetry ;
LPVOID lpvIgnore = &dlgAdvancedAssertTemplate.itemIgnore ;
// Can't assert here, so just trace the equivalent.
if ( ((DWORD_PTR)lpvSend & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvSend & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvNote1 & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvNote1 & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvNote2 & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvNote2 & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvMessage & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvMessage & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvAbort & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvAbort & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvRetry & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvRetry & 0x0003) == 0);\n") );
if ( ((DWORD_PTR)lpvIgnore & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvIgnore & 0x0003) == 0);\n") );
HINSTANCE hInstance = AfxGetResourceHandle() ;
// v9.3 - update 03 - 64-bit - added cast (DLGPROC) to 4th parameter - test! - TD
int nCode = (int)::DialogBoxIndirectParam ( hInstance, (LPCDLGTEMPLATE)&dlgAdvancedAssertTemplate, hwndParent, (DLGPROC)AdvancedAssertDlgProc, (LPARAM)&dataAssert ) ;
// If the custom version fails, then use the original version.
if ( nCode == -1 )
nCode = ::MessageBox ( hwndParent, szMessage, _T("Assertion Failed!"), MB_TASKMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE | MB_SETFOREGROUND ) ;
if ( bQuit )
::PostQuitMessage ((int) msg.wParam ) ;
// cleanup
::InterlockedDecrement ( &lAdvancedAssertBusy ) ;
#else
if ( nAdvancedIgnoreAssertCount > 0 )
{
nAdvancedIgnoreAssertCount-- ;
return FALSE ;
}
// In case _AfxGetAppDataFails.
if ( ++lAdvancedAssertBusy > 0 )
{
TCHAR szMessage[MAX_MSG ]=szNULL ;
TCHAR szExeName[_MAX_PATH]=szNULL ;
if ( !GetModuleFileName(NULL, szExeName, _MAX_PATH) )
_tcscpy( szExeName, _T("<program name unknown>") ) ;
// assume the debugger or auxiliary port
wsprintf ( szMessage, _T("ASSERT( %hs ); Assertion Failed: %s: File %hs, Line %d\n"), lpszCondition, szExeName, lpszFileName, nLine ) ;
::OutputDebugString ( szMessage ) ;
lAdvancedAssertBusy-- ;
// break into the debugger (or Dr Watson log)
AfxDebugBreak() ;
return FALSE ;
}
TCHAR szMessage[MAX_MSG ]=szNULL ; // Separate message because of potential interlock problem.
TCHAR szExeName[_MAX_PATH]=szNULL ;
if ( !GetModuleFileName(NULL, szExeName, _MAX_PATH) )
_tcscpy ( szExeName, _T("<program name unknown>") ) ;
if ( afxTraceEnabled )
{
// assume the debugger or auxiliary port
wsprintf ( szMessage, _T("ASSERT( %hs ); Assertion Failed: %s: File %hs, Line %d\n"), lpszCondition, szExeName, lpszFileName, nLine ) ;
::OutputDebugString ( szMessage ) ;
}
wsprintf ( szMessage, _T("Condition: ASSERT( %hs ); ") szCRLF _T("Program:%s ") szCRLF _T("File: %hs ") szCRLF _T("Line: %d"), lpszCondition, szExeName, lpszFileName, nLine ) ;
// we remove WM_QUIT because if it is in the queue then the message box
// won't display
MSG msg ;
BOOL bQuit = ::PeekMessage ( &msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE ) ;
// display the assert
SAdvancedAssertData dataAssert ;
dataAssert.pszMessage = szMessage ;
dataAssert.bEnableSend = g_bEnableAssertSend ;
// The dialog template must be aligned on a 4-byte boundry.
LPVOID lpvSend = &dlgAdvancedAssertTemplate.itemSend ;
LPVOID lpvNote1 = &dlgAdvancedAssertTemplate.itemNote1 ;
LPVOID lpvNote2 = &dlgAdvancedAssertTemplate.itemNote2 ;
LPVOID lpvMessage = &dlgAdvancedAssertTemplate.itemMessage ;
LPVOID lpvAbort = &dlgAdvancedAssertTemplate.itemAbort ;
LPVOID lpvRetry = &dlgAdvancedAssertTemplate.itemRetry ;
LPVOID lpvIgnore = &dlgAdvancedAssertTemplate.itemIgnore ;
// Can't assert here, so just trace the equivalent.
if ( ((DWORD)lpvSend & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvSend & 0x0003) == 0);\n") );
if ( ((DWORD)lpvNote1 & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvNote1 & 0x0003) == 0);\n") );
if ( ((DWORD)lpvNote2 & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvNote2 & 0x0003) == 0);\n") );
if ( ((DWORD)lpvMessage & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvMessage & 0x0003) == 0);\n") );
if ( ((DWORD)lpvAbort & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvAbort & 0x0003) == 0);\n") );
if ( ((DWORD)lpvRetry & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvRetry & 0x0003) == 0);\n") );
if ( ((DWORD)lpvIgnore & 0x0003) != 0 ) TRACE( _T("ASSERT( lpvIgnore & 0x0003) == 0);\n") );
HINSTANCE hInstance = AfxGetResourceHandle() ;
HWND hwndParent = _AfxGetSafeOwner ( NULL ) ;
int nCode = ::DialogBoxIndirectParam ( hInstance, (LPCDLGTEMPLATE)&dlgAdvancedAssertTemplate, hwndParent, AdvancedAssertDlgProc, (LPARAM)&dataAssert ) ;
// If the custom version fails, then use the original version.
if ( nCode == -1 )
nCode = ::MessageBox ( hwndParent, szMessage, _T("Assertion Failed!"), MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE ) ;
if ( bQuit )
::PostQuitMessage ( msg.wParam ) ;
lAdvancedAssertBusy-- ;
#endif
if ( nCode == IDIGNORE )
return FALSE ; // ignore
else if ( nCode == IDRETRY )
return TRUE ; // will cause AfxDebugBreak
else if ( nCode == IDC_SEND )
{
// Simple MAPI does not like unicode strings, so convert to regular strings.
char szNote [MAX_MSG]="" ;
char szSubject[MAX_MSG]="" ;
CString csSubject ;
csSubject = AfxGetApp()->m_pszAppName ;
csSubject += " Assertion Failed!" ;
int nMessageLength = (int)_tcslen ( szMessage ) ;
#ifdef _UNICODE
::WideCharToMultiByte(CP_ACP, 0, csSubject,csSubject.GetLength(), szSubject, _countof(szSubject), NULL, NULL);
::WideCharToMultiByte(CP_ACP, 0, szMessage, nMessageLength, szNote, _countof(szNote), NULL, NULL);
#else
UTBStr::strncpy(szSubject, _countof(szSubject), csSubject, __min(csSubject.GetLength()+1, _countof(szSubject)) ) ;
UTBStr::strncpy(szNote, _countof(szNote), szMessage, __min(nMessageLength+1, _countof(szNote)) ) ;
#endif
LPCSTR pszAttachment = NULL ;
SendMailToBeta ( szSubject, szNote, pszAttachment ) ;
return FALSE ;
}
AfxAbort() ; // should not return (but otherwise AfxDebugBreak)
return TRUE ;
}
// AAW: END
#endif // _DEBUG || BETA