#include "pch.h"
#include <stdio.h>

#include "tools.h"
#include <sys/types.h> 
#include <sys/timeb.h>
#include "StringHelper.h"
#ifdef _AFXDLL
	#include "afxpriv.h"
#endif
#include <ShlObj.h>
#pragma comment(lib,"version.lib")

#include <setupapi.h>
#include <devguid.h>
#pragma comment(lib,"SetupAPI.lib")

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <strsafe.h>

#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
#include <Shellapi.h>


// 调试打印函数
void OutputDebugPrintf(const char* strOutputString, ...)
{
#define PUT_PUT_DEBUG_BUF_LEN   1024
	char strBuffer[PUT_PUT_DEBUG_BUF_LEN] = { 0 };
	va_list vlArgs;
	va_start(vlArgs, strOutputString);
	_vsnprintf_s(strBuffer, sizeof(strBuffer) - 1, strOutputString, vlArgs);  //_vsnprintf_s  _vsnprintf
	va_end(vlArgs);
	OutputDebugStringA(strBuffer);  //OutputDebugString    // OutputDebugStringW
}


int64_t getTimeMsTick()
{
	struct __timeb64 t;
	_ftime64_s(&t);
	return t.time * 1000 + t.millitm;

}


bool GetFileVersion(const wchar_t * sTargetFileName, std::wstring &verstr)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
			TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
			pTranslate[i].wLanguage,
			pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		verstr = pVersion;
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate>0;

}

bool GetFileVersion(const wchar_t* sTargetFileName, sVersion& ver)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
			TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
			pTranslate[i].wLanguage,
			pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		ver.fromStr(pVersion);
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate > 0;
}

bool GetFileVersion(const wchar_t* sTargetFileName, sVersion2& ver)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
			TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
			pTranslate[i].wLanguage,
			pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		ver.fromStr(pVersion);
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate > 0;
}

bool GetProductVersion(const wchar_t* sTargetFileName, std::wstring& verstr)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
						TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"),
						pTranslate[i].wLanguage,
						pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		verstr = pVersion;
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate > 0;
}

bool GetProductVersion(const wchar_t* sTargetFileName, sVersion& ver)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
			TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"),
			pTranslate[i].wLanguage,
			pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		ver.fromStr(pVersion);
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate > 0;
}

bool GetProductVersion(const wchar_t* sTargetFileName, sVersion2& ver)
{
	DWORD nInfoSize = 0, dwHandle = 0;
	// 获取版本信息表大小
	nInfoSize = GetFileVersionInfoSize(sTargetFileName, &dwHandle);
	if (nInfoSize == 0)
	{
		return _T("");
	}
	// 分配缓冲区，读版本信息
	char* pInfoBuf = new char[nInfoSize];
	GetFileVersionInfo(sTargetFileName, 0, nInfoSize, pInfoBuf);
	// 信息表中语言信息结构体
	struct LANGANDCODEPAGE {
		WORD wLanguage;
		WORD wCodePage;
	}*pTranslate;

	UINT cbTranslate = 0;
	VerQueryValue(pInfoBuf, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&pTranslate, &cbTranslate);

	// Read the file description for each language and code page.
	for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
	{
		WCHAR SubBlock[256] = { 0 };
		wsprintf(SubBlock,
			TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"),
			pTranslate[i].wLanguage,
			pTranslate[i].wCodePage);

		WCHAR* pVersion = NULL;
		UINT nBytes = 0;
		VerQueryValue(pInfoBuf, SubBlock, (LPVOID*)&pVersion, &nBytes);
		ver.fromStr(pVersion);
		break;
	}

	delete[] pInfoBuf;

	return cbTranslate > 0;
}

static bool GetModuleFileVersion(const wchar_t* modulePath, DWORD& major, DWORD& minor, DWORD& build, DWORD& revision)
{
	DWORD handle = 0;
	DWORD verSize = GetFileVersionInfoSizeW(modulePath, &handle);
	if (verSize == 0) {
		return false;
	}

	std::vector<BYTE> verData(verSize);
	if (!GetFileVersionInfoW(modulePath, 0, verSize, verData.data())) {
		return false;
	}

	VS_FIXEDFILEINFO* pFileInfo = nullptr;
	UINT len = 0;
	if (!VerQueryValueW(verData.data(), L"\\", reinterpret_cast<void**>(&pFileInfo), &len)) {
		return false;
	}

	if (len == 0 || pFileInfo == nullptr) {
		return false;
	}

	major = HIWORD(pFileInfo->dwFileVersionMS);
	minor = LOWORD(pFileInfo->dwFileVersionMS);
	build = HIWORD(pFileInfo->dwFileVersionLS);
	revision = LOWORD(pFileInfo->dwFileVersionLS);
	return true;
}

// 检查当前进程所使用的 VC 运行库版本
int CheckVcRuntimeVersion(sVersion& Ver)
{
	// 1. 枚举当前进程模块，找 VC 运行库 DLL
	HMODULE hMods[1024];
	DWORD cbNeeded = 0;
	if (!EnumProcessModules(GetCurrentProcess(), hMods, sizeof(hMods), &cbNeeded)) {
		return -1;
	}
#ifdef _DEBUG
	const wchar_t* targetNames[] = {
		L"vcruntime140d.dll",
		L"vcruntime140_1d.dll",
		L"msvcp140d.dll",
		L"vcruntime140_2d.dll" // 覆盖更多可能
	};
#else
	const wchar_t* targetNames[] = {
		L"vcruntime140.dll",
		L"vcruntime140_1.dll",
		L"msvcp140.dll",
		L"vcruntime140_2.dll" // 覆盖更多可能
	};
#endif

	wchar_t path[MAX_PATH] = {};
	DWORD major = 0, minor = 0, build = 0, rev = 0;
	bool found = false;

	const UINT moduleCount = cbNeeded / sizeof(HMODULE);
	for (UINT i = 0; i < moduleCount && !found; ++i) {
		if (GetModuleFileNameW(hMods[i], path, MAX_PATH) == 0) {
			continue;
		}

		const wchar_t* fileName = wcsrchr(path, L'\\');
		fileName = fileName ? fileName + 1 : path;

		for (auto name : targetNames) {
			if (_wcsicmp(fileName, name) == 0) {
				if (GetModuleFileVersion(path, major, minor, build, rev)) {
					found = true;
				}
				break;
			}
		}
	}

	if (!found) {
		// 没找到运行库 DLL
		return -1;
	}

	Ver.Major = static_cast<uint8_t>(major);
	Ver.Mid = static_cast<uint8_t>(minor);
	Ver.Minor = static_cast<uint16_t>(build);

	return 1;
}

//SHBrowseForFolder可以用来得到一个用户选择的目录。
//可是有时候会有需要去指定一个初始目录, 比如希望上次用户选择的目录可以保存下来。这该如何去做？
//在BROWSEINFO结构体中提供了一个成员，这是一个指向函数的指针，通过这个回调函数，可以处理初始化的时候需要做的一些事情。

static TCHAR g_szLastSelDir[MAX_PATH];

static int   CALLBACK   BrowseCallbackProc(HWND   hwnd, UINT   msg, LPARAM   lp, LPARAM   pData)
{
	if (msg == BFFM_INITIALIZED)
	{
		::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)g_szLastSelDir);
	}
	return   0;
}

BOOL   BrowseDirectory(HWND   hwnd, LPTSTR   lpszDir)
{
	lstrcpyn(g_szLastSelDir, lpszDir, sizeof(g_szLastSelDir)/sizeof(TCHAR));

	BROWSEINFO   bi;
	bi.hwndOwner = hwnd;
	bi.pidlRoot = 0;
	bi.pszDisplayName = 0;
	bi.lpszTitle = L"Browse   Directory";
	bi.lpfn = BrowseCallbackProc;
	bi.lParam = 0;
	bi.ulFlags = BIF_STATUSTEXT | BIF_USENEWUI | BIF_RETURNONLYFSDIRS;

	LPITEMIDLIST   pidl;
	if (pidl = SHBrowseForFolder(&bi))
	{
		SHGetPathFromIDList(pidl, lpszDir);

		_tcscpy_s(g_szLastSelDir, MAX_PATH, lpszDir);
		return   TRUE;
	}
	return   FALSE;
}

#define		STM32_CRC_DEF   0x04c11db7      //STM32硬件CRC计数等式

uint32_t crc32update_f4soft(uint32_t crc, uint32_t* pBuffer, uint32_t len)
{
	uint32_t    xbit = 0;                //CRC计算式计算 扫描变量
	uint32_t    data = 0;                //当前用于CRC的数据缓存
	uint32_t     bits = 0;                    //位计数变量
	len /= 4;
	while (len--) {
		xbit = 0x80000000;
		data = *pBuffer++;
		for (bits = 0; bits < 32; bits++) {
			if (crc & 0x80000000) {   //CRC计算式计算	
				crc <<= 1;
				crc ^= STM32_CRC_DEF;
			}
			else {
				crc <<= 1;
			}

			if (data & xbit) {   //CRC计算式计算
				crc ^= STM32_CRC_DEF;
			}
			xbit >>= 1;
		}
	}
	return crc;
}

uint32_t crc32calc_f4soft(uint32_t* pBuffer, uint32_t len)
{
	return crc32update_f4soft(0xFFFFFFFF, pBuffer, len);
}

#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

int GetMotherboardAndBIOSInfo(std::wstring& Manufacturer, std::wstring& Model, std::wstring& BisoVer, bool needCoInit)
{
	HRESULT hres;
	if (needCoInit) { // MFC程序默认已经初始化了COM，所以这里可以选择不初始化。
		// 初始化COM.
		hres = CoInitializeEx(0, COINIT_MULTITHREADED);
		if (FAILED(hres)) {
			switch (hres) {
			case S_FALSE:
				std::wcout << L"CoInitializeEx again. " << std::endl;
				break;
			case RPC_E_CHANGED_MODE:
				std::wcout << L"CoInitializeEx failed for changed mode " << std::endl;
				break;
			default:
				std::wcout << L"CoInitializeEx failed with HRESULT: " << std::hex << hres << std::endl;
				break;
			}

			return -1; // 如果失败，直接返回
		}
	}

	hres = CoInitializeSecurity(
		NULL,
		-1,                          // COM认证的用户级别
		NULL,                        // 授权服务的ID列表
		NULL,                        // 保留
		RPC_C_AUTHN_LEVEL_DEFAULT,   // 默认的认证级别
		RPC_C_IMP_LEVEL_IMPERSONATE, // 模拟级别的认证
		NULL,                        // 身份验证服务的权限
		EOAC_NONE,                   // 额外的客户端权限
		NULL                         // 保留
	);

	if (FAILED(hres)) {
		if (needCoInit) CoUninitialize();
		return -2;
	}

	IWbemLocator* pLoc = NULL;
	hres = CoCreateInstance(
		CLSID_WbemLocator,
		0,
		CLSCTX_INPROC_SERVER,
		IID_IWbemLocator, (LPVOID*)&pLoc);

	if (FAILED(hres)) {
		if (needCoInit) CoUninitialize();
		return -3;
	}

	IWbemServices* pSvc = NULL;
	hres = pLoc->ConnectServer(
		_bstr_t(L"ROOT\\CIMV2"), // WMI命名空间
		NULL,                    // 用户名
		NULL,                    // 密码
		0,                       // 其他选项
		NULL,                    // 上下文
		0,                       // 启动标志
		0,                       // 保留
		&pSvc                    // IWbemServices proxy
	);

	if (FAILED(hres)) {
		pLoc->Release();
		if (needCoInit) CoUninitialize();
		return -4;
	}

	hres = CoSetProxyBlanket(
		pSvc,                        // WMI代理
		RPC_C_AUTHN_WINNT,           // 认证服务
		RPC_C_AUTHZ_NONE,            // 授权服务
		NULL,                        // 服务器原则名称
		RPC_C_AUTHN_LEVEL_CALL,      // 认证级别
		RPC_C_IMP_LEVEL_IMPERSONATE, // 模拟级别
		NULL,                        // 客户端身份
		EOAC_NONE                    // 代理能力
	);

	if (FAILED(hres)) {
		pSvc->Release();
		pLoc->Release();
		if (needCoInit) CoUninitialize();
		return -5;
	}

	IEnumWbemClassObject* pEnumerator = NULL;
	hres = pSvc->ExecQuery(
		bstr_t("WQL"),
		bstr_t("SELECT * FROM Win32_BaseBoard"), // 查询主板信息
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		NULL,
		&pEnumerator);

	if (SUCCEEDED(hres)) {
		IWbemClassObject* pclsObj = NULL;
		ULONG uReturn = 0;

		while (pEnumerator) {
			HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
				&pclsObj, &uReturn);

			if (0 == uReturn) break;

			VARIANT vtProp;
			hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0);
			Manufacturer = vtProp.bstrVal; // 获取主板制造商
			VariantClear(&vtProp);

			hr = pclsObj->Get(L"Product", 0, &vtProp, 0, 0);
			Model = vtProp.bstrVal; // 获取主板型号
			VariantClear(&vtProp);

			pclsObj->Release();
		}
	}
	else {
		pSvc->Release();
		pLoc->Release();
		if (needCoInit) CoUninitialize();
		return -6;
	}

	hres = pSvc->ExecQuery(
		bstr_t("WQL"),
		bstr_t("SELECT * FROM Win32_BIOS"), // 查询BIOS信息
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		NULL,
		&pEnumerator);

	if (SUCCEEDED(hres)) {
		IWbemClassObject* pclsObj = NULL;
		ULONG uReturn = 0;

		while (pEnumerator) {
			HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
				&pclsObj, &uReturn);

			if (0 == uReturn) break;

			VARIANT vtProp;
			hr = pclsObj->Get(L"SMBIOSBIOSVersion", 0, &vtProp, 0, 0);
			BisoVer = vtProp.bstrVal; // 获取BIOS版本
			VariantClear(&vtProp);

			pclsObj->Release();
		}
	}
	else {
		pSvc->Release();
		pLoc->Release();
		if (needCoInit) CoUninitialize();
		return -7;
	}

	// 清理
	pSvc->Release();
	pLoc->Release();
	pEnumerator->Release();
	if (needCoInit)CoUninitialize();
	return 0; // 成功
}


// 在binPath目录下找vc_redist.x64*.exe，获取版本最高的那个
bool installVcRuntime(const fs::path& binPath, const sVersion& minVer)
{
	fs::path highestRedist;
	sVersion highestVer = minVer; // 初始为编译版本

	if (fs::exists(binPath) && fs::is_directory(binPath)) {
		for (const auto& entry : fs::directory_iterator(binPath)) {
			if (entry.is_regular_file()) {
				std::wstring filename = entry.path().filename().wstring();
				// 匹配 vc_redist.x64 开头的 .exe 文件
				if (filename.find(L"vc_redist.x64") == 0 &&
					entry.path().extension() == L".exe") {

					sVersion fileVer;
					if (GetFileVersion(entry.path().wstring().c_str(), fileVer)) {
						if (fileVer > highestVer) {
							highestVer = fileVer;
							highestRedist = entry.path();
						}
					}
				}
			}
		}
	}

	std::wstring message = L"检测到VC++运行库版本过低，建议更新到14.44及以上版本，以保证软件稳定运行。\n";
	if (!highestRedist.empty()) {
		message += fmt::format(L"\n在软件目录下找到运行库安装包(版本{}.{}.{})：\n{}\n\n是否立即安装？\n\n",
			highestVer.Major, highestVer.Mid, highestVer.Minor, highestRedist.filename().wstring());
		message += L"点击【是】立即安装，点击【否】退出程序手动下载安装。";

		int result = MessageBox(nullptr, message.c_str(), L"运行库版本过低", MB_ICONWARNING | MB_YESNO);
		if (result == IDYES) {
			// 启动安装程序并等待其执行完成
			SHELLEXECUTEINFOW sei = {};
			sei.cbSize = sizeof(sei);
			sei.fMask = SEE_MASK_NOCLOSEPROCESS;
			sei.hwnd = nullptr;
			sei.lpVerb = L"open";
			sei.lpFile = highestRedist.c_str();
			sei.lpParameters = L"/install /quiet /norestart";
			sei.lpDirectory = nullptr;
			sei.nShow = SW_SHOWNORMAL;

			if (ShellExecuteExW(&sei)) {
				if (sei.hProcess != nullptr) {
					// 等待安装程序执行完
					WaitForSingleObject(sei.hProcess, INFINITE);
					CloseHandle(sei.hProcess);
				}

				MessageBox(nullptr,
					L"VC++ 运行库安装完成，为保证软件稳定运行，建议重启电脑后再使用本软件。",
					L"安装完成",
					MB_ICONINFORMATION | MB_OK);
				return true;
			}
			else {
				MessageBox(nullptr,
					L"无法启动 VC++ 运行库安装程序，请手动在 bin 目录或公司钉盘中运行安装包。",
					L"安装失败",
					MB_ICONERROR | MB_OK);
			}
		}
		else {

		}
	}
	else {
		message += L"请在公司钉盘\"软件发布 / 运行库\"目录下载安装最新的VC运行库。\n"
			L"或微软下载：https://aka.ms/vc14/vc_redist.x64.exe";
		MessageBox(nullptr, message.c_str(), L"运行库版本过低", MB_ICONWARNING);

	}
	return false;
}