/***************************************************************************************************************** FILENAME: TextBlock.cpp COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. */ #include "stdafx.h" #include #include #include #include #include #include #include "ErrMacro.h" #include "DfrgRes.h" #include "TextBlock.h" #include "secattr.h" #include PTCHAR CommafyNumberFloat( double number, BOOL bDecimal, PTCHAR stringBuffer, UINT stringBufferLength ); /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: Constructor for CTextBlock GLOBAL VARIABLES: None INPUT: None RETURN: None */ CTextBlock::CTextBlock(void) { // initialize m_isFixedWidth = m_isUseTabs = m_isUseCRLF = FALSE; m_colCount = m_currentCol = 0; m_hResource = NULL; m_pEndOfBuffer = m_pText = NULL; // Allocate 64K EV((m_hMemory = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, 0x10000)) != NULL); // Lock the memory and get the pointer m_pText = (PTCHAR) GlobalLock(m_hMemory); EV(m_pText); m_pEndOfBuffer = m_pText; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ CTextBlock::~CTextBlock(void) { if (m_hMemory){ EH_ASSERT(GlobalUnlock(m_hMemory) == FALSE); EH_ASSERT(GlobalFree(m_hMemory) == NULL); } } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void __cdecl CTextBlock::WriteToBuffer( PTCHAR cFormat, ... ) { // cannot have fixed width with no columns defined assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0)); va_list argptr; va_start(argptr, cFormat); // init the argument list if (m_isFixedWidth){ TCHAR buffer[4 * MAX_PATH]; int num; // print the data into a temp buffer num = vswprintf(buffer, cFormat, argptr); assert(num < 4 * MAX_PATH); // concat and pad onto text buffer //m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], buffer); WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]); } else{ m_pEndOfBuffer += vswprintf(m_pEndOfBuffer, cFormat, argptr); } va_end(argptr); // increment the column counter m_currentCol++; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteToBufferLL( LONGLONG number ) { // cannot have fixed width with no columns defined assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0)); // convert to a string, putting commas in if needed TCHAR tmpBuffer[256]; CommafyNumber(number, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR)); if (m_isFixedWidth){ // concat and pad onto text buffer WriteToBufferAndPad(tmpBuffer, m_colWidth[m_currentCol]); //m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), m_colWidth[m_currentCol], tmpBuffer); } else{ m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, tmpBuffer); } // increment the column counter m_currentCol++; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteToBuffer( UINT resourceID ) { // cannot have fixed width with no columns defined assert((m_isFixedWidth == FALSE) || (m_isFixedWidth && m_colCount > 0)); // must have assigned a handle to the resource assert(m_hResource); TCHAR buffer[256]; EH_ASSERT(LoadString(m_hResource, resourceID, buffer, sizeof(buffer)/sizeof(TCHAR))); if (m_isFixedWidth){ WriteToBufferAndPad(buffer, m_colWidth[m_currentCol]); } else{ m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer); } // increment the column counter m_currentCol++; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::SetColumnWidth( UINT col, UINT colWidth ) { // cannot have fixed width with no columns defined assert(m_isFixedWidth); assert(m_colCount > 0); // the column number must be less than the column count assert(col < m_colCount); m_colWidth[col] = colWidth; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteTab( void ) { // only write the tab if the tab feature has been turned on if (m_isUseTabs) m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\t")); } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteNULL( void ) { m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\0")); } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::EndOfLine( void ) { // the first few lines here are to strip off trailing spaces PTCHAR pEOL = m_pEndOfBuffer-1; while (*pEOL == TEXT(' ') && pEOL != m_pText){ pEOL--; } m_pEndOfBuffer = pEOL + 1; *m_pEndOfBuffer = NULL; // only write the tab if the tab feature has been turned on if (m_isUseCRLF) m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("\r\n")); // reset the col counter to col 0 (start of next line) m_currentCol = 0; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteByteCount( LONGLONG number ) { TCHAR buffer[256]; // formats the number and appends the units FormatNumber(m_hResource, number, buffer); // write the number and units to the text block WriteToBuffer(buffer); } void CTextBlock::FormatNum( HINSTANCE hResource, LONGLONG number, PTCHAR buffer ) { FormatNumber(hResource, number, buffer); } /*************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. DESCRIPTION: DATA STRUCTURES: None. GLOBALS: None. INPUT: RETURN: The number of characters written. 0 on error. */ DWORD FormatNumber( HINSTANCE hResource, LONGLONG number, PTCHAR buffer ) { UINT resourceID = IDS_UNITS_GB; double numberFloat = 0; BOOL bDecimal = FALSE; numberFloat = (double) number; __try{ //Byte range. if (number < 1024){ resourceID = IDS_UNITS_BYTES; __leave; } // KB range numberFloat = (double) number / 1024; if (numberFloat < 1024){ resourceID = IDS_UNITS_KB; __leave; } // MB range numberFloat /= 1024; if (numberFloat < 1024){ resourceID = IDS_UNITS_MB; __leave; } // GB range //This is the default range that we will display, so we dont need to test number numberFloat /= 1024; resourceID = IDS_UNITS_GB; if (numberFloat < 100) { bDecimal = TRUE; } __leave; } __finally { // load the "units" string from resources TCHAR units[30]; EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR))); // convert to a string, putting commas in if needed TCHAR tmpBuffer[256]; CommafyNumberFloat(numberFloat, bDecimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR)); // concat a spacer _tcscat(tmpBuffer, TEXT(" ")); // concat the units _tcscat(tmpBuffer, units); // write the number and units to the text block _tcscpy(buffer, tmpBuffer); } return _tcslen(buffer); } DWORD FormatNumberMB( HINSTANCE hResource, LONGLONG number, PTCHAR buffer ) { // MB range double numberMB = (double) (number / 0x100000); // 1 MB UINT resourceID = IDS_UNITS_MB; BOOL decimal = FALSE; // if it turned out to be 0, switch over to KB if (numberMB < 1){ numberMB = (double) number / 1024; // 1 KB resourceID = IDS_UNITS_KB; } else if (numberMB > 1024){ // if it is greater than 1024 MB, switch to GB numberMB /= 1024; resourceID = IDS_UNITS_GB; if (numberMB < 100) { decimal = TRUE; } } // load the "units" string from resources TCHAR units[30]; EH_ASSERT(LoadString(hResource, resourceID, units, sizeof(units)/sizeof(TCHAR))); // convert to a string, putting commas in if needed TCHAR tmpBuffer[256]; CommafyNumberFloat(numberMB, decimal, tmpBuffer, sizeof(tmpBuffer) / sizeof(TCHAR)); // concat a spacer _tcscat(tmpBuffer, TEXT(" ")); // concat the units _tcscat(tmpBuffer, units); // write the number and units to the text block _tcscpy(buffer, tmpBuffer); return _tcslen(buffer); } /*************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. DESCRIPTION: This takes the source string and works from right to left, copying chars from the source to the target, adding commas every third character DATA STRUCTURES: None. GLOBALS: None. INPUT: RETURN: Pointer to buffer with commafied number or NULL if error */ PTCHAR CommafyNumber( LONGLONG number, PTCHAR stringBuffer, UINT stringBufferLength ) { EN_ASSERT(stringBuffer); EN_ASSERT(stringBufferLength); TCHAR sourceString[256]; TCHAR targetString[256]; TCHAR tcThousandsSep[2] = {TEXT(','), 0}; struct lconv *locals = localeconv(); if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) { _stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep)); } UINT uGrouping = 0; if (locals && (locals->grouping)) { uGrouping = atoi(locals->grouping); } if(uGrouping == 0) { uGrouping = 3; //default value if its not supported } // convert LONGLONG number to a Unicode string _stprintf(sourceString, TEXT("%I64d"), number); // point the source pointer at the null terminator PTCHAR pSource = sourceString + _tcslen(sourceString); // put the target pointer at the end of the target buffer PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1; // write the null terminator *pTarget = NULL; for (UINT i=0; i<_tcslen(sourceString); i++) { if (i>0 && i%uGrouping == 0) { pTarget--; *pTarget = tcThousandsSep[0]; } pTarget--; pSource--; *pTarget = *pSource; } if (stringBufferLength > _tcslen(pTarget)){ _tcscpy(stringBuffer, pTarget); } else{ _tcscpy(stringBuffer, TEXT("")); } return stringBuffer; } /*************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. DESCRIPTION: This takes the source string and works from right to left, copying chars from the source to the target, adding commas every third character DATA STRUCTURES: None. GLOBALS: None. INPUT: RETURN: Pointer to buffer with commafied number or NULL if error */ PTCHAR CommafyNumberFloat( double number, BOOL bDecimal, PTCHAR stringBuffer, UINT stringBufferLength ) { EN_ASSERT(stringBuffer); EN_ASSERT(stringBufferLength); TCHAR sourceString[256]; TCHAR targetString[256]; TCHAR tcThousandsSep[2] = {TEXT(','), 0}; struct lconv *locals = localeconv(); if (locals && (locals->thousands_sep) && (*(locals->thousands_sep) != 0)) { _stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep)); } UINT uGrouping = 0; if (locals && (locals->grouping)) { uGrouping = atoi(locals->grouping); } if(uGrouping == 0) { uGrouping = 3; //default value if its not supported } if (bDecimal) { // convert double number to a Unicode string _stprintf(sourceString, TEXT("%0.02f"), number); } else { // convert double number to a Unicode string _stprintf(sourceString, TEXT("%0.0f"), number); } // point the source pointer at the null terminator PTCHAR pSource = sourceString + _tcslen(sourceString); // put the target pointer at the end of the target buffer PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1; // write the null terminator *pTarget = NULL; if (bDecimal) { for (UINT j = 0; j < 3; j++) { pTarget--; pSource--; *pTarget = *pSource; } } for (UINT i=0; i<_tcslen(sourceString)-(bDecimal ? 3 : 0); i++) { if (i>0 && i%uGrouping == 0) { pTarget--; *pTarget = tcThousandsSep[0]; } pTarget--; pSource--; *pTarget = *pSource; } if (stringBufferLength > _tcslen(pTarget)){ _tcscpy(stringBuffer, pTarget); } else{ _tcscpy(stringBuffer, TEXT("")); } return stringBuffer; } /*************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. DESCRIPTION: DATA STRUCTURES: None. GLOBALS: None. INPUT: RETURN: */ BOOL CTextBlock::StoreFile( IN TCHAR* cStoreFileName, IN DWORD dwCreate ) { HANDLE hFileHandle = NULL; SECURITY_ATTRIBUTES saSecurityAttributes; SECURITY_DESCRIPTOR sdSecurityDescriptor; ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR)); saSecurityAttributes.nLength = sizeof (saSecurityAttributes); saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor; saSecurityAttributes.bInheritHandle = FALSE; if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) { return FALSE; } // Create a new file for this text hFileHandle = CreateFile( cStoreFileName, GENERIC_WRITE, 0, // no sharing &saSecurityAttributes, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL); CleanupSecurityAttributes(&saSecurityAttributes); ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR)); // No error handling here! The calling function may wish // to handle different situations in different ways. Save the error. if(hFileHandle == INVALID_HANDLE_VALUE) { return FALSE; } DWORD dwWriteCount; // Total bytes written during WriteFile DWORD dwByteCount = _tcslen(m_pText) * sizeof(TCHAR); // The hex pattern FFFE must be the first 2 characters of a Unicode text file char unicodeMarker[3]; unicodeMarker[0] = '\xFF'; unicodeMarker[1] = '\xFE'; unicodeMarker[2] = NULL; // write the Unicode marker EF(WriteFile(hFileHandle, unicodeMarker, 2, &dwWriteCount, NULL)); // write the rest of the text block EF(WriteFile(hFileHandle, m_pText, dwByteCount, &dwWriteCount, NULL)); CloseHandle(hFileHandle); // Make sure we wrote the correct amount. if (dwByteCount == dwWriteCount) return TRUE; return FALSE; } /***************************************************************************************************************** COPYRIGHT© 2001 Microsoft Corporation and Executive Software International, Inc. ROUTINE DESCRIPTION: GLOBAL VARIABLES: None INPUT: None RETURN: None */ void CTextBlock::WriteToBufferAndPad( PTCHAR buffer, UINT length ) { // concat and pad onto text buffer m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%s"), buffer); char outputBuffer[300]; int ret = WideCharToMultiByte( GetACP(), //CP_ACP, 0, buffer, -1, outputBuffer, sizeof(outputBuffer), NULL, NULL); if (((int)length - (int)strlen(outputBuffer)) > 0) { m_pEndOfBuffer += _stprintf(m_pEndOfBuffer, TEXT("%-*s"), length - strlen(outputBuffer), TEXT("")); } }