714 lines
18 KiB
C++
714 lines
18 KiB
C++
#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;
|
||
} |