Commit 1cfc4e40 authored by captainwong's avatar captainwong

Initial commit

parents
// FileOper.h: interface for the CFileOper class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_FILEOPER_H__25D4B209_DAC6_4D93_98B2_692621E5508F__INCLUDED_)
#define AFX_FILEOPER_H__25D4B209_DAC6_4D93_98B2_692621E5508F__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <stdio.h>
#include <Shlobj.h>
static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)
{
switch(uMsg)
{
case BFFM_INITIALIZED: //初始化消息
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);
break;
case BFFM_SELCHANGED: //选择路径变化,
{
TCHAR curr[MAX_PATH];
SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);
::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);
}
break;
default:
break;
}
return 0;
}
class CFileOper
{
public:
// 弹出文件夹选择对话框,并返回选定的文件夹路径
static BOOL BrowseGetPath(CString &path, HWND hWnd){
TCHAR szPath[MAX_PATH] = {0};
BROWSEINFO bi;
memset(&bi, 0, sizeof(bi));
bi.hwndOwner = hWnd;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
bi.lpszTitle = _T("select folder");
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LONG)(LPCTSTR)path;
LPITEMIDLIST idl = SHBrowseForFolder(&bi);
if(idl == NULL)
return FALSE;
SHGetPathFromIDList(idl, szPath);
path.Format(_T("%s"), szPath);
return TRUE;
}
// 删除该路径下所有文件与文件夹
static BOOL DeleteFolderAndAllSubFolder_Files(LPCTSTR folderPath){
system("echo delete old folder and sub files...\n");
//CString cmd = _T("");
char cmd[64] = {0};
#if defined(_UNICODE) || defined(UNICODE)
char *path = Utf16ToAnsi(folderPath);
sprintf_s(cmd, "rd /s /q \"%s\"", path);
SAFEDELETEARR(path);
#else
sprintf_s(cmd, "rd /s /q \"%s\"", folderPath);
#endif
BOOL ret = system(cmd) == 0;
sprintf_s(cmd, "echo delete %s\n", ret ? "success" : "failed");
system(cmd);
return ret;
}
// 获取文件大小
static long GetFileSize(const CString& path){
FILE *p = NULL;
#if defined(_UNICODE) || defined(UNICODE)
char *cpath = Utf16ToAnsi(path);
fopen_s(&p, cpath, "r");
if(p == NULL)
{
SAFEDELETEARR(cpath);
return 0;
}
SAFEDELETEARR(cpath);
#else
fopen_s(&p, cpath, "r");
if(p == NULL)
return 0;
#endif
fseek(p, 0, SEEK_END);
long len = ftell(p);
fclose(p);
return len;
}
// 获取路径中最右的文件夹名称,如D:\A\B,返回B
static CString GetCurFolderFromFullPath(CString strpath){
int pos = -1;
pos = strpath.ReverseFind(_T('\\'));
if(pos != -1)
return strpath.Right(strpath.GetLength() - pos - 1);
return _T("");
}
// 复制文件夹到目的,并弹出文件夹复制对话框
static BOOL CopyFolder(CString dstFolder, CString srcFolder, HWND hWnd){
TCHAR szDst[MAX_PATH], szSrc[MAX_PATH];
ZeroMemory(szDst, MAX_PATH);
ZeroMemory(szSrc, MAX_PATH);
lstrcpy(szDst, dstFolder);
lstrcpy(szSrc, srcFolder);
SHFILEOPSTRUCT lpFile;
lpFile.hwnd = hWnd;
lpFile.wFunc = FO_COPY;
lpFile.pFrom = szSrc;
lpFile.pTo = szDst;
lpFile.fFlags = FOF_ALLOWUNDO;
lpFile.fAnyOperationsAborted = FALSE;
lpFile.hNameMappings = NULL;
lpFile.lpszProgressTitle = NULL;
int ret = SHFileOperation(&lpFile);
return ret == 0 && lpFile.fAnyOperationsAborted == FALSE;
}
// 判断指定路径是否存在(文件夹)
static BOOL IsFolderExists(LPCTSTR lpszFolderPath){
return FindFirstFileExists(lpszFolderPath, FILE_ATTRIBUTE_DIRECTORY);
}
// 判断指定路径是否存在(文件或文件夹)
static BOOL PathExists(LPCTSTR lpszPath){
return FindFirstFileExists(lpszPath, FALSE);
}
// 更改文件名后缀名
static CString ChangeFileExt(const CString& srcFilePath, const CString& dstExt){
CString dstFilePath = srcFilePath;
int pos = srcFilePath.ReverseFind(_T('.'));
if(pos != -1){
dstFilePath = srcFilePath.Left(pos + 1);
dstFilePath += dstExt;
}
return dstFilePath;
}
// 从文件路径中获取文件标题,如D:\AAA.TXT或者AAA.TXT,返回AAA
static CString GetFileTitle(const CString& fileName){
CString title = _T("");
int pos = -1;
pos = fileName.FindOneOf(_T("\\"));
CString name = fileName;
if(pos > 0)
name = GetFileNameFromPathName(fileName);
pos = name.ReverseFind(_T('.'));
if(pos != -1)
title = name.Left(pos);
return title;
}
// 从文件路径中获取文件后缀名,如D:\AAA.TXT,返回TXT
static CString GetFileExt(const CString& filePath){
CString ext = _T("");
int pos = filePath.ReverseFind(_T('.'));
if(pos != -1){
ext = filePath.Right(filePath.GetLength() - pos - 1);
ext.MakeUpper();
}
return ext;
}
// 从文件路径中获取文件名,如D:\AAA.TXT,返回AAA.TXT
static CString GetFileNameFromPathName(const CString& filePathName){
CString fileName = _T("");
int pos = filePathName.ReverseFind(_T('\\'));
if(pos != -1) {
fileName = filePathName.Right(filePathName.GetLength() - pos - 1);
}
return fileName;
}
// 寻找目录(该路径不能以 \ 结尾)下所有指定后缀名(不支持*.*)的文件,并将结果保存在CStringList中,
static int FindFilesInFolder(LPCTSTR lpszFolder, LPCTSTR lpszFilter, CStringList &dstList){
if(lstrlen(lpszFolder) == 0)
return 0;
int nNums = 0;
CFileFind filefind;
CString path, filter;
filter.Format(_T("%s\\%s"), lpszFolder, lpszFilter);
BOOL bFound = filefind.FindFile(filter);
while(bFound){
bFound = filefind.FindNextFile();
if(filefind.IsDots())
continue;
if(!filefind.IsDirectory()){
path = filefind.GetFilePath();
dstList.AddTail(path);
nNums++;
}
}
filefind.Close();
return nNums;
}
// 将目录下符合 *n.* 的文件(n代表数字)重命名为 *00n.*的形式,将n格式化为3位数
static BOOL RenameFile03d(LPCTSTR lpszFilePath){
CString fileName = lpszFilePath;
CString tittle, num, ext, newFileName;
int pos;
pos = fileName.ReverseFind(_T('.'));
if(pos == -1) return FALSE;
tittle = fileName.Left(pos);
ext = fileName.Right(fileName.GetLength() - pos);
int i = 0, posNum = 0, numnums = 0;
TCHAR ch;
bool bNumCharFound = false;
for(i = tittle.GetLength()-1, posNum = i+1; i > 0; i--){
ch = tittle.GetAt(i);
if(ch > _T('0') && ch < _T('9')){
if(posNum != i+1)
break;
posNum = i;
numnums++;
bNumCharFound = true;
}
}
if(!bNumCharFound) return FALSE;
num = tittle.Right(numnums);
tittle = tittle.Left(posNum);
int nums = _ttoi(num.GetBuffer(num.GetLength()));
num.ReleaseBuffer();
num.Format(_T("%03d"), nums);
tittle += num;
newFileName.Format(_T("%s%s"), tittle, ext);
LPCTSTR szOldName = fileName.GetBuffer(fileName.GetLength());
fileName.ReleaseBuffer();
LPCTSTR szNewName = newFileName.GetBuffer(newFileName.GetLength());
newFileName.ReleaseBuffer();
MoveFile(szOldName, szNewName);
TRACE(_T("movefile %s to %s \n"), fileName, newFileName);
return TRUE;
}
// 删除所有该目录路径下指定后缀名的文件
static DWORD DeleteFilesInFolder(LPCTSTR lpszFolder, LPCTSTR lpszFilter){
DWORD dwDeletedFileNums = 0;
CFileFind find;
BOOL bfoundone = FALSE;
CString filter = _T("");
filter.Format(_T("%s\\%s"), lpszFolder, lpszFilter);
BOOL bFound = find.FindFile(filter);
TRACE(_T("CFileOper::DeleteFilesInFolder find path %s\n"), filter);
CString filepath = _T("");
while(bFound){
bFound = find.FindNextFile();
if(find.IsDots())
continue;
if(!find.IsDirectory()){
filepath = find.GetFilePath();
if(DeleteFile(filepath.GetBuffer(filepath.GetLength()))){
CString trace;trace.Format(_T("CFileOper::DeleteFilesInFolder delete file %s \n"),
find.GetFilePath());
TRACE(trace);
bfoundone = TRUE;
dwDeletedFileNums++;
}
}
}
if(!bfoundone)
TRACE(_T("CFileOper::DeleteFilesInFolder no file deleted\n"));
find.Close();
return dwDeletedFileNums;
}
private:
CFileOper();
virtual ~CFileOper();
protected:
static BOOL FindFirstFileExists(LPCTSTR lspzPath, DWORD dwFilter){
TCHAR realPath[MAX_PATH] = {0};
if(_tcsclen(lspzPath) > MAX_PATH)
GetShortPathName(lspzPath, realPath, MAX_PATH);
else
_tcscpy_s(realPath, lspzPath);
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(realPath, &fd);
BOOL bFilter = (FALSE == dwFilter) ? TRUE : fd.dwFileAttributes & dwFilter;
BOOL RetValue = ((hFind != INVALID_HANDLE_VALUE) && bFilter) ? TRUE : FALSE;
FindClose(hFind);
return RetValue;
}
};
#endif // !defined(AFX_FILEOPER_H__25D4B209_DAC6_4D93_98B2_692621E5508F__INCLUDED_)
#ifndef ___IOCP_H_INCLUDED___
#define ___IOCP_H_INCLUDED___
#include <windows.h>
#include "socket_client.h"
///////////////////////////////////////////////////////////////////////////////////////////////
// A template class (wrapper) to handle basic operations
// related to IO Completion Ports (IOCP).
template<class T>
class IOCPSimple {
private:
HANDLE m_hIocp;
DWORD m_dwTimeout;
protected:
// Useful method to queue a socket (handler in fact) in the IOCP's
// queue, without requesting any 'physical' I/O operations.
BOOL PostQueuedCompletionStatus( ClientSocket<T> *sock, MYOVERLAPPED *pMov ) {
return ::PostQueuedCompletionStatus( this->m_hIocp, 1,
(DWORD) sock, (OVERLAPPED*) pMov );
};
public:
~IOCPSimple() {
// Destroy the IOCP handler
::CloseHandle( this->m_hIocp );
};
IOCPSimple( DWORD dwTimeout = 0 ) {
// This will be used as a timeout value to wait
// for completion events from IOCP (in milliseconds).
// See 'GetQueuedCompletionStatus(...)' for more
// details. If is set to 0 == means infinite.
m_dwTimeout = dwTimeout;
// Create the IOCP handler
this->m_hIocp = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
if ( this->m_hIocp == NULL ) {
throw "CreateIoCompletionPort() failed to create IO Completion port.";
}
};
// Method associates Socket handler with the handler
// of the IOCP. It is important to do this association
// first of all, once Socket is accepted and is valid.
// In fact, this method registers socket with the IOCP,
// so IOCP will monitor every I/O operation happening
// with the socket.
void AssociateSocket( ClientSocket<T> *sock ) {
if ( sock != NULL ) {
// As a key of this association, the pointer to the
// "sock" is set. The pointer to the "sock" will be
// returned with "GetQueuedCompletionStatus" call
// whenever a I/O operation completes, so we always know
// which is the relevant socket.
::CreateIoCompletionPort( (HANDLE) sock->GetSocket(),
this->m_hIocp, (DWORD) sock, 0 );
}
};
// Queue in the IOCP's queue with the status 'pending'.
// This is a fictive status (not real). Method is useful in
// cases when packets/data buffers to send via socket are yet
// not ready (e.g. due some internal, time consuming, calculations)
// and rather than keeping socket somewhere, in separate structures,
// place it in the queue with status pending. It will be returned
// shortly with the "GetQueuedCompletionStatus" call anyway.
BOOL SetPendingMode( ClientSocket<T> *sock ) {
BOOL ret = false;
if ( sock != NULL ) {
// Get a free instance of the structure
// from the pool.
MYOVERLAPPED *mov = Overlapped::Get();
if ( mov != NULL ) {
mov->OperationType = _PENDING;
mov->nSession = sock->GetSession();
ret = PostQueuedCompletionStatus( sock, mov );
if ( !ret ) Overlapped::Release( mov );
}
}
return ret;
};
// Queue in the IOCP's queue with the status 'close'.
// This is a fictive status (not real). Useful only
// when close socket cases should be treated/handled
// within the routine, handling I/O completion statuses,
// and just to not spread the code across different
// modules/classes.
BOOL SetCloseMode( ClientSocket<T> *sock, MYOVERLAPPED *pMov = NULL ) {
BOOL ret = false;
if ( sock != NULL ) {
// Get a free instance of the structure
// from the pool.
MYOVERLAPPED *mov = Overlapped::Get();
if ( mov != NULL ) {
mov->OperationType = _CLOSE;
mov->nSession = sock->GetSession();
if (pMov != NULL) {
mov->DataBuf.buf = pMov->DataBuf.buf;
mov->DataBuf.len = pMov->DataBuf.len;
}
ret = PostQueuedCompletionStatus( sock, mov );
if ( !ret ) Overlapped::Release( mov );
}
}
return ret;
};
// Queue in the IOCP's queue with the status 'accept'.
// This is a fictive status (not real). When a new
// client connection is accepted by the server socket,
// method is used to acknowledge the routine, handling
// I/O completion statuses, of this. Same reason as per
// 'close' status, just to have a unique piece of code
// handling all the possible statuses.
BOOL SetAcceptMode( ClientSocket<T> *sock ) {
BOOL ret = false;
if ( sock != NULL ) {
// Get a free instance of the structure
// from the pool.
MYOVERLAPPED *mov = Overlapped::Get();
if ( mov != NULL ) {
mov->OperationType = _ACCEPT;
mov->nSession = sock->GetSession();
ret = PostQueuedCompletionStatus( sock, mov );
if ( !ret ) Overlapped::Release( mov );
}
}
return ret;
};
// This method is just a wrapper. For more details,
// see MSDN for "GetQueuedCompletionStatus". The only
// difference is, method is adjusted to handle
// 'ClientSocket<T>' (as registered with 'AssociateSocket(...)')
// rather than pointer to the 'DWORD'.
BOOL GetQueuedCompletionStatus( LPDWORD pdwBytesTransferred,
ClientSocket<T> **sock, MYOVERLAPPED **lpOverlapped ) {
return ::GetQueuedCompletionStatus( this->m_hIocp, pdwBytesTransferred,
(LPDWORD) sock, (LPOVERLAPPED*) lpOverlapped, m_dwTimeout );
};
};
#endif
\ No newline at end of file
#ifndef ___LOG_H_INCLUDED___
#define ___LOG_H_INCLUDED___
#include "INCLUDE/sync_simple.h"
#include "D:/global/log.h"
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A simple class to log messages to the console
// considering multithreading
class Log {
private:
static QMutex m_qMutex;
//static wchar_t m_buff[1024];
public:
static void LogMessage(const char* str);
static void LogMessage(const wchar_t *str);
static void LogMessage(const wchar_t *str, long num);
static void LogMessage(const wchar_t *str, long num1, long num2);
static void LogMessage(const wchar_t *str, long num, const wchar_t *str1);
static void LogMessage(const wchar_t *str, const wchar_t *str1);
static void LogMessage(const wchar_t *str, const wchar_t *str1, const wchar_t *str2);
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- IMPLEMENTATION -------------------------------------------------
QMutex Log::m_qMutex;
void Log::LogMessage(const wchar_t *str, long num1, long num2) {
m_qMutex.Lock();
//wsprintf(m_buff, str, num1, num2);
CLog::WriteLogW(str, num1, num2);
m_qMutex.Unlock();
}
void Log::LogMessage(const wchar_t *str, long num, const wchar_t *str1) {
m_qMutex.Lock();
CLog::WriteLogW(str, num, str1);
m_qMutex.Unlock();
}
void Log::LogMessage(const wchar_t *str, const wchar_t *str1, const wchar_t *str2) {
m_qMutex.Lock();
CLog::WriteLogW(str, str1, str2);
m_qMutex.Unlock();
}
void Log::LogMessage(const wchar_t *str, const wchar_t *str1) {
m_qMutex.Lock();
CLog::WriteLogW(str, str1);
m_qMutex.Unlock();
}
void Log::LogMessage(const wchar_t *str, long num) {
m_qMutex.Lock();
CLog::WriteLogW(str, num);
m_qMutex.Unlock();
}
void Log::LogMessage(const wchar_t *str) {
m_qMutex.Lock();
CLog::WriteLogW(str);
m_qMutex.Unlock();
}
void Log::LogMessage(const char *str) {
m_qMutex.Lock();
CLog::WriteLogA(str);
m_qMutex.Unlock();
}
#endif
\ No newline at end of file
#ifndef ___MEM_MANAGER_H_INCLUDED___
#define ___MEM_MANAGER_H_INCLUDED___
#pragma warning(disable:4786)
#include <vector>
#include <queue>
#include <set>
#include "sync_simple.h"
using namespace std;
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A priority queue that allows pre-setting capacity of the container.
template<class T>
class mpriority_queue : public priority_queue<T, vector<T>, less<typename vector<T>::value_type> > {
public:
void reserve(size_type _N) { c.reserve(_N); };
size_type capacity() const { return c.capacity(); };
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A template class allowing re-using of the memory blocks.
template<class T>
class QueuedBlocks {
private:
QMutex m_qMutex;
set< T* > m_quBlocks;
vector< T* > m_allBlocks;
public:
QueuedBlocks(int nInitSize = 1): m_qMutex(), m_quBlocks(), m_allBlocks() {
int i;
int nSize = (nInitSize <= 0)?1:nInitSize;
// allocate and push the blocks to the queue
for (i = 0; i < nSize; i++) {
T *t = new T();
if (t != NULL) {
t->Clear();
m_quBlocks.insert( t );
m_allBlocks.push_back( t );
}
}
};
// get a free block from the queue, if one cannot be found
// then NULL is returned
T* GetFromQueue() {
T* t = NULL;
m_qMutex.Lock();
if (!m_quBlocks.empty()) {
set<T*>::iterator itPos = m_quBlocks.begin();
t = *itPos;
m_quBlocks.erase( t );
}
m_qMutex.Unlock();
return t;
};
// get a free block from the queue, if one cannot be found
// then a new one is created
T* Get() {
T* t = GetFromQueue();
if (t == NULL) {
t = new T();
if (t != NULL) {
t->Clear();
m_qMutex.Lock();
m_allBlocks.push_back( t );
m_qMutex.Unlock();
}
}
return t;
};
// Release the used block, place it
// back to the queue. For performance reason,
// we assume that the block was previously taken
// from the queue.
void Release(T* t) {
if (t != NULL) {
t->Clear();
m_qMutex.Lock();
m_quBlocks.insert( t );
m_qMutex.Unlock();
}
};
// Return all the blocks ever allocated.
vector<T*> *GetBlocks() { return &m_allBlocks; };
~QueuedBlocks() {
m_qMutex.Lock();
m_quBlocks.clear();
vector<T*>::iterator itPos = m_allBlocks.begin();
for (; itPos < m_allBlocks.end(); itPos++) {
T* t = *itPos;
t->Clear();
delete t;
}
m_allBlocks.clear();
m_qMutex.Unlock();
};
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A template class used for providing free blocks as well
// as releasing unnecessary ones. Uses "QueuedBlocks" which
// allows reusing of the blocks.
template<class T>
class StaticBlocks {
private:
static QueuedBlocks<T> *blocks;
public:
static void Init(int nSize = 1) {
if (blocks == NULL) blocks = new QueuedBlocks<T>(nSize);
};
static void Clear() {
if (blocks != NULL) {
delete blocks; blocks = NULL;
}
}
static T *Get() {
if (blocks == NULL) return NULL;
return blocks->Get();
};
static void Release(T *b) {
if (blocks != NULL) blocks->Release(b);
};
};
#endif
This diff is collapsed.
This diff is collapsed.
#ifndef ___SOCKET_CLIENT_H_INCLUDED___
#define ___SOCKET_CLIENT_H_INCLUDED___
#include <winsock2.h>
#include "mem_manager.h"
#define RECV_BUFFER_EMPTY -2
enum IO_SOCK_MODES {_CLOSE, _ACCEPT, _READ, _WRITE, _PENDING};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Overlapped structure used with this implementation of the IOCP.
// Only the "Overlapped" member is used in context with the
// standard IOCP API, anything else is just to help this particular
// implementation.
typedef struct {
// It is very important "Overlapped" to be the very first
// member of the structure because pointer pointing to
// "this" is == to the address of the first member.
// This makes usage of the MYOVERLAPPED equivalent
// to the OVERLAPPED in context of the standard IOCP API (just a trick).
OVERLAPPED Overlapped;
// A structure that points to the data packet and size of the data
// packet associated with current overlapped operation.
WSABUF DataBuf;
// Operation type associated with current overlapped operation.
IO_SOCK_MODES OperationType;
// Internally used. If nSession != ClientSocket::m_nSession
// that means that socket was closed (recently) and
// operation retrieved from IOCP queue or TaskPool queue
// is not relevant, to the current session of the socket.
volatile unsigned int nSession;
// Method is used by 'QueuedBlocks' from
// "mem_manager.h".
void Clear() {
memset(this, 0, sizeof(MYOVERLAPPED));
};
} MYOVERLAPPED;
// a pool of the MYOVERLAPPED structures
typedef StaticBlocks<MYOVERLAPPED> Overlapped;
QueuedBlocks<MYOVERLAPPED> *Overlapped::blocks = NULL;
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A class wrapping basic client socket's operations
template<class T>
class ClientSocket {
//friend class MyServerService;
private:
SOCKET m_ClientSock;
volatile unsigned int m_nSession;
QMutex m_qMutex;
struct sockaddr_in m_psForeignAddIn;
volatile bool m_blnIsBusy;
T m_objAttachment;
protected:
public:
ClientSocket(): m_objAttachment(), m_qMutex() {
this->m_nSession = 1;
this->m_ClientSock = 0;
this->m_blnIsBusy = false;
};
~ClientSocket() {
if (this->m_blnIsBusy) this->CloseSocket();
};
// Is the object assigned a socket.
bool IsBusy() { return this->m_blnIsBusy; };
// Method is used by 'QueuedBlocks' from
// "mem_manager.h".
void Clear() { CloseSocket(); };
// Returns the socket associated with the object.
SOCKET GetSocket() { return this->m_ClientSock; };
void GetAddrIn(struct sockaddr_in& addrin) {memcpy(&addrin, &m_psForeignAddIn,sizeof(struct sockaddr_in));}
// Returns the session of the current client socket.
// Technically, this is the counter of how may times
// current instance was pooled, but really, this is used
// to check if session of operation (MYOVERLAPPED)
// is == with the session of the socket.
unsigned int GetSession() { return this->m_nSession; };
// Internally used by this implementation. Don't call it.
void Lock() { m_qMutex.Lock(); };
// Internally used by this implementation. Don't call it.
void UnLock() { m_qMutex.Unlock(); };
// Associate the object with a socket.
int Associate(SOCKET sSocket, struct sockaddr_in *psForeignAddIn) {
int nRet = SOCKET_ERROR;
if (sSocket < 0) return nRet;
if (this->m_blnIsBusy) return nRet;
this->m_blnIsBusy = true;
this->m_ClientSock = sSocket;
memcpy(&m_psForeignAddIn, psForeignAddIn, sizeof(struct sockaddr_in));
m_objAttachment.Clear();
return (int) this->m_ClientSock;
};
// Returns the attachment of the object.
// Use the attachment to associate the socket with any other
// additional information required.
T* GetAttachment() { return &m_objAttachment; };
// Write data to the socket,
// uses overlapped style.
int WriteToSocket(char *pBuffer, DWORD buffSize) {
int nRet = SOCKET_ERROR ;
DWORD dwSendBytes = 0;
DWORD dwFlags = 0;
if ( this->m_blnIsBusy ) {
// Get a free instance of the structure
// from the pool.
MYOVERLAPPED *mov = Overlapped::Get();
if ( mov != NULL ) {
mov->DataBuf.buf = pBuffer;
mov->DataBuf.len = buffSize;
mov->OperationType = _WRITE;
mov->nSession = GetSession();
nRet = WSASend(this->m_ClientSock, &mov->DataBuf, 1,
&dwSendBytes, dwFlags, (OVERLAPPED *) mov, NULL);
if (nRet == SOCKET_ERROR) {
if ((WSAGetLastError()) == WSA_IO_PENDING) nRet = 0;
}
}
}
return nRet;
};
// Read data from the socket,
// uses overlapped style.
int ReadFromSocket(char *pBuffer, DWORD buffSize) {
int nRet = SOCKET_ERROR ;
DWORD dwRecvBytes;
DWORD dwFlags = 0;
if ( this->m_blnIsBusy ) {
if (buffSize > 0) {
// Get a free instance of the structure
// from the pool.
MYOVERLAPPED *mov = Overlapped::Get();
if ( mov != NULL ) {
mov->DataBuf.buf = pBuffer;
mov->DataBuf.len = buffSize;
mov->OperationType = _READ;
mov->nSession = GetSession();
nRet = WSARecv(this->m_ClientSock, &mov->DataBuf, 1,
&dwRecvBytes, &dwFlags, (OVERLAPPED *) mov, NULL);
if (nRet == SOCKET_ERROR) {
if ((WSAGetLastError()) == WSA_IO_PENDING) nRet = 0;
}
}
}
else nRet = RECV_BUFFER_EMPTY;
}
return nRet;
};
// Closes the socket associated with this instance
// of the object and performs clean-up.
void CloseSocket() {
if ( this->m_blnIsBusy ) {
this->m_blnIsBusy = false;
if ((this->m_nSession++) > 0x0FFFD) this->m_nSession = 1;
shutdown(this->m_ClientSock, 2);
closesocket(this->m_ClientSock);
this->m_ClientSock = 0;
memset(&m_psForeignAddIn, 0 , sizeof(struct sockaddr_in));
m_objAttachment.Clear();
}
};
};
#endif
\ No newline at end of file
#ifndef ___SOCKET_SERVER_H_INCLUDED___
#define ___SOCKET_SERVER_H_INCLUDED___
#include <winsock2.h>
#include "mem_manager.h"
#include "socket_client.h"
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A class for handling basic server socket operations.
template<class T>
class ServerSocket {
private:
// Server socket.
SOCKET m_ServSock;
// Pool of client sockets.
QueuedBlocks<ClientSocket<T> > m_SockPool;
protected:
public:
// Set the size of the socket pool to the maximum number of accepted
// client connections.
ServerSocket(unsigned int nPort, unsigned int nMaxClients,
bool blnCreateAsync = false, bool blnBindLocal = true): m_SockPool(nMaxClients) {
int nRet;
unsigned long lngMode = 1;
struct sockaddr_in sAddrIn;
// Create the server socket, set the necessary
// parameters for making it IOCP compatible.
this->m_ServSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (this->m_ServSock <= 0) {
throw "server socket creation failed.";
}
// Make server socket Synchronous (blocking)
// or Asynchronous (non-blocking)
if (blnCreateAsync) {
nRet = ioctlsocket(this->m_ServSock, FIONBIO, (u_long FAR*) &lngMode);
if (nRet < 0) {
closesocket(this->m_ServSock);
throw "server socket creation failed.";
}
}
// Fill the structure for binding operation
sAddrIn.sin_family = AF_INET;
sAddrIn.sin_port = htons(nPort);
// Bind to the localhost ("127.0.0.1") to accept connections only from
// localhost or
// "0.0.0.0" (INADDR_ANY) to accept connections from any IP address.
if (blnBindLocal) sAddrIn.sin_addr.s_addr = inet_addr("127.0.0.1");
else sAddrIn.sin_addr.s_addr = htonl(INADDR_ANY);
// Bind the structure to the created server socket.
nRet = bind(this->m_ServSock, (struct sockaddr *) &sAddrIn, sizeof(sAddrIn));
if (nRet < 0) {
closesocket(this->m_ServSock);
throw "server socket failed to bind on given port.";
}
// Set server socket in listen mode and set the listen queue to 20.
nRet = listen(this->m_ServSock, 20);
if (nRet < 0) {
closesocket(this->m_ServSock);
throw "server scket failed to listen.";
}
};
// Returns a pointer to the ClientSocket instance, bind
// to the accepted client socket (incoming connection).
ClientSocket<T>* Accept() {
SOCKET sAccept;
struct sockaddr_in sForeignAddIn;
int nLength = sizeof(struct sockaddr_in);
ClientSocket<T> *ret = NULL;
// Check if there is something in the listen queue.
sAccept = WSAAccept(this->m_ServSock, (struct sockaddr *) &sForeignAddIn,
&nLength, NULL, NULL);
// Check for errors.
if (sAccept != INVALID_SOCKET) {
// Get a pointer to the free ClientSocket
// instance from the pool.
ret = m_SockPool.GetFromQueue();
if (ret == NULL) {
// There are no free instances in the pool, maximum
// number of accepted client connections is reached.
::shutdown(sAccept,2);
::closesocket(sAccept);
}
else {
// Everything is fine, so associate the instance
// with the client socket.
ret->Lock();
ret->Associate(sAccept, &sForeignAddIn);
ret->UnLock();
}
}
return ret;
};
// Release the client socket, will try closing connection and
// will place it back to the pool.
void Release(ClientSocket<T> *sock) {
if (sock != NULL) {
// check if client socket object is
// assigned a socket handler. If yes,
// close it.
if (sock->IsBusy()) sock->CloseSocket();
// Place it back to the pool.
m_SockPool.Release(sock);
}
};
vector<ClientSocket<T> *> *GetPool() {
return m_SockPool.GetBlocks();
};
~ServerSocket() {
shutdown(this->m_ServSock, 2);
closesocket(this->m_ServSock);
};
};
#endif
\ No newline at end of file
#ifndef ___SYNC_SIMPLE_H_INCLUDED___
#define ___SYNC_SIMPLE_H_INCLUDED___
#include <windows.h>
#pragma comment(lib, "kernel32.lib")
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Implementation of the critical section
class QMutex {
private:
CRITICAL_SECTION m_Cs;
public:
QMutex() { ::InitializeCriticalSection(&this->m_Cs); }
~QMutex() { ::DeleteCriticalSection(&this->m_Cs); }
void Lock() { ::EnterCriticalSection(&this->m_Cs); }
BOOL TryLock() { return (BOOL) ::TryEnterCriticalSection(&this->m_Cs); }
void Unlock() { ::LeaveCriticalSection(&this->m_Cs); }
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Implementation of the semaphore
class QSemaphore {
private:
HANDLE m_hSemaphore;
long m_lMaximumCount;
public:
QSemaphore(long lMaximumCount) {
this->m_hSemaphore = ::CreateSemaphore(NULL, lMaximumCount, lMaximumCount, NULL);
if (this->m_hSemaphore == NULL) throw "Call to CreateSemaphore() failed. Could not create semaphore.";
this->m_lMaximumCount = lMaximumCount;
};
~QSemaphore() { ::CloseHandle(this->m_hSemaphore); };
long GetMaximumCount() const { return this->m_lMaximumCount; };
void Inc() { ::WaitForSingleObject(this->m_hSemaphore, INFINITE); };
void Dec() { ::ReleaseSemaphore(this->m_hSemaphore, 1, NULL); };
void Dec(long lCount) { ::ReleaseSemaphore(this->m_hSemaphore, lCount, NULL); };
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Implementation of the read-write mutex.
// Multiple threads can have read access at the same time.
// Write access is exclusive for only one thread.
class ReadWriteMutex {
private:
QMutex m_qMutex;
QSemaphore m_qSemaphore;
public:
ReadWriteMutex(long lMaximumReaders): m_qSemaphore(lMaximumReaders) {};
void lockRead() { m_qSemaphore.Inc(); };
void unlockRead() { m_qSemaphore.Dec(); };
void lockWrite() {
m_qMutex.Lock();
for (int i = 0; i < maxReaders(); ++i) m_qSemaphore.Inc();
m_qMutex.Unlock();
};
void unlockWrite() { m_qSemaphore.Dec(m_qSemaphore.GetMaximumCount()); };
int maxReaders() const { return m_qSemaphore.GetMaximumCount(); };
};
#endif
\ No newline at end of file
#ifndef ___THREADING_H_INCLUDED___
#define ___THREADING_H_INCLUDED___
#include <windows.h>
#include "mem_manager.h"
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
class CThread;
class CSimpleThreadPool;
///////////////////////////////////////////////////////////////////////////////////////////////
// The core interface of this threading implementation.
class IRunnable {
friend class CThread;
friend class CSimpleThreadPool;
protected:
virtual void run() = 0;
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// structure holds Thread Local Storage descriptor
struct TLSDescriptor {
DWORD descriptor;
TLSDescriptor() {
descriptor = TlsAlloc();
if (descriptor == -1) throw "TlsAlloc() failed to create descriptor";
};
~TLSDescriptor() { TlsFree(descriptor); };
};
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Very basic thread class, implementing basic threading API
class CThread: public IRunnable {
private:
static TLSDescriptor m_TLSDesc;
volatile bool m_bIsInterrupted;
volatile bool m_bIsRunning;
int m_nThreadPriority;
IRunnable *m_RunObj;
QMutex m_qMutex;
// See ::CreateThread(...) within the start() method. This is
// the thread's API function to be executed. Method executes
// run() method of the CThread instance passed as parameter.
static DWORD WINAPI StartThreadST(LPVOID PARAM) {
CThread *_this = (CThread *) PARAM;
if (_this != NULL) {
_this->m_qMutex.Lock();
// Set the pointer to the instance of the passed CThread
// in the current Thread's Local Storage. Also see
// currentThread() method.
TlsSetValue(CThread::m_TLSDesc.descriptor, (LPVOID) _this);
_this->run();
_this->m_bIsRunning = false;
_this->m_qMutex.Unlock();
}
return 0;
};
protected:
// It is not possible to instantiate CThread objects directly. Possible only by
// specifying a IRunnable object to execute its run() method.
CThread(int nPriority = THREAD_PRIORITY_NORMAL): m_qMutex() {
this->m_bIsInterrupted = false;
this->m_bIsRunning = false;
this->m_nThreadPriority = nPriority;
this->m_RunObj = NULL;
};
// this implementation of the run() will execute the passed IRunnable
// object (if not null). Inheriting class is responsible for using this
// method or overriding it with a different one.
virtual void run() {
if (this->m_RunObj != NULL) this->m_RunObj->run();
};
public:
CThread(IRunnable *RunTask, int nPriority = THREAD_PRIORITY_NORMAL): m_qMutex() {
this->m_bIsInterrupted = false;
this->m_bIsRunning = false;
this->m_nThreadPriority = nPriority;
if (this != RunTask) this->m_RunObj = RunTask;
else throw "Self referencing not allowed.";
};
virtual ~CThread() {
this->interrupt();
// wait until thread ends
this->join();
};
// Method returns the instance of a CThread responsible
// for the context of the current thread.
static CThread& currentThread() {
CThread *thr = (CThread *) TlsGetValue(CThread::m_TLSDesc.descriptor);
if (thr == NULL) throw "Call is not within a CThread context.";
return *thr;
};
// Method signals thread to stop execution.
void interrupt() { this->m_bIsInterrupted = true; };
// Check if thread was signaled to stop.
bool isInterrupted() { return this->m_bIsInterrupted; };
// Method will wait for thread's termination.
void join() {
this->m_qMutex.Lock();
this->m_qMutex.Unlock();
};
// Method starts the Thread. If thread is already started/running, method
// will simply return.
void start() {
HANDLE hThread;
LPTHREAD_START_ROUTINE pStartRoutine = &CThread::StartThreadST;
if (this->m_qMutex.TryLock()) {
if (!this->m_bIsRunning) {
this->m_bIsRunning = true;
this->m_bIsInterrupted = false;
hThread = ::CreateThread(NULL, 0, pStartRoutine, (PVOID) this, 0, NULL);
if (hThread == NULL) {
this->m_bIsRunning = false;
this->m_qMutex.Unlock();
throw "Failed to call CreateThread(). Thread not started.";
}
::SetThreadPriority(hThread, this->m_nThreadPriority);
::CloseHandle(hThread);
}
this->m_qMutex.Unlock();
}
};
};
TLSDescriptor CThread::m_TLSDesc;
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// Helper class to submit tasks to the CSimpleThreadPool
class CPriorityTask {
private:
int m_nPriority;
IRunnable *m_pRunObj;
public:
CPriorityTask(const CPriorityTask &t) {
m_pRunObj = t.m_pRunObj;
m_nPriority = t.m_nPriority;
};
CPriorityTask() {
m_pRunObj = NULL;
m_nPriority = 0;
};
CPriorityTask(IRunnable *pRunObj, int nPriority = 0) {
m_pRunObj = pRunObj;
m_nPriority = nPriority;
};
int getPriority() const { return m_nPriority; };
IRunnable *getTask() const { return m_pRunObj; };
~CPriorityTask() {};
CPriorityTask& operator=(const CPriorityTask &t) {
m_nPriority = t.m_nPriority;
m_pRunObj = t.m_pRunObj;
return *this;
};
};
//Overload the < operator.
bool operator< (const CPriorityTask& pt1, const CPriorityTask& pt2) {
return pt1.getPriority() < pt2.getPriority();
}
//Overload the > operator.
bool operator> (const CPriorityTask& pt1, const CPriorityTask& pt2) {
return pt1.getPriority() > pt2.getPriority();
}
///////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------- CLASS ----------------------------------------------------------
// A class containing a collection of CThreadTask's.
// Every CThreadTask will execute same CSimpleThreadPool::run() method.
class CSimpleThreadPool: public IRunnable {
private:
QMutex m_qMutex;
vector<CThread*> m_arrThreadTasks;
mpriority_queue<CPriorityTask> m_PQueue;
// Method will return a task from the queue,
// if there are no tasks in the queue, method will return NULL.
IRunnable *get() {
IRunnable *ret = NULL;
m_qMutex.Lock();
if (!m_PQueue.empty()) {
CPriorityTask t = m_PQueue.top();
m_PQueue.pop();
ret = t.getTask();
}
m_qMutex.Unlock();
return ret;
};
public:
// How many threads are in the collection.
int threads() const { m_arrThreadTasks.size(); };
// Method starts pool's threads.
void startAll() {
for (unsigned int i = 0; i < m_arrThreadTasks.size(); i++) {
m_arrThreadTasks[i]->start();
}
};
// Constructor creates the thread pool and sets capacity for the task queue.
CSimpleThreadPool(unsigned int nThreadsCount, unsigned int nQueueCapacity = 16):
m_qMutex(), m_PQueue() {
unsigned int i;
CThread *thTask = NULL;
if (nThreadsCount <= 0) throw "Invalid number of threads supplied.";
if (nQueueCapacity <= 0) throw "Invalid capacity supplied.";
// Set initial capacity of the tasks Queue.
m_PQueue.reserve(nQueueCapacity);
// Initialize thread pool.
for (i = 0; i < nThreadsCount; i++) {
thTask = new CThread(this);
if (thTask != NULL) m_arrThreadTasks.push_back(thTask);
}
};
// Submit a new task to the pool
void submit(IRunnable *pRunObj, int nPriority = 0) {
if (this == pRunObj) throw "Self referencing not allowed.";
m_qMutex.Lock();
m_PQueue.push(CPriorityTask(pRunObj, nPriority));
m_qMutex.Unlock();
};
// Method will execute task's run() method within its CThread context.
virtual void run() {
IRunnable *task;
while (!CThread::currentThread().isInterrupted()) {
// Get a task from the queue.
task = get();
// Execute the task.
if (task != NULL) task->run();
::Sleep(2);
}
};
virtual ~CSimpleThreadPool() {
vector<CThread*>::iterator itPos = m_arrThreadTasks.begin();
for (; itPos < m_arrThreadTasks.end(); itPos++) delete *itPos;
m_arrThreadTasks.clear();
while (!m_PQueue.empty()) { m_PQueue.pop(); }
};
// Method signals threads to stop and waits for termination
void shutdown() {
for (unsigned int i = 0; i < m_arrThreadTasks.size(); i++) {
m_arrThreadTasks[i]->interrupt();
m_arrThreadTasks[i]->join();
}
};
};
#endif
\ No newline at end of file
// LocalLock.h: interface for the CLocalLock class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_LOCALLOCK_H__FD10F2F9_1DF2_46A6_8261_1FA9E2AB061C__INCLUDED_)
#define AFX_LOCALLOCK_H__FD10F2F9_1DF2_46A6_8261_1FA9E2AB061C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CLocalLock
{
public:
CLocalLock(LPCRITICAL_SECTION lpCriticalSection)
:m_lpCriticalSection(lpCriticalSection)
{
EnterCriticalSection(m_lpCriticalSection);
}
~CLocalLock()
{
LeaveCriticalSection(m_lpCriticalSection);
}
private:
LPCRITICAL_SECTION m_lpCriticalSection;
};
class CLock
{
public:
CLock()
{
InitializeCriticalSection(&m_cs);
}
~CLock()
{
DeleteCriticalSection(&m_cs);
}
void Lock()
{
EnterCriticalSection(&m_cs);
}
void UnLock()
{
LeaveCriticalSection(&m_cs);
}
private:
CRITICAL_SECTION m_cs;
};
#endif // !defined(AFX_LOCALLOCK_H__FD10F2F9_1DF2_46A6_8261_1FA9E2AB061C__INCLUDED_)
This diff is collapsed.
This diff is collapsed.
#pragma comment(lib, "USER32" )
#include <crtdbg.h>
#include <tchar.h>
#pragma comment(lib, "version.lib")
#define MTVERIFY(a) (a)
#if 0
#define SHOWERROR(a) PrintError(a,__FILE__,__LINE__,GetLastError())
#ifdef DEBUG
#define MTASSERT(a) _ASSERTE(a)
#define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())
#else /*DEBUG*/
#define MTASSERT(a)
#define MTVERIFY(a) (a)
#endif /*DEBUG*/
__inline void PrintError(LPCTSTR linedesc, LPCTSTR filename, int lineno, DWORD errnum)
{
LPTSTR lpBuffer;
TCHAR errbuf[256];
#ifdef _WINDOWS_
TCHAR modulename[MAX_PATH];
#else //_WINDOWS_
DWORD numread;
#endif //_WINDOWS_
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
0,
NULL
);
_stprintf(errbuf, _T("\nThe following call failed at line %d in %s:\n\n %s\n\nReason: %s\n"),
lineno, filename, linedesc, lpBuffer);
#ifndef _WINDOWS_
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, lstrlen(errbuf), &numread, FALSE );
Sleep(3000);
#else //_WINDOWS_
GetModuleFileName(NULL, modulename, MAX_PATH);
MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
OutputDebugString(errbuf);
#endif //_WINDOWS_
LocalFree(lpBuffer);
//exit(EXIT_FAILURE);
}
#endif
__inline void WaitTillThreadActive(HANDLE &handle)
{
if(handle != INVALID_HANDLE_VALUE)
{
BOOL rc = FALSE;
DWORD ec = 0;
for(;;)
{
rc = GetExitCodeThread(handle, &ec);
if(rc && (ec == STILL_ACTIVE))
break;
Sleep(500);
}
}
}
// obsolete
/*
__inline void WaitTillThreadExited(HANDLE &handle, DWORD dwMilliseconds = 3000)
{
if(handle != INVALID_HANDLE_VALUE)
{
BOOL rc = FALSE;
DWORD ec = 0;
DWORD dwStart = GetTickCount();
for(;;)
{
if(GetTickCount() - dwStart >= dwMilliseconds)
{
::TerminateThread(handle, 0xffffffff);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
break;
}
if(handle == INVALID_HANDLE_VALUE)
break;
rc = GetExitCodeThread(handle, &ec);
if(rc && (ec != STILL_ACTIVE))
{
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
break;
}
Sleep(500);
}
}
}
*/
__forceinline void WaitTillThreadExited(HANDLE &handle, DWORD dwMilliseconds = 5000)
{
if(handle == INVALID_HANDLE_VALUE)
return;
DWORD ret = ::WaitForSingleObject(handle, dwMilliseconds);
if(ret != WAIT_OBJECT_0)
{ //::TerminateThread(handle, 0xffffffff);
}
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
}
__inline LPTSTR GetModuleFilePath()
{
static TCHAR szPath[MAX_PATH] = {'\0'};
if(lstrlen(szPath) != 0)
return szPath;
TCHAR szExe[MAX_PATH];
GetModuleFileName(GetModuleHandle(NULL), szExe, MAX_PATH);
int len = lstrlen(szExe);
for(int i = len; i > 0; i--)
{
if(szExe[i] == '\\')
{
szExe[i] = '\0';
lstrcpy(szPath, szExe);
break;
}
}
return szPath;
}
/////////*********************自定义宏********************////////////////////////
//安全删除普通堆内存
#define SAFEDELETEP(p) {if(p){delete (p); (p)=NULL;}}
#define SAFEDELETEARR(pArr) {if((pArr)){delete[] (pArr); (pArr)=NULL;}}
//安全删除对话框类堆内存
#define SAFEDELETEDLG(pDlg) {if((pDlg)){(pDlg)->DestroyWindow(); delete (pDlg); (pDlg)=NULL;}}
//关闭核心对象句柄
#define CLOSEHANDLE(h){\
if(h != INVALID_HANDLE_VALUE)\
{ \
::CloseHandle(h); \
h = INVALID_HANDLE_VALUE;\
} \
}
#define CLOSESOCKET(s){\
if(s != INVALID_SOCKET)\
{ \
::closesocket(s); \
s = INVALID_SOCKET;\
} \
}
#ifdef _DEBUG
#define VERIFYPTR(p, cb) {MTVERIFY(!IsBadWritePtr(p, cb));}
#else
#define VERIFYPTR(p, cb)
#endif
/**************UNICODE-ANSI mutually transform**************************/
// need be manuly delete
__forceinline LPSTR Utf16ToAnsi(const wchar_t * const wSrc)
{
char* pElementText;
int iTextLen;
iTextLen = WideCharToMultiByte( CP_ACP, 0, wSrc, -1, NULL,0, NULL, NULL );
pElementText = new char[iTextLen + 1];
memset( ( void* )pElementText, 0, sizeof( char ) * ( iTextLen + 1 ) );
::WideCharToMultiByte( CP_ACP,0,wSrc,-1,pElementText,iTextLen,NULL,NULL);
return pElementText;
}
__forceinline BOOL Utf16ToAnsiUseCharArray(const wchar_t * const wSrc,
char *ansiArr, WORD ansiArrLen)
{
int iTextLen = WideCharToMultiByte( CP_ACP, 0, wSrc, -1, NULL,0, NULL, NULL );
if(iTextLen < ansiArrLen){
memset( ( void* )ansiArr, 0, sizeof( char ) * ( iTextLen + 1 ) );
::WideCharToMultiByte(CP_ACP,0,wSrc,-1,ansiArr,iTextLen,NULL,NULL);
return TRUE;
}
return FALSE;
}
__forceinline wchar_t* AnsiToUtf16(PCSTR ansiSrc)
{
wchar_t *pWide;
int iUnicodeLen = ::MultiByteToWideChar( CP_ACP,
0, ansiSrc, -1, NULL, 0);
pWide = new wchar_t[iUnicodeLen + 1];
memset(pWide, 0, (iUnicodeLen+1) * sizeof(wchar_t) );
::MultiByteToWideChar( CP_ACP, 0, ansiSrc, -1, (LPWSTR)pWide, iUnicodeLen );
return pWide;
}
__forceinline BOOL AnsiToUtf16Array(PCSTR ansiSrc, wchar_t* warr, int warr_len)
{
int iUnicodeLen = ::MultiByteToWideChar( CP_ACP,
0, ansiSrc, -1, NULL, 0);
if(warr_len >= iUnicodeLen){
memset(warr, 0, (iUnicodeLen+1) * sizeof(wchar_t) );
::MultiByteToWideChar( CP_ACP, 0, ansiSrc, -1, (LPWSTR)warr, iUnicodeLen );
return TRUE;
}
return FALSE;
}
__forceinline wchar_t* Utf8ToUtf16(PCSTR ansiSrc)
{
wchar_t *pWide;
int iUnicodeLen = ::MultiByteToWideChar( CP_UTF8,
0, ansiSrc, -1, NULL, 0);
pWide = new wchar_t[iUnicodeLen + 1];
memset(pWide, 0, (iUnicodeLen+1) * sizeof(wchar_t) );
::MultiByteToWideChar( CP_UTF8, 0, ansiSrc, -1, (LPWSTR)pWide, iUnicodeLen );
return pWide;
}
/*
__forceinline CString GetFileVersion()
{
int iVerInfoSize;
char *pBuf;
CString asVer= _T("");
VS_FIXEDFILEINFO *pVsInfo;
unsigned int iFileInfoSize = sizeof(VS_FIXEDFILEINFO);
TCHAR fileName[MAX_PATH];
GetModuleFileName(NULL, fileName, MAX_PATH);
iVerInfoSize = GetFileVersionInfoSize(fileName, NULL);
if(iVerInfoSize != 0){
pBuf = new char[iVerInfoSize];
if(GetFileVersionInfo(fileName, 0, iVerInfoSize, pBuf)){
if(VerQueryValue(pBuf, _T("//"), (void**)&pVsInfo, &iFileInfoSize)){
asVer.Format(_T("%d.%d.%d.%d"),
HIWORD(pVsInfo->dwFileVersionMS),
LOWORD(pVsInfo->dwFileVersionMS),
HIWORD(pVsInfo->dwFileVersionLS),
LOWORD(pVsInfo->dwFileVersionLS));
}
}
delete pBuf;
}
return asVer;
}
*/
\ No newline at end of file
#pragma comment( lib, "USER32" )
#include <crtdbg.h>
#include <tchar.h>
#define MTVERIFY(a) (a)
#if 0
#define SHOWERROR(a) PrintError(a,__FILE__,__LINE__,GetLastError())
#ifdef DEBUG
#define MTASSERT(a) _ASSERTE(a)
#define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())
#else /*DEBUG*/
#define MTASSERT(a)
#define MTVERIFY(a) (a)
#endif /*DEBUG*/
__inline void PrintError(LPCTSTR linedesc, LPCTSTR filename, int lineno, DWORD errnum)
{
LPTSTR lpBuffer;
TCHAR errbuf[256];
#ifdef _WINDOWS_
TCHAR modulename[MAX_PATH];
#else //_WINDOWS_
DWORD numread;
#endif //_WINDOWS_
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
0,
NULL
);
_stprintf(errbuf, _T("\nThe following call failed at line %d in %s:\n\n %s\n\nReason: %s\n"),
lineno, filename, linedesc, lpBuffer);
#ifndef _WINDOWS_
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, lstrlen(errbuf), &numread, FALSE );
Sleep(3000);
#else //_WINDOWS_
GetModuleFileName(NULL, modulename, MAX_PATH);
MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
OutputDebugString(errbuf);
#endif //_WINDOWS_
LocalFree(lpBuffer);
//exit(EXIT_FAILURE);
}
#endif
__inline void ExitError(LPCTSTR error)
{
//SHOWERROR(error);
ExitProcess(0);
}
__inline void WaitTillThreadActive(HANDLE &handle)
{
if(handle != INVALID_HANDLE_VALUE)
{
BOOL rc = FALSE;
DWORD ec = 0;
for(;;)
{
rc = GetExitCodeThread(handle, &ec);
if(rc && (ec == STILL_ACTIVE))
break;
Sleep(500);
}
}
}
// obsolete
/*
__inline void WaitTillThreadExited(HANDLE &handle, DWORD dwMilliseconds = 3000)
{
if(handle != INVALID_HANDLE_VALUE)
{
BOOL rc = FALSE;
DWORD ec = 0;
DWORD dwStart = GetTickCount();
for(;;)
{
if(GetTickCount() - dwStart >= dwMilliseconds)
{
::TerminateThread(handle, 0xffffffff);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
break;
}
if(handle == INVALID_HANDLE_VALUE)
break;
rc = GetExitCodeThread(handle, &ec);
if(rc && (ec != STILL_ACTIVE))
{
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
break;
}
Sleep(500);
}
}
}
*/
__forceinline void WaitTillThreadExited(HANDLE &handle, DWORD dwMilliseconds = 5000)
{
if(handle == INVALID_HANDLE_VALUE)
return;
DWORD ret = ::WaitForSingleObject(handle, dwMilliseconds);
if(ret != WAIT_OBJECT_0)
{ ::TerminateThread(handle, 0xffffffff); }
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
}
__inline LPTSTR GetModuleFilePath()
{
static TCHAR szPath[MAX_PATH] = {'\0'};
if(lstrlen(szPath) != 0)
return szPath;
TCHAR szExe[MAX_PATH];
GetModuleFileName(GetModuleHandle(NULL), szExe, MAX_PATH);
int len = lstrlen(szExe);
for(int i = len; i > 0; i--)
{
if(szExe[i] == '\\')
{
szExe[i] = '\0';
lstrcpy(szPath, szExe);
break;
}
}
return szPath;
}
/////////*********************自定义宏********************////////////////////////
//安全删除普通堆内存
#define SAFEDELETEP(p) {if(p){delete (p); (p)=NULL;}}
#define SAFEDELETEARR(pArr) {if((pArr)){delete[] (pArr); (pArr)=NULL;}}
//安全删除对话框类堆内存
#define SAFEDELETEDLG(pDlg) {if((pDlg)){(pDlg)->DestroyWindow(); delete (pDlg); (pDlg)=NULL;}}
//关闭核心对象句柄
#define CLOSEHANDLE(h){\
if(h != INVALID_HANDLE_VALUE)\
{ \
::CloseHandle(h); \
h = INVALID_HANDLE_VALUE;\
} \
}
#define CLOSESOCKET(s){\
if(s != INVALID_SOCKET)\
{ \
::closesocket(s); \
s = INVALID_SOCKET;\
} \
}
#ifdef _DEBUG
#define VERIFYPTR(p, cb) {MTVERIFY(!IsBadWritePtr(p, cb));}
#else
#define VERIFYPTR(p, cb)
#endif
/**************UNICODE-ANSI mutually transform**************************/
// need be manuly delete
__forceinline LPSTR UnicodeToAnsi(const wchar_t * const wSrc)
{
char* pElementText;
int iTextLen;
iTextLen = WideCharToMultiByte( CP_ACP, 0, wSrc, -1, NULL,0, NULL, NULL );
pElementText = new char[iTextLen + 1];
memset( ( void* )pElementText, 0, sizeof( char ) * ( iTextLen + 1 ) );
::WideCharToMultiByte( CP_ACP,0,wSrc,-1,pElementText,iTextLen,NULL,NULL);
return pElementText;
}
__forceinline BOOL UnicodeToAnsiUseCharArray(const wchar_t * const wSrc, char *ansiArr, WORD ansiArrLen)
{
int iTextLen = WideCharToMultiByte( CP_ACP, 0, wSrc, -1, NULL,0, NULL, NULL );
if(iTextLen < ansiArrLen)
{
memset( ( void* )ansiArr, 0, sizeof( char ) * ( iTextLen + 1 ) );
::WideCharToMultiByte(CP_ACP,0,wSrc,-1,ansiArr,iTextLen,NULL,NULL);
return TRUE;
}
return FALSE;
}
__forceinline wchar_t* AnsiToUtf16(PCSTR ansiSrc)
{
wchar_t *pWide;
int iUnicodeLen = ::MultiByteToWideChar( CP_ACP,
0, ansiSrc, -1, NULL, 0);
pWide = new wchar_t[iUnicodeLen + 1];
memset(pWide, 0, (iUnicodeLen+1) * sizeof(wchar_t) );
::MultiByteToWideChar( CP_ACP, 0, ansiSrc, -1, (LPWSTR)pWide, iUnicodeLen );
return pWide;
}
__forceinline wchar_t* Utf8ToUtf16(PCSTR ansiSrc)
{
wchar_t *pWide;
int iUnicodeLen = ::MultiByteToWideChar( CP_UTF8,
0, ansiSrc, -1, NULL, 0);
pWide = new wchar_t[iUnicodeLen + 1];
memset(pWide, 0, (iUnicodeLen+1) * sizeof(wchar_t) );
::MultiByteToWideChar( CP_UTF8, 0, ansiSrc, -1, (LPWSTR)pWide, iUnicodeLen );
return pWide;
}
// PointerList.cpp: implementation of the CPointerList class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "PointerList.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CPointerList::CPointerList()
{
m_pHead = m_pTail = NULL;
m_nCount = 0;
}
CPointerList::~CPointerList()
{
RemoveAll();
}
void CPointerList::AddTail(void *element)
{
PELEMENT pTmp = new ELEMENT;
pTmp->element = element;
if(m_pHead == NULL)
{
m_pHead = m_pTail = pTmp;
}
else
{
pTmp->pPrev = m_pTail;
m_pTail->pNext = pTmp;
m_pTail = pTmp;
}
m_nCount++;
int * p = (int*)&m_pHead;
int *p2 = &m_nCount;
}
void CPointerList::AddHead(void *element)
{
PELEMENT pTmp = new ELEMENT;
pTmp->element = element;
if(m_pHead == NULL)
{
m_pHead = m_pTail = pTmp;
}
else
{
pTmp->pNext = m_pHead;
m_pHead->pPrev = pTmp;
m_pHead = pTmp;
}
m_nCount++;
}
void CPointerList::RemoveAt(int index)
{
if(m_nCount > 0 && index >= 0 && index < m_nCount)
{
PELEMENT pCur = GetElementAt(index);
if(pCur)
{
PELEMENT pPrev = pCur->pPrev;
PELEMENT pNext = pCur->pNext;
delete pCur;
pCur = NULL;
if(pPrev)
pPrev->pNext = pNext;
else
m_pHead = pNext;
if(pNext)
pNext->pPrev = pPrev;
else
m_pTail = pPrev;
m_nCount--;
}
}
}
void CPointerList::RemoveHead()
{
if(m_nCount > 0)
{
PELEMENT pTmp = m_pHead->pNext;
delete m_pHead;
if(pTmp)
pTmp->pPrev = NULL;
m_pHead = pTmp;
m_nCount--;
}
}
void CPointerList::RemoveTail()
{
if(m_nCount > 0)
{
PELEMENT pTmp = m_pTail->pPrev;
delete m_pTail;
if(pTmp)
pTmp->pNext = NULL;
m_pTail = pTmp;
m_nCount--;
}
}
void CPointerList::RemoveAll()
{
if(m_nCount > 0)
{
PELEMENT pTmp = m_pHead;
while(pTmp)
{
m_pHead = pTmp;
pTmp = pTmp->pNext;
delete m_pHead;
}
m_pHead = m_pTail = NULL;
m_nCount = 0;
}
}
void CPointerList::InsertAt(int index, void *element)
{
PELEMENT pCur = GetElementAt(index);
if(pCur)
{
PELEMENT pNew = new ELEMENT;
pNew->element = element;
PELEMENT pPrev = pCur->pPrev;
if(pPrev)
{
pNew->pPrev = pPrev;
pPrev->pNext = pNew;
}
else
{
m_pHead = pNew;
}
pNew->pNext = pCur;
pCur->pPrev = pNew;
m_nCount++;
}
else
{
AddHead(element);
}
}
int CPointerList::GetCount()
{
return m_nCount;
}
void *CPointerList::GetHead()
{
return m_pHead->element;
}
void *CPointerList::GetTail()
{
return m_pTail->element;
}
void *CPointerList::GetNext(void *element)
{
PELEMENT pTmp = FindElement(element);
if(pTmp)
{
pTmp = pTmp->pNext;
}
return pTmp ? pTmp->element : NULL;
}
void *CPointerList::GetPrev(void *element)
{
PELEMENT pTmp = FindElement(element);
if(pTmp)
{
pTmp = pTmp->pPrev;
}
return pTmp ? pTmp->element : NULL;
}
int CPointerList::Find(void *element)
{
bool find = false;
int index = 0;
if(m_nCount > 0)
{
PELEMENT pTmp = m_pHead;
while(pTmp)
{
if(pTmp->element == element)
{
find = true;
break;
}
pTmp = pTmp->pNext;
index++;
}
}
return find ? index : -1;
}
PELEMENT CPointerList::GetElementAt(int index)
{
PELEMENT pTmp = NULL;
if(m_nCount > 0 && index >= 0 && index < m_nCount)
{
pTmp = m_pHead;
int i = 0;
while(i < index)
{
pTmp = pTmp->pNext;
i++;
}
}
return pTmp;
}
void* CPointerList::GetAt(int index)
{
PELEMENT pTmp = NULL;
if(m_nCount > 0 && index >= 0 && index < m_nCount)
{
pTmp = m_pHead;
int i = 0;
while(i < index && pTmp)
{
pTmp = pTmp->pNext;
i++;
}
if(i == index && pTmp)
return pTmp->element;
}
return NULL;
}
PELEMENT CPointerList::FindElement(void *element)
{
bool find = false;
PELEMENT pTmp = NULL;
if(m_nCount > 0)
{
pTmp = m_pHead;
while(pTmp)
{
if(pTmp->element == element)
{
find = true;
break;
}
pTmp = pTmp->pNext;
}
}
return find ? pTmp : NULL;
}
// PointerList.h: interface for the CPointerList class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_POINTERLIST_H__3FB7FEA8_DAE8_468B_9494_92CA39593E1A__INCLUDED_)
#define AFX_POINTERLIST_H__3FB7FEA8_DAE8_468B_9494_92CA39593E1A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//自定义存取指针的链表,不需要手动回收指针(删除节点时自动删除指针所指向的内存)
class CPointerList
{
typedef struct _ELEMENT
{
void *element;
_ELEMENT *pNext;
_ELEMENT *pPrev;
_ELEMENT() : element(NULL), pNext(NULL), pPrev(NULL) { }
}ELEMENT, *PELEMENT;
public:
CPointerList():m_pHead(NULL), m_pTail(NULL), m_nCount(0) { }
virtual ~CPointerList() {RemoveAll();}
public:
void* GetAt(int index){
PELEMENT pTmp = NULL;
if(m_nCount > 0 && index >= 0 && index < m_nCount){
pTmp = m_pHead;
int i = 0;
while(i < index && pTmp){
pTmp = pTmp->pNext;
i++;
}
if(i == index && pTmp)
return pTmp->element;
}
return NULL;
}
int Find(void *element){
bool find = false;
int index = 0;
if(m_nCount > 0){
PELEMENT pTmp = m_pHead;
while(pTmp){
if(pTmp->element == element){
find = true;
break;
}
pTmp = pTmp->pNext;
index++;
}
}
return find ? index : -1;
}
void AddTail(void *element){
PELEMENT pTmp = new ELEMENT;
pTmp->element = element;
if(m_pHead == NULL){
m_pHead = m_pTail = pTmp;
}else{
pTmp->pPrev = m_pTail;
m_pTail->pNext = pTmp;
m_pTail = pTmp;
}
m_nCount++;
}
void AddHead(void *element){
PELEMENT pTmp = new ELEMENT;
pTmp->element = element;
if(m_pHead == NULL){
m_pHead = m_pTail = pTmp;
}else{
pTmp->pNext = m_pHead;
m_pHead->pPrev = pTmp;
m_pHead = pTmp;
}
m_nCount++;
}
void RemoveAt(int index){
if(m_nCount > 0 && index >= 0 && index < m_nCount){
PELEMENT pCur = GetElementAt(index);
if(pCur){
PELEMENT pPrev = pCur->pPrev;
PELEMENT pNext = pCur->pNext;
delete pCur;
pCur = NULL;
if(pPrev)
pPrev->pNext = pNext;
else
m_pHead = pNext;
if(pNext)
pNext->pPrev = pPrev;
else
m_pTail = pPrev;
m_nCount--;
}
}
}
void RemoveHead(){
if(m_nCount > 0){
PELEMENT pTmp = m_pHead->pNext;
delete m_pHead;
if(pTmp)
pTmp->pPrev = NULL;
m_pHead = pTmp;
m_nCount--;
}
}
void RemoveTail(){
if(m_nCount > 0){
PELEMENT pTmp = m_pTail->pPrev;
delete m_pTail;
if(pTmp)
pTmp->pNext = NULL;
m_pTail = pTmp;
m_nCount--;
}
}
void RemoveAll(){
if(m_nCount > 0){
PELEMENT pTmp = m_pHead;
while(pTmp){
m_pHead = pTmp;
pTmp = pTmp->pNext;
delete m_pHead;
}
m_pHead = m_pTail = NULL;
m_nCount = 0;
}
}
void InsertAt(int index, void *element){
PELEMENT pCur = GetElementAt(index);
if(pCur){
PELEMENT pNew = new ELEMENT;
pNew->element = element;
PELEMENT pPrev = pCur->pPrev;
if(pPrev){
pNew->pPrev = pPrev;
pPrev->pNext = pNew;
}else{
m_pHead = pNew;
}
pNew->pNext = pCur;
pCur->pPrev = pNew;
m_nCount++;
}else{
AddHead(element);
}
}
int GetCount() const{
return m_nCount;
}
void *GetHead(){
return m_pHead ? m_pHead->element : NULL;
}
void *GetTail(){
return m_pTail ? m_pTail->element : NULL;
}
void *GetNext(void *element){
PELEMENT pTmp = FindElement(element);
if(pTmp)
pTmp = pTmp->pNext;
return pTmp ? pTmp->element : NULL;
}
void *GetPrev(void *element){
PELEMENT pTmp = FindElement(element);
if(pTmp)
pTmp = pTmp->pPrev;
return pTmp ? pTmp->element : NULL;
}
private:
PELEMENT m_pHead;
PELEMENT m_pTail;
int m_nCount;
protected:
PELEMENT GetElementAt(int index){
PELEMENT pTmp = NULL;
if(m_nCount > 0 && index >= 0 && index < m_nCount){
pTmp = m_pHead;
int i = 0;
while(i < index){
pTmp = pTmp->pNext;
i++;
}
}
return pTmp;
}
PELEMENT FindElement(void *element){
bool find = false;
PELEMENT pTmp = NULL;
if(m_nCount > 0){
pTmp = m_pHead;
while(pTmp){
if(pTmp->element == element){
find = true;
break;
}
pTmp = pTmp->pNext;
}
}
return find ? pTmp : NULL;
}
};
#endif // !defined(AFX_POINTERLIST_H__3FB7FEA8_DAE8_468B_9494_92CA39593E1A__INCLUDED_)
// VsVer.h
#pragma once
/***************************************/
// 为了代码在vc6和vs2010下都能通过编译,定义以下宏
#if _MSC_VER == 1200 // vc6的cl版本号
#define _ultoa_s _ultoa
#define _itoa_s _itoa
#define _ltoa_s _ltoa
#define _gcvt_s(buffer, sizeInBytes, value, digits) _gcvt(value, digits, buffer)
#define sprintf_s sprintf
#define fopen_s(p,f,m) {*p = fopen(f,m);}
#define _tfopen_s(p,f,m) {*p = _tfopen(f,m);}
#define _tfreopen_s(p,t,m,s) {*p = _tfreopen(t,m,s);}
#define _tcscpy_s _tcscpy
#define strcpy_s(dst, ct, src) strcpy(dst, src)
#define _vsntprintf_s(buff, size, count, format, argptr) _vsntprintf(buff, count, format, argptr)
#define _vsnwprintf_s(buff, size, count, format, argptr) _vsnwprintf(buff, count, format, argptr)
#define _vsnprintf_s(buff, size, count, format, argptr) _vsnprintf(buff, count, format, argptr)
//#define _snprintf_s(buff, size, count, format, argptr) _snprintf(buff, count, format, argptr)
//#define _snprintf_s(buff, count, format, argptr) _snprintf(buff, format, argptr)
#define _stprintf_s(buff, format, arg1, arg2) _stprintf(buff, format, arg1, arg2)
#define strcat_s(dst, len, src) strcat(dst, src)
#define _countof sizeof
#endif
/***************************************/
\ No newline at end of file
This diff is collapsed.
tinyxml2 @ cf33e37d
Subproject commit cf33e37d25346d108ef00b3bfa447b9a8f69382f
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment