Browse Source

1、SATClient类
2、数据加载gif对话框;

scbc.sat2 5 years ago
parent
commit
8fbdb49fcb

+ 130 - 0
SATHelper/SATHelper/Base64.cpp

@@ -0,0 +1,130 @@
+#include "stdafx.h"
+#include "Base64.h"
+
+CBase64::CBase64(void)
+{
+}
+
+CBase64::~CBase64(void)
+{
+}
+
+const char CBase64::sm_base64digits[65] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const char CBase64::sm_base64val[128] = {
+	BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+	BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+	BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+	52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+	BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
+	15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+	BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
+	41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+
+/************************************************************************/
+/*  函数:[6/2/2016 IT];
+/*  描述:将字节转换为Base64字符;
+/*  参数:;
+/*  	[IN] pbinary:			要转换成Base64字符的二进制字节数组;
+/*  	[IN] nbinaryLen:		pbinary所指向的缓存大小;
+/*  	[OUT] pOutBase64:		返回转换后的Base64字符,以'\0'结束;
+/*  返回:返回转换成功后的Base64字符数;
+/*  注意:注意参数1是字节BYTE,返回的pOutBase64是人为加上'\0'结束符;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+void CBase64::binToBase64(IN const unsigned char *pbinary, IN size_t nbinaryLen, OUT char *pOutBase64)
+{
+	for ( ; nbinaryLen >= 3; nbinaryLen -= 3, pbinary += 3) 
+	{
+		*pOutBase64++ = sm_base64digits[pbinary[0] >> 2];
+		*pOutBase64++ = sm_base64digits[((pbinary[0] << 4) & 0x30) | (pbinary[1] >> 4)];
+		*pOutBase64++ = sm_base64digits[((pbinary[1] << 2) & 0x3c) | (pbinary[2] >> 6)];
+		*pOutBase64++ = sm_base64digits[pbinary[2] & 0x3f];
+	}
+
+	if (nbinaryLen > 0) 
+	{
+		unsigned char fragment;
+		*pOutBase64++ = sm_base64digits[pbinary[0] >> 2];
+		fragment = (pbinary[0] << 4) & 0x30;
+
+		if (nbinaryLen > 1)
+			fragment |= pbinary[1] >> 4;
+
+		*pOutBase64++ = sm_base64digits[fragment];
+		*pOutBase64++ = (nbinaryLen < 2) ? '=' : sm_base64digits[(pbinary[1] << 2) & 0x3c];
+		*pOutBase64++ = '=';
+	}
+	*pOutBase64 = '\0';
+}
+
+/************************************************************************/
+/*  函数:[6/2/2016 IT];
+/*  描述:将Base64字符串转为化二进制字节字符串;
+/*  参数:;
+/*  	[IN] pBase64:		要转化成二进制字节字符串的Base64字符;
+/*  	[OUT] pbinary:		返回转化成二进制字节的字符串;
+/*  	[IN] maxLen:		pbinary指向的缓存大小;
+/*  返回:返回转化成二进制字节字符数;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+int CBase64::base64ToBin(IN const char *pBase64, OUT unsigned char *pbinary, IN size_t maxLen)
+{
+	size_t len = 0;
+	unsigned char digit1, digit2, digit3, digit4;
+
+	if (pBase64[0] == '+' && pBase64[1] == ' ')
+		pBase64 += 2;
+	if (pBase64[0] == '\r')
+		return 0;
+
+	while (*pBase64 && *pBase64 != '\r' /*&& digit4 != '='*/) 
+	{
+		digit1 = pBase64[0];
+		if (decode64(digit1) == BAD)
+			return -1;
+		digit2 = pBase64[1];
+		if (decode64(digit2) == BAD)
+			return -1;
+		digit3 = pBase64[2];
+		if (digit3 != '=' && decode64(digit3) == BAD)
+			return -1; 
+		digit4 = pBase64[3];
+		if (digit4 != '=' && decode64(digit4) == BAD)
+			return -1;
+		pBase64 += 4;
+
+		++len;
+		if (maxLen && len > maxLen)
+			return -1;
+
+		*(pbinary++) = (decode64(digit1) << 2) | (decode64(digit2) >> 4);
+		if (digit3 != '=') 
+		{
+			++len;
+			if (maxLen && len > maxLen)
+				return -1;
+			*(pbinary++) = ((decode64(digit2) << 4) & 0xf0) | (decode64(digit3) >> 2);
+			if (digit4 != '=') 
+			{
+				++len;
+				if (maxLen && len > maxLen)
+					return -1;
+				*(pbinary++) = ((decode64(digit3) << 6) & 0xc0) | decode64(digit4);
+			} // if
+		} // if
+	} // while
+
+	return len;
+}

+ 70 - 0
SATHelper/SATHelper/Base64.h

@@ -0,0 +1,70 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[5/24/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#ifndef __BASE64_CODE__
+#define __BASE64_CODE__
+
+#pragma once
+
+class CBase64
+{
+public:
+	CBase64(void);
+	~CBase64(void);
+
+	/************************************************************************/
+	/*  函数:[5/24/2016 IT];
+	/*  描述:获取指定字符串长度对应的Base64字符长度;
+	/*  参数:;
+	/*  	[IN] len:要计算的字符长度;
+	/*  返回:返回指定长度len的字符串转换为编码Base64对应的长度,并多加一个'\0'结束符;
+	/*  注意:;
+	/************************************************************************/
+	static int CalcBase64Len(IN const size_t& len) {
+		return (len / 3 + (len % 3 ? 1 : 0)) * 4 + 1; // one more byte for '\0'
+	}
+
+	static void binToBase64(IN const unsigned char *pbinary, IN size_t nbinaryLen, OUT char *pOutBase64);
+
+	/************************************************************************/
+	/*  函数:[5/24/2016 IT];
+	/*  描述:获取指定Base64字符串长度对应的字节长度;
+	/*  参数:;
+	/*  	[IN] len:要计算的Base64字符长度;
+	/*  返回:返回指定长度len的Base64字符串转换为字节对应的长度;
+	/*  注意:;
+	/************************************************************************/
+	static int CalcBinLen(size_t len) {
+		return len / 4 * 3; 
+	}
+
+	static int base64ToBin(IN const char *pBase64, OUT unsigned char *pbinary, IN size_t maxLen);
+
+private:
+	static char decode64(unsigned char ch) {
+		return ch < 128 ? sm_base64val[ch] : BAD;
+	}
+
+private:
+	enum {BAD = -1};
+	// 必须是ASCII字符;
+	static const char sm_base64digits[65];
+	// 必须是ASCII字符;
+	static const char sm_base64val[128];
+};
+
+#endif // __BASE64_CODE__

+ 740 - 0
SATHelper/SATHelper/CharEncoding.cpp

@@ -0,0 +1,740 @@
+#include "stdafx.h"
+#include "CharEncoding.h"
+
+WCHAR* CharEncoding::ASCII2UNICODE(IN LPCCH lpASCIIStr)
+{
+	if ( lpASCIIStr == NULL )
+		return NULL;
+
+	// 获取宽字符字节数;
+	int cchWideChar  = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, NULL, 0);
+	if ( cchWideChar == 0)
+		return NULL;
+
+	// 转换成宽字符串;
+	WCHAR *pWideChar = new WCHAR[cchWideChar + 1];
+	memset(pWideChar, 0 , sizeof(WCHAR)*(cchWideChar + 1));
+	int nWriteNum = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, pWideChar, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+	{ 
+		if (pWideChar) 
+			delete []pWideChar;
+		return NULL;
+	}
+
+	return pWideChar;
+}
+
+BOOL CharEncoding::ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen)
+{
+	if ( lpASCIIStr == NULL )
+		return FALSE;
+
+	// 获取宽字符字节数;
+	int cchWideChar  = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, NULL, 0);
+	if ( cchWideChar == 0 || cchWideChar >= nUNICODEStrLen)
+		return FALSE;
+
+	// 转换成宽字符串;
+	memset(pUNICODEStr, 0 , sizeof(WCHAR)*nUNICODEStrLen);
+	int nWriteNum = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, pUNICODEStr, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+		return FALSE;
+
+	return TRUE;
+}
+
+BOOL CharEncoding::ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT wstring &strResult)
+{
+	if ( lpASCIIStr == NULL )
+		return FALSE;
+
+	// 获取宽字符字节数;
+	int cchWideChar  = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, NULL, 0);
+	if ( cchWideChar == 0 )
+		return FALSE;
+
+	// 转换成宽字符串;
+	WCHAR *pResult = new WCHAR[cchWideChar];
+	memset(pResult, 0 , sizeof(WCHAR)*cchWideChar);
+	int nWriteNum = MultiByteToWideChar(CP_ACP, 0, lpASCIIStr, -1, pResult, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+		return FALSE;
+
+	strResult = pResult;
+	if ( pResult )
+		delete[] pResult;
+
+	return TRUE;
+}
+
+CHAR* CharEncoding::UNICODE2ASCII(IN LPWCH lpUNICODEStr)
+{
+	if ( lpUNICODEStr == NULL )
+		return NULL;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 )
+		return NULL;
+
+	// 转换成多字节字符;
+	CHAR *pMultiByteStr = new CHAR[cbMultiByte+1];
+	memset(pMultiByteStr, 0, cbMultiByte + 1);
+	int nWriteNum = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, pMultiByteStr, cbMultiByte, NULL, NULL);
+	if (nWriteNum != cbMultiByte)
+	{
+		if (pMultiByteStr) 
+			delete []pMultiByteStr;
+		return NULL;
+	}
+
+	return pMultiByteStr;
+}
+
+BOOL CharEncoding::UNICODE2ASCII(IN LPWCH lpUNICODEStr, OUT LPCH pASCIIStr, IN CONST INT& nASCIIStrLen)
+{
+	if ( lpUNICODEStr == NULL )
+		return FALSE;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 || cbMultiByte >= nASCIIStrLen )
+		return FALSE;
+
+	// 转换成多字节字符;
+	memset((void*)pASCIIStr, 0, nASCIIStrLen);
+	int nWriteNum = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, pASCIIStr, cbMultiByte, NULL, NULL);
+	if (nWriteNum != cbMultiByte)
+	{
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+BOOL CharEncoding::UNICODE2ASCII(IN LPWCH lpUNICODEStr, OUT string &strResult)
+{
+	if ( lpUNICODEStr == NULL )
+		return FALSE;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 )
+		return FALSE;
+
+	// 转换成多字节字符;
+	CHAR* pResult = new CHAR[cbMultiByte];
+	memset(pResult, 0, cbMultiByte);
+	int nWriteNum = WideCharToMultiByte(CP_OEMCP, 0, lpUNICODEStr, -1, pResult, cbMultiByte, NULL, NULL);
+	if (nWriteNum != cbMultiByte)
+		return FALSE;
+
+	strResult = pResult;
+	if ( pResult )
+		delete[] pResult;
+
+	return TRUE;
+}
+
+CHAR* CharEncoding::UNICODE2UTF8(IN LPWCH lpUNICODEStr)
+{
+	if ( lpUNICODEStr == NULL )
+		return NULL;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 )
+		return NULL;
+
+	// 转换成多字节字符;
+	CHAR* pMultiByteStr = new CHAR[cbMultiByte+1];
+	memset(pMultiByteStr, 0, cbMultiByte + 1);
+	int nWriteNum = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, pMultiByteStr, cbMultiByte, NULL, NULL);
+	if (nWriteNum != cbMultiByte)
+	{
+		if (pMultiByteStr) 
+			delete []pMultiByteStr;
+		return NULL;
+	}
+
+	return pMultiByteStr;
+}
+
+BOOL CharEncoding::UNICODE2UTF8(IN LPWCH lpUNICODEStr, OUT LPCH pUTF8Str, IN CONST INT& nUTF8StrLen)
+{
+	if ( lpUNICODEStr == NULL )
+		return FALSE;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 || cbMultiByte >= nUTF8StrLen )
+		return FALSE;
+
+	// 转换成多字节字符;
+	memset(pUTF8Str, 0, nUTF8StrLen);
+	int nWriteNum = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, pUTF8Str, cbMultiByte, NULL, NULL);
+	if (nWriteNum != cbMultiByte)
+	{
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+BOOL CharEncoding::UNICODE2UTF8(IN LPWCH lpUNICODEStr, OUT string &strResult)
+{
+	if ( lpUNICODEStr == NULL )
+		return FALSE;
+
+	// 获取多字节字符字节数;
+	int cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, NULL, 0, NULL, NULL);
+	if ( cbMultiByte == 0 )
+		return FALSE;
+
+	// 转换成多字节字符;
+	CHAR *pResult = new CHAR[cbMultiByte];
+	memset(pResult, 0, cbMultiByte);
+	int nWriteNum = WideCharToMultiByte(CP_UTF8, 0, lpUNICODEStr, -1, pResult, cbMultiByte, NULL, NULL);
+	
+	strResult = pResult;
+	if ( pResult )
+		delete[] pResult;
+
+	if (nWriteNum != cbMultiByte)
+		return FALSE;
+
+	return TRUE;
+}
+
+CHAR* CharEncoding::ASCII2UTF8(IN LPCCH lpASCIIStr)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = ASCII2UNICODE(lpASCIIStr);
+	if ( pWideChar == NULL )
+		return NULL;
+
+	// 再将UICODE转成UTF8;
+	CHAR* pUTF8 = UNICODE2UTF8(pWideChar);
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return pUTF8;
+}
+
+BOOL CharEncoding::ASCII2UTF8(IN LPCCH lpASCIIStr, OUT LPCH pUTF8Str, IN CONST INT& nUTF8StrLen)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = ASCII2UNICODE(lpASCIIStr);
+	if ( pWideChar == NULL )
+		return FALSE;
+
+	// 再将UICODE转成UTF8;
+	BOOL bResult = UNICODE2UTF8(pWideChar, pUTF8Str, nUTF8StrLen);
+
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return bResult;
+}
+
+BOOL CharEncoding::ASCII2UTF8(IN LPCCH lpASCIIStr, OUT string &strResult)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = ASCII2UNICODE(lpASCIIStr);
+	if ( pWideChar == NULL )
+		return FALSE;
+
+	// 再将UICODE转成UTF8;
+	BOOL bResult = UNICODE2UTF8(pWideChar, strResult);
+
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return bResult;
+}
+
+WCHAR* CharEncoding::UTF82UNICODE(IN LPCCH lpUTF8)
+{
+	if ( lpUTF8 == NULL )
+		return NULL;
+
+	// 获取unicode字符数;
+	int cchWideChar = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, NULL, 0);
+	if ( cchWideChar == 0)
+		return NULL;
+
+	// 转换成宽字符串;
+	WCHAR *pWideChar = new WCHAR[cchWideChar + 1];
+	memset(pWideChar, 0 , sizeof(WCHAR)*(cchWideChar + 1));
+	int nWriteNum = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, pWideChar, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+	{ 
+		if (pWideChar) 
+			delete []pWideChar;
+		return NULL;
+	}
+
+	return pWideChar;
+}
+
+BOOL CharEncoding::UTF82UNICODE(IN LPCCH lpUTF8, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen)
+{
+	if ( lpUTF8 == NULL )
+		return FALSE;
+
+	// 获取宽字符字节数;
+	int cchWideChar  = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, NULL, 0);
+	if ( cchWideChar == 0 || cchWideChar >= nUNICODEStrLen)
+		return FALSE;
+
+	// 转换成宽字符串;
+	memset(pUNICODEStr, 0 , sizeof(WCHAR)*nUNICODEStrLen);
+	int nWriteNum = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, pUNICODEStr, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+		return FALSE;
+
+	return TRUE;
+}
+
+BOOL CharEncoding::UTF82UNICODE(IN LPCCH lpUTF8, OUT wstring &strResult)
+{
+	if ( lpUTF8 == NULL )
+		return FALSE;
+
+	// 获取宽字符字节数;
+	int cchWideChar  = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, NULL, 0);
+	if ( cchWideChar == 0 )
+		return FALSE;
+
+	// 转换成宽字符串;
+	WCHAR* pResult = new WCHAR[cchWideChar];
+	memset(pResult, 0 , sizeof(WCHAR)*cchWideChar);
+	int nWriteNum = MultiByteToWideChar(CP_UTF8, 0, lpUTF8, -1, pResult, cchWideChar );
+	if ( nWriteNum != cchWideChar)
+		return FALSE;
+
+	strResult = pResult;
+	if ( pResult )
+		delete[] pResult;
+
+	return TRUE;
+}
+
+CHAR* CharEncoding::UTF82ASCII(IN LPCCH lpUTF8)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = UTF82UNICODE(lpUTF8);
+	if ( pWideChar == NULL )
+		return NULL;
+
+	// 再将UICODE转成UTF8;
+	CHAR* pUTF8 = UNICODE2ASCII(pWideChar);
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return pUTF8;
+}
+
+BOOL CharEncoding::UTF82ASCII(IN LPCCH lpUTF8, OUT LPCH pASCIIStr, IN CONST INT& nASCIIStrLen)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = UTF82UNICODE(lpUTF8);
+	if ( pWideChar == NULL )
+		return FALSE;
+
+	// 再将UICODE转成UTF8;
+	BOOL bResult = UNICODE2ASCII(pWideChar, pASCIIStr, nASCIIStrLen);
+
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return bResult;
+}
+
+BOOL CharEncoding::UTF82ASCII(IN LPCCH lpUTF8, OUT string &strResult)
+{
+	// 将ASCII字符串转成UNICODE字符串;
+	WCHAR* pWideChar = UTF82UNICODE(lpUTF8);
+	if ( pWideChar == NULL )
+		return FALSE;
+
+	// 再将UICODE转成UTF8;
+	BOOL bResult = UNICODE2ASCII(pWideChar, strResult);
+
+	if ( pWideChar )
+		delete []pWideChar;
+
+	return bResult;
+}
+
+//做为解Url使用
+char CharEncoding::CharToInt(char ch)
+{
+	if (ch >= '0' && ch <= '9')return (char)(ch - '0');
+	if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10);
+	if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10);
+	return -1;
+}
+
+char CharEncoding::StrToBin(IN char (&str)[2])
+{
+	char tempWord[2];
+	char chn;
+
+	tempWord[0] = CharToInt(str[0]);                         //make the B to 11 -- 00001011
+	tempWord[1] = CharToInt(str[1]);                         //make the 0 to 0  -- 00000000
+
+	chn = (tempWord[0] << 4) | tempWord[1];                //to change the BO to 10110000
+
+	return chn;
+}
+
+//GB2312 转为 UTF-8
+void CharEncoding::GB2312ToUTF_8(string& pOut, const char *pText, int pLen)
+{
+	char buf[4];
+	memset(buf, 0, 4);
+
+	pOut.clear();
+
+	int i = 0;
+	while (i < pLen)
+	{
+		//如果是英文直接复制就可以;
+		if (pText[i] >= 0)
+		{
+			char asciistr[2] = { 0 };
+			asciistr[0] = (pText[i++]);
+			pOut.append(asciistr);
+		}
+		else
+		{
+			WCHAR pbuffer[2] = {0};
+			MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pText + i, 2, pbuffer, 1);
+			UNICODE2UTF8(pbuffer, buf, 4);
+			pOut.append(buf);
+			i += 2;
+		}
+	}
+
+	return;
+}
+
+/************************************************************************/
+/*  函数:[7/26/2016 IT];
+/*  描述:将字符串编码成为GB2312格式的URL;;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+string CharEncoding::EnCode_GB2312URL(IN const CHAR* pText)
+{
+	string dd;
+	size_t len = strlen(pText);
+	for (size_t i = 0; i < len; i++)
+	{
+		if (isalnum((BYTE)pText[i]))
+		{
+			char tempbuff[2];
+			sprintf_s(tempbuff, "%c", pText[i]);
+			dd.append(tempbuff);
+		}
+		else if (isspace((BYTE)pText[i]))
+		{
+			dd.append("+");
+		}
+		else
+		{
+			char tempbuff[4];
+			sprintf_s(tempbuff, "%%%X%X", ((BYTE*)pText)[i] >> 4, ((BYTE*)pText)[i] % 16);
+			dd.append(tempbuff);
+		}
+	}
+	return dd;
+}
+
+void CharEncoding::EnCode_GB2312URL(IN CHAR* pText, OUT string& strResult)
+{
+	size_t len = strlen(pText);
+	for (size_t i = 0; i < len; i++)
+	{
+		if (isalnum((BYTE)pText[i]))
+		{
+			char tempbuff[2];
+			sprintf_s(tempbuff, "%c", pText[i]);
+			strResult.append(tempbuff);
+		}
+		else if (isspace((BYTE)pText[i]))
+		{
+			strResult.append("+");
+		}
+		else
+		{
+			char tempbuff[4];
+			sprintf_s(tempbuff, "%%%X%X", ((BYTE*)pText)[i] >> 4, ((BYTE*)pText)[i] % 16);
+			strResult.append(tempbuff);
+		}
+	}
+}
+
+/************************************************************************/
+/*  函数:[7/26/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+string CharEncoding::EnCode_UTF8URL(IN const CHAR* pText)
+{
+	string tt = "";
+	string dd = "";
+	ASCII2UTF8(pText,tt);
+
+	size_t len = tt.length();
+	for (size_t i = 0; i < len; i++)
+	{
+		if (isalnum((BYTE)tt.at(i)))
+		{
+			char tempbuff[2] = { 0 };
+			sprintf_s(tempbuff, "%c", (BYTE)tt.at(i));
+			dd.append(tempbuff);
+		}
+		else if (isspace((BYTE)tt.at(i)))
+		{
+			dd.append("+");
+		}
+		else
+		{
+			char tempbuff[4];
+			sprintf_s(tempbuff, "%%%X%X", ((BYTE)tt.at(i)) >> 4, ((BYTE)tt.at(i)) % 16);
+			dd.append(tempbuff);
+		}
+	}
+	return dd;
+}
+
+void CharEncoding::EnCode_UTF8URL(IN const CHAR* pText, OUT string& strResult)
+{
+	string tt = "";
+	ASCII2UTF8(pText,tt);
+
+	size_t len = tt.length();
+	for (size_t i = 0; i < len; i++)
+	{
+		if (isalnum((BYTE)tt.at(i)))
+		{
+			char tempbuff[2] = { 0 };
+			sprintf_s(tempbuff, "%c", (BYTE)tt.at(i));
+			strResult.append(tempbuff);
+		}
+		else if (isspace((BYTE)tt.at(i)))
+		{
+			strResult.append("+");
+		}
+		else
+		{
+			char tempbuff[4];
+			sprintf_s(tempbuff, "%%%X%X", ((BYTE)tt.at(i)) >> 4, ((BYTE)tt.at(i)) % 16);
+			strResult.append(tempbuff);
+		}
+	}
+}
+
+string CharEncoding::EnCode_UNICODEURL(IN const CHAR* pText)
+{
+	return "";
+}
+
+/************************************************************************/
+/*  函数:[7/26/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+string CharEncoding::DeCode_URLGB2312(IN const CHAR* pURLText)
+{
+	string output = "";
+	char tmp[2];
+	int i = 0, idx = 0, len = strlen(pURLText);
+
+	while (i < len){
+		if (pURLText[i] == '%')
+		{
+			tmp[0] = pURLText[i + 1];
+			tmp[1] = pURLText[i + 2];
+			output += StrToBin(tmp);
+			i = i + 3;
+		}
+		else if (pURLText[i] == '+')
+		{
+			output += ' ';
+			i++;
+		}
+		else{
+			output += pURLText[i];
+			i++;
+		}
+	}
+
+	return output;
+}
+
+void CharEncoding::DeCode_URLGB2312(IN const CHAR* pURLText, OUT string& strResult)
+{
+	char tmp[2];
+	int i = 0, idx = 0, len = strlen(pURLText);
+
+	while (i < len){
+		if (pURLText[i] == '%')
+		{
+			tmp[0] = pURLText[i + 1];
+			tmp[1] = pURLText[i + 2];
+			strResult += StrToBin(tmp);
+			i = i + 3;
+		}
+		else if (pURLText[i] == '+')
+		{
+			strResult += ' ';
+			i++;
+		}
+		else{
+			strResult += pURLText[i];
+			i++;
+		}
+	}
+}
+
+/************************************************************************/
+/*  函数:[7/26/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+string CharEncoding::DeCode_URLUTF8(IN const CHAR* pURLText)
+{
+	string output = "";
+	string temp = DeCode_URLGB2312(pURLText);
+	UTF82ASCII(temp.c_str(), output);
+	return output;
+}
+
+void CharEncoding::DeCode_URLUTF8(IN const CHAR* pURLText, OUT string& strResult)
+{
+	string temp = DeCode_URLGB2312(pURLText);
+	UTF82ASCII(temp.c_str(), strResult);
+}
+
+/************************************************************************/
+/*  函数:[7/26/2016 IT];
+/*  描述:;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+string CharEncoding::DeCode_URLUNICODE(IN const CHAR* pURLText)
+{
+	string str = pURLText;
+	string strResult = "";
+
+	INT nIndex = 0;
+	string strTemp = "";
+
+	while ( str.find_first_of("\\u") != string::npos )
+	{
+		nIndex = str.find_first_of("\\u");
+		strResult.append(str.substr(0, nIndex));
+		strTemp = str.substr(nIndex + 2, 4);
+		str = str.substr(nIndex + 2 +4);
+		CHAR szReturn[10] = {0};
+
+		union  __UNION_VAR_INT{
+			BYTE   ch[2];   
+			int	   value;   
+		}unionVarInt;
+
+		unionVarInt.ch[0] =  (CharToInt(strTemp.at(2)) << 4) | (CharToInt(strTemp.at(3))  & 0x00FF);
+		unionVarInt.ch[1] =  (CharToInt(strTemp.at(0)) << 4) | (CharToInt(strTemp.at(1))  & 0x00FF);
+
+		WCHAR szWide[2] = {0};
+		szWide[0] = unionVarInt.value;
+		UNICODE2ASCII(szWide,szReturn,10);
+		strResult.append(szReturn);
+	}
+	strResult.append(str);
+
+	return strResult;
+}
+
+void CharEncoding::DeCode_URLUNICODE(IN const CHAR* pURLText, OUT string& strResult)
+{
+	string str = pURLText;
+
+	INT nIndex = 0;
+	string strTemp = "";
+
+	while ( str.find_first_of("\\u") != string::npos )
+	{
+		nIndex = str.find_first_of("\\u");
+		strResult.append(str.substr(0, nIndex));
+		strTemp = str.substr(nIndex + 2, 4);
+		str = str.substr(nIndex + 2 +4);
+		CHAR szReturn[10] = {0};
+
+		union  __UNION_VAR_INT{
+			BYTE   ch[2];   
+			int	   value;   
+		}unionVarInt;
+
+		unionVarInt.ch[0] =  (CharToInt(strTemp.at(2)) << 4) | (CharToInt(strTemp.at(3))  & 0x00FF);
+		unionVarInt.ch[1] =  (CharToInt(strTemp.at(0)) << 4) | (CharToInt(strTemp.at(1))  & 0x00FF);
+
+		WCHAR szWide[2] = {0};
+		szWide[0] = unionVarInt.value;
+		UNICODE2ASCII(szWide,szReturn,10);
+		strResult.append(szReturn);
+	}
+	strResult.append(str);
+}

+ 97 - 0
SATHelper/SATHelper/CharEncoding.h

@@ -0,0 +1,97 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [IT], 保留所有权利;
+/*  模 块 名:公共模块,未做性能优化;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[IT];
+/*  日    期:[7/26/2016];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[IT];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#ifndef __CHAR_ENCODING__
+#define __CHAR_ENCODING__
+
+#include <string>
+#include <vector>
+using namespace std;
+
+#ifndef _UNICODE
+typedef string TString;
+#else
+typedef wstring TString;
+#endif
+
+#pragma once
+
+
+class  CharEncoding
+{
+public:
+	// 将字符转化为对应的ASCII十进制值;
+	static char CharToInt(char ch);
+	// 将两个字符串转化成十六进制值;
+	static char StrToBin(IN char (&str)[2]);
+	static void GB2312ToUTF_8(string& pOut, const char *pText, int pLen);
+	// 将ASCII字符串转成UNICODE字符串;
+	static WCHAR* ASCII2UNICODE(IN LPCCH lpASCIIStr);
+	static BOOL   ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen);
+	static BOOL   ASCII2UNICODE(IN LPCCH lpASCIIStr, OUT wstring &strResult);
+
+	// 将UNICODE字符串转成ASCII字符串;
+	static CHAR* UNICODE2ASCII(IN LPWCH lpUNICODEStr);
+	static BOOL  UNICODE2ASCII(IN LPWCH lpUNICODEStr, OUT LPCH pASCIIStr, IN CONST INT& nASCIIStrLen);
+	static BOOL  UNICODE2ASCII(IN LPWCH lpUNICODEStr, OUT string &strResult);
+
+	// 将UNICODE字符串转成UFT8字符串;
+	static CHAR* UNICODE2UTF8(IN LPWCH lpUNICODEStr);
+	static BOOL  UNICODE2UTF8(IN LPWCH lpUNICODEStr, OUT LPCH pUTF8Str, IN CONST INT& nUTF8StrLen);
+	static BOOL  UNICODE2UTF8(IN LPWCH lpUNICODEStr, OUT string &strResult);
+
+	// 将ASCII字符串转成UTF8字符串;
+	static CHAR* ASCII2UTF8(IN LPCCH lpASCIIStr);
+	static BOOL  ASCII2UTF8(IN LPCCH lpASCIIStr, OUT LPCH pUTF8Str, IN CONST INT& nUTF8StrLen);
+	static BOOL  ASCII2UTF8(IN LPCCH lpASCIIStr, OUT string &strResult);
+
+	// 将UTF-8字符串转成UNICODE字符串;
+	static WCHAR* UTF82UNICODE(IN LPCCH lpUTF8);
+	static BOOL   UTF82UNICODE(IN LPCCH lpUTF8, OUT PWCH pUNICODEStr, IN CONST INT& nUNICODEStrLen);
+	static BOOL   UTF82UNICODE(IN LPCCH lpUTF8, OUT wstring &strResult);
+
+	// 将UTF-8字符串转成ASCII字符串;
+	static CHAR*  UTF82ASCII(IN LPCCH lpUTF8);
+	static BOOL   UTF82ASCII(IN LPCCH lpUTF8, OUT LPCH pASCIIStr, IN CONST INT& nASCIIStrLen);
+	static BOOL   UTF82ASCII(IN LPCCH lpUTF8, OUT string &strResult);
+
+	// 将UTF-8编码成GB2312;
+	static string UTF8IntoGB2313(IN CHAR* pUTF8Text, IN const INT& nUTF8TextLen);
+	// 将GB2312编码成UTF-8;
+	static string GB2312IntoUTF8(IN CHAR* pGB2312Text, IN const INT& nGB2312TextLen);
+
+	// 将字符串编码成为GB2312编码格式的URL;
+	static string EnCode_GB2312URL(IN const CHAR* pText);
+	static void EnCode_GB2312URL(IN CHAR* pText, OUT string& strResult);
+	// 将字符串编码成为UTF-8编码格式的URL;
+	static string EnCode_UTF8URL(IN const CHAR* pText);
+	static void EnCode_UTF8URL(IN const CHAR* pText, OUT string& strResult);
+	// 将字符串编码成为UNICODE编码格式的URL;
+	static string EnCode_UNICODEURL(IN const CHAR* pText);	// 未完成该函数;
+
+	// 解码UTF-8编码格式的URL;
+	static string DeCode_URLUTF8(IN const CHAR* pURLText);
+	static void DeCode_URLUTF8(IN const CHAR* pURLText, OUT string& strResult);
+	// 解码GB2312编码格式的URL;
+	static string DeCode_URLGB2312(IN const CHAR* pURLText);
+	static void DeCode_URLGB2312(IN const CHAR* pURLText, OUT string& strResult);
+	// 解码UNICODE编码格式的URL;
+	static string DeCode_URLUNICODE(IN const CHAR* pURLText);
+	static void DeCode_URLUNICODE(IN const CHAR* pURLText, OUT string& strResult);
+};
+
+#endif

+ 71 - 0
SATHelper/SATHelper/DlgLogin.cpp

@@ -0,0 +1,71 @@
+// DlgLogin.cpp: 实现文件
+//
+
+#include "stdafx.h"
+#include "SATHelper.h"
+#include "DlgLogin.h"
+#include "afxdialogex.h"
+#include "SATClient.h"
+
+
+// CDlgLogin 对话框
+
+IMPLEMENT_DYNAMIC(CDlgLogin, CDialogEx)
+
+CDlgLogin::CDlgLogin(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DLG_LOGIN, pParent)
+{
+
+}
+
+CDlgLogin::~CDlgLogin()
+{
+}
+
+void CDlgLogin::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CDlgLogin, CDialogEx)
+	ON_BN_CLICKED(IDOK, &CDlgLogin::OnBnClickedOk)
+	ON_BN_CLICKED(IDCANCEL, &CDlgLogin::OnBnClickedCancel)
+END_MESSAGE_MAP()
+
+
+// CDlgLogin 消息处理程序
+
+
+BOOL CDlgLogin::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// TODO:  在此添加额外的初始化
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 异常: OCX 属性页应返回 FALSE
+}
+
+
+void CDlgLogin::OnBnClickedOk()
+{
+	// TODO: 在此添加控件通知处理程序代码
+	CString strUserName, strPassword;
+	GetDlgItemText(IDC_EDIT_USERNAME, strUserName);
+	GetDlgItemText(IDC_EDIT_PASSWORD, strPassword);
+
+	if ( CSATClient::GetInstance()->TCPLogin(strUserName.GetString(), strPassword.GetString()) )
+	{
+
+	}
+
+	CDialogEx::OnOK();
+}
+
+
+void CDlgLogin::OnBnClickedCancel()
+{
+	// TODO: 在此添加控件通知处理程序代码
+	CDialogEx::OnCancel();
+}

+ 27 - 0
SATHelper/SATHelper/DlgLogin.h

@@ -0,0 +1,27 @@
+#pragma once
+
+
+// CDlgLogin 对话框
+
+class CDlgLogin : public CDialogEx
+{
+	DECLARE_DYNAMIC(CDlgLogin)
+
+public:
+	CDlgLogin(CWnd* pParent = nullptr);   // 标准构造函数
+	virtual ~CDlgLogin();
+
+// 对话框数据
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DLG_LOGIN };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg void OnBnClickedOk();
+	afx_msg void OnBnClickedCancel();
+};

+ 168 - 0
SATHelper/SATHelper/DlgProBar.cpp

@@ -0,0 +1,168 @@
+// DlgProBar.cpp : 实现文件
+//
+#include "stdafx.h"
+#include "SATHelper.h"
+#include "DlgProBar.h"
+#include "afxdialogex.h"
+
+#include "IMGCommon.h"
+#include "SATClient.h"
+
+// CDlgProBar 对话框
+
+Image* CDlgProBar::m_spImg = NULL;
+BOOL CDlgProBar::m_sbRuning = TRUE;
+Brush *CDlgProBar::m_pBrush = NULL;
+IMPLEMENT_DYNAMIC(CDlgProBar, CDialogEx)
+
+CDlgProBar::CDlgProBar(CWnd* pParent /*=NULL*/)
+	: CDialogEx(IDD_DLG_PROBAR, pParent)
+{
+	m_ulTimeCount = 0;
+	m_nFrameCount = 0;
+	m_nCurFrameIndex = 0;
+	m_pPropertyItem = NULL;
+}
+
+CDlgProBar::~CDlgProBar()
+{
+}
+
+void CDlgProBar::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CDlgProBar, CDialogEx)
+	ON_MESSAGE(WM_STOPTHREAD, &CDlgProBar::StopThread)
+	ON_WM_TIMER()
+END_MESSAGE_MAP()
+
+
+// CDlgProBar 消息处理程序
+
+BOOL CDlgProBar::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// TODO:  在此添加额外的初始化
+	m_sbRuning = TRUE;
+	if ( m_spImg )
+		delete m_spImg;
+	m_spImg = NULL;
+	m_spImg = IMGCommon::LoadImgFromResource(NULL, MAKEINTRESOURCE(GIF_PROBAR), _T("GIF"));
+
+#if 1
+	// 获取gif里的维度个数(gif就一个维度);
+	UINT nCount = m_spImg->GetFrameDimensionsCount();
+	
+	// 获得维度的GUID列表;
+	GUID* pDimensionsIDs = (GUID*)new GUID[nCount];
+	m_spImg->GetFrameDimensionsList(pDimensionsIDs, nCount);
+	
+	// 获得指定的维度的帧数;
+	//WCHAR strGUID[39] = { 0 };
+	//StringFromGUID2(pDimensionsIDs[0], strGUID, 39);
+	m_nFrameCount = m_spImg->GetFrameCount(&pDimensionsIDs[0]);
+	delete[] pDimensionsIDs;
+
+	// 获得每帧之间的时间间隔;
+	int size = m_spImg->GetPropertyItemSize(PropertyTagFrameDelay);	// 获取时间间隔属性item;
+	m_pPropertyItem = new byte[size];
+	PropertyItem*  pItem = (PropertyItem*)m_pPropertyItem;
+	m_spImg->GetPropertyItem(PropertyTagFrameDelay, size, pItem);
+
+	CClientDC dc(this);
+	Graphics gc(dc);
+	gc.DrawImage(m_spImg, 0, 0, m_spImg->GetWidth(), m_spImg->GetHeight());
+
+	// 超时值;
+	m_ulTimeCount = GetTickCount64();
+	SetTimer(0, 0, NULL);
+#endif
+
+	MoveWindow(0, 0, m_spImg->GetWidth(), m_spImg->GetHeight());
+	CenterWindow();
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+	// 异常: OCX 属性页应返回 FALSE
+}
+
+LRESULT CDlgProBar::StopThread(WPARAM wp, LPARAM lp)
+{
+	m_sbRuning = FALSE;
+	return 0;
+}
+
+void CDlgProBar::OnCancel()
+{
+	// TODO: 在此添加专用代码和/或调用基类
+	CDialogEx::OnCancel();
+}
+
+void CDlgProBar::OnOK()
+{
+	// TODO: 在此添加专用代码和/或调用基类
+
+	//CDialogEx::OnOK();
+}
+
+DWORD g_dwTimeOut = 30000;
+void CDlgProBar::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	if ( nIDEvent == 0 )
+	{
+		KillTimer(0);
+
+		// 是否超时;
+		if (GetTickCount64() - m_ulTimeCount > g_dwTimeOut) {
+			m_sbRuning = FALSE;
+			if (m_spImg)
+				delete m_spImg;
+			m_spImg = NULL;
+			if (m_pPropertyItem)
+				delete[]m_pPropertyItem;
+			m_pPropertyItem = NULL;
+
+			CSATClient::GetInstance()->Stop();
+			AfxMessageBox(_T("连接超时!"));
+
+			PostMessage(WM_CLOSE);
+			
+			return;
+		}
+
+		GUID guid = FrameDimensionTime;
+		CClientDC dc(this);
+		Graphics gc(dc);
+		gc.DrawImage(m_spImg, 0, 0, m_spImg->GetWidth(), m_spImg->GetHeight());
+		// 选择要显示的帧;
+		m_spImg->SelectActiveFrame(&guid, m_nCurFrameIndex++);
+		if (m_nCurFrameIndex == m_nFrameCount)
+		{
+			m_nCurFrameIndex = 0;
+		}
+
+		PropertyItem* pItem = (PropertyItem*)m_pPropertyItem;
+		long pause = ((long*)pItem->value)[m_nCurFrameIndex] * 1000;
+		pause = pause ? pause : 39;
+		
+		if (m_sbRuning)
+		{
+			SetTimer(0, pause, NULL);
+		}
+		else
+		{
+			if (m_spImg)
+				delete m_spImg;
+			m_spImg = NULL;
+			if (m_pPropertyItem)
+				delete[]m_pPropertyItem;
+			m_pPropertyItem = NULL;
+			PostMessage(WM_CLOSE);
+		}
+	}
+	CDialogEx::OnTimer(nIDEvent);
+}

+ 43 - 0
SATHelper/SATHelper/DlgProBar.h

@@ -0,0 +1,43 @@
+#ifndef __DLG_PRO_BAR__
+#define __DLG_PRO_BAR__
+
+#pragma once
+
+// CDlgProBar 对话框
+#define  WM_STOPTHREAD		WM_USER + 1001
+
+class CDlgProBar : public CDialogEx
+{
+	DECLARE_DYNAMIC(CDlgProBar)
+
+public:
+	CDlgProBar(CWnd* pParent = NULL);   // 标准构造函数
+	virtual ~CDlgProBar();
+
+// 对话框数据
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DLG_PROBAR };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+
+	ULONGLONG m_ulTimeCount;
+	static Brush *m_pBrush;
+	static Image *m_spImg;
+	static BOOL m_sbRuning;
+	UINT	m_nFrameCount;
+	INT		m_nCurFrameIndex;
+	BYTE*	m_pPropertyItem;
+	virtual void OnCancel();
+
+	LRESULT	StopThread(WPARAM wp, LPARAM lp);
+	virtual void OnOK();
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+};
+
+#endif

+ 1558 - 0
SATHelper/SATHelper/IMGCommon.cpp

@@ -0,0 +1,1558 @@
+#include "StdAfx.h"
+#include "IMGCommon.h"
+#include <strsafe.h>
+
+#include "CharEncoding.h"
+
+#ifdef _DEBUG  
+#define new DEBUG_NEW  
+#endif 
+
+const ColorMatrix _ClrMatrix = 
+{
+	1.0, 0.0, 0.0, 0.0, 0.0, 
+	0.0, 1.0, 0.0, 0.0, 0.0, 
+	0.0, 0.0, 0.3, 0.0, 0.0, 
+	0.0, 0.0, 0.0, 1.0, 0.0, 
+	0.0, 0.0, 0.0, 0.0, 1.0, 
+};
+
+ULONG_PTR IMGCommon::m_gdiplusToken;
+
+IMGCommon::IMGCommon(void)
+{
+	GdiplusStartupInput gdiplusStartupInput;
+	GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+IMGCommon::~IMGCommon(void)
+{
+	Gdiplus::GdiplusShutdown(m_gdiplusToken);
+}
+
+	/************************************************************************/
+	/*  函数:IsValidpath[3/20/2016 IT];
+	/*  描述:判断一个路径是否是本地可以盘符或可用的网络路径;
+	/*  参数:;
+	/*  	[IN] strPath:要判断的路径;
+	/*  返回:盘符或网络路径有效返回TRUE;
+	/*  注意:;
+	/*  示例:;
+	/*
+	/*  修改:;
+	/*  日期:;
+	/*  内容:;
+	/************************************************************************/
+	BOOL IMGCommon::IsValidpath(IN CONST TString &strPath)
+	{
+		// 文件表现形式有三种:
+		// 1.本地形式: C:\myfolder\you
+		// 2.共享形式: \\192.168.1.112\myfolder\\you
+		if (strPath.size() < 2) return FALSE;
+
+		// 含":"为本地路径;
+		if (strPath[1] == _T(':'))
+		{
+			DWORD dwDiskType = 0;
+			dwDiskType = GetDriveType(strPath.substr(0, 3).c_str());
+			switch (dwDiskType)
+			{
+			case DRIVE_UNKNOWN:			// 未知驱动盘符;
+			case DRIVE_NO_ROOT_DIR:		// 没有根目录;
+				//case DRIVE_REMOVABLE:		// 移动存储设备盘符;
+				// case DRIVE_FIXED:		// 硬盘;
+			case DRIVE_CDROM:			// CD盘符;
+			case DRIVE_RAMDISK:			// ;
+				return FALSE;
+				break;
+			}
+		}
+		else if (strPath.substr(0, 2).find(_T("\\\\")) != TString::npos)
+		{
+			// 共享路径;
+			TString strtmp = strPath.substr(2);
+			int n = strPath.substr(2).find(_T("\\"));
+			if (n == TString::npos)
+				return FALSE;
+
+			strtmp = strPath.substr(0, n + 2);
+
+			// 需要判断网络路径可用否;
+			DWORD dwRet = 0;
+			NETRESOURCE nr;
+			memset(&nr, 0, sizeof(nr));
+			nr.dwScope = RESOURCE_CONNECTED;
+			nr.dwType = RESOURCETYPE_ANY;
+			nr.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
+			nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
+
+#ifndef UNICODE
+			nr.lpRemoteName = (LPSTR)strtmp.c_str();
+#else
+			nr.lpRemoteName = (LPWSTR)(strtmp.c_str());
+#endif
+			dwRet = WNetAddConnection2(&nr, NULL, NULL, CONNECT_UPDATE_PROFILE);
+			if (dwRet == ERROR_BAD_NETPATH)// 无效的网络路径,表示没有这个网络地址;
+				return FALSE;
+			else if (dwRet == ERROR_LOGON_FAILURE)// 登陆这个网络路径失败,因为当前用户名和密码错误; 没有权限;
+				return FALSE;
+		}
+
+		return TRUE;
+	}
+
+void IMGCommon::Splitpath(IN CONST TCHAR *path, IN TCHAR * drive, IN size_t driveNumberOfElements, IN TCHAR * dir, IN size_t dirNumberOfElements, IN CONST int &nTimes)
+	{
+		int i = 0;
+		int npoint = 0;	// '.'
+		int nsprit = 0; // '\\'
+		int ncolon = 0; // ':'
+		int ntimes = 0;
+		int nlen = _tcslen(path);
+		while (nlen > i++)
+		{
+			if (path[i] == _T(':') && !ncolon )
+			{
+				ncolon = i;
+			}
+			else if (path[i] == _T('\\'))
+			{
+				if ( ncolon )
+				{// 本地目录;
+					if ( i == ncolon+1 )
+						continue;
+
+					nsprit = i;
+					ntimes++;
+					if (nTimes == ntimes) break;
+				}
+				else
+				{// 网络路径;
+					if ( i == 0 || i == 1 )
+						continue;
+
+					nsprit = i;
+					ntimes++;
+					if (nTimes == ntimes-1) break;
+				}
+			}
+		}
+
+		memcpy_s(drive, driveNumberOfElements*sizeof(TCHAR), path, (ncolon + 1)*sizeof(TCHAR));
+		memcpy_s(dir, dirNumberOfElements*sizeof(TCHAR), &path[ncolon + 1], (nsprit - ncolon)*sizeof(TCHAR));
+	}
+
+	/************************************************************************/
+	/*  函数:CreateDirectoryEx,多字节版本,支持UNICODE[9/13/2016 IT];
+	/*  描述:创建目录及子目录文件夹;
+	/*  参数:;
+	/*  	[IN] lpDestDirectory:目录,必须是"E:\lyfzdb\数据\"格式,目录最后必须有"\",否则最后一个子目录无法创建!建议使用系统_tsplitpath来分隔目录,这样会保存最后一个"\"斜杠;
+	/*  返回:成功创建返回TRUE;
+	/*  注意:;
+	/*  示例:;
+	/*
+	/*  修改:;
+	/*  日期:;
+	/*  内容:;
+	/************************************************************************/
+	BOOL IMGCommon::CreateDirectoryEx(IN LPCTSTR lpNewDirectory)
+	{
+		// 判断路径有效性 ;
+		if (!lpNewDirectory || !IsValidpath(lpNewDirectory)) return FALSE;
+
+		BOOL bExists = FALSE;
+		TCHAR szNewFileName[_MAX_PATH] = { 0 };
+		TCHAR szDrive[_MAX_DRIVE] = { 0 };
+		TCHAR szDir[_MAX_DIR] = { 0 };
+		TCHAR szFna[_MAX_FNAME] = { 0 };
+		TCHAR szExt[_MAX_EXT] = { 0 };
+
+		TCHAR szNewDirectory[_MAX_PATH] = { 0 };
+		if (lpNewDirectory[_tcslen(lpNewDirectory) - 1] != _T('\\'))
+			StringCchPrintf(szNewDirectory, _MAX_PATH, _T("%s\\"), lpNewDirectory);
+		else
+			StringCchPrintf(szNewDirectory, _MAX_PATH, _T("%s"), lpNewDirectory);
+
+		int nIndex = 0;
+		do
+		{
+			bExists = PathFileExists(szNewDirectory);
+			if (!bExists)
+			{
+
+				memset(szDrive, 0, _MAX_DRIVE*sizeof(TCHAR));
+				memset(szDir, 0, _MAX_DIR*sizeof(TCHAR));
+				memset(szFna, 0, _MAX_FNAME*sizeof(TCHAR));
+				memset(szExt, 0, _MAX_EXT*sizeof(TCHAR));
+
+				Splitpath(szNewDirectory, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, ++nIndex);
+				StringCchPrintf(szNewFileName, _MAX_PATH, _T("%s%s"), szDrive, szDir);
+				if (!CreateDirectory(szNewFileName, NULL))
+				{
+					DWORD dwError = GetLastError();				
+					switch (dwError)
+					{
+					case ERROR_PATH_NOT_FOUND:		// 路径未找到,上一层目录未创建导致该错误;
+					case ERROR_ACCESS_DENIED:		// 没有权限访问;
+					case ERROR_BAD_NET_NAME:		// 错误的网络名称;
+						//case ERROR_BAD_PATHNAME: // 
+						//WriteTextLog(_T("创建目录失败:%s"), GetErrorInfo(dwError));
+						return FALSE;
+						break;
+					case ERROR_ALREADY_EXISTS:		// 文件存在,不需要创建;
+						break;
+					default:
+						//WriteTextLog(_T("创建目录失败:%s"), GetErrorInfo(dwError));
+						break;
+					}
+				}
+			}
+		} while (!bExists);
+
+		return TRUE;
+	}
+
+//////////////////////////////////////////////////////////////////////////
+BOOL IMGCommon::LoadImgFromFile(IN Image** pImg, LPCTSTR lpPath)
+{
+	if ( !PathFileExists(lpPath) )
+		return FALSE;
+
+	if ( *pImg )
+		delete *pImg;
+
+	*pImg  = NULL;
+
+#ifdef UNICODE
+	*pImg = Image::FromFile(lpPath);
+#else
+	BSTR strtmp = _bstr_t(lpPath);
+	*pImg = Image::FromFile(strtmp);
+	SysFreeString(strtmp);
+#endif
+
+	return (*pImg ? TRUE : FALSE);
+}
+
+BOOL IMGCommon::LoadImgFromBuffer(IN Image** pImg, IN BYTE* pBuffer, IN CONST INT& nBufLen)
+{
+	if ( pBuffer == NULL )
+		return FALSE;
+
+	if ( *pImg )
+		delete *pImg;
+
+	*pImg  = NULL;
+	HGLOBAL hMemery = GlobalAlloc(GMEM_MOVEABLE, nBufLen);
+	if ( hMemery == NULL )
+		return FALSE;
+
+	BYTE *pMem = (BYTE*)GlobalLock(hMemery);
+	memcpy(pMem, pBuffer, nBufLen);
+
+	IStream *pstream = NULL;
+	CreateStreamOnHGlobal(hMemery, TRUE, &pstream);
+	*pImg = Image::FromStream(pstream);
+	GlobalUnlock(hMemery);
+	pstream->Release();
+
+	return (*pImg ? TRUE : FALSE);
+}
+
+// 先以只读方式从文件中读取二进制流出来,可以做到不独占文件;
+BOOL IMGCommon::LoadImgFromBuffer(IN Image** pImg, LPCTSTR lpPath)
+{
+	if ( !PathFileExists(lpPath) )
+		return FALSE;
+
+	if ( *pImg )
+		delete *pImg;
+	*pImg  = NULL;
+	
+	CFile fp;
+	CFileException e;
+	BOOL bRet = FALSE;
+	if ( fp.Open(lpPath, CFile::modeRead, &e))
+	{
+		DWORD dwLength = (DWORD)fp.GetLength();
+		BYTE *pData = new BYTE[dwLength];
+		
+		fp.Read(pData,dwLength);
+		fp.Close();
+
+		bRet = LoadImgFromBuffer(pImg, pData, dwLength);
+
+		if( pData )
+			delete []pData;
+	}
+
+	return bRet;
+}
+
+/************************************************************************/
+/*  函数:LoadImgFromResource[9/21/2016 IT];
+/*  描述:从资源中加载;
+/*  参数:;
+/*  	[IN] :;
+/*  	[OUT] :;
+/*  	[IN/OUT] :;
+/*  返回:void;
+/*  注意:;
+/*  示例:;
+/*
+/*  修改:;
+/*  日期:;
+/*  内容:;
+/************************************************************************/
+Image* IMGCommon::LoadImgFromResource(IN HMODULE hModule, IN LPCTSTR lpName, IN LPCTSTR lpType)
+{
+	HGLOBAL	hGlobal = NULL;
+	HRSRC	hSource = NULL;
+	LPVOID  lpBuffer = NULL;
+	DWORD   dwSize = 0;
+	// 1.定位我们的自定义资源,这里因为我们是从本模块定位资源,所以将句柄简单地置为NULL即可
+	hSource = FindResource(hModule, lpName, lpType);
+	if (hSource == NULL)
+	{
+		_tprintf(_T("载入资源失败:%s"), lpName);
+		return NULL;
+	}
+
+	// 2.获取资源的大小;
+	dwSize = (UINT)SizeofResource(NULL, hSource);
+
+	// 3.加载资源;
+	hGlobal = LoadResource(NULL, hSource);
+	if (hGlobal == NULL)
+	{
+		_tprintf(_T("载入资源失败:%s"), lpName);
+		return NULL;
+	}
+
+	// 4.锁定资源,获取buffer;
+	lpBuffer = LockResource(hGlobal);
+	if (lpBuffer == NULL)
+	{
+		_tprintf(_T("载入资源失败:%s"), lpName);
+		return NULL;;
+	}
+
+	// lpFileFullName需要先判断文件是否存在??不需要;
+	Image *pImg = NULL;
+	LoadImgFromBuffer(&pImg, (BYTE*)lpBuffer, dwSize);
+
+	UnlockResource(hGlobal);
+	FreeResource(hGlobal);
+
+	return pImg;
+}
+
+BOOL IMGCommon::GetOrientation(IN Image *pImg)
+{
+	if (pImg == NULL) return FALSE;
+
+	UINT totalBufferSize;
+	UINT numProperties;
+	pImg->GetPropertySize(&totalBufferSize, &numProperties);
+	// Allocate the buffer that will receive the property items.
+	PropertyItem* pAllItems = (PropertyItem*)malloc(totalBufferSize);
+	// Fill the buffer.
+	pImg->GetAllPropertyItems(totalBufferSize, numProperties, pAllItems);
+	// Print the id data member of each property item.
+	for (UINT j = 0; j < numProperties; ++j)
+	{
+		if (PropertyTagOrientation == pAllItems[j].id)
+		{
+			short* ptrLong = (short*)(pAllItems[j].value);
+			int ret = (int)*ptrLong;
+			free(pAllItems);
+			return ret;
+		}
+	}
+	free(pAllItems);
+
+	return TRUE;
+}
+
+
+/************************************************************************/
+/*
+	函数:GetEncoderClsid
+	描述:获取GDI+支持的图像格式编码器种类,以及所有种类编码器信息;
+	参数:
+		IN:  format 要获取的图像格式;
+		OUT: pClsid 返回符合条件的图像编码器信息;
+	返回:成功返回编码器索引,否则返回-1;
+*/
+/************************************************************************/
+int IMGCommon::GetEncoderClsid(IN CONST WCHAR* format, OUT CLSID* pClsid)
+{
+	// GDI+支持的图像编码器数量;
+	UINT  numEncoders = 0;
+	// GDI+所有图像格式编码器详细信息所需要的空间大小;
+	UINT  nSize = 0;
+
+	ImageCodecInfo* pImageCodecInfo = NULL;
+
+	// 2.获取GDI+支持的所有图像格式编码器详细信息所需要的空间大小;
+	GetImageEncodersSize(&numEncoders, &nSize);
+	if (nSize == 0)
+		return -1;
+
+	//3.为ImageCodecInfo数组分配足额空间;
+	pImageCodecInfo = (ImageCodecInfo*)(malloc(nSize));
+	if (pImageCodecInfo == NULL)
+		return -1;
+
+	//4.获取所有的图像编码器信息;
+	GetImageEncoders(numEncoders, nSize, pImageCodecInfo);
+
+	//5.查找符合的图像编码器的Clsid;
+	for (UINT i = 0; i < numEncoders; ++i)
+	{
+		if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
+		{
+			*pClsid = pImageCodecInfo[i].Clsid;
+			free(pImageCodecInfo);
+			return i;  // Success
+		}
+	}
+
+	//6.释放步骤3分配的内存;
+	free(pImageCodecInfo);
+
+	return -1;
+}
+
+/************************************************************************/
+/*
+	函数:SaveImg2newfile
+	描述:将Image对象另存为其他格式的文件;
+	参数:
+		IN:  pImg		GDI+ Image对象指针,需要保存的图像对象;
+		IN:	 lpnewfile	其他格式的新文件名(jpg,bmp,png,jpeg);
+		IN:  uQuality	另存为新文件时的图像质量值;
+	返回:
+
+	注意:Image::Save 若文件存在,会覆盖存在的文件;
+*/
+/************************************************************************/
+BOOL IMGCommon::SaveImg2newfile(IN Image* pImg, IN CString strNewfile, IN ULONG uQuality)
+{
+	if (pImg == NULL) return FALSE;
+
+	// 需要判断路径是否存在,不存在创建目录;
+	int nIndex = strNewfile.ReverseFind(_T('\\'));
+	if (nIndex == -1)
+		return FALSE;
+
+	if (!PathFileExists(strNewfile.Left(nIndex)))
+	{
+		// 如果文件夹不存在,创建;
+#if 0
+		CreateDirectoryEx(strNewfile.Left(nIndex));
+#else
+		SHCreateDirectoryEx(NULL, strNewfile.Left(nIndex), NULL);
+#endif
+	}
+
+	nIndex = strNewfile.ReverseFind(_T('.'));
+	if (nIndex == -1)
+		return FALSE;
+
+	Status stat = GenericError;
+	CLSID encoderClsid = { 0 };
+	BSTR newfile = strNewfile.AllocSysString();
+
+	strNewfile = strNewfile.Mid(nIndex + 1);
+	if (strNewfile.CompareNoCase(_T("bmp")) == 0)
+	{
+		GetEncoderClsid(L"image/bmp", &encoderClsid);
+		stat = pImg->Save(newfile, &encoderClsid, NULL);
+	}
+	else if (strNewfile.CompareNoCase(_T("png")) == 0)
+	{
+		GetEncoderClsid(L"image/png", &encoderClsid);
+		stat = pImg->Save(newfile, &encoderClsid, NULL);
+	}
+	else// if ( strNewfile.CompareNoCase(_T("jpeg")) == 0 )
+	{
+		GetEncoderClsid(L"image/jpeg", &encoderClsid);
+
+		EncoderParameters encoderParameters;
+		encoderParameters.Count = 1;
+		encoderParameters.Parameter[0].Guid = EncoderQuality;
+		encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
+		encoderParameters.Parameter[0].NumberOfValues = 1;
+		// Save the image as a JPEG with quality level 100.
+		encoderParameters.Parameter[0].Value = &uQuality;
+		stat = pImg->Save(newfile, &encoderClsid, &encoderParameters);
+	}
+
+	SysFreeString(newfile);
+
+	return stat == Ok ? TRUE : FALSE;
+}
+
+BOOL IMGCommon::SaveImg2newfile(IN Image* pImg, IN TString strNewfile, IN ULONG uQuality)
+{
+	if (pImg == NULL) return FALSE;
+
+	// 需要判断路径是否存在,不存在创建目录;
+	int nIndex = strNewfile.find_last_of(_T('\\'));
+	if (nIndex == TString::npos)
+		return FALSE;
+
+	if (!PathFileExists(strNewfile.substr(0, nIndex).c_str()))
+	{
+		// 如果文件夹不存在,创建;
+#if 0
+		CreateDirectoryEx(strNewfile.substr(0, nIndex).c_str());
+#else
+		SHCreateDirectoryEx(NULL, strNewfile.substr(0, nIndex).c_str(), NULL);
+#endif
+	}
+
+	nIndex = strNewfile.find_last_of(_T('.'));
+	if (nIndex == TString::npos)
+		return FALSE;
+
+	Status stat = GenericError;
+	CLSID encoderClsid = { 0 };
+	BSTR newfile = _bstr_t(strNewfile.c_str());
+
+	strNewfile = strNewfile.substr(nIndex + 1);
+	if (strNewfile.find(_T("bmp")) == 0)
+	{
+		GetEncoderClsid(L"image/bmp", &encoderClsid);
+		stat = pImg->Save(newfile, &encoderClsid, NULL);
+	}
+	else if (strNewfile.find(_T("png")) == 0)
+	{
+		GetEncoderClsid(L"image/png", &encoderClsid);
+		stat = pImg->Save(newfile, &encoderClsid, NULL);
+	}
+	else// if ( strNewfile.CompareNoCase(_T("jpeg")) == 0 )
+	{
+		GetEncoderClsid(L"image/jpeg", &encoderClsid);
+
+		EncoderParameters encoderParameters;
+		encoderParameters.Count = 1;
+		encoderParameters.Parameter[0].Guid = EncoderQuality;
+		encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
+		encoderParameters.Parameter[0].NumberOfValues = 1;
+		// Save the image as a JPEG with quality level 100.
+		encoderParameters.Parameter[0].Value = &uQuality;
+		stat = pImg->Save(newfile, &encoderClsid, &encoderParameters);
+	}
+
+	SysFreeString(newfile);
+
+	return stat == Ok ? TRUE : FALSE;
+}
+
+/************************************************************************/
+/*
+	函数:ZoomImg
+	描述:缩放到指定大小的区域中,返回缩放后的尺寸;
+	参数:
+		IN:		Imgrc			图像的大小;
+		IN:		dwDisplayPix	图像要显示的区域的大小;
+		OUT:	dwZoomPix		图像在显示区域内缩放后的尺寸;
+	返回:
+
+	注意:dwZoomPix的尺寸必须在dwDisplayPix内;
+*/
+/************************************************************************/
+int IMGCommon::ZoomImg(IN CRect &Imgrc, IN CONST DWORD &dwDisplayPix, OUT DWORD &dwZoomPix)
+{
+	double fDisplayWidth = GET_XPIX(dwDisplayPix);
+	double fDisplayHeight = GET_YPIX(dwDisplayPix);
+
+	// 显示区域长宽比;
+	double fDisplayAspectRatio = fDisplayWidth / fDisplayHeight;
+
+	// 图片长宽比;
+	double fImgAspectRatio = ((double)Imgrc.Width()) / ((double)Imgrc.Height());
+
+	double fZoomWidth;
+	double fZoomHeight;
+
+	if (fDisplayAspectRatio > fImgAspectRatio)
+	{
+		fZoomWidth = fDisplayHeight*fImgAspectRatio;
+		fZoomHeight = fDisplayHeight;
+	}
+	else
+	{
+		fZoomWidth = fDisplayWidth;
+		fZoomHeight = fDisplayWidth / fImgAspectRatio;
+	}
+
+	dwZoomPix = SET_PIX((int)fZoomWidth, (int)fZoomHeight);
+
+	//////////////////////////////////////////////////////////////////////////
+	int nRetval = 0;
+	if ((fDisplayWidth == Imgrc.Width()) && (fDisplayHeight == Imgrc.Height()))
+	{
+		nRetval = ZoomNull;
+	}
+	else if ((fDisplayWidth > Imgrc.Width()) && (fDisplayHeight > Imgrc.Height()))
+	{
+		nRetval = ZoomOut;
+	}
+	else
+	{
+		nRetval = ZoomIn;
+	}
+
+	return nRetval;
+}
+
+int IMGCommon::ZoomImg(IN CONST DWORD &dwImgPix, IN CONST DWORD &dwDisplayPix, OUT DWORD &dwZoomPix)
+{
+	double fDisplayWidth = GET_XPIX(dwDisplayPix);
+	double fDisplayHeight = GET_YPIX(dwDisplayPix);
+
+	// 显示区域长宽比;
+	double fDisplayAspectRatio = fDisplayWidth / fDisplayHeight;
+
+	// 图片长宽比;
+	double fImgAspectRatio = ((double)GET_XPIX(dwImgPix)) / ((double)GET_YPIX(dwImgPix));
+
+	double fZoomWidth;
+	double fZoomHeight;
+
+	if (fDisplayAspectRatio > fImgAspectRatio)
+	{
+		fZoomWidth = fDisplayHeight*fImgAspectRatio;
+		fZoomHeight = fDisplayHeight;
+	}
+	else
+	{
+		fZoomWidth = fDisplayWidth;
+		fZoomHeight = fDisplayWidth / fImgAspectRatio;
+	}
+
+	dwZoomPix = SET_PIX((int)fZoomWidth, (int)fZoomHeight);
+
+	//////////////////////////////////////////////////////////////////////////
+	int nRetval = 0;
+	if ((fDisplayWidth == GET_XPIX(dwImgPix)) && (fDisplayHeight == GET_YPIX(dwImgPix)))
+	{
+		nRetval = ZoomNull;
+	}
+	else if ((fDisplayWidth > GET_XPIX(dwImgPix)) && (fDisplayHeight > GET_YPIX(dwImgPix)))
+	{
+		nRetval = ZoomOut;
+	}
+	else
+	{
+		nRetval = ZoomIn;
+	}
+
+	return nRetval;
+}
+
+/************************************************************************/
+/*
+	函数:ImgThumbnail
+	描述:生成高质量的图像缩略图;
+	参数:
+	返回:
+
+	注意:为了健壮性,strNewfile的路径可以在函数内再次判断是否有效,防止在函数外没有进行经判断;
+*/
+/************************************************************************/
+BOOL IMGCommon::ImgThumbnail(IN Image* pImg, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality)
+{
+	if (pImg == NULL) return FALSE;
+
+	DWORD dwZoomPix;
+	int retval = ZoomImg(SET_PIX(pImg->GetWidth(), pImg->GetHeight()), dwDisplayPix, dwZoomPix);
+	if (retval == ZoomOut)
+	{
+		return FALSE;
+	}
+	else if (retval == ZoomNull)
+	{
+		return SaveImg2newfile(pImg, strNewfile, uQuality);
+	}
+
+	// 绘制缩略图;
+	Bitmap bitmap(GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	Graphics *graphic = Graphics::FromImage(&bitmap);
+	graphic->Clear(Color(255, 255, 255, 255));
+
+	// 设置缩放或旋转图片时的算法(图片质量);
+	graphic->SetInterpolationMode(InterpolationModeHighQualityBicubic);
+	// 设置渲染图形对象的质量;
+	graphic->SetSmoothingMode(SmoothingModeHighQuality);//SmoothingModeHighSpeed
+	// 设置图形对象的像素偏移模式;
+	graphic->SetPixelOffsetMode(PixelOffsetModeHighQuality);
+	// 设置图形对象的合成模式;
+	graphic->SetCompositingMode(CompositingModeSourceOver);
+	// 设置图形对象的合成质量;
+	graphic->SetCompositingQuality(CompositingQualityHighQuality);
+	// 设置图形对象的文本渲染模式;
+	graphic->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
+	graphic->DrawImage(pImg, 0, 0, GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+
+	delete graphic;
+
+	// 生成缩略图;
+	return SaveImg2newfile(&bitmap, strNewfile, uQuality);
+}
+
+BOOL IMGCommon::ImgThumbnail(IN LPCTSTR lpImgpath, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality)
+{
+	if (!PathFileExists(lpImgpath))
+		return FALSE;
+
+#ifdef UNICODE
+	Image Img(lpImgpath);
+#else
+	BSTR strtmp = _bstr_t(lpImgpath);
+	Image Img(strtmp);
+	SysFreeString(strtmp);
+#endif
+
+	DWORD dwZoomPix;
+	int retval = ZoomImg(SET_PIX(Img.GetWidth(), Img.GetHeight()), dwDisplayPix, dwZoomPix);
+	if (retval == ZoomOut)
+	{
+		return FALSE;
+	}
+	else if (retval == ZoomNull)
+	{
+		return SaveImg2newfile(&Img, strNewfile, uQuality);
+	}
+
+	// 绘制缩略图;
+	Bitmap bitmap(GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	Graphics *graphic = Graphics::FromImage(&bitmap);
+	graphic->Clear(Color(255, 255, 255, 255));
+
+	// 设置缩放或旋转图片时的算法(图片质量);
+	graphic->SetInterpolationMode(InterpolationModeHighQualityBicubic);
+	// 设置渲染图形对象的质量;
+	graphic->SetSmoothingMode(SmoothingModeHighQuality);//SmoothingModeHighSpeed
+	// 设置图形对象的像素偏移模式;
+	graphic->SetPixelOffsetMode(PixelOffsetModeHighQuality);
+	// 设置图形对象的合成模式;
+	graphic->SetCompositingMode(CompositingModeSourceOver);
+	// 设置图形对象的合成质量;
+	graphic->SetCompositingQuality(CompositingQualityHighQuality);
+	// 设置图形对象的文本渲染模式;
+	graphic->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
+	Status st = graphic->DrawImage(&Img, 0, 0, GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	if ( st != Ok  )
+	{
+		delete graphic;
+		return FALSE;
+	}
+
+	delete graphic;
+	// 生成缩略图;
+	return SaveImg2newfile(&bitmap, strNewfile, uQuality);
+}
+
+BOOL IMGCommon::ImgThumbnail(IN CONST TString &strImgpath, IN CONST DWORD &dwDisplayPix, IN TString strNewfile, IN ULONG uQuality)
+{
+	if (!PathFileExists(strImgpath.c_str()))
+	{
+		SetLastError(GetLastError());
+		return FALSE;
+	}
+
+#ifdef UNICODE
+	BSTR strtmp = _bstr_t(strImgpath.c_str());
+	Image Img(strtmp);
+	SysFreeString(strtmp);
+	//Image Img(strImgpath);
+#else
+	BSTR strtmp = _bstr_t(strImgpath.c_str());
+	Image Img(strtmp);
+	SysFreeString(strtmp);
+#endif
+
+	DWORD dwZoomPix;
+	int retval = ZoomImg(SET_PIX(Img.GetWidth(), Img.GetHeight()), dwDisplayPix, dwZoomPix);
+	if (retval == ZoomOut)
+	{
+		return FALSE;
+	}
+	else if (retval == ZoomNull)
+	{
+		return SaveImg2newfile(&Img, strNewfile, uQuality);
+	}
+
+	// 绘制缩略图;
+	Bitmap bitmap(GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	Graphics *graphic = Graphics::FromImage(&bitmap);
+	graphic->Clear(Color(255, 255, 255, 255));
+
+	// 设置缩放或旋转图片时的算法(图片质量);
+	graphic->SetInterpolationMode(InterpolationModeHighQualityBicubic);
+	// 设置渲染图形对象的质量;
+	graphic->SetSmoothingMode(SmoothingModeHighQuality);//SmoothingModeHighSpeed
+	// 设置图形对象的像素偏移模式;
+	graphic->SetPixelOffsetMode(PixelOffsetModeHighQuality);
+	// 设置图形对象的合成模式;
+	graphic->SetCompositingMode(CompositingModeSourceOver);
+	// 设置图形对象的合成质量;
+	graphic->SetCompositingQuality(CompositingQualityHighQuality);
+	// 设置图形对象的文本渲染模式;
+	graphic->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
+	Status st = graphic->DrawImage(&Img, 0, 0, GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	if ( st != Ok  )
+	{
+		delete graphic;
+		return FALSE;
+	}
+
+	delete graphic;
+	// 生成缩略图;
+	return SaveImg2newfile(&bitmap, strNewfile, uQuality);
+}
+
+BOOL IMGCommon::SimpleImgThumbnail(IN LPCTSTR lpImgpath, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality)
+{
+	if (!PathFileExists(lpImgpath))
+		return FALSE;
+
+	DWORD dwZoomPix;
+	Image *pImg = NULL;
+	LoadImgFromFile(&pImg, lpImgpath);
+	if ( pImg == NULL )
+	{
+		return FALSE;
+	}
+
+	int retval = ZoomImg(SET_PIX(pImg->GetWidth(), pImg->GetHeight()), dwDisplayPix, dwZoomPix);
+	if (retval == ZoomOut)
+	{
+		if (pImg) delete pImg;
+		
+		return FALSE;
+	}
+	else if (retval == ZoomNull)
+	{
+		BOOL bRet = SaveImg2newfile(pImg, strNewfile, uQuality);
+		if (pImg) delete pImg;
+
+		return bRet;
+	}
+
+	Image *pThumbnailImg = pImg->GetThumbnailImage(GET_XPIX(dwZoomPix), GET_YPIX(dwZoomPix));
+	if (pThumbnailImg)
+	{
+		// 提高缩略图质量;
+		Graphics graphic(pThumbnailImg);
+		graphic.DrawImage(pImg, 0, 0, pThumbnailImg->GetWidth(), pThumbnailImg->GetHeight());
+		INT nRientation = GetOrientation(pImg);
+		if ( nRientation == 8 )
+		{
+			pThumbnailImg->RotateFlip(Rotate270FlipNone);
+		}
+		else if (nRientation == 6)
+		{
+			pThumbnailImg->RotateFlip(Rotate90FlipNone);
+		}
+		SaveImg2newfile(pThumbnailImg, strNewfile, uQuality);
+	}
+	else
+	{
+		if (pImg) delete pImg;
+		return FALSE;
+	}
+
+	if (pImg) delete pImg;
+	if (pThumbnailImg) delete pThumbnailImg;
+
+	return TRUE;
+}
+
+Image* IMGCommon::AppendImgWatermark(IN Image* pImg, IN Image* pWatemarkImg)
+{
+	if ( pImg == NULL || pWatemarkImg == NULL )
+		return NULL;
+
+	// Status st = GenericError;
+	// 创建图像显示属性对象;
+	ImageAttributes ImgAttr;
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建水印图显示位置;
+	RectF layWatemarkRect(10.0, 10.0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight());
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 设置透明颜色为水印图片四角底色,水印图显示为圆角;
+	if ( Ok != ImgAttr.SetColorKey(0xFF00FF00, 0xFF00FF00, ColorAdjustTypeBitmap))
+		goto clear;
+	// 设置水印图片透明底为0.3;
+	if ( Ok != ImgAttr.SetColorMatrix(&_ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap) )
+		goto clear;
+	// 在画布左上角画水印;
+	if ( Ok != grap->DrawImage(pWatemarkImg, layWatemarkRect, 0, 0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight(), UnitPixel, &ImgAttr) )
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	return NULL;
+}
+
+Image* IMGCommon::AppendImgWatermark(IN Image* pImg, IN LPCTSTR lpWatemarkImgpath)
+{
+	if ( !PathFileExists(lpWatemarkImgpath) || pImg == NULL )
+		return FALSE;
+
+#ifdef UNICODE
+	Image *pWatemarkImg = Image::FromFile(lpWatemarkImgpath);
+#else
+	BSTR str = _bstr_t(lpWatemarkImgpath);
+	Image* pWatemarkImg = Image::FromFile(str);
+	SysFreeString(str);
+#endif
+
+	if ( pImg == NULL )
+		return NULL;
+
+	//Status st = GenericError;
+	// 创建图像显示属性对象;
+	ImageAttributes ImgAttr;
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建水印图显示位置;
+	RectF layWatemarkRect(10.0, 10.0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight());
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 设置透明颜色为水印图片四角底色,水印图显示为圆角;
+	if ( Ok != ImgAttr.SetColorKey(0xFF00FF00, 0xFF00FF00, ColorAdjustTypeBitmap))
+		goto clear;
+	// 设置水印图片透明底为0.3;
+	if ( Ok != ImgAttr.SetColorMatrix(&_ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap) )
+		goto clear;
+	// 在画布左上角画水印;
+	if ( Ok != grap->DrawImage(pWatemarkImg, layWatemarkRect, 0, 0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight(), UnitPixel, &ImgAttr) )
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	if ( pWatemarkImg )
+		delete pWatemarkImg;
+
+	return NULL;
+}
+
+Image* IMGCommon::AppendImgWatermark(IN LPCTSTR lpImgpath, IN Image* pWatemarkImg)
+{
+	if ( !PathFileExists(lpImgpath) || pWatemarkImg == NULL )
+		return FALSE;
+
+#ifdef UNICODE
+	Image *pImg = Image::FromFile(lpImgpath);
+#else
+	BSTR str = _bstr_t(lpImgpath);
+	Image* pImg = Image::FromFile(str);
+	SysFreeString(str);
+#endif
+
+	if ( pImg == NULL )
+		return NULL;
+
+	//Status st = GenericError;
+	// 创建图像显示属性对象;
+	ImageAttributes ImgAttr;
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建水印图显示位置;
+	RectF layWatemarkRect(10.0, 10.0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight());
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 设置透明颜色为水印图片四角底色,水印图显示为圆角;
+	if ( Ok != ImgAttr.SetColorKey(0xFF00FF00, 0xFF00FF00, ColorAdjustTypeBitmap))
+		goto clear;
+	// 设置水印图片透明底为0.3;
+	if ( Ok != ImgAttr.SetColorMatrix(&_ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap) )
+		goto clear;
+	// 在画布左上角画水印;
+	if ( Ok != grap->DrawImage(pWatemarkImg, layWatemarkRect, 0, 0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight(), UnitPixel, &ImgAttr) )
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	if ( pImg )
+		delete pImg;
+
+	return NULL;
+}
+
+Image* IMGCommon::AppendImgWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkImgpath)
+{
+	if ( !PathFileExists(lpImgpath) || !PathFileExists(lpWatemarkImgpath) )
+		return FALSE;
+
+#ifdef UNICODE
+	Image *pImg = Image::FromFile(lpImgpath);
+	Image *pWatemarkImg = Image::FromFile(lpWatemarkImgpath);
+#else
+	BSTR str = _bstr_t(lpImgpath);
+	Image* pImg = Image::FromFile(str);
+	SysFreeString(str);
+
+	BSTR str2 = _bstr_t(lpWatemarkImgpath);
+	Image* pWatemarkImg = Image::FromFile(str2);
+	SysFreeString(str2);
+#endif
+
+	if ( pImg == NULL || pWatemarkImg == NULL )
+		return NULL;
+
+	//Status st = GenericError;
+	// 创建图像显示属性对象;
+	ImageAttributes ImgAttr;
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建水印图显示位置;
+	RectF layWatemarkRect(10.0, 10.0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight());
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 设置透明颜色为水印图片四角底色,水印图显示为圆角;
+	if ( Ok != ImgAttr.SetColorKey(0xFF00FF00, 0xFF00FF00, ColorAdjustTypeBitmap))
+		goto clear;
+	// 设置水印图片透明底为0.3;
+	if ( Ok != ImgAttr.SetColorMatrix(&_ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap) )
+		goto clear;
+	// 在画布左上角画水印;
+	if ( Ok != grap->DrawImage(pWatemarkImg, layWatemarkRect, 0, 0, pWatemarkImg->GetWidth(), pWatemarkImg->GetHeight(), UnitPixel, &ImgAttr) )
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	if ( pImg )
+		delete pImg;
+
+	if ( pWatemarkImg )
+		delete pWatemarkImg;
+
+	return NULL;
+}
+
+BOOL IMGCommon::AppendImgWatermark(IN Image* pImg, IN Image* pWatemarkImg, IN LPCTSTR lpSaveImgpath)
+{
+	Image* pSaveImg = AppendImgWatermark(pImg, pWatemarkImg);
+	if ( pSaveImg == NULL )
+		return FALSE;
+
+	// 创建新的目录;
+	CString strImgs = lpSaveImgpath;
+	INT nIndex = strImgs.ReverseFind(_T('\\'));
+	if ( nIndex != -1 )
+	{
+		strImgs = strImgs.Mid(0,nIndex+1);
+		if ( !PathFileExists(strImgs) )
+		{
+#if 0
+			if ( CreateDirectoryEx(strImgs) )
+#else
+			if (SHCreateDirectoryEx(NULL, strImgs, NULL))
+#endif
+			{
+				if (SaveImg2newfile(pSaveImg, (CString)lpSaveImgpath, 100))
+				{
+					if ( pSaveImg )
+						delete pSaveImg;
+					pSaveImg = NULL;
+
+					return TRUE;
+				}
+
+				return FALSE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+BOOL IMGCommon::AppendImgWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkImgpath, IN LPCTSTR lpSaveImgpath)
+{
+	Image *pSaveImg = AppendImgWatermark(lpImgpath, lpWatemarkImgpath);
+	if ( pSaveImg == NULL)
+		return FALSE;
+
+	// 创建新的目录;
+	CString strImgs = lpSaveImgpath;
+	INT nIndex = strImgs.ReverseFind(_T('\\'));
+	if ( nIndex != -1 )
+	{
+		strImgs = strImgs.Mid(0,nIndex+1);
+		if ( !PathFileExists(strImgs) )
+		{
+#if 0
+			if (CreateDirectoryEx(strImgs))
+#else
+			if (SHCreateDirectoryEx(NULL, strImgs, NULL))
+#endif
+			{
+				if (SaveImg2newfile(pSaveImg, (CString)lpSaveImgpath, 100))
+				{
+					if ( pSaveImg )
+						delete pSaveImg;
+					pSaveImg = NULL;
+
+					return TRUE;
+				}
+
+				return FALSE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+Image* IMGCommon::AppendWordWatermark(IN Image* pImg, IN LPCTSTR lpWatemarkString)
+{
+	if ( pImg == NULL || lpWatemarkString == NULL || lpWatemarkString[0] == _T('\0'))
+		return NULL;
+
+#ifndef UNICODE
+	WCHAR* pText = CharEncoding::ASCII2UNICODE(lpWatemarkString);
+#endif
+
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建字体;
+	FontFamily ffly(L"宋体");
+	Gdiplus::Font ft(&ffly, 24, FontStyleRegular, UnitPixel);
+	// 创建画刷;
+	SolidBrush brush(0x99000000);
+	// 创建文本格式;
+	StringFormat sf;
+	sf.SetAlignment(StringAlignmentCenter);	// 水平居中;
+	// 创建水印文本显示位置;
+	RectF layWatemarkRect(pImg->GetWidth(), pImg->GetHeight() - 25, 0.0, 0.0);	// 文字阴影;
+	RectF layWatemarkRect2(pImg->GetWidth(), pImg->GetHeight() - 26, 0.0, 0.0);		// 文字原体;
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 画水印阴影;
+#ifdef UNICODE
+	if ( Ok != grap->DrawString(lpWatemarkString, wcslen(lpWatemarkString), &ft, layWatemarkRect, &sf, &brush) )
+#else
+	if ( Ok != grap->DrawString(pText, wcslen(pText), &ft, layWatemarkRect, &sf, &brush) )
+#endif
+		goto clear;
+	// 画水印文本;
+	brush.SetColor(0x99ffffff);
+#ifdef UNICODE
+	if ( Ok != grap->DrawString(lpWatemarkString, wcslen(lpWatemarkString), &ft, layWatemarkRect2, &sf, &brush) )
+#else
+	if ( Ok != grap->DrawString(pText, wcslen(pText), &ft, layWatemarkRect, &sf, &brush) )
+#endif
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	if ( pImg )
+		delete pImg;
+
+#ifndef UNICODE
+	if (pText)
+		delete []pText;
+#endif
+
+	return NULL;
+}
+
+Image* IMGCommon::AppendWordWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkString)
+{
+	if ( !PathFileExists(lpImgpath) || lpWatemarkString == NULL || lpWatemarkString[0] == _T('\0'))
+		return NULL;
+
+#ifdef UNICODE
+	Image *pImg = Image::FromFile(lpImgpath);
+#else
+	BSTR str = _bstr_t(lpImgpath);
+	Image* pImg = Image::FromFile(str);
+	SysFreeString(str);
+#endif
+
+#ifndef UNICODE
+	WCHAR* pText = CharEncoding::ASCII2UNICODE(lpWatemarkString);
+#endif
+
+	// 创建新位图;
+	Bitmap *pBitmap = ::new Bitmap(pImg->GetWidth(), pImg->GetHeight(), PixelFormat32bppPARGB);
+	// 创建字体;
+	FontFamily ffly(L"宋体");
+	Gdiplus::Font ft(&ffly, 24, FontStyleRegular, UnitPixel);
+	// 创建画刷;
+	SolidBrush brush(0x99000000);
+	// 创建文本格式;
+	StringFormat sf;
+	sf.SetAlignment(StringAlignmentCenter);	// 水平居中;
+	// 创建水印文本显示位置;
+	RectF layWatemarkRect(pImg->GetWidth(), pImg->GetHeight() - 25, 0.0, 0.0);	// 文字阴影;
+	RectF layWatemarkRect2(pImg->GetWidth(), pImg->GetHeight() - 26, 0.0, 0.0);		// 文字原体;
+	// 创建画布对象;
+	Graphics *grap = Graphics::FromImage(pBitmap);
+	// 绘制画布底色;
+	if ( Ok != grap->Clear(Color(255,255,255,255)) )
+		goto clear;
+	// 设置图片显示质量;
+	if ( Ok != grap->SetSmoothingMode(SmoothingModeAntiAlias) )
+		goto clear;
+	// 设置文本质量;
+	if ( Ok != grap->SetTextRenderingHint(TextRenderingHintAntiAlias))
+		goto clear;
+	// 在画布上画原始图片;
+	if ( Ok != grap->DrawImage(pImg, 0, 0, pImg->GetWidth(), pImg->GetHeight()) )
+		goto clear;
+
+	// 画水印阴影;
+#ifdef UNICODE
+	if ( Ok != grap->DrawString(lpWatemarkString, wcslen(lpWatemarkString), &ft, layWatemarkRect, &sf, &brush) )
+#else
+	if ( Ok != grap->DrawString(pText, wcslen(pText), &ft, layWatemarkRect, &sf, &brush) )
+#endif
+		goto clear;
+	// 画水印文本;
+	brush.SetColor(0x99ffffff);
+#ifdef UNICODE
+	if ( Ok != grap->DrawString(lpWatemarkString, wcslen(lpWatemarkString), &ft, layWatemarkRect2, &sf, &brush) )
+#else
+	if ( Ok != grap->DrawString(pText, wcslen(pText), &ft, layWatemarkRect, &sf, &brush) )
+#endif
+		goto clear;
+
+	if ( grap )
+		delete grap;
+
+	return pBitmap;
+
+clear:
+	if ( grap )
+		delete grap;
+
+	if ( pBitmap )
+		delete pBitmap;
+
+	if ( pImg )
+		delete pImg;
+
+#ifndef UNICODE
+	if (pText)
+		delete []pText;
+#endif
+
+	return NULL;
+}
+
+BOOL IMGCommon::SaveBitmap(IN CDC *pDC, IN CBitmap* pBitmap, IN CONST INT& nBitdepth, IN const INT& nWidth, IN const INT& nHeight, IN LPCTSTR lpSavepath)
+{
+	// 计算出位图大小 =  ((宽 * 位宽 + 31)/ 32)* 4 * 高;
+	DWORD dwBmpSize = ((nWidth*nBitdepth + 31) / 32) * 4 * nHeight;
+
+	HANDLE hFile = CreateFile(lpSavepath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (hFile == INVALID_HANDLE_VALUE)
+	{
+		//WriteLog(_T("二维码位图创建失败"));
+		return FALSE;
+	}
+
+	HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 
+		sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + dwBmpSize, NULL);
+	LPBYTE lpbyMapView = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
+
+	ZeroMemory(lpbyMapView, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + dwBmpSize);
+
+	//结构体地址割付;
+
+	LPBITMAPFILEHEADER pbfh = (LPBITMAPFILEHEADER)lpbyMapView;
+	LPBITMAPINFO       pbmi = (LPBITMAPINFO)(lpbyMapView + sizeof(BITMAPFILEHEADER));
+	LPVOID             pbdt = lpbyMapView + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2;
+
+	// BITMAPFILEHEADER
+	//pbfh->bfType      = (WORD) (('M' << 8) | 'B'); // "BM"
+	// BMP类型,与上面同值;
+	pbfh->bfType      = 0x4D42;
+	pbfh->bfSize      = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + dwBmpSize;	// 文件总长;
+	pbfh->bfReserved1 = 0;
+	pbfh->bfReserved2 = 0;
+	pbfh->bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2;	// 位图数据相对于文件头的偏移量;
+
+	// LPBITMAPINFO->BITMAPINFOHEADER
+	pbmi->bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
+	pbmi->bmiHeader.biWidth			= nWidth;
+	pbmi->bmiHeader.biHeight		= nHeight;
+	pbmi->bmiHeader.biPlanes		= 1;
+	pbmi->bmiHeader.biBitCount		= nBitdepth;			// 位深度 1;
+	pbmi->bmiHeader.biCompression	= BI_RGB;
+	pbmi->bmiHeader.biSizeImage		= dwBmpSize;
+	pbmi->bmiHeader.biXPelsPerMeter = 3780;
+	pbmi->bmiHeader.biYPelsPerMeter = 3780;
+	pbmi->bmiHeader.biClrUsed		= 0;
+	pbmi->bmiHeader.biClrImportant	= 0;
+
+	// 放大到指定的像素宽高;
+	CDC* pWorkDC = new CDC;
+	pWorkDC->CreateCompatibleDC(NULL);
+
+	CBitmap* pWorkBitmap = new CBitmap;
+	pWorkBitmap->CreateBitmap(nWidth, nHeight, 1, 1, NULL);
+
+	CBitmap* pOldBitmap = pWorkDC->SelectObject(pWorkBitmap);
+	pWorkDC->StretchBlt(0, 0, nWidth, nHeight, pDC, 0, 0, nWidth, nHeight, SRCCOPY);
+
+	GetDIBits(pWorkDC->m_hDC, (HBITMAP)*pWorkBitmap, 0, nHeight, pbdt, pbmi, DIB_RGB_COLORS);
+
+	pWorkDC->SelectObject(pOldBitmap);
+	delete pWorkBitmap;
+	delete pWorkDC;
+
+	UnmapViewOfFile(lpbyMapView);
+	CloseHandle(hFileMapping);
+	CloseHandle(hFile);
+
+	return TRUE;
+}
+
+BOOL IMGCommon::SaveBitmap2(IN CDC *pDC, IN CBitmap* pBitmap, IN CONST INT& nBitdepth, IN const INT& nWidth, IN const INT& nHeight, IN LPCTSTR lpSavepath)
+{
+	DWORD dwPaletteSize = 0;	//调色板大小;
+	DWORD dwbmdibitSize = 0;
+	WORD  wbitsCount = 0;		//位图中每个像素所占字节数;
+	if( nBitdepth <= 1 )
+		wbitsCount = 1;
+	if( nBitdepth <= 4 )
+		wbitsCount = 4;
+	if( nBitdepth <= 8 )
+		wbitsCount = 8;
+	if( nBitdepth <= 16 )
+		wbitsCount = 16;
+	if( nBitdepth <= 24 )
+		wbitsCount = 24;
+	else 
+		wbitsCount = 32;
+
+	if( wbitsCount <= 8 )
+		dwPaletteSize = (1 << wbitsCount) * sizeof(RGBQUAD);
+
+	// 计算出位图大小 =  ((宽 * 位宽 + 31)/ 32)* 4 * 高;
+	DWORD dwBmpSize = ((nWidth*wbitsCount + 31) / 8) * nHeight;
+
+	HANDLE hFile = CreateFile(lpSavepath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (hFile == INVALID_HANDLE_VALUE)
+	{
+		//WriteLog(_T("二维码位图创建失败"));
+		return FALSE;
+	}
+
+	HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 
+		//sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + dwBmpSize, NULL);
+		sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmpSize, NULL);
+	LPBYTE lpbyMapView = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
+
+	//ZeroMemory(lpbyMapView, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + dwBmpSize);
+	ZeroMemory(lpbyMapView, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmpSize);
+
+	//结构体地址割付;
+
+	LPBITMAPFILEHEADER pbfh = (LPBITMAPFILEHEADER)lpbyMapView;
+	LPBITMAPINFO       pbmi = (LPBITMAPINFO)(lpbyMapView + sizeof(BITMAPFILEHEADER));
+	LPVOID             pbdt = lpbyMapView + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmpSize;
+
+	// BITMAPFILEHEADER
+	//pbfh->bfType      = (WORD) (('M' << 8) | 'B'); // "BM"
+	// BMP类型,与上面同值;
+	pbfh->bfType      = 0x4D42;
+	pbfh->bfSize      = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmpSize;	// 文件总长;
+	pbfh->bfReserved1 = 0;
+	pbfh->bfReserved2 = 0;
+	pbfh->bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize;	// 位图数据相对于文件头的偏移量;
+
+	// LPBITMAPINFO->BITMAPINFOHEADER
+	pbmi->bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
+	pbmi->bmiHeader.biWidth			= nWidth;
+	pbmi->bmiHeader.biHeight		= nHeight;
+	pbmi->bmiHeader.biPlanes		= 1;
+	pbmi->bmiHeader.biBitCount		= wbitsCount;			// 位深度 1;
+	pbmi->bmiHeader.biCompression	= BI_RGB;
+	pbmi->bmiHeader.biSizeImage		= dwBmpSize;
+	pbmi->bmiHeader.biXPelsPerMeter = 3780;
+	pbmi->bmiHeader.biYPelsPerMeter = 3780;
+	pbmi->bmiHeader.biClrUsed		= 0;
+	pbmi->bmiHeader.biClrImportant	= 0;
+
+	// 放大到指定的像素宽高;
+	CDC* pWorkDC = new CDC;
+	pWorkDC->CreateCompatibleDC(NULL);
+
+	CBitmap* pWorkBitmap = new CBitmap;
+	pWorkBitmap->CreateBitmap(nWidth, nHeight, 1, 1, NULL);
+
+	CBitmap* pOldBitmap = pWorkDC->SelectObject(pWorkBitmap);
+	pWorkDC->StretchBlt(0, 0, nWidth, nHeight, pDC, 0, 0, nWidth, nHeight, SRCCOPY);
+
+	GetDIBits(pWorkDC->m_hDC, (HBITMAP)*pWorkBitmap, 0, nHeight, pbdt, pbmi, DIB_RGB_COLORS);
+
+	pWorkDC->SelectObject(pOldBitmap);
+	delete pWorkBitmap;
+	delete pWorkDC;
+
+	UnmapViewOfFile(lpbyMapView);
+	CloseHandle(hFileMapping);
+	CloseHandle(hFile);
+
+	return TRUE;
+}
+
+void IMGCommon::DrawString(IN CDC* pdc, IN CONST INT& nFontSize, IN LPCTSTR lpFontName, IN LPCTSTR lpString, IN OUT CRect &rcString)
+{
+	if ( !pdc || !lpString )
+		return;
+
+	LOGFONT log;
+	// 设置字体字号;
+	log.lfHeight = -MulDiv(nFontSize ? nFontSize : 9, GetDeviceCaps(pdc->GetSafeHdc(), LOGPIXELSY), 72);
+	log.lfWidth = 0;
+	log.lfEscapement = 0;   
+	log.lfOrientation = 0;   
+	log.lfWeight = FW_REGULAR;   
+	log.lfItalic =  false;
+	log.lfUnderline = false;   
+	log.lfStrikeOut = 0;   
+	log.lfCharSet = ANSI_CHARSET;
+	log.lfOutPrecision = OUT_DEFAULT_PRECIS;   
+	log.lfClipPrecision = CLIP_DEFAULT_PRECIS;   
+	log.lfQuality = DEFAULT_QUALITY;
+	log.lfPitchAndFamily = DEFAULT_PITCH || FF_ROMAN;  
+	// 设置字体名称;
+	_tcscpy_s(log.lfFaceName, (lpFontName && (lpFontName[0] != _T('\0'))) ? lpFontName : _T("Arial"));
+
+	CFont cf;
+	cf.CreateFontIndirect(&log);
+	CFont *oldf = pdc->SelectObject(&cf);
+
+	SIZE Size;
+	GetTextExtentPoint32(pdc->GetSafeHdc(), lpString, _tcslen(lpString), &Size);
+	rcString.SetRect(rcString.left, rcString.top, Size.cx + rcString.left, Size.cy + rcString.top);
+	pdc->TextOut(rcString.left, rcString.top, lpString);
+}

+ 89 - 0
SATHelper/SATHelper/IMGCommon.h

@@ -0,0 +1,89 @@
+#ifndef __IMG_COMMON_20151214__
+#define __IMG_COMMON_20151214__
+
+#pragma once
+
+//#include "gdi.h"
+#include <gdiplus.h>
+using namespace Gdiplus;
+#pragma comment(lib, "gdiplus.lib")
+
+// WNetAddConnection的使用;
+#include <Winnetwk.h>
+#pragma comment(lib,"Mpr.lib")
+
+#include <string>
+using namespace std;
+
+#ifndef _UNICODE
+typedef string TString;
+#else
+typedef wstring TString;
+#endif
+
+enum	// 缩放结果;
+{
+	ZoomNull = 0,		// 无缩放;
+	ZoomIn = 1,			// 缩小;
+	ZoomOut = 2			// 放大;
+};
+
+#define GET_XPIX(x)			( x >> 16)				// 高16位;
+#define GET_YPIX(y)			(y & 0x0000ffff)		// 低16位;
+#define SET_PIX(x,y)		(( x << 16) | y)		// 高低合并;
+#define INVALID_COPY_PIX	((DWORD)-1)				// 传递此值,表示没有复制压缩;
+
+#if 0
+#define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
+#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
+#define LOWORD(l)           ((WORD)(((DWORD_PTR)(l)) & 0xffff))
+#define HIWORD(l)           ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
+#define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
+#define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
+#endif
+
+class IMGCommon
+{
+public:
+	IMGCommon(void);
+	~IMGCommon(void);
+
+	static ULONG_PTR m_gdiplusToken;
+
+public:
+	static BOOL IsValidpath(IN CONST TString &strPath);
+	static void Splitpath(IN CONST TCHAR *path, IN TCHAR * drive, IN size_t driveNumberOfElements, IN TCHAR * dir, IN size_t dirNumberOfElements, IN CONST int &nTimes);
+	static BOOL CreateDirectoryEx(IN LPCTSTR lpNewDirectory);
+	//////////////////////////////////////////////////////////////////////////
+	static BOOL LoadImgFromFile(IN Image** pImg, LPCTSTR lpPath);
+	static BOOL LoadImgFromBuffer(IN Image** pImg, IN BYTE* pBuffer, IN CONST INT& nBufLen);
+	static BOOL LoadImgFromBuffer(IN Image** pImg, LPCTSTR lpPath);
+	static Image* LoadImgFromResource( IN HMODULE hModule, IN LPCTSTR lpName, IN LPCTSTR lpType);
+	//////////////////////////////////////////////////////////////////////////
+	static BOOL GetOrientation(IN Image *pImg);
+	static int GetEncoderClsid(IN CONST WCHAR* format, OUT CLSID* pClsid);
+	static BOOL SaveImg2newfile(IN Image* pImg, IN CString strNewfile, IN ULONG uQuality);
+	static BOOL SaveImg2newfile(IN Image* pImg, IN TString strNewfile, IN ULONG uQuality);
+	static int ZoomImg(IN CRect &Imgrc, IN CONST DWORD &dwDisplayPix, OUT DWORD &dwZoomPix);
+	static int ZoomImg(IN CONST DWORD &dwImgPix, IN CONST DWORD &dwDisplayPix, OUT DWORD &dwZoomPix);
+	static BOOL ImgThumbnail(IN Image* pImg, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality);
+	static BOOL ImgThumbnail(IN LPCTSTR lpImgpath, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality);
+	static BOOL ImgThumbnail(IN CONST TString &strImgpath, IN CONST DWORD &dwDisplayPix, IN TString strNewfile, IN ULONG uQuality);
+	static BOOL SimpleImgThumbnail(IN LPCTSTR lpImgpath, IN CONST DWORD &dwDisplayPix, IN CString strNewfile, IN ULONG uQuality);
+	// 给指定的图片加图片水印(位置、大小暂不支持);
+	static Image* AppendImgWatermark(IN Image* pImg, IN Image* pWatemarkImg);
+	static Image* AppendImgWatermark(IN Image* pImg, IN LPCTSTR lpWatemarkImgpath);
+	static Image* AppendImgWatermark(IN LPCTSTR lpImgpath, IN Image* pWatemarkImg);
+	static Image* AppendImgWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkImgpath);
+	static BOOL AppendImgWatermark(IN Image* pImg, IN Image* pWatemarkImg, IN LPCTSTR lpSaveImgpath);
+	static BOOL AppendImgWatermark(IN Image* pImg, IN LPCTSTR lpWatemarkImgpath, IN LPCTSTR lpSaveImgpath);
+	static BOOL AppendImgWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkImgpath, IN LPCTSTR lpSaveImgpath);
+	// 给指定图片加文字水印(位置、字体、颜色暂不支持);
+	static Image* AppendWordWatermark(IN Image* pImg, IN LPCTSTR lpWatemarkString);
+	static Image* AppendWordWatermark(IN LPCTSTR lpImgpath, IN LPCTSTR lpWatemarkString);
+	static BOOL SaveBitmap(IN CDC *pDC, IN CBitmap* pBitmap, IN CONST INT& nBitdepth, IN const INT& nWidth, IN const INT& nHeight, IN LPCTSTR lpSavepath);
+	static BOOL SaveBitmap2(IN CDC *pDC, IN CBitmap* pBitmap, IN CONST INT& nBitdepth, IN const INT& nWidth, IN const INT& nHeight, IN LPCTSTR lpSavepath);
+	static void DrawString(IN CDC* pdc, IN CONST INT& nFontSize, IN LPCTSTR lpFontName, IN LPCTSTR lpString, IN OUT CRect &rcString);
+};
+
+#endif

+ 10 - 10
SATHelper/SATHelper/IOCPModel.cpp

@@ -788,7 +788,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 			if (phead->len == pIoContext->m_Overlapped.InternalHigh)
 			{
 				OutputDebugString("A:供憐돨관;\n");
-				_TaskProcess(pIoContext, (Package*)pIoContext->m_wsaBuf.buf);
+				_TaskProcess(pIoContext, (ProPackage*)pIoContext->m_wsaBuf.buf);
 			}
 			// 鬼관;
 			else if (phead->len > pIoContext->m_Overlapped.InternalHigh)
@@ -801,7 +801,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 			{
 				OutputDebugString("A:낚관;\n");
 				pSocketContext->lastData.append(pIoContext->m_wsaBuf.buf + phead->len, pIoContext->m_Overlapped.InternalHigh - phead->len);
-				_TaskProcess(pIoContext, (Package*)pIoContext->m_wsaBuf.buf);
+				_TaskProcess(pIoContext, (ProPackage*)pIoContext->m_wsaBuf.buf);
 			}
 		}
 	}
@@ -817,7 +817,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 				{
 					OutputDebugString("C:낚관;\n");
 					// 供憐관;
-					_TaskProcess(pIoContext, (Package*)pSocketContext->lastData.substr(0, phead->len).data());
+					_TaskProcess(pIoContext, (ProPackage*)pSocketContext->lastData.substr(0, phead->len).data());
 
 					pSocketContext->lastData = pSocketContext->lastData.substr(phead->len);
 					pSocketContext->lastData.append(pIoContext->m_wsaBuf.buf, pIoContext->m_Overlapped.InternalHigh);
@@ -828,7 +828,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 					lastlen = pSocketContext->lastData.size() + pIoContext->m_Overlapped.InternalHigh - phead->len;
 					pSocketContext->lastData.append(pIoContext->m_wsaBuf.buf, pIoContext->m_Overlapped.InternalHigh - lastlen);
 					// 供憐관;
-					_TaskProcess(pIoContext, (Package*)pSocketContext->lastData.data());
+					_TaskProcess(pIoContext, (ProPackage*)pSocketContext->lastData.data());
 					// 假岱관;
 					pSocketContext->lastData.clear();
 					if (lastlen)
@@ -862,7 +862,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 				{
 					OutputDebugString("B:供憐관;\n");
 					pSocketContext->lastData.append(pIoContext->m_wsaBuf.buf + diflen, pIoContext->m_Overlapped.InternalHigh - diflen);
-					_TaskProcess(pIoContext, (Package*)pSocketContext->lastData.data());
+					_TaskProcess(pIoContext, (ProPackage*)pSocketContext->lastData.data());
 					pSocketContext->lastData.clear();
 				}
 				// 鬼관;
@@ -877,7 +877,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 					OutputDebugString("B:낚관;\n");
 					// 莉供냥관;
 					pSocketContext->lastData.append(pIoContext->m_wsaBuf.buf + diflen, phead->len - PAK_LEN);
-					_TaskProcess(pIoContext, (Package*)pSocketContext->lastData.data());
+					_TaskProcess(pIoContext, (ProPackage*)pSocketContext->lastData.data());
 					pSocketContext->lastData.clear();
 					int last = pIoContext->m_Overlapped.InternalHigh - diflen - phead->len + PAK_LEN;
 					if (last)
@@ -890,7 +890,7 @@ void CIOCPModel::_RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT
 	}
 }
 
-void CIOCPModel::_TaskProcess(PER_IO_CONTEXT* pIoContext, Package* pak)
+void CIOCPModel::_TaskProcess(PER_IO_CONTEXT* pIoContext, ProPackage* pak)
 {
 	if (pak->header.version == 0xAA)
 	{
@@ -902,7 +902,7 @@ void CIOCPModel::_TaskProcess(PER_IO_CONTEXT* pIoContext, Package* pak)
 	}
 }
 
-void CIOCPModel::_DeviceProc(PER_IO_CONTEXT* pIoContext, Package* pak)
+void CIOCPModel::_DeviceProc(PER_IO_CONTEXT* pIoContext, ProPackage* pak)
 {
 	cJSON* pJson = cJSON_Parse((const char*)&pak->buf);
 	if ( pJson == NULL )
@@ -945,7 +945,7 @@ void CIOCPModel::_DeviceProc(PER_IO_CONTEXT* pIoContext, Package* pak)
 	char* pjdata = cJSON_Print(pJson);
 
 	byte* sdata = new byte[strlen(pjdata) + PAK_LEN];
-	Package* reponse_pak = (Package*)sdata;
+	ProPackage* reponse_pak = (ProPackage*)sdata;
 	reponse_pak->header.version = 0xAB;
 	reponse_pak->header.len = strlen(pjdata) + PAK_LEN;
 	memcpy(reponse_pak->buf, pjdata, strlen(pjdata));
@@ -963,7 +963,7 @@ void CIOCPModel::_DeviceProc(PER_IO_CONTEXT* pIoContext, Package* pak)
 	}
 }
 
-void CIOCPModel::_CaptureProc(PER_IO_CONTEXT* pIoContext, Package* pak)
+void CIOCPModel::_CaptureProc(PER_IO_CONTEXT* pIoContext, ProPackage* pak)
 {
 
 }

+ 6 - 5
SATHelper/SATHelper/IOCPModel.h

@@ -5,6 +5,7 @@
 #include <MSWSock.h>
 //#include <ws2tcpip.h>
 #pragma comment(lib,"ws2_32.lib")
+#include "SATProtocol.h"
 
 // 缓冲区长度 (1024*8)
 // 之所以为什么设置8K,也是一个江湖上的经验值
@@ -25,11 +26,11 @@ typedef struct _PRO_HEADER_
 }ProHeader;
 
 // 请求包
-typedef struct _PACKAGE_
+typedef struct _PRO_PACKAGE_
 {
 	ProHeader header;
 	byte	buf[4]; // json格式;
-}Package;
+}ProPackage;
 #pragma pack(pop)
 
 typedef struct _REQUEST_JSON_
@@ -266,10 +267,10 @@ protected:
 	void _ShowMessage( const CString szFormat,...) const;
 
 	void _RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext);
-	void _TaskProcess(PER_IO_CONTEXT* pIoContext, Package* pak);
+	void _TaskProcess(PER_IO_CONTEXT* pIoContext, ProPackage* pak);
 	// 具体处理;
-	void _DeviceProc(PER_IO_CONTEXT* pIoContext, Package *pak);
-	void _CaptureProc(PER_IO_CONTEXT* pIoContext, Package* pak);
+	void _DeviceProc(PER_IO_CONTEXT* pIoContext, ProPackage*pak);
+	void _CaptureProc(PER_IO_CONTEXT* pIoContext, ProPackage* pak);
 private:
 
 	HANDLE                       m_hShutdownEvent;              // 用来通知线程系统退出的事件,为了能够更好的退出线程

+ 12 - 0
SATHelper/SATHelper/MainFrm.cpp

@@ -17,6 +17,7 @@
 #include "SATHelper.h"
 
 #include "MainFrm.h"
+#include "DlgLogin.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -90,6 +91,7 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
 	ON_UPDATE_COMMAND_UI(ID_COMBO_TVPORT, &CMainFrame::OnUpdateCombo2Tv)
 	ON_COMMAND(ID_CHECK_WATCHTV, &CMainFrame::OnCheckWatchtv)
 	ON_UPDATE_COMMAND_UI(ID_CHECK_WATCHTV, &CMainFrame::OnUpdateCheckWatchtv)
+	ON_COMMAND(ID_TRAYMENU_LOGIN, &CMainFrame::OnTraymenuLogin)
 END_MESSAGE_MAP()
 
 // CMainFrame 构造/析构
@@ -1571,3 +1573,13 @@ void CMainFrame::OnUpdateCheckWatchtv(CCmdUI* pCmdUI)
 	// TODO: 在此添加命令更新用户界面处理程序代码
 	pCmdUI->SetCheck(m_rscfg.bWatchTV);
 }
+
+
+void CMainFrame::OnTraymenuLogin()
+{
+	// TODO: 在此添加命令处理程序代码
+	CDlgLogin dlg;
+	if ( dlg.DoModal() )
+	{
+	}
+}

+ 1 - 0
SATHelper/SATHelper/MainFrm.h

@@ -289,6 +289,7 @@ public:
 	afx_msg void OnUpdateCombo2Tv(CCmdUI* pCmdUI);
 	afx_msg void OnCheckWatchtv();
 	afx_msg void OnUpdateCheckWatchtv(CCmdUI* pCmdUI);
+	afx_msg void OnTraymenuLogin();
 };
 
 

+ 9 - 3
SATHelper/SATHelper/Resource.h

@@ -114,6 +114,9 @@
 #define IDB_UNCHECKED                   311
 #define DLG_DEVICEMANAGER               312
 #define DLG_UB530VIEW                   314
+#define IDD_DLG_LOGIN                   317
+#define IDD_DLG_PROBAR                  319
+#define GIF_PROBAR                      322
 #define IDC_COMBO1                      1000
 #define IDC_COMBO2                      1001
 #define IDC_CHECK1                      1002
@@ -121,6 +124,8 @@
 #define IDC_BUTTON1                     1004
 #define IDC_BUTTON2                     1005
 #define IDC_EDIT1                       1006
+#define IDC_EDIT_PASSWORD               1007
+#define IDC_EDIT_USERNAME               1008
 #define ID_WRITE_PASTEASHYPERLINK       32770
 #define ID_TRAYMENU_RECONNECT           32771
 #define ID_TRAYMENU_EXIT                32772
@@ -165,14 +170,15 @@
 #define ID_CHECK_IR_SHOT                32823
 #define ID_CHECK2                       32824
 #define ID_CHECK_WATCHTV                32824
+#define ID_TRAYMENU_LOGIN               32825
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        317
-#define _APS_NEXT_COMMAND_VALUE         32825
-#define _APS_NEXT_CONTROL_VALUE         1007
+#define _APS_NEXT_RESOURCE_VALUE        323
+#define _APS_NEXT_COMMAND_VALUE         32826
+#define _APS_NEXT_CONTROL_VALUE         1009
 #define _APS_NEXT_SYMED_VALUE           310
 #endif
 #endif

+ 344 - 0
SATHelper/SATHelper/SATClient.cpp

@@ -0,0 +1,344 @@
+#include "stdafx.h"
+#include "SATClient.h"
+//#include <ws2def.h>
+#include "DlgProBar.h"
+
+const int SOCK_TCP = SOCK_STREAM - 1;
+const int SOCK_UDP = SOCK_DGRAM - 1;
+const int AF_IPV4 = 0;
+const int AF_IPV6 = 1;
+#define PAK_LEN sizeof(DataHeader)
+#define HEADER_LEN sizeof(DataHeader)
+// 进度条;
+CDlgProBar* g_pDlgProBar = NULL;
+
+void CSATClient::OnThreadBegin(CSocketHandle* pSH)
+{
+	ASSERT(pSH == m_SocketClient);
+	(pSH);
+	CString strAddr;
+	SockAddrIn sockAddr;
+	m_SocketClient->GetSockName(sockAddr);
+	GetAddress(sockAddr, strAddr);
+	InitializeCriticalSection(&pSH->m_hClient2SrvSection);
+}
+
+void CSATClient::OnThreadExit(CSocketHandle* pSH)
+{
+	ASSERT(pSH == m_SocketClient);
+	DeleteCriticalSection(&pSH->m_hClient2SrvSection);
+	(pSH);
+}
+
+void CSATClient::OnDataReceived(CSocketHandle* pSH, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr)
+{
+	ASSERT(pSH == m_SocketClient);
+	(pSH);
+
+	if (!m_SocketClient->IsOpen()) return;
+
+	OnReceive(pbData, dwCount);
+}
+
+void CSATClient::OnConnectionDropped(CSocketHandle* pSH)
+{
+	ASSERT(pSH == m_SocketClient);
+	(pSH);
+	TRACE(_T("======连接服务器断开.\r\n"));
+
+	m_bSocket = FALSE;
+}
+
+void CSATClient::OnConnectionError(CSocketHandle* pSH, DWORD dwError)
+{
+	ASSERT(pSH == m_SocketClient);
+	(pSH);
+	_com_error err(dwError);
+
+	m_bSocket = FALSE;
+}
+
+CSATClient::CSATClient(void)
+{
+	m_nMode = AF_IPV4;
+	m_nSockType = SOCK_TCP;
+	m_SocketClient.SetInterface(this);
+	m_bSocket = FALSE;
+}
+
+CSATClient::~CSATClient(void)
+{
+}
+
+bool CSATClient::OnSend(const byte* pData, int nLen)
+{
+	CDlgProBar dlg;
+	g_pDlgProBar = &dlg;
+	DWORD dwLen = m_SocketClient.Write((const LPBYTE)pData, nLen);
+	if (dwLen == nLen)
+	{
+		dlg.DoModal();
+		OutputDebugString(_T("发送数据成功!\n"));
+		return true;
+	}
+	else
+	{
+		g_pDlgProBar = NULL;
+		OutputDebugString(_T("发送数据失败!\n"));
+	}
+
+	return false;
+}
+
+bool CSATClient::OnReceive(const byte* pData, int nLen)
+{
+	// 小于包头;
+	DataHeader* phead = NULL;
+	if (lastData.size() == 0)
+	{
+		// 不足包头;
+		if (PAK_LEN > nLen)
+		{
+			OutputDebugString("A:不足包头;\n");
+			lastData.append((char*)pData, nLen);
+		}
+		else
+		{
+			// 包头充足;
+			phead = (DataHeader*)pData;
+
+			// 完整的包;
+			if (phead->len == nLen)
+			{
+				OutputDebugString("A:完整的包;\n");
+				TaskProcess((Package*)pData);
+			}
+			// 小包;
+			else if (phead->len > nLen)
+			{
+				OutputDebugString("A:小包;\n");
+				lastData.append((char*)pData, nLen);
+			}
+			// 超包;
+			else if (phead->len < nLen)
+			{
+				OutputDebugString("A:超包;\n");
+				lastData.append((char*)pData + phead->len, nLen - phead->len);
+				TaskProcess((Package*)pData);
+			}
+		}
+	}
+	else
+	{
+		int lastlen = nLen;
+		if (lastData.size() >= PAK_LEN)
+		{
+			phead = (DataHeader*)lastData.data();
+			if (phead->len <= lastData.size() + nLen)
+			{
+				if (phead->len <= lastData.size())
+				{
+					OutputDebugString("C:超包;\n");
+					// 完整包;
+					TaskProcess((Package*)lastData.substr(0, phead->len).data());
+
+					lastData = lastData.substr(phead->len);
+					lastData.append((char*)pData, nLen);
+				}
+				else
+				{
+					OutputDebugString("D:超包;\n");
+					lastlen = lastData.size() + nLen - phead->len;
+					lastData.append((char*)pData, nLen - lastlen);
+					// 完整包;
+					TaskProcess((Package*)lastData.data());
+					// 剩余包;
+					lastData.clear();
+					if (lastlen)
+						lastData.append((char*)pData + nLen - lastlen, lastlen);
+				}
+			}
+			else
+			{
+				OutputDebugString("C:仍不足一个包;\n");
+				lastData.append((char*)pData, nLen);
+			}
+		}
+		else
+		{
+			// 包头剩余长度;
+			int diflen = PAK_LEN - lastData.size();
+			// 仍不足一个包头;
+			if (diflen > nLen)
+			{
+				OutputDebugString("B:仍不足一个包头;\n");
+				lastData.append((char*)pData, nLen);
+			}
+			else
+			{
+				// 拼成完整包头;
+				lastData.append((char*)pData, diflen);
+				phead = (DataHeader*)lastData.data();
+
+				// 完整包;
+				if (phead->len == PAK_LEN + nLen - diflen)
+				{
+					OutputDebugString("B:完整包;\n");
+					lastData.append((char*)pData + diflen, nLen - diflen);
+					TaskProcess((Package*)lastData.data());
+					lastData.clear();
+				}
+				// 小包;
+				else if (phead->len > PAK_LEN + nLen - diflen)
+				{
+					OutputDebugString("B:小包;\n");
+					lastData.append((char*)pData + diflen, nLen - diflen);
+				}
+				// 超包;
+				else if (phead->len < PAK_LEN + nLen - diflen)
+				{
+					OutputDebugString("B:超包;\n");
+					// 组完成包;
+					lastData.append((char*)pData + diflen, phead->len - PAK_LEN);
+					TaskProcess((Package*)lastData.data());
+					lastData.clear();
+					int last = nLen - diflen - phead->len + PAK_LEN;
+					if (last)
+					{
+						lastData.append((char*)pData + nLen - last, last);
+					}
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+bool CSATClient::OnClose()
+{
+	return false;
+}
+
+bool CSATClient::OnConnect()
+{
+	return false;
+}
+
+void CSATClient::TaskProcess(Package* pak)
+{
+	DataHeader* pHeader = &pak->header;
+	if (pHeader->protocol == 0xAA) {
+		Sleep(20000);
+		if (g_pDlgProBar) {
+			while (!::IsWindow(g_pDlgProBar->m_hWnd));
+			g_pDlgProBar->PostMessage(WM_STOPTHREAD);
+			g_pDlgProBar = NULL;
+		}
+
+		switch (pHeader->cmd)
+		{
+			case CMD_LOGIN:
+			{
+				TPResponse* pRespone = (TPResponse*)pak->buf;
+			}
+			break;
+			case CMD_LOGOUT:
+				break;
+			case CMD_ADD_DEVICE:
+				break;
+			case CMD_DEL_DEVICE:
+				break;
+			case CMD_QUERY_DEVICES:
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+BOOL CSATClient::Start()
+{
+	//std::string strAddr = "10.118.158.175";
+	std::string strAddr = "";
+	std::string strPort = "5588";
+	int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6;
+	if (!m_SocketClient.StartClient(NULL, strAddr.c_str(), strPort.c_str(), nFamily, (m_nSockType + 1)))
+	{
+#ifdef _DEBUG
+		OutputDebugString("连接服务器失败\n");
+#endif
+		m_bSocket = FALSE;
+		return FALSE;
+	}
+	else
+	{
+		m_bSocket = TRUE;
+		CSocketHandle* pSH = (CSocketHandle*)m_SocketClient;
+
+		// 设置等待数据为0;
+		pSH->m_nPendingSize = 0;
+		memset(pSH->m_PendingBuffer, 0, SOCKET_BUFFSIZE);
+
+		// 设置多播;
+		SetupMCAST();
+		return TRUE;
+	}
+	return 0;
+}
+
+void CSATClient::Stop()
+{
+	m_SocketClient.Terminate();
+}
+
+bool CSATClient::SetupMCAST()
+{
+	const TCHAR szIPv4MCAST[] = TEXT("239.121.1.2");
+	const TCHAR szIPv6MCAST[] = TEXT("FF02:0:0:0:0:0:0:1"); // All Nodes local address
+	bool result = false;
+	if (m_nSockType == SOCK_UDP)
+	{
+		if (m_nMode == AF_IPV4) {
+			result = m_SocketClient->AddMembership(szIPv4MCAST, NULL);
+		}
+		else {
+			result = m_SocketClient->AddMembership(szIPv6MCAST, NULL);
+			HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
+			hr = hr;
+		}
+	}
+	return result;
+}
+
+void CSATClient::GetAddress(const SockAddrIn& addrIn, CString& rString) const
+{
+	TCHAR szIPAddr[MAX_PATH] = { 0 };
+	CSocketHandle::FormatIP(szIPAddr, MAX_PATH, addrIn);
+	rString.Format(_T("%s : %d"), szIPAddr, static_cast<int>(static_cast<UINT>(ntohs(addrIn.GetPort()))));
+}
+
+bool CSATClient::TCPLogin(std::string strUserName, std::string strPassword)
+{
+	int len = HEADER_LEN + sizeof(TPLogin);
+	byte* pbuff = new byte[len];
+	memset(pbuff, 0, len);
+	Package* pData = (Package*)pbuff;
+
+	pData->header.protocol = 0xAA;
+	pData->header.len = len;
+	pData->header.cmd = CMD_LOGIN;
+
+	memcpy(pData->buf, strUserName.c_str(), strUserName.size());
+	memcpy(pData->buf + MAX_PATH, strPassword.c_str(), strPassword.size());
+
+	bool bret = OnSend(pbuff, len);
+	delete[]pbuff;
+
+	return bret;
+}
+
+bool CSATClient::TCPLogout(std::string strUserName, std::string strPassword)
+{
+	return false;
+}

+ 71 - 0
SATHelper/SATHelper/SATClient.h

@@ -0,0 +1,71 @@
+#ifndef __SAT_CLIENT__
+#define __SAT_CLIENT__
+
+#include "SocketHandle.h"
+#include "SocketClientImpl.h"
+#include "SATProtocol.h"
+
+#pragma once
+class CSATClient:public ISocketClientHandler
+{
+	CSATClient(void);
+	typedef SocketClientImpl<ISocketClientHandler> CSocketClient;
+	friend CSocketClient;
+protected:
+	// ISocketServerHandler
+	virtual void OnThreadBegin(CSocketHandle* pSH);
+	virtual void OnThreadExit(CSocketHandle* pSH);
+	virtual void OnDataReceived(CSocketHandle* pSH, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr);
+	virtual void OnConnectionDropped(CSocketHandle* pSH);
+	virtual void OnConnectionError(CSocketHandle* pSH, DWORD dwError);
+
+public:
+	static CSATClient* GetInstance()
+	{
+		static CSATClient* pInstance = NULL;
+		if (pInstance == NULL)
+		{
+			pInstance = new CSATClient;
+		}
+
+		return pInstance;
+	}
+
+	~CSATClient(void);
+
+private:
+	BOOL m_bSocket;			// 是否连接成功;
+	int m_nSockType;		// UDP 或 TCP
+	int m_nMode;			// IP4 或 IP6
+	std::string lastData;
+	CSocketClient m_SocketClient;
+	bool OnSend(const byte* pData, int nLen);
+	bool OnReceive(const byte* pData, int nLen);
+	bool OnClose();
+	bool OnConnect();
+	void TaskProcess(Package *pak);
+
+public:
+	// 启动TCP客户端连接实例;
+	BOOL Start();
+	// 停止TCP客户端连接;
+	void Stop();
+	// 多播(Multicasting);
+	bool SetupMCAST();
+	// 获取本机地址;
+	void GetAddress(const SockAddrIn& addrIn, CString& rString) const;
+
+	// 登录;
+	bool TCPLogin(std::string strUserName, std::string strPassword);
+	// 登出;
+	bool TCPLogout(std::string strUserName, std::string strPassword);
+
+	// 添加设备;
+	bool TCPAddDevice(std::string strDevice);
+	// 删除设备;
+	bool TCPDelDevice(std::string strDevice);
+	// 查询设备;
+	bool TCPQueryDevices(std::vector<std::string> &vtDevices);
+};
+
+#endif // __SAT_CLIENT__

+ 8 - 0
SATHelper/SATHelper/SATHelper.cpp

@@ -24,6 +24,9 @@
 #include "SATHelperView.h"
 
 #include "IOCPModel.h"
+#ifdef _DEBUG
+#include "SATClient.h"
+#endif
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -143,6 +146,11 @@ BOOL CSATHelperApp::InitInstance()
 	Global::GetConfig();
 	Global::WriteTextLog("程序启动");
 
+#ifdef _DEBUG 
+	CSATClient::GetInstance()->Start();
+	//CSATClient::GetInstance()->TCPLogin("superAdmin", "123456");
+#endif
+
 	g_iocp.LoadSocketLib();
 	g_iocp.Start(5566);
 #endif

+ 62 - 8
SATHelper/SATHelper/SATHelper.rc

@@ -53,11 +53,11 @@ BEGIN
     "\r\n"
     "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n"
     "LANGUAGE 4, 2\r\n"
-    "#include ""res\\SATHelper.rc2""  // 闂?Microsoft Visual C++ 缂傚倸鍊搁崐鎼佸磹瑜版帗鍋嬮柣鎰仛椤愯姤銇勯幇鍫曟闁稿骸绉归弻娑㈠即閵娿儲鐏撻梺闈涚墱閸嬪懐鎹?\n"
-    "#include ""l.CHS\\afxres.rc""      // 闂傚倷绀侀幖顐ょ矓閺夋嚚娲Χ婢跺﹪妫峰銈嗙墬缁海澹曟總鍛婄厱闁哄洢鍔嬬花鍏笺亜?\n"
-    "#include ""l.CHS\\afxprint.rc""    // 闂傚倷鑳堕幊鎾绘倶濮樿泛绠扮紒瀣硶閺?闂傚倷鑳堕幊鎾绘倶濮樿泛绠扮紒瀣硶閺嗐倝鏌涢幇銊︽珨缂佹唻缍侀弻娑㈠即閵娿儲鐝┑鐐插悑濡啴骞冪涵鍜佹Щ闁诲孩鍑归崢楣冩嚍?\n"
+    "#include ""res\\SATHelper.rc2""  // 闂?Microsoft Visual C++ 缂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鎲搁悧鍫濈瑲闁稿顑夐弻锝夊箛椤掑倷绮靛銈嗗姌婵倝濡甸崟顖氱疀闁割偅娲橀宥夋⒑缁嬪潡顎楃紒澶婄秺瀵鈽夐姀鐘插祮闂侀潧顭堥崕鏌ユ倶閹剧粯鈷戦梻鍫熺〒婢ч亶鏌涚€n亝鍣介柟?\n"
+    "#include ""l.CHS\\afxres.rc""      // 闂傚倸鍊搁崐椋庣矆娓氣偓楠炴牠顢曢妶鍥╃厠闂佸搫顦伴崵姘洪鍕幯冾熆鐠虹尨韬俊顐㈠槻椤啴濡堕崱娆忣潷缂備緡鍠栧ù閿嬬珶閺囩喓闄勯柛娑橈功閸橀亶姊洪崫鍕偍闁告柨顑囬懞閬嶅礂缁楄桨绨?\n"
+    "#include ""l.CHS\\afxprint.rc""    // 闂傚倸鍊搁崐鐑芥嚄閸洖绠犻柟鍓х帛閸婅埖鎱ㄥΟ鎸庣【缂佺姵澹嗙槐鎺斺偓锝庡幗绾爼鏌?闂傚倸鍊搁崐鐑芥嚄閸洖绠犻柟鍓х帛閸婅埖鎱ㄥΟ鎸庣【缂佺姵澹嗙槐鎺斺偓锝庡幗绾爼鏌¢崱鎰偓婵嬪蓟濞戙垹绠涢柕濠忛檮閻濄劎绱撴担鐟版暰缂傚秳绶氬璇测槈閵忕姴宓嗛梺闈涱焾閸庢煡鎮甸灏栨斀闁绘劖褰冮幃鎴炰繆椤愩垹鏆f鐐插暟濞戠敻宕担鍓愨晠姊虹拠鎻掝劉闁告垵缍婂畷銏°偅閸愨晛娈?\n"
     "#if !defined(_AFXDLL)\r\n"
-    "#include ""l.CHS\\afxribbon.rc""        // MFC 闂傚倷绀侀幉鈥愁潖婵犳艾绐楅柡鍥ュ灩缁€鍌涙叏濡炶浜鹃悗瑙勬礈婵炩偓鐎规洦鍋婂畷鐔碱敆閳ь剟顢旈鐐粹拺缁绢厼鎳愰悞浠嬫煕閹扳晛濡块柛姗嗗墴濮婃椽宕崟鍨紖闂侀潧鐗嗗ú銏ゅ磻閹烘垟鏀?\n"
+    "#include ""l.CHS\\afxribbon.rc""        // MFC 闂傚倸鍊搁崐椋庣矆娓氣偓楠炲鍨鹃幇浣圭稁婵犵數濮甸懝鍓х玻濡ゅ懏鐓涢柛銉e劚閻忊晝绱掗埀顒勫磼濞戞瑥寮垮┑锛勫仩椤曆勭妤e啯鍊甸悷娆忓缁€鍫濃攽閻愨晛浜鹃柣搴ゎ潐濞诧箓宕戞繝鍌滄殾闁绘梻鈷堥弫鍡涙煃瑜滈崜鐔笺€侀弮鍫晬闁绘劗琛ラ幏铏圭磼缂併垹骞栭柟铏姍閹偞绂掔€n偆鍘遍梺瑙勫閺呮稒淇婇崸妤佺厱婵妫楁晶瀛樻叏婵犲啯銇濈€规洦鍋婂畷鐔煎垂椤愵剛绀€闂傚倷绶氬褔鎮ч崱妞曟椽濮€閵堝懐锛涢梺鍦劋閸ㄧ喖寮?\n"
     "#endif\r\n"
     "#endif\r\n"
     "\0"
@@ -270,6 +270,7 @@ BEGIN
     END
     POPUP "TrayMenu"
     BEGIN
+        MENUITEM "登录",                          ID_TRAYMENU_LOGIN
         MENUITEM "重连",                          ID_TRAYMENU_RECONNECT
         MENUITEM "退出",                          ID_TRAYMENU_EXIT
     END
@@ -464,6 +465,25 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
 END
 
+IDD_DLG_LOGIN DIALOGEX 0, 0, 225, 114
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "登录"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    EDITTEXT        IDC_EDIT_USERNAME,89,23,74,14,ES_AUTOHSCROLL
+    EDITTEXT        IDC_EDIT_PASSWORD,89,48,74,14,ES_PASSWORD | ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "确定",IDOK,52,78,50,14
+    PUSHBUTTON      "取消",IDCANCEL,124,78,50,14
+    LTEXT           "用户",IDC_STATIC,62,26,17,8
+    LTEXT           "密码",IDC_STATIC,62,50,17,8
+END
+
+IDD_DLG_PROBAR DIALOGEX 0, 0, 135, 85
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -535,6 +555,22 @@ BEGIN
         TOPMARGIN, 7
         BOTTOMMARGIN, 96
     END
+
+    IDD_DLG_LOGIN, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 218
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 107
+    END
+
+    IDD_DLG_PROBAR, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 128
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 78
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
@@ -567,6 +603,24 @@ BEGIN
     0
 END
 
+IDD_DLG_LOGIN AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
+IDD_DLG_PROBAR AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GIF
+//
+
+GIF_PROBAR              GIF                     "res\\probar.gif"
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -782,11 +836,11 @@ END
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
 LANGUAGE 4, 2
-#include "res\SATHelper.rc2"  // 闂?Microsoft Visual C++ 缂傚倸鍊搁崐鎼佸磹瑜版帗鍋嬮柣鎰仛椤愯姤銇勯幇鍫曟闁稿骸绉归弻娑㈠即閵娿儲鐏撻梺闈涚墱閸嬪懐鎹?
-#include "l.CHS\afxres.rc"      // 闂傚倷绀侀幖顐ょ矓閺夋嚚娲Χ婢跺﹪妫峰銈嗙墬缁海澹曟總鍛婄厱闁哄洢鍔嬬花鍏笺亜?
-#include "l.CHS\afxprint.rc"    // 闂傚倷鑳堕幊鎾绘倶濮樿泛绠扮紒瀣硶閺?闂傚倷鑳堕幊鎾绘倶濮樿泛绠扮紒瀣硶閺嗐倝鏌涢幇銊︽珨缂佹唻缍侀弻娑㈠即閵娿儲鐝┑鐐插悑濡啴骞冪涵鍜佹Щ闁诲孩鍑归崢楣冩嚍?
+#include "res\SATHelper.rc2"  // 闂?Microsoft Visual C++ 缂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鎲搁悧鍫濈瑲闁稿顑夐弻锝夊箛椤掑倷绮靛銈嗗姌婵倝濡甸崟顖氱疀闁割偅娲橀宥夋⒑缁嬪潡顎楃紒澶婄秺瀵鈽夐姀鐘插祮闂侀潧顭堥崕鏌ユ倶閹剧粯鈷戦梻鍫熺〒婢ч亶鏌涚€n亝鍣介柟?
+#include "l.CHS\afxres.rc"      // 闂傚倸鍊搁崐椋庣矆娓氣偓楠炴牠顢曢妶鍥╃厠闂佸搫顦伴崵姘洪鍕幯冾熆鐠虹尨韬俊顐㈠槻椤啴濡堕崱娆忣潷缂備緡鍠栧ù閿嬬珶閺囩喓闄勯柛娑橈功閸橀亶姊洪崫鍕偍闁告柨顑囬懞閬嶅礂缁楄桨绨?
+#include "l.CHS\afxprint.rc"    // 闂傚倸鍊搁崐鐑芥嚄閸洖绠犻柟鍓х帛閸婅埖鎱ㄥΟ鎸庣【缂佺姵澹嗙槐鎺斺偓锝庡幗绾爼鏌?闂傚倸鍊搁崐鐑芥嚄閸洖绠犻柟鍓х帛閸婅埖鎱ㄥΟ鎸庣【缂佺姵澹嗙槐鎺斺偓锝庡幗绾爼鏌¢崱鎰偓婵嬪蓟濞戙垹绠涢柕濠忛檮閻濄劎绱撴担鐟版暰缂傚秳绶氬璇测槈閵忕姴宓嗛梺闈涱焾閸庢煡鎮甸灏栨斀闁绘劖褰冮幃鎴炰繆椤愩垹鏆f鐐插暟濞戠敻宕担鍓愨晠姊虹拠鎻掝劉闁告垵缍婂畷銏°偅閸愨晛娈?
 #if !defined(_AFXDLL)
-#include "l.CHS\afxribbon.rc"        // MFC 闂傚倷绀侀幉鈥愁潖婵犳艾绐楅柡鍥ュ灩缁€鍌涙叏濡炶浜鹃悗瑙勬礈婵炩偓鐎规洦鍋婂畷鐔碱敆閳ь剟顢旈鐐粹拺缁绢厼鎳愰悞浠嬫煕閹扳晛濡块柛姗嗗墴濮婃椽宕崟鍨紖闂侀潧鐗嗗ú銏ゅ磻閹烘垟鏀?
+#include "l.CHS\afxribbon.rc"        // MFC 闂傚倸鍊搁崐椋庣矆娓氣偓楠炲鍨鹃幇浣圭稁婵犵數濮甸懝鍓х玻濡ゅ懏鐓涢柛銉e劚閻忊晝绱掗埀顒勫磼濞戞瑥寮垮┑锛勫仩椤曆勭妤e啯鍊甸悷娆忓缁€鍫濃攽閻愨晛浜鹃柣搴ゎ潐濞诧箓宕戞繝鍌滄殾闁绘梻鈷堥弫鍡涙煃瑜滈崜鐔笺€侀弮鍫晬闁绘劗琛ラ幏铏圭磼缂併垹骞栭柟铏姍閹偞绂掔€n偆鍘遍梺瑙勫閺呮稒淇婇崸妤佺厱婵妫楁晶瀛樻叏婵犲啯銇濈€规洦鍋婂畷鐔煎垂椤愵剛绀€闂傚倷绶氬褔鎮ч崱妞曟椽濮€閵堝懐锛涢梺鍦劋閸ㄧ喖寮?
 #endif
 #endif
 

+ 18 - 0
SATHelper/SATHelper/SATHelper.vcxproj

@@ -207,16 +207,21 @@
     <ClInclude Include="..\UI\SubLabel.h" />
     <ClInclude Include="..\UI\TreeComboBox.h" />
     <ClInclude Include="..\UI\XColorStatic.h" />
+    <ClInclude Include="Base64.h" />
     <ClInclude Include="calendarbar.h" />
     <ClInclude Include="CaptureDef.h" />
+    <ClInclude Include="CharEncoding.h" />
     <ClInclude Include="DeviceView.h" />
     <ClInclude Include="ChildFrm.h" />
     <ClInclude Include="ClassView.h" />
     <ClInclude Include="CritSection.h" />
     <ClInclude Include="Device.h" />
+    <ClInclude Include="DlgLogin.h" />
+    <ClInclude Include="DlgProBar.h" />
     <ClInclude Include="FileView.h" />
     <ClInclude Include="framework.h" />
     <ClInclude Include="Global.h" />
+    <ClInclude Include="IMGCommon.h" />
     <ClInclude Include="IOCPModel.h" />
     <ClInclude Include="IRControlWnd.h" />
     <ClInclude Include="MainFrm.h" />
@@ -225,6 +230,10 @@
     <ClInclude Include="MemoryDef.h" />
     <ClInclude Include="OutputWnd.h" />
     <ClInclude Include="QCAP.H" />
+    <ClInclude Include="SATClient.h" />
+    <ClInclude Include="SATProtocol.h" />
+    <ClInclude Include="SocketClientImpl.h" />
+    <ClInclude Include="SocketHandle.h" />
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="PropertiesWnd.h" />
     <ClInclude Include="Resource.h" />
@@ -254,19 +263,26 @@
     <ClCompile Include="..\UI\SubLabel.cpp" />
     <ClCompile Include="..\UI\TreeComboBox.cpp" />
     <ClCompile Include="..\UI\XColorStatic.cpp" />
+    <ClCompile Include="Base64.cpp" />
     <ClCompile Include="calendarbar.cpp" />
+    <ClCompile Include="CharEncoding.cpp" />
     <ClCompile Include="DeviceView.cpp" />
     <ClCompile Include="ChildFrm.cpp" />
     <ClCompile Include="ClassView.cpp" />
     <ClCompile Include="Device.cpp" />
+    <ClCompile Include="DlgLogin.cpp" />
+    <ClCompile Include="DlgProBar.cpp" />
     <ClCompile Include="FileView.cpp" />
     <ClCompile Include="Global.cpp" />
+    <ClCompile Include="IMGCommon.cpp" />
     <ClCompile Include="IOCPModel.cpp" />
     <ClCompile Include="IRControlWnd.cpp" />
     <ClCompile Include="MainFrm.cpp" />
     <ClCompile Include="MemoryClient.cpp" />
     <ClCompile Include="MemoryComm.cpp" />
     <ClCompile Include="OutputWnd.cpp" />
+    <ClCompile Include="SATClient.cpp" />
+    <ClCompile Include="SocketHandle.cpp" />
     <ClCompile Include="stdafx.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
@@ -316,6 +332,7 @@
     <Image Include="res\pages_hc.bmp" />
     <Image Include="res\pages_small.bmp" />
     <Image Include="res\pages_small_hc.bmp" />
+    <Image Include="res\probar.gif" />
     <Image Include="res\properties.bmp" />
     <Image Include="res\properties_hc.bmp" />
     <Image Include="res\properties_wnd.ico" />
@@ -331,6 +348,7 @@
     <Image Include="res\writesmall.bmp" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="res\gif1.bin" />
     <None Include="res\ribbon.mfcribbon-ms" />
     <None Include="res\SATHelper.rc2" />
   </ItemGroup>

+ 63 - 0
SATHelper/SATHelper/SATHelper.vcxproj.filters

@@ -37,6 +37,15 @@
     <Filter Include="视图">
       <UniqueIdentifier>{ed995c5b-408e-413c-93ea-67ed56e847fc}</UniqueIdentifier>
     </Filter>
+    <Filter Include="SATClient">
+      <UniqueIdentifier>{9ce316cd-1a39-4a22-bd76-fc89574ed5c7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="进度条">
+      <UniqueIdentifier>{e9ffb0db-1b30-44d8-8193-f431720d3a2a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="字符编码">
+      <UniqueIdentifier>{e5c97bbe-7cd7-42ef-90bd-466af4138e54}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="SATHelper.h">
@@ -165,6 +174,33 @@
     <ClInclude Include="CaptureDef.h">
       <Filter>iocp</Filter>
     </ClInclude>
+    <ClInclude Include="DlgLogin.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="SATClient.h">
+      <Filter>SATClient</Filter>
+    </ClInclude>
+    <ClInclude Include="SocketHandle.h">
+      <Filter>SATClient</Filter>
+    </ClInclude>
+    <ClInclude Include="SocketClientImpl.h">
+      <Filter>SATClient</Filter>
+    </ClInclude>
+    <ClInclude Include="SATProtocol.h">
+      <Filter>SATClient</Filter>
+    </ClInclude>
+    <ClInclude Include="DlgProBar.h">
+      <Filter>进度条</Filter>
+    </ClInclude>
+    <ClInclude Include="IMGCommon.h">
+      <Filter>进度条</Filter>
+    </ClInclude>
+    <ClInclude Include="Base64.h">
+      <Filter>字符编码</Filter>
+    </ClInclude>
+    <ClInclude Include="CharEncoding.h">
+      <Filter>字符编码</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="SATHelper.cpp">
@@ -269,6 +305,27 @@
     <ClCompile Include="UB530View.cpp">
       <Filter>视图</Filter>
     </ClCompile>
+    <ClCompile Include="DlgLogin.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="SATClient.cpp">
+      <Filter>SATClient</Filter>
+    </ClCompile>
+    <ClCompile Include="SocketHandle.cpp">
+      <Filter>SATClient</Filter>
+    </ClCompile>
+    <ClCompile Include="DlgProBar.cpp">
+      <Filter>进度条</Filter>
+    </ClCompile>
+    <ClCompile Include="IMGCommon.cpp">
+      <Filter>进度条</Filter>
+    </ClCompile>
+    <ClCompile Include="Base64.cpp">
+      <Filter>字符编码</Filter>
+    </ClCompile>
+    <ClCompile Include="CharEncoding.cpp">
+      <Filter>字符编码</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="SATHelper.rc">
@@ -393,6 +450,9 @@
     <Image Include="res\unchecked.bmp">
       <Filter>资源文件</Filter>
     </Image>
+    <Image Include="res\probar.gif">
+      <Filter>资源文件</Filter>
+    </Image>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\ribbon.mfcribbon-ms">
@@ -401,6 +461,9 @@
     <None Include="res\SATHelper.rc2">
       <Filter>资源文件</Filter>
     </None>
+    <None Include="res\gif1.bin">
+      <Filter>资源文件</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Xml Include="layout.xml" />

+ 53 - 0
SATHelper/SATHelper/SATProtocol.h

@@ -0,0 +1,53 @@
+#ifndef __SAT_PROTOCOL__
+#define __SAT_PROTOCOL__
+
+#pragma once
+
+//////////////////////////////////////////////////////////////////////////
+// 야竟葵累寧즈;
+enum ProtocolCMD
+{
+	// 되쩌、되놔;
+	CMD_LOGIN					= 0,
+	CMD_LOGOUT					= 1,
+	// �구;
+	CMD_ADD_DEVICE				= 2,
+	CMD_DEL_DEVICE				= 3,
+	CMD_QUERY_DEVICES			= 4,
+};
+
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct _DATAHEADER_ {
+	// 葵累깃街륜;
+	byte			protocol;
+	// 뎠품繫斤관돨낀똑=header낀똑+buf낀똑;
+	unsigned int	len;
+	// 츱즈잚謹;
+	byte			cmd;
+}DataHeader, *pDataHeader;
+
+// 헝헹관
+typedef struct _PACKAGE_
+{
+	DataHeader	header;
+	byte		buf[4]; // 야竟코휭(寧濾뒈囹);
+}Package;
+
+// 칵훰럿쀼令;
+typedef struct __TPRESPONSE__
+{
+	bool bResult;
+}TPResponse, *pTPResponse;
+
+// 痰黨되쩌/되놔;
+typedef struct __TPLOGIN__
+{
+	char		szUserName[MAX_PATH];
+	char		szPassword[MAX_PATH];
+}TPLogin, *pTPLogin;
+
+#pragma pack(pop)
+
+#endif // __SAT_PROTOCOL__

+ 255 - 0
SATHelper/SATHelper/SocketClientImpl.h

@@ -0,0 +1,255 @@
+#ifndef SOCKETCLIENTIMPL_H
+#define SOCKETCLIENTIMPL_H
+#pragma once
+#pragma warning(push)
+#pragma warning(disable:4995)
+#include <vector>
+#pragma warning(pop)
+#include "SocketHandle.h"
+
+/**
+ * ISocketClientHandler
+ * Event handler that SocketClientImpl<T> must implement
+ * This class is not required, you can do the same thing as long your class exposes these functions.
+ * (These are not pure to save you some typing)
+ */
+class ISocketClientHandler
+{
+public:
+    virtual void OnThreadBegin(CSocketHandle* ) {}
+    virtual void OnThreadExit(CSocketHandle* ) {}
+    virtual void OnDataReceived(CSocketHandle* , const BYTE* , DWORD , const SockAddrIn& ) {}
+    virtual void OnConnectionDropped(CSocketHandle* ) {}
+    virtual void OnConnectionError(CSocketHandle* , DWORD ) {}
+};
+
+
+/**
+ * SocketClientImpl<T, tBufferSize>
+ * Because <typename T> may refer to any class of your choosing,
+ * Client Communication wrapper
+ */
+template <typename T, size_t tBufferSize = 2048>
+class SocketClientImpl
+{
+    typedef SocketClientImpl<T, tBufferSize> thisClass;
+public:
+    SocketClientImpl()
+    : _pInterface(0)
+    , _thread(0)
+    {
+    }
+
+    void SetInterface(T* pInterface)
+    {
+        ::InterlockedExchangePointer(reinterpret_cast<void**>(&_pInterface), pInterface);
+    }
+
+    operator CSocketHandle*() throw()
+    {
+        return( &_socket );
+    }
+
+    CSocketHandle* operator->() throw()
+    {
+        return( &_socket );
+    }
+
+    bool IsOpen() const
+    {
+        return _socket.IsOpen();
+    }
+
+    bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
+    {
+        return _socket.CreateSocket(pszHost, pszServiceName, nFamily, nType, uOptions);
+    }
+    
+    bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType)
+    {
+        return _socket.ConnectTo(pszHostName, pszRemote, pszServiceName, nFamily, nType);
+    }
+    
+    void Close()
+    {
+        _socket.Close();
+    }
+
+    DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
+    {
+        return _socket.Read(lpBuffer, dwSize, lpAddrIn, dwTimeout);
+    }
+
+    DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
+    {
+        return _socket.Write(lpBuffer, dwCount, lpAddrIn, dwTimeout);
+    }
+
+    bool StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
+    void Terminate(DWORD dwTimeout = INFINITE);
+
+    static bool IsConnectionDropped(DWORD dwError);
+
+protected:
+    void Run();
+    static DWORD WINAPI SocketClientProc(thisClass* _this);
+
+    T*              _pInterface;
+    HANDLE          _thread;
+    CSocketHandle   _socket;
+};
+
+
+template <typename T, size_t tBufferSize>
+bool SocketClientImpl<T, tBufferSize>::StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
+{
+    // must be closed first...
+    if ( IsOpen() ) return false;
+    bool result = false;
+    if ( nType == SOCK_STREAM )
+    {
+        result = _socket.ConnectTo(pszHost, pszRemote, pszServiceName, nFamily, nType); // TCP
+    }
+    else
+    {
+        // let provider select a port for us
+        result = _socket.CreateSocket(pszHost, TEXT("0"), nFamily, nType, uOptions); // UDP
+    }
+    if ( result )
+    {
+        _thread = AtlCreateThread(SocketClientProc, this);
+        if ( _thread == NULL )
+        {
+            DWORD dwError = GetLastError();
+            _socket.Close();
+            SetLastError(dwError);
+            result = false;
+        }
+    }
+    return result;
+}
+
+template <typename T, size_t tBufferSize>
+void SocketClientImpl<T, tBufferSize>::Run()
+{
+    SockAddrIn addrIn;
+    std::vector<unsigned char> data;
+    data.resize( tBufferSize );
+    DWORD dwRead;
+    DWORD dwError;
+
+    _ASSERTE( _pInterface != NULL && "Need an interface to pass events");
+
+    // Notification: OnThreadBegin
+    if ( _pInterface != NULL ) {
+        _pInterface->OnThreadBegin(*this);
+    }
+
+    int type = _socket.GetSocketType();
+    if (type == SOCK_STREAM) {
+        _socket.GetPeerName( addrIn );
+    }
+
+    while ( _socket.IsOpen() )
+    {
+        if (type == SOCK_STREAM)
+        {
+            dwRead = _socket.Read(&data[0], tBufferSize, NULL, INFINITE);
+        }
+        else
+        {
+            dwRead = _socket.Read(&data[0], tBufferSize, addrIn, INFINITE);
+        }
+        if ( (dwRead != -1L) && (dwRead > 0))
+        {
+            // Notification: OnDataReceived
+            if ( _pInterface != NULL ) {
+                _pInterface->OnDataReceived(*this, &data[0], dwRead, addrIn);
+            }
+        }
+        else if (type == SOCK_STREAM && dwRead == 0L )
+        {
+            // connection broken
+            if ( _pInterface != NULL )
+            {
+                _pInterface->OnConnectionDropped(*this);
+            }
+            break;
+        }
+        else if ( dwRead == -1L )
+        {
+            dwError = GetLastError();
+            if ( _pInterface != NULL )
+            {
+                if (IsConnectionDropped( dwError) ) {
+                    // Notification: OnConnectionDropped
+                    if (type == SOCK_STREAM || (dwError == WSAENOTSOCK || dwError == WSAENETDOWN))
+                    {
+                        _pInterface->OnConnectionDropped(*this);
+                        break;
+                    }
+                }
+                // Notification: OnConnectionError
+                _pInterface->OnConnectionError(*this, dwError);
+            }
+            else {
+                break;
+            }
+        }
+    }
+
+    data.clear();
+
+    // Notification: OnThreadExit
+    if ( _pInterface != NULL ) {
+        _pInterface->OnThreadExit(*this);
+    }
+}
+
+template <typename T, size_t tBufferSize>
+void SocketClientImpl<T, tBufferSize>::Terminate(DWORD dwTimeout /*= INFINITE*/)
+{
+    _socket.Close();
+    if ( _thread != NULL )
+    {
+        if ( WaitForSingleObject(_thread, dwTimeout) == WAIT_TIMEOUT ) {
+            TerminateThread(_thread, 1);
+        }
+        CloseHandle(_thread);
+        _thread = NULL;
+    }
+}
+
+template <typename T, size_t tBufferSize>
+DWORD WINAPI SocketClientImpl<T, tBufferSize>::SocketClientProc(thisClass* _this)
+{
+    if ( _this != NULL )
+    {
+        _this->Run();
+    }
+    return 0;
+}
+
+template <typename T, size_t tBufferSize>
+bool SocketClientImpl<T, tBufferSize>::IsConnectionDropped(DWORD dwError)
+{
+    // see: winerror.h for definition
+    switch( dwError )
+    {
+        case WSAENOTSOCK:
+        case WSAENETDOWN:
+        case WSAENETUNREACH:
+        case WSAENETRESET:
+        case WSAECONNABORTED:
+        case WSAECONNRESET:
+        case WSAESHUTDOWN:
+        case WSAEHOSTDOWN:
+        case WSAEHOSTUNREACH:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+#endif //SOCKETCLIENTIMPL_H

+ 1141 - 0
SATHelper/SATHelper/SocketHandle.cpp

@@ -0,0 +1,1141 @@
+/*
+** Copyright 2003-2009, Ernest Laurentin (http://www.ernzo.com/)
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+**
+** File:        SocketHandle.cpp
+** Version:     1.4 - IPv6 support
+**              1.3 - Update for Asynchronous mode / Linux port
+**              1.2 - Update interface for TCP remote connection
+**              1.1 - Added multicast support
+*/
+#include "stdafx.h"
+#ifdef WIN32
+#include <stdlib.h>
+#ifndef UNDER_CE
+#include <crtdbg.h>
+#endif
+#include <strsafe.h>
+#endif
+#include "SocketHandle.h"
+#include "Wspiapi.h"
+#include "Ws2tcpip.h"
+
+
+#ifndef BUFFER_SIZE
+#define BUFFER_SIZE     64*1024
+#endif
+#ifndef SOCKHANDLE_TTL
+#define SOCKHANDLE_TTL 5
+#endif
+#ifndef SOCKHANDLE_HOPS
+#define SOCKHANDLE_HOPS 10
+#endif
+#define HOSTNAME_SIZE   MAX_PATH
+#define STRING_LENGTH   40
+
+#if !defined(PLATFORM_HAS_INETFUNC)
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
+int _inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifdef WIN32
+#ifndef UNDER_CE
+#pragma comment(lib, "ws2_32.lib")
+#else
+#pragma comment(lib, "Ws2.lib")
+#endif
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SockAddrIn Struct
+SockAddrIn SockAddrIn::NULLAddr;
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructs
+
+SockAddrIn::SockAddrIn()
+{
+    Clear();
+}
+
+SockAddrIn::SockAddrIn(const SockAddrIn& sin)
+{
+    Copy( sin );
+}
+
+SockAddrIn::~SockAddrIn()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clear
+void SockAddrIn::Clear()
+{
+    memset(this, 0, sizeof(sockaddr_storage));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Copy
+SockAddrIn& SockAddrIn::Copy(const SockAddrIn& sin)
+{
+    ss_family = sin.ss_family;
+    memcpy(this, &sin, Size());
+    return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// IsEqual
+bool SockAddrIn::IsEqual(const SockAddrIn& sin) const
+{
+    // Is it Equal? - ignore 'sin_zero'
+    if ( ss_family == AF_INET ) {
+        return (memcmp(this, &sin, Size()-8) == 0);
+    }
+    return (memcmp(this, &sin, Size()) == 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CreateFrom
+bool SockAddrIn::CreateFrom(LPCTSTR pszAddr, LPCTSTR pszService, int nFamily /*=AF_INET*/)
+{
+    Clear();
+    CSocketHandle::GetAddressInfo(pszAddr, pszService, nFamily, *this);
+    return !IsNull();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CreateFrom
+bool SockAddrIn::CreateFrom(ULONG lIPAddr, USHORT nPort, int nFamily /*= AF_INET*/, bool bFmtHost /*= true*/)
+{
+    Clear();
+    _ASSERTE( nFamily == AF_INET ); // supports IPv4 only
+    SOCKADDR_IN* psin = reinterpret_cast<SOCKADDR_IN*>(this);
+    psin->sin_family = static_cast<short>(nFamily);
+    if ( bFmtHost )
+    {
+        psin->sin_addr.s_addr = htonl( lIPAddr );
+        psin->sin_port = htons( nPort );
+    }
+    else
+    {
+        psin->sin_addr.s_addr = lIPAddr;
+        psin->sin_port = nPort;
+    }
+    return !IsNull();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CSocketHandle
+CSocketHandle::CSocketHandle()
+: m_hSocket(INVALID_SOCKET)
+{
+}
+
+CSocketHandle::~CSocketHandle()
+{
+    Close();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// IsOpen
+bool CSocketHandle::IsOpen() const 
+{
+    return ( INVALID_SOCKET != m_hSocket );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetSocket
+SOCKET CSocketHandle::GetSocket() const
+{
+    return m_hSocket;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetSocketType
+int CSocketHandle::GetSocketType() const
+{
+    int type = -1;
+    if ( INVALID_SOCKET != m_hSocket ) {
+        socklen_t optlen = sizeof(int);
+        if ( getsockopt(GetSocket(), SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&type),
+                        &optlen) == SOCKET_ERROR)
+        {
+            SetLastError( WSAGetLastError() );
+        }
+    }
+    return type;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Attach
+bool CSocketHandle::Attach(SOCKET sock)
+{
+    if ( INVALID_SOCKET == m_hSocket )
+    {
+        m_hSocket = sock;
+        return true;
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Detach
+SOCKET CSocketHandle::Detach()
+{
+    SOCKET sock = m_hSocket;
+    ::InterlockedExchange(reinterpret_cast<long*>(&m_hSocket), INVALID_SOCKET);
+    return sock;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetSockName
+bool CSocketHandle::GetSockName(SockAddrIn& saddr_in) const
+{
+    _ASSERTE( IsOpen() );
+    if (IsOpen()) {
+        socklen_t namelen = (socklen_t)saddr_in.Size();
+        if (SOCKET_ERROR != getsockname(GetSocket(), saddr_in, &namelen))
+        {
+            return true;
+        }
+        SetLastError( WSAGetLastError() );
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetPeerName
+bool CSocketHandle::GetPeerName(SockAddrIn& saddr_in) const
+{
+    _ASSERTE( IsOpen() );
+    if (IsOpen()) {
+        socklen_t namelen = (socklen_t)saddr_in.Size();
+        if (SOCKET_ERROR != getpeername(GetSocket(), saddr_in, &namelen))
+        {
+            return true;
+        }
+        SetLastError( WSAGetLastError() );
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Close
+void CSocketHandle::Close()
+{
+    if ( IsOpen() )
+    {
+        ShutdownConnection(static_cast<SOCKET>(
+            ::InterlockedExchange((LONG*)&m_hSocket, INVALID_SOCKET)
+            ));
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AddMembership
+bool CSocketHandle::AddMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC)
+{
+    _ASSERTE( IsOpen() );
+    if ( IsOpen() )
+    {
+        int nType = 0;
+        socklen_t nOptLen = sizeof(int);
+        if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
+        {
+            if ( nType == SOCK_DGRAM )
+            {
+                // Setup interface for multicast traffic
+                SockAddrIn mcastAddr;
+                if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
+                {
+                    SockAddrIn interfAddr;
+                    GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
+                    if ( mcastAddr.ss_family == AF_INET )
+                    {
+                        int nTTL = SOCKHANDLE_TTL;
+                        if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&nTTL, sizeof(nTTL)))
+                        {
+                            ULONG ulNIC = interfAddr.GetIPAddr();
+                            if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_IF,(char *) &ulNIC, sizeof(ulNIC)))
+                            {
+                                ip_mreq mreq = { 0 };
+                                mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
+                                mreq.imr_interface.s_addr = ulNIC;
+                                if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
+                                {
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                    else if ( mcastAddr.ss_family == AF_INET6 )
+                    {
+                        int nTTL = SOCKHANDLE_HOPS;
+                        if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&nTTL, sizeof(nTTL)))
+                        {
+                            ipv6_mreq mreq6 = { 0 };
+                            IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
+                            memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
+                            if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
+                            {
+                                return true;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // invalid socket option
+                        WSASetLastError(WSAENOPROTOOPT);
+                    }
+                }
+            }
+            else
+            {
+                // invalid socket option
+                WSASetLastError(WSAENOPROTOOPT);
+            }
+        }
+        SetLastError( WSAGetLastError() );
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DropMembership
+bool CSocketHandle::DropMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC)
+{
+    _ASSERTE( IsOpen() );
+    if ( IsOpen() )
+    {
+        int nType = 0;
+        socklen_t nOptLen = sizeof(int);
+        if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
+        {
+            if ( nType == SOCK_DGRAM )
+            {
+                SockAddrIn mcastAddr;
+                if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
+                {
+                    SockAddrIn interfAddr;
+                    GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
+                    if ( mcastAddr.ss_family == AF_INET )
+                    {
+                        ip_mreq mreq;
+                        mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
+                        mreq.imr_interface.s_addr = interfAddr.GetIPAddr();;
+                        if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
+                        {
+                            return true;
+                        }
+                    }
+                    else if ( mcastAddr.ss_family == AF_INET6 )
+                    {
+                        ipv6_mreq mreq6 = { 0 };
+                        IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
+                        memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
+                        if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
+                        {
+                            return true;
+                        }
+                    }
+                    else
+                    {
+                        // invalid socket option
+                        WSASetLastError(WSAENOPROTOOPT);
+                    }
+                }
+            }
+            else
+            {
+                // invalid socket option
+                WSASetLastError(WSAENOPROTOOPT);
+            }
+        }
+        SetLastError( WSAGetLastError() );
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CreateSocket
+bool CSocketHandle::CreateSocket(LPCTSTR pszHostName, LPCTSTR pszServiceName,
+                                int nFamily, int nType, UINT uOptions /* = 0 */)
+{
+    // Socket is already opened
+    if ( IsOpen() ) {
+        SetLastError(ERROR_ACCESS_DENIED);
+        return false;
+    }
+
+    // Create a Socket that is bound to a specific service provider
+    // nFamily: (AF_INET, AF_INET6)
+    // nType: (SOCK_STREAM, SOCK_DGRAM)
+#ifdef SOCKHANDLE_USE_OVERLAPPED
+    SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
+#else
+    SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
+#endif
+    if (INVALID_SOCKET != sock)
+    {
+        if (uOptions & SO_REUSEADDR)
+        {
+            // Inform Windows Sockets provider that a bind on a socket should not be disallowed
+            // because the desired address is already in use by another socket
+            BOOL optval = TRUE;
+            if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof( BOOL ) ) )
+            {
+                SetLastError( WSAGetLastError() );
+                closesocket( sock );
+                return false;
+            }
+        }
+
+        if (nType == SOCK_DGRAM)
+        {
+            if ((uOptions & SO_BROADCAST) && (nFamily == AF_INET))
+            {
+                // Inform Windows Sockets provider that broadcast messages are allowed
+                BOOL optval = TRUE;
+                if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof( BOOL ) ) )
+                {
+                    SetLastError( WSAGetLastError() );
+                    closesocket( sock );
+                    return false;
+                }
+            }
+#ifdef SOCKHANDLE_CONFIGBUF
+            // configure buffer size
+            socklen_t rcvbuf = BUFFER_SIZE;
+            if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
+            {
+                SetLastError( WSAGetLastError() );
+                closesocket( sock );
+                return false;
+            }
+#endif
+        }
+
+        // Associate a local address with the socket
+        SockAddrIn sockAddr;
+        sockAddr.CreateFrom(pszHostName, pszServiceName, nFamily);
+
+        if ( SOCKET_ERROR == ::bind(sock, sockAddr, (int)sockAddr.Size()))
+        {
+            SetLastError( WSAGetLastError() );
+            closesocket( sock );
+            return false;
+        }
+
+        // Listen to the socket, only valid for connection socket (TCP)
+        if (SOCK_STREAM == nType)
+        {
+            if ( SOCKET_ERROR == listen(sock, SOMAXCONN))
+            {
+                SetLastError( WSAGetLastError() );
+                closesocket( sock );
+                return false;
+            }
+        }
+
+        // Success, now we may save this socket
+        m_hSocket = sock;
+    }
+
+    return (INVALID_SOCKET != sock);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ConnectTo
+bool CSocketHandle::ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote,
+                              LPCTSTR pszServiceName, int nFamily, int nType)
+{
+    // Socket is already opened
+    if ( IsOpen() ) {
+        SetLastError(ERROR_ACCESS_DENIED);
+        return false;
+    }
+
+    // Create a Socket that is bound to a specific service provider
+    // nFamily: (AF_INET, AF_INET6)
+    // nType: (SOCK_STREAM, SOCK_DGRAM)
+#ifdef SOCKHANDLE_USE_OVERLAPPED
+    SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
+#else
+    SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
+#endif
+    if (INVALID_SOCKET != sock)
+    {
+        // Associate a local address with the socket but let provider assign a port number
+        SockAddrIn sockAddr;
+        if (false == sockAddr.CreateFrom(pszHostName, TEXT("0"), nFamily))
+        {
+            SetLastError( WSAGetLastError() );
+            closesocket( sock );
+            return false;
+        }
+
+        if ( SOCKET_ERROR == ::bind(sock, sockAddr, (int)sockAddr.Size()))
+        {
+            SetLastError( WSAGetLastError() );
+            closesocket( sock );
+            return false;
+        }
+
+#ifdef SOCKHANDLE_CONFIGBUF
+        if (nType == SOCK_DGRAM)
+        {
+            // configure buffer size
+            socklen_t rcvbuf = BUFFER_SIZE;
+            if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
+            {
+                SetLastError( WSAGetLastError() );
+                closesocket( sock );
+                return false;
+            }
+        }
+#endif
+        // Now get destination address & port
+        sockAddr.CreateFrom( pszRemote, pszServiceName, nFamily );
+
+        // try to connect - if fail, server not ready
+        if (SOCKET_ERROR == connect( sock, sockAddr, (int)sockAddr.Size()))
+        {
+            SetLastError( WSAGetLastError() );
+            closesocket( sock );
+            return false;
+        }
+
+        // Success, now we may save this socket
+        m_hSocket = sock;
+    }
+    return (INVALID_SOCKET != sock);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Read
+DWORD CSocketHandle::Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
+                         DWORD dwTimeout)
+{
+    _ASSERTE( IsOpen() );
+    _ASSERTE( lpBuffer != NULL );
+
+    if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
+        return (DWORD)-1L;
+
+    fd_set  fdRead  = { 0 };
+    TIMEVAL stTime;
+    TIMEVAL *pstTime = NULL;
+
+    if ( INFINITE != dwTimeout ) {
+        stTime.tv_sec = dwTimeout/1000;
+        stTime.tv_usec = (dwTimeout%1000)*1000;
+        pstTime = &stTime;
+    }
+
+    SOCKET s = GetSocket();
+
+    // Set Descriptor
+    FD_SET( s, &fdRead );
+
+    // Select function set read timeout
+    DWORD dwBytesRead = 0L;
+    int res = 1;
+    if ( pstTime != NULL )
+        res = select((int)s, &fdRead, NULL, NULL, pstTime );
+    if ( res > 0)
+    {
+        if (lpAddrIn)
+        {
+            // UDP
+            socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
+            res = recvfrom(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0, lpAddrIn, &fromlen);
+        }
+        else
+        {
+            // TCP
+            res = recv(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0);
+        }
+        if ( res == 0 ) {
+            WSASetLastError(WSAECONNRESET);
+            res = SOCKET_ERROR;
+        }
+    }
+    if ( res == SOCKET_ERROR )
+    {
+        SetLastError( WSAGetLastError() );
+    }
+    dwBytesRead = (DWORD)((res >= 0)?(res) : (-1));
+
+    return dwBytesRead;
+}
+
+#ifdef WIN32
+///////////////////////////////////////////////////////////////////////////////
+// ReadEx
+DWORD CSocketHandle::ReadEx(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
+                         LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine)
+{
+    _ASSERTE( IsOpen() );
+    _ASSERTE( lpBuffer != NULL );
+
+    if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
+        return (DWORD)-1L;
+
+    SOCKET s = GetSocket();
+    // Send message to peer
+    WSABUF wsabuf;
+    wsabuf.buf = (char FAR*)lpBuffer;
+    wsabuf.len = dwSize;
+
+    // Select function set read timeout
+    DWORD dwBytesRead = 0L;
+    DWORD dwFlags = 0L;
+    int res = 0;
+    if (lpAddrIn)
+    {
+        // UDP
+        socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
+        res = WSARecvFrom( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpAddrIn, &fromlen, lpOverlapped, lpCompletionRoutine);
+    }
+    else
+    {
+        // TCP
+        res = WSARecv( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpOverlapped, lpCompletionRoutine);
+    }
+    if ( res == SOCKET_ERROR )
+    {
+        res = WSAGetLastError();
+        if ( res != WSA_IO_PENDING )
+        {
+            dwBytesRead = (DWORD)-1L;
+            SetLastError( res );
+        }
+    }
+
+    return dwBytesRead;
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Write
+DWORD CSocketHandle::Write(const LPBYTE lpBuffer, DWORD dwCount,
+                          const LPSOCKADDR lpAddrIn, DWORD dwTimeout)
+{
+    _ASSERTE( IsOpen() );
+    _ASSERTE( NULL != lpBuffer );
+
+    // validate params
+    if (!IsOpen() || NULL == lpBuffer)
+        return (DWORD)-1L;
+
+    fd_set  fdWrite  = { 0 };
+    TIMEVAL stTime;
+    TIMEVAL *pstTime = NULL;
+
+    if ( INFINITE != dwTimeout ) {
+        stTime.tv_sec = dwTimeout/1000;
+        stTime.tv_usec = (dwTimeout%1000)*1000;
+        pstTime = &stTime;
+    }
+
+    SOCKET s = GetSocket();
+
+    // Set Descriptor
+    FD_SET( s, &fdWrite );
+
+    // Select function set write timeout
+    DWORD dwBytesWritten = 0L;
+    int res = 1;
+    if ( pstTime != NULL )
+        res = select((int)s, NULL, &fdWrite, NULL, pstTime );
+    if ( res > 0)
+    {
+        // Send message to peer
+        if (lpAddrIn)
+        {
+            // UDP
+            res = sendto( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE));
+        }
+        else
+        {
+            // TCP
+            res = send( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0);
+        }
+    }
+    if ( res == SOCKET_ERROR )
+    {
+        SetLastError( WSAGetLastError() );
+    }
+    dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
+
+    return dwBytesWritten;
+}
+
+#ifdef WIN32
+///////////////////////////////////////////////////////////////////////////////
+// WriteEx
+DWORD CSocketHandle::WriteEx(const LPBYTE lpBuffer, DWORD dwCount,
+                            const LPSOCKADDR lpAddrIn,
+                            LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine)
+{
+    _ASSERTE( IsOpen() );
+    _ASSERTE( NULL != lpBuffer );
+
+    // validate params
+    if (!IsOpen() || NULL == lpBuffer)
+        return (DWORD)-1L;
+
+    SOCKET s = GetSocket();
+
+    // Select function set write timeout
+    DWORD dwBytesWritten = 0L;
+    int res = 0;
+    // Send message to peer
+    WSABUF wsabuf;
+    wsabuf.buf = (char FAR*) lpBuffer;
+    wsabuf.len = dwCount;
+    if (lpAddrIn)
+    {
+        // UDP
+        res = WSASendTo( s, &wsabuf, 1, &dwBytesWritten, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE),
+            lpOverlapped, lpCompletionRoutine);
+    }
+    else // TCP
+        res = WSASend( s, &wsabuf, 1, &dwBytesWritten, 0, lpOverlapped, lpCompletionRoutine);
+
+    if ( res == SOCKET_ERROR )
+    {
+        res = WSAGetLastError();
+        if ( res != WSA_IO_PENDING )
+        {
+            dwBytesWritten = (DWORD)-1L;
+            SetLastError( res );
+        }
+    }
+
+    return dwBytesWritten;
+}
+#endif
+
+#ifdef WIN32
+///////////////////////////////////////////////////////////////////////////////
+// IOControl
+bool CSocketHandle::IOControl(DWORD dwIoCode, LPBYTE lpInBuffer, DWORD cbInBuffer,
+                              LPBYTE lpOutBuffer, DWORD cbOutBuffer,
+                              LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
+                              LPWSACOMPLETIONROUTINE lpCompletionRoutine)
+{
+    _ASSERTE( IsOpen() );
+    // validate params
+    if ( !IsOpen() ) {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return false;
+    }
+    int res;
+    SOCKET s = GetSocket();
+    res = WSAIoctl(s, dwIoCode, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer,
+                   lpcbBytesReturned, lpOverlapped, lpCompletionRoutine);
+    if ( res == SOCKET_ERROR )
+    {
+        SetLastError( WSAGetLastError() );
+    }
+    return ( res != SOCKET_ERROR );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetTransferOverlappedResult
+bool CSocketHandle::GetTransferOverlappedResult(LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer,
+                                 bool bWait /*= true*/, LPDWORD lpdwFlags /*= NULL*/)
+{
+    _ASSERTE( IsOpen() );
+    _ASSERTE( NULL != lpOverlapped );
+
+    // validate params
+    if (!IsOpen() || NULL == lpOverlapped) {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return false;
+    }
+
+    SOCKET s = GetSocket();
+    DWORD dwFlags = 0;
+    if ( lpdwFlags == NULL )
+        lpdwFlags = &dwFlags;
+    BOOL bRet = WSAGetOverlappedResult( s, lpOverlapped, lpcbTransfer, bWait, lpdwFlags );
+    if ( !bRet )
+    {
+        SetLastError( WSAGetLastError() );
+    }
+    return (bRet != FALSE);
+}
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Utility functions
+
+///////////////////////////////////////////////////////////////////////////////
+// InitLibrary
+bool CSocketHandle::InitLibrary(WORD wVersion)
+{
+#ifdef WIN32
+    WSADATA WSAData = { 0 };
+    return ( 0 == WSAStartup( wVersion, &WSAData ) );
+#else
+    return true;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ReleaseLibrary
+bool CSocketHandle::ReleaseLibrary()
+{
+#ifdef WIN32
+    return ( 0 == WSACleanup() );
+#else
+    return true;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WaitForConnection
+SOCKET CSocketHandle::WaitForConnection(SOCKET sock)
+{
+    return accept(sock, 0, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ShutdownConnection
+bool CSocketHandle::ShutdownConnection(SOCKET sock)
+{
+    shutdown(sock, SD_BOTH);
+    return ( 0 == closesocket( sock ));
+}
+
+static unsigned char chMinClassA_IP [] = { 1,   0,   0,   0   } ;
+static unsigned char chMinClassD_IP [] = { 224, 0,   0,   0   } ;
+static unsigned char chMaxClassD_IP [] = { 239, 255, 255, 255 } ;
+
+///////////////////////////////////////////////////////////////////////////////
+// IsUnicastIP
+bool CSocketHandle::IsUnicastIP( ULONG ulAddr )
+{
+    return (((unsigned char *) & ulAddr) [0] >= chMinClassA_IP [0] &&
+            ((unsigned char *) & ulAddr) [0] < chMinClassD_IP [0]) ;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// IsMulticastIP
+bool CSocketHandle::IsMulticastIP( ULONG ulAddr )
+{
+    return (((unsigned char *) & ulAddr) [0] >= chMinClassD_IP [0] &&
+            ((unsigned char *) & ulAddr) [0] <= chMaxClassD_IP [0]) ;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FormatIP
+bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, ULONG ulAddr, bool bFmtHost)
+{
+    if ( pszIPAddr && nSize > 8)
+    {
+        if ( bFmtHost )
+            ulAddr = htonl( ulAddr );
+        // Create Address string
+        return (SUCCEEDED(StringCchPrintf(pszIPAddr, nSize, TEXT("%u.%u.%u.%u"),
+                            (UINT)(((PBYTE) &ulAddr)[0]),
+                            (UINT)(((PBYTE) &ulAddr)[1]),
+                            (UINT)(((PBYTE) &ulAddr)[2]),
+                            (UINT)(((PBYTE) &ulAddr)[3]))));
+    }
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FormatIP
+bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, const SockAddrIn& addrIn)
+{
+    if ( pszIPAddr && nSize > 8)
+    {
+        const void* addr;
+        char szIPAddr[MAX_PATH] = { 0 };
+        if (addrIn.ss_family == AF_INET) {
+            addr = &((const sockaddr_in*)&addrIn)->sin_addr;
+        } else {
+            addr = &((const sockaddr_in6*)&addrIn)->sin6_addr;
+        }
+        if (inet_ntop(addrIn.ss_family, addr, szIPAddr, MAX_PATH) != NULL)
+        {
+#ifdef _UNICODE
+            return (0 != MultiByteToWideChar(CP_UTF8, 0, szIPAddr, -1, pszIPAddr, nSize ));
+#else
+            ::StringCbCopyA(pszIPAddr, nSize, szIPAddr);
+            return true;
+#endif
+        }
+    }
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetPortNumber
+USHORT CSocketHandle::GetPortNumber( LPCTSTR pszServiceName )
+{
+    LPSERVENT   lpservent;
+    USHORT      nPort = 0;
+
+    if ( _istdigit( pszServiceName[0] ) ) {
+        nPort = (USHORT) _ttoi( pszServiceName );
+    }
+    else {
+#ifdef _UNICODE
+        char pstrService[HOSTNAME_SIZE] = { 0 };
+        WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
+#else
+        LPCTSTR pstrService = pszServiceName;
+#endif
+        // Convert network byte order to host byte order
+        if ( (lpservent = getservbyname( pstrService, NULL )) != NULL )
+            nPort = ntohs( lpservent->s_port );
+    }
+
+    return nPort;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetIPAddress
+ULONG CSocketHandle::GetIPAddress( LPCTSTR pszHostName )
+{
+    LPHOSTENT   lphostent;
+    ULONG       uAddr = INADDR_NONE;
+    TCHAR       szLocal[HOSTNAME_SIZE] = { 0 };
+
+    // if no name specified, get local
+    if ( NULL == pszHostName || !pszHostName[0])
+    {
+        GetLocalName(szLocal, HOSTNAME_SIZE);
+        pszHostName = szLocal;
+    }
+
+#ifdef _UNICODE
+    char pstrHost[HOSTNAME_SIZE] = { 0 };
+    WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
+#else
+    LPCTSTR pstrHost = pszHostName;
+#endif
+
+    // Check for an Internet Protocol dotted address string
+    uAddr = inet_addr( pstrHost );
+
+    if ( (INADDR_NONE == uAddr) && (strcmp( pstrHost, "255.255.255.255" )) )
+    {
+        // It's not an address, then try to resolve it as a hostname
+        if ( (lphostent = gethostbyname( pstrHost )) != NULL )
+            uAddr = *((ULONG *) lphostent->h_addr_list[0]);
+    }
+    
+    return ntohl( uAddr );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetLocalName
+bool CSocketHandle::GetLocalName(LPTSTR pszName, UINT nSize)
+{
+    if (pszName != NULL && nSize > 0)
+    {
+        char szHost[HOSTNAME_SIZE] = { 0 };
+
+        // get host name, if fail, SetLastError is set
+        if (SOCKET_ERROR != gethostname(szHost, sizeof(szHost)))
+        {
+            struct hostent* hp;
+            hp = gethostbyname(szHost);
+            if (hp != NULL) {
+                ::StringCbCopyA(szHost, HOSTNAME_SIZE, hp->h_name);
+            }
+
+            // check if user provide enough buffer
+            size_t cbLength = 0;
+            ::StringCbLengthA(szHost, HOSTNAME_SIZE, &cbLength);
+            if ( cbLength > nSize )
+            {
+                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return false;
+            }
+
+            // Unicode conversion
+#ifdef _UNICODE
+            return (0 != MultiByteToWideChar(CP_UTF8, 0, szHost, -1, pszName, nSize ));
+#else
+            ::StringCbCopyA(pszName, nSize, szHost);
+            return true;
+#endif
+        }
+        else
+            SetLastError( WSAGetLastError() );
+    }
+    else
+        SetLastError(ERROR_INVALID_PARAMETER);
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetLocalAddress
+bool CSocketHandle::GetLocalAddress(LPTSTR pszAddress, UINT nSize, int nFamily /*= AF_INET*/)
+{
+    if (pszAddress != NULL && nSize > 0)
+    {
+        TCHAR szHost[HOSTNAME_SIZE] = { 0 };
+
+        // Get computer local address
+        // get host name, if fail, SetLastError is set
+        if (GetLocalName(szHost, HOSTNAME_SIZE))
+        {
+            char szAddress[MAX_PATH] = { 0 };
+
+#ifdef _UNICODE
+            char pstrHost[HOSTNAME_SIZE] = { 0 };
+            WideCharToMultiByte(CP_UTF8, 0, szHost, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
+#else
+            LPCTSTR pstrHost = szHost;
+#endif
+            // get address info
+            sockaddr_storage addr_store = { 0 };
+            addr_store.ss_family = static_cast<short>(nFamily);
+            inet_pton(nFamily, pstrHost, &addr_store);
+            const void* addr;
+            if (addr_store.ss_family == AF_INET) {
+                addr = &((const sockaddr_in*)&addr_store)->sin_addr;
+            } else {
+                addr = &((const sockaddr_in6*)&addr_store)->sin6_addr;
+            }
+            if (inet_ntop(addr_store.ss_family, addr, szAddress, MAX_PATH) != NULL)
+            {
+                // Unicode conversion
+#ifdef _UNICODE
+                return (0 != MultiByteToWideChar(CP_UTF8, 0, szAddress, -1, pszAddress, nSize ));
+#else
+                ::StringCbCopyA(pszAddress, nSize, szAddress);
+                return true;
+#endif
+            }
+            else
+                SetLastError( WSAGetLastError() );
+        }
+    }
+    else
+        SetLastError(ERROR_INVALID_PARAMETER);
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetAddressInfo
+bool CSocketHandle::GetAddressInfo(LPCTSTR pszHostName, LPCTSTR pszServiceName,
+                                   int nFamily, SockAddrIn& sockAddr)
+{
+    const TCHAR szZERO[] = TEXT("0");
+    ADDRINFO aiHints;
+    ADDRINFO *aiList = NULL;
+    memset(&aiHints, 0, sizeof(aiHints));
+//    aiHints.ai_flags = AI_ADDRCONFIG;
+    aiHints.ai_family = static_cast<short>(nFamily);
+
+    TCHAR szLocal[HOSTNAME_SIZE] = { 0 };
+    // if no name specified, get local
+    if ( NULL == pszHostName || !pszHostName[0])
+    {
+        GetLocalName(szLocal, HOSTNAME_SIZE);
+        pszHostName = szLocal;
+    }
+    if ( NULL == pszServiceName || !pszServiceName[0])
+    {
+        pszServiceName = szZERO;
+    }
+
+#ifdef _UNICODE
+    char pstrHost[HOSTNAME_SIZE] = { 0 };
+    WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
+    char pstrService[HOSTNAME_SIZE] = { 0 };
+    WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
+#else
+    LPCTSTR pstrHost = pszHostName;
+    LPCTSTR pstrService = pszServiceName;
+#endif
+    if ( SOCKET_ERROR != getaddrinfo(pstrHost, pstrService, &aiHints, &aiList) && ( aiList != 0 ))
+    {
+        ADDRINFO ai = { 0 };
+        ai.ai_addr = sockAddr;
+        memcpy(ai.ai_addr, aiList->ai_addr, aiList->ai_addrlen);
+        freeaddrinfo( aiList );
+        return true;
+    }
+    SetLastError( WSAGetLastError() );
+    return false;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Globals
+///////////////////////////////////////////////////////////////////////////////
+#if !defined(PLATFORM_HAS_INETFUNC)
+///////////////////////////////////////////////////////////////////////////////
+// inet_ntop
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+{
+    if ( dst != NULL)
+    {
+        dst[0] = 0;
+        if (af == AF_INET)
+        {
+            sockaddr_in in;
+            memset(&in, 0, sizeof(in));
+            in.sin_family = AF_INET;
+            memcpy(&in.sin_addr, src, sizeof(in_addr));
+            getnameinfo((sockaddr *)&in, sizeof(sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
+            return dst;
+        }
+        else if (af == AF_INET6)
+        {
+            sockaddr_in6 in;
+            memset(&in, 0, sizeof(in));
+            in.sin6_family = AF_INET6;
+            memcpy(&in.sin6_addr, src, sizeof(in6_addr));
+            getnameinfo((sockaddr *)&in, sizeof(sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
+            return dst;
+        }
+    }
+    WSASetLastError(WSA_INVALID_PARAMETER);
+    return dst;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// inet_pton
+int _inet_pton(int af, const char *src, void *dst)
+{
+    int result = SOCKET_ERROR;
+    addrinfo aiHints, *aiList = NULL;
+    memset(&aiHints, 0, sizeof(aiHints));
+    aiHints.ai_family = af;
+
+    if ( SOCKET_ERROR != getaddrinfo(src, NULL, &aiHints, &aiList) && (aiList != NULL))
+    {
+        memcpy(dst, aiList->ai_addr, aiList->ai_addrlen);
+        freeaddrinfo(aiList);
+        result = 0;
+    }
+    return result;
+}
+#endif

+ 501 - 0
SATHelper/SATHelper/SocketHandle.h

@@ -0,0 +1,501 @@
+/*
+** Copyright 2003-2009, Ernest Laurentin (http://www.ernzo.com/)
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+**
+** File:        SocketHandle.h
+** Version:     1.4 - IPv6 support
+**              1.3 - Update for Asynchronous mode / Linux port
+**              1.2 - Update interface for TCP remote connection
+**              1.1 - Added multicast support
+*/
+#ifndef SOCKETHANDLE_H
+#define SOCKETHANDLE_H
+#pragma once
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#elif BSD_SOCKET
+#include "platform.h"
+#endif
+
+/**
+ * @defgroup _SockHandle Socket Communication Classes
+ * @{
+ */
+
+/**
+ * SockAddrIn structure
+ * Encapsulate SOCKADDR_STORAGE (IPv4: SOCKADDR_IN, IPv6: SOCKADDR_IN6) structures
+ */
+struct SockAddrIn : public sockaddr_storage {
+public:
+    /**
+     * Default constructor
+     */
+    SockAddrIn();
+
+    /**
+     * Copy constructor
+     * @param sin reference object
+     */
+    SockAddrIn(const SockAddrIn& sin);
+
+    /**
+     * Destructor
+     */
+    ~SockAddrIn();
+
+    /**
+     * Copy function
+     * @param sin reference object
+     * @return reference of 'this' object
+     */
+    SockAddrIn& Copy(const SockAddrIn& sin);
+
+    /**
+     * Clear struct
+     */
+    void    Clear();
+
+    /**
+     * Compare NetworkAddr object
+     * @param sin reference object
+     * @return true if equal, otherwise false
+     */
+    bool    IsEqual(const SockAddrIn& sin) const;
+
+    /**
+     * Check if NULL
+     * @return true if object is 'NULL' - not valid
+     */
+    bool    IsNull() const { return IsEqual(NULLAddr); }
+
+    /**
+     * Get Socket address family
+     * @return Socket address family (IPv4: AF_INET, IPv6: AF_INET6)
+     */
+    short GetFamily () const { return ss_family; }
+
+    /**
+     * Get IP address (IPv4)
+     * @return IPv4 network address in network format
+     */
+	ULONG   GetIPAddr() const { return ((SOCKADDR_IN*)this)->sin_addr.s_addr; }
+
+    /**
+     * Get Port
+     * @return Port number in network format
+     */
+    short   GetPort() const { return ((SOCKADDR_IN*)this)->sin_port; }
+
+    /**
+     * Create from string. Service is service name or port number.
+     * @param pszAddr Hostname or IP address
+     * @param pszService Service name or port
+     * @param nFamily Socket address family (default: AF_INET, AF_INET6)
+     * @return true if object is now valid
+     */
+    bool    CreateFrom(LPCTSTR pszAddr, LPCTSTR pszService, int nFamily = AF_INET);
+
+    /**
+     * Create from number. Initialize object from host or network format values (IPv4 only).
+     * @param lIPAddr IP Address
+     * @param nPort Port number
+     * @param nFamily Socket address family (default: AF_INET)
+     * @param bFmtHost flag to indicate that IP address and port are in host (true) or network format (false)
+     * @return true if object is now valid
+     */
+    bool    CreateFrom(ULONG lIPAddr, USHORT nPort, int nFamily = AF_INET, bool bFmtHost = true);
+
+    /**
+     * Object copy operator
+     * @param sin reference object to copy from
+     * @return reference of 'this' object
+     */
+    SockAddrIn& operator=(const SockAddrIn& sin) { return Copy( sin ); }
+
+    /**
+     * Equality operator
+     * @param sin reference object to test
+     * @return true if object is equal
+     */
+    bool    operator==(const SockAddrIn& sin) const { return IsEqual( sin ); }
+
+    /**
+     * Not Equal operator
+     * @param sin reference object to test
+     * @return true if object is different
+     */
+    bool    operator!=(const SockAddrIn& sin) const { return !IsEqual( sin ); }
+
+    /**
+     * SOCKADDR conversion. Return SOCKADDR of this object.
+     */
+    operator LPSOCKADDR() { return reinterpret_cast<LPSOCKADDR>(this); }
+
+    /**
+     * PIN6_ADDR conversion. Return const PIN6_ADDR of this object.
+     */
+    operator const IN6_ADDR*() const { return reinterpret_cast<const IN6_ADDR*>(this); }
+
+    /**
+     * PIN6_ADDR conversion. Return PIN6_ADDR of this object.
+     */
+    operator PIN6_ADDR() { return reinterpret_cast<PIN6_ADDR>(this); }
+
+    /**
+     * Size of this struct (SOCKADDR_IN) or (SOCKADDR_STORAGE) depending on address family
+     * @return size of this structure (SOCKADDR_IN) or (SOCKADDR_STORAGE)
+     */
+    size_t  Size() const { return (ss_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_storage); }
+
+    /**
+     * Initialize this object from SOCKADDR_IN struct.
+     * @param psin SOCKADDR_IN object pointer
+     */
+    void    SetAddr(const sockaddr_in* psin) { SetAddr(reinterpret_cast<const sockaddr_storage*>(psin)); }
+
+    /**
+     * Initialize this object from SOCKADDR_IN6 struct.
+     * @param psin SOCKADDR_IN6 object pointer
+     */
+    void    SetAddr(const sockaddr_in6* psin) { SetAddr(reinterpret_cast<const sockaddr_storage*>(psin)); }
+
+    /**
+     * Initialize this object from SOCKADDR_STORAGE struct.
+     * @param pss SOCKADDR_STORAGE object pointer
+     */
+    void    SetAddr(const sockaddr_storage* pss) { ss_family = pss->ss_family; memcpy(this, pss, Size()); }
+
+    static SockAddrIn NULLAddr;    ///< Null Address
+};
+
+#ifdef WIN32
+typedef LPWSAOVERLAPPED_COMPLETION_ROUTINE LPWSACOMPLETIONROUTINE;
+#endif
+
+#define SOCKET_SERVER_PORT				6432
+#define SOCKET_BUFFSIZE					1024 * 10  //注意, 这里单个包的大小不能超过该设置数值 
+
+/**
+ * CSocketHandle class
+ * Socket communication class
+ */
+class CSocketHandle
+{
+public:
+    /**
+     * Default constructor
+     */
+    CSocketHandle();
+
+    /**
+     * Destructor
+     */
+    ~CSocketHandle();
+
+    /**
+     * Check if socket is opened
+     * @return true if this is opened (valid)
+     */
+    bool IsOpen() const;
+
+    /**
+     * Get SOCKET handle
+     * @return SOCKET handle (handle is INVALID_SOCKET if object is closed)
+     */
+    SOCKET GetSocket() const;
+
+    /**
+     * Get SOCKET type
+     * @return SOCKET type (-1 if not a valid socket)
+     */
+    int GetSocketType() const;
+
+    /**
+     * Attach a socket handle
+     * This function may fail is socket handle is not valid or object already in used. Call Detach or Close to release object.
+     * @param sock Socket handle to attach to this class
+     * @return true if successful, otherwise false
+     */
+    bool Attach(SOCKET sock);
+
+    /**
+     * Detach a socket handle
+     * @return previous socket handle or INVALID_SOCKET
+     */
+    SOCKET Detach();
+
+    /**
+     * Create a Socket - Server side.
+     * @param pszHost hostname or IP address of adapter
+     * @param pszServiceName Network service name or port number
+     * @param nFamily address family to use (AF_INET, AF_INET6)
+     * @param nType type of socket to create (SOCK_STREAM, SOCK_DGRAM)
+     * @param uOptions Additional options (SO_BROADCAST, SO_REUSEADDR)
+     * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
+     * @sa InitLibrary, ConnectTo, IsOpen
+     */
+    bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
+
+    /**
+     * Create a socket, connect to a server - Client side.
+     * @param pszHostName Hostname or NIC address
+     * @param pszRemote Remote network address
+     * @param pszServiceName Network service name or port number
+     * @param nFamily address family to use (AF_INET, AF_INET6)
+     * @param nType type of socket to create (SOCK_STREAM, SOCK_DGRAM)
+     * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
+     * @sa InitLibrary, CreateSocket, IsOpen
+     */
+    bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType);
+
+    /**
+     * Close Socket
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen
+     */
+    void Close();
+
+    /**
+     * Read from socket
+     * @param lpBuffer Buffer to receive data
+     * @param dwSize Size of buffer in bytes
+     * @param lpAddrIn Peer address for UDP - this must be NULL for TCP
+     * @param dwTimeout Read timeout in milliseconds
+     * @return number of bytes read or (-1L) if fail
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, Write, WriteEx
+     */
+    DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE);
+
+#ifdef WIN32
+    /**
+     * Read from socket (asynchronous mode).
+     * @param lpBuffer Buffer to receive data
+     * @param dwSize Size of buffer in bytes
+     * @param lpAddrIn SockAddrIn for UDP - this must be NULL for TCP
+     * @param lpOverlapped Windows Overlapped structure (required)
+     * @param lpCompletionRoutine Winsock Completion routine (required)
+     * @return number of bytes read, overlapped operation is pending or (-1L) if fail
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, Write, WriteEx, IOControl, GetTransferOverlappedResult
+     */
+    DWORD ReadEx(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
+                LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine);
+#endif
+    /**
+     * Write to a destination socket
+     * @param lpBuffer Buffer to send
+     * @param dwCount Number of bytes to send
+     * @param lpAddrIn Peer address for UDP - this must be NULL for TCP
+     * @param dwTimeout Write timeout in milliseconds
+     * @return number of bytes sent or (-1L) if fail
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, WriteEx
+     */
+    DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE);
+
+#ifdef WIN32
+    /**
+     * Write to a destination socket (asynchronous mode).
+     * @param lpBuffer Buffer to send
+     * @param dwCount Number of bytes to send
+     * @param lpAddrIn SockAddrIn for UDP - this must be NULL for TCP
+     * @param lpOverlapped Windows Overlapped structure (required)
+     * @param lpCompletionRoutine Winsock Completion routine (required)
+     * @return number of bytes read, overlapped operation is pending or (-1L) if fail
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, Write, IOControl, GetTransferOverlappedResult
+     */
+    DWORD WriteEx(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn,
+                LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine);
+#endif
+
+#ifdef WIN32
+    /**
+     * Control the mode of a socket (asynchronous mode)
+     * @param dwIoCode Control code of operation to perform
+     * @param lpInBuffer Pointer to the input buffer
+     * @param cbInBuffer Size of the input buffer, in bytes
+     * @param lpOutBuffer Pointer to the output buffer
+     * @param cbOutBuffer Size of the output buffer, in bytes
+     * @param lpcbBytesReturned Pointer to actual number of bytes of output
+     * @param lpOverlapped Winsock Overlapped structure
+     * @param lpCompletionRoutine Winsock Completion routine
+     * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, GetTransferOverlappedResult
+     */
+    bool IOControl(DWORD dwIoCode, LPBYTE lpInBuffer, DWORD cbInBuffer,
+               LPBYTE lpOutBuffer, DWORD cbOutBuffer,
+               LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
+               LPWSACOMPLETIONROUTINE lpCompletionRoutine);
+
+    /**
+     * Get Overlapped result (asynchronous mode)
+     * @param lpOverlapped Windows Overlapped structure (required)
+     * @param lpcbTransfer Pointer to get number of bytes transferred
+     * @param bWait Force wait for overlapped operation to complete
+     * @param lpdwFlags Optional flags (see MSDN on WSARecv API)
+     * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, IOControl
+     */
+    bool GetTransferOverlappedResult(LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, bool bWait = true, LPDWORD lpdwFlags = 0);
+#endif
+
+    /**
+     * Get Socket name - get local address
+     * @param saddr_in current local address and port when connected
+     * @return true if successful
+     * @sa InitLibrary
+     */
+    bool GetSockName(SockAddrIn& saddr_in) const;
+
+    /**
+     * Get Peer Socket name - get peer address
+     * @param saddr_in peer address and port (use only with TCP or client mode UDP)
+     * @return true if successful
+     * @sa InitLibrary
+     */
+    bool GetPeerName(SockAddrIn& saddr_in) const;
+
+    /**
+     * Register to multicast address
+     * @param pszIPAddr multicast IP group
+     * @param pszNIC interface IP address
+     * @return true if successful
+     * @sa InitLibrary
+     */
+    bool AddMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC);
+
+    /**
+     * Unregister from a multicast address
+     * @param pszIPAddr multicast IP group
+     * @param pszNIC interface IP address
+     * @return true if successful
+     * @sa InitLibrary
+     */
+    bool DropMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC);
+
+    /**
+     * Initialize Winsock library. This function calls WSAStartup.
+     * @param wVersion Winsock version use MAKEWORD macro if possible (e.g.: MAKEWORD(2,2))
+     * @return true if successful
+     * @sa ReleaseLibrary
+     */
+    static bool InitLibrary(WORD wVersion);
+
+    /**
+     * Release Winsock library
+     * @return true if successful
+     * @sa InitLibrary
+     */
+    static bool ReleaseLibrary();
+
+    /**
+     * Wait for a new connection
+     * @param sock A TCP socket handle. A new socket is return returned.
+     * @return A new socket when a new client connects
+     * @sa GetSocket, CreateSocket
+     */
+    static SOCKET WaitForConnection(SOCKET sock);
+
+    /**
+     * Shutdown a connection
+     * @param sock Socket to shutdown communication
+     * @return true if successful
+     */
+    static bool ShutdownConnection(SOCKET sock);
+
+    /**
+     * Check if IP address is unicast (network order).
+     * @param ulAddr IP address (expected valid unicast address)
+     * @return true if successful
+     */
+    static bool IsUnicastIP( ULONG ulAddr );
+
+    /**
+     * Check if IP address is multicast (network order).
+     * @param ulAddr IP address (expected valid multicast address)
+     * @return true if successful
+     */
+    static bool IsMulticastIP( ULONG ulAddr );
+
+    /**
+     * Format IP address to string
+     * @param pszIPAddr Buffer to hold string
+     * @param nSize Size of buffer in characters
+     * @param ulAddr IP Address to format
+     * @param bFmtHost Specify if address (ulAddr) is in host (true) or network format (false)
+     * @return true if successful. Possible error could be INSUFFICIENT_BUFFER
+     */
+    static bool FormatIP(LPTSTR pszIPAddr, UINT nSize, ULONG ulAddr, bool bFmtHost);
+
+    /**
+     * Format IP address to string
+     * @param pszIPAddr Buffer to hold string
+     * @param nSize Size of buffer in characters
+     * @param addrIn IP Address to format
+     * @return true if successful. Possible error could be INSUFFICIENT_BUFFER
+     */
+    static bool FormatIP(LPTSTR pszIPAddr, UINT nSize, const SockAddrIn& addrIn);
+
+    /**
+     * Get service port number
+     * @param pszServiceName Network service name (e.g.: "ftp", "telnet") or port number
+     * @return port number
+     */
+    static USHORT GetPortNumber( LPCTSTR pszServiceName );
+
+    /**
+     * Get IP address of a host
+     * @param pszHostName host name or IP address
+     * @return Host IP address in host format
+     * @sa GetAddressInfo
+     */
+    static ULONG GetIPAddress( LPCTSTR pszHostName );
+
+    /**
+     * Get current localname for this machine
+     * @param pszName Buffer to receive host name
+     * @param nSize Size of this buffer in character
+     * @return true if successful
+     */
+    static bool GetLocalName(LPTSTR pszName, UINT nSize);
+
+    /**
+     * Get current (default) IP address for this machine
+     * @param pszAddress Buffer to receive IP address (IPv4, IPv6 format)
+     * @param nSize Size of this buffer in character
+     * @param nFamily address family to use (AF_INET, AF_INET6)
+     * @return true if successful
+     */
+    static bool GetLocalAddress(LPTSTR pszAddress, UINT nSize, int nFamily = AF_INET);
+
+    /**
+     * Get IP address info of a host (Supports: IPv4 and IPv6)
+     * @param pszHostName host name or IP address
+     * @param pszServiceName pszServiceName Network service name (e.g.: "ftp", "telnet") or port number
+     * @param nFamily address family to use (AF_INET, AF_INET6)
+     * @param sockAddr Socket address to fill in
+     * @return true if successful
+     */
+    static bool  GetAddressInfo( LPCTSTR pszHostName, LPCTSTR pszServiceName, int nFamily, SockAddrIn& sockAddr);
+
+// CSocketHandle - data
+protected:
+    SOCKET      m_hSocket;  ///< socket handle
+public:
+	char m_PendingBuffer[ SOCKET_BUFFSIZE ];
+    int m_nPendingSize;
+    CRITICAL_SECTION m_hClient2SrvSection;
+};
+
+/** @}*/
+
+#endif //SOCKETHANDLE_H

+ 1 - 1
SATHelper/SATHelper/UB530View.cpp

@@ -837,7 +837,7 @@ void CUB530View::CaptureImageThread(CUB530View* pView)
 		while (!pView->m_pBuffer)
 			pView->m_data_cond.wait(lk);
 #endif
-		//Global::WriteTextLogEx(1, "CaptureImageThread=%s", pView->m_CaptureInfo.szSaveDir);
+		Global::WriteTextLogEx(1, "CaptureImageThread=%s", pView->m_CaptureInfo.szSaveDir);
 		// 保存截图;
 		pView->SaveImageByCaptureInfo(pView->m_CaptureInfo);
 		// 标记保存完成;

BIN
SATHelper/SATHelper/res/probar.gif


+ 11 - 80
SATHelper/SATHelper/res/ribbon.mfcribbon-ms

@@ -47,13 +47,13 @@
                 </ID>
             </IMAGE_LARGE>
             <ELEMENTS>
-                <ELEMENT>
+				<ELEMENT>
                     <ELEMENT_NAME>Button</ELEMENT_NAME>
                     <ID>
-                        <NAME>ID_TRAYMENU_RECONNECT</NAME>
-                        <VALUE>32771</VALUE>
+                        <NAME>ID_TRAYMENU_LOGIN</NAME>
+                        <VALUE>32825</VALUE>
                     </ID>
-                    <TEXT>重连(&amp;C)</TEXT>
+                    <TEXT>登录(&amp;C)</TEXT>
                     <PALETTE_TOP>FALSE</PALETTE_TOP>
                     <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
                     <INDEX_SMALL>8</INDEX_SMALL>
@@ -64,90 +64,21 @@
                 <ELEMENT>
                     <ELEMENT_NAME>Button</ELEMENT_NAME>
                     <ID>
-                        <NAME>ID_FILE_PRINT</NAME>
-                        <VALUE>57607</VALUE>
+                        <NAME>ID_TRAYMENU_RECONNECT</NAME>
+                        <VALUE>32771</VALUE>
                     </ID>
-                    <TEXT>打印</TEXT>
-                    <KEYS>P</KEYS>
-                    <KEYS_MENU>W</KEYS_MENU>
+                    <TEXT>重连(&amp;C)</TEXT>
                     <PALETTE_TOP>FALSE</PALETTE_TOP>
                     <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                    <INDEX_SMALL>4</INDEX_SMALL>
-                    <INDEX_LARGE>4</INDEX_LARGE>
+                    <INDEX_SMALL>8</INDEX_SMALL>
+                    <INDEX_LARGE>8</INDEX_LARGE>
                     <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
                     <ALWAYS_DESCRIPTION>FALSE</ALWAYS_DESCRIPTION>
-                    <ELEMENTS>
-                        <ELEMENT>
-                            <ELEMENT_NAME>Label</ELEMENT_NAME>
-                            <TEXT>预览并打印文档</TEXT>
-                            <PALETTE_TOP>FALSE</PALETTE_TOP>
-                            <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                            <INDEX_SMALL>-1</INDEX_SMALL>
-                            <INDEX_LARGE>-1</INDEX_LARGE>
-                            <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
-                        </ELEMENT>
-                        <ELEMENT>
-                            <ELEMENT_NAME>Button</ELEMENT_NAME>
-                            <ID>
-                                <NAME>ID_FILE_PRINT_DIRECT</NAME>
-                                <VALUE>57608</VALUE>
-                            </ID>
-                            <TEXT>快速打印(&amp;Q)</TEXT>
-                            <PALETTE_TOP>FALSE</PALETTE_TOP>
-                            <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                            <INDEX_SMALL>5</INDEX_SMALL>
-                            <INDEX_LARGE>5</INDEX_LARGE>
-                            <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
-                            <ALWAYS_DESCRIPTION>TRUE</ALWAYS_DESCRIPTION>
-                        </ELEMENT>
-                        <ELEMENT>
-                            <ELEMENT_NAME>Button</ELEMENT_NAME>
-                            <ID>
-                                <NAME>ID_FILE_PRINT_PREVIEW</NAME>
-                                <VALUE>57609</VALUE>
-                            </ID>
-                            <TEXT>打印预览(&amp;V)</TEXT>
-                            <PALETTE_TOP>FALSE</PALETTE_TOP>
-                            <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                            <INDEX_SMALL>6</INDEX_SMALL>
-                            <INDEX_LARGE>6</INDEX_LARGE>
-                            <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
-                            <ALWAYS_DESCRIPTION>TRUE</ALWAYS_DESCRIPTION>
-                        </ELEMENT>
-                        <ELEMENT>
-                            <ELEMENT_NAME>Button</ELEMENT_NAME>
-                            <ID>
-                                <NAME>ID_FILE_PRINT_SETUP</NAME>
-                                <VALUE>57606</VALUE>
-                            </ID>
-                            <TEXT>打印设置(&amp;U)</TEXT>
-                            <PALETTE_TOP>FALSE</PALETTE_TOP>
-                            <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                            <INDEX_SMALL>7</INDEX_SMALL>
-                            <INDEX_LARGE>7</INDEX_LARGE>
-                            <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
-                            <ALWAYS_DESCRIPTION>TRUE</ALWAYS_DESCRIPTION>
-                        </ELEMENT>
-                    </ELEMENTS>
-                </ELEMENT>
+                </ELEMENT>           
                 <ELEMENT>
                     <ELEMENT_NAME>Separator</ELEMENT_NAME>
                     <HORIZ>TRUE</HORIZ>
-                </ELEMENT>
-                <ELEMENT>
-                    <ELEMENT_NAME>Button</ELEMENT_NAME>
-                    <ID>
-                        <NAME>ID_FILE_CLOSE</NAME>
-                        <VALUE>57602</VALUE>
-                    </ID>
-                    <TEXT>关闭(&amp;C)</TEXT>
-                    <PALETTE_TOP>FALSE</PALETTE_TOP>
-                    <ALWAYS_LARGE>FALSE</ALWAYS_LARGE>
-                    <INDEX_SMALL>8</INDEX_SMALL>
-                    <INDEX_LARGE>8</INDEX_LARGE>
-                    <DEFAULT_COMMAND>TRUE</DEFAULT_COMMAND>
-                    <ALWAYS_DESCRIPTION>FALSE</ALWAYS_DESCRIPTION>
-                </ELEMENT>
+                </ELEMENT>              
                 <ELEMENT>
                     <ELEMENT_NAME>Button_Main_Panel</ELEMENT_NAME>
                     <ID>

+ 9 - 3
SATHelper/SATHelper/resource.h

@@ -114,6 +114,9 @@
 #define IDB_UNCHECKED                   311
 #define DLG_DEVICEMANAGER               312
 #define DLG_UB530VIEW                   314
+#define IDD_DLG_LOGIN                   317
+#define IDD_DLG_PROBAR                  319
+#define GIF_PROBAR                      322
 #define IDC_COMBO1                      1000
 #define IDC_COMBO2                      1001
 #define IDC_CHECK1                      1002
@@ -121,6 +124,8 @@
 #define IDC_BUTTON1                     1004
 #define IDC_BUTTON2                     1005
 #define IDC_EDIT1                       1006
+#define IDC_EDIT_PASSWORD               1007
+#define IDC_EDIT_USERNAME               1008
 #define ID_WRITE_PASTEASHYPERLINK       32770
 #define ID_TRAYMENU_RECONNECT           32771
 #define ID_TRAYMENU_EXIT                32772
@@ -165,14 +170,15 @@
 #define ID_CHECK_IR_SHOT                32823
 #define ID_CHECK2                       32824
 #define ID_CHECK_WATCHTV                32824
+#define ID_TRAYMENU_LOGIN               32825
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        317
-#define _APS_NEXT_COMMAND_VALUE         32825
-#define _APS_NEXT_CONTROL_VALUE         1007
+#define _APS_NEXT_RESOURCE_VALUE        323
+#define _APS_NEXT_COMMAND_VALUE         32826
+#define _APS_NEXT_CONTROL_VALUE         1009
 #define _APS_NEXT_SYMED_VALUE           310
 #endif
 #endif