开始我的第一个vc模块的设计。
这个是一个vc的写日志的类,为什么叫CLog3...因为之前有两版写log的类,但是都是用C#写的,所以这个vc写的就叫CLog3吧。
功能只是简单模拟C#中的写Log的方法的设计。
设计思路:
因为在程序运行过程中, 需要记录一些信息到log中, 同时要尽量减少对主处理模块的影响,减少i|o的操作,所以CLog3中设计的思路为自己创建一个Thread,该Thread会获取一个队列中的讯息,当要写一个讯息的时候, 将要写的信息添加到队列中,并通知Thread获取队列中的资料,写入已经打开的文件中。
因为在StartLog的时候,就已经将一个CFile对象打开了,所以减少了写是在Open的操作。
而调用方只是将要写的log扔到队列中,然后就可以继续处理自己的事情了,不用等待log写完后在处理,减少了对主模块的影响。
该开发环境是windows 2003 + vc.net 2005, 因为vc.net 2005中默认开启了Unicode 的模式,所以要写汉字到文件需要将CString转换成char * ,祥见: http://www.cnblogs.com/zhucl1006/archive/2008/01/02/1023380.html
Clog3.h

/**//* 一个写log的类
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#pragma once

#include <afxmt.h>
// CLog3 命令目标

class CLog3


{
public:
CLog3();
void Init(CString FilePath,CString FileName);
virtual ~CLog3();

public :
CString m_FilePath;
CString m_FileName;
DWORD m_Fileday;
CFile m_File;

HANDLE m_processStopHandle,m_processSignalHandle,m_processThreadHandle;

CStringList m_messageQueue;
CMutex m_mutex;

static void LogProcessorThread(LPVOID data);

void QueueMessage(CString szLogEntry);
void StartLog();
void StopLog();
void CrateLog(CString csFilePath,CString csFileName);



};





CLog3.cpp
//
//

/**//* 一个写log的类
时间 :2008-1-2
版本 :1.0.0.0
作者 :Karl.zhu
*/
#include "stdafx.h"
#include "Log3Demo.h"
#include "Log3.h"

#include <process.h>

// CLog3

CLog3::CLog3()


{

}
void CLog3::Init(CString FilePath,CString FileName)


{
m_FilePath = FilePath;
m_FileName = FileName;
}
CLog3::~CLog3()


{

}


// CLog3 成员函数

void CLog3::CrateLog(CString csFilePath,CString csFileName)


{
try

{
this->m_mutex.Lock();

CFileFind find ;
if (!find.FindFile(csFilePath))

{
CreateDirectory(csFilePath,NULL);
}

CString filename,fileexe;

int Where = csFileName.ReverseFind(_T('.'));
if (Where != -1)

{
filename = csFileName.Left(Where);
fileexe = csFileName.Right(csFileName.GetLength() - Where - 1);
}
else

{
filename = csFileName;
fileexe = "";
}

CTime now_time ;
SYSTEMTIME tm;
GetLocalTime(&tm);
CString day;
day.Format(_T("_%02d"),tm.wDay);

CString FileFullPath;
FileFullPath.Format(_T("%s\\%s%s.%s"),csFilePath,filename,day,fileexe);


if (m_File.m_hFile != CFile::hFileNull)

{
m_File.Close();
}
if (!find.FindFile(FileFullPath,NULL))

{
//没有找到
if (!m_File.Open(FileFullPath,CFile::modeCreate|CFile::modeReadWrite| CFile::shareDenyNone))

{
AfxMessageBox(_T("Open File Error"));
}
this->m_Fileday = tm.wDay;
}
else

{

//找到
WIN32_FIND_DATA FindFileData;
FindClose(FindFirstFile(FileFullPath,&FindFileData));
SYSTEMTIME csCreateTime;
FileTimeToSystemTime(&FindFileData.ftCreationTime,&csCreateTime);

if (tm.wDay == csCreateTime.wDay && tm.wMonth == csCreateTime.wMonth && tm.wYear == csCreateTime.wYear)

{
if(!m_File.Open(FileFullPath,CFile::modeReadWrite| CFile::shareDenyNone))

{
AfxMessageBox(_T("Open Log Error"));
}
this->m_Fileday = tm.wDay;

}
else

{
if (!m_File.Open(FileFullPath,CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone))

{
AfxMessageBox(_T("Open Log Error"));
}

else
{
FILETIME ft;
SystemTimeToFileTime(&tm,&ft);
SetFileTime(m_File.m_hFile,&ft,&ft,&ft);
this->m_Fileday = tm.wDay;

}
}
//memset(&FileInfo,0,sizeof(FILE_INFO));
}
}
catch (
)

{
DWORD lastError = GetLastError();
CString Err ;
Err.Format(_T("%d"),lastError);
AfxMessageBox(Err);
}
this->m_mutex.Unlock();

}



void CLog3::StartLog()


{
CrateLog(m_FilePath,m_FileName);
this->m_processStopHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
this->m_processSignalHandle = CreateEvent(NULL,TRUE,FALSE,NULL);

m_processThreadHandle = HANDLE(_beginthread(LogProcessorThread, 0, this));
if(m_processThreadHandle != LPVOID(-1))

{
AfxMessageBox(_T("Log Thread OK"));

}
else

{
AfxMessageBox(_T("Log Thread Faild"));
}

}
void CLog3::StopLog()


{
SetEvent(this->m_processStopHandle);
}
void CLog3::LogProcessorThread(LPVOID data)


{
CLog3 *me = (CLog3 *) data;
BOOL bStop = FALSE;
DWORD dwWritten;
HANDLE hHandleArray[2];

ASSERT(me);

hHandleArray[0] = me->m_processStopHandle;
hHandleArray[1] = me->m_processSignalHandle;

CString csData;

while (bStop == FALSE)

{
switch (WaitForMultipleObjects(2, hHandleArray, FALSE, INFINITE))

{
case WAIT_OBJECT_0:
bStop = TRUE;
break;

case WAIT_OBJECT_0 + 1:
// Lock the queue to get the count and the next entry
SYSTEMTIME tm1;
GetLocalTime(&tm1);
if (me->m_Fileday != tm1.wDay)

{
me->CrateLog(me->m_FilePath,me->m_FileName);
}
me->m_mutex.Lock();
while (me->m_messageQueue.GetCount())

{
csData = me->m_messageQueue.RemoveTail();
SYSTEMTIME tm;
GetLocalTime(&tm);
CString csFullData;
csFullData.Format(_T("%02d:%02d:%02d[%03d] %s"),tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds,csData);
// Now unlock the queue while we write
me->m_mutex.Unlock();

// Seek to the end of the file
me->m_File.SeekToEnd();
DWORD leg = WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,NULL,0,NULL,FALSE);
CHAR strchar [5000];
WideCharToMultiByte(CP_OEMCP,NULL,csFullData,-1,strchar,leg,NULL,FALSE);
me->m_File.Write(strchar,strlen(strchar));

CHAR * endline ="\r\n";
me->m_File.Write(endline,strlen(endline));
me->m_mutex.Lock();
}

// Now unlock it again
me->m_mutex.Unlock();

// Force output to disk
me->m_File.Flush();
ResetEvent(me->m_processSignalHandle);
break;
}
}

me->m_File.Close();

AfxMessageBox(_T("end File"));

_endthread();
}

void CLog3::QueueMessage(CString szLogEntry)


{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

ASSERT(szLogEntry);
ASSERT(AfxIsValidString(szLogEntry));

// Lock the object for the addhead call
// (must be fast once we get the lock).
m_mutex.Lock();
m_messageQueue.AddHead(szLogEntry);
m_mutex.Unlock();

// Now tell our processing thread there's
// new stuff to write
SetEvent(m_processSignalHandle);

}

这个算是我第一个vc的code,可能也存在什么不妥之处,读者们见笑了。
Demo下载