Browse Source

添加所在相关模块功能,待拼接逻辑

Jeff 3 years ago
parent
commit
5e771a7698

+ 2 - 4
Source/OGCAssistTool/OGCAssistTool/DlgLogin.cpp

@@ -99,6 +99,7 @@ HBRUSH CDlgLogin::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
 
 void CDlgLogin::OnBnClickedOk()
 {
+	return CDialogEx::OnOK();
 	// TODO: 在此添加控件通知处理程序代码
 	CString strAccount, strPassword, strLine;
 	GetDlgItemText(EDIT_LINE, strLine);
@@ -123,10 +124,7 @@ void CDlgLogin::OnBnClickedOk()
 		return;
 	}
 
-	GLOBAL::strLine = strLine.GetString();
-	GLOBAL::strAccount = strAccount.GetString();
-	GLOBAL::strPassword = strPassword.GetString();
-	GLOBAL::bOffline = ((CButton*)GetDlgItem(CHECK_OFFLINE))->GetCheck();
+	GLOBAL::g_config.nOffline = ((CButton*)GetDlgItem(CHECK_OFFLINE))->GetCheck();
 
 #pragma region 账号密码验证
 	// 获取账号密码;

+ 1061 - 0
Source/OGCAssistTool/OGCAssistTool/Global.cpp

@@ -0,0 +1,1061 @@
+#include "StdAfx.h"
+#include "Global.h"
+
+// 获取文件版本号函数头文件;
+#include <WinVer.h>		
+#pragma comment(lib,"version.lib")
+using namespace std;
+#include <psapi.h>
+#pragma comment(lib,"Psapi.lib")
+#include <locale.h>
+#include <io.h>//_access头文件;
+
+namespace GLOBAL
+{
+	CONFIG g_config;
+	TCHAR g_szModulePath[MAX_PATH] = _T("");			// 软件目录;
+	TCHAR g_szModuleFileName[MAX_PATH] = _T("");		// 软件名称;
+	TCHAR g_szConfigFile[MAX_PATH] = _T("");
+	PROC_WND_INFO g_procWndInfo;
+	BOOL g_bHijacted = FALSE;
+#define TRACE4(sz, p1, p2, p3, p4)  TRACE(_T(sz), p1, p2, p3, p4)
+
+	BOOL GetConfigInfo(LPCTSTR lpIniDir /* = NULL */, LPCTSTR lpConfigName /* = NULL */)
+	{
+		TCHAR szDrive[_MAX_DRIVE] = { 0 };
+		TCHAR szDir[_MAX_DIR] = { 0 };
+		TCHAR szFna[_MAX_DIR] = { 0 };
+		TCHAR szExt[_MAX_DIR] = { 0 };
+		::GetModuleFileName(NULL, g_szModulePath, sizeof(g_szModulePath) / sizeof(TCHAR));
+		_stprintf_s(g_szModuleFileName, _T("%s"), g_szModulePath);
+
+		_tsplitpath_s(g_szModulePath, szDrive, szDir, szFna, szExt);
+		_tcscpy_s(g_szModulePath, szDrive);
+		_tcscat_s(g_szModulePath, szDir);
+
+		if (lpIniDir != NULL && lpConfigName != NULL)
+			_stprintf_s(g_szConfigFile, _T("%s%s"), lpIniDir, lpConfigName);
+		else
+			_stprintf_s(g_szConfigFile, _T("%s%s.ini"), g_szModulePath, szFna);
+
+		HANDLE hFile = CreateFile(g_szConfigFile, 0/*GENERIC_READ*/, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+		if (ERROR_FILE_NOT_FOUND == GetLastError())
+		{
+			return FALSE;
+		}
+
+		CloseHandle(hFile);
+		hFile = NULL;
+
+#pragma region 获取配置文件信息;
+		TCHAR szValue[MAX_PATH] = {0};
+		// LOGIN;
+		GetPrivateProfileString(_T("LOGIN"), _T("account"), _T(""), g_config.szAccount, MAX_PATH, g_szConfigFile);
+		GetPrivateProfileString(_T("LOGIN"), _T("password"), _T(""), g_config.szPassword, MAX_PATH, g_szConfigFile);
+		GetPrivateProfileString(_T("LOGIN"), _T("line"), _T(""), g_config.szLine, MAX_PATH, g_szConfigFile);
+		g_config.nOffline = GetPrivateProfileInt(_T("LOGIN"), _T("offline"), 0, g_szConfigFile);
+		// SYSTEM;
+		g_config.nStdOut = GetPrivateProfileInt(_T("SYSTEM"), _T("stdprint"), 0, g_szConfigFile);
+		GetPrivateProfileString(_T("SYSTEM"), _T("OGCTool"), _T(""), g_config.szOGCToolProgram, MAX_PATH, g_szConfigFile);
+		// BATCH;
+		g_config.nDeltaEType = GetPrivateProfileInt(_T("BATCH"), _T("EType"), 0, g_szConfigFile);
+		GetPrivateProfileString(_T("BATCH"), _T("EValue"), _T(""), szValue, MAX_PATH, g_szConfigFile);
+		g_config.dDeltaEValue = _tstof(szValue);
+		GetPrivateProfileString(_T("BATCH"), _T("batchNumber"), _T(""), g_config.szBatchNumber, MAX_PATH, g_szConfigFile);
+#pragma endregion
+
+		if ( g_config.nStdOut ) {
+			AllocConsole();                             // 开辟控制台;
+			SetConsoleTitle(_T("调试输出"));			// 设置控制台窗口标题;
+			freopen("CONOUT$", "w+t", stdout);			// 重定向输出;
+			freopen("CONIN$", "r+t", stdin);			// 重定向输入;
+
+			HWND hWnd = NULL;
+again:
+			hWnd = ::FindWindow(NULL, _T("调试输出"));
+			if( hWnd ) {
+				if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE)) {
+					_tprintf_s(_T("前置设置失败\n"));
+				} else {
+					_tprintf_s(_T("前置设置成功\n"));
+				}
+			} else {
+				goto again;
+			}
+		}
+
+		return TRUE;
+	}
+
+	DWORD FindProcess(LPCTSTR lpProName)
+	{
+		ASSERT(lpProName!=NULL);
+
+		DWORD dwProcId = 0;
+		PROCESSENTRY32 pe32 = { 0 };
+
+		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+		if (hSnapshot == NULL)
+		{
+			return 0;
+		}
+		pe32.dwSize = sizeof(PROCESSENTRY32);
+
+		if (Process32First(hSnapshot, &pe32))
+		{
+			do {
+				if (_tcsicmp(lpProName, pe32.szExeFile) == 0)
+				{
+					dwProcId = pe32.th32ProcessID;
+					break;
+				}
+			} while (Process32Next(hSnapshot, &pe32));
+		}
+		CloseHandle(hSnapshot);
+
+		return dwProcId;
+	}
+
+	vector<DWORD> FindAllProcess(LPCTSTR lpProName)
+	{
+		ASSERT(lpProName!=NULL);
+
+		vector<DWORD> vtPID;
+		PROCESSENTRY32 pe32 = { 0 };
+
+		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+		if (hSnapshot == NULL)
+			return vector<DWORD>();
+
+		pe32.dwSize = sizeof(PROCESSENTRY32);
+		if (Process32First(hSnapshot, &pe32))
+		{
+			do {
+				if (_tcsicmp(lpProName, pe32.szExeFile) == 0)
+				{
+					vtPID.push_back(pe32.th32ProcessID);
+				}
+			} while (Process32Next(hSnapshot, &pe32));
+		}
+		CloseHandle(hSnapshot);
+
+		return vtPID;
+	}
+
+	void FindAllProcess(std::vector<PROC_INFO> &vtProInfo)
+	{
+		PROCESSENTRY32 pe32 = { 0 };
+		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+		if (hSnapshot == NULL)
+			return;
+
+		pe32.dwSize = sizeof(PROCESSENTRY32);
+		if (!Process32First(hSnapshot, &pe32))
+			goto end;
+
+		do 
+		{
+			PROC_INFO proinfo;
+			proinfo.dwProcId = pe32.th32ProcessID;
+			proinfo.strProcName = pe32.szExeFile;
+			vtProInfo.push_back(proinfo);
+		} while (Process32Next(hSnapshot, &pe32));
+
+end:
+		CloseHandle(hSnapshot);
+	}
+
+	HANDLE FindModule(LPCTSTR lpModuleName, DWORD dwProcId)
+	{
+		ASSERT(lpModuleName!=NULL);
+
+		DWORD dwMID = 0;
+		MODULEENTRY32 me32 = { 0 };
+		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, dwProcId);
+		if (hSnapshot == NULL)
+			return NULL;
+
+		me32.dwSize = sizeof(MODULEENTRY32);
+		if (Module32First(hSnapshot, &me32))
+		{
+			do {
+				if (_tcsicmp(lpModuleName, me32.szModule) == 0)
+				{
+					break;
+				}
+			} while (Module32Next(hSnapshot, &me32));
+		}
+		CloseHandle(hSnapshot);
+
+		return me32.hModule;
+	}
+
+	LPCTSTR GetModulePath(LPCTSTR lpModuleName, DWORD dwProcId)
+	{
+		ASSERT(lpModuleName!=NULL);
+
+		DWORD dwMID = 0;
+		MODULEENTRY32 me32 = { 0 };
+		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, dwProcId);
+		if (hSnapshot == NULL)
+			return NULL;
+
+		me32.dwSize = sizeof(MODULEENTRY32);
+		if (Module32First(hSnapshot, &me32))
+		{
+			do {
+				if (_tcsicmp(lpModuleName, me32.szModule) == 0)
+				{
+					break;
+				}
+			} while (Module32Next(hSnapshot, &me32));
+		}
+		CloseHandle(hSnapshot);
+
+		return me32.szExePath;
+	}
+
+	HANDLE FindModuleEx(LPCTSTR lpModuleName, DWORD dwProcId)
+	{
+		HMODULE hMods[1024] = {0};
+		DWORD cbNeeded = 0;
+		TCHAR szModName[MAX_PATH];
+		BOOL Wow64Process;
+
+		HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId);
+		IsWow64Process(hProcess, &Wow64Process); //判断是32位还是64位进程
+		if ( EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, Wow64Process?LIST_MODULES_32BIT:LIST_MODULES_64BIT) )
+		{
+			for (UINT i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
+			{
+				GetModuleFileNameEx(hProcess, hMods[i], szModName, _countof(szModName));
+#ifdef _DEBUG
+				WriteTextLog(_T("目标=%s, 原始=%s, 地址=%p"), szModName, lpModuleName, hMods[i]);
+#endif
+				if (_tcsicmp(lpModuleName, szModName) == 0)
+				{
+					CloseHandle(hProcess);
+					WriteTextLog(_T("【目标=%s, 原始=%s, 地址=%p】"), szModName, lpModuleName, hMods[i]);
+					return hMods[i];
+				}
+			}
+		}
+
+		CloseHandle(hProcess);
+
+		return NULL;
+	}
+
+	// WINDOWS NT 以上的内核需要提权,才能对系统进行高级管理;
+	BOOL GetDebugPriv()
+	{
+		// 返回的访问令牌指针;
+		HANDLE	hToken;
+		// 接收所返回的制定特权名称的信息;
+		LUID	sedebugnameValue;
+		// 新特权信息的指针(结构体);
+		TOKEN_PRIVILEGES tkp;
+		//DWORD	dwCurProcId = GetCurrentProcessId();
+		// 要修改访问权限的进程句柄;
+		HANDLE	hCurProc = ::GetCurrentProcess();
+		//hCurProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwCurProcId);
+
+		if (!::OpenProcessToken(hCurProc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+		{
+			return FALSE;
+		}
+
+		if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
+		{
+			CloseHandle(hToken);
+			return FALSE;
+		}
+
+		tkp.PrivilegeCount = 1;
+		tkp.Privileges[0].Luid = sedebugnameValue;
+		tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+		if (!::AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
+		{
+			CloseHandle(hToken);
+			return FALSE;
+		}
+
+		CloseHandle(hCurProc);
+		CloseHandle(hToken);
+		return TRUE;
+	}
+
+	/************************************************************************/
+	/* 
+	函数:GetFileVersion
+	描述:获取可执行文件的文件版号;
+	参数:
+	hModule[IN]		可执行文件模块句柄;
+	dwArray[OUT]	返回的文件版本号;
+	返回:
+	成功返回TRUE,失败返回FALSE;
+	注意:
+	当hModule为空时,表示要获取的可执行文件为本程序的文件版本号;
+	*/
+	/************************************************************************/
+	BOOL GetFileVersion( IN HMODULE hModule, OUT DWORD (&dwArray)[4])
+	{
+		TCHAR fname[MAX_PATH];
+		VS_FIXEDFILEINFO *pVi;
+		DWORD dwHandle;
+
+		if ( GetModuleFileName(hModule, fname, MAX_PATH))
+		{
+			INT nSize = GetFileVersionInfoSize(fname, &dwHandle);
+
+			if (nSize > 0)
+			{
+				BYTE *pBuffer = new BYTE[nSize];
+				memset(pBuffer, 0, nSize);
+
+				if (GetFileVersionInfo(fname, dwHandle, nSize, pBuffer))
+				{
+					if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
+					{
+						dwArray[0] = HIWORD(pVi->dwFileVersionMS);
+						dwArray[1] = LOWORD(pVi->dwFileVersionMS);
+						dwArray[2] = HIWORD(pVi->dwFileVersionLS);
+						dwArray[3] = LOWORD(pVi->dwFileVersionLS);
+
+						delete[]pBuffer;
+						return TRUE;
+					}
+				}
+
+				if ( pBuffer )
+					delete[]pBuffer;
+			}
+		}
+
+		return FALSE;
+	}
+
+	/************************************************************************/
+	/* 
+	函数:GetFileVersion
+	描述:获取可执行文件的文件版号;
+	参数:
+	lpFileName[IN]	可执行文件名全路径;
+	dwArray[OUT]	返回的文件版本号;
+	返回:
+	成功返回TRUE,失败返回FALSE;
+	注意:
+	*/
+	/************************************************************************/
+	BOOL GetFileVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] )
+	{
+		if ( lpFileName == NULL || !PathFileExists(lpFileName) )
+		{
+			OutputDebugString(_T("文件名错误或文件不存在\n"));
+			return FALSE;
+		}
+
+		DWORD dwHandle = 0;
+		VS_FIXEDFILEINFO *pVi = NULL;
+		INT nSize = GetFileVersionInfoSize(lpFileName, &dwHandle);
+		if ( nSize > 0 )
+		{
+			BYTE *pBuffer = new BYTE[nSize];
+			memset(pBuffer, 0, nSize);
+
+			if ( GetFileVersionInfo(lpFileName, dwHandle, nSize, pBuffer) )
+			{
+				if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
+				{
+					dwArray[0] = HIWORD(pVi->dwFileVersionMS);
+					dwArray[1] = LOWORD(pVi->dwFileVersionMS);
+					dwArray[2] = HIWORD(pVi->dwFileVersionLS);
+					dwArray[3] = LOWORD(pVi->dwFileVersionLS);
+
+					if (pBuffer)
+						delete[]pBuffer;
+					return TRUE;
+				}
+			}
+
+			if (pBuffer)
+				delete[]pBuffer;
+		}
+
+		return FALSE;
+	}
+
+	/************************************************************************/
+	/* 
+	函数:GetProductVersion
+	描述:获取可执行文件的产品版号;
+	参数:
+	hModule[IN]		可执行文件模块句柄;
+	dwArray[OUT]	返回的产品版本号;
+	返回:
+	成功返回TRUE,失败返回FALSE;
+	注意:
+	当hModule为空时,表示要获取的可执行文件为本程序的产品版本号;
+	*/
+	/************************************************************************/
+	BOOL GetProductVersion(IN HMODULE hModule, IN DWORD (&dwArray)[4] )
+	{
+		TCHAR fname[MAX_PATH];
+		VS_FIXEDFILEINFO *pVi;
+		DWORD dwHandle;
+
+		if (::GetModuleFileName(hModule, fname, MAX_PATH))
+		{
+			INT nSize = GetFileVersionInfoSize(fname, &dwHandle);
+
+			if (nSize > 0)
+			{
+				BYTE *pBuffer = new BYTE[nSize];
+				memset(pBuffer, 0, nSize);
+
+				if (GetFileVersionInfo(fname, dwHandle, nSize, pBuffer))
+				{
+					if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
+					{
+						dwArray[0] = HIWORD(pVi->dwProductVersionMS);
+						dwArray[1] = LOWORD(pVi->dwProductVersionMS);
+						dwArray[2] = HIWORD(pVi->dwProductVersionLS);
+						dwArray[3] = LOWORD(pVi->dwProductVersionLS);
+
+						if(pBuffer)
+							delete[]pBuffer;
+						return TRUE;
+					}
+				}
+				if(pBuffer)
+					delete[]pBuffer;
+			}
+		}
+
+		return FALSE;
+	}
+
+	/************************************************************************/
+	/* 
+	函数:GetProductVersion
+	描述:获取可执行文件的产品版号;
+	参数:
+	lpFileName[IN]	可执行文件名全路径;
+	dwArray[OUT]	返回的产品版本号;
+	返回:
+	成功返回TRUE,失败返回FALSE;
+	注意:
+	*/
+	/************************************************************************/
+	BOOL GetProductVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] )
+	{
+		if ( lpFileName == NULL || !PathFileExists(lpFileName) )
+		{
+			OutputDebugString(_T("文件名错误或文件不存在\n"));
+			return FALSE;
+		}
+
+		DWORD dwHandle = 0;
+		VS_FIXEDFILEINFO *pVi = NULL;
+		INT nSize = GetFileVersionInfoSize(lpFileName, &dwHandle);
+		if ( nSize > 0 )
+		{
+			BYTE *pBuffer = new BYTE[nSize];
+			memset(pBuffer, 0, nSize);
+
+			if ( GetFileVersionInfo(lpFileName, dwHandle, nSize, pBuffer) )
+			{
+				if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
+				{
+					dwArray[0] = HIWORD(pVi->dwProductVersionMS);
+					dwArray[1] = LOWORD(pVi->dwProductVersionMS);
+					dwArray[2] = HIWORD(pVi->dwProductVersionLS);
+					dwArray[3] = LOWORD(pVi->dwProductVersionLS);
+
+					if (pBuffer)
+						delete[]pBuffer;
+					return TRUE;
+				}
+			}
+
+			if (pBuffer)
+				delete[]pBuffer;
+		}
+
+		return FALSE;
+	}
+
+	/************************************************************************/
+	/*  函数:WriteTextLog[7/28/2016 IT];
+	/*  描述:写文本日志;
+	/*  参数:;
+	/*  	[IN] :;
+	/*  返回:void;
+	/*  注意:;
+	/*  示例:;
+	/*
+	/*  修改:;
+	/*  日期:;
+	/*  内容:;
+	/************************************************************************/
+	void WriteTextLog(const TCHAR *format, ...)
+	{
+#if 0
+		try
+		{
+			//static ThreadSection _critSection;
+			//AutoThreadSection aSection(&_critSection);
+			// 解析出日志路径;
+			TCHAR szlogpath[MAX_PATH] = {0};
+			static TCHAR szModulePath[MAX_PATH] = {0};
+			static TCHAR szFna[_MAX_DIR] = { 0 };
+			if ( szModulePath[0] == _T('\0') )
+			{
+				TCHAR szDrive[_MAX_DRIVE] = { 0 };
+				TCHAR szDir[_MAX_DIR] = { 0 };
+				TCHAR szExt[_MAX_DIR] = { 0 };
+				::GetModuleFileName(NULL, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
+				_tsplitpath_s(szModulePath, szDrive, szDir, szFna, szExt);
+				_tcscpy_s(szModulePath, szDrive);
+				_tcscat_s(szModulePath, szDir);
+			}
+
+			_stprintf_s(szlogpath, _T("%s日志\\%s%s.txt"), szModulePath, szFna, CTime::GetCurrentTime().Format("[%Y-%m-%d]"));
+
+			// 打开或创建文件;
+			CStdioFile fp;
+			if (PathFileExists(szlogpath))
+			{
+				if (fp.Open(szlogpath, CFile::modeWrite) == FALSE)
+				{
+					return;
+				}
+				fp.SeekToEnd();
+			}
+			else
+			{
+				fp.Open(szlogpath, CFile::modeCreate | CFile::modeWrite);
+			}
+
+			// 格式化前设置语言区域;
+			TCHAR* old_locale = _tcsdup(_tsetlocale(LC_CTYPE, NULL));
+			_tsetlocale(LC_CTYPE, _T("chs"));//设定中文;
+
+			// 格式化日志内容;
+			va_list		args = NULL;
+			int			len = 0;
+			TCHAR		*buffer = NULL;
+			va_start( args, format );
+			// _vscprintf doesn't count. terminating '\0'
+			len = _vsctprintf( format, args )  + 1;
+			buffer = (TCHAR*)malloc( len * sizeof(TCHAR) );
+			_vstprintf_s( buffer, len, format, args ); // C4996
+			// Note: vsprintf is deprecated; consider using vsprintf_s instead
+
+			// 将日志内容输入到文件中;
+			fp.WriteString( CTime::GetCurrentTime().Format(_T("%Y-%m-%d %H:%M:%S ")) );
+			fp.WriteString(buffer);
+			fp.WriteString(_T("\n"));
+
+			// 关闭文件,释放资源并设置回原语言区域;
+			free( buffer );
+			_tsetlocale(LC_CTYPE, old_locale);
+			free(old_locale);//还原区域设定;
+			fp.Close();
+		}
+		catch (CException *e)
+		{
+			e->ReportError();
+			e->Delete();
+		}
+#else
+		// 解析出日志路径;
+		TCHAR szlogpath[MAX_PATH] = { 0 };
+		static TCHAR szModulePath[MAX_PATH] = { 0 };
+		static TCHAR szFna[MAX_PATH] = { 0 };
+		if (szModulePath[0] == _T('\0'))
+		{
+			TCHAR szDrive[MAX_PATH] = { 0 };
+			TCHAR szDir[MAX_PATH] = { 0 };
+			TCHAR szExt[MAX_PATH] = { 0 };
+			::GetModuleFileName(NULL, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
+			_tsplitpath_s(szModulePath, szDrive, szDir, szFna, szExt);
+			_tcscpy_s(szModulePath, szDrive);
+			_tcscat_s(szModulePath, szDir);
+		}
+
+		_stprintf_s(szlogpath, _T("%s%s.txt"), szModulePath, szFna);
+		// 打开或创建文件;
+		FILE *fp = NULL;
+		//if (_taccess(szlogpath, 0) != -1)
+#ifndef UNICODE
+		if (_access(szlogpath, 0) != -1)
+#else
+		if (_taccess(szlogpath, 0) != -1)
+#endif
+		{// 存在;
+			fp = _tfopen(szlogpath, _T("a+"));
+			// 移动到末尾;
+			fseek(fp, 0, SEEK_END);
+		}
+		else
+		{// 不存在;
+			fp = _tfopen(szlogpath, _T("w+"));
+		}
+
+		if (fp == NULL)
+			return;
+
+		// 格式化前设置语言区域;
+		TCHAR* old_locale = _tcsdup(_tsetlocale(LC_CTYPE, NULL));
+		_tsetlocale(LC_CTYPE, _T("chs"));//设定中文;
+
+		// 格式化日志内容;
+		va_list		args = NULL;
+		int			len = 0;
+		TCHAR		*buffer = NULL;
+		va_start(args, format);
+		// _vscprintf doesn't count. terminating '\0'
+		len = _vsctprintf(format, args) + 1;
+		buffer = (TCHAR*)malloc(len * sizeof(TCHAR));
+		_vstprintf_s(buffer, len, format, args);
+		// 将日志内容输入到文件中;
+		// 获取今年年份;
+		__time64_t gmt = time(NULL);// 获取当前日历时间(1900-01-01开始的Unix时间戳);
+		struct tm gmtm = { 0 };
+		localtime_s(&gmtm, &gmt); // 时间戳转成本地时间;
+		_ftprintf(fp, _T("%04d-%02d-%02d %02d:%02d:%02d %s\n"), gmtm.tm_year + 1990, gmtm.tm_mon + 1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec, buffer);
+
+		// 关闭文件,释放资源并设置回原语言区域;
+		free(buffer);
+		fclose(fp);
+		_tsetlocale(LC_CTYPE, old_locale);
+		free(old_locale);//还原区域设定;
+#endif
+	}
+
+
+	//---------------------------------------------------------------------
+	// add by Jeff 2014.10.27
+	// 函数:全局函数IsDirectoryLegitimate,多字节版本,非UNICODE
+	// 描述:判断一个目录路径字符串,是否属于合法的、可创建的目录路径。
+	// 参数:strDirectory 被验证的路径字符串;
+	//		
+	// 返回:合法路径返回TRUE;
+	//---------------------------------------------------------------------
+	BOOL IsDirectoryLegitimate(const CString &strDirectory)
+	{
+		if (strDirectory.Find('/') != -1 ||
+			strDirectory.Find('\\') != -1 ||
+			strDirectory.Find(':') != -1 ||
+			strDirectory.Find('*') != -1 ||
+			strDirectory.Find('?') != -1 ||
+			strDirectory.Find('\"') != -1 ||
+			strDirectory.Find('>') != -1 ||
+			strDirectory.Find('<') != -1 ||
+			strDirectory.Find('|') != -1
+			)
+			return FALSE;
+
+		return TRUE;
+	}
+
+
+	//--------------------------------------------------------------------------------
+	// Jeff add 2014.06.23;
+	// 函数:ErrorExit
+	// 描述:
+	// 参数:
+	//     lpszFunction:函数名;
+	//     dwError:错误码; 
+	//
+	//--------------------------------------------------------------------------------
+	void ShowSystemErrorInfo(CString strDescription, const DWORD &dwError)
+	{
+#if 1
+		LPVOID lpMsgBuf;
+
+		BOOL fOk = FormatMessage(
+			FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			FORMAT_MESSAGE_FROM_SYSTEM |
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			dwError,
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+			(LPTSTR)&lpMsgBuf,
+			0, NULL);
+
+		if (!fOk)
+		{
+			// Is it a network-related error?
+			HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
+
+			if (hDll != NULL)
+			{
+				FormatMessage(
+					FORMAT_MESSAGE_FROM_HMODULE |
+					FORMAT_MESSAGE_FROM_SYSTEM |
+					FORMAT_MESSAGE_IGNORE_INSERTS,
+					hDll,
+					dwError,
+					MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+					(LPTSTR)&lpMsgBuf,
+					0,
+					NULL);
+
+				FreeLibrary(hDll);
+			}
+		}
+
+		if (lpMsgBuf != NULL)
+		{
+			CString strDisplay;
+			strDisplay.Format(_T("%s.错误码=%d,Windows描述:%s"), strDescription, dwError, (PCTSTR)LocalLock(lpMsgBuf));
+			//WriteLog(strDisplay);
+			LocalFree(lpMsgBuf);
+		}
+		else
+		{
+			//WriteLog(strDescription);
+		}
+#else
+		HLOCAL hlocal = NULL;   // Buffer that gets the error message string
+
+		// Get the error code's textual description
+		BOOL fOk = FormatMessage(
+			FORMAT_MESSAGE_FROM_SYSTEM |
+			FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			dwError,
+			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+			(PTSTR)&hlocal,
+			0,
+			NULL);
+
+		if (!fOk)
+		{
+			// Is it a network-related error?
+			HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
+
+			if (hDll != NULL)
+			{
+				FormatMessage(
+					FORMAT_MESSAGE_FROM_HMODULE |
+					FORMAT_MESSAGE_FROM_SYSTEM |
+					FORMAT_MESSAGE_IGNORE_INSERTS,
+					hDll,
+					dwError,
+					MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+					(PTSTR)&hlocal,
+					0,
+					NULL);
+				FreeLibrary(hDll);
+			}
+		}
+
+		if (hlocal != NULL)
+		{
+			CString strDisplay;
+			strDisplay.Format("%s 失败错误码=%d,Windows系统描述:%s", strDescription, dwError, (PCTSTR)LocalLock(hlocal));
+			//WriteLog(strDisplay);
+			LocalFree(hlocal);
+		}
+		else
+		{
+			//WriteLog("Error number not found.");
+		}
+#endif
+
+	}
+
+	// The system displays a dialog box with a custom message and a message to the user to close applications within the specified time-out interval (30 seconds). 
+	// After the time-out interval elapses, the system is restarted.
+	//The application must enable the SE_SHUTDOWN_NAME privilege before calling InitiateSystemShutdown
+	BOOL MySystemShutdown(LPTSTR lpMsg)
+	{
+		HANDLE hToken;              // handle to process token 
+		TOKEN_PRIVILEGES tkp;       // pointer to token structure 
+
+		BOOL fResult;               // system shutdown flag 
+
+		// Get the current process token handle so we can get shutdown 
+		// privilege. 
+
+		if (!OpenProcessToken(GetCurrentProcess(),
+			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+			return FALSE;
+
+		// Get the LUID for shutdown privilege. 
+
+		LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
+			&tkp.Privileges[0].Luid);
+
+		tkp.PrivilegeCount = 1;  // one privilege to set    
+		tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+		// Get shutdown privilege for this process. 
+
+		AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
+			(PTOKEN_PRIVILEGES)NULL, 0);
+
+		// Cannot test the return value of AdjustTokenPrivileges. 
+
+		if (GetLastError() != ERROR_SUCCESS)
+			return FALSE;
+
+		// Display the shutdown dialog box and start the countdown. 
+
+		fResult = InitiateSystemShutdown(
+			NULL,    // shut down local computer 
+			lpMsg,   // message for user
+			30,      // time-out period, in seconds 
+			FALSE,   // ask user to close apps 
+			TRUE);   // reboot after shutdown 
+
+		if (!fResult)
+			return FALSE;
+
+		// Disable shutdown privilege. 
+
+		tkp.Privileges[0].Attributes = 0;
+		AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
+			(PTOKEN_PRIVILEGES)NULL, 0);
+
+		return TRUE;
+	}
+
+	// If the AbortSystemShutdown function is executed in the time-out period specified by InitiateSystemShutdown, 
+	// the system does not shut down. For example, if PreventSystemShutdown is called after MySystemShutdown, 
+	// the system closes the dialog box and does not restart the system.
+	BOOL PreventSystemShutdown()
+	{
+		HANDLE hToken;              // handle to process token 
+		TOKEN_PRIVILEGES tkp;       // pointer to token structure 
+
+		// Get the current process token handle  so we can get shutdown 
+		// privilege. 
+
+		if (!OpenProcessToken(GetCurrentProcess(),
+			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+			return FALSE;
+
+		// Get the LUID for shutdown privilege. 
+
+		LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
+			&tkp.Privileges[0].Luid);
+
+		tkp.PrivilegeCount = 1;  // one privilege to set    
+		tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+		// Get shutdown privilege for this process. 
+
+		AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
+			(PTOKEN_PRIVILEGES)NULL, 0);
+
+		if (GetLastError() != ERROR_SUCCESS)
+			return FALSE;
+
+		// Prevent the system from shutting down. 
+
+		if (!AbortSystemShutdown(NULL))
+			return FALSE;
+
+		// Disable shutdown privilege. 
+
+		tkp.Privileges[0].Attributes = 0;
+		AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
+			(PTOKEN_PRIVILEGES)NULL, 0);
+
+		return TRUE;
+	}
+
+	// Shutting down flushes file buffers to disk and brings the system to a condition in which it is safe to turn off the computer
+	// The application must first enable the SE_SHUTDOWN_NAME privilege. 
+	// The final parameter in the call to ExitWindowsEx indicates that the system was shut down for a planning update of the operating system.
+	BOOL MySystemShutdown()
+	{
+		HANDLE hToken;
+		TOKEN_PRIVILEGES tkp;
+
+		// Get a token for this process. 
+
+		if (!OpenProcessToken(GetCurrentProcess(),
+			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+			return(FALSE);
+
+		// Get the LUID for the shutdown privilege. 
+
+		LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
+			&tkp.Privileges[0].Luid);
+
+		tkp.PrivilegeCount = 1;  // one privilege to set    
+		tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+		// Get the shutdown privilege for this process. 
+
+		AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
+			(PTOKEN_PRIVILEGES)NULL, 0);
+
+		if (GetLastError() != ERROR_SUCCESS)
+			return FALSE;
+
+		// Shut down the system and force all applications to close. 
+
+		if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE,
+			SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
+			SHTDN_REASON_MINOR_UPGRADE |
+			SHTDN_REASON_FLAG_PLANNED))
+			return FALSE;
+
+		return TRUE;
+	}
+
+	HWND GetProcessMainWnd(const DWORD& dwTagetProcessId, LPCTSTR lpTagetWndName)
+	{
+		DWORD dwCurPorcessId = 0;
+		HWND hTagetProcessWnd = NULL;
+		TCHAR szWndName[MAX_PATH] = { 0 };
+		TCHAR szClassName[MAX_PATH] = { 0 };
+
+		// 取得第一个窗口句柄;
+		for (HWND hCurWnd = ::GetTopWindow(NULL); hCurWnd != NULL; hCurWnd = ::GetNextWindow(hCurWnd, GW_HWNDNEXT)) {
+			// 重置为0;
+			dwCurPorcessId = 0;
+			// 通过窗口句柄反查进程pid;
+			DWORD dwThreadId = ::GetWindowThreadProcessId(hCurWnd, &dwCurPorcessId);
+			if (dwThreadId != 0) {
+				// 判断当前进程id是否和目标进程id相同;
+				if (dwCurPorcessId == dwTagetProcessId) {
+					if (lpTagetWndName == NULL) {
+						hTagetProcessWnd = hCurWnd;
+						break;
+					}
+					else {
+						// 获取窗口名称;
+						::GetWindowText(hCurWnd, szWndName, sizeof(szWndName) / sizeof(TCHAR));
+						// 获取窗口类名;
+						::GetClassName(hCurWnd, szClassName, sizeof(szClassName) / sizeof(TCHAR));
+#ifdef _DEBUG
+						TCHAR szLogMsg[MAX_PATH] = { 0 };
+						_stprintf_s(szLogMsg, _T("类名:%s, 窗口名:%s,窗口地址:%p \n"), szClassName, szWndName, hCurWnd);
+						OutputDebugString(szLogMsg);
+#endif
+						if (_tcsstr(szWndName, lpTagetWndName) != NULL) {
+							hTagetProcessWnd = hCurWnd;
+							break;
+						}
+					}
+				}
+			}
+		}
+
+		// 当前窗口有可能不是进程父窗口;
+		HWND hParentWnd = hTagetProcessWnd;
+		while (hParentWnd) {
+			hParentWnd = ::GetParent(hTagetProcessWnd);
+			if (hParentWnd == NULL)
+				break;
+			hTagetProcessWnd = hParentWnd;
+		}
+
+		return hTagetProcessWnd;
+	}
+
+	BOOL CALLBACK EnumChildWindowCallBack(HWND hWnd, LPARAM lParam)  
+	{  
+		DWORD dwPid = 0;  
+		LPPROC_WND_INFO lpWndData = (LPPROC_WND_INFO)lParam;
+		GetWindowThreadProcessId(hWnd, &dwPid); // 获得找到窗口所属的进程  
+		if(dwPid == lpWndData->dwProcId) // 判断是否是目标进程的窗口  
+		{  
+			WND_INFO wndInfo;
+			wndInfo.hWnd=hWnd;
+			SendMessage(hWnd, WM_GETTEXT, MAX_PATH, (LPARAM)wndInfo.szWndTitle);  
+			GetClassName(hWnd, wndInfo.szClassName, MAX_PATH);
+			wndInfo.dwCtrlId = ::GetDlgCtrlID(hWnd);
+			lpWndData->AddWnd(wndInfo);
+			// 输出窗口信息  
+			TRACE4("A-0x%08X, %ld, %s, %s\n", hWnd, wndInfo.dwCtrlId, wndInfo.szClassName, wndInfo.szWndTitle);  
+			// 此处如果再递归,会导致重复查找2次子窗口;
+			//EnumChildWindows(hWnd, EnumChildWindowCallBack, lParam);    // 递归查找子窗口 
+			return TRUE;
+		}  
+
+		return FALSE;  
+	}  
+
+	BOOL CALLBACK EnumWindowCallBack(HWND hWnd, LPARAM lParam)  
+	{  
+		DWORD dwPid = 0; 
+		LPPROC_WND_INFO lpWndData = (LPPROC_WND_INFO)lParam;
+		GetWindowThreadProcessId(hWnd, &dwPid); // 获得找到窗口所属的进程  
+		if(dwPid == lpWndData->dwProcId) // 判断是否是目标进程的窗口  
+		{  
+			WND_INFO wndInfo;
+			wndInfo.hWnd=hWnd;
+			SendMessage(hWnd, WM_GETTEXT, MAX_PATH, (LPARAM)wndInfo.szWndTitle);  
+			GetClassName(hWnd, wndInfo.szClassName, MAX_PATH);
+			wndInfo.dwCtrlId = ::GetDlgCtrlID(hWnd);
+			lpWndData->AddWnd(wndInfo);
+			// 输出窗口信息  
+			TRACE4("A-0x%08X, %ld, %s, %s\n", hWnd, wndInfo.dwCtrlId, wndInfo.szClassName, wndInfo.szWndTitle);  
+			EnumChildWindows(hWnd, EnumChildWindowCallBack, lParam);    // 继续查找子窗口  
+		}
+
+		return TRUE;  
+	} 
+
+	BOOL EnumProcessAllWnd(LPPROC_WND_INFO lpProcWndInfo)
+	{
+		return EnumWindows(EnumWindowCallBack, (LPARAM)lpProcWndInfo);
+	}
+
+	BOOL StartProcess(LPCTSTR lpPath, BOOL bShowWnd, BOOL bSuspend)
+	{
+		STARTUPINFO si;
+		PROCESS_INFORMATION pi;
+		ZeroMemory(&si, sizeof(si));
+		si.cb = sizeof(si);
+		ZeroMemory(&pi, sizeof(pi));
+
+		CString strDir = lpPath;
+		strDir = strDir.Left(strDir.ReverseFind(_T('\\')));
+		si.dwFlags = STARTF_USESHOWWINDOW;							// 指定wShowWindow成员有效
+		si.wShowWindow = bShowWnd ? SW_SHOW : SW_HIDE;				// 设置创建进程时,窗口不显示,
+		// 为FALSE的话则不显示
+		BOOL bRet = ::CreateProcess (
+			lpPath,				// 不在此指定可执行文件的文件名
+			NULL,				// 命令行参数
+			NULL,				// 默认进程安全性
+			NULL,				// 默认线程安全性
+			FALSE,				// 指定当前进程内的句柄不可以被子进程继承
+			bSuspend ? CREATE_SUSPENDED : NULL,
+			NULL,				// 使用本进程的环境变量
+			strDir,				// 使用本进程的驱动器和目录
+			&si,
+			&pi);
+
+		if(bRet)
+		{
+			// 进程挂起后,仍能成功注入dll;
+			// 		TCHAR szDllPath[MAX_PATH];
+			// 		ZeroMemory(szDllPath,MAX_PATH);
+			// 		_stprintf_s(szDllPath, _T("%shook.dll"), g_szModulePath);
+			// 		for (int i = 0; i < 10; i++)
+			// 		{
+			// 			CInjection inject(pi.dwProcessId,szDllPath);
+			// 			inject.InjectDynamicLibrary();
+			// 			inject.EjectDynamicLibrary();
+			// 		}
+			g_procWndInfo.dwProcId = pi.dwProcessId;
+			// 既然我们不使用两个句柄,最好是立刻将它们关闭
+			::CloseHandle (pi.hThread);
+			::CloseHandle (pi.hProcess);
+		}
+
+		return bRet;
+	}
+};

+ 152 - 0
Source/OGCAssistTool/OGCAssistTool/Global.h

@@ -0,0 +1,152 @@
+#ifndef __GLOBAL_22__
+#define __GLOBAL_22__
+
+#include <tlhelp32.h>
+#include <vector>
+#include <string>
+using namespace std;
+
+#ifdef UNICODE
+typedef wstring TString;
+#else
+typedef string TString;
+#endif
+
+#define WECHAT _T("WeChat.exe")
+#define OGC_TOOL _T("Demo.exe")
+
+namespace GLOBAL {
+	// DeltaE76
+	// DeltaE94
+	// DeltaE00
+	typedef enum {
+		DeltaE00 = 0,
+		DeltaE76 = 1,
+		DeltaE94 = 2
+	}DETYPE;
+
+	// 进程信息;
+	typedef struct __PROC_INFO__ {
+		DWORD   dwProcId;        // 进程id;
+		TString strProcName;     // 进程名称;
+		TString strProcFile;     // 进程路径;
+	}PROC_INFO, *LPPROC_INFO;
+
+	// 窗口信息;
+	typedef struct __WND_INFO__ {
+		HWND    hWnd;
+		DWORD	dwCtrlId;
+		TCHAR   szClassName[MAX_PATH];
+		TCHAR   szWndTitle[MAX_PATH];
+		__WND_INFO__() {
+			dwCtrlId = 0;
+			memset(szClassName, 0, sizeof(TCHAR)*MAX_PATH);
+			memset(szWndTitle, 0, sizeof(TCHAR)*MAX_PATH);
+		}
+
+		__WND_INFO__ &operator=(const __WND_INFO__ &that) {
+			if ( this == &that )
+				return *this;
+
+			hWnd = that.hWnd;
+			dwCtrlId = that.dwCtrlId;
+			_stprintf(szWndTitle, _T("%s"), that.szWndTitle);
+			_stprintf(szClassName, _T("%s"), that.szClassName);
+
+			return *this;
+		}
+	}WND_INFO, *LPWND_INFO;
+
+	// 进程内所有窗口信息;
+	typedef struct __PROC_WND_INFO__ {
+		DWORD   dwProcId;
+		std::vector<WND_INFO> vtWndInfo;
+
+		void AddWnd(WND_INFO &data) {
+			if (!IsExistWnd(data.hWnd))
+				vtWndInfo.push_back(data);
+		}
+
+		bool IsExistWnd(HWND hWnd) {
+			bool bExist = false;
+			for (std::vector<WND_INFO>::iterator it = vtWndInfo.begin(); it != vtWndInfo.end(); it++ ) {
+				if ( it->hWnd == hWnd ) {
+					bExist = true;
+					break;
+				}
+			}
+
+			return bExist;
+		}
+	}PROC_WND_INFO,*LPPROC_WND_INFO;
+
+	// Config文件内的配置信息;
+	typedef struct __CONFIG__{
+		INT		nStdOut;
+		INT		nOffline;
+		INT		nDeltaEType;
+		DOUBLE	dDeltaEValue;
+		DWORD	dwOGCToolProcId;
+		TCHAR	szLine[MAX_PATH];
+		TCHAR	szAccount[MAX_PATH];			
+		TCHAR	szPassword[MAX_PATH];		
+		TCHAR	szBatchNumber[MAX_PATH];
+		TCHAR	szOGCToolProgram[MAX_PATH];
+		__CONFIG__() {
+			nStdOut = 0;
+			nOffline = 0;
+			nDeltaEType = 0;
+			dDeltaEValue = 0.0;
+			dwOGCToolProcId = -1;
+			memset(szLine, 0, sizeof(TCHAR)*MAX_PATH);
+			memset(szAccount, 0, sizeof(TCHAR)*MAX_PATH);
+			memset(szPassword, 0, sizeof(TCHAR)*MAX_PATH);
+			memset(szBatchNumber, 0, sizeof(TCHAR)*MAX_PATH);
+			memset(szOGCToolProgram, 0, sizeof(TCHAR)*MAX_PATH);
+		}
+	}CONFIG, *LPCONFIG;
+
+	extern BOOL g_bHijacted;
+	// 配置信息;
+	extern CONFIG g_config;
+	// 全局路径;
+	extern TCHAR g_szModulePath[MAX_PATH];			// 软件目录;
+	extern TCHAR g_szModuleFileName[MAX_PATH];		// 软件名称;
+	extern TCHAR g_szConfigFile[MAX_PATH];
+	// 目标里程窗口信息;
+	extern PROC_WND_INFO g_procWndInfo;
+
+	BOOL GetConfigInfo(LPCTSTR lpIniDir = NULL, LPCTSTR lpConfigName = NULL);
+	DWORD FindProcess(LPCTSTR lpProName);
+	vector<DWORD> FindAllProcess(LPCTSTR lpProName);
+	void FindAllProcess(std::vector<PROC_INFO> &vtProInfo);
+	HANDLE FindModule(LPCTSTR lpModuleName, DWORD dwProcId);
+	LPCTSTR GetModulePath(LPCTSTR lpModuleName, DWORD dwProcId);
+	HANDLE FindModuleEx(LPCTSTR lpModuleName, DWORD dwProcId);
+	BOOL GetDebugPriv();
+
+	BOOL GetFileVersion( IN HMODULE hModule, IN DWORD (&dwArray)[4]);
+	BOOL GetFileVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] );
+	BOOL GetProductVersion( IN HMODULE hModule, IN DWORD (&dwArray)[4]);
+	BOOL GetProductVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] );
+
+	BOOL GetOSDisplayString(LPTSTR pszOS);
+	void WriteTextLog(const TCHAR *format, ...);
+	BOOL CopyFileEx(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, const BOOL &bFailIfExists=TRUE);
+	void tSplitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
+	void tSplitpath(const char *path, char *drive, char *dir, const int &nTimes);
+	BOOL IsDirectoryLegitimate(const CString &strDirectory);
+	void ShowSystemErrorInfo(CString strDescription, const DWORD &dwError);
+	BOOL MySystemShutdown(LPTSTR lpMsg);
+	BOOL PreventSystemShutdown();
+	BOOL MySystemShutdown();
+
+	// 根据进程pid获取进程对应程序的窗口句柄;
+	HWND GetProcessMainWnd(const DWORD& dwTagetProcessId, LPCTSTR lpTagetWndName);
+	// 获取指定进程名的进程主窗口;
+	HWND GetProcessMainWnd(LPCTSTR lpProcessName, LPCTSTR lpTagetWndName);
+	BOOL EnumProcessAllWnd(LPPROC_WND_INFO lpProcWndInfo);
+	BOOL StartProcess(LPCTSTR lpPath, BOOL bShowWnd = FALSE, BOOL bSuspend = FALSE);
+};
+
+#endif

+ 161 - 0
Source/OGCAssistTool/OGCAssistTool/Injection.cpp

@@ -0,0 +1,161 @@
+#include "StdAfx.h"
+#include "Injection.h"
+#include "Global.h"
+
+CInjection::CInjection():m_dwInjectPID(0),
+m_hInjectProcess(NULL),
+m_lpInjectData(NULL),
+m_lpEjectData(NULL),
+m_hInjectThread(NULL),
+m_hEjectThread(NULL),
+m_dwPathLen(0)
+{
+}
+
+CInjection::CInjection(DWORD dwProcessID, LPCTSTR lpDynamicLibraryPath)
+:m_dwInjectPID(dwProcessID),
+m_hInjectProcess(NULL),
+m_lpInjectData(NULL),
+m_lpEjectData(NULL),
+m_hInjectThread(NULL),
+m_hEjectThread(NULL),
+m_dwPathLen(0)
+{
+	ASSERT(dwProcessID!=0);
+	ASSERT(lpDynamicLibraryPath!=NULL);
+
+	memset(m_szDllPath, 0, sizeof(m_szDllPath));
+	_tcscpy_s(m_szDllPath,lpDynamicLibraryPath);
+	
+	m_hInjectProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwInjectPID);
+	if ( m_hInjectProcess == NULL)
+	{
+		GLOBAL::WriteTextLog(_T("打开WeChat.exe进程失败"));
+	}
+	//m_hInjectProcess = OpenProcess(PROCESS_CREATE_THREAD	| PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwInjectPID);
+}
+
+CInjection::~CInjection(void)
+{
+	// 卸载dll;
+	//EjectDynamicLibrary();
+
+	// 释放所有资源;
+	if (m_hInjectThread)
+		CloseHandle(m_hInjectThread);
+	m_hInjectThread = NULL;
+
+	if (m_hEjectThread)
+		CloseHandle(m_hEjectThread);
+	m_hEjectThread = NULL;
+
+	if (m_lpInjectData)
+		VirtualFreeEx(m_hInjectProcess, m_lpInjectData, m_dwPathLen, MEM_RELEASE);
+	m_lpInjectData = NULL;
+
+	if (m_lpEjectData)
+		VirtualFreeEx(m_hInjectProcess, m_lpEjectData, m_dwPathLen, MEM_RELEASE);
+	m_lpEjectData = NULL;
+
+	if (m_hInjectProcess)
+		CloseHandle(m_hInjectProcess);
+	m_hInjectProcess = NULL;
+}
+
+void CInjection::setInjectionObj(DWORD dwProcessID, LPCTSTR lpDynamicLibraryPath)
+{
+	ASSERT(dwProcessID != 0);
+	ASSERT(lpDynamicLibraryPath != NULL);
+
+	m_dwInjectPID = dwProcessID;
+	memset(m_szDllPath, 0, sizeof(m_szDllPath));
+	_tcscpy_s(m_szDllPath, lpDynamicLibraryPath);
+
+	m_hInjectProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwInjectPID);
+	if (m_hInjectProcess == NULL)
+	{
+		GLOBAL::WriteTextLog(_T("打开WeChat.exe进程失败"));
+	}
+	//m_hInjectProcess = OpenProcess(PROCESS_CREATE_THREAD	| PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, m_dwInjectPID);
+}
+
+BOOL CInjection::InjectDynamicLibrary()
+{
+	ASSERT(m_hInjectProcess!=NULL);
+
+	m_dwPathLen = _tcslen(m_szDllPath)*sizeof(TCHAR)+1;
+	m_lpInjectData = VirtualAllocEx(m_hInjectProcess,NULL, m_dwPathLen, MEM_COMMIT, PAGE_READWRITE);
+	if (NULL == m_lpInjectData)
+	{
+		GLOBAL::WriteTextLog(_T("创建WeChat.exe进程虚拟内存失败"));
+		return FALSE;
+	}
+
+	if (WriteProcessMemory(m_hInjectProcess, m_lpInjectData, m_szDllPath, m_dwPathLen, NULL) == 0)
+	{
+		// 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
+		VirtualFreeEx(m_hInjectProcess, m_lpInjectData, 0, MEM_RELEASE);
+		return FALSE;
+	}
+
+	HMODULE hk32 = GetModuleHandle(_T("kernel32.dll"));
+	// 注意:微信使用的是W版本;
+	LPVOID lpAddr = GetProcAddress(hk32,"LoadLibraryW");
+
+	m_hInjectThread = CreateRemoteThread(m_hInjectProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, m_lpInjectData, 0, NULL);
+	if (NULL == m_hInjectThread)
+	{
+		// 注意:MEM_RELEASE释放时第三参数一定要为0,请查看MSDN;
+		VirtualFreeEx(m_hInjectProcess, m_lpInjectData, 0, MEM_RELEASE);
+		return FALSE;
+	}
+
+	WaitForSingleObject(m_hInjectThread, INFINITE);
+	if (m_hInjectThread)
+		CloseHandle(m_hInjectThread);
+	m_hInjectThread = NULL;
+	
+	/* 注入成功后,不能释放内存否则微信会挂;
+	if (m_lpInjectData != NULL)
+		VirtualFreeEx(m_hInjectProcess, m_lpInjectData, 0, MEM_RELEASE);
+	*/
+
+	return TRUE;
+}
+
+BOOL CInjection::EjectDynamicLibrary()
+{
+	if(m_hInjectProcess==NULL)
+		return TRUE;
+
+	// 获取模块句柄;
+	HANDLE hModule = GLOBAL::FindModuleEx(m_szDllPath, m_dwInjectPID);
+	if (hModule == NULL )
+	{
+		GLOBAL::WriteTextLog(_T("获取WeChat.exe进程模块hook.dll失败"));
+		return FALSE;
+	}
+
+	LPVOID lpAddr = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibraryAndExitThread");//FreeLibraryAndExitThread//FreeLibrary
+	if (lpAddr == NULL )
+	{
+		GLOBAL::WriteTextLog(_T("获取kernel32.dll中的FreeLibraryAndExitThread失败"));
+		return FALSE;
+	}
+
+	m_hEjectThread = CreateRemoteThread(m_hInjectProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddr, hModule, 0, NULL);
+	if ( m_hEjectThread == NULL )
+	{
+		GLOBAL::WriteTextLog(_T("创建WeChat.exe远程线程(FreeLibraryAndExitThread)失败"));
+		return FALSE;
+	}
+
+	WaitForSingleObject(m_hEjectThread, INFINITE);
+	if (m_hEjectThread)
+		CloseHandle(m_hEjectThread);
+	m_hEjectThread = NULL;
+
+	return TRUE;
+}
+
+

+ 56 - 0
Source/OGCAssistTool/OGCAssistTool/Injection.h

@@ -0,0 +1,56 @@
+/************************************************************************/
+/*  Copyright (C), 2016-2020, [Home], 保留所有权利;
+/*  模 块 名:;
+/*  描    述:;
+/*
+/*  版    本:[V];	
+/*  作    者:[Home];
+/*  日    期:[1/6/2019];
+/*
+/*
+/*  注    意:;
+/*
+/*  修改记录:[Home];
+/*  修改日期:;
+/*  修改版本:;
+/*  修改内容:;
+/************************************************************************/
+#ifndef __INJECTION_OBJ__
+#define __INJECTION_OBJ__
+
+#pragma once
+
+class CInjection
+{
+public:
+	CInjection();
+	explicit CInjection(DWORD dwProcessID, LPCTSTR lpDynamicLibraryPath);
+	~CInjection(void);
+	// dll路径和要注入的进程id;
+	void setInjectionObj(DWORD dwProcessID, LPCTSTR lpDynamicLibraryPath);
+
+public:
+	BOOL InjectDynamicLibrary();
+	BOOL EjectDynamicLibrary();
+	inline HANDLE GetInjectProcess(){
+		return m_hInjectProcess;
+	}
+private:
+	// 当前注入的进程ID;
+	DWORD			m_dwInjectPID;
+	// 动态库路径;
+	TCHAR			m_szDllPath[MAX_PATH];
+	// 当前注入的进程句柄;
+	HANDLE			m_hInjectProcess;
+	// 路径分配的内存;
+	LPVOID			m_lpInjectData;
+	LPVOID			m_lpEjectData;
+	// 路径长度;
+	DWORD			m_dwPathLen;
+	// 注入线程句柄;
+	HANDLE			m_hInjectThread;
+	// 卸载线程句柄;
+	HANDLE			m_hEjectThread;
+};
+
+#endif

+ 294 - 0
Source/OGCAssistTool/OGCAssistTool/MD5.cpp

@@ -0,0 +1,294 @@
+#include "stdafx.h"
+#include "Md5.h"
+#include <strsafe.h>
+
+
+// MD5Transform函数使用的常量;
+#define S11 7  
+#define S12 12  
+#define S13 17  
+#define S14 22  
+#define S21 5  
+#define S22 9  
+#define S23 14  
+#define S24 20  
+#define S31 4  
+#define S32 11  
+#define S33 16  
+#define S34 23  
+#define S41 6  
+#define S42 10  
+#define S43 15  
+#define S44 21  
+
+// 基础的MD5函数(四个非线性函数(每轮一个))
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+// 将x左移n个bit位;
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+// FF, GG, HH, 和 II 是用来转换 Rounds1,2,3,4的 ;
+// Rotation is separate from addition to prevent recomputation;
+#define FF(a, b, c, d, x, s, ac) { \
+	(a) += F ((b), (c), (d)) + (x) + (UINT32)(ac); \
+	(a) = ROTATE_LEFT ((a), (s)); \
+	(a) += (b); \
+}
+#define GG(a, b, c, d, x, s, ac) { \
+	(a) += G ((b), (c), (d)) + (x) + (UINT32)(ac); \
+	(a) = ROTATE_LEFT ((a), (s)); \
+	(a) += (b); \
+}
+#define HH(a, b, c, d, x, s, ac) { \
+	(a) += H ((b), (c), (d)) + (x) + (UINT32)(ac); \
+	(a) = ROTATE_LEFT ((a), (s)); \
+	(a) += (b); \
+}
+#define II(a, b, c, d, x, s, ac) { \
+	(a) += I ((b), (c), (d)) + (x) + (UINT32)(ac); \
+	(a) = ROTATE_LEFT ((a), (s)); \
+	(a) += (b); \
+}
+
+static unsigned char PADDING[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMD5::CMD5(void)
+{
+	m_nInputLen = 0;
+	m_pInputText = NULL;
+	m_bValidDigest = FALSE;
+	memset(m_digestStr,0,33);
+}
+
+CMD5::CMD5(IN CONST BYTE* szInput,IN CONST size_t& nInputLen)
+{
+	m_pInputText =  const_cast<BYTE*>(szInput); 
+	m_nInputLen = nInputLen;
+	memset(m_digestStr, 0, 33);
+	m_bValidDigest = CalcDigest();
+}
+
+CMD5::~CMD5(void)
+{
+
+}
+
+void CMD5::Decode(IN UINT32 *output, IN UINT8 *input, IN CONST size_t& len)
+{
+	UINT32 i, j;
+	for (i = 0, j = 0; j < len; i++, j += 4)
+		output[i] = (input[j]) | ((input[j+1]) << 8) | ((input[j+2]) << 16) | ((input[j+3]) << 24);
+}
+
+void CMD5::Encode(IN UINT8 *output, IN UINT32 *input, IN CONST size_t& len)
+{
+	UINT32 i, j;
+	for (i = 0, j = 0; j < len; i++, j += 4) 
+	{
+		output[j] = input[i] & 0xFF;
+		output[j+1] = (input[i] >> 8) & 0xFF;
+		output[j+2] = (input[i] >> 16) & 0xFF;
+		output[j+3] = (input[i] >> 24) & 0xFF;
+	}
+}
+
+void CMD5::MD5Init(IN MD5_CTX* md5ctx)
+{
+	md5ctx->count[0] = md5ctx->count[1] = 0;
+	// 用魔数常量来初始化;
+	md5ctx->state[0] = 0x67452301;
+	md5ctx->state[1] = 0xefcdab89;
+	md5ctx->state[2] = 0x98badcfe;
+	md5ctx->state[3] = 0x10325476;
+}
+
+void CMD5::MD5Update(IN MD5_CTX* md5ctx, IN UINT8* Input, IN CONST size_t& InputLen)
+{
+	UINT32 i, nIndex, nPartLen;
+
+	// 计算出模64(0x3F)后的值;
+	nIndex = (md5ctx->count[0] >> 3) & 0x3F;
+
+	// 更新bit位数;
+	if ( (md5ctx->count[0] += (InputLen << 3))< (InputLen << 3) )
+		md5ctx->count[1]++;
+	md5ctx->count[1] += (InputLen >> 29);
+
+	// 设置缓冲区的字节数;
+	nPartLen = 64 - nIndex;
+
+	// 尽可能多的转换;
+	if (InputLen >= nPartLen) 
+	{
+		memcpy(&md5ctx->buffer[nIndex], Input, nPartLen);
+		MD5Transform(md5ctx->state, md5ctx->buffer);
+
+		for (i = nPartLen; i + 63 < InputLen; i += 64)
+			MD5Transform(md5ctx->state, &Input[i]);
+
+		nIndex = 0;
+	}
+	else
+		i = 0;
+
+	// 复制剩余的缓冲内容;
+	memcpy(&md5ctx->buffer[nIndex], &Input[i], InputLen-i);
+}
+
+void CMD5::MD5Transform(IN UINT32 state[4], IN UINT8 block[64] )
+{
+	UINT32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+	Decode(x, block, 64);
+
+	// 第一轮分组运算;
+	FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+	FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+	FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+	FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+	FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+	FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+	FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+	FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+	FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+	FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+	FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+	FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+	FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+	FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+	FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+	FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+	// 第二轮分组运算;
+	GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+	GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+	GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+	GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+	GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+	GG(d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+	GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+	GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+	GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+	GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+	GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+	GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+	GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+	GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+	GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+	GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+	// 第三轮分组运算;
+	HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+	HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+	HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+	HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+	HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+	HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+	HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+	HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+	HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+	HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+	HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+	HH(b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+	HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+	HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+	HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+	HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+	// 第四轮分组运算;
+	II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+	II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+	II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+	II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+	II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+	II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+	II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+	II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+	II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+	II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+	II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+	II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+	II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+	II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+	II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+	II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+
+	memset(x, 0, sizeof(x));
+}
+
+void CMD5::MD5Final(IN UINT8 digest[16], IN MD5_CTX* md5ctx)
+{
+	UINT8 bits[8];
+	UINT32 index, padLen;
+
+	// 保存2进制位数;
+	Encode(bits, md5ctx->count, 8);
+
+	/* Pad out to 56 mod 64.*/
+	index = (unsigned int)((md5ctx->count[0] >> 3) & 0x3f);
+	padLen = (index < 56) ? (56 - index) : (120 - index);
+	MD5Update(md5ctx, PADDING, padLen);
+
+	/* Append length (before padding) */
+	MD5Update(md5ctx, bits, 8);
+
+	/* Store state in digest */
+	Encode(digest, md5ctx->state, 16);
+
+	memset(md5ctx, 0, sizeof(*md5ctx));
+}
+
+void CMD5::SetBYTEText(IN CONST BYTE* szInput, IN CONST size_t& nInputLen)
+{
+	m_pInputText =  const_cast<BYTE*>(szInput); 
+	m_nInputLen = nInputLen;
+	m_bValidDigest = CalcDigest();
+}
+
+BOOL CMD5::CalcDigest()
+{
+	MD5_CTX md5ctx;
+	// 初始化md5;
+	MD5Init(&md5ctx); 
+	MD5Update(&md5ctx, m_pInputText, m_nInputLen);
+	MD5Final(m_digest,&md5ctx);
+
+	// 转化为32位的16进制字符;
+	int p = 0;
+	for (int i = 0; i < 16; i++)
+	{
+#ifdef UNICODE
+		StringCchPrintfW(&m_digestStr[p], 3, L"%02x", m_digest[i]);
+#else
+		StringCchPrintfA(&m_digestStr[p], 3, "%02x", m_digest[i]);
+#endif
+		p += 2;
+	}
+
+	return TRUE;
+}
+
+CONST TCHAR* CMD5::GetMD5Digest()
+{
+	if( m_bValidDigest )
+		return m_digestStr;
+
+	return NULL;
+}

+ 55 - 0
Source/OGCAssistTool/OGCAssistTool/MD5.h

@@ -0,0 +1,55 @@
+#ifndef __MD5__
+#define __MD5__
+
+#pragma once
+//////////////////////////////////////////////////////////////////////////
+// MD5的Context结构体;
+typedef struct 
+{
+	// 状态 (ABCD);
+	UINT32 state[4];     
+	// 2进制位个数, modulo 2^64 (lsb first);
+	UINT32 count[2];  
+	// 输入的缓冲区;
+	UINT8  buffer[64];                        
+} MD5_CTX;
+
+class __declspec(dllexport) CMD5
+{
+public:
+	CMD5(void);
+	CMD5(IN CONST BYTE* szInput,IN CONST size_t& nInputLen);
+	~CMD5(void);
+
+private:
+	// md5核心算法;
+	void MD5Init(IN MD5_CTX* md5ctx);
+	void MD5Update(IN MD5_CTX* md5ctx, IN UINT8* Input, IN CONST size_t& InputLen);
+	void MD5Transform(IN UINT32 state[4], IN UINT8 block[64] );
+	void MD5Final(IN UINT8 digest[16], IN MD5_CTX* md5ctx);
+
+	void Decode(IN UINT32 *output, IN UINT8 *input, IN CONST size_t& len);
+	void Encode(IN UINT8 *output, IN UINT32 *input, IN CONST size_t& len);
+
+private:
+	// md5封装;
+	// 计算md5是否成功;
+	BOOL	m_bValidDigest;
+	// md5计算后的结果值;
+	UINT8	m_digest[16];
+	// 将md5数值转化为16进制字符串;
+	TCHAR	m_digestStr[33];
+	// 要计算的字符串;
+	BYTE*	m_pInputText;
+	// 要计算的字符串长度;
+	size_t  m_nInputLen;
+	// 计算出md5转化结果;
+	BOOL CalcDigest();
+
+	// 对外接口;
+public:
+	void SetBYTEText(IN CONST BYTE* szInput,IN CONST size_t& nInputLen);
+	CONST TCHAR* GetMD5Digest();
+};
+
+#endif

+ 51 - 0
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.cpp

@@ -60,6 +60,57 @@ BOOL COGCAssistToolApp::InitInstance()
 	// 例如修改为公司或组织名
 	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
 
+	MTVERIFY(GLOBAL::GetConfigInfo());
+
+#pragma region 打开目标进程;
+	DWORD dwProcId = 0;
+	if ( 0 == ( dwProcId = GLOBAL::FindProcess(_T("Demo.exe"))) )
+	{
+		// 没有找到目标进程,启动;
+		if ( !GLOBAL::StartProcess(GLOBAL::g_config.szOGCToolProgram) )
+		{
+			return FALSE;
+		}
+	}
+	else 
+	{
+		TCHAR szModulPath[MAX_PATH] = {0};
+		_stprintf(szModulPath, _T("%s"), GLOBAL::GetModulePath(_T("Demo.exe"), dwProcId));
+		if ( _tcscmp(szModulPath, GLOBAL::g_config.szOGCToolProgram) != 0 )
+		{
+			TCHAR szMsg[1024] = {0};
+			_stprintf_s(szMsg, 
+				_T("存在同名进程,目录非指定路径,请手动关闭非目标路径程序")
+				_T("\n\n当前进程路径:%s\n\n正确进程路径:%s\n\n")
+				_T("是:关闭当前进程并启动目标进程\n")
+				_T("否:不关闭当前进程,退出登录\n")
+				_T("取消:不关闭当前进程,启动目标进程\n"), 
+				szModulPath, 
+				GLOBAL::g_config.szOGCToolProgram);
+			INT nChoose = MessageBox(NULL, szMsg, _T("错误,存在同名进程!"), MB_ICONERROR|MB_YESNOCANCEL);
+			if ( nChoose == IDNO )
+			{
+				return FALSE;
+			}
+			else if ( nChoose == IDYES )
+			{
+				// 关闭当前进程;
+				HANDLE token = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcId);
+				TerminateProcess(token, 0);
+			}
+
+			if ( !GLOBAL::StartProcess(GLOBAL::g_config.szOGCToolProgram) )
+			{
+				return FALSE;
+			}
+		}
+		else
+		{
+			GLOBAL::g_procWndInfo.dwProcId = dwProcId;
+		}
+	}
+#pragma endregion
+
 #pragma region 登录对话框;
 	CDlgLogin LoginDlg;
 	if ( LoginDlg.DoModal() != IDOK )

+ 21 - 18
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.rc

@@ -89,8 +89,8 @@ BEGIN
 END
 
 IDD_OGCASSISTTOOL_DIALOG DIALOGEX 0, 0, 639, 360
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_APPWINDOW
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST | WS_EX_APPWINDOW
 CAPTION "OGCAssistTool"
 FONT 9, "MS Shell Dlg", 0, 0, 0x1
 BEGIN
@@ -119,22 +119,26 @@ EXSTYLE WS_EX_STATICEDGE
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
     GROUPBOX        "参数",IDC_STATIC,7,7,717,31
-    EDITTEXT        IDC_EDIT1,41,18,96,14,ES_AUTOHSCROLL
+    EDITTEXT        EDIT_LINE,41,18,52,14,ES_AUTOHSCROLL | ES_READONLY
     LTEXT           "线体:",IDC_STATIC,15,21,25,8
-    EDITTEXT        IDC_EDIT2,175,18,96,14,ES_AUTOHSCROLL
-    LTEXT           "BOM:",IDC_STATIC,151,21,24,8
-    CONTROL         "锁定",CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,20,32,10,WS_EX_TRANSPARENT
-    LTEXT           "▲E标准值:",IDC_STATIC,418,21,43,8
-    LTEXT           "▲E类型:",IDC_STATIC,318,21,35,8
-    COMBOBOX        IDC_COMBO1,353,18,48,80,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
-    EDITTEXT        IDC_EDIT3,463,18,48,14,ES_AUTOHSCROLL
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,512,18,11,14
-    EDITTEXT        IDC_EDIT4,563,18,154,14,ES_AUTOHSCROLL
-    LTEXT           "SN:",IDC_STATIC,542,21,17,8
-    CONTROL         "",LIST_DEBUG_DATA,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,73,717,242
-    GROUPBOX        "结果:",IDC_STATIC,7,39,717,31
-    LTEXT           "▲E平均值:",IDC_STATIC,15,53,43,8
-    EDITTEXT        IDC_EDIT5,64,50,73,14,ES_AUTOHSCROLL
+    EDITTEXT        EDIT_BATCH_NUMBER,129,18,96,14,ES_AUTOHSCROLL
+    LTEXT           "BOM:",IDC_STATIC,103,21,24,8
+    CONTROL         "锁定",CHECK_LOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,226,20,32,10,WS_EX_TRANSPARENT
+    LTEXT           "▲E标准值:",IDC_STATIC,359,21,43,8
+    LTEXT           "▲E类型:",IDC_STATIC,266,21,35,8
+    COMBOBOX        COMBO_ETYPE,301,18,48,80,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+    EDITTEXT        EDIT_EVALUE,405,18,48,14,ES_AUTOHSCROLL
+    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,454,18,11,14
+    EDITTEXT        EDIT_SN,499,18,154,14,ES_AUTOHSCROLL
+    LTEXT           "SN:",IDC_STATIC,478,21,17,8
+    CONTROL         "",LIST_DEBUG_DATA,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,41,717,242
+    GROUPBOX        "结果:",IDC_STATIC,7,284,717,31
+    LTEXT           "▲E平均值:",IDC_STATIC,15,298,43,8
+    EDITTEXT        EDIT_ARG_EVALUE,64,295,73,14,ES_AUTOHSCROLL | ES_READONLY
+    PUSHBUTTON      "显示窗口",BTN_SHOW_WND,503,295,50,14
+    PUSHBUTTON      "隐藏窗口",BTN_HIDE_WND,560,295,50,14
+    CONTROL         "劫持窗口",CHECK_HIJACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,617,297,48,10
+    CONTROL         "恢复劫持",CHECK_RESUME_HIJACKING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,672,297,48,10
 END
 
 PAGE_LOG DIALOGEX 0, 0, 732, 322
@@ -243,7 +247,6 @@ BEGIN
     BEGIN
         LEFTMARGIN, 7
         RIGHTMARGIN, 724
-        VERTGUIDE, 137
         TOPMARGIN, 7
         BOTTOMMARGIN, 315
     END

+ 44 - 0
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.vcproj

@@ -310,6 +310,50 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="Core"
+			>
+			<File
+				RelativePath=".\Global.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\Global.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Injection.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\Injection.h"
+				>
+			</File>
+			<File
+				RelativePath=".\MD5.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\MD5.h"
+				>
+			</File>
+			<File
+				RelativePath=".\MTVERIFY.H"
+				>
+			</File>
+			<File
+				RelativePath=".\PipeService.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\PipeService.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Protocol.h"
+				>
+			</File>
+		</Filter>
 		<File
 			RelativePath=".\ReadMe.txt"
 			>

+ 122 - 2
Source/OGCAssistTool/OGCAssistTool/OGCAssistToolDlg.cpp

@@ -9,12 +9,20 @@
 #include "PageLog.h"
 #include "PageConfig.h"
 #include "PageStatistics.h"
+#include "Injection.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #endif
 
-
+// 注入;
+CInjection g_Injection;
+// OGC Tool无序句柄;
+HWND g_hWnd_SN = NULL;
+HWND g_hWnd_SN_Combobox = NULL;
+HWND g_hWnd_Tester = NULL;
+HWND g_hWnd_FWVersion = NULL;
+HWND g_hWnd_Channel = NULL;
 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 
 class CAboutDlg : public CDialogEx
@@ -69,6 +77,7 @@ BEGIN_MESSAGE_MAP(COGCAssistToolDlg, CDialogEx)
 	ON_WM_QUERYDRAGICON()
 	//}}AFX_MSG_MAP
 	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB, &COGCAssistToolDlg::OnTcnSelchangeTab)
+	ON_WM_TIMER()
 END_MESSAGE_MAP()
 
 
@@ -106,12 +115,14 @@ BOOL COGCAssistToolDlg::OnInitDialog()
 	// TODO: 在此添加额外的初始化代码
 	//SetBackgroundImage(IDB_LOGO);
 	//SetBackgroundColor(RGB(255,255,255));
-	if ( GLOBAL::bOffline )
+	if ( GLOBAL::g_config.nOffline )
 	{
 
 	}
 	InitTabCtrl();
 
+	SetTimer(0, 300, NULL);
+
 	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
 }
 
@@ -248,6 +259,77 @@ void COGCAssistToolDlg::InitTabCtrl()
 	m_tabCtrl.SetCurSel(m_CurSelTab=0);
 }
 
+HWND COGCAssistToolDlg::MyFindWindow(LPCTSTR lpClassName)
+{
+	HWND hWnd = NULL;
+	if ( lpClassName == NULL || lpClassName[0] == '\0' )
+		return hWnd;
+
+	for (std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		// 返回第一个找到的类名;
+		if ( _tcscmp(lpClassName, it->szClassName) == 0 )
+		{
+			hWnd = it->hWnd;
+			break;
+		}
+	}
+
+	return hWnd;
+}
+
+void COGCAssistToolDlg::FetchOGCWnd()
+{
+	// SN Combobox;
+	for(std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		if ( _tcscmp(_T("TfrmDemo"), it->szClassName) == 0 )
+		{
+			g_hWnd_SN_Combobox = (++it)->hWnd;
+			break;
+		}
+	}
+
+	// SN Edit && Tester;
+	for(std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		if ( !_tcscmp(_T("OCC"), it->szWndTitle) &&  !_tcscmp(_T("TCheckBox"), it->szClassName) )
+		{
+			g_hWnd_SN = (--it)->hWnd;
+			g_hWnd_Tester = (--it)->hWnd;
+			break;
+		}
+	}
+
+	// Channel Edit;
+	for(std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		if ( !_tcscmp(_T("Connect CA310"), it->szWndTitle) &&  !_tcscmp(_T("TButton"), it->szClassName) )
+		{
+			g_hWnd_Channel = (--it)->hWnd;
+			break;
+		}
+	}
+
+	// FW Version;
+	for(std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		if ( !_tcscmp(_T("FS2"), it->szWndTitle) &&  !_tcscmp(_T("TCheckBox"), it->szClassName) )
+		{
+			g_hWnd_FWVersion = (--it)->hWnd;
+			break;
+		}
+	}
+
+#ifdef _DEBUG
+	TCHAR szMsg[MAX_PATH] = {0};
+	//_stprintf(szMsg, _T("Channel=%08X, SN=%08X, Combobox=%08X, Tester=%08X, FWVersion=%08X\n"), g_hWnd_Channel, g_hWnd_SN, g_hWnd_SN_Combobox, g_hWnd_Tester, g_hWnd_FWVersion);
+	_stprintf(szMsg, _T("Channel=%ld, SN=%ld, Combobox=%ld, Tester=%ld, FWVersion=%ld\n"), g_hWnd_Channel, g_hWnd_SN, g_hWnd_SN_Combobox, g_hWnd_Tester, g_hWnd_FWVersion);
+	//TRACE(szMsg);
+	GLOBAL::WriteTextLog(szMsg);
+#endif
+}
+
 void COGCAssistToolDlg::OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
 {
 	// TODO: 在此添加控件通知处理程序代码
@@ -271,3 +353,41 @@ BOOL COGCAssistToolDlg::DestroyWindow()
 	}
 	return CDialogEx::DestroyWindow();
 }
+
+void COGCAssistToolDlg::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	switch (nIDEvent)
+	{
+	case 0:
+		{
+			// OGC启动时间较长(5~7秒,根据电脑性能决定),需要判断窗口是否完全显示出来;
+			if ( FindWindow(_T("TApplication"), _T("Demo")) && FindWindow(_T("TfrmDemo"), _T("(TPV 2021/09/29) UHD Series OGC Tool V2.21.1.3")) )
+			{
+				Sleep(1200); // 再等多会;
+				GLOBAL::EnumProcessAllWnd(&GLOBAL::g_procWndInfo);
+				if ( !GLOBAL::g_bHijacted )
+				{
+					if ( g_Injection.GetInjectProcess() )
+					{
+						g_Injection.EjectDynamicLibrary();
+					}
+
+					TCHAR szDll[MAX_PATH] = {0};
+					_stprintf(szDll, _T("%s%s"), GLOBAL::g_szModulePath, _T("OGCAssist.dll"));
+					g_Injection.setInjectionObj(GLOBAL::g_procWndInfo.dwProcId, szDll);
+					GLOBAL::g_bHijacted = g_Injection.InjectDynamicLibrary();
+				}
+
+				// 附加窗口句柄;
+				FetchOGCWnd();
+
+				KillTimer(nIDEvent);
+			}			
+		}
+		break;
+	default:
+		break;
+	}
+	CDialogEx::OnTimer(nIDEvent);
+}

+ 4 - 0
Source/OGCAssistTool/OGCAssistTool/OGCAssistToolDlg.h

@@ -35,7 +35,11 @@ public:
 	int m_CurSelTab;
 	CDialogEx* m_pDialog[4];
 	CImageList  m_ImageList;
+
 	void InitTabCtrl();
+	HWND MyFindWindow(LPCTSTR lpClassName);
+	void FetchOGCWnd();	
 	afx_msg void OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult);
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
 	virtual BOOL DestroyWindow();
 };

+ 56 - 4
Source/OGCAssistTool/OGCAssistTool/PageDebug.cpp

@@ -4,8 +4,16 @@
 #include "stdafx.h"
 #include "OGCAssistTool.h"
 #include "PageDebug.h"
-
-
+#include "Injection.h"
+
+// 注入;
+extern CInjection g_Injection;
+// OGC Tool无序句柄;
+extern HWND g_hWnd_SN;
+extern HWND g_hWnd_SN_Combobox;
+extern HWND g_hWnd_Tester;
+extern HWND g_hWnd_FWVersion;
+extern HWND g_hWnd_Channel;
 // CDlgDebug 对话框
 
 IMPLEMENT_DYNAMIC(CPageDebug, CDialogEx)
@@ -29,6 +37,8 @@ void CPageDebug::DoDataExchange(CDataExchange* pDX)
 
 BEGIN_MESSAGE_MAP(CPageDebug, CDialogEx)
 	ON_WM_CTLCOLOR()
+	ON_BN_CLICKED(BTN_SHOW_WND, &CPageDebug::OnBnClickedShowWnd)
+	ON_BN_CLICKED(BTN_HIDE_WND, &CPageDebug::OnBnClickedHideWnd)
 END_MESSAGE_MAP()
 
 
@@ -39,7 +49,8 @@ BOOL CPageDebug::OnInitDialog()
 	CDialogEx::OnInitDialog();
 
 	// TODO:  在此添加额外的初始化
-	SetBackgroundColor(RGB(255,255,255));
+	//SetBackgroundColor(RGB(255,255,255));
+	SetBackgroundColor(RGB(200,200,200));
 	InitListCtrl();
 	return TRUE;  // return TRUE unless you set the focus to a control
 	// 异常: OCX 属性页应返回 FALSE
@@ -89,4 +100,45 @@ void CPageDebug::InitListCtrl()
 	m_ctrlList.SetColumnWidth( 3, 100);
 	m_ctrlList.InsertColumn( 4, _T("▲E实际值"));
 	m_ctrlList.SetColumnWidth(4, 100);
-}
+}
+
+HWND MyFindWindow(LPCTSTR lpClassName)
+{
+	HWND hWnd = NULL;
+	if ( lpClassName == NULL || lpClassName[0] == '\0' )
+		return hWnd;
+
+	for (std::vector<GLOBAL::WND_INFO>::iterator it = GLOBAL::g_procWndInfo.vtWndInfo.begin(); it != GLOBAL::g_procWndInfo.vtWndInfo.end(); it++ )
+	{
+		// 返回第一个找到的类名;
+		if ( _tcscmp(lpClassName, it->szClassName) == 0 )
+		{
+			hWnd = it->hWnd;
+			break;
+		}
+	}
+
+	return hWnd;
+}
+
+void CPageDebug::OnBnClickedShowWnd()
+{
+	// TODO: 在此添加控件通知处理程序代码
+	HWND hWnd = NULL;
+	if ( hWnd = MyFindWindow(_T("TfrmDemo")) )
+		::ShowWindow(hWnd, SW_SHOW);
+
+	if ( hWnd = MyFindWindow(_T("TApplication")) )
+		::ShowWindow(hWnd, SW_SHOW);
+}
+
+void CPageDebug::OnBnClickedHideWnd()
+{
+	// TODO: 在此添加控件通知处理程序代码
+	HWND hWnd = NULL;
+	if ( hWnd = MyFindWindow(_T("TfrmDemo")) )
+		::ShowWindow(hWnd, SW_HIDE);
+
+	if ( hWnd = MyFindWindow(_T("TApplication")) )
+		::ShowWindow(hWnd, SW_HIDE);
+}

+ 2 - 0
Source/OGCAssistTool/OGCAssistTool/PageDebug.h

@@ -24,4 +24,6 @@ public:
 	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
 	CListCtrl m_ctrlList;
 	void InitListCtrl();
+	afx_msg void OnBnClickedShowWnd();
+	afx_msg void OnBnClickedHideWnd();
 };

+ 490 - 0
Source/OGCAssistTool/OGCAssistTool/PipeService.cpp

@@ -0,0 +1,490 @@
+#include "StdAfx.h"
+#include "PipeService.h"
+//#include "MainDlg.h"
+#include "Protocol.h"
+
+#define PIPENAME _T("\\\\.\\pipe\\OGCAssist")
+// 每一个处理器上产生多少个线程(为了最大限度的提升服务器性能,详见配套文档)
+#define WORKER_THREADS_PER_PROCESSOR 2
+// 同时投递的Accept请求的数量(这个要根据实际的情况灵活设置)
+#define MAX_POST_ACCEPT              2
+// 传递给Worker线程的退出信号
+#define EXIT_CODE                    NULL
+
+
+// 释放指针和句柄资源的宏
+
+// 释放指针宏
+#define RELEASE(x)                      {if(x != NULL ){delete x;x=NULL;}}
+// 释放句柄宏
+#define RELEASE_HANDLE(x)               {if(x != NULL && x!=INVALID_HANDLE_VALUE){ CloseHandle(x);x = NULL;}}
+// 释放Socket宏
+#define RELEASE_SOCKET(x)               {if(x !=INVALID_SOCKET) { closesocket(x);x=INVALID_SOCKET;}}
+
+
+CIOCPPipe::CIOCPPipe(void)
+{
+    m_nThreads = 0;
+    m_hShutdownEvent = NULL;
+    m_hIOCompletionPort = NULL;
+    m_phWorkerThreads= NULL;
+    m_pMain = NULL;
+}
+
+CIOCPPipe::~CIOCPPipe(void)
+{
+	// 确保资源彻底释放
+	this->Stop();
+}
+
+DWORD WINAPI CIOCPPipe::_WorkerThread(LPVOID lpParam)
+{    
+	THREADPARAMS_WORKER* pParam = (THREADPARAMS_WORKER*)lpParam;
+	CIOCPPipe* pIOCPModel = (CIOCPPipe*)pParam->pIOCPModel;
+	int nThreadNo = (int)pParam->nThreadNo;
+
+	pIOCPModel->ShowMessage(_T("工作者线程启动,ID: %d."),nThreadNo);
+
+	OVERLAPPED           *pOverlapped = NULL;
+	ULONG_PTR            pCompletionKey  = NULL;
+	DWORD                dwBytesTransfered = 0;
+	PER_PIPE_CONTEXT	 *pPipeContext = NULL;
+
+	// 循环处理请求,知道接收到Shutdown信息为止
+	while (WAIT_OBJECT_0 != WaitForSingleObject(pIOCPModel->m_hShutdownEvent, 0))
+	{
+		BOOL bReturn = GetQueuedCompletionStatus(
+			pIOCPModel->m_hIOCompletionPort,
+			&dwBytesTransfered,
+			(PULONG_PTR)&pPipeContext,
+			&pOverlapped,
+			INFINITE);
+
+        dprintf(_T("IOCP有消息"));
+
+		// 如果收到的是退出标志,则直接退出
+		if ( EXIT_CODE==(DWORD)pPipeContext )
+		{
+			//break;
+            continue;
+		}
+
+		// 判断是否出现了错误
+		if( !bReturn )  
+		{  
+			DWORD dwErr = GetLastError();
+
+			// 显示一下提示信息
+			if( !pIOCPModel->HandleError( pPipeContext, dwErr ) )
+			{
+				//break;
+                continue;
+			}
+
+			continue;  
+		}  
+		else  
+		{  	
+			// 读取传入的参数
+			PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverlapped, PER_IO_CONTEXT, m_Overlapped);  
+
+			// 判断是否有客户端断开了
+			if((0 == dwBytesTransfered) && ( OP_RECV==pIoContext->m_OpType || OP_SEND==pIoContext->m_OpType))  
+			{  
+				//pIOCPModel->_ShowMessage( _T("客户端 %s:%d 断开连接."),pIoContext->szClientName, pIoContext->dwProcessId );
+
+				// 释放掉对应的资源
+				pIOCPModel->RemoveContext( pPipeContext );
+
+ 				continue;  
+			}  
+			else
+			{
+				switch( pIoContext->m_OpType )  
+				{  
+				case OP_ACCEPT:
+					{ 
+						pIOCPModel->DoAccpet( pPipeContext, pIoContext );
+                        dprintf(_T("客户端连接成功"));
+					}
+					break;
+				case OP_RECV:
+					{
+						pIOCPModel->DoRecv( pPipeContext, pIoContext );
+					}
+					break;
+				case OP_SEND:
+					break;
+				default:
+					// 不应该执行到这里
+					TRACE(_T("_WorkThread中的 pIoContext->m_OpType 参数异常.\n"));
+					break;
+				}
+			}
+		}
+	}
+
+	TRACE(_T("工作者线程 %d 号退出.\n"),nThreadNo);
+
+	// 释放线程参数
+	RELEASE(lpParam);	
+
+	return 0;
+}
+
+bool CIOCPPipe::Start()
+{
+	// 初始化线程互斥量
+	InitializeCriticalSection(&m_csContextList);
+
+	// 建立系统退出的事件通知
+	m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	// 初始化IOCP
+	if (false == InitIOCP())
+	{
+		ShowMessage(_T("初始化IOCP失败!\n"));
+		return false;
+	}
+	else
+	{
+		ShowMessage(_T("\nIOCP初始化完毕\n."));
+	}
+
+
+	ShowMessage(_T("系统准备就绪,等候连接....\n"));
+
+	return true;
+}
+
+void CIOCPPipe::Stop()
+{
+    // 激活关闭消息通知
+    SetEvent(m_hShutdownEvent);
+
+    for (int i = 0; i < m_nThreads; i++)
+    {
+        // 通知所有的完成端口操作退出
+        PostQueuedCompletionStatus(m_hIOCompletionPort, 0, (DWORD)EXIT_CODE, NULL);
+    }
+
+    // 等待所有的客户端资源退出
+    WaitForMultipleObjects(m_nThreads, m_phWorkerThreads, TRUE, INFINITE);
+
+    // 清除客户端列表信息
+    ClearContextList();
+
+    // 释放其他资源
+    DeInitialize();
+
+    ShowMessage(_T("停止监听\n"));
+}
+
+bool CIOCPPipe::InitIOCP()
+{
+	// 建立第一个完成端口
+	m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0 );
+
+	if ( NULL == m_hIOCompletionPort)
+	{
+		ShowMessage(_T("建立完成端口失败!错误代码: %d!\n"), WSAGetLastError());
+		return false;
+	}
+
+	// 根据本机中的处理器数量,建立对应的线程数
+#ifdef _DEBUG
+    m_nThreads = 2;
+#else
+	m_nThreads = WORKER_THREADS_PER_PROCESSOR * _GetNoOfProcessors();
+#endif
+
+	// 为工作者线程初始化句柄
+	m_phWorkerThreads = new HANDLE[m_nThreads];
+	
+	// 根据计算出来的数量建立工作者线程
+	DWORD nThreadID;
+	for (int i = 0; i < m_nThreads; i++)
+	{
+		THREADPARAMS_WORKER* pThreadParams = new THREADPARAMS_WORKER;
+		pThreadParams->pIOCPModel = this;
+		pThreadParams->nThreadNo  = i+1;
+		m_phWorkerThreads[i] = ::CreateThread(0, 0, _WorkerThread, (void *)pThreadParams, 0, &nThreadID);
+	}
+
+	for ( int i = 0; i < MAX_POST_ACCEPT; i++ )
+	{
+		PostAccept();
+	}
+    
+	TRACE(" 建立 _WorkerThread %d 个.\n", m_nThreads );
+
+	return true;
+}
+
+void CIOCPPipe::DeInitialize()
+{
+	// 删除客户端列表的互斥量
+	DeleteCriticalSection(&m_csContextList);
+
+	// 关闭系统退出事件句柄
+	RELEASE_HANDLE(m_hShutdownEvent);
+
+	// 释放工作者线程句柄指针
+	for( int i=0;i<m_nThreads;i++ )
+	{
+		RELEASE_HANDLE(m_phWorkerThreads[i]);
+	}
+	
+	RELEASE(m_phWorkerThreads);
+
+	// 关闭IOCP句柄
+	RELEASE_HANDLE(m_hIOCompletionPort);
+
+	ShowMessage(_T("释放资源完毕.\n"));
+}
+
+bool CIOCPPipe::PostAccept()
+{
+	PER_PIPE_CONTEXT* pPipeContext = new PER_PIPE_CONTEXT;
+    pPipeContext->m_hPipe = CreateNamedPipe(
+        PIPENAME,                // pipe name 
+        PIPE_ACCESS_DUPLEX |     // read/write access 
+        FILE_FLAG_OVERLAPPED,    // overlapped mode 
+        PIPE_TYPE_MESSAGE |      // message-type pipe 
+        PIPE_READMODE_MESSAGE |  // message-read mode 
+        PIPE_WAIT,               // blocking mode 
+        PIPE_UNLIMITED_INSTANCES,               // number of instances 
+        0,   // output buffer size 
+        0,   // input buffer size 
+        NMPWAIT_WAIT_FOREVER,     // client time-out 
+        NULL);                   // default security attributes
+
+    if ( pPipeContext->m_hPipe == INVALID_HANDLE_VALUE )
+	{
+		delete pPipeContext;
+		return false;
+	}
+
+	// 绑定到完成端口中;
+	HANDLE hIOCP = CreateIoCompletionPort((HANDLE)pPipeContext->m_hPipe, m_hIOCompletionPort, (DWORD)pPipeContext, 0);
+    if ( hIOCP == NULL )
+    {
+		delete pPipeContext;
+        return false;
+    }
+
+	// 异步等待客户端连接;
+    PER_IO_CONTEXT *pNewIoContext = pPipeContext->GetNewIoContext();
+    memset(pNewIoContext, 0, sizeof(PER_IO_CONTEXT));
+    pNewIoContext->m_OpType = OP_ACCEPT;
+    pNewIoContext->m_PipeAccept = pPipeContext->m_hPipe;
+    BOOL bConnect = ConnectNamedPipe(pPipeContext->m_hPipe, (LPOVERLAPPED)pNewIoContext);
+
+	if( bConnect )  
+	{// 重叠IO或完成端口,返回的是Fase;
+        CloseHandle(hIOCP);
+		//pPipeContext->RemoveContext(pNewIoContext);
+		ShowMessage(_T("创建用于Accept的Pipe失败!错误代码: %d"), GetLastError()); 
+		dprintf(_T("创建用于Accept的Pipe失败!错误代码: %d"), GetLastError()); 
+		delete pPipeContext;
+
+		return false;  
+	} 
+
+#if 0 // 线程中处理?;
+	BOOL fPendingIO = FALSE;
+	switch(GetLastError())
+	{
+		// The overlapped connection in progress.
+	case ERROR_IO_PENDING:
+		fPendingIO = TRUE;
+		break;
+		// Client is already connected, so signal an event
+	case ERROR_PIPE_CONNECTED:
+		break;
+		// If an error occurs during the connect operation...
+	default:
+		break;
+	}
+
+	return fPendingIO;
+#else
+	AddToContextList(pPipeContext);
+
+	return true;
+#endif
+}
+
+bool CIOCPPipe::DoAccpet( PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT* pIoContext )
+{
+	if( !PostRecv(pIoContext) )
+	{
+		return false;
+	}
+
+	pIoContext->ResetBuffer();
+	return PostAccept(); 	
+}
+
+bool CIOCPPipe::PostRecv( PER_IO_CONTEXT* pIoContext )
+{
+	// 初始化变量
+	DWORD dwFlags = 0;
+	DWORD dwBytes = 0;
+	//WSABUF *p_wbuf   = &pIoContext->chRequest;
+	OVERLAPPED *p_ol = &pIoContext->m_Overlapped;
+
+	pIoContext->ResetBuffer();
+	pIoContext->m_OpType = OP_RECV;
+
+	dprintf(_T("等待客户端消息"));
+	// 初始化完成后,投递WSARecv请求
+	int nBytesRecv = ReadFile( pIoContext->m_PipeAccept, pIoContext->chRequest, BUFSIZE, &dwBytes, p_ol );
+
+	// 如果返回值错误,并且错误的代码并非是Pending的话,那就说明这个重叠请求失败了
+	if ((-1 == nBytesRecv) && (ERROR_IO_PENDING != GetLastError()))
+	{
+		ShowMessage(_T("投递第一个WSARecv失败!"));
+		dprintf(_T("投递第一个WSARecv失败"));
+		return false;
+	}
+
+	return true;
+}
+
+bool CIOCPPipe::DoRecv( PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT* pIoContext )
+{
+	RecvProcess(pPipeContext, pIoContext);
+
+	// 然后开始投递下一个WSARecv请求
+	return PostRecv( pIoContext );
+}
+
+bool CIOCPPipe::AssociateWithIOCP( PER_IO_CONTEXT* pIoContext )
+{
+	// 将用于和客户端通信的SOCKET绑定到完成端口中
+	
+	return true;
+}
+
+void CIOCPPipe::AddToContextList( PER_PIPE_CONTEXT* pPipeContext )
+{
+	EnterCriticalSection(&m_csContextList);
+
+	m_arrayClientContext.Add(pPipeContext);	
+	
+	LeaveCriticalSection(&m_csContextList);
+}
+
+void CIOCPPipe::RemoveContext( PER_PIPE_CONTEXT* pPipeContext )
+{
+	EnterCriticalSection(&m_csContextList);
+
+	for( int i=0; i<m_arrayClientContext.GetCount(); i++ )
+	{
+		if( pPipeContext == m_arrayClientContext.GetAt(i) )
+		{
+			RELEASE( pPipeContext );			
+			m_arrayClientContext.RemoveAt(i);			
+			break;
+		}
+	}
+
+	LeaveCriticalSection(&m_csContextList);
+}
+
+void CIOCPPipe::ClearContextList()
+{
+	EnterCriticalSection(&m_csContextList);
+
+	for( int i=0;i<m_arrayClientContext.GetCount();i++ )
+	{
+		delete m_arrayClientContext.GetAt(i);
+	}
+
+	m_arrayClientContext.RemoveAll();
+
+	LeaveCriticalSection(&m_csContextList);
+}
+
+int CIOCPPipe::GetNoOfProcessors()
+{
+	SYSTEM_INFO si;
+
+	GetSystemInfo(&si);
+
+	return si.dwNumberOfProcessors;
+}
+
+void CIOCPPipe::ShowMessage(const CString szFormat,...) const
+{
+	// 根据传入的参数格式化字符串
+	CString   strMessage;
+	va_list   arglist;
+
+	// 处理变长参数
+	va_start(arglist, szFormat);
+	strMessage.FormatV(szFormat,arglist);
+	va_end(arglist);
+}
+
+void CIOCPPipe::RecvProcess(PER_PIPE_CONTEXT* pPipeContext, PER_IO_CONTEXT* pIoContext)
+{
+	if ( pIoContext )
+	{
+		// 数据长度;
+		pIoContext->m_Overlapped.InternalHigh;
+		dprintf(_T("接收到客户端消息:%s, %ld"), pIoContext->chRequest, GetCurrentThreadId());
+		
+		/* 
+			PACKAGE pak;
+			memcpy整个chRequest到其pak后, pIoContext空;原因:是因为pak结构大小只有DATAHEADER+buf,buf并不能代替MSG_INFO。
+			所以将chRequest整个内存复制到pak时,越界了。
+
+			memcpy(&pak, pIoContext->chRequest, pIoContext->m_Overlapped.InternalHigh);
+		*/
+		DATAHEADER header;
+		MSG_INFO msg_info;
+		memcpy(&header, pIoContext->chRequest, sizeof(DATAHEADER));
+		memcpy(&msg_info, pIoContext->chRequest+sizeof(DATAHEADER), sizeof(MSG_INFO));
+
+		DWORD lpNumberOfBytesWritten = 0;
+		TCHAR szMsg[MAX_PATH] = {0};
+		_stprintf(szMsg, _T("%ld:%ld"), GetCurrentThreadId(), GetTickCount());
+		BOOL bRet = WriteFile(pIoContext->m_PipeAccept, pIoContext->chRequest, pIoContext->m_Overlapped.InternalHigh, &lpNumberOfBytesWritten, NULL);
+		if ( !bRet )
+		{
+			dprintf(_T("发送消息失败:%s, %ld, %ld"), pIoContext->chRequest, GetLastError(), GetCurrentThreadId());
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////
+// 判断客户端Socket是否已经断开,否则在一个无效的Socket上投递WSARecv操作会出现异常
+// 使用的方法是尝试向这个socket发送数据,判断这个socket调用的返回值
+// 因为如果客户端网络异常断开(例如客户端崩溃或者拔掉网线等)的时候,服务器端是无法收到客户端断开的通知的
+
+bool CIOCPPipe::HandleError( PER_PIPE_CONTEXT *pPipeContext, const DWORD& dwErr )
+{
+	// 如果是超时了,就再继续等吧  
+	if( WAIT_TIMEOUT == dwErr )  
+	{  	
+		return true;
+	}
+	// 可能是客户端异常退出了
+	else if( ERROR_BROKEN_PIPE == dwErr )
+	{
+		RemoveContext(pPipeContext);
+		//ShowMessage( _T("检测到客户端异常退出!") );
+		dprintf(_T("检测到客户端异常退出"));
+		return true;
+	}
+
+	ShowMessage( _T("完成端口操作出现错误,线程退出。错误代码:%d"),dwErr );
+
+	return false;
+}
+
+
+
+

+ 230 - 0
Source/OGCAssistTool/OGCAssistTool/PipeService.h

@@ -0,0 +1,230 @@
+#pragma once
+
+#define CONNECTING_STATE 0
+#define READING_STATE 1
+#define WRITING_STATE 2
+#define INSTANCES 4
+#define PIPE_TIMEOUT 5000
+#define BUFSIZE 4096
+
+// 命名管道在完成端口上投递的I/O操作的类型
+typedef enum _OPERATION_TYPE
+{
+    OP_ACCEPT, // Accept操作;
+    OP_SEND,   // 发送操作
+    OP_RECV,   // 接收操作
+    OP_MAX     // 上限;
+} OPERATION_TYPE;
+
+// 单个IO请求;
+typedef struct _PER_IO_CONTEXT
+{
+    OVERLAPPED m_Overlapped;
+    HANDLE m_PipeAccept;
+    OPERATION_TYPE m_OpType;
+	// 接收客户端的消息;
+    TCHAR chRequest[BUFSIZE];
+    DWORD cbRead;
+	// 发送给客户的消息;
+    TCHAR chReply[BUFSIZE];
+    DWORD cbToWrite;
+    // 管道状态;
+    DWORD dwState;
+    // IO是否在等待;
+    BOOL fPendingIO;
+    
+    // 初始化
+    _PER_IO_CONTEXT()
+    {
+        ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
+        ZeroMemory(chRequest, BUFSIZE);
+        ZeroMemory(chReply, BUFSIZE);
+		m_PipeAccept = INVALID_HANDLE_VALUE;
+        m_OpType = OP_ACCEPT;
+        fPendingIO = FALSE;
+        dwState = 0;
+    }
+
+    // 释放掉句柄
+    ~_PER_IO_CONTEXT()
+    {		
+        if (m_PipeAccept != INVALID_HANDLE_VALUE)
+        {
+            //CloseHandle(m_PipeAccept);// 此处不能CloseHandle,因为m_PipeAccept在PER_PIPE_CONTEXT中已释放;
+            m_PipeAccept = INVALID_HANDLE_VALUE;
+        }
+    }
+
+    // 重置缓冲区内容
+    void ResetBuffer()
+    {
+		dprintf(_T("ResetBuffer\n"));
+        ZeroMemory(chRequest, BUFSIZE);
+        ZeroMemory(chReply, BUFSIZE);
+    }
+
+} PER_IO_CONTEXT, *PPER_IO_CONTEXT;
+
+
+typedef struct _PER_PIPE_CONTEXT
+{
+	HANDLE m_hPipe;
+	// 客户端进程PID;
+	DWORD dwProcessId;
+	// 客户端进程窗口名称;
+	TCHAR szClientName[255];
+	// 该Pipe下的所有IO事件;
+	CArray<_PER_IO_CONTEXT*> m_arrayIoContext;
+
+	_PER_PIPE_CONTEXT()
+	{
+		m_hPipe = INVALID_HANDLE_VALUE;
+		dwProcessId = 0;
+		memset(szClientName, 0, sizeof(TCHAR)*255);
+	}
+
+	~_PER_PIPE_CONTEXT()
+	{
+		if ( m_hPipe != INVALID_HANDLE_VALUE )
+		{
+			CloseHandle(m_hPipe);
+			m_hPipe = INVALID_HANDLE_VALUE;
+
+			// 释放掉所有的IO上下文数据
+			for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
+			{
+				delete m_arrayIoContext.GetAt(i);
+			}
+			m_arrayIoContext.RemoveAll();
+		}
+	}
+
+	// 设置客户端信息;
+	void SetClientInfo(DWORD dwClientId, LPCTSTR lpszClientName)
+	{
+		dwProcessId = dwClientId;
+		_stprintf_s(szClientName, _T("%s"), lpszClientName == NULL ? _T("Null") : lpszClientName);
+	}
+
+	// 获取一个新的IoContext
+	_PER_IO_CONTEXT* GetNewIoContext()
+	{
+		_PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
+
+		m_arrayIoContext.Add( p );
+
+		return p;
+	}
+
+	// 从数组中移除一个指定的IoContext
+	void RemoveContext( _PER_IO_CONTEXT* pContext )
+	{
+		ASSERT( pContext!=NULL );
+		for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
+		{
+			if( pContext == m_arrayIoContext.GetAt(i) )
+			{
+				delete pContext;
+				pContext = NULL;
+				m_arrayIoContext.RemoveAt(i);				
+				break;
+			}
+		}
+	}
+}PER_PIPE_CONTEXT, *PPER_PIPE_CONTEXT;
+
+
+// 工作者线程的线程参数
+class CIOCPPipe;
+typedef struct _tagThreadParams_WORKER
+{
+    CIOCPPipe *pIOCPModel;	// 类指针,用于调用类中的函数
+    int nThreadNo;          // 线程编号
+
+} THREADPARAMS_WORKER, *PTHREADPARAM_WORKER;
+
+
+// CIOCPPipe类
+class CIOCPPipe
+{
+public:
+    CIOCPPipe(void);
+    ~CIOCPPipe(void);
+
+public:
+    // 启动服务器
+    bool Start();
+
+    //	停止服务器
+    void Stop();
+
+    // 设置主界面的指针,用于调用显示信息到界面中
+    void SetMainDlg(CDialog *p) { m_pMain = p; }
+
+	// 向客户端发送消息;
+	bool SendMessage();
+
+protected:
+    // 初始化IOCP
+    bool InitIOCP();
+
+    // 最后释放资源
+    void DeInitialize();
+
+    // 投递Accept请求
+    bool PostAccept();
+
+    // 投递接收数据请求
+    bool PostRecv(PER_IO_CONTEXT *pIoContext);
+
+    // 在有客户端连入的时候,进行处理
+    bool DoAccpet(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
+
+    // 在有接收的数据到达的时候,进行处理
+    bool DoRecv(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
+
+    // 将客户端的相关信息存储到数组中
+    void AddToContextList(PER_PIPE_CONTEXT *pPipeContext);
+
+    // 将客户端的信息从数组中移除
+    void RemoveContext(PER_PIPE_CONTEXT *pPipeContext);
+
+    // 清空客户端信息
+    void ClearContextList();
+
+    // 将句柄绑定到完成端口中
+    bool AssociateWithIOCP(PER_IO_CONTEXT *pIoContext);
+
+    // 处理完成端口上的错误
+    bool HandleError(PER_PIPE_CONTEXT *pPipeContext, const DWORD &dwErr);
+
+    // 线程函数,为IOCP请求服务的工作者线程
+    static DWORD WINAPI _WorkerThread(LPVOID lpParam);
+
+    // 获得本机的处理器数量
+    int GetNoOfProcessors();
+
+    // 判断客户端Socket是否已经断开
+    bool IsSocketAlive(SOCKET s);
+
+    // 在主界面中显示信息
+    void ShowMessage(const CString szFormat, ...) const;
+
+	// 处理返回值;
+	void RecvProcess(PER_PIPE_CONTEXT* pPipeContext, PER_IO_CONTEXT* pIoContext);
+
+private:
+    HANDLE m_hShutdownEvent; // 用来通知线程系统退出的事件,为了能够更好的退出线程
+
+    HANDLE m_hIOCompletionPort; // 完成端口的句柄
+
+    HANDLE *m_phWorkerThreads; // 工作者线程的句柄指针
+
+    int m_nThreads; // 生成的线程数量
+
+    CDialog *m_pMain; // 主界面的界面指针,用于在主界面中显示消息
+
+    CRITICAL_SECTION m_csContextList; // 用于Worker线程同步的互斥量
+
+    CArray<PER_PIPE_CONTEXT *> m_arrayClientContext; // 客户端Socket的Context信息
+};

+ 80 - 0
Source/OGCAssistTool/OGCAssistTool/Protocol.h

@@ -0,0 +1,80 @@
+#define NAME_LEN 128
+#define DATA_LEN 256
+
+#pragma region Simple communication protocol
+
+#pragma pack(push)
+#pragma pack(1)
+typedef enum
+{
+	//////////////////////////////////////////////////////////////////////////
+	// 服务端:发出劫持消息;		客户端返回:成功/失败
+	S2C_BEGIN_HIJACK,
+	// 服务端:发出恢复消息;		客户端返回:成功/失败;
+	S2C_END_HIJACK,
+	//\ 服务端:发出Connect消息;		客户端返回:成功/失败;
+	S2C_CONNECT,
+	//\ 服务端:发出Disconnect消息;		客户端返回:成功/失败;
+	S2C_DISCONNECT,
+	//\ 服务端:发出CheckFW消息;		客户端返回:成功/失败;
+	S2C_CHECKFW,
+	//\ 服务端:发出Go消息;				客户端返回:成功/失败;
+	S2C_GO,
+
+	//////////////////////////////////////////////////////////////////////////
+	// 客户端:发出Disconnect触发结果;
+	C2S_DISCONNECT,
+	// 客户端:发出Connect触发结果;成功/失败;
+	C2S_CONNECT,
+	// 客户端:发出CheckFW触发结果; 成功/失败;	(成功->服务端读取当前版本);
+	C2S_CHECKFW,
+	// 客户端:发出Go触发结果;成功/失败; 成功->耗时值、输出目录
+	C2S_GO,
+	// 客户端:产生异常时通知服务端结束程序;
+	C2S_EXCEPTION,
+};
+
+typedef struct _HEADER_
+{
+	// 协议标识符;
+	BYTE	byProtocol;
+	// 整个协议包长度;
+	DWORD	dwPackageLen;
+	// 消息类型;
+	BYTE	byMsgType;
+	_HEADER_()
+	{
+		byProtocol = 0xAC;
+		dwPackageLen = 0;
+		byMsgType = 0;
+	}
+}DATAHEADER, *LPDATAHEADER;
+
+// 请求包
+typedef struct _PACKAGE_ {
+	DATAHEADER	header;
+	//BYTE		buf[4]; // 具体内容(指针地址);
+	LPVOID		buf;
+}PACKAGE, *LPPACKAGE;
+
+typedef struct _MSG_INFO_
+{
+	// 客户端ID;
+	DWORD	dwClientId;
+	// 客户端名称;
+	TCHAR	szClientName[NAME_LEN];
+	// 按钮执行结果;
+	BYTE	byResult;
+	// 按钮数据;
+	BYTE	byData[DATA_LEN];
+	_MSG_INFO_()
+	{
+		byResult = 0;
+		dwClientId = 0;
+		memset(byData, 0, DATA_LEN);
+		memset(szClientName, 0, sizeof(TCHAR)*NAME_LEN);
+	}
+}MSG_INFO,*LPMSG_INFO;
+
+#pragma pack(pop)
+#pragma endregion 简单通信协议

+ 10 - 1
Source/OGCAssistTool/OGCAssistTool/resource.h

@@ -22,14 +22,23 @@
 #define IDC_EDIT1                       1002
 #define CHECK_OFFLINE                   1003
 #define IDC_EDIT2                       1003
+#define EDIT_BATCH_NUMBER               1003
 #define IDC_CHECK1                      1004
 #define CHECK_LOCK                      1004
 #define IDC_COMBO1                      1005
+#define COMBO_ETYPE                     1005
 #define IDC_EDIT3                       1006
+#define EDIT_EVALUE                     1006
 #define IDC_SPIN1                       1007
 #define IDC_EDIT4                       1008
+#define EDIT_SN                         1008
 #define LIST_DEBUG_DATA                 1009
 #define IDC_EDIT5                       1010
+#define EDIT_ARG_EVALUE                 1010
+#define BTN_HIDE_WND                    1011
+#define CHECK_HIJACK                    1012
+#define BTN_SHOW_WND                    1013
+#define CHECK_RESUME_HIJACKING          1014
 
 // Next default values for new objects
 // 
@@ -37,7 +46,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        133
 #define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1010
+#define _APS_NEXT_CONTROL_VALUE         1014
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

+ 18 - 15
Source/OGCAssistTool/OGCAssistTool/stdafx.cpp

@@ -5,21 +5,24 @@
 
 #include "stdafx.h"
 
-
-namespace GLOBAL
+#define MAX_SIZE 8912
+void dprintf(TCHAR* pszStr, ...)
 {
-	bool bOffline = false;
-#ifdef _UNICODE
-	CString strLine = _T("");
-	CString strAccount = _T("");
-	CString strPassword = _T("");
-	CString strBatchNumber = _T("");
+	TCHAR szData[MAX_SIZE] = {0};
+	// 获取今年年份;
+	__time64_t gmt = time(NULL);// 获取当前日历时间(1900-01-01开始的Unix时间戳);
+	struct tm gmtm = { 0 };
+	localtime_s(&gmtm, &gmt); // 时间戳转成本地时间;
+#if _MSC_VER >= 1200 && _MSC_VER < 1500
+	sprintf(szData, _T("%s %s "), _T("[Assist] "), gmtm.tm_year + 1900, gmtm.tm_mon + 1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec);
 #else
-	std::string strLine = "";
-	std::string strAccount = "";
-	std::string strPassword = "";
-	std::string strBatchNumber = "";
+	_stprintf_s(szData, _T("%s %04d-%02d-%02d %02d:%02d:%02d "), _T("[Assist] "), gmtm.tm_year + 1900, gmtm.tm_mon + 1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec);
 #endif
-	int nDeltaEType = DeltaE00;
-	double dDeltaEVaule = 0.0;
-};
+	int len = _tcslen(szData)*sizeof(TCHAR);
+	va_list args;
+	va_start(args, pszStr);
+	_vsntprintf_s(szData + len, MAX_SIZE - len, MAX_SIZE - len, pszStr, args);
+	va_end(args);
+	_tcscat_s(szData, _T("\n"));
+	OutputDebugString(szData);
+}

+ 3 - 42
Source/OGCAssistTool/OGCAssistTool/stdafx.h

@@ -37,49 +37,10 @@
 
 #include <afxcontrolbars.h>     // 功能区和控件条的 MFC 支持
 #include <string>
+#include "MTVERIFY.H"
+#include "Global.h"
 
-// DeltaE76
-// DeltaE94
-// DeltaE00
-typedef enum {
-	DeltaE00 = 0,
-	DeltaE76 = 1,
-	DeltaE94 = 2
-}DETYPE;
-
-// 全局变量空间;
-namespace GLOBAL
-{
-	// 是否离线模式;
-	extern bool bOffline;
-#ifdef _UNICODE
-	// 线体名称;
-	extern CString strLine;
-	// 账号;
-	extern CString strAccount;
-	// 密码;
-	extern CString strPassword;
-	// 批次号;
-	extern CString strBatchNumber;
-#else
-	// 线体名称;
-	extern std::string strLine;
-	// 账号;
-	extern std::string strAccount;
-	// 密码;
-	extern std::string strPassword;
-	// 批次号;
-	extern std::string strBatchNumber;
-#endif
-	// 当前▲E类型;
-	extern int nDeltaEType;
-	// 当前▲E标准值;
-	extern double dDeltaEVaule;
-};
-
-
-
-
+extern void dprintf(TCHAR* pszStr, ...);
 
 
 #ifdef _UNICODE