#include "CCmd.h"

#pragma region cmd指令说明
// 【/k】:调用cmd进程时，必须调用此参数
// //  【x:】:x为x盘符,cd到不同盘符下的文件夹路径之前，必须要要调用此参数，否则cd指令不生效；
// 【cd xxx】：切换到指定的文件夹xxx路径
// 【start/wait】：start启动进程，wait等待指令调用结束
//【APPDIR】: 安装路径
// 【qb】：cmd后台静默执行
//【qn】：无安装界面运行，静默安装指令参数
//【norestart】：安装后不启动App，默认为不启动(目前已经去掉该参数)
//vba不支持带空格路径安装，即便用路径标识符也不行，例如%cd%
#pragma endregion

CCmd::CCmd()
{

}

BOOL CCmd::Installcmd()
{
	std::wstring cmd = L"";
	//防止目标路径与当前进程所在盘符不一致，所以在cd之前，要指定目标路径的盘符cdDisk
	auto cdDisk = PathCore::smPath_Install.substr(0, 1) + L": & ";
	cmd = L"/k " + cdDisk + L"cd \"" + PathCore::smPath_Install + L"\"" + L" & start/wait " + Product::smName_InstallPackage + L" APPDIR=\"" + PathCore::smPath_Install + L"\" /qb /qn";

	LogIni::GetLogToIni("Install cmd", cmd);
	TCHAR* tc = (TCHAR*)(&cmd[0]);
	return Executecmd(tc);
}

//环境检测，如果没有就安装NET Framework
BOOL CCmd::InstallNetcmd()
{
	wstring systemLetter = DiskCore::GetSystemDriveLetter();//获取系统盘符
	SYSTEM_INFO si;
	GetNativeSystemInfo(&si);//获取系统信息
	std::wstring netframe;
	bool isSystem64 = true;

	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
		si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
	{
		isSystem64 = true;
	}
	else
	{
		isSystem64 = false;
	}


	if (systemLetter == L"")
	{
		systemLetter = L"C";

	}

	//安装NET Framework工具所在路径是固定的
	if (isSystem64)
	{
		netframe = systemLetter + L":\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319";
	}
	else
	{
		netframe = systemLetter + L":\\Windows\\Microsoft.NET\\Framework\\v4.0.30319";
	}

	std::wstring cmd = L"";
	//cmd = L"dism /online /enable-feature /featurename:IIS-ASPNET45 /all";//win8需要启动ASPNET4.5服务，目前暂时没用到；

	//检测当前系统为win8或更高版本
	if (IsWindows8OrGreater())
	{
		cmd = L"/k " + systemLetter + L": & cd " + netframe + L" & aspnet_regiis.exe -i /qb /qn";

		std::map<wstring, wstring> map{ {L"InstallNetFramwork", cmd}, { L"WindowsVersion", L"Win8,10.." }};
		LogIni::GetLogToIniMaps(map);
		m_IsWin8InstallNet = true;
	}
	else
	{
		cmd = L"/k " + systemLetter + L": & cd " + netframe + L" & aspnet_regiis.exe -i /qb /qn";

		std::map<wstring, wstring> map{ {L"InstallNetFramwork", cmd}, { L"WindowsVersion", L"Win7" } };
		LogIni::GetLogToIniMaps(map);
	}

	TCHAR* tc = (TCHAR*)(&cmd[0]);
	return Executecmd(tc);
}

BOOL CCmd::InstallVcPlusPluscmd() {
	std::wstring cmd = L"";
	wchar_t downloadsPath[MAX_PATH];
	DWORD bufferSize = ::GetEnvironmentVariable(L"USERPROFILE", downloadsPath, MAX_PATH);
	std::wstring wstrPath_Install(downloadsPath);
	wstrPath_Install += L"\\Downloads";
	//防止目标路径与当前进程所在盘符不一致，所以在cd之前，要指定目标路径的盘符cdDisk
	auto cdDisk = wstrPath_Install.substr(0, 1) + L": & ";
	cmd = L"/k " + cdDisk + L"cd \"" + wstrPath_Install + L"\"" + L" & curl -o vc_redist.x64.exe https://download.visualstudio.microsoft.com/download/pr/eaab1f82-787d-4fd7-8c73-f782341a0c63/917C37D816488545B70AFFD77D6E486E4DD27E2ECE63F6BBAAF486B178B2B888/VC_redist.x64.exe && start /wait vc_redist.x64.exe /install /quiet /norestart && del vc_redist.x64.exe";

	//LogIni::GetLogToIni("Install cmd", cmd);
	TCHAR* tc = (TCHAR*)(&cmd[0]);
	return Executecmd(tc);

}

BOOL CCmd::OpenAppcmd()
{
	//Todo：目前不使用该函数
	std::wstring cmd = L"";

	auto cdDisk = PathCore::smPath_Install.substr(0, 1) + L": & ";

	cmd = L"/k " + cdDisk + L"cd \"" + PathCore::smPath_Install + L"\"" + L" & start/wait " + Product::smName_Application;

	LogIni::GetLogToIni("Start App cmd", cmd);
	TCHAR* tc = (TCHAR*)(&cmd[0]);
	return Executecmd(tc);
}

BOOL CCmd::Executecmd(TCHAR pszCmdLine[], bool isVBA)
{
	char Buffer[4096];
	STARTUPINFO sInfo;//新进程的主窗口特性
	PROCESS_INFORMATION pInfo;
	SECURITY_ATTRIBUTES sa;
	HANDLE hRead, hWrite;
	DWORD bytesRead;    //读取代码的长度
	sa.nLength = sizeof(SECURITY_ATTRIBUTES); //结构体的大小，可用SIZEOF取得
	sa.lpSecurityDescriptor = NULL;//安全描述符
	sa.bInheritHandle = TRUE;; //安全描述的对象能否被新创建ÆÆ的进程继承

	if (!CreatePipe(&hRead, &hWrite, &sa, 0))
	{
		return GetLastError();
	}

	GetStartupInfo(&sInfo);
	sInfo.cb = sizeof(sInfo);
	sInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	sInfo.wShowWindow = SW_HIDE;
	sInfo.hStdError = hWrite;   //将管道的写端交给子进程
	sInfo.hStdOutput = hWrite;
	memset(&pInfo, 0, sizeof(pInfo));
	wstring cmdPath = L"";
	if (isVBA == false)
	{
		cmdPath = L"c:\\windows\\system32\\cmd.exe";
	}
	else
	{
		wstring Installpath = PathCore::smPath_Install + L"\\install.bat";
		cmdPath = Installpath;
	}
	if (!CreateProcessW(cmdPath.c_str(), pszCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &sInfo, &pInfo))
	{
		CloseHandle(hWrite);
		CloseHandle(hRead);
		return GetLastError();
	}


	for (int i = 0;; ++i)
	{
		//执行cmd结束之后，则读取文件结束
		if (!ReadFile(hRead, Buffer, sizeof(Buffer) - 1, &bytesRead, NULL))
		{
			break;
			Buffer[bytesRead] = 0;
		}
		else
		{
			WaitForSingleObject(pInfo.hProcess, 1000);
			CloseHandle(hWrite);
			CloseHandle(hRead);
			return TRUE;
		}


	}

	CloseHandle(hWrite);
	CloseHandle(hRead);
	return TRUE;

}

#pragma region VBA脚本指令（备用方案）
//编辑vba脚本内容-》生成文件vba文件到安装路径-》执行vba文件
// 
// 
//因时间有限，暂时不进行排查修复UTF-16的vba脚本执行没反应的问题
bool CCmd::GetVBA_UTF16()
{

	std::wstring cmdd = L"";
	std::wstring echoc = L"ECHO.";
	//vba脚本内容
	cmdd = L"@echo off\n" +
		echoc + L"\n" +
		PathCore::smPath_Install.substr(0, 1) + L": & " + L"cd " + L"%~dp0" + L"\n" +
		echoc + L"\n" +
		echoc + L"\n" +
		L"start/wait " + Product::smName_InstallPackage + L" APPDIR=\"" + PathCore::smPath_Install + L"\" /qb /qn" + L"\n" +
		echoc + L"\n" +
		L"EXIT";

	wstring Installpath = PathCore::smPath_Install + L"\\install.bat";
	HANDLE hDevice = CreateFileW(Installpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0,
		OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		DWORD errorCode = GetLastError();
		return false;
	}

	DWORD dwWriteSize = 0;
	auto chBuffer = cmdd.c_str();
	DWORD nBytes;
	WORD a = 0xFEFF;
	WriteFile(hDevice, &a, sizeof(a), &nBytes, NULL);
	BOOL bRet = WriteFile(hDevice, chBuffer, lstrlen(chBuffer) * sizeof(wchar_t), &nBytes, NULL);
	//BOOL bRet = WriteFile(hDevice, chBuffer, cmdd.length(), &dwWriteSize, NULL);
	//BOOL bRet = WriteFile(hDevice, chBuffer, cmdd.length(), &dwWriteSize, NULL);
	if (bRet)
	{

	}
	FlushFileBuffers(hDevice);   //将缓冲区数据写入磁盘

	LONG IDistance = 0;
	DWORD dwPtr = SetFilePointer(hDevice, IDistance, NULL, FILE_BEGIN);  //调整文件指针到文件开头
	DWORD dwSize = GetFileSize(hDevice, NULL);
	//bRet = ReadFile(hDevice, chBuffer, dwSize, &dwSize, NULL);
	//if (bRet)
	//{
	//	//printf("chbuffer is %s /n", chBuffer);
	//}
	CloseHandle(hDevice);
	Executecmd(nullptr, true);
}

//含有中文空格的路径，调用UTF8 VBA脚本会失败（安装到一半，就自动回退到安装前状态）
bool CCmd::GetVBA_UTF8()
{
	wstring Installpath = PathCore::smPath_Install + L"\\install.bat";
	LPCWSTR Installpathstr = Installpath.c_str();

	wchar_t* rootptr = _wcsdup(PathCore::smPath_Install.substr(0, 1).c_str());
	auto rootch = CharConvert::GetMultiByteW(rootptr);

	wchar_t* rootptr22 = _wcsdup(PathCore::smPath_Install.c_str());
	auto rootch22 = CharConvert::GetMultiByteW(rootptr22);


	wchar_t* ptrInstallPackage = _wcsdup(Product::smName_InstallPackage.c_str()/*.substr(0, 1).c_str()*/);
	auto InstallPackagech = CharConvert::GetMultiByteW(ptrInstallPackage);

	std::string cmdd = "";
	std::string echoc = "ECHO.";
	cmdd = "@echo off\n" +
		echoc + "\n" +
		rootch + ": & " + "cd " + "%~dp0" + "\n" +
		echoc + "\n" +
		echoc + "\n" +
		"start/wait " + InstallPackagech + " APPDIR=%cd%" + +" /qb /qn" + "\n" +
		echoc + "\n" +
		"EXIT";
	char* chBuffer = &cmdd[0];

	HANDLE hDevice = CreateFile(Installpathstr, GENERIC_READ | GENERIC_WRITE, 0, 0,
		OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		DWORD errorCode = GetLastError();
		return false;
	}
	DWORD dwSize = GetFileSize(hDevice, NULL);
	DWORD dwWriteSize = 0;
	WORD a = 0xFEFF;
	WriteFile(hDevice, &a, sizeof(a), &dwWriteSize, NULL);
	BOOL bRet = WriteFile(hDevice, chBuffer, lstrlenA(chBuffer) * sizeof(char), &dwWriteSize, NULL);
	//BOOL bRet = WriteFile(hDevice, chBuffer, cmdd.length(), &dwWriteSize, NULL);
	if (bRet)
	{
		return false;
	}
	FlushFileBuffers(hDevice);

	LONG IDistance = 0;
	DWORD dwPtr = SetFilePointer(hDevice, IDistance, NULL, FILE_BEGIN);
	DWORD dwReadSize = 0;
	/*bRet = ReadFile(hDevice, chBuffer, 10, &dwReadSize, NULL);
	if (bRet)
	{
		printf("chbuffer is %s /n", chBuffer);
	}*/
	CloseHandle(hDevice);

	return Executecmd(nullptr, true);;

}
#pragma endregion



