抛弃GdCpp*.dll/pdb历史重新建库。libhv和Sqlite的dll保留
This commit is contained in:
121
source/CDesktop.cpp
Normal file
121
source/CDesktop.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "pch.h"
|
||||
#include "CDesktop.h"
|
||||
#include "GdCpp.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <wingdi.h>
|
||||
|
||||
CDesktop::CDesktop()
|
||||
{
|
||||
INT iNumber = 0;
|
||||
BOOL bFlag = TRUE;
|
||||
|
||||
DISPLAY_DEVICE dd;
|
||||
ZeroMemory(&dd, sizeof(dd));
|
||||
dd.cb = sizeof(dd);
|
||||
|
||||
|
||||
DEVMODE devMode;
|
||||
ZeroMemory(&devMode, sizeof(devMode));
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
|
||||
// FixMe:这里只能获取到显卡连接的显示器,获取不到USB-C显示器
|
||||
// 而且双显示器分辨率不同时,有时第二个显示器的宽、高变大。
|
||||
do
|
||||
{
|
||||
bFlag = EnumDisplayDevices(NULL, iNumber, &dd, 0);
|
||||
bFlag = bFlag && EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
|
||||
if (bFlag) {
|
||||
RECT r;
|
||||
r.left= devMode.dmPosition.x;
|
||||
r.top = devMode.dmPosition.y;
|
||||
r.right = r.left + devMode.dmPelsWidth;
|
||||
r.bottom = r.top + devMode.dmPelsHeight;
|
||||
screen.push_back(r);
|
||||
iNumber += 1;
|
||||
}
|
||||
} while (bFlag);
|
||||
}
|
||||
|
||||
void CDesktop::TestDesktop()
|
||||
{
|
||||
auto *desktop = new CDesktop();
|
||||
auto num = desktop->screen.size();
|
||||
if (num == 0) {
|
||||
alog->error("No Screen found!");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
auto &s = desktop->screen[i];
|
||||
alog->info("Screen {}: {}, {}, {}, {}", s.left, s.top, s.right - s.left, s.bottom - s.top);
|
||||
}
|
||||
delete desktop;
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <ShellScalingApi.h>
|
||||
// 链接Shcore.lib
|
||||
#pragma comment(lib, "Shcore.lib")
|
||||
|
||||
//BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
//{
|
||||
// MONITORINFOEX monitorInfo;
|
||||
// monitorInfo.cbSize = sizeof(MONITORINFOEX);
|
||||
// GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
//
|
||||
// UINT dpiX, dpiY;
|
||||
// if (GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK) {
|
||||
// std::cout << "Monitor " << monitorInfo.szDevice << " DPI: " << dpiX << std::endl;
|
||||
// }
|
||||
//
|
||||
// return TRUE;
|
||||
//}
|
||||
|
||||
// 回调函数用于获取每个显示器的信息
|
||||
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
MONITORINFOEX monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
|
||||
DISPLAY_DEVICE displayDevice;
|
||||
displayDevice.cb = sizeof(DISPLAY_DEVICE);
|
||||
EnumDisplayDevices(monitorInfo.szDevice, 0, &displayDevice, 0);
|
||||
|
||||
std::wcout << L"Display Device Name: " << displayDevice.DeviceName << std::endl;
|
||||
std::wcout << L"Monitor Name: " << monitorInfo.szDevice << std::endl;
|
||||
std::cout << "Monitor Resolution: " << monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left << "x"
|
||||
<< monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top << std::endl;
|
||||
std::cout << "Monitor Position: (" << monitorInfo.rcMonitor.left << ", " << monitorInfo.rcMonitor.top << ")"
|
||||
<< std::endl;
|
||||
|
||||
// DPI信息获取
|
||||
UINT dpiX, dpiY;
|
||||
if (GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK) {
|
||||
std::cout << "Monitor DPI: " << "x=" << dpiX << ", y=" << dpiY << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
void TestGetDpi() {
|
||||
// 获取系统的DPI
|
||||
int dpiX = GetDpiForSystem();
|
||||
std::cout << "System DPI: " << dpiX << std::endl;
|
||||
|
||||
// 获取主显示器桌面的DPI
|
||||
HWND hWndDesktop = GetDesktopWindow();
|
||||
if (hWndDesktop != NULL) {
|
||||
HMONITOR hMonitor = MonitorFromWindow(hWndDesktop, MONITOR_DEFAULTTONEAREST);
|
||||
UINT dpiX, dpiY;
|
||||
if (GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK) {
|
||||
std::cout << "Desktop DPI: " << dpiX << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// 遍历所有显示器的DPI
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
|
||||
}
|
||||
69
source/CLang.cpp
Normal file
69
source/CLang.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "pch.h"
|
||||
#include "CLang.h"
|
||||
|
||||
// 全局共用的当前语言实例
|
||||
CLang gLang;
|
||||
|
||||
void to_json(jsonobj& j, const CLang & p)
|
||||
{
|
||||
if (p.Lang >= 0 && p.Lang < CLang::LangNum) {
|
||||
j["Language"] = p.LangStr[p.Lang];
|
||||
}
|
||||
else {
|
||||
j["Language"] = p.LangStr[CLang::zh];
|
||||
}
|
||||
|
||||
}
|
||||
void from_json(const jsonobj& j, CLang &p)
|
||||
{
|
||||
CLang::eLang lang;
|
||||
readEnum(j, "Language", lang, CLang::zh, p.LangStr, CLang::LangNum);
|
||||
p.Lang = lang;
|
||||
}
|
||||
|
||||
///language在参数文件里的字符串转成enum
|
||||
CLang::eLang CLang::fromStr(const char* str)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < LangNum; i++) {
|
||||
if (strcmp(str,LangStr[i])==0) {
|
||||
return eLang(i);
|
||||
}
|
||||
}
|
||||
//返回缺省
|
||||
return eLang::zh;
|
||||
}
|
||||
|
||||
|
||||
/// 用于json文件的英文字符串
|
||||
const char* CLang::LangStr[LangNum] =
|
||||
{
|
||||
"zh",
|
||||
"en",
|
||||
"vn",
|
||||
"th",
|
||||
"sp",
|
||||
"jp",
|
||||
"ru",
|
||||
};
|
||||
|
||||
/// 用于UI显示的中英文字符串
|
||||
const wchar_t* CLang::LangWStr[LangNum] = {
|
||||
L"简体中文",
|
||||
L"English",
|
||||
L"Vietnamese",
|
||||
L"Thai",
|
||||
L"Español",
|
||||
L"日本語",
|
||||
L"русский",
|
||||
};
|
||||
|
||||
const wchar_t* CLang::LangWStrCn[LangNum] = {
|
||||
L"简体中文",
|
||||
L"英语",
|
||||
L"越南语",
|
||||
L"泰语",
|
||||
L"西班牙语",
|
||||
L"日语",
|
||||
L"俄语",
|
||||
};
|
||||
23
source/CSQLite/CSQLiteColumn.cpp
Normal file
23
source/CSQLite/CSQLiteColumn.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file CSQLiteColumn.cpp
|
||||
* @ingroup CSQLite
|
||||
* @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#include "pch.h"
|
||||
#include "CSQLite/CSQLiteColumn.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// Standard std::ostream inserter
|
||||
std::ostream& operator<<(std::ostream& aStream, const CSQLiteColumn& aColumn)
|
||||
{
|
||||
aStream.write(aColumn.getText(), aColumn.getBytes());
|
||||
return aStream;
|
||||
}
|
||||
105
source/CSQLite/CSQLiteDB.cpp
Normal file
105
source/CSQLite/CSQLiteDB.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "pch.h"
|
||||
#include "CSQLite/CSQLite.h"
|
||||
#include "aLog.h"
|
||||
|
||||
int CSQLiteDB::open(const char* apFilename, const int aFlags) noexcept
|
||||
{
|
||||
mFilename = apFilename;
|
||||
dbErrCode = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, nullptr);
|
||||
if (SQLITE_OK != dbErrCode)
|
||||
{
|
||||
dbErrMsg = sqlite3_errmsg(mpSQLite);
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return dbErrCode;
|
||||
}
|
||||
|
||||
int CSQLiteDB::open(const std::string &apFilename, const int aFlags) noexcept
|
||||
{
|
||||
mFilename = apFilename;
|
||||
dbErrCode = sqlite3_open_v2(apFilename.c_str(), &mpSQLite, aFlags, nullptr);
|
||||
if (SQLITE_OK != dbErrCode)
|
||||
{
|
||||
dbErrMsg = sqlite3_errmsg(mpSQLite);
|
||||
sqlite3_close(mpSQLite); // close is required even in case of error on opening
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return dbErrCode;
|
||||
}
|
||||
|
||||
int CSQLiteDB::openInRam(const char* apFilename)
|
||||
{
|
||||
UNUSED(apFilename);
|
||||
return dbErrCode;
|
||||
|
||||
}
|
||||
|
||||
int CSQLiteDB::close()
|
||||
{
|
||||
if(bInTransaction)
|
||||
{
|
||||
// 没有主动Commit,就Rollback();
|
||||
Rollback();
|
||||
}
|
||||
bInTransaction = false;
|
||||
int ret =0;
|
||||
if(mpSQLite){
|
||||
ret = sqlite3_close(mpSQLite);
|
||||
|
||||
if(SQLITE_OK != ret){
|
||||
switch (ret) {
|
||||
case SQLITE_MISUSE:
|
||||
alog->error("CSQLiteDB::close(): Library used incorrectly {}, {}", ret, mFilename);
|
||||
break;
|
||||
case SQLITE_BUSY:
|
||||
alog->error("CSQLiteDB::close(): database is locked {}, {}", ret, mFilename);
|
||||
break;
|
||||
default:
|
||||
alog->error("CSQLiteDB::close(): database close error {}, {}", ret, mFilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mpSQLite = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
|
||||
*
|
||||
* This is useful in multithreaded program to handle case where a table is locked for writting by a thread.
|
||||
* Any other thread cannot access the table and will receive a SQLITE_BUSY error:
|
||||
* setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
|
||||
* Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
|
||||
* Default busy timeout is 0ms.
|
||||
*
|
||||
* @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY
|
||||
*
|
||||
* @throw SQLite::Exception in case of error
|
||||
*/
|
||||
void CSQLiteDB::setBusyTimeout(const int aBusyTimeoutMs)
|
||||
{
|
||||
const int ret = sqlite3_busy_timeout(mpSQLite, aBusyTimeoutMs);
|
||||
check(ret);
|
||||
}
|
||||
|
||||
// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
|
||||
int CSQLiteDB::exec(const char* apQueries)
|
||||
{
|
||||
const int ret = sqlite3_exec(mpSQLite, apQueries, nullptr, nullptr, nullptr);
|
||||
check(ret);
|
||||
|
||||
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
|
||||
return sqlite3_changes(mpSQLite);
|
||||
}
|
||||
|
||||
// Shortcut to test if a table exists.
|
||||
bool CSQLiteDB::tableExists(const char* apTableName)
|
||||
{
|
||||
CSQLiteStatement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
|
||||
query.bind(1, apTableName);
|
||||
(void)query.executeStep(); // Cannot return false, as the above query always return a result
|
||||
return (1 == query.getColumn(0).getInt());
|
||||
}
|
||||
199
source/CSQLite/CSQLiteStatement.cpp
Normal file
199
source/CSQLite/CSQLiteStatement.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* @file Statement.cpp
|
||||
* @ingroup CSQLite
|
||||
* @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#include "pch.h"
|
||||
#include "CSQLite/CSQLite.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
|
||||
// Compile and register the SQL query for the provided SQLite Database Connection
|
||||
CSQLiteStatement::CSQLiteStatement(CSQLiteDB &aDatabase, const char* apQuery) :
|
||||
mQuery(apQuery),
|
||||
mStmtPtr(std::make_shared<_Statement>(aDatabase.mpSQLite, mQuery)), // prepare the SQL query, and ref count (needs Database friendship)
|
||||
mColumnCount(0),
|
||||
mbHasRow(false),
|
||||
mbDone(false)
|
||||
{
|
||||
mColumnCount = sqlite3_column_count(*mStmtPtr);
|
||||
}
|
||||
|
||||
// Compile and register the SQL query for the provided SQLite Database Connection
|
||||
CSQLiteStatement::CSQLiteStatement(CSQLiteDB &aDatabase, const std::string& aQuery) :
|
||||
mQuery(aQuery),
|
||||
mStmtPtr(std::make_shared<_Statement>(aDatabase.mpSQLite, mQuery)), // prepare the SQL query, and ref count (needs Database friendship)
|
||||
mColumnCount(0),
|
||||
mbHasRow(false),
|
||||
mbDone(false)
|
||||
{
|
||||
mColumnCount = sqlite3_column_count(*mStmtPtr);
|
||||
}
|
||||
|
||||
CSQLiteStatement::CSQLiteStatement(CSQLiteStatement&& aStatement) noexcept :
|
||||
mQuery(std::move(aStatement.mQuery)),
|
||||
mStmtPtr(std::move(aStatement.mStmtPtr)),
|
||||
mColumnCount(aStatement.mColumnCount),
|
||||
mbHasRow(aStatement.mbHasRow),
|
||||
mbDone(aStatement.mbDone)
|
||||
{
|
||||
aStatement.mColumnCount = 0;
|
||||
aStatement.mbHasRow = false;
|
||||
aStatement.mbDone = false;
|
||||
}
|
||||
|
||||
// Finalize and unregister the SQL query from the SQLite Database Connection.
|
||||
CSQLiteStatement::~CSQLiteStatement()
|
||||
{
|
||||
// the finalization will be done by the destructor of the last shared pointer
|
||||
}
|
||||
|
||||
// Execute a step of the query to fetch one row of results
|
||||
bool CSQLiteStatement::executeStep()
|
||||
{
|
||||
const int ret = tryExecuteStep();
|
||||
if ((SQLITE_ROW != ret) && (SQLITE_DONE != ret)) // on row or no (more) row ready, else it's a problem
|
||||
{
|
||||
if (ret == sqlite3_errcode(*mStmtPtr))
|
||||
{
|
||||
throw CSQLiteException(*mStmtPtr, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CSQLiteException("Statement needs to be reseted", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return mbHasRow; // true only if one row is accessible by getColumn(N)
|
||||
}
|
||||
|
||||
// Execute a one-step query with no expected result
|
||||
int CSQLiteStatement::exec()
|
||||
{
|
||||
const int ret = tryExecuteStep();
|
||||
if (SQLITE_DONE != ret) // the statement has finished executing successfully
|
||||
{
|
||||
if (SQLITE_ROW == ret)
|
||||
{
|
||||
throw CSQLiteException("exec() does not expect results. Use executeStep.");
|
||||
}
|
||||
else if (ret == sqlite3_errcode(*mStmtPtr))
|
||||
{
|
||||
throw CSQLiteException(*mStmtPtr, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CSQLiteException("Statement needs to be reseted", ret);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
|
||||
return sqlite3_changes(*mStmtPtr);
|
||||
}
|
||||
|
||||
int CSQLiteStatement::tryExecuteStep() noexcept
|
||||
{
|
||||
if (false == mbDone)
|
||||
{
|
||||
const int ret = sqlite3_step(*mStmtPtr);
|
||||
if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
|
||||
{
|
||||
mbHasRow = true;
|
||||
}
|
||||
else if (SQLITE_DONE == ret) // no (more) row ready : the query has finished executing
|
||||
{
|
||||
mbHasRow = false;
|
||||
mbDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mbHasRow = false;
|
||||
mbDone = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Statement needs to be reseted !
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the named assigned to the specified result column (potentially aliased)
|
||||
const char* CSQLiteStatement::getColumnName(const int aIndex) const
|
||||
{
|
||||
checkIndex(aIndex);
|
||||
return sqlite3_column_name(*mStmtPtr, aIndex);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
// Return the named assigned to the specified result column (potentially aliased)
|
||||
const char* CSQLiteStatement::getColumnOriginName(const int aIndex) const
|
||||
{
|
||||
checkIndex(aIndex);
|
||||
return sqlite3_column_origin_name(*mStmtPtr, aIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return the index of the specified (potentially aliased) column name
|
||||
int CSQLiteStatement::getColumnIndex(const char* apName) const
|
||||
{
|
||||
// Build the map of column index by name on first call
|
||||
if (mColumnNames.empty())
|
||||
{
|
||||
for (int i = 0; i < mColumnCount; ++i)
|
||||
{
|
||||
const char* pName = sqlite3_column_name(*mStmtPtr, i);
|
||||
mColumnNames[pName] = i;
|
||||
}
|
||||
}
|
||||
|
||||
const TColumnNames::const_iterator iIndex = mColumnNames.find(apName);
|
||||
if (iIndex == mColumnNames.end())
|
||||
{
|
||||
std::string errStr = "Unknown column name:";
|
||||
errStr += apName;
|
||||
throw CSQLiteException(errStr);
|
||||
}
|
||||
|
||||
return (*iIndex).second;
|
||||
}
|
||||
|
||||
int CSQLiteStatement::getBindParameterCount() const noexcept
|
||||
{
|
||||
return sqlite3_bind_parameter_count(*mStmtPtr);
|
||||
}
|
||||
|
||||
// Return the numeric result code for the most recent failed API call (if any).
|
||||
int CSQLiteStatement::getErrorCode() const noexcept // nothrow
|
||||
{
|
||||
return sqlite3_errcode(*mStmtPtr);
|
||||
}
|
||||
|
||||
// Return the extended numeric result code for the most recent failed API call (if any).
|
||||
int CSQLiteStatement::getExtendedErrorCode() const noexcept // nothrow
|
||||
{
|
||||
return sqlite3_extended_errcode(*mStmtPtr);
|
||||
}
|
||||
|
||||
// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
|
||||
const char* CSQLiteStatement::getErrorMsg() const noexcept // nothrow
|
||||
{
|
||||
return sqlite3_errmsg(*mStmtPtr);
|
||||
}
|
||||
|
||||
// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
|
||||
std::string CSQLiteStatement::getExpandedSQL() {
|
||||
char* expanded = sqlite3_expanded_sql(*mStmtPtr);
|
||||
std::string expandedString(expanded);
|
||||
sqlite3_free(expanded);
|
||||
return expandedString;
|
||||
}
|
||||
|
||||
59
source/CSQLite/CSQLiteTransaction.cpp
Normal file
59
source/CSQLite/CSQLiteTransaction.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file CSQLiteTransaction.cpp
|
||||
* @ingroup SQLiteCpp
|
||||
* @brief A CSQLiteTransaction is way to group multiple SQL statements into an atomic secured operation.
|
||||
*
|
||||
* Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#include "pch.h"
|
||||
#include "CSQLite/CSQLiteTransaction.h"
|
||||
|
||||
#include "CSQLite/CSQLiteDB.h"
|
||||
|
||||
// Begins the SQLite CSQLiteTransaction
|
||||
CSQLiteTransaction::CSQLiteTransaction(CSQLiteDB & aDatabase, bool startnow) :
|
||||
mDatabase(aDatabase),
|
||||
mbCommited(false)
|
||||
{
|
||||
if(startnow)
|
||||
{
|
||||
mDatabase.exec("BEGIN");
|
||||
mbCommited = false;
|
||||
}else{
|
||||
mbCommited = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Safely rollback the CSQLiteTransaction if it has not been committed.
|
||||
CSQLiteTransaction::~CSQLiteTransaction()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
try
|
||||
{
|
||||
mDatabase.exec("ROLLBACK");
|
||||
}
|
||||
catch (CSQLiteException&)
|
||||
{
|
||||
// Never throw an exception in a destructor: error if already rollbacked, but no harm is caused by this.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit the CSQLiteTransaction.
|
||||
void CSQLiteTransaction::commit()
|
||||
{
|
||||
if (false == mbCommited)
|
||||
{
|
||||
mDatabase.exec("COMMIT");
|
||||
mbCommited = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CSQLiteException("CSQLiteTransaction already commited.");
|
||||
}
|
||||
}
|
||||
|
||||
76
source/CTic.cpp
Normal file
76
source/CTic.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "pch.h"
|
||||
#include "CTic.h"
|
||||
|
||||
// 高精度定时器的频率,单位Hz,调用Init()确定
|
||||
// 目前测到频率在2.5M - 10M
|
||||
int64_t CTic::Freq = 0;
|
||||
// 高精度定时器的频率,单位kHz,调用Init()确定
|
||||
int64_t CTic::Freq_1k = 0;
|
||||
int64_t CTic::Freq_10k = 0;
|
||||
int64_t CTic::Freq_100k = 0;
|
||||
int64_t CTic::Freq_M10 =0; //0.1Hz
|
||||
int64_t CTic::Freq_M100 =0; //0.01Hz
|
||||
// 记录启动软件时的时间戳
|
||||
int64_t CTic::AppStartTick = 0;
|
||||
|
||||
|
||||
bool CTic::Init()
|
||||
{
|
||||
if (Freq == 0) { // 确保只调用一次,避免多次调用后AppStartTick发生变化
|
||||
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&Freq));
|
||||
QueryCnt(AppStartTick);
|
||||
}
|
||||
Freq_1k = Freq / 1000;
|
||||
Freq_10k = Freq / 10000;
|
||||
Freq_100k = Freq / 100000;
|
||||
|
||||
Freq_M10 = Freq * 10;
|
||||
Freq_M100 = Freq * 100;
|
||||
|
||||
bool ok = (Freq_100k * 100000 == Freq);
|
||||
_ASSERT_EXPR(ok, "Freq_100k * 100000 == Freq"); // 必须满足频率是100k的倍数
|
||||
return ok;
|
||||
}
|
||||
|
||||
int64_t CAvgDiffTick::add(int64_t newvalue)
|
||||
{
|
||||
if (!Buf) return 0;
|
||||
if (Cnt == 0) {
|
||||
index = 0;
|
||||
_Avg = 0;
|
||||
}
|
||||
else if (Cnt < N) {
|
||||
_Avg = int((newvalue - Buf[0]) / Cnt);
|
||||
}
|
||||
else {
|
||||
if (index >= N) index = 0;
|
||||
_Avg = int(((newvalue - Buf[index]) + N / 2) / N);
|
||||
}
|
||||
Buf[index] = newvalue;
|
||||
index++;
|
||||
Cnt++;
|
||||
return _Avg;
|
||||
}
|
||||
|
||||
// 测试代码
|
||||
void CAvgDiffTick::Test1(int avgnum)
|
||||
{
|
||||
CAvgDiffTick Avg(avgnum);
|
||||
int64_t x = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
x += 1000 + rand() % 10 - 5;
|
||||
std::cout << Avg.add(x) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CAvgDiffTick::Test2(int avgnum)
|
||||
{
|
||||
CAvgDiffTick Avg(avgnum);
|
||||
int64_t x = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
std::cout << Avg.add(Avg.appRun_100us()) << std::endl;
|
||||
Sleep(100);
|
||||
}
|
||||
}
|
||||
35
source/CWinErr.cpp
Normal file
35
source/CWinErr.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "pch.h"
|
||||
#include "CWinErr.h"
|
||||
#include <windows.h>
|
||||
#include "aLog.h"
|
||||
|
||||
|
||||
wchar_t* getWinErrString(DWORD winErrCode)
|
||||
{
|
||||
wchar_t* lpMsgBuf = nullptr;
|
||||
|
||||
auto nRet = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
nullptr,
|
||||
winErrCode,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0, nullptr);
|
||||
if(nRet ==0) {
|
||||
LocalFree(lpMsgBuf);
|
||||
lpMsgBuf = nullptr;
|
||||
}
|
||||
return lpMsgBuf;
|
||||
}
|
||||
|
||||
DWORD getWinErrString(DWORD winErrCode, wchar_t* lpMsgBuf, DWORD nSize)
|
||||
{
|
||||
return FormatMessage(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
nullptr,
|
||||
winErrCode,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
lpMsgBuf,
|
||||
nSize, nullptr);
|
||||
|
||||
}
|
||||
202
source/IpHelper.cpp
Normal file
202
source/IpHelper.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "pch.h"
|
||||
#include "IpHelper.h"
|
||||
#include <IPTypes.h>
|
||||
#include <IPHlpApi.h>
|
||||
|
||||
#pragma comment(lib,"Iphlpapi.lib")
|
||||
#pragma comment (lib,"ws2_32.lib") //加载 ws2_32.dll
|
||||
|
||||
std::vector<std::wstring> CAdapterList::gExcludedList;
|
||||
|
||||
//枚举网卡列表
|
||||
//void CAdapterList::Enum(bool excludelist, bool includelocalhost)
|
||||
//{
|
||||
// //得到结构体大小
|
||||
// unsigned long stSize = 0;
|
||||
// int nRel = GetAdaptersInfo(0, &stSize);
|
||||
//
|
||||
// //PIP_ADAPTER_INFO结构体指针存储本机网卡信息
|
||||
// PIP_ADAPTER_INFO allIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
|
||||
// // 指向第一条
|
||||
// PIP_ADAPTER_INFO pIpAdapterInfo = allIpAdapterInfo;
|
||||
//
|
||||
// nRel = GetAdaptersInfo(allIpAdapterInfo, &stSize);
|
||||
//
|
||||
// if (ERROR_SUCCESS == nRel)
|
||||
// {
|
||||
// //输出网卡信息
|
||||
// //可能有多网卡,因此通过循环去判断
|
||||
// while (pIpAdapterInfo)
|
||||
// {
|
||||
// sAdapter s(pIpAdapterInfo->AdapterName, pIpAdapterInfo->Description);
|
||||
// bool skip = false;
|
||||
// if(excludelist) {
|
||||
// for (auto& e : Excluded) {
|
||||
// if (s.Description._Starts_with(e)) {
|
||||
// skip = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!skip) {
|
||||
// d.push_back(s);
|
||||
// auto last = d.rbegin();
|
||||
// //可能网卡有多IP,因此通过循环去判断
|
||||
// IP_ADDR_STRING* pIpAddrString = &(pIpAdapterInfo->IpAddressList);
|
||||
// do
|
||||
// {
|
||||
// last->IpAddr.push_back({ pIpAddrString->IpAddress.String, pIpAddrString->IpMask.String });
|
||||
// pIpAddrString = pIpAddrString->Next;
|
||||
// } while (pIpAddrString);
|
||||
//
|
||||
// }
|
||||
// pIpAdapterInfo = pIpAdapterInfo->Next;
|
||||
// }
|
||||
// }
|
||||
// if (includelocalhost) {
|
||||
// d.push_back({ "", "localhost" });
|
||||
// auto last = d.rbegin();
|
||||
// last->IpAddr.push_back({ "127.0.0.1", "255.255.255.0" });
|
||||
// }
|
||||
//
|
||||
//
|
||||
// //释放内存空间
|
||||
//
|
||||
// delete[] allIpAdapterInfo;
|
||||
//}
|
||||
|
||||
|
||||
void CAdapterList::Enum(uint32_t exclude_flag)
|
||||
{
|
||||
d.clear();
|
||||
|
||||
std::vector<std::wstring> localExcluedList;
|
||||
if(exclude_flag) _SetExcludedList(localExcluedList, exclude_flag);
|
||||
|
||||
DWORD dwRetVal = 0;
|
||||
|
||||
LPVOID lpMsgBuf = NULL;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
ULONG outBufLen = 16384; // Allocate a 16 KB buffer to start with,不够可以递增
|
||||
ULONG Iterations = 0; // 递增次数
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
||||
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
|
||||
|
||||
do {
|
||||
pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
|
||||
if (pAddresses == NULL) {
|
||||
//printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
|
||||
return;
|
||||
}
|
||||
/* Set to AF_INET to specify the IPv4 address family */
|
||||
// 不要返回 IPv6 任何广播地址。不要返回多播地址。
|
||||
dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, pAddresses, &outBufLen);
|
||||
|
||||
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAddresses);
|
||||
pAddresses = NULL;
|
||||
Iterations++;
|
||||
outBufLen += 16384;//增加缓冲区
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3));
|
||||
|
||||
if (dwRetVal == NO_ERROR) {
|
||||
pCurrAddresses = pAddresses;
|
||||
while (pCurrAddresses) {
|
||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||
if (pUnicast != NULL) {
|
||||
bool skip = false;
|
||||
|
||||
std::wstring desc(pCurrAddresses->Description);
|
||||
// 比对全局排除列表
|
||||
for (auto& e : gExcludedList) {
|
||||
if (desc._Starts_with(e)) { skip = true; break; }
|
||||
}
|
||||
// 比对标志位添加的排除列表
|
||||
if (!skip && exclude_flag) {
|
||||
for (auto& e : localExcluedList) {
|
||||
if (desc._Starts_with(e)) { skip = true; break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
sAdapter s;
|
||||
s.Description = pCurrAddresses->Description;
|
||||
s.FriendlyName = pCurrAddresses->FriendlyName;
|
||||
s.OperStatus = pCurrAddresses->OperStatus;
|
||||
|
||||
//printf("%d, %S\n", s.OperStatus, pCurrAddresses->FriendlyName);
|
||||
|
||||
while (pUnicast != NULL) {
|
||||
if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) {//限制IPV4
|
||||
ipv4addr addr(pUnicast->Address.lpSockaddr);
|
||||
// 保留最后一个ip
|
||||
// 如果网卡设置了固定IP但未连接,会出现两个ip,第一个是169.254.x.x,第2个才是设置的ip
|
||||
s.IpAddr=addr;
|
||||
//printf("\tIPv4 Address: %s\n", addr.ipStr().c_str());
|
||||
}
|
||||
pUnicast = pUnicast->Next;
|
||||
}
|
||||
d.push_back(s);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//printf("\tNo unicast addresses found for this adapter\n");
|
||||
}
|
||||
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
}
|
||||
//else {
|
||||
// printf("Call to GetAdaptersAddresses failed with error: %d\n", dwRetVal);
|
||||
// if (dwRetVal == ERROR_NO_DATA) {
|
||||
// printf("\tNo addresses were found for the requested parameters\n");
|
||||
// }
|
||||
// else {
|
||||
// if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
// FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
// NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
// // Default language
|
||||
// (char*)&lpMsgBuf, 0, NULL)) {
|
||||
// printf("\tError: %s", (char*)lpMsgBuf);
|
||||
// LocalFree(lpMsgBuf);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
if (pAddresses) {
|
||||
free(pAddresses);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 要求已经执行过WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
int getIPFromHostname(const char* hostname, std::vector<ipv4addr>& foundIp)
|
||||
{
|
||||
struct addrinfo* result_list = NULL;
|
||||
struct addrinfo hints = {};
|
||||
hints.ai_family = AF_INET; // IPv4
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
int result = getaddrinfo(hostname, nullptr, &hints, &result_list);
|
||||
if (result != 0) {
|
||||
//std::cerr << "getaddrinfo failed: " << gai_strerror(result) << std::endl;
|
||||
//WSACleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (struct addrinfo* res = result_list; res != NULL; res = res->ai_next) {
|
||||
struct sockaddr_in* ip4 = (struct sockaddr_in*)res->ai_addr;
|
||||
ipv4addr addr(ip4);
|
||||
foundIp.push_back(addr);
|
||||
}
|
||||
|
||||
freeaddrinfo(result_list);
|
||||
return int(foundIp.size());
|
||||
}
|
||||
391
source/Mem/CImageBuf.cpp
Normal file
391
source/Mem/CImageBuf.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "Mem\CImageBuf.h"
|
||||
#include <Windows.h>
|
||||
#include "GdCpp.h"
|
||||
//#include "json.h"
|
||||
#include "aLog.h"
|
||||
#include <cstdio> // FILE, _wfopen_s, fwrite, fclose
|
||||
|
||||
// 颜色类型与BPP的对应关系
|
||||
std::map<uint32_t, uint32_t> sImageInfo::MapColor2BBP;
|
||||
// 颜色类型与BPP的对应关系
|
||||
std::map<uint32_t, uint32_t> sImageInfo::MapBBP2Color;
|
||||
|
||||
static RGBQUAD bmiColors[256] = { 0 };
|
||||
|
||||
bool CImageBuf::saveBMP(const wchar_t* filename)
|
||||
{
|
||||
if (!filename) return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
errno_t err = _wfopen_s(&f, filename, L"wb"); // 二进制写入,覆盖创建
|
||||
if (err != 0 || !f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
do {
|
||||
BITMAPFILEHEADER fileheader = {};
|
||||
BITMAPINFOHEADER infoheader = {};
|
||||
static const char _blank[2] = { 0 };
|
||||
|
||||
// 填充信息头
|
||||
infoheader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
infoheader.biWidth = Width;
|
||||
infoheader.biHeight = -Height; // top-down BMP
|
||||
infoheader.biPlanes = 1;
|
||||
infoheader.biBitCount = BPP * 8;
|
||||
infoheader.biCompression = BI_RGB; // 0 = BI_RGB
|
||||
infoheader.biSizeImage = LineSize * Height;
|
||||
infoheader.biXPelsPerMeter = 3780;
|
||||
infoheader.biYPelsPerMeter = 3780;
|
||||
infoheader.biClrUsed = 0;
|
||||
infoheader.biClrImportant = 0;
|
||||
|
||||
// 文件头
|
||||
fileheader.bfType = 0x4D42; // 'BM' = 19778
|
||||
fileheader.bfReserved1 = 0;
|
||||
fileheader.bfReserved2 = 0;
|
||||
|
||||
// 计算像素数据偏移
|
||||
if (BPP == 3) {
|
||||
fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2; // +2 for alignment
|
||||
}
|
||||
else if (BPP == 1) {
|
||||
fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + 2;
|
||||
}
|
||||
else {
|
||||
// 不支持的 BPP
|
||||
break;
|
||||
}
|
||||
|
||||
fileheader.bfSize = fileheader.bfOffBits + infoheader.biSizeImage;
|
||||
|
||||
// 写入文件头
|
||||
if (fwrite(&fileheader, sizeof(fileheader), 1, f) != 1) break;
|
||||
if (fwrite(&infoheader, sizeof(infoheader), 1, f) != 1) break;
|
||||
|
||||
// 写入调色板(仅 8-bit)
|
||||
if (BPP == 1) {
|
||||
if (bmiColors[255].rgbRed == 0) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
bmiColors[i].rgbRed = (BYTE)i;
|
||||
bmiColors[i].rgbGreen = (BYTE)i;
|
||||
bmiColors[i].rgbBlue = (BYTE)i;
|
||||
bmiColors[i].rgbReserved = 0;
|
||||
}
|
||||
}
|
||||
if (fwrite(bmiColors, sizeof(RGBQUAD), 256, f) != 256) break;
|
||||
}
|
||||
|
||||
// 写入对齐填充(2 字节)
|
||||
if (fwrite(_blank, sizeof(_blank), 1, f) != 1) break;
|
||||
|
||||
// 写入像素数据
|
||||
if (fwrite(Addr(), 1, infoheader.biSizeImage, f) != infoheader.biSizeImage) break;
|
||||
|
||||
ret = true;
|
||||
} while (0);
|
||||
|
||||
// 错误处理:记录失败原因(可选)
|
||||
if (!ret) {
|
||||
alog->error(L"Failed to write BMP file: {}", filename);
|
||||
}
|
||||
|
||||
if (f) fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 保存原始数据
|
||||
bool CImageBuf::saveRaw(std::wstring& filename)
|
||||
{
|
||||
if (filename.empty()) return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
errno_t err = _wfopen_s(&f, filename.c_str(), L"wb");
|
||||
if (err != 0 || !f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t written = fwrite(Addr(), 1, ImageSize, f);
|
||||
fclose(f);
|
||||
|
||||
return (written == ImageSize);
|
||||
}
|
||||
|
||||
// 从 std::wstring 加载原始数据
|
||||
bool CImageBuf::loadRaw(std::wstring& filename)
|
||||
{
|
||||
if (filename.empty()) return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
errno_t err = _wfopen_s(&f, filename.c_str(), L"rb");
|
||||
if (err != 0 || !f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t read = fread(Addr(), 1, ImageSize, f);
|
||||
fclose(f);
|
||||
|
||||
return (read == ImageSize);
|
||||
}
|
||||
|
||||
// 从 const wchar_t* 加载原始数据
|
||||
bool CImageBuf::loadRaw(const wchar_t* filename)
|
||||
{
|
||||
if (!filename) return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
errno_t err = _wfopen_s(&f, filename, L"rb");
|
||||
if (err != 0 || !f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t read = fread(Addr(), 1, ImageSize, f);
|
||||
fclose(f);
|
||||
|
||||
return (read == ImageSize);
|
||||
}
|
||||
|
||||
void CImageBuf::debugCopyErr(int err, const char* exinfo)
|
||||
{
|
||||
/*switch(err){
|
||||
case Ok:
|
||||
break;
|
||||
case Err_DstWidth:
|
||||
qsError() << exinfo << "dest w is larger than width";
|
||||
break;
|
||||
case Err_DstHeight:
|
||||
qsError() << exinfo << "dest y is larger than height";
|
||||
break;
|
||||
case Warn_CropWidth:
|
||||
qsWarn() << exinfo << "image is croped in width";
|
||||
break;
|
||||
case Warn_CropHeight:
|
||||
qsWarn() << exinfo << "image is croped in height";
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
///将来源目标图像缓冲区的(sx,sy,sw,sh)区域的数据复制到目标图像缓冲区的(dx,dy)处。两者的bpp必须相同
|
||||
int CImageBuf::copy(CImageBuf* src, int sx, int sy, int sw, int sh, CImageBuf* dst, int dx, int dy, const char* debugstr)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t* sp = src->getAddr(sx, sy);
|
||||
uint8_t* dp = dst->getAddr(dx, dy);
|
||||
|
||||
int dw = dst->Width - dx; //目标缓冲区可写的宽度
|
||||
int dh = dst->Height - dy; //目标缓冲区可写的高度
|
||||
do {
|
||||
if (dw <= 0) {
|
||||
ret = Err_DstWidth; //dx超出了目标缓冲区的范围
|
||||
break;
|
||||
}
|
||||
if (dh <= 0) {
|
||||
ret = Err_DstHeight; //dy超出了目标缓冲区的范围
|
||||
break;
|
||||
}
|
||||
|
||||
//判断宽度是否超出
|
||||
if (sw > dw) {
|
||||
sw = dw;
|
||||
ret = Warn_CropWidth;
|
||||
}
|
||||
if (sh > dh) {
|
||||
sh = dh;
|
||||
ret = Warn_CropHeight;
|
||||
}
|
||||
size_t line = size_t(sw * src->BPP);
|
||||
for (int h = 0; h < sh; h++) {
|
||||
memcpy(dp, sp, line);
|
||||
sp += src->LineSize;
|
||||
dp += dst->LineSize;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (debugstr) {
|
||||
debugCopyErr(ret, debugstr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CImageBuf::copy(CImageBuf* src, int sx, int sy, int sw, int sh, uint8_t* dst)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t* sp = src->getAddr(sx, sy);
|
||||
uint8_t* dp = dst;
|
||||
|
||||
|
||||
do {
|
||||
size_t line = size_t(sw * src->BPP);
|
||||
for (int h = 0; h < sh; h++) {
|
||||
memcpy(dp, sp, line);
|
||||
sp += src->LineSize;
|
||||
dp += line;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// buf1,buf2数值相加平均写到dst,长度为line
|
||||
static void meanline(uint8_t* buf1, uint8_t* buf2, uint8_t* dst, int line)
|
||||
{
|
||||
for (int i = 0; i < line; i++) {
|
||||
*dst++ = uint8_t((uint32_t(*buf1++) + uint32_t(*buf2++)) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
///叠加图片,颜色值各取1/2
|
||||
int CImageBuf::overlay(CImageBuf* src, int sx, int sy, int sw, int sh, CImageBuf* dst, int dx, int dy, const char* debugstr)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t* sp = src->getAddr(sx, sy);
|
||||
uint8_t* dp = dst->getAddr(dx, dy);
|
||||
|
||||
int dw = dst->Width - dx; //目标缓冲区可写的宽度
|
||||
int dh = dst->Height - dy; //目标缓冲区可写的高度
|
||||
do {
|
||||
if (dw <= 0) {
|
||||
ret = Err_DstWidth; //dx超出了目标缓冲区的范围
|
||||
break;
|
||||
}
|
||||
if (dh <= 0) {
|
||||
ret = Err_DstHeight; //dy超出了目标缓冲区的范围
|
||||
break;
|
||||
}
|
||||
|
||||
//判断宽度是否超出
|
||||
if (sw > dw) {
|
||||
sw = dw;
|
||||
ret = Warn_CropWidth;
|
||||
}
|
||||
if (sh > dh) {
|
||||
sh = dh;
|
||||
ret = Warn_CropHeight;
|
||||
}
|
||||
size_t line = size_t(sw * src->BPP);
|
||||
// 创建临时行
|
||||
uint8_t* tmpline = new uint8_t[size_t(line)];
|
||||
for (int h = 0; h < sh; h++) {
|
||||
meanline(dp, sp, dp, int(line));
|
||||
sp += src->LineSize;
|
||||
dp += dst->LineSize;
|
||||
}
|
||||
delete[] tmpline;
|
||||
} while (0);
|
||||
|
||||
if (debugstr) {
|
||||
debugCopyErr(ret, debugstr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CImageBuf::fill4(uint32_t val)
|
||||
{
|
||||
auto* pline = Addr();
|
||||
switch (BPP) {
|
||||
case 1: { //一次算4个像素
|
||||
val &= 0xFF;
|
||||
uint32_t v = val | val << 8 | val << 16 | val << 24;
|
||||
for (int h = 0; h < Height; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < Width / 4; i++) *p++ = v;
|
||||
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: { //一次算4个像素
|
||||
val &= 0xFFFFFF;
|
||||
uint32_t v1 = val | val << 24;
|
||||
uint32_t v2 = (val >> 8) | (val << 16);
|
||||
uint32_t v3 = (val >> 16) | (val << 8);
|
||||
for (int h = 0; h < Height; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < Width / 4; i++) {
|
||||
*p++ = v1;
|
||||
*p++ = v2;
|
||||
*p++ = v3;
|
||||
}
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {//一次算1个像素
|
||||
for (int h = 0; h < Height; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < Width; i++) *p++ = val;
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// 填充颜色,要求4像素对齐
|
||||
void CImageBuf::fill4(uint32_t val, int x, int y, int W, int H)
|
||||
{
|
||||
auto* pline = getAddr(x, y);
|
||||
switch (BPP) {
|
||||
case 1: { //一次算4个像素
|
||||
val &= 0xFF;
|
||||
uint32_t v = val | val << 8 | val << 16 | val << 24;
|
||||
for (int h = 0; h < H; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < W / 4; i++) *p++ = v;
|
||||
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: { //一次算4个像素
|
||||
val &= 0xFFFFFF;
|
||||
uint32_t v1 = val | val << 24;
|
||||
uint32_t v2 = (val >> 8) | (val << 16);
|
||||
uint32_t v3 = (val >> 16) | (val << 8);
|
||||
for (int h = 0; h < H; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < W / 4; i++) {
|
||||
*p++ = v1;
|
||||
*p++ = v2;
|
||||
*p++ = v3;
|
||||
}
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {//一次算1个像素
|
||||
for (int h = 0; h < H; h++) {
|
||||
auto p = (uint32_t*)pline;
|
||||
for (int i = 0; i < W; i++) *p++ = val;
|
||||
pline += LineSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//cv::Mat toMat(const CImageBuf& img)
|
||||
//{
|
||||
// switch (img.BytePerPix)
|
||||
// {
|
||||
// case 1:
|
||||
// return cv::Mat(img.Height, img.Width, CV_8UC1, img.Addr, img.LineSize);
|
||||
// case 2:
|
||||
// return cv::Mat(img.Height, img.Width, CV_8UC2, img.Addr, img.LineSize);
|
||||
// case 3:
|
||||
// return cv::Mat(img.Height, img.Width, CV_8UC3, img.Addr, img.LineSize);
|
||||
// case 4:
|
||||
// return cv::Mat(img.Height, img.Width, CV_8UC4, img.Addr, img.LineSize);
|
||||
// default:
|
||||
// return cv::Mat();
|
||||
// }
|
||||
//}
|
||||
|
||||
478
source/Mem/CMem.cpp
Normal file
478
source/Mem/CMem.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
#include "pch.h"
|
||||
#include "Mem\CMem.h"
|
||||
#include <Windows.h>
|
||||
#include "AlignSize.h"
|
||||
//#include "CSystemSemaphore.h"
|
||||
#include "aLog.h"
|
||||
|
||||
// 静态成员变量
|
||||
size_t CMemUsage::totalContainerSize=0;
|
||||
size_t CMemUsage::totalMemSize=0;
|
||||
std::list<CMemUsage*> CMemUsage::MemList;
|
||||
std::mutex CMemUsage::MemListLock;
|
||||
|
||||
std::mutex CMem::uplocker;
|
||||
|
||||
|
||||
void CMemUsage::report(std::wstring& str)
|
||||
{
|
||||
std::lock_guard guard(MemListLock); // 加锁
|
||||
_updateUsage();
|
||||
str = L"内存使用统计:\n";
|
||||
for (auto mem : MemList)
|
||||
{
|
||||
if(mem->memName.empty()) {
|
||||
str += fmt::format(L"未命名, {}, {}k/{}k, {}M/{}M\n", mem->memType.c_str(), mem->memSize / 1_K, mem->containerSize / 1_K, mem->memSize / 1_M, mem->containerSize / 1_M);
|
||||
}else {
|
||||
str += fmt::format(L"{}, {}, {}k/{}k, {}M/{}M\n", mem->memName.c_str(), mem->memType.c_str(), mem->memSize / 1_K, mem->containerSize / 1_K, mem->memSize / 1_M, mem->containerSize / 1_M);
|
||||
}
|
||||
}
|
||||
|
||||
str += fmt::format(L"\n总内存:{}M/{}M\n", totalMemSize / 1_M, totalContainerSize / 1_M);
|
||||
}
|
||||
|
||||
|
||||
bool CMem::_allocVirtual(void* addr, size_t size, bool commit)
|
||||
{
|
||||
const DWORD flag = (commit) ? (MEM_RESERVE | MEM_COMMIT) : MEM_RESERVE;
|
||||
// 执行windows api
|
||||
Addr = static_cast<uint8_t*>(VirtualAlloc(
|
||||
addr, // 0: 系统自动分配地址, 其他值:指定未使用的内存地址
|
||||
size, // Size of allocation
|
||||
flag,
|
||||
PAGE_READWRITE)); //只支持Read + Write,未考虑其他情况
|
||||
// 结果
|
||||
if (Addr) { // 分配成功
|
||||
containerSize = size;
|
||||
memSize = (commit) ? size : 0;
|
||||
selfAlloc = true;
|
||||
return true;
|
||||
}
|
||||
else { // 调用处来处理不成功的情况,这里不管
|
||||
containerSize = 0;
|
||||
memSize = 0;
|
||||
selfAlloc = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* CMem::allocVirtual(size_t size)
|
||||
{
|
||||
// 执行windows api
|
||||
return static_cast<uint8_t*>(VirtualAlloc(
|
||||
nullptr, // 0: 系统自动分配地址, 其他值:指定未使用的内存地址
|
||||
size, // Size of allocation
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE)); //只支持Read + Write,未考虑其他情况
|
||||
}
|
||||
|
||||
void CMem::freeVirtual(uint8_t* addr)
|
||||
{
|
||||
if(addr) VirtualFree(addr, 0, MEM_RELEASE);
|
||||
// 未处理失败情况,假设不会失败
|
||||
// 此处addr未清零,在dealloc()中清零
|
||||
}
|
||||
|
||||
bool CMem::_allocUpperVirtual(size_t size, bool commit)
|
||||
{
|
||||
const DWORD flag = (commit) ? (MEM_RESERVE | MEM_TOP_DOWN | MEM_COMMIT) : (MEM_RESERVE | MEM_TOP_DOWN);
|
||||
// 执行windows api
|
||||
Addr = static_cast<uint8_t*>(VirtualAlloc(
|
||||
nullptr, // System selects address
|
||||
size, // Size of allocation
|
||||
flag,
|
||||
PAGE_READWRITE)); //只支持Read + Write,未考虑其他情况
|
||||
// 结果
|
||||
if (Addr) {
|
||||
containerSize = size;
|
||||
memSize = 0;
|
||||
selfAlloc = true;
|
||||
return true;
|
||||
}
|
||||
else { // 调用处来处理不成功的情况,这里不管
|
||||
containerSize = 0;
|
||||
memSize = 0;
|
||||
selfAlloc = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 分配虚拟内存
|
||||
bool CWinMem::alloc(void* addr, size_t container, size_t size)
|
||||
{
|
||||
// addr可以为0或指定某个未分配的地址
|
||||
ASSERT(container != 0); //虚拟内存大小,不能为0
|
||||
ASSERT(size <= container);//物理内存大小不超过虚拟内存大小,可以为0
|
||||
|
||||
AlignUp(container, 64 * 1024); // 调整虚拟内存大小对齐到64k。win默认按64k分配虚拟内存
|
||||
AlignUp(size, 4 * 1024); // 调整物理内存大小对齐到4k。win默认按4k分配物理内存
|
||||
|
||||
if (size == 0) {
|
||||
return _allocVirtual(addr, container, false); // 不分配物理内存
|
||||
} else if (size == container) {
|
||||
return _allocVirtual(addr, container, true); // 分配全部物理内存
|
||||
} else {
|
||||
const bool ret = _allocVirtual(addr, container, false);
|
||||
if (!ret) {
|
||||
selfAlloc = false;
|
||||
return false;
|
||||
}
|
||||
if (nullptr != VirtualAlloc(Addr, size, MEM_COMMIT, PAGE_READWRITE)) { // 分配指定大小的物理内存
|
||||
memSize = size;
|
||||
selfAlloc = true;
|
||||
} else {
|
||||
selfAlloc = true; // 虽然没有物理内存, 分到虚拟内存了也算selfAlloc
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWinMem::allocUpper(size_t container, size_t size)
|
||||
{
|
||||
ASSERT(container != 0);
|
||||
ASSERT(size <= container);
|
||||
|
||||
AlignUp(container, 64_K);
|
||||
AlignUp(size, 4_K);
|
||||
|
||||
std::lock_guard guard(uplocker);
|
||||
|
||||
if (size == 0) {
|
||||
return _allocUpperVirtual(container, false);
|
||||
}
|
||||
else if (size == container) {
|
||||
return _allocUpperVirtual(container, true);
|
||||
}
|
||||
else {
|
||||
const bool ret = _allocUpperVirtual(container, false);
|
||||
if (!ret) {
|
||||
selfAlloc = false;
|
||||
return false;
|
||||
}
|
||||
if (nullptr != VirtualAlloc(Addr, size, MEM_COMMIT, PAGE_READWRITE)) {
|
||||
memSize = size;
|
||||
selfAlloc = true;
|
||||
}
|
||||
else {
|
||||
selfAlloc = true; // 虽然没有物理内存, 分到虚拟内存了也算selfAlloc
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 调整大小不影响containerSize、Addr和selfAlloc
|
||||
bool CWinMem::resize(size_t size)
|
||||
{
|
||||
if (containerSize == 0) return false;
|
||||
AlignUp(size, 4 * 1024);
|
||||
if (size > containerSize) return false;
|
||||
if (size == memSize) {
|
||||
return true;
|
||||
}
|
||||
else if (size > memSize) {
|
||||
if (nullptr != VirtualAlloc(Addr + memSize, size - memSize, MEM_COMMIT, PAGE_READWRITE)) {
|
||||
memSize = size;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
VirtualFree(Addr + size, memSize - size, MEM_DECOMMIT); // 有多的释放掉
|
||||
memSize = size;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// 调整大小不影响containerSize、Addr和selfAlloc
|
||||
bool CWinMem::reserve(size_t size)
|
||||
{
|
||||
if (containerSize == 0) return false;
|
||||
AlignUp(size, 4 * 1024);
|
||||
if (size > containerSize) return false;
|
||||
if (size == memSize) return true;
|
||||
else if (size > memSize) {
|
||||
if (nullptr != VirtualAlloc(Addr + memSize, size - memSize, MEM_COMMIT, PAGE_READWRITE)) {
|
||||
memSize = size;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
//VirtualFree(Addr + size, memSize - size, MEM_DECOMMIT); // 有多的不释放
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CWinMem::dealloc()
|
||||
{
|
||||
if (Addr) {
|
||||
VirtualFree(Addr, 0, MEM_RELEASE); // 只能release整个区域
|
||||
}
|
||||
CMem::dealloc();
|
||||
}
|
||||
|
||||
std::wstring CWinMem::details()
|
||||
{
|
||||
std::wstring str = fmt::format(L"虚拟内存地址:{}, 大小{}M,物理内存大小{}M\n", (void*)Addr, containerSize / 1_M, memSize / 1_M);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CFileMapMem2::allocNamed(const std::wstring& name, size_t container, size_t size)
|
||||
{
|
||||
// 确认调用前的状态,避免逻辑错误
|
||||
ASSERT(hand == nullptr); // 未创建内存映射文件
|
||||
ASSERT(containerSize == 0); // 未映射文件
|
||||
ASSERT(allMem.containerSize == 0); // 未分配虚拟内存
|
||||
ASSERT(allMem.Addr == nullptr);
|
||||
ASSERT(memSize == 0); // 未映射文件
|
||||
// 确认参数有效
|
||||
ASSERT(container > 0);
|
||||
ASSERT(isAlign(container, 64_K));
|
||||
ASSERT(size ==0);
|
||||
|
||||
_nativeKey = std::wstring(L"Ks_Grabber_MemMapFile_") + name;
|
||||
|
||||
std::lock_guard guard(uplocker);
|
||||
|
||||
allMem.Addr = static_cast<uint8_t*>(VirtualAlloc(
|
||||
nullptr, // System selects address
|
||||
container * 2, // Size of allocation
|
||||
MEM_RESERVE | MEM_TOP_DOWN,
|
||||
PAGE_READWRITE)); //只支持Read + Write,未考虑其他情况
|
||||
|
||||
if(!allMem.Addr) return false;
|
||||
|
||||
allMem.containerSize = container * 2;
|
||||
allMem.memSize = 0;
|
||||
|
||||
// Create the file mapping.
|
||||
hand = CreateFileMapping(INVALID_HANDLE_VALUE
|
||||
, nullptr
|
||||
, PAGE_READWRITE | SEC_COMMIT // 不能加SEC_NOCACHE
|
||||
, container >> 32, container & 0xFFFFFFFFu,
|
||||
_nativeKey.c_str());
|
||||
|
||||
if (!hand) {
|
||||
VirtualFree(allMem.Addr, 0, MEM_RELEASE); // 释放虚拟内存空间
|
||||
allMem.containerSize = 0;
|
||||
selfAlloc = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 供外部访问的内存属性
|
||||
Addr = nullptr; //地址后面mapFile()时再计算,反正只有映射了才能真正访问到。
|
||||
containerSize = container; // 容量可以先保存下来。
|
||||
memSize = 0;
|
||||
memName = name;
|
||||
selfAlloc = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CFileMapMem2::dealloc()
|
||||
{
|
||||
std::lock_guard guard(uplocker);
|
||||
unmapFile(false);
|
||||
|
||||
if(hand)
|
||||
{
|
||||
CloseHandle(hand);
|
||||
hand = nullptr;
|
||||
}
|
||||
selfAlloc = false;
|
||||
}
|
||||
|
||||
bool CFileMapMem2::resize(size_t size)
|
||||
{
|
||||
std::lock_guard guard(uplocker);
|
||||
if (containerSize == 0) return false;
|
||||
if (size > containerSize) return false;
|
||||
|
||||
if (size == 0) {
|
||||
if (memSize == containerSize) {
|
||||
unmapFile(true);
|
||||
}
|
||||
else if (memSize == 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else if (size == containerSize) {
|
||||
if (memSize == containerSize) {
|
||||
return true; // nothing todo
|
||||
}
|
||||
else if (memSize == 0) {
|
||||
return mapFile();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFileMapMem2::mapFile()
|
||||
{
|
||||
ASSERT(hand != nullptr);
|
||||
ASSERT(allMem.containerSize > 0);
|
||||
|
||||
size_t fileSize = allMem.containerSize / 2;
|
||||
size_t halfSize1 = fileSize / 2;
|
||||
AlignDown(halfSize1, 64_K);
|
||||
size_t halfSize2 = allMem.containerSize/2 - halfSize1;
|
||||
|
||||
ULARGE_INTEGER fileOffset1, fileOffset2;
|
||||
fileOffset1.QuadPart = 0;
|
||||
fileOffset2.QuadPart = halfSize1;
|
||||
VirtualFree(allMem.Addr, 0, MEM_RELEASE); // 释放虚拟内存空间
|
||||
//但内存总容量allMem.containerSize保持不变
|
||||
|
||||
// 内存 映像文件
|
||||
// -------------
|
||||
// | 2 |
|
||||
// ============== --- ==============
|
||||
// | 1 | | 1 |
|
||||
// -------------- --------------
|
||||
// | 2 | | 2 |
|
||||
// ============== --- ==============
|
||||
// | 1 |
|
||||
// --------------
|
||||
Addr = (uint8_t*)MapViewOfFileEx(hand, FILE_MAP_ALL_ACCESS
|
||||
, fileOffset1.HighPart, fileOffset1.LowPart
|
||||
, fileSize, allMem.Addr + halfSize2);
|
||||
|
||||
if(!Addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
containerSize = memSize = allMem.containerSize/2;
|
||||
|
||||
BottomMem.Addr = (uint8_t*)MapViewOfFileEx(hand, FILE_MAP_READ
|
||||
, fileOffset1.HighPart, fileOffset1.LowPart
|
||||
, halfSize1, allMem.Addr + halfSize2 + fileSize);
|
||||
|
||||
TopMem.Addr = (uint8_t*)MapViewOfFileEx(hand, FILE_MAP_READ
|
||||
, fileOffset2.HighPart, fileOffset2.LowPart
|
||||
, halfSize2, allMem.Addr);
|
||||
|
||||
if(!TopMem.Addr || !BottomMem.Addr) // 前面成功了,这里不大可能失败,稳妥起见加上
|
||||
{
|
||||
UnmapViewOfFile(Addr);
|
||||
Addr = nullptr;
|
||||
containerSize = memSize = 0;
|
||||
|
||||
if (TopMem.Addr) UnmapViewOfFile(TopMem.Addr);
|
||||
if (BottomMem.Addr) UnmapViewOfFile(BottomMem.Addr);
|
||||
|
||||
TopMem.dealloc();
|
||||
BottomMem.dealloc();
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
TopMem.containerSize = halfSize2;
|
||||
TopMem.memSize = 0;
|
||||
BottomMem.containerSize = halfSize1;
|
||||
TopMem.memSize = 0;
|
||||
}
|
||||
verifyMap();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CFileMapMem2::unmapFile(bool realloc)
|
||||
{
|
||||
if (containerSize == 0 || hand == nullptr) return;
|
||||
|
||||
if (memSize == containerSize) {
|
||||
if (TopMem.Addr) UnmapViewOfFile(TopMem.Addr);
|
||||
if (BottomMem.Addr) UnmapViewOfFile(BottomMem.Addr);
|
||||
if (Addr) UnmapViewOfFile(Addr);
|
||||
|
||||
TopMem.dealloc();
|
||||
BottomMem.dealloc();
|
||||
|
||||
Addr = nullptr;
|
||||
containerSize = memSize = 0;
|
||||
|
||||
if (realloc) {
|
||||
_allocVirtual(allMem.Addr, allMem.containerSize, false);
|
||||
}
|
||||
else {
|
||||
allMem.dealloc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CFileMapMem2::verifyMap(bool compare_content)
|
||||
{
|
||||
ASSERT(hand != nullptr);
|
||||
// 验证容量
|
||||
ASSERT(containerSize != 0);
|
||||
ASSERT(memSize = containerSize);
|
||||
ASSERT(containerSize = allMem.containerSize / 2);
|
||||
ASSERT(TopMem.containerSize + BottomMem.containerSize == containerSize);
|
||||
// 验证地址
|
||||
ASSERT(allMem.Addr);
|
||||
ASSERT(TopMem.Addr == allMem.Addr);
|
||||
ASSERT(Addr == allMem.Addr + TopMem.containerSize);
|
||||
ASSERT(BottomMem.Addr = Addr + containerSize);
|
||||
// 验证内容
|
||||
bool succ = true;
|
||||
if(compare_content)
|
||||
{
|
||||
uint64_t* p = (uint64_t*)(Addr);
|
||||
for(int i=0; i<containerSize/8; i++)
|
||||
{
|
||||
*p++ = i;
|
||||
}
|
||||
if (memcmp(Addr, BottomMem.Addr, BottomMem.containerSize) != 0)
|
||||
{
|
||||
alog->error("memcmp(Addr, BottomMem.Addr, BottomMem.containerSize) != 0");
|
||||
succ = false;
|
||||
}
|
||||
else {
|
||||
alog->info("底部映射验证通过");
|
||||
}
|
||||
|
||||
if (memcmp(Addr + BottomMem.containerSize, TopMem.Addr, TopMem.containerSize) != 0)
|
||||
{
|
||||
alog->error("Addr + BottomMem.containerSize, TopMem.Addr, TopMem.containerSize) != 0");
|
||||
succ = false;
|
||||
}
|
||||
else {
|
||||
alog->info("顶部映射验证通过");
|
||||
}
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
|
||||
std::wstring CFileMapMem2::details()
|
||||
{
|
||||
std::wstring str = fmt::format(L"虚拟内存地址:{}, 大小{}M\n", (void *)allMem.Addr, allMem.containerSize/1_M);
|
||||
|
||||
str += fmt::format(L"数据内存地址:{}, 偏移量:{}M,大小{}M\n", (void*)Addr, (Addr - allMem.Addr) / 1_M, memSize / 1_M);
|
||||
str += fmt::format(L"底部内存地址:{}, 偏移量:{:4d}M,大小{:4d}M,映射到偏移量{:4d}M\n"
|
||||
, (void*)BottomMem.Addr, (BottomMem.Addr - allMem.Addr) / 1_M, BottomMem.containerSize / 1_M, (Addr - allMem.Addr) / 1_M);
|
||||
str += fmt::format(L"顶部内存地址:{}, 偏移量:{:4d}M,大小{:4d}M,映射到偏移量{:4d}M\n"
|
||||
, (void*)TopMem.Addr, (TopMem.Addr - allMem.Addr) / 1_M, TopMem.containerSize / 1_M, (TopMem.containerSize+ BottomMem.containerSize) / 1_M);
|
||||
|
||||
return str;
|
||||
}
|
||||
2
source/Mem/CStack.cpp
Normal file
2
source/Mem/CStack.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "pch.h"
|
||||
#include "Mem\CStack.h"
|
||||
285
source/ProcessHelper.cpp
Normal file
285
source/ProcessHelper.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
#include "pch.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
// 请求关机或重启,EWX_SHUTDOWN、EWX_REBOOT
|
||||
// cmd: EWX_SHUTDOWN, EWX_REBOOT, EWX_POWEROFF 等
|
||||
// reason: SHTDN_REASON_MAJOR_OPERATINGSYSTEM, SHTDN_REASON_MINOR_OTHER 等
|
||||
void DoShutdown(uint32_t cmd, DWORD reason)
|
||||
{
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
|
||||
// 获取进程令牌
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
|
||||
_tprintf(_T("OpenProcessToken failed (%d)\n"), GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取关机权限
|
||||
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
|
||||
tkp.PrivilegeCount = 1;
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// 调整权限
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0)) {
|
||||
_tprintf(_T("AdjustTokenPrivileges failed (%d)\n"), GetLastError());
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// 关闭令牌句柄
|
||||
CloseHandle(hToken);
|
||||
|
||||
// 调用关机或重启
|
||||
if (!ExitWindowsEx(cmd, reason)) {
|
||||
_tprintf(_T("ExitWindowsEx failed (%d)\n"), GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 检查某个进程是否正在运行,返回找到的第一个匹配进程名
|
||||
BOOL IsProcessRunning(LPCTSTR pszProcName, LPTSTR pFoundName, DWORD dwFoundLen)
|
||||
{
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (Process32First(hSnapshot, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (_tcsicmp(pe.szExeFile, pszProcName) == 0)
|
||||
{
|
||||
StringCchCopy(pFoundName, dwFoundLen, pe.szExeFile);
|
||||
CloseHandle(hSnapshot);
|
||||
return TRUE;
|
||||
}
|
||||
} while (Process32Next(hSnapshot, &pe));
|
||||
}
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// 查找正在运行的目标进程,返回数量,并将找到的进程写入 outFoundProcs
|
||||
int FindRunningProcesses_BeginWith(const std::vector<std::wstring>& targetProcs, std::vector<sProcessInfo>& outFoundProcs)
|
||||
{
|
||||
// outFoundProcs大小要么与targetProcs相同,要么等于空
|
||||
bool sameSize = (targetProcs.size() == outFoundProcs.size());
|
||||
if (!sameSize && !outFoundProcs.empty()) {
|
||||
return -1; // 如果不相同且outFoundProcs不为空,则返回0
|
||||
}
|
||||
int count = 0;
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
return -2;
|
||||
|
||||
PROCESSENTRY32W pe; // 使用宽字符版本
|
||||
pe.dwSize = sizeof(PROCESSENTRY32W);
|
||||
|
||||
if (Process32FirstW(hSnapshot, &pe)) // 宽字符 API
|
||||
{
|
||||
do
|
||||
{
|
||||
std::wstring currProcName(pe.szExeFile);
|
||||
|
||||
for (uint32_t i = 0; i < targetProcs.size(); i++)
|
||||
{
|
||||
const auto& target = targetProcs[i];
|
||||
if (currProcName.size() >= target.size() && 0 == _wcsnicmp(currProcName.c_str(), target.c_str(), target.size()))
|
||||
{
|
||||
++count;
|
||||
if (sameSize) {
|
||||
outFoundProcs[i] = sProcessInfo(currProcName, pe.th32ProcessID); // 更新对应位置
|
||||
}
|
||||
else {
|
||||
outFoundProcs.push_back(sProcessInfo(currProcName, pe.th32ProcessID));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (Process32NextW(hSnapshot, &pe));
|
||||
}
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
return count;
|
||||
}
|
||||
|
||||
// 查找正在运行的目标进程,返回数量,并将找到的进程写入 outFoundProcs
|
||||
int FindRunningProcesses_Exact(const std::vector<std::wstring>& targetProcs, std::vector<sProcessInfo>& outFoundProcs)
|
||||
{
|
||||
// outFoundProcs大小要么与targetProcs相同,要么等于空
|
||||
bool sameSize = (targetProcs.size() == outFoundProcs.size());
|
||||
if (!sameSize && !outFoundProcs.empty()) {
|
||||
return -1; // 如果不相同且outFoundProcs不为空,则返回0
|
||||
}
|
||||
int count = 0;
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
return -2;
|
||||
|
||||
PROCESSENTRY32W pe; // 使用宽字符版本
|
||||
pe.dwSize = sizeof(PROCESSENTRY32W);
|
||||
|
||||
if (Process32FirstW(hSnapshot, &pe)) // 宽字符 API
|
||||
{
|
||||
do
|
||||
{
|
||||
std::wstring currProcName(pe.szExeFile);
|
||||
|
||||
for (uint32_t i = 0; i < targetProcs.size(); i++)
|
||||
{
|
||||
const auto& target = targetProcs[i];
|
||||
if (0 == _wcsicmp(currProcName.c_str(), target.c_str()))
|
||||
{
|
||||
++count;
|
||||
if (sameSize) {
|
||||
outFoundProcs[i] = sProcessInfo(currProcName, pe.th32ProcessID); // 更新对应位置
|
||||
}
|
||||
else {
|
||||
outFoundProcs.push_back(sProcessInfo(currProcName, pe.th32ProcessID));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (Process32NextW(hSnapshot, &pe));
|
||||
}
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
return count;
|
||||
}
|
||||
|
||||
// 启动一个进程,并获取其 PID。注意启动的程序是当前程序的子进程。
|
||||
bool StartProcessAndGetPid(const fs::path& exePath, DWORD* outPid)
|
||||
{
|
||||
// 将路径转换为宽字符串
|
||||
std::wstring widePath = exePath.wstring();
|
||||
|
||||
STARTUPINFO si = { sizeof(STARTUPINFO) };
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// 创建进程
|
||||
if (CreateProcess(
|
||||
NULL, // 应用程序名称(NULL 表示使用命令行)
|
||||
&widePath[0], // 命令行(可修改参数)
|
||||
NULL, // 进程句柄不可继承
|
||||
NULL, // 线程句柄不可继承
|
||||
FALSE, // 不继承句柄
|
||||
0, // 无创建标志
|
||||
NULL, // 使用父进程环境
|
||||
NULL, // 使用父进程目录
|
||||
&si, // 启动信息
|
||||
&pi // 返回的进程信息
|
||||
))
|
||||
{
|
||||
// 获取 PID
|
||||
if (outPid) *outPid = pi.dwProcessId;
|
||||
|
||||
// 关闭进程和线程句柄(但不等待进程结束)
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 独立启动一个进程,使其与当前进程解耦(类似双击运行)
|
||||
bool StartProcessIndependently(const fs::path& exePath)
|
||||
{
|
||||
// 构造命令:cmd /c start "" "full\path\to\a.exe"
|
||||
// 注意:start 的第一个参数是窗口标题,留空用 ""
|
||||
std::wstring cmd = L"cmd.exe /c start \"\" \"" + exePath.wstring() + L"\"";
|
||||
|
||||
STARTUPINFOW si = { sizeof(STARTUPINFOW) };
|
||||
PROCESS_INFORMATION pi = {};
|
||||
|
||||
// 启动 cmd.exe(隐藏窗口,不继承句柄)
|
||||
BOOL success = CreateProcessW(
|
||||
nullptr, // lpApplicationName
|
||||
&cmd[0], // lpCommandLine (可修改)
|
||||
nullptr, // lpProcessAttributes
|
||||
nullptr, // lpThreadAttributes
|
||||
FALSE, // bInheritHandles = false
|
||||
CREATE_NO_WINDOW | // 隐藏中间 cmd.exe 的黑窗口(用户体验更好)
|
||||
DETACHED_PROCESS, // 进一步解耦确保新进程不继承调用者的控制台(即使 cmd 本身有控制台也不传给 a.exe)
|
||||
nullptr, // lpEnvironment
|
||||
nullptr, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&pi // lpProcessInformation
|
||||
);
|
||||
|
||||
if (success)
|
||||
{
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NotifyProcessToExit(DWORD pid, DWORD timeoutMs)
|
||||
{
|
||||
HWND mainHwnd = nullptr;
|
||||
struct FindMainWindowParam {
|
||||
DWORD pid;
|
||||
HWND hwnd;
|
||||
} param{ pid, nullptr };
|
||||
|
||||
EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
|
||||
auto* p = reinterpret_cast<FindMainWindowParam*>(lParam);
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(hwnd, &processId);
|
||||
if (processId == p->pid) {
|
||||
if (GetWindow(hwnd, GW_OWNER) == nullptr && IsWindowVisible(hwnd)) {
|
||||
p->hwnd = hwnd;
|
||||
return FALSE; // 找到主窗口,停止枚举
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}, reinterpret_cast<LPARAM>(¶m));
|
||||
|
||||
mainHwnd = param.hwnd;
|
||||
|
||||
if (mainHwnd) {
|
||||
PostMessage(mainHwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
else {
|
||||
// 枚举该进程的所有窗口并发送 WM_CLOSE
|
||||
EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
|
||||
DWORD processId = 0;
|
||||
GetWindowThreadProcessId(hwnd, &processId);
|
||||
if (processId == static_cast<DWORD>(lParam)) {
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
return TRUE;
|
||||
}, static_cast<LPARAM>(pid));
|
||||
}
|
||||
|
||||
// 等待进程退出
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
if (hProcess)
|
||||
{
|
||||
DWORD result = WaitForSingleObject(hProcess, timeoutMs);
|
||||
CloseHandle(hProcess);
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
237
source/StringHelper.cpp
Normal file
237
source/StringHelper.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include "pch.h"
|
||||
#include <WinNls.h>
|
||||
#include "StringHelper.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool cmpIngoreCase(const string& s1, const string& s2)
|
||||
{
|
||||
if (s1.length() != s2.length()) return false;
|
||||
|
||||
return std::equal(s1.begin(), s1.end(), s2.begin(),
|
||||
[](char a, char b)->bool
|
||||
{
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
}
|
||||
|
||||
bool cmpIngoreCase(const std::string& s1, const char* s2)
|
||||
{
|
||||
if (s1.length() != strlen(s2)) return false;
|
||||
|
||||
return std::equal(s1.begin(), s1.end(), string_view(s2).begin(),
|
||||
[](char a, char b)->bool
|
||||
{
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
}
|
||||
|
||||
bool cmpIngoreCase(const wstring& s1, const wstring& s2)
|
||||
{
|
||||
if (s1.length() != s2.length()) return false;
|
||||
|
||||
return std::equal(s1.begin(), s1.end(), s2.begin(),
|
||||
[](wchar_t a, wchar_t b)->bool
|
||||
{
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
}
|
||||
|
||||
bool cmpIngoreCase(const std::wstring& s1, const wchar_t* s2)
|
||||
{
|
||||
if (s1.length() != wcslen(s2)) return false;
|
||||
|
||||
return std::equal(s1.begin(), s1.end(), wstring_view(s2).begin(),
|
||||
[](wchar_t a, wchar_t b)->bool
|
||||
{
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
}
|
||||
|
||||
// Convert a wide Unicode string to an UTF8 string
|
||||
std::string utf16_8(const std::wstring& wstr)
|
||||
{
|
||||
if (wstr.empty()) return std::string();
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
std::string utf16_8(const wchar_t* wstr)
|
||||
{
|
||||
if (wstr == nullptr) return std::string();
|
||||
int srclen = int(wcslen(wstr));
|
||||
if (srclen == 0) return std::string();
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, srclen, NULL, 0, NULL, NULL);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, srclen, &strTo[0], size_needed, NULL, NULL);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
int utf16_8(const wchar_t* wstr, char* dst, int dstsize)
|
||||
{
|
||||
if (wstr == nullptr) return 0;
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
if (size_needed > dstsize) {
|
||||
return 0;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, dst, size_needed, NULL, NULL);
|
||||
return size_needed;
|
||||
}
|
||||
|
||||
std::string Utf16ToGBK(const wchar_t* wstr)
|
||||
{
|
||||
if (wstr == nullptr) return std::string();
|
||||
int srclen = int(wcslen(wstr));
|
||||
if (srclen == 0) return std::string();
|
||||
int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr, srclen, NULL, 0, NULL, NULL);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr, srclen, &strTo[0], size_needed, NULL, NULL);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
int Utf16ToGBK(const wchar_t* wstr, char* dst, int dstsize)
|
||||
{
|
||||
if (wstr == nullptr) return 0;
|
||||
int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
if (size_needed > dstsize) {
|
||||
return 0;
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr, -1, dst, size_needed, NULL, NULL);
|
||||
return size_needed;
|
||||
}
|
||||
|
||||
// Convert an UTF8 string to a wide Unicode String
|
||||
std::wstring utf8_16(const std::string& str)
|
||||
{
|
||||
if (str.empty()) return std::wstring();
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
|
||||
std::wstring wstrTo(size_needed, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
|
||||
return wstrTo;
|
||||
}
|
||||
|
||||
std::wstring utf8_16(const char* str)
|
||||
{
|
||||
if (str == nullptr) return std::wstring();
|
||||
int srclen = int(strlen(str));
|
||||
if (srclen == 0) return std::wstring();
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, srclen, NULL, 0);
|
||||
std::wstring strTo(size_needed, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, srclen, &strTo[0], size_needed);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string GbkToUtf8(const std::string& src_str)
|
||||
{
|
||||
int srclen = int(src_str.size());
|
||||
if (srclen == 0) return std::string();
|
||||
|
||||
const auto tmpsize = MultiByteToWideChar(CP_ACP, 0, &src_str[0], srclen, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[tmpsize + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, &src_str[0], srclen, wstr, tmpsize);
|
||||
wstr[tmpsize] = 0;
|
||||
|
||||
auto dstlen = WideCharToMultiByte(CP_UTF8, 0, wstr, tmpsize, NULL, 0, NULL, NULL);
|
||||
std::string dst_str(dstlen, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, tmpsize, &dst_str[0], dstlen, NULL, NULL);
|
||||
delete[] wstr;
|
||||
return dst_str;
|
||||
}
|
||||
|
||||
std::string GbkToUtf8(const char* src_str)
|
||||
{
|
||||
int srclen = int(strlen(src_str));
|
||||
if (srclen == 0) return std::string();
|
||||
|
||||
const auto tmpsize = MultiByteToWideChar(CP_ACP, 0, src_str, srclen, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[tmpsize + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, src_str, srclen, wstr, tmpsize);
|
||||
wstr[tmpsize] = 0;
|
||||
|
||||
auto dstlen = WideCharToMultiByte(CP_UTF8, 0, wstr, tmpsize, NULL, 0, NULL, NULL);
|
||||
std::string dst_str(dstlen, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, tmpsize, &dst_str[0], dstlen, NULL, NULL);
|
||||
delete[] wstr;
|
||||
return dst_str;
|
||||
}
|
||||
|
||||
|
||||
std::string Utf8ToGbk(const std::string& src_str)
|
||||
{
|
||||
int srclen = int(src_str.size());
|
||||
if (srclen == 0) return std::string();
|
||||
|
||||
const auto tmpsize = MultiByteToWideChar(CP_UTF8, 0, &src_str[0], srclen, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[tmpsize + 1];
|
||||
MultiByteToWideChar(CP_UTF8, 0, &src_str[0], srclen, wstr, tmpsize);
|
||||
wstr[tmpsize] = 0;
|
||||
|
||||
auto dstlen = WideCharToMultiByte(CP_ACP, 0, wstr, tmpsize, NULL, 0, NULL, NULL);
|
||||
std::string dst_str(dstlen, 0);
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr, tmpsize, &dst_str[0], dstlen, NULL, NULL);
|
||||
delete[] wstr;
|
||||
return dst_str;
|
||||
}
|
||||
std::string Utf8ToGbk(const char* src_str)
|
||||
{
|
||||
int srclen = int(strlen(src_str));
|
||||
if (srclen == 0) return std::string();
|
||||
|
||||
const auto tmpsize = MultiByteToWideChar(CP_UTF8, 0, src_str, srclen, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[tmpsize + 1];
|
||||
MultiByteToWideChar(CP_UTF8, 0, src_str, srclen, wstr, tmpsize);
|
||||
wstr[tmpsize] = 0;
|
||||
|
||||
auto dstlen = WideCharToMultiByte(CP_ACP, 0, wstr, tmpsize, NULL, 0, NULL, NULL);
|
||||
std::string dst_str(dstlen, 0);
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr, tmpsize, &dst_str[0], dstlen, NULL, NULL);
|
||||
delete[] wstr;
|
||||
return dst_str;
|
||||
}
|
||||
#else
|
||||
#include <iconv.h>
|
||||
|
||||
int GbkToUtf8(char* str_str, size_t src_len, char* dst_str, size_t dst_len)
|
||||
{
|
||||
iconv_t cd;
|
||||
char** pin = &str_str;
|
||||
char** pout = &dst_str;
|
||||
|
||||
cd = iconv_open("utf8", "gbk");
|
||||
if (cd == 0)
|
||||
return -1;
|
||||
memset(dst_str, 0, dst_len);
|
||||
if (iconv(cd, pin, &src_len, pout, &dst_len) == -1)
|
||||
return -1;
|
||||
iconv_close(cd);
|
||||
*pout = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Utf8ToGbk(char* src_str, size_t src_len, char* dst_str, size_t dst_len)
|
||||
{
|
||||
iconv_t cd;
|
||||
char** pin = &src_str;
|
||||
char** pout = &dst_str;
|
||||
|
||||
cd = iconv_open("gbk", "utf8");
|
||||
if (cd == 0)
|
||||
return -1;
|
||||
memset(dst_str, 0, dst_len);
|
||||
if (iconv(cd, pin, &src_len, pout, &dst_len) == -1)
|
||||
return -1;
|
||||
iconv_close(cd);
|
||||
*pout = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
714
source/Tools.cpp
Normal file
714
source/Tools.cpp
Normal file
@@ -0,0 +1,714 @@
|
||||
#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;
|
||||
}
|
||||
216
source/aLog.cpp
Normal file
216
source/aLog.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "pch.h"
|
||||
#include "aLog.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
#include "spdlog/async.h"
|
||||
|
||||
//app全局通用的logger实例
|
||||
std::shared_ptr<spdlog::logger> alog;
|
||||
|
||||
static std::wstring _LogFilePath;
|
||||
static std::wstring _LogFilePath2;
|
||||
|
||||
spdlog::sink_ptr pConsoleSink;
|
||||
spdlog::sink_ptr pFileSink;
|
||||
spdlog::sink_ptr pFileSink2;
|
||||
|
||||
// 用于console log
|
||||
static FILE* _stream=nullptr;
|
||||
static bool _consoleAttached = false; // 附着到父进程的控制台
|
||||
static bool _consoleAllocated = false; // 我们新创建的控制台
|
||||
|
||||
static void _initConsoleLog()
|
||||
{
|
||||
// 若已存在控制台,直接使用;否则尝试附着父进程控制台,失败再创建
|
||||
if (GetConsoleWindow()) {
|
||||
// 已有控制台(通常是控制台子系统)
|
||||
}
|
||||
else if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
_consoleAttached = true;
|
||||
}
|
||||
else if (AllocConsole()) {
|
||||
_consoleAllocated = true;
|
||||
}
|
||||
// 若成功获得控制台,重定向 stdout 并设置 UTF-8
|
||||
if (GetConsoleWindow()) {
|
||||
//freopen_s(&_stream, "CONOUT$", "w", stdout);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
// 尝试启用虚拟终端处理(让 ANSI 颜色也能生效,兼容使用 ansicolor sink 的场景)
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hOut != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (GetConsoleMode(hOut, &mode)) {
|
||||
// 添加虚拟终端 & 已处理输出标志(如果父控制台支持则颜色更稳定)
|
||||
SetConsoleMode(hOut, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
}
|
||||
}
|
||||
|
||||
pConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
pConsoleSink->set_level(spdlog::level::debug);
|
||||
}
|
||||
}
|
||||
|
||||
static void _deinitConsoleLog()
|
||||
{
|
||||
pConsoleSink.reset();
|
||||
if (_stream) {
|
||||
fclose(_stream);
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
// 只在我们附着或创建过控制台时释放
|
||||
if (_consoleAttached || _consoleAllocated) {
|
||||
FreeConsole();
|
||||
_consoleAttached = false;
|
||||
_consoleAllocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InitRollFileLog(std::shared_ptr<spdlog::logger>& log, const char * logname, int flag, const fs::path& logDir, const std::wstring& filename, int logfilesize_K, int logfilenum)
|
||||
{
|
||||
spdlog::drop(logname); // 删除原来的logger
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
|
||||
// 创建异步logger, 默认必须有一个文件log
|
||||
|
||||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
|
||||
_LogFilePath = (logDir / name).wstring();
|
||||
log = spdlog::create_async_nb<spdlog::sinks::rotating_file_sink_mt>(logname, _LogFilePath, size_t(logfilesize_K) * 1024, logfilenum);
|
||||
|
||||
|
||||
pFileSink = log->sinks()[0];
|
||||
|
||||
// 添加console log
|
||||
if (flag & INIT_CONSOLE_LOG) {
|
||||
_initConsoleLog();
|
||||
if(pConsoleSink) log->sinks().push_back(pConsoleSink);
|
||||
}
|
||||
|
||||
pFileSink->set_level(spdlog::level::debug);
|
||||
|
||||
if(flag & INIT_ERROR_FILE_LOG) {
|
||||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
|
||||
_LogFilePath2 = (logDir / name).wstring();
|
||||
pFileSink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(_LogFilePath2, size_t(logfilesize_K) * 1024, logfilenum);
|
||||
|
||||
pFileSink2->set_level(spdlog::level::warn);
|
||||
log->sinks().push_back(pFileSink2);
|
||||
}
|
||||
|
||||
log->set_level(spdlog::level::debug);
|
||||
log->flush_on(spdlog::level::err); //记录error立即flush一次
|
||||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||||
}
|
||||
|
||||
void InitBasicFileLog(std::shared_ptr<spdlog::logger>& log, const char* logname, int flag, const fs::path& logDir, const std::wstring& filename)
|
||||
{
|
||||
spdlog::drop(logname); // 删除原来的logger
|
||||
|
||||
std::time_t t = std::time(nullptr);
|
||||
|
||||
// 创建异步logger, 默认必须有一个文件log
|
||||
|
||||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
|
||||
_LogFilePath = (logDir / name).wstring();
|
||||
log = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(logname, _LogFilePath);
|
||||
|
||||
pFileSink = log->sinks()[0];
|
||||
|
||||
// 添加console log
|
||||
if (flag & INIT_CONSOLE_LOG) {
|
||||
_initConsoleLog();
|
||||
log->sinks().push_back(pConsoleSink);
|
||||
}
|
||||
|
||||
pFileSink->set_level(spdlog::level::debug);
|
||||
|
||||
if (flag & INIT_ERROR_FILE_LOG) {
|
||||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
|
||||
_LogFilePath2 = (logDir / name).wstring();
|
||||
pFileSink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(_LogFilePath2);
|
||||
|
||||
pFileSink2->set_level(spdlog::level::warn);
|
||||
log->sinks().push_back(pFileSink2);
|
||||
}
|
||||
|
||||
log->set_level(spdlog::level::debug);
|
||||
log->flush_on(spdlog::level::err); //记录error立即flush一次
|
||||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||||
}
|
||||
|
||||
// ---- 这两段用于简单的程序,只开console log -----
|
||||
|
||||
// 仅开Console log
|
||||
void aLogInitConsole()
|
||||
{
|
||||
spdlog::drop(""); // 删除默认logger
|
||||
|
||||
// 创建异步logger
|
||||
alog = spdlog::create_async_nb<spdlog::sinks::stdout_color_sink_mt>("");
|
||||
|
||||
pConsoleSink = alog->sinks()[0];
|
||||
pConsoleSink->set_level(spdlog::level::debug);
|
||||
|
||||
_initConsoleLog();
|
||||
|
||||
alog->set_level(spdlog::level::debug);
|
||||
alog->flush_on(spdlog::level::err); //记录error立即flush一次
|
||||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||||
|
||||
}
|
||||
|
||||
void LogDeinit(std::shared_ptr<spdlog::logger>& log, bool byelog)
|
||||
{
|
||||
// 关闭前打印一条信息
|
||||
if(byelog) alog->info("Log正常关闭");
|
||||
alog->flush();
|
||||
Sleep(100); // 确保已经输出了
|
||||
alog->sinks().clear();
|
||||
|
||||
if (pConsoleSink) {
|
||||
_deinitConsoleLog();
|
||||
}
|
||||
if (pFileSink) {
|
||||
pFileSink.reset();
|
||||
}
|
||||
if (pFileSink2) {
|
||||
pFileSink.reset();
|
||||
}
|
||||
|
||||
spdlog::shutdown();
|
||||
}
|
||||
|
||||
// ---- 这两段用于5C,运行过程中随时开启、关闭console log -----
|
||||
|
||||
// 如果没开启Console log,打开
|
||||
void openConsoleLog()
|
||||
{
|
||||
if (!pConsoleSink) {
|
||||
_initConsoleLog();
|
||||
}
|
||||
alog->sinks().push_back(pConsoleSink);
|
||||
|
||||
}
|
||||
|
||||
// 如果已经打开了Console Log,关闭掉
|
||||
void closeConsoleLog()
|
||||
{
|
||||
if (pConsoleSink) {//开启了console要关闭
|
||||
for (auto it = alog->sinks().begin(); it != alog->sinks().end(); it++) {
|
||||
if (pConsoleSink == *it) {
|
||||
alog->warn("已停止刷新Log到Console");
|
||||
alog->flush();
|
||||
Sleep(100); // 确保已经输出了
|
||||
alog->sinks().erase(it); // 假设没有别的线程在输出
|
||||
Sleep(100); // 确保已经输出了
|
||||
_deinitConsoleLog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
201
source/sApp.cpp
Normal file
201
source/sApp.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#include "pch.h"
|
||||
#include "sApp.h"
|
||||
|
||||
#include "CreateDump.h"
|
||||
#include "Tools.h"
|
||||
|
||||
#include <gdiplus.h>
|
||||
#include "aLog.h"
|
||||
#include "CTic.h"
|
||||
|
||||
using namespace Gdiplus;
|
||||
#pragma comment (lib,"Gdiplus.lib")
|
||||
|
||||
int sApp::preInit()
|
||||
{
|
||||
CTic::Init();
|
||||
|
||||
TCHAR path[MAX_PATH + 1];
|
||||
GetModuleFileName(NULL, path, MAX_PATH);
|
||||
ExeFullPath = path; //完整路径
|
||||
wstrExeName = ExeFullPath.stem().wstring(); //保存去掉扩展名的文件名
|
||||
ExeDir = ExeFullPath.parent_path(); //exe所在路径
|
||||
|
||||
setCreateDump((ExeDir / wstrExeName).c_str(), MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs | MiniDumpWithHandleData | MiniDumpWithThreadInfo);
|
||||
|
||||
hInstance_Exe = GetModuleHandle(NULL);
|
||||
GetFileVersion(path, exeFileVerStr);
|
||||
|
||||
// 如果版本号是以.0结尾,去掉
|
||||
auto pos = exeFileVerStr.rfind(L".0");
|
||||
if (pos != std::wstring::npos && pos == exeFileVerStr.size() - 2) {
|
||||
exeFileVerStr.erase(pos);
|
||||
}
|
||||
|
||||
GetProductVersion(path, exeProductVerStr);
|
||||
pos = exeProductVerStr.rfind(L".0");
|
||||
if (pos != std::wstring::npos && pos == exeProductVerStr.size() - 2) {
|
||||
exeProductVerStr.erase(pos);
|
||||
}
|
||||
|
||||
// 设置搜索dll的方式
|
||||
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
|
||||
// 默认工作目录是exe所在目录
|
||||
WorkDir = ExeDir;
|
||||
|
||||
// 如果在Debug/Release目录之下调试,工作目录向上一级
|
||||
auto pathname = ExeDir.filename().wstring();
|
||||
if (pathname._Starts_with(L"Debug")
|
||||
|| pathname._Starts_with(L"Release")
|
||||
|| pathname._Starts_with(L"debug")
|
||||
|| pathname._Starts_with(L"release")) {
|
||||
WorkDir = ExeDir.parent_path();
|
||||
fs::path solutionDir = WorkDir.parent_path();
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 子类不用调用sApp::init(),这里只是打个样;
|
||||
int sApp::init()
|
||||
{
|
||||
// 如果要更改WorkDir,在这开头修改
|
||||
|
||||
SettingDir = WorkDir / L"Setting";
|
||||
LogDir = WorkDir / L"Log";
|
||||
|
||||
if (!fs::exists(SettingDir)) {
|
||||
fs::create_directories(SettingDir);
|
||||
}
|
||||
|
||||
// Log目录不存在则创建
|
||||
if (!fs::exists(LogDir)) {
|
||||
fs::create_directories(LogDir);
|
||||
}
|
||||
|
||||
initGDI();
|
||||
|
||||
|
||||
initSocket();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sApp::deinit()
|
||||
{
|
||||
if(wsaData.wVersion) // 初始化过应该是0x0202
|
||||
WSACleanup();
|
||||
|
||||
if(m_gdiplusToken)
|
||||
GdiplusShutdown(m_gdiplusToken);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sApp::initGDI()
|
||||
{
|
||||
GdiplusStartupInput gdiplusStartupInput;
|
||||
|
||||
// Initialize GDI+.
|
||||
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
}
|
||||
|
||||
bool sApp::initSocket()
|
||||
{
|
||||
//第一个参数为WinSock版本号,低字节为主版本号,高字节为修正版本号,第二个参数为WSADATA类型的指针 初始化成功返回0
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
alog->error("WSAStartup 失败");
|
||||
//TRACE(_T("WSAStartup 失败!\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sApp::RestartWindows()
|
||||
{
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
|
||||
// Get a token for this process.
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
return;
|
||||
|
||||
// Get the LUID for the shutdown privilege.
|
||||
if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
tkp.PrivilegeCount = 1; // one privilege to set
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// Get the shutdown privilege for this process.
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shut down the system and force all applications to close.
|
||||
if (!ExitWindowsEx(EWX_REBOOT | EWX_FORCE,
|
||||
SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
|
||||
SHTDN_REASON_MINOR_UPGRADE)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
//shutdown was successful
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
void sApp::ShutdownWindows()
|
||||
{
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
|
||||
// Get a token for this process.
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
return;
|
||||
|
||||
// Get the LUID for the shutdown privilege.
|
||||
if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
tkp.PrivilegeCount = 1; // one privilege to set
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// Get the shutdown privilege for this process.
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shut down the system and force all applications to close.
|
||||
if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE,
|
||||
SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
|
||||
SHTDN_REASON_MINOR_UPGRADE)) {
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
|
||||
//shutdown was successful
|
||||
CloseHandle(hToken);
|
||||
return;
|
||||
}
|
||||
260493
source/sqlite3.c
Normal file
260493
source/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user