Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / MFC

The Ultimate TCP/IP Home Page

Rate me:
Please Sign up or sign in to vote.
4.98/5 (77 votes)
25 Aug 2007CPOL13 min read 2.6M   45.4K   267  
Ultimate TCP-IP is now Open Source
//=================================================================
//  class: CUH_Control
//  file:  uh_ctrl.cpp
//
//  Purpose:
//
//   Ultimate History - Output Window and Logging Control
//
// ===================================================================
// Ultimate TCP/IP v4.2
// 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"

#include "uh_ctrl.h"
#include "ut_strop.h"

// Suppress warnings for non-safe str fns. Transitional, for VC6 support.
#pragma warning (push)
#pragma warning (disable : 4996 )

// these do not exist in core VC6 
#if _MSC_VER < 1400
#if !defined ULONG_PTR
#define ULONG_PTR DWORD
#define LONG_PTR DWORD
#endif
#endif

/**********************************
Constructor
***********************************/
CUH_Control::CUH_Control(){
    
    //setup the critical section variable
    #ifdef UH_THREADSAFE
    InitializeCriticalSection(&m_criticalSection);
    #endif

    //logging variables
    m_logName       = NULL;
    m_enableLog     = FALSE;
    m_timeStampedLog= FALSE;
    m_logDay        = 0;
    m_logMonth      = 0;
    m_logYear       = 0;
    m_fileHandle    = NULL;

    //window handle
    m_hWnd          = NULL;

    //display properties
    m_textColor     = GetSysColor(COLOR_WINDOWTEXT);
    m_backColor     = GetSysColor(COLOR_WINDOW);
    m_alignment     = TA_LEFT;
    m_margin        = 2;
    
    //setup the font
	m_font = NULL;
    SetFont(NULL);
    
    //history list variables
    m_historyList       = NULL;
    m_historyListMaxLen = 0;
    m_HLCurrentPosPtr   = NULL;
    m_HLCurrentPos      = -1;
    m_HLEndPosPtr       = NULL;
    m_HLEndPos          = -1;

    //scrollbar variables
    m_vScrollRange      = 0;
    m_vScrollPos        = 0;
    m_hScrollRange      = 0;                                             
    m_hScrollPos        = 0;
    m_vScrollPageSize   = 0;
    m_hScrollPageSize   = 0;

    //max line width
    m_maxLineWidth = 0;

    //datestamp to string format
    m_DateFormatString = NULL;
    SetTimeStampFormat(_T("%X"));
}
/**********************************
Destructor
***********************************/
CUH_Control::~CUH_Control(){

    ClearHistory();

    if(m_font)
        DeleteObject(m_font);

    if(m_hWnd != NULL)
        DestroyWindow(m_hWnd);

    if(m_DateFormatString != NULL)
        delete[] m_DateFormatString;
    if(m_logName != NULL)
        delete[] m_logName;


    CloseLog();

    //release the critical section
    #ifdef UH_THREADSAFE
    DeleteCriticalSection(&m_criticalSection);
    #endif
}

/**********************************
CreateHistoryWindow
    Creates a window to be associated
    with the history control
Params
    parent - parent window handle
    style - window style
    rect - inital size and position
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::CreateHistoryWindow(HWND parent,DWORD style,RECT &rect){

    if(parent == NULL)
        return UH_ERROR;

    #ifdef WIN32
        HINSTANCE hInstance = (HINSTANCE)(ULONG_PTR)GetWindowLong(parent,GWL_HINSTANCE);
    #else
        HINSTANCE hInstance = (HINSTANCE)GetWindowWord(parent,GWW_HINSTANCE);
    #endif

    WNDCLASS wndclass;

    //if the window class is not yet registered then register it
    if(GetClassInfo(hInstance,_T("CUH_Control"),&wndclass)==FALSE)
        RegisterWindowClass(hInstance);

    //create the window
    m_hWnd = CreateWindow(_T("CUH_Control"),_T(""),style,
                rect.left,rect.top,
                rect.right - rect.left,
                rect.bottom - rect.top,
                parent,
                NULL,
                hInstance,
                NULL);
    
    if(m_hWnd == NULL)
        return UH_ERROR;

    SendMessage(m_hWnd,UH_SET_THIS_PTR,0,(LPARAM)this);

    return UH_SUCCESS;
}

/**********************************
AttachHistoryWindow
    Attaches the CUH_Control class to an existing
    window (of "CUH_Control" type). This function 
    is usually used to attach this class to a 
    child control from a dialog
Params 
    parent - parent window handle
    ID - id number of the child control to attach to
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::AttachHistoryWindow(HWND parent,UINT ID){

    if(parent == NULL)
        return UH_ERROR;

    m_hWnd = GetDlgItem(parent,ID);
    
    if(m_hWnd == NULL)
        return UH_ERROR;

    SendMessage(m_hWnd,UH_SET_THIS_PTR,0,(LPARAM)this);

    //get the number of screen lines
    RECT rect;
    GetClientRect(m_hWnd,&rect);
    m_vScrollPageSize = (rect.bottom / m_fontHeight);
    m_hScrollPageSize = (rect.right / m_fontWidth);
    SetHistoryLength(m_historyListMaxLen);

    return UH_SUCCESS;
}

/**********************************
RegisterWindowClass
    Registers a window class of type 'CUH_Control'
    so that it can be used in dialog boxes
Params
    hInstance - program instance handle
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::RegisterWindowClass(HINSTANCE hInstance){


    WNDCLASS wndclass;

    //register this new window class
    wndclass.style          = CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS;
    wndclass.lpfnWndProc    = WndProc;
    wndclass.cbClsExtra     = 0 ;
    wndclass.cbWndExtra     = 20;
    wndclass.hInstance      = hInstance ;
    wndclass.hIcon          = NULL;
    wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground  = NULL;
    wndclass.lpszMenuName   = NULL;
    wndclass.lpszClassName  = _T("CUH_Control");

    RegisterClass(&wndclass);

    if(GetClassInfo(hInstance,_T("CUH_Control"),&wndclass))
        return UH_SUCCESS;
    return UH_ERROR;
}

/**********************************
WndProc
    Internal Function
    Window procedure that distributes
    all window messages for windows of
    type 'CUH_Control' it then dispatches
    the messages to the class that is attached
    to the window
Params
    n/a
Return
    n/a
***********************************/
long CALLBACK CUH_Control::WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){

    switch(message){
        case WM_NCCREATE:{
            SetWindowLong(hwnd,0,(LPARAM)NULL);
            return 1;
        }
        case UH_SET_THIS_PTR:{
            //store the pointer to the calling class
            // CUH_Control *_this = (CUH_Control*)lParam;
            SetWindowLong(hwnd,0,(LONG)lParam);
            return 1;
        }
    }

    //get the pointer to the calling class
    CUH_Control *_this = (CUH_Control*)(ULONG_PTR)GetWindowLong(hwnd,0);

    //call the functions that match in incoming message
    if(_this != NULL){
        switch(message){
			case WM_KEYDOWN:
				if(_this->OnKeyDown((int)wParam) == TRUE)
					return 0;
				break;
            case WM_PAINT:
                _this->OnPaint();
                return 0;
            case WM_SIZE:
                _this->OnSize();
                return 0;
            case WM_NCDESTROY:
                _this->m_hWnd = NULL;
                return 0;
            case WM_HSCROLL:
                #ifdef WIN32
                _this->OnHScroll(LOWORD(wParam),HIWORD(wParam));
                #else
                _this->OnHScroll(wParam,LOWORD(lParam));
                #endif
                return 0;
            case WM_VSCROLL:
                #ifdef WIN32
                _this->OnVScroll(LOWORD(wParam),HIWORD(wParam));
                #else
                _this->OnVScroll(wParam,LOWORD(lParam));
                #endif
                return 0;
            case WM_MOUSEACTIVATE:
                SetFocus(_this->m_hWnd);
                break;
            case WM_ERASEBKGND:
                return 1;
        }
    }
    
    return (long)DefWindowProc(hwnd,message,wParam,lParam);
}

/**********************************
OnPaint
    Internal function
    This routine paints the window.
    It displays the current history
    items
Params
    none
Return 
    none
***********************************/
void CUH_Control::OnPaint(){

    if(m_hWnd ==  NULL)
        return;

    //start from the bottom of the rect and work up
    RECT rect,rect2;
    GetClientRect(m_hWnd,&rect);
    CopyRect(&rect2,&rect);
	UINT	nFormat;

    //get hte device context
    PAINTSTRUCT ps;
    HDC dc = BeginPaint(m_hWnd, &ps);

    HFONT oldFont = NULL;
    if(m_font != NULL)
        oldFont = (HFONT)SelectObject(dc,m_font);

    if(m_historyList != NULL){

		// Enter into a critical section
		#ifdef UH_THREADSAFE
		EnterCriticalSection(&m_criticalSection);
		#endif

        //if the scrollbar range is zero then draw from the top
        if(m_vScrollRange ==0){
            rect2.top =0;
            rect2.bottom =0;
            UH_HistoryList *next = m_HLEndPosPtr;
            int margin = m_margin-(m_hScrollPos * m_fontWidth);
            for(int t = m_HLEndPos; t >= 0  && next != NULL; t--){
                rect2.bottom += m_fontHeight;

				::SetTextColor(dc, (next->m_textColor == 0xFFFFFFFF) ? m_textColor : next->m_textColor);
                SetBkColor(dc, (next->m_backColor == 0xFFFFFFFF) ? m_backColor : next->m_backColor);
				
				ExtTextOut(dc,0,0,ETO_CLIPPED|ETO_OPAQUE, &rect2, NULL, 0,NULL);
				RECT	rect3;								
				CopyRect(&rect3, &rect2);

				if(m_alignment == TA_CENTER) {
					rect3.left += margin/2;
					nFormat = DT_CENTER;
					}
				else if(m_alignment == TA_RIGHT) {
					rect3.right -= margin;
					nFormat = DT_RIGHT;
					}
				else {
					rect3.left += margin;
					nFormat = DT_LEFT;
					}

                DrawText(dc, next->m_string, next->m_len, &rect3, DT_EXPANDTABS | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP | nFormat);


                next = next->m_prev;
                rect2.top = rect2.bottom;
            }
            rect2.bottom = rect.bottom;
            SetBkColor(dc, m_backColor);
            ExtTextOut(dc,rect2.left,rect2.top,ETO_OPAQUE,&rect2,_T(""),0,NULL);
        }
        else{
            rect2.top = rect.bottom;
            rect2.bottom = rect.bottom;
            
            int margin = m_margin-(m_hScrollPos * m_fontWidth);
            int pos = m_vScrollRange - m_vScrollPos;
            if(m_HLCurrentPos != pos)
                SetCurrentPosPtr(pos);
            UH_HistoryList *next = m_HLCurrentPosPtr;
            for(int t = pos ;t <= m_HLEndPos && next != NULL; t++) {
                rect2.top -= m_fontHeight;

				::SetTextColor(dc, (next->m_textColor == 0xFFFFFFFF) ? m_textColor : next->m_textColor);
                SetBkColor(dc, (next->m_backColor == 0xFFFFFFFF) ? m_backColor : next->m_backColor);

				ExtTextOut(dc,0,0,ETO_CLIPPED|ETO_OPAQUE, &rect2, NULL, 0,NULL);
				RECT	rect3;								
				CopyRect(&rect3, &rect2);

				if(m_alignment == TA_CENTER) {
					rect3.left += margin/2;
					rect3.right -= margin/2;
					nFormat = DT_CENTER;
					}
				else if(m_alignment == TA_RIGHT) {
					rect3.right -= margin;
					nFormat = DT_RIGHT;
					}
				else {
					rect3.left += margin;
					nFormat = DT_LEFT;
					}

                DrawText(dc, next->m_string, next->m_len, &rect3, DT_EXPANDTABS | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP | nFormat);


                next = next->m_next;
                rect2.bottom = rect2.top;
                if(rect2.bottom <0)
                    break;
            }
            rect2.top = rect.top;
            SetBkColor(dc,m_backColor);
            ExtTextOut(dc,rect2.left,rect2.top,ETO_OPAQUE,&rect2,_T(""),0,NULL);
        }

	//exit the critical section
    #ifdef UH_THREADSAFE
    LeaveCriticalSection(&m_criticalSection);
    #endif

    }
    else{
        SetBkColor(dc,m_backColor);
        ExtTextOut(dc,0,0,ETO_OPAQUE,&rect,_T(""),0,NULL);
    }
    //clean -up
    if(m_font != NULL)
        SelectObject(dc,oldFont);

    EndPaint(m_hWnd,&ps);
}

/**********************************
OnSize
    Internal function
    This routine is called when the
    window sizes. It will also check to
    see if the scrollbars should be
    displayed
Params
    none
Return 
    none
***********************************/
void CUH_Control::OnSize(){
    
    if(m_hWnd ==  NULL)
        return;
    
    //get the number of screen lines
    RECT rect;
    GetClientRect(m_hWnd,&rect);
    m_vScrollPageSize = (rect.bottom / m_fontHeight);
    m_hScrollPageSize = (rect.right / m_fontWidth);

    SetHistoryLength(m_historyListMaxLen);
}

/**********************************
OnKeyDown
    Process scrolling through keyboard
Params
    nKeyCode	- key scan code
Return 
    TRUE		- if we process this key
***********************************/
BOOL CUH_Control::OnKeyDown(int nKeyCode) {
	
	switch(nKeyCode) {
		case(VK_DOWN):
			OnVScroll(SB_LINEDOWN, 0);
			break;
		case(VK_UP):
			OnVScroll(SB_LINEUP, 0);
			break;
		case(VK_NEXT):
			OnVScroll(SB_PAGEDOWN, 0);
			break;
		case(VK_PRIOR):
			OnVScroll(SB_PAGEUP, 0);
			break;
		case(VK_LEFT):
			OnHScroll(SB_LINEUP, 0);
			break;
		case(VK_RIGHT):
			OnHScroll(SB_LINEDOWN, 0);
			break;
		default:
			return FALSE;
		}

	return TRUE;
}

/**********************************
UpdateScrollRange
    Internal function
    This function calcs the scrollbar
    ranges
Params
    none
Return 
    none
***********************************/
void CUH_Control::UpdateScrollRange(){
    
    if(m_hWnd == NULL)
        return;

    //update the vertical scrollbar
    int offset = m_vScrollRange - m_vScrollPos;

    m_vScrollRange = m_HLEndPos - m_vScrollPageSize +1; 
    if(m_vScrollRange <0)
        m_vScrollRange = 0;
    
    m_vScrollPos = m_vScrollRange - offset;
    if(m_vScrollPos <0)
        m_vScrollPos = 0;
    
    SetScrollRange(m_hWnd,SB_VERT,0,m_vScrollRange,FALSE);
    SetScrollPos(m_hWnd,SB_VERT,m_vScrollPos,TRUE);

    //update the horizontal scrollbar
    m_hScrollRange = m_maxLineWidth - m_hScrollPageSize+1;
    if(m_hScrollPos > m_hScrollRange)
        m_hScrollPos = m_hScrollRange;
    if(m_hScrollPos <0)
        m_hScrollPos = 0;
    SetScrollRange(m_hWnd,SB_HORZ,0,m_hScrollRange,FALSE);
    SetScrollPos(m_hWnd,SB_HORZ,m_hScrollPos,TRUE);
    
}

/**********************************
OnVScroll
    Internal function
    This function processes vertical
    scrollbar messages and scrolls 
    the history window contents
Params
    n/a
Return
    none
***********************************/
void CUH_Control::OnVScroll(int code,int pos){
    
    int oldPos = m_vScrollPos;

    switch(code){
        case SB_LINEDOWN:
            m_vScrollPos++;
            break;
        case SB_LINEUP:
            m_vScrollPos--;
            break;
        case SB_PAGEDOWN:
            m_vScrollPos += m_vScrollPageSize;
            break;
        case SB_PAGEUP:
            m_vScrollPos -= m_vScrollPageSize;
            break;
        case SB_THUMBTRACK:
        case SB_THUMBPOSITION:
            m_vScrollPos = pos;
            break;
    }

    //check to see if the position has changed
    if(oldPos != m_vScrollPos){
        //range checking
        if(m_vScrollPos > m_vScrollRange)
            m_vScrollPos = m_vScrollRange;
        if(m_vScrollPos <0)
            m_vScrollPos = 0;
        SetScrollPos(m_hWnd,SB_VERT,m_vScrollPos,TRUE);
        
        //redraw the screen
        SetCurrentPosPtr(m_vScrollRange - m_vScrollPos);
        InvalidateRect(m_hWnd,NULL,TRUE);
    }
}

/**********************************
OnVScroll
    Internal function
    This function processes horizontal
    scrollbar messages and scrolls 
    the history window contents
Params
    n/a
Return
    none
***********************************/
void CUH_Control::OnHScroll(int code,int pos){

    int oldPos = m_hScrollPos;

    switch(code){
        case SB_LINEDOWN:
            m_hScrollPos++;
            break;
        case SB_LINEUP:
            m_hScrollPos--;
            break;
        case SB_PAGEDOWN :
            m_hScrollPos += m_hScrollPageSize;
            break;
        case SB_PAGEUP:
            m_hScrollPos -= m_hScrollPageSize;
            break;
        case SB_THUMBTRACK:
        case SB_THUMBPOSITION:
            m_hScrollPos = pos;
            break;
    }

    //check to see if the position has changed
    if(oldPos != m_hScrollPos){
        //range checking
        if(m_hScrollPos > m_hScrollRange)
            m_hScrollPos = m_hScrollRange;
        if(m_hScrollPos <0)
            m_hScrollPos = 0;
        SetScrollPos(m_hWnd,SB_HORZ,m_hScrollPos,TRUE);
        //redraw the screen
        InvalidateRect(m_hWnd,NULL,TRUE);
    }
}

/**********************************
SetFont
    Sets the font to use when new 
    lines are added to the history list
Params
    hont - handle to a font
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetFont(HFONT font){

    SIZE size;
    HFONT   oldFont = NULL;

	if(m_font != NULL && font != NULL)
        DeleteObject(m_font);

    m_font = font;

    //get the font height
    if(m_hWnd != NULL){
        HDC dc = GetDC(m_hWnd);
        if(m_font != NULL)
            oldFont = (HFONT)SelectObject(dc,m_font);
        GetTextExtentPoint(dc,_T("X"),1,&size);
        if(m_font != NULL)
            SelectObject(dc,oldFont);
        ReleaseDC(m_hWnd,dc);
    }
    else{
        HDC dc = GetDC(NULL);
        if(m_font != NULL)
            oldFont = (HFONT)SelectObject(dc,m_font);
        GetTextExtentPoint(dc,_T("X"),1,&size);
        if(m_font != NULL)
            SelectObject(dc,oldFont);
        ReleaseDC(NULL,dc);
    }

    //store the font height
    m_fontHeight = size.cy;
    m_fontWidth = size.cx;

    //get the number of screen lines
    if(m_hWnd != NULL){
        RECT rect;
        GetClientRect(m_hWnd,&rect);
        m_vScrollPageSize = (rect.bottom / m_fontHeight);
        m_hScrollPageSize = (rect.right / m_fontWidth);
        SetHistoryLength(m_historyListMaxLen);
    }

    return UH_SUCCESS;
}

/**********************************
SetCurrentPosPtr
    Internal function
    Sets the current position within 
    the history linked list
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
void CUH_Control::SetCurrentPosPtr(int pos){
    
    if(m_HLCurrentPosPtr == NULL)
        return;

    while(m_HLCurrentPos <pos){
        if(m_HLCurrentPosPtr->m_next == NULL)
            break;
        m_HLCurrentPosPtr = m_HLCurrentPosPtr->m_next;
        m_HLCurrentPos++;
    }
    while(m_HLCurrentPos > pos){
        if(m_HLCurrentPosPtr->m_prev == NULL)
            break;
        m_HLCurrentPosPtr = m_HLCurrentPosPtr->m_prev;
        m_HLCurrentPos--;
    }
}

/**********************************
GetHistoryLength
    Gets the minimum number of items
    that the history list can hold
Params
    none
Return
    mimimum number of items
***********************************/
int CUH_Control::GetHistoryLength() const
{
	return m_historyListMaxLen;
}
/**********************************
SetHistoryLength
    Sets the minimum number of items
    that the history list can hold
Params
    len - mimimum number of items
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetHistoryLength(int len){

    //make sure the min history length is the 
    //number of items visible on the screen
    if(m_hWnd != NULL){
        RECT rect;
        GetClientRect(m_hWnd,&rect);
        //get the number of screen lines
        int screenLen = (rect.bottom / m_fontHeight);
        if(len < screenLen)
            len = screenLen;
    }   

    //if the list length is zero then just clear it
    if(len == 0){
        ClearHistory();
        m_historyListMaxLen = 0;
    }
    else{
        
        m_historyListMaxLen = len;

        //if the current position is now out of range, re-adjust
        while(m_HLCurrentPos >= m_historyListMaxLen){
            if(m_HLCurrentPosPtr->m_prev != NULL){
                m_HLCurrentPosPtr = m_HLCurrentPosPtr->m_prev;
                m_HLCurrentPos --;
            }
        }

        //delete any items out of range
        UH_HistoryList *prev = NULL;
        while(m_HLEndPos >= m_historyListMaxLen){
            if(m_HLEndPosPtr != NULL){
                if(m_HLEndPosPtr->m_string != NULL)
                    delete[] m_HLEndPosPtr->m_string;
                prev = m_HLEndPosPtr->m_prev;
                prev = m_HLEndPosPtr->m_next = NULL;
                delete m_HLEndPosPtr;           
            }   

            m_HLEndPosPtr = prev;
        }
        UpdateScrollRange();
    }

    return UH_SUCCESS;
}

/**********************************
SetAligment
    Sets text alignment
Params
    alignment - new alignment
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetAlignment(int alignment){
    m_alignment = alignment;
    return UH_SUCCESS;
}
/**********************************
GetAligment
    Gets text alignment
Params
    none
Return
	alignment
***********************************/
int CUH_Control::GetAlignment() const
{
    return m_alignment;
}


/**********************************
SetTextColor
    Sets the text color to use when 
    new lines are added to the history
    list
Params
    color - new text color to use
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetTextColor(COLORREF color){

    m_textColor = color;

    return UH_SUCCESS;
}

/**********************************
SetBackColor
    Sets the backgorund color to use when 
    new lines are added to the history
    list
Params
    color - new back color to use
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)

***********************************/
int CUH_Control::SetBackColor(COLORREF color){
    
    m_backColor = color;
    return UH_SUCCESS;
}

/**********************************
GetTextColor
    Gets the text color to use when 
    new lines are added to the history
    list
Params
    color - new text color to use
Return
    text color
***********************************/
COLORREF CUH_Control::GetTextColor() const
{
    return m_textColor;
}

/**********************************
GetBackColor
    Gets the backgorund color to use when 
    new lines are added to the history
    list
Params
    color - new back color to use
Return
    back color
***********************************/
COLORREF CUH_Control::GetBackColor() const
{
    return m_backColor;
}
/**********************************
SetMargin
    Sets the new margin to use when 
    new lines are added to the history
    list
Params
    margin - margin in pixels
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetMargin(int margin){

    m_margin = margin;
    return UH_SUCCESS;
}

/**********************************
GetMargin
    Gets the new margin to use when 
    new lines are added to the history
    list
Params
    none
Return
    margin - margin in pixels
***********************************/
int CUH_Control::GetMargin() const
{
    return m_margin;
}
/**********************************
SetLogName
    Sets the filename of the log file.
    If date stamping is enabled then
    then date stamp will be instered just
    be for the extenion in the filename
Params
    logName - file name (plus optional
        path)
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::SetLogName(LPCTSTR logName){
    
    int rt = UH_SUCCESS;

    int len = (int)_tcslen(logName);

    if(len <1 || len > 255){
        rt  =  UH_ERROR;
    }
    else{
        if(m_logName != NULL)
            delete[] m_logName;
        
        m_logName = new _TCHAR[len+1];
        _tcscpy(m_logName,logName);
    }

    return rt;
}
/**********************************
SetLogName
    Sets the filename of the log file.
    If date stamping is enabled then
    then date stamp will be instered just
    be for the extenion in the filename
Params
	none
Return
    log file name
***********************************/
LPCTSTR CUH_Control::GetLogName() const
{
    return m_logName;
}

/**********************************
EnableLog
    Turn file logging on and off
Params
    yesNo - TRUE to enable FALSE to disable
        Disable is default
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::EnableLog(BOOLEAN yesNo){
    
    if(yesNo){
        m_enableLog = TRUE;
        OpenLog();
    }
    else{
        m_enableLog = FALSE;
        CloseLog();
    }

    return UH_SUCCESS;
}

/**********************************
IsLogEnabled
    Turn file logging on and off
Params
    none
Return
	TRUE/FALSE
***********************************/
BOOL CUH_Control::IsLogEnabled() const
{
     return m_enableLog;
}


/**********************************
EnableTimeStampedLog
    Turns date stamped log file naming on and
    off. If on then a new file will be created
    whenever the system date changes. This way
    a new file will be created every 24 hours.
    The date stamp is interted into the log file
    name just before the filename extention.
Params
    yesNo - TRUE to enable , FALSE to disable
        Disable is default
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::EnableTimeStampedLog(BOOLEAN yesNo){

    if(yesNo)
        m_timeStampedLog = TRUE;
    else
        m_timeStampedLog = FALSE;

    return UH_SUCCESS;
}
/**********************************
EnableTimeStampedLog
	Return time stamp enabled flag
Params
	none	
Return
    Log time stamp enabled flag
***********************************/
BOOL CUH_Control::IsTimeStampedLogEnabled() const
{
    return m_timeStampedLog;
}

/**********************************
AddLine
    Adds a new line to the control.
    If logging is on and the addToLog
    param is TRUE then this line is also
    added to the log file.
Params
    string - string to add
    addToLog - if TRUE then add to the file
        log, if it is enabled
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::AddLine(LPCTSTR string, COLORREF TextColor, COLORREF BackColor, BOOLEAN addToLog){
    
    //enter into a critical section
    #ifdef UH_THREADSAFE
    EnterCriticalSection(&m_criticalSection);
    #endif

    //update the log file
    if(addToLog && m_enableLog)
        WriteToLog(string,TRUE);

    //check to see if a window exists
	int updateScrollFlag = FALSE;
    if(m_hWnd != NULL){
        UH_HistoryList *old = m_historyList;

        m_historyList = new UH_HistoryList;
        m_historyList->m_next =old;
        m_historyList->m_prev = NULL;
        m_historyList->m_textColor = TextColor;
        m_historyList->m_backColor = BackColor;

        if(old != NULL)
            old->m_prev = m_historyList;
    
        int len = (int)_tcslen(string);
        if(len == 0) {
            m_historyList->m_string = new _TCHAR[1];
            m_historyList->m_string = 0;
            m_historyList->m_len =0;
        }
        else{
			m_historyList->m_string = new _TCHAR[len+1];
            _tcscpy(m_historyList->m_string,string);
// TD TODO			CUT_StrMethods::RemoveCRLF(m_historyList->m_string);
            m_historyList->m_len = (int)_tcslen(m_historyList->m_string);
        }

        //store the max line width
        if(len > m_maxLineWidth){
            m_maxLineWidth = len;
            updateScrollFlag = TRUE;
        }

        //adjust the current pos
        if(m_HLCurrentPosPtr != NULL)
            m_HLCurrentPosPtr = m_HLCurrentPosPtr->m_prev;
        else{
            m_HLCurrentPosPtr = m_historyList;
            m_HLCurrentPos = 0;
        }

        //cut items off the end - if reached
        if(m_HLEndPosPtr != NULL){
            if(m_HLEndPos == m_historyListMaxLen -1){
                UH_HistoryList *old = m_HLEndPosPtr;
                m_HLEndPosPtr = m_HLEndPosPtr->m_prev;
                m_HLEndPosPtr->m_next = NULL;
            
                //if this is the longest line
                //then find the new longest line
                if(old->m_len == m_maxLineWidth){
                    UH_HistoryList *check = old->m_prev;
                    m_maxLineWidth = 0;
                    while(check != NULL){
                        if(m_maxLineWidth < check->m_len)
                            m_maxLineWidth = check->m_len;
                        check = check->m_prev;
                    }
                    updateScrollFlag = TRUE;
                }
                if(old->m_string!= NULL)
                    delete[]old->m_string;
                delete old;
            }
            else{
                m_HLEndPos ++;
                updateScrollFlag = TRUE;
            }
        }
        else{
            m_HLEndPosPtr = m_historyList;
            m_HLEndPos = 0;
        }

    }

    //exit the critical section
    #ifdef UH_THREADSAFE
    LeaveCriticalSection(&m_criticalSection);
    #endif

	if(m_hWnd != NULL) {
        //update the scrollbar
        if(updateScrollFlag)
            UpdateScrollRange();

        //redraw the screen
        InvalidateRect(m_hWnd,NULL,TRUE);
		}

    return UH_SUCCESS;
}

/**********************************
AddStampedLine
    Adds a new line to the control with
    a time stamp added to the beginning
    of the line.
    If logging is on and the addToLog
    param is TRUE then this line is also
    added to the log file.
Params
    string - string to add
    addToLog - if TRUE then add to the file
        log, if it is enabled
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::AddStampedLine(LPCTSTR string, COLORREF TextColor, COLORREF BackColor, BOOLEAN addToLog){

    //enter into a critical section
    #ifdef UH_THREADSAFE
    EnterCriticalSection(&m_criticalSection);
    #endif

    int len = (int)_tcslen(string);
    _TCHAR *buf = new _TCHAR[len+25];

    GetTimeDateStamp(buf,len+25);
    _tcscat(buf,_T(" "));
    _tcscat(buf,string);
    int rt = AddLine(buf,TextColor, BackColor, addToLog);
    delete[] buf;

    //exit the critical section
    #ifdef UH_THREADSAFE
    LeaveCriticalSection(&m_criticalSection);
    #endif

    return rt;
}

/**********************************
AppendToLine
    Appends more information to the last 
    line added.
    If logging is on and the addToLog
    param is TRUE then this line is also
    added to the log file.
Params
    string - string to add
    addToLog - if TRUE then add to the file
        log, if it is enabled
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::AppendToLine(LPCTSTR string,BOOLEAN addToLog){

    
    //enter into a critical section
    #ifdef UH_THREADSAFE
    EnterCriticalSection(&m_criticalSection);
    #endif

    int rt = UH_SUCCESS;

    if(m_historyList == NULL){
        rt = UH_ERROR;
    }
    else if(m_historyList->m_string == NULL){
        rt = UH_ERROR;
    }       
    else{
        //update the log file
        if(addToLog && m_enableLog)
            WriteToLog(string,FALSE);

        //check to see if a window exists
        if(m_hWnd != NULL){

            int len = (int)_tcslen(string) + (int)_tcslen(m_historyList->m_string);
            _TCHAR *buf = new _TCHAR[len+1];
            _tcscpy(buf,m_historyList->m_string);
            _tcscat(buf,string);
    
            delete[] m_historyList->m_string;
            m_historyList->m_string = buf;
            m_historyList->m_len = len;

            //store the max line width
            if(len > m_maxLineWidth){
                m_maxLineWidth = len;
                UpdateScrollRange();
            }
            //redraw the screen
            InvalidateRect(m_hWnd,NULL,TRUE);
        }
    }

    //exit the critical section
    #ifdef UH_THREADSAFE
    LeaveCriticalSection(&m_criticalSection);
    #endif

    return rt;
}

/**********************************
ClearHistory
    Clears all items from the history
    list
Params
    none
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************/
int CUH_Control::ClearHistory(){

    //enter into a critical section
    #ifdef UH_THREADSAFE
    EnterCriticalSection(&m_criticalSection);
    #endif

    UH_HistoryList *current = m_historyList;
    UH_HistoryList *next;
    //delete the history list
    while(current != NULL){
        next= current->m_next;

        if(current->m_string != NULL)
            delete[] current->m_string;
        delete current;

        current = next;
    }
    m_historyList = NULL;
    m_HLCurrentPosPtr = NULL;
    m_HLCurrentPos = -1;
    m_HLEndPosPtr = NULL;
    m_HLEndPos = -1;
    
    m_maxLineWidth = 0;

    if(m_hWnd != NULL){
        UpdateScrollRange();
        InvalidateRect(m_hWnd,NULL,TRUE);
        SendMessage(m_hWnd,WM_PAINT,0,0);
    }

    //exit the critical section
    #ifdef UH_THREADSAFE
    LeaveCriticalSection(&m_criticalSection);
    #endif

    return UH_SUCCESS;
}

/**********************************************
GetTimeDateStamp
    Internal function
    Returns a string with a time stamp that includes
    the date.
Params
    string - buffer for the stamp to be put in
    len - length of the buffer
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************************/
int CUH_Control::GetTimeDateStamp(LPTSTR string,int len){

    if(len < 18)
        return UH_ERROR;

    //get the time/date
    time_t  t           = time(NULL);
    struct tm * systime = localtime(&t);
    
    //format the date into a string
    if(_tcsftime(string,len,m_DateFormatString,systime) == 0){
        string[0] =0;
        return UH_ERROR;
    }
    return UH_SUCCESS;
}

/**********************************************
SetTimeStampFormat
    Sets the format for stamped lines. See the
    information on the strftime function for 
    for full information on format strings
Params
    formatString - format mask for the time stamp
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************************/
int CUH_Control::SetTimeStampFormat(LPCTSTR formatString){

    int len = (int)_tcslen(formatString);

    if(len <1){
        return UH_ERROR;
    }

    if(m_DateFormatString != NULL)
        delete[] m_DateFormatString;

    m_DateFormatString = new _TCHAR[len+1];
    _tcscpy(m_DateFormatString,formatString);

    return UH_SUCCESS;
}
/**********************************************
GetTimeStampFormat
    Gets the format for stamped lines. See the
    information on the strftime function for 
    for full information on format strings
Params
    none
Return
    format mask for the time stamp
***********************************************/
LPCTSTR CUH_Control::GetTimeStampFormat() const
{
    return m_DateFormatString;
}

/**********************************************
OpenLog
    Internal function
    Opens up the history log file for writing.
Params
    none
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************************/
int CUH_Control::OpenLog(){
    
    CloseLog();

    if(m_timeStampedLog){
        //get the date string
        time_t  t           = time(NULL);
        struct tm * systime = localtime(&t);
        _TCHAR strDate[30];
        m_logDay    = systime->tm_mday;
        m_logMonth  = systime->tm_mon;
        m_logYear   = systime->tm_year;
        _sntprintf(strDate,sizeof(strDate)/sizeof(_TCHAR)-1,_T("%2.2d%2.2d%4.4d"),systime->tm_mday,systime->tm_mon+1,
            systime->tm_year+1900);
        
        //find the .
        int pos;
        int len = (int)_tcslen(m_logName);
        for(pos = 0; pos < len; pos++){
            if(m_logName[pos] == '.')
                break;
        }

        //add the date string just before the . in the filename
        _TCHAR * buf = new _TCHAR[len+10];
        _tcscpy(buf,m_logName);
        buf[pos] =0;
        _tcscat(buf,strDate);
        _tcscat(buf,&m_logName[pos]);

        m_fileHandle = _tfopen(buf,_T("a+"));

        delete[] buf;
    }
    else{
        m_fileHandle = _tfopen(m_logName,_T("a+"));
    }

    if(m_fileHandle == NULL)
        return UH_ERROR;

    return UH_SUCCESS;
}

/**********************************************
CloseLog
    Internal function
Params
    none
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************************/
int CUH_Control::CloseLog(){
    if(m_fileHandle != NULL)
        fclose(m_fileHandle);

    return UH_SUCCESS;
}

/**********************************************
WriteToLog
    Internal function
Params
    string - the string to write to the log
    newline - TRUE if a new line is to be added
        after the string
Return
    0 - (UH_SUCCESS)
    1 - (UH_ERROR)
***********************************************/
void CUH_Control::WriteToLog(LPCTSTR string,int newline){

    //check to see if the date has changed
    time_t  t  = time(NULL);
    struct tm * lt = localtime(&t);
    if(m_logDay != lt->tm_mday || m_logMonth != lt->tm_mon ||
      m_logYear != lt->tm_year){
        OpenLog();
    }
    
    if(m_fileHandle == NULL)
        return;

    if(newline)
        fwrite("\n",sizeof(char),1,m_fileHandle);
#if defined _UNICODE
	size_t size = _tcslen(string);
	char * buffA = (char*) alloca(size+1);
	*buffA = '\0';
	CUT_Str::cvtcpy(buffA, size, string);	// convert to ANSI
	fwrite(buffA,sizeof(char),_tcslen(string),m_fileHandle);
#else
	fwrite(string,sizeof(char),_tcslen(string),m_fileHandle);
#endif //_UNICODE
}

#if defined _UNICODE
int CUH_Control::AddLine(LPCSTR string, COLORREF TextColor, COLORREF BackColor, BOOLEAN addToLog)
{
	return AddLine(WC(string), TextColor, BackColor, addToLog);
}
int CUH_Control::AddStampedLine(LPCSTR string, COLORREF TextColor, COLORREF BackColor, BOOLEAN addToLog)
{
	return AddStampedLine(WC(string), TextColor, BackColor, addToLog);
}
int CUH_Control::AppendToLine(LPCSTR string, BOOLEAN addToLog)
{
	return AppendToLine(WC(string), addToLog); 
}
#endif

#pragma warning ( pop )

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions