Files
GdCpp12/source/Tools.cpp

714 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}