// lyfzRename.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "rename.h"
#include <Shlwapi.h>
#include <io.h>
#include "PARAMETERS.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

HMODULE g_hCurModule = NULL;
TCHAR g_szCurModulePath[MAX_PATH] = {0};
TCHAR g_szFna[MAX_PATH] = {0};

BOOL GetDebugPriv();
void WriteTextLog(const TCHAR *format, ...);
string GetFileVersion(const string &strFilePath);
bool GetFileVersion(IN const TCHAR *fname, IN HMODULE hModule, OUT WORD *pBuffer);
bool GetProductVersion(IN const TCHAR *fname, IN HMODULE hModule, OUT WORD *pBuffer);
void getopt(PARAMETERS & params, int argc, char ** argv);
// 唯一的应用程序对象

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;
	TCHAR szDrive[_MAX_DRIVE] = { 0 };
	TCHAR szDir[_MAX_DIR] = { 0 };
	TCHAR szFna[_MAX_DIR] = { 0 };
	TCHAR szExt[_MAX_DIR] = { 0 };
	::GetModuleFileName(NULL, g_szCurModulePath, sizeof(g_szCurModulePath) / sizeof(TCHAR));
	_tsplitpath_s(g_szCurModulePath, szDrive, szDir, g_szFna, szExt);
	_tcscpy_s(g_szCurModulePath, szDrive);
	_tcscat_s(g_szCurModulePath, szDir);

	GetDebugPriv();
	// 初始化 MFC 并在失败时显示错误
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: 更改错误代码以符合您的需要
		_tprintf(_T("错误: MFC 初始化失败\n"));
		nRetCode = 1;
	}
	else
	{
		// 获取参数;
		PARAMETERS params;
		getopt(params, argc, argv);
#ifdef _DEBUG
		WriteTextLog(_T("%ld, %ld,%s,%s"),params.dwProcId, params.killproc, params.NewVerPath.c_str(), params.OldVerPath.c_str());
#endif
		if ( params.dwProcId != 0)
		{	
			// 等待进程退出;
			DWORD dwTargetProId = 0;
			HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, params.dwProcId);
			if ( hProc != NULL)
			{
				if ( params.killproc )
				{//结束进程;
					TerminateProcess(hProc, 0);
					Sleep(500);
				}
				else
				{
					// 等待线程结束;
					WaitForSingleObject(hProc, INFINITE);
					CloseHandle(hProc);
				}
			}

			if (!PathFileExists(params.NewVerPath.c_str()))
			{
				exit(0);
			}
#if 0//以主程序为升级包的处理方法;
			// 删除旧版本文件;
			DeleteFile(params.OldVerPath.c_str());
			// 移动文件;
			MoveFile(params.NewVerPath.c_str(), params.OldVerPath.c_str());	

			if ( params.killproc )
			{
				// 启动程序;
				CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);//某些情况下要初始化COM才能使用ShellExecuteEx;
				SHELLEXECUTEINFO stuExecInfo = { 0 };
				DWORD dwExitCode = STILL_ACTIVE;
				stuExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
				stuExecInfo.lpFile = params.OldVerPath.c_str();
				stuExecInfo.nShow = SW_SHOW;
				stuExecInfo.lpVerb = _T("open");
				stuExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;

				if (!ShellExecuteEx(&stuExecInfo))
				{
					DWORD dwError = GetLastError();
					WriteTextLog(_T("ShellExecuteEx Error=%ld"), dwError);
					return -1;
				}

				HANDLE hProcess = stuExecInfo.hProcess;
				if ( hProcess != NULL )
				{
					//WaitForSingleObject(hProcess,INFINITE);//不等待结束;
					CloseHandle(hProcess);
				}
			}
#else//以安装包为升级包的处理方法;//可以选择静默安装安装包;
			if ( params.killproc )
			{
				// 启动程序;
				CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);//某些情况下要初始化COM才能使用ShellExecuteEx;
				SHELLEXECUTEINFO stuExecInfo = { 0 };
				DWORD dwExitCode = STILL_ACTIVE;
				CString strParameters = _T("/S");
				stuExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
				stuExecInfo.lpFile = params.NewVerPath.c_str();
				stuExecInfo.nShow = SW_SHOW;
				//stuExecInfo.lpParameters = strParameters;//不静默安装;
				stuExecInfo.lpVerb = _T("open");
				stuExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;

				if (!ShellExecuteEx(&stuExecInfo))
				{
					DWORD dwError = GetLastError();
					WriteTextLog(_T("ShellExecuteEx Error=%ld"), dwError);
					return -1;
				}

				HANDLE hProcess = stuExecInfo.hProcess;
				if ( hProcess != NULL )
				{
					CloseHandle(hProcess);
				}
			}
#endif
		}
	}

	return nRetCode;
}

void getopt(PARAMETERS & params, int argc, char ** argv)
{
	std::string cmd = "";
	for ( argc > 0; argc--; argv++ )
	{
		if ( _tcsicmp(*argv, _T("--pid")) == 0)
		{
			cmd = _T("--pid");
		}
		else if (_tcsicmp(*argv, _T("--oldpath")) == 0)
		{
			cmd = _T("--oldpath");
		}
		else if (_tcsicmp(*argv, _T("--newpath")) == 0)
		{
			cmd = _T("--newpath");
		}
		else if (_tcsicmp(*argv, _T("--killproc")) == 0)
		{
			cmd = _T("--killproc");
		}
		else
		{
			if ( _tcsicmp(cmd.c_str(), _T("--pid")) == 0)
			{
				params.dwProcId = atoi(*argv);
			}
			else if (_tcsicmp(cmd.c_str(), _T("--oldpath")) == 0)
			{
				params.OldVerPath = *argv;
			}
			else if (_tcsicmp(cmd.c_str(), _T("--newpath")) == 0)
			{
				params.NewVerPath = *argv;
			}
			else if (_tcsicmp(cmd.c_str(), _T("--killproc")) == 0)
			{
				params.killproc = atoi(*argv);
			}

			cmd = "";
		}
	}
}

//2.获得其他exe或dll的版本信息
string GetFileVersion(const string &strFilePath) 
{
	DWORD dwSize; 
	DWORD dwRtn; 
	string szVersion;
	//获取版本信息大小
	dwSize = GetFileVersionInfoSize(strFilePath.c_str(),NULL); 
	DWORD dwErr = GetLastError();
	if (dwSize == 0) 
	{ 
		return ""; 
	}
	char *pBuf; 
	pBuf= new char[dwSize + 1]; 
	if(pBuf == NULL)
		return "";
	memset(pBuf, 0, dwSize + 1);
	//获取版本信息
	dwRtn = GetFileVersionInfo(strFilePath.c_str(),NULL, dwSize, pBuf); 
	if(dwRtn == 0) 
	{ 
		return ""; 
	}
	LPVOID lpBuffer = NULL;
	UINT uLen = 0;
	//版本资源中获取信息
	dwRtn = VerQueryValue(pBuf, 
		TEXT("\\StringFileInfo\\080404b0\\FileVersion"), //0804中文
		//04b0即1252,ANSI
		//可以从ResourceView中的Version中BlockHeader中看到
		//可以测试的属性
		/*
		CompanyName 
		FileDescription 
		FileVersion 
		InternalName 
		LegalCopyright
		OriginalFilename
		ProductName 
		ProductVersion 
		Comments
		LegalTrademarks 
		PrivateBuild 
		SpecialBuild 
		*/ 
		&lpBuffer, 
		&uLen); 
	if(dwRtn == 0) 
	{ 
		return ""; 
	}
	szVersion = (char*)lpBuffer;
	delete pBuf; 
	return szVersion; 
}


// hModule 模块句柄 NULL表示当前模块;
bool GetFileVersion(IN const TCHAR *fname, IN HMODULE hModule, OUT WORD *pBuffer)
{
	//TCHAR fname[MAX_PATH];
	VS_FIXEDFILEINFO *pVi = NULL;
	DWORD dwHandle = 0;
	string str;


	int size = GetFileVersionInfoSize(fname, &dwHandle);

	if (size > 0) 
	{
		BYTE *buffer = new BYTE[size];
		memset(buffer,0,size);

		if (GetFileVersionInfo(fname, dwHandle, size, buffer)) 
		{
			if (VerQueryValue(buffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&size)) 
			{
				pBuffer[0] = HIWORD(pVi->dwFileVersionMS);
				pBuffer[1] = LOWORD(pVi->dwFileVersionMS);
				pBuffer[2] = HIWORD(pVi->dwFileVersionLS);
				pBuffer[3] = LOWORD(pVi->dwFileVersionLS);

				delete []buffer;
				return true;
			}
		}

		delete []buffer;
	}

	return false;
}

bool GetProductVersion(IN const TCHAR *fname, IN HMODULE hModule, OUT WORD *pBuffer)
{
	//TCHAR fname[MAX_PATH];
	VS_FIXEDFILEINFO *pVi = NULL;
	DWORD dwHandle = 0;
	string str;


	int size = GetFileVersionInfoSize(fname, &dwHandle);

	if (size > 0) 
	{
		BYTE *buffer = new BYTE[size];
		memset(buffer,0,size);

		if (GetFileVersionInfo(fname, dwHandle, size, buffer)) 
		{
			if (VerQueryValue(buffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&size)) 
			{
				pBuffer[0] = HIWORD(pVi->dwProductVersionMS);
				pBuffer[1] = LOWORD(pVi->dwProductVersionMS);
				pBuffer[2] = HIWORD(pVi->dwProductVersionLS);
				pBuffer[3] = LOWORD(pVi->dwProductVersionLS);

				delete []buffer;
				return true;
			}
		}

		delete []buffer;
	}

	return false;
}


BOOL GetDebugPriv()
{
	// 返回的访问令牌指针;
	HANDLE	hToken;
	// 接收所返回的制定特权名称的信息;
	LUID	sedebugnameValue;
	// 新特权信息的指针(结构体);
	TOKEN_PRIVILEGES tkp;
	DWORD	dwCurProcId = GetCurrentProcessId(); 
	// 要修改访问权限的进程句柄;
	HANDLE	hCurProc;	
	hCurProc = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwCurProcId ); 

	if ( !::OpenProcessToken( hCurProc,TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
	{
		DWORD dwError = GetLastError();
		//CString strError;
		//strError.Format("升级包提权失败,错误码=%d",dwError);
		//AfxMessageBox(strError);
		return FALSE;
	}

	if ( ! ::LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
	{
		DWORD dwError = GetLastError();
		//CString strError;
	///	strError.Format("升级包提权失败,错误码=%d",dwError);
		//AfxMessageBox(strError);
		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 ) )
	{
		DWORD dwError = GetLastError();
		//CString strError;
		//strError.Format("升级包提权失败,错误码=%d",dwError);
		//AfxMessageBox(strError);
		CloseHandle( hToken );
		return FALSE;
	}

	CloseHandle(hCurProc);
	CloseHandle(hToken);
	return TRUE;
}

/************************************************************************/
/*  函数：WriteTextLog[7/28/2009 Jeff];
/*  描述：写文本日志;
/*  参数：;
/*  	[IN] ：;
/*  返回：void;
/*  注意：;
/*  示例：;
/*
/*  修改：;
/*  日期：;
/*  内容：;
/************************************************************************/
void WriteTextLog(const TCHAR *format, ...)
{
	// 解析出日志路径;
	TCHAR szlogpath[MAX_PATH] = { 0 };
	_stprintf_s(szlogpath, _T("%s%s.txt"), g_szCurModulePath, g_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);//还原区域设定;
}
