Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jlib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
jlib
Commits
c9174ca4
Commit
c9174ca4
authored
Nov 06, 2023
by
captainwong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
c024947b
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1415 additions
and
1410 deletions
+1415
-1410
ErrorCode.h
jlib/qt/ErrorCode.h
+47
-47
QtDebug.h
jlib/qt/QtDebug.h
+50
-50
QtPathHelper.h
jlib/qt/QtPathHelper.h
+181
-181
version.h
jlib/util/version.h
+264
-259
path_helper.h
jlib/win32/path_helper.h
+177
-177
path_op.h
jlib/win32/path_op.h
+123
-123
process.h
jlib/win32/process.h
+435
-435
rect.h
jlib/win32/rect.h
+138
-138
No files found.
jlib/qt/ErrorCode.h
View file @
c9174ca4
#pragma once
#include "qt_global.h"
#include <system_error>
#include <QString>
JLIBQT_NAMESPACE_BEGIN
//!
获取错误码文字描述
inline
QString
ecString
(
const
std
::
error_code
&
ec
)
{
return
QString
::
fromLocal8Bit
(
ec
.
message
().
data
());
}
//!
获取错误码文字描述(带有错误目录)
inline
QString
ecStringWithCategory
(
const
std
::
error_code
&
ec
)
{
return
QString
::
fromLocal8Bit
(
ec
.
category
().
name
())
+
": "
+
QString
::
fromLocal8Bit
(
ec
.
message
().
data
());
}
#define BREAK_IF_QUERY_FAILED(ec_type) if (!ok) { \
ec = ec_type; \
MYQCRITICAL << ecStringWithCategory(ec) << "\n" << query.lastError(); \
break; \
}
enum
class
DatabaseErrorCode
{
OpenDbFailed
=
1
,
CreateDbTableFailed
,
QueryDbFailed
,
};
JLIBQT_NAMESPACE_END
#define ENABLE_ENUM_AS_ERROR_CODE(type) \
namespace std { \
template <> struct is_error_code_enum<type> : true_type {}; \
std::error_code make_error_code(type); \
}
ENABLE_ENUM_AS_ERROR_CODE
(
JLIBQT_NAMESPACE
DatabaseErrorCode
)
std
::
error_code
std
::
make_error_code
(
JLIBQT_NAMESPACE
DatabaseErrorCode
ec
);
#pragma once
#include "qt_global.h"
#include <system_error>
#include <QString>
JLIBQT_NAMESPACE_BEGIN
//!
获取错误码文字描述
inline
QString
ecString
(
const
std
::
error_code
&
ec
)
{
return
QString
::
fromLocal8Bit
(
ec
.
message
().
data
());
}
//!
获取错误码文字描述(带有错误目录)
inline
QString
ecStringWithCategory
(
const
std
::
error_code
&
ec
)
{
return
QString
::
fromLocal8Bit
(
ec
.
category
().
name
())
+
": "
+
QString
::
fromLocal8Bit
(
ec
.
message
().
data
());
}
#define BREAK_IF_QUERY_FAILED(ec_type) if (!ok) { \
ec
=
ec_type
;
\
MYQCRITICAL
<<
ecStringWithCategory
(
ec
)
<<
"
\n
"
<<
query
.
lastError
();
\
break
;
\
}
enum
class
DatabaseErrorCode
{
OpenDbFailed
=
1
,
CreateDbTableFailed
,
QueryDbFailed
,
};
JLIBQT_NAMESPACE_END
#define ENABLE_ENUM_AS_ERROR_CODE(type) \
namespace
std
{
\
template
<>
struct
is_error_code_enum
<
type
>
:
true_type
{};
\
std
::
error_code
make_error_code
(
type
);
\
}
ENABLE_ENUM_AS_ERROR_CODE
(
JLIBQT_NAMESPACE
DatabaseErrorCode
)
std
::
error_code
std
::
make_error_code
(
JLIBQT_NAMESPACE
DatabaseErrorCode
ec
);
jlib/qt/QtDebug.h
View file @
c9174ca4
#pragma once
#include <QDebug>
#include <QDateTime>
#ifdef _WIN32
#include <Windows.h>
#endif //_WIN32
#define JLIBQT_QDEBUG_FILE_LINE_STREAM "[" << __FUNCTION__ << __LINE__ << "]: "
#define JLIBQT_QDEBUG_FILE_LINE_VALUE (QString("[") + __FUNCTION__ + " " + QString::number(__LINE__) + "]: ")
#define MYQDEBUG qDebug() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO qInfo() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN qWarning() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL qCritical() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG_NOQUOTE qDebug().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO_NOQUOTE qInfo().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN_NOQUOTE qWarning().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL_NOQUOTE qCritical().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG2 qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO2 qInfo() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN2 qWarning() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL2 qCritical() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG2_NOQUOTE qDebug().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO2_NOQUOTE qInfo().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN2_NOQUOTE qWarning().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL2_NOQUOTE qCritical().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
//!
弹窗报告行号开关
// #define JLIBQT_SHOW_LINE 0
//!
当行号大于下方定义的值时,弹窗报告行号,否则忽略。可在多个cpp文件分别定义不同的值。
// #define JLIBQT_SHOW_MSGBOX_AFTER_LINE 1
#if JLIBQT_SHOW_LINE
#ifdef JLIBQT_SHOW_MSGBOX_AFTER_LINE
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER if(__LINE__ >= JLIBQT_SHOW_MSGBOX_AFTER_LINE) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), L"Test", 0); }
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title) if(__LINE__ >= JLIBQT_SHOW_MSGBOX_AFTER_LINE) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), title, 0); }
#else
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), L"Test", 0); }
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), title, 0); }
#endif
#else
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title)
#endif
#pragma once
#include <QDebug>
#include <QDateTime>
#ifdef _WIN32
#include <Windows.h>
#endif //_WIN32
#define JLIBQT_QDEBUG_FILE_LINE_STREAM "[" << __FUNCTION__ << __LINE__ << "]: "
#define JLIBQT_QDEBUG_FILE_LINE_VALUE (QString("[") + __FUNCTION__ + " " + QString::number(__LINE__) + "]: ")
#define MYQDEBUG qDebug() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO qInfo() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN qWarning() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL qCritical() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG_NOQUOTE qDebug().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO_NOQUOTE qInfo().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN_NOQUOTE qWarning().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL_NOQUOTE qCritical().noquote() << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG2 qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO2 qInfo() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN2 qWarning() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL2 qCritical() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQDEBUG2_NOQUOTE qDebug().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQINFO2_NOQUOTE qInfo().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQWARN2_NOQUOTE qWarning().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
#define MYQCRITICAL2_NOQUOTE qCritical().noquote() << QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") << JLIBQT_QDEBUG_FILE_LINE_STREAM
//!
弹窗报告行号开关
// #define JLIBQT_SHOW_LINE 0
//!
当行号大于下方定义的值时,弹窗报告行号,否则忽略。可在多个cpp文件分别定义不同的值。
// #define JLIBQT_SHOW_MSGBOX_AFTER_LINE 1
#if JLIBQT_SHOW_LINE
#ifdef JLIBQT_SHOW_MSGBOX_AFTER_LINE
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER if(__LINE__ >= JLIBQT_SHOW_MSGBOX_AFTER_LINE) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), L"Test", 0); }
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title) if(__LINE__ >= JLIBQT_SHOW_MSGBOX_AFTER_LINE) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), title, 0); }
#else
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), L"Test", 0); }
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title) { MessageBoxW(nullptr, (std::wstring(__FILEW__) + L":" + std::to_wstring(__LINE__)).data(), title, 0); }
#endif
#else
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER
#define JLIBQT_SHOW_MSGBOX_LINE_NUMBER_WITH_TITLE(title)
#endif
jlib/qt/QtPathHelper.h
View file @
c9174ca4
#pragma once
#include "qt_global.h"
#include <QDir>
#include <QCoreApplication>
#include <QString>
#include <QDateTime>
#include <QStandardPaths>
JLIBQT_NAMESPACE_BEGIN
static
const
auto
JLIBQT_FILE_TIME_FORMAT
=
"yyyy-MM-dd_hh-mm-ss"
;
struct
PathHelper
{
static
inline
bool
mkpath
(
const
QString
&
path
)
{
QDir
dir
;
return
dir
.
exists
(
path
)
?
true
:
dir
.
mkpath
(
path
);
}
static
inline
QString
currentTimeString
()
{
return
QDateTime
::
currentDateTime
().
toString
(
JLIBQT_FILE_TIME_FORMAT
);
}
static
inline
QString
getFolder
(
const
QString
&
path
)
{
QDir
dir
(
path
);
dir
.
cdUp
();
return
dir
.
absolutePath
();
}
virtual
~
PathHelper
()
{}
virtual
QString
program
()
const
{
return
programPath_
;
}
virtual
QString
exe
()
const
{
return
exePath_
;
}
virtual
QString
bin
()
const
{
return
program
()
+
"/bin"
;
}
virtual
QString
data
()
const
{
return
program
()
+
"/data"
;
}
virtual
QString
log
()
const
{
return
program
()
+
"/log"
;
}
virtual
QString
dumps
()
const
{
return
program
()
+
"/dumps"
;
}
virtual
QString
config
()
const
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
{
return
data
()
+
"/db"
;
}
protected
:
// disable constructor
explicit
PathHelper
()
{}
//!
应用程序安装目录
QString
programPath_
=
{};
//!
应用程序路径
QString
exePath_
=
{};
};
struct
AutoSwithToBin
{
AutoSwithToBin
(
PathHelper
*
helper
)
:
helper
(
helper
)
{}
AutoSwithToBin
(
PathHelper
*
helper
,
const
QString
&
path
)
:
helper
(
helper
)
{
QDir
().
setCurrent
(
path
);
}
~
AutoSwithToBin
()
{
if
(
helper
)
{
QDir
().
setCurrent
(
helper
->
bin
());
}
}
PathHelper
*
helper
=
nullptr
;
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll在bin文件夹
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperLocal
:
PathHelper
{
PathHelperLocal
()
:
PathHelper
()
{
exePath_
=
QCoreApplication
::
applicationFilePath
();
QDir
dir
(
QCoreApplication
::
applicationDirPath
());
dir
.
cdUp
();
programPath_
=
dir
.
absolutePath
();
}
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll也在安装目录
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | | |-- config
* @note | | |-- db
* @note | |-- program.exe
* @note | |-- *.dlls
*/
struct
PathHelperLocalWithoutBin
:
PathHelper
{
PathHelperLocalWithoutBin
()
:
PathHelper
()
{
exePath_
=
QCoreApplication
::
applicationFilePath
();
QDir
dir
(
QCoreApplication
::
applicationDirPath
());
programPath_
=
dir
.
absolutePath
();
}
virtual
QString
bin
()
const
override
{
return
program
();
}
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note program-name
无需设置,Qt会自动设置
* @note
如果在调用此类之前先调用了 QCoreApplication::setOrganizationName("your-organization-name");
* @note
那么program-name在your-organization-name下
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note
* @note |-- writable-dir
* @note | |-- your-organization-name
* @note | | |-- program-name
* @note | | |-- log
* @note | | |-- dumps
* @note | | |-- config
* @note | | |-- db
*/
struct
PathHelperDataSeperated
:
PathHelperLocal
{
PathHelperDataSeperated
(
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocal
(),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
QString
data
()
const
override
{
return
QStandardPaths
::
writableLocation
(
QStandardPaths
::
AppDataLocation
);
}
virtual
QString
log
()
const
override
{
return
useTmpAsLogFolder
?
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
)
:
(
data
()
+
"/log"
);
}
virtual
QString
dumps
()
const
override
{
return
data
()
+
"/dumps"
;
}
virtual
QString
config
()
const
override
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
override
{
return
data
()
+
"/db"
;
}
protected
:
bool
useTmpAsLogFolder
=
false
;
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note program-name
无需设置,Qt会自动设置
* @note
如果在调用此类之前先调用了 QCoreApplication::setOrganizationName("your-organization-name");
* @note
那么program-name在your-organization-name下
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- program.exe
* @note | |-- *.dlls
* @note
* @note |-- writable-dir
* @note | |-- your-organization-name
* @note | | |-- program-name
* @note | | |-- log
* @note | | |-- dumps
* @note | | |-- config
* @note | | |-- db
*/
struct
PathHelperDataSeperatedWithoutBin
:
PathHelperLocalWithoutBin
{
PathHelperDataSeperatedWithoutBin
(
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocalWithoutBin
(),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
QString
data
()
const
override
{
return
QStandardPaths
::
writableLocation
(
QStandardPaths
::
AppDataLocation
);
}
virtual
QString
log
()
const
override
{
return
useTmpAsLogFolder
?
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
)
:
(
data
()
+
"/log"
);
}
virtual
QString
dumps
()
const
override
{
return
data
()
+
"/dumps"
;
}
virtual
QString
config
()
const
override
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
override
{
return
data
()
+
"/db"
;
}
protected
:
bool
useTmpAsLogFolder
=
false
;
};
JLIBQT_NAMESPACE_END
#pragma once
#include "qt_global.h"
#include <QDir>
#include <QCoreApplication>
#include <QString>
#include <QDateTime>
#include <QStandardPaths>
JLIBQT_NAMESPACE_BEGIN
static
const
auto
JLIBQT_FILE_TIME_FORMAT
=
"yyyy-MM-dd_hh-mm-ss"
;
struct
PathHelper
{
static
inline
bool
mkpath
(
const
QString
&
path
)
{
QDir
dir
;
return
dir
.
exists
(
path
)
?
true
:
dir
.
mkpath
(
path
);
}
static
inline
QString
currentTimeString
()
{
return
QDateTime
::
currentDateTime
().
toString
(
JLIBQT_FILE_TIME_FORMAT
);
}
static
inline
QString
getFolder
(
const
QString
&
path
)
{
QDir
dir
(
path
);
dir
.
cdUp
();
return
dir
.
absolutePath
();
}
virtual
~
PathHelper
()
{}
virtual
QString
program
()
const
{
return
programPath_
;
}
virtual
QString
exe
()
const
{
return
exePath_
;
}
virtual
QString
bin
()
const
{
return
program
()
+
"/bin"
;
}
virtual
QString
data
()
const
{
return
program
()
+
"/data"
;
}
virtual
QString
log
()
const
{
return
program
()
+
"/log"
;
}
virtual
QString
dumps
()
const
{
return
program
()
+
"/dumps"
;
}
virtual
QString
config
()
const
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
{
return
data
()
+
"/db"
;
}
protected
:
// disable constructor
explicit
PathHelper
()
{}
//!
应用程序安装目录
QString
programPath_
=
{};
//!
应用程序路径
QString
exePath_
=
{};
};
struct
AutoSwithToBin
{
AutoSwithToBin
(
PathHelper
*
helper
)
:
helper
(
helper
)
{}
AutoSwithToBin
(
PathHelper
*
helper
,
const
QString
&
path
)
:
helper
(
helper
)
{
QDir
().
setCurrent
(
path
);
}
~
AutoSwithToBin
()
{
if
(
helper
)
{
QDir
().
setCurrent
(
helper
->
bin
());
}
}
PathHelper
*
helper
=
nullptr
;
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll在bin文件夹
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperLocal
:
PathHelper
{
PathHelperLocal
()
:
PathHelper
()
{
exePath_
=
QCoreApplication
::
applicationFilePath
();
QDir
dir
(
QCoreApplication
::
applicationDirPath
());
dir
.
cdUp
();
programPath_
=
dir
.
absolutePath
();
}
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll也在安装目录
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | | |-- config
* @note | | |-- db
* @note | |-- program.exe
* @note | |-- *.dlls
*/
struct
PathHelperLocalWithoutBin
:
PathHelper
{
PathHelperLocalWithoutBin
()
:
PathHelper
()
{
exePath_
=
QCoreApplication
::
applicationFilePath
();
QDir
dir
(
QCoreApplication
::
applicationDirPath
());
programPath_
=
dir
.
absolutePath
();
}
virtual
QString
bin
()
const
override
{
return
program
();
}
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note program-name
无需设置,Qt会自动设置
* @note
如果在调用此类之前先调用了 QCoreApplication::setOrganizationName("your-organization-name");
* @note
那么program-name在your-organization-name下
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note
* @note |-- writable-dir
* @note | |-- your-organization-name
* @note | | |-- program-name
* @note | | |-- log
* @note | | |-- dumps
* @note | | |-- config
* @note | | |-- db
*/
struct
PathHelperDataSeperated
:
PathHelperLocal
{
PathHelperDataSeperated
(
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocal
(),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
QString
data
()
const
override
{
return
QStandardPaths
::
writableLocation
(
QStandardPaths
::
AppDataLocation
);
}
virtual
QString
log
()
const
override
{
return
useTmpAsLogFolder
?
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
)
:
(
data
()
+
"/log"
);
}
virtual
QString
dumps
()
const
override
{
return
data
()
+
"/dumps"
;
}
virtual
QString
config
()
const
override
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
override
{
return
data
()
+
"/db"
;
}
protected
:
bool
useTmpAsLogFolder
=
false
;
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note program-name
无需设置,Qt会自动设置
* @note
如果在调用此类之前先调用了 QCoreApplication::setOrganizationName("your-organization-name");
* @note
那么program-name在your-organization-name下
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- program.exe
* @note | |-- *.dlls
* @note
* @note |-- writable-dir
* @note | |-- your-organization-name
* @note | | |-- program-name
* @note | | |-- log
* @note | | |-- dumps
* @note | | |-- config
* @note | | |-- db
*/
struct
PathHelperDataSeperatedWithoutBin
:
PathHelperLocalWithoutBin
{
PathHelperDataSeperatedWithoutBin
(
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocalWithoutBin
(),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
QString
data
()
const
override
{
return
QStandardPaths
::
writableLocation
(
QStandardPaths
::
AppDataLocation
);
}
virtual
QString
log
()
const
override
{
return
useTmpAsLogFolder
?
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
)
:
(
data
()
+
"/log"
);
}
virtual
QString
dumps
()
const
override
{
return
data
()
+
"/dumps"
;
}
virtual
QString
config
()
const
override
{
return
data
()
+
"/config"
;
}
virtual
QString
db
()
const
override
{
return
data
()
+
"/db"
;
}
protected
:
bool
useTmpAsLogFolder
=
false
;
};
JLIBQT_NAMESPACE_END
jlib/util/version.h
View file @
c9174ca4
#
pragma
once
#include "../base/config.h"
#include <string>
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <vector>
#include <stdint.h>
namespace
jlib
{
//! 应用程序版本分支
enum
class
Branch
:
int
{
//! 测试版,一般仅用于测试人员测试
Test
,
//! 体验版,可以投放给少量用户进行灰度测试
Experimental
,
//! 正式版
Stable
,
BranchCount
,
InvalidBranch
=
0x0FFFFFFF
,
};
static
constexpr
auto
BranchNameTest
=
"test"
;
static
constexpr
auto
BranchNameExperimental
=
"experimental"
;
static
constexpr
auto
BranchNameStable
=
"stable"
;
inline
const
char
*
branchName
(
Branch
branch
)
{
switch
(
branch
)
{
case
jlib
:
:
Branch
::
Test
:
return
BranchNameTest
;
case
jlib
:
:
Branch
::
Experimental
:
return
BranchNameExperimental
;
case
jlib
:
:
Branch
::
Stable
:
return
BranchNameStable
;
default:
return
"InvalidBranch"
;
}
}
inline
Branch
branchFromString
(
const
std
::
string
&
name
)
{
if
(
name
==
BranchNameTest
)
{
return
Branch
::
Test
;
}
else
if
(
name
==
BranchNameExperimental
)
{
return
Branch
::
Experimental
;
}
else
if
(
name
==
BranchNameStable
)
{
return
Branch
::
Stable
;
}
else
{
return
Branch
::
InvalidBranch
;
}
}
//! 应用程序版本号
struct
Version
{
//! 主版本
uint16_t
major
=
0
;
//! 功能更新
uint16_t
minor
=
0
;
//! bug 修复
uint16_t
revision
=
0
;
//! 随意,我一般用来表示程序总迭代(编译成功)次数
uint16_t
build
=
0
;
Version
()
=
default
;
Version
(
uint16_t
major
,
uint16_t
minor
,
uint16_t
revision
,
uint16_t
build
)
:
major
(
major
),
minor
(
minor
),
revision
(
revision
),
build
(
build
)
{}
Version
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
}
Version
(
uint64_t
v
)
{
fromUInt64
(
v
);
}
Version
&
fromString
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
return
*
this
;
}
Version
&
operator
=
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
return
*
this
;
}
Version
&
operator
=
(
uint64_t
v
)
{
fromUInt64
(
v
);
return
*
this
;
}
bool
valid
()
const
{
return
!
(
major
==
0
&&
minor
==
0
&&
revision
==
0
&&
build
==
0
);
}
void
reset
()
{
major
=
minor
=
revision
=
build
=
0
;
}
bool
_fromString
(
const
std
::
string
&
s
)
{
if
(
std
::
sscanf
(
s
.
c_str
(),
"%hu.%hu.%hu.%hu"
,
&
major
,
&
minor
,
&
revision
,
&
build
)
!=
4
)
{
reset
();
return
false
;
}
if
(
major
<
0
)
major
=
0
;
if
(
minor
<
0
)
minor
=
0
;
if
(
revision
<
0
)
revision
=
0
;
if
(
build
<
0
)
build
=
0
;
return
true
;
}
std
::
string
toString
()
const
{
return
std
::
to_string
(
major
)
+
"."
+
std
::
to_string
(
minor
)
+
"."
+
std
::
to_string
(
revision
)
+
"."
+
std
::
to_string
(
build
);
}
void
fromUInt64
(
uint64_t
v
)
{
major
=
(
v
>>
48
)
&
0xFFFF
;
minor
=
(
v
>>
32
)
&
0xFFFF
;
revision
=
(
v
>>
16
)
&
0xFFFF
;
build
=
v
&
0xFFFF
;
}
uint64_t
toUInt64
()
const
{
return
((
uint64_t
)
major
<<
48
)
|
((
uint64_t
)
minor
<<
32
)
|
((
uint64_t
)
revision
<<
16
)
|
(
uint64_t
)
build
;
}
//! require cpp17
template
<
typename
T
>
bool
fromFile
(
T
const
&
path
)
{
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
string
>
);
else
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
wstring
>
);
else
{
return
false
;
}
std
::
ifstream
in
(
path
);
if
(
!
in
)
return
false
;
std
::
stringstream
is
;
is
<<
in
.
rdbuf
();
Version
file_ver
(
is
.
str
());
if
(
file_ver
.
valid
())
{
*
this
=
file_ver
;
return
true
;
}
return
false
;
}
//! require cpp17
template
<
typename
T
>
bool
toFile
(
T
const
&
path
)
{
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
string
>
);
else
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
wstring
>
);
else
{
return
false
;
}
std
::
ofstream
out
(
path
);
if
(
!
out
)
{
return
false
;
}
auto
str
=
toString
();
out
.
write
(
str
.
data
(),
str
.
size
());
return
true
;
}
bool
operator
==
(
const
Version
&
ver
)
const
{
return
toUInt64
()
==
ver
.
toUInt64
();
}
bool
operator
<
(
const
Version
&
ver
)
const
{
return
toUInt64
()
<
ver
.
toUInt64
();
}
bool
operator
>
(
const
Version
&
ver
)
const
{
return
toUInt64
()
>
ver
.
toUInt64
();
}
bool
operator
<=
(
const
Version
&
ver
)
const
{
return
toUInt64
()
<=
ver
.
toUInt64
();
}
bool
operator
>=
(
const
Version
&
ver
)
const
{
return
toUInt64
()
>=
ver
.
toUInt64
();
}
};
//! 安装包下载链接
struct
DownLoadLink
{
std
::
string
host
=
{};
// local, qcloud, aliyun, ...
std
::
string
link
=
{};
std
::
string
md5
=
{};
};
//! 发布
struct
Release
{
Branch
branch
=
Branch
::
InvalidBranch
;
Version
version
=
{};
bool
force_update
=
false
;
//! 版本更新说明
std
::
string
change
=
{};
std
::
vector
<
DownLoadLink
>
dllinks
=
{};
std
::
string
toString
()
const
{
auto
s
=
std
::
string
(
branchName
(
branch
))
+
" "
+
version
.
toString
()
+
"
\n
force_update="
+
(
force_update
?
"true"
:
"false"
)
+
"
\n
change="
+
change
+
"
\n
download_links=
\n
"
;
if
(
!
dllinks
.
empty
())
{
for
(
const
auto
&
link
:
dllinks
)
{
s
+=
link
.
host
+
" : link="
+
link
.
link
+
" md5="
+
link
.
md5
+
"
\n
"
;
}
}
else
{
s
+=
"empty"
;
}
return
s
;
}
bool
valid
()
const
{
return
(
branch
!=
Branch
::
InvalidBranch
)
&&
version
.
valid
()
&&
!
dllinks
.
empty
();
}
};
//! 最新的发布,包含各个分支的最新版本
struct
LatestRelease
{
std
::
vector
<
Release
>
releases
=
{};
std
::
string
toString
()
const
{
std
::
string
str
;
for
(
const
auto
&
r
:
releases
)
{
if
(
r
.
valid
())
{
str
+=
r
.
toString
()
+
"
\n
"
;
}
}
return
str
;
}
};
/*
* @brief 从服务器获取最新版本信息,包含各个分支的最新版本
* @param value 为从服务器获取的最新发布信息,以 JSON 表示
* @param latestReleases 版本信息
* @return count
* @note 示例数据
* @code{.json}
* {
* "test": {
* "version": "2.2.11.13262",
* "force_update": true,
* "release_note": "测试;",
* "download_links": {
* "local": {
* "link": "https://your-host.com/download/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* }
* }
* },
* "stable": {
* "version": "2.2.12.13282",
* "force_update": false,
* "release_note": "测试稳定",
* "download_links": {
* "local": {
* "link": "https://your-host.com/download/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* },
* "qcloud": {
* "link": "https://xxx.file.myqcloud.com/xxx/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* }
* }
* }
* }
* @endcode
*/
template
<
typename
JsonValue
>
int
resolveLatestRelease
(
const
JsonValue
&
value
,
LatestRelease
&
latestRelease
)
{
int
count
=
0
;
for
(
int
i
=
0
;
i
<
(
int
)
Branch
::
BranchCount
;
i
++
)
{
Branch
branch
=
Branch
(
i
);
if
(
value
.
isMember
(
branchName
(
branch
)))
{
const
auto
&
detail
=
value
[
branchName
(
branch
)];
Release
release
;
release
.
branch
=
branch
;
release
.
force_update
=
detail
.
isMember
(
"force_update"
)
?
detail
[
"force_update"
].
asBool
()
:
false
;
release
.
version
=
detail
[
"version"
].
asString
();
release
.
change
=
detail
[
"release_note"
].
asString
();
if
(
detail
[
"download_links"
].
isMember
(
"local"
))
{
DownLoadLink
dl
;
dl
.
host
=
"local"
;
dl
.
link
=
detail
[
"download_links"
][
"local"
][
"link"
].
asString
();
dl
.
md5
=
detail
[
"download_links"
][
"local"
][
"md5"
].
asString
();
release
.
dllinks
.
push_back
(
dl
);
}
if
(
detail
[
"download_links"
].
isMember
(
"qcloud"
))
{
DownLoadLink
dl
;
dl
.
host
=
"qcloud"
;
dl
.
link
=
detail
[
"download_links"
][
"qcloud"
][
"link"
].
asString
();
dl
.
md5
=
detail
[
"download_links"
][
"qcloud"
][
"md5"
].
asString
();
release
.
dllinks
.
push_back
(
dl
);
}
latestRelease
.
releases
.
push_back
(
release
);
count
++
;
}
}
return
count
;
}
}
// end namespace jlib
#
pragma
once
#include "../base/config.h"
#include <string>
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <vector>
#include <stdint.h>
namespace
jlib
{
//! 应用程序版本分支
enum
class
Branch
:
int
{
// 开发版,开发人员自测
Dev
,
//! 测试版,一般仅用于测试人员测试
Test
,
//! 体验版,可以投放给少量用户进行灰度测试
Experimental
,
//! 正式版
Stable
,
BranchCount
,
InvalidBranch
=
0x0FFFFFFF
,
};
static
constexpr
auto
BranchNameDev
=
"dev"
;
static
constexpr
auto
BranchNameTest
=
"test"
;
static
constexpr
auto
BranchNameExperimental
=
"experimental"
;
static
constexpr
auto
BranchNameStable
=
"stable"
;
inline
const
char
*
branchName
(
Branch
branch
)
{
switch
(
branch
)
{
case
jlib
:
:
Branch
::
Dev
:
return
BranchNameDev
;
case
jlib
:
:
Branch
::
Test
:
return
BranchNameTest
;
case
jlib
:
:
Branch
::
Experimental
:
return
BranchNameExperimental
;
case
jlib
:
:
Branch
::
Stable
:
return
BranchNameStable
;
default:
return
"InvalidBranch"
;
}
}
inline
Branch
branchFromString
(
const
std
::
string
&
name
)
{
if
(
name
==
BranchNameDev
)
{
return
Branch
::
Dev
;
}
else
if
(
name
==
BranchNameTest
)
{
return
Branch
::
Test
;
}
else
if
(
name
==
BranchNameExperimental
)
{
return
Branch
::
Experimental
;
}
else
if
(
name
==
BranchNameStable
)
{
return
Branch
::
Stable
;
}
else
{
return
Branch
::
InvalidBranch
;
}
}
//! 应用程序版本号
struct
Version
{
//! 主版本
uint16_t
major
=
0
;
//! 功能更新
uint16_t
minor
=
0
;
//! bug 修复
uint16_t
revision
=
0
;
//! 随意,我一般用来表示程序总迭代(编译成功)次数
uint16_t
build
=
0
;
Version
()
=
default
;
Version
(
uint16_t
major
,
uint16_t
minor
,
uint16_t
revision
,
uint16_t
build
)
:
major
(
major
),
minor
(
minor
),
revision
(
revision
),
build
(
build
)
{}
Version
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
}
Version
(
uint64_t
v
)
{
fromUInt64
(
v
);
}
Version
&
fromString
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
return
*
this
;
}
Version
&
operator
=
(
const
std
::
string
&
s
)
{
_fromString
(
s
);
return
*
this
;
}
Version
&
operator
=
(
uint64_t
v
)
{
fromUInt64
(
v
);
return
*
this
;
}
bool
valid
()
const
{
return
!
(
major
==
0
&&
minor
==
0
&&
revision
==
0
&&
build
==
0
);
}
void
reset
()
{
major
=
minor
=
revision
=
build
=
0
;
}
bool
_fromString
(
const
std
::
string
&
s
)
{
if
(
std
::
sscanf
(
s
.
c_str
(),
"%hu.%hu.%hu.%hu"
,
&
major
,
&
minor
,
&
revision
,
&
build
)
!=
4
)
{
reset
();
return
false
;
}
if
(
major
<
0
)
major
=
0
;
if
(
minor
<
0
)
minor
=
0
;
if
(
revision
<
0
)
revision
=
0
;
if
(
build
<
0
)
build
=
0
;
return
true
;
}
std
::
string
toString
()
const
{
return
std
::
to_string
(
major
)
+
"."
+
std
::
to_string
(
minor
)
+
"."
+
std
::
to_string
(
revision
)
+
"."
+
std
::
to_string
(
build
);
}
void
fromUInt64
(
uint64_t
v
)
{
major
=
(
v
>>
48
)
&
0xFFFF
;
minor
=
(
v
>>
32
)
&
0xFFFF
;
revision
=
(
v
>>
16
)
&
0xFFFF
;
build
=
v
&
0xFFFF
;
}
uint64_t
toUInt64
()
const
{
return
((
uint64_t
)
major
<<
48
)
|
((
uint64_t
)
minor
<<
32
)
|
((
uint64_t
)
revision
<<
16
)
|
(
uint64_t
)
build
;
}
//! require cpp17
template
<
typename
T
>
bool
fromFile
(
T
const
&
path
)
{
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
string
>
);
else
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
wstring
>
);
else
{
return
false
;
}
std
::
ifstream
in
(
path
);
if
(
!
in
)
return
false
;
std
::
stringstream
is
;
is
<<
in
.
rdbuf
();
Version
file_ver
(
is
.
str
());
if
(
file_ver
.
valid
())
{
*
this
=
file_ver
;
return
true
;
}
return
false
;
}
//! require cpp17
template
<
typename
T
>
bool
toFile
(
T
const
&
path
)
{
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
string
>
);
else
if
constexpr
(
std
::
is_convertible_v
<
T
,
std
::
wstring
>
);
else
{
return
false
;
}
std
::
ofstream
out
(
path
);
if
(
!
out
)
{
return
false
;
}
auto
str
=
toString
();
out
.
write
(
str
.
data
(),
str
.
size
());
return
true
;
}
bool
operator
==
(
const
Version
&
ver
)
const
{
return
toUInt64
()
==
ver
.
toUInt64
();
}
bool
operator
<
(
const
Version
&
ver
)
const
{
return
toUInt64
()
<
ver
.
toUInt64
();
}
bool
operator
>
(
const
Version
&
ver
)
const
{
return
toUInt64
()
>
ver
.
toUInt64
();
}
bool
operator
<=
(
const
Version
&
ver
)
const
{
return
toUInt64
()
<=
ver
.
toUInt64
();
}
bool
operator
>=
(
const
Version
&
ver
)
const
{
return
toUInt64
()
>=
ver
.
toUInt64
();
}
};
//! 安装包下载链接
struct
DownLoadLink
{
std
::
string
host
=
{};
// local, qcloud, aliyun, ...
std
::
string
link
=
{};
std
::
string
md5
=
{};
};
//! 发布
struct
Release
{
Branch
branch
=
Branch
::
InvalidBranch
;
Version
version
=
{};
bool
force_update
=
false
;
//! 版本更新说明
std
::
string
change
=
{};
std
::
vector
<
DownLoadLink
>
dllinks
=
{};
std
::
string
toString
()
const
{
auto
s
=
std
::
string
(
branchName
(
branch
))
+
" "
+
version
.
toString
()
+
"
\n
force_update="
+
(
force_update
?
"true"
:
"false"
)
+
"
\n
change="
+
change
+
"
\n
download_links=
\n
"
;
if
(
!
dllinks
.
empty
())
{
for
(
const
auto
&
link
:
dllinks
)
{
s
+=
link
.
host
+
" : link="
+
link
.
link
+
" md5="
+
link
.
md5
+
"
\n
"
;
}
}
else
{
s
+=
"empty"
;
}
return
s
;
}
bool
valid
()
const
{
return
(
branch
!=
Branch
::
InvalidBranch
)
&&
version
.
valid
()
&&
!
dllinks
.
empty
();
}
};
//! 最新的发布,包含各个分支的最新版本
struct
LatestRelease
{
std
::
vector
<
Release
>
releases
=
{};
std
::
string
toString
()
const
{
std
::
string
str
;
for
(
const
auto
&
r
:
releases
)
{
if
(
r
.
valid
())
{
str
+=
r
.
toString
()
+
"
\n
"
;
}
}
return
str
;
}
};
/*
* @brief 从服务器获取最新版本信息,包含各个分支的最新版本
* @param value 为从服务器获取的最新发布信息,以 JSON 表示
* @param latestReleases 版本信息
* @return count
* @note 示例数据
* @code{.json}
* {
* "test": {
* "version": "2.2.11.13262",
* "force_update": true,
* "release_note": "测试;",
* "download_links": {
* "local": {
* "link": "https://your-host.com/download/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* }
* }
* },
* "stable": {
* "version": "2.2.12.13282",
* "force_update": false,
* "release_note": "测试稳定",
* "download_links": {
* "local": {
* "link": "https://your-host.com/download/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* },
* "qcloud": {
* "link": "https://xxx.file.myqcloud.com/xxx/installer.exe",
* "md5": "06907d59d7a656be62fc93bbf867604b"
* }
* }
* }
* }
* @endcode
*/
template
<
typename
JsonValue
>
int
resolveLatestRelease
(
const
JsonValue
&
value
,
LatestRelease
&
latestRelease
)
{
int
count
=
0
;
for
(
int
i
=
0
;
i
<
(
int
)
Branch
::
BranchCount
;
i
++
)
{
Branch
branch
=
Branch
(
i
);
if
(
value
.
isMember
(
branchName
(
branch
)))
{
const
auto
&
detail
=
value
[
branchName
(
branch
)];
Release
release
;
release
.
branch
=
branch
;
release
.
force_update
=
detail
.
isMember
(
"force_update"
)
?
detail
[
"force_update"
].
asBool
()
:
false
;
release
.
version
=
detail
[
"version"
].
asString
();
release
.
change
=
detail
[
"release_note"
].
asString
();
if
(
detail
[
"download_links"
].
isMember
(
"local"
))
{
DownLoadLink
dl
;
dl
.
host
=
"local"
;
dl
.
link
=
detail
[
"download_links"
][
"local"
][
"link"
].
asString
();
dl
.
md5
=
detail
[
"download_links"
][
"local"
][
"md5"
].
asString
();
release
.
dllinks
.
push_back
(
dl
);
}
if
(
detail
[
"download_links"
].
isMember
(
"qcloud"
))
{
DownLoadLink
dl
;
dl
.
host
=
"qcloud"
;
dl
.
link
=
detail
[
"download_links"
][
"qcloud"
][
"link"
].
asString
();
dl
.
md5
=
detail
[
"download_links"
][
"qcloud"
][
"md5"
].
asString
();
release
.
dllinks
.
push_back
(
dl
);
}
latestRelease
.
releases
.
push_back
(
release
);
count
++
;
}
}
return
count
;
}
}
// end namespace jlib
jlib/win32/path_helper.h
View file @
c9174ca4
#pragma once
#include "../base/config.h"
#include <string>
#include "path_op.h"
#include "../util/chrono_wrapper.h"
namespace
jlib
{
namespace
win32
{
struct
PathHelper
{
static
inline
bool
mkpath
(
const
std
::
string
&
path
)
{
return
folderExists
(
path
)
?
true
:
createDirectory
(
path
);
}
static
inline
bool
mkpath
(
const
std
::
wstring
&
path
)
{
return
folderExists
(
path
)
?
true
:
createDirectory
(
path
);
}
static
inline
std
::
wstring
currentTimeString
()
{
return
integrateFileName
(
nowToWString
());
}
static
inline
std
::
string
currentTimeStringA
()
{
return
integrateFileName
(
nowToString
());
}
virtual
~
PathHelper
()
{}
virtual
std
::
string
program
()
const
{
return
programPath_
;
}
virtual
std
::
string
exe
()
const
{
return
exePath_
;
}
virtual
std
::
string
bin
()
const
{
return
program
()
+
"
\\
bin"
;
}
virtual
std
::
string
data
()
const
{
return
program
()
+
"
\\
data"
;
}
virtual
std
::
string
log
()
const
{
return
program
()
+
"
\\
log"
;
}
virtual
std
::
string
dumps
()
const
{
return
program
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
{
return
data
()
+
"
\\
db"
;
}
protected
:
// disable constructor
explicit
PathHelper
()
{}
//!
应用程序安装目录
std
::
string
programPath_
=
{};
//!
应用程序路径
std
::
string
exePath_
=
{};
};
struct
AutoSwithToBin
{
AutoSwithToBin
(
PathHelper
*
helper
)
:
helper
(
helper
)
{}
AutoSwithToBin
(
PathHelper
*
helper
,
const
std
::
string
&
path
)
:
helper
(
helper
)
{
::
SetCurrentDirectoryA
(
path
.
c_str
());
}
~
AutoSwithToBin
()
{
if
(
helper
)
{
::
SetCurrentDirectoryA
(
helper
->
bin
().
c_str
());
}
}
PathHelper
*
helper
=
nullptr
;
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll在bin文件夹
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperLocal
:
PathHelper
{
PathHelperLocal
()
:
PathHelper
()
{
exePath_
=
getExePathA
();
programPath_
=
getFolder
(
getFolder
(
exePath_
));
}
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll也在安装目录
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | | |-- config
* @note | | |-- db
* @note | |-- program.exe
* @note | |-- *.dlls
*/
struct
PathHelperLocalWithoutBin
:
PathHelper
{
PathHelperLocalWithoutBin
()
:
PathHelper
()
{
exePath_
=
getExePathA
();
programPath_
=
getFolder
(
exePath_
);
}
virtual
std
::
string
bin
()
const
override
{
return
program
();
}
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note
* @note |-- C:/Users/[USER]/AppData/Roaming
* @note | |-- program-name
* @note | |-- log
* @note | |-- dumps
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperDataSeperated
:
PathHelperLocal
{
PathHelperDataSeperated
(
const
std
::
string
&
appName
,
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocal
(),
appName
(
appName
),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
std
::
string
data
()
const
override
{
auto
path
=
getAppDataPathA
()
+
"
\\
"
+
appName
;
mkpath
(
path
);
return
path
;
}
virtual
std
::
string
log
()
const
override
{
return
useTmpAsLogFolder
?
getTempPathA
()
:
(
data
()
+
"
\\
log"
);
}
virtual
std
::
string
dumps
()
const
override
{
return
data
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
override
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
override
{
return
data
()
+
"
\\
db"
;
}
protected
:
std
::
string
appName
=
{};
bool
useTmpAsLogFolder
=
false
;
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- program.exe
* @note | |-- *.dlls
* @note
* @note |-- C:/Users/[USER]/AppData/Roaming
* @note | |-- program-name
* @note | |-- log
* @note | |-- dumps
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperDataSeperatedWithoutBin
:
PathHelperLocalWithoutBin
{
PathHelperDataSeperatedWithoutBin
(
const
std
::
string
&
appName
,
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocalWithoutBin
(),
appName
(
appName
),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
std
::
string
data
()
const
override
{
auto
path
=
getAppDataPathA
()
+
"
\\
"
+
appName
;
mkpath
(
path
);
return
path
;
}
virtual
std
::
string
log
()
const
override
{
return
useTmpAsLogFolder
?
getTempPathA
()
:
(
data
()
+
"
\\
log"
);
}
virtual
std
::
string
dumps
()
const
override
{
return
data
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
override
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
override
{
return
data
()
+
"
\\
db"
;
}
protected
:
std
::
string
appName
=
{};
bool
useTmpAsLogFolder
=
false
;
};
}
}
#pragma once
#include "../base/config.h"
#include <string>
#include "path_op.h"
#include "../util/chrono_wrapper.h"
namespace
jlib
{
namespace
win32
{
struct
PathHelper
{
static
inline
bool
mkpath
(
const
std
::
string
&
path
)
{
return
folderExists
(
path
)
?
true
:
createDirectory
(
path
);
}
static
inline
bool
mkpath
(
const
std
::
wstring
&
path
)
{
return
folderExists
(
path
)
?
true
:
createDirectory
(
path
);
}
static
inline
std
::
wstring
currentTimeString
()
{
return
integrateFileName
(
nowToWString
());
}
static
inline
std
::
string
currentTimeStringA
()
{
return
integrateFileName
(
nowToString
());
}
virtual
~
PathHelper
()
{}
virtual
std
::
string
program
()
const
{
return
programPath_
;
}
virtual
std
::
string
exe
()
const
{
return
exePath_
;
}
virtual
std
::
string
bin
()
const
{
return
program
()
+
"
\\
bin"
;
}
virtual
std
::
string
data
()
const
{
return
program
()
+
"
\\
data"
;
}
virtual
std
::
string
log
()
const
{
return
program
()
+
"
\\
log"
;
}
virtual
std
::
string
dumps
()
const
{
return
program
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
{
return
data
()
+
"
\\
db"
;
}
protected
:
// disable constructor
explicit
PathHelper
()
{}
//!
应用程序安装目录
std
::
string
programPath_
=
{};
//!
应用程序路径
std
::
string
exePath_
=
{};
};
struct
AutoSwithToBin
{
AutoSwithToBin
(
PathHelper
*
helper
)
:
helper
(
helper
)
{}
AutoSwithToBin
(
PathHelper
*
helper
,
const
std
::
string
&
path
)
:
helper
(
helper
)
{
::
SetCurrentDirectoryA
(
path
.
c_str
());
}
~
AutoSwithToBin
()
{
if
(
helper
)
{
::
SetCurrentDirectoryA
(
helper
->
bin
().
c_str
());
}
}
PathHelper
*
helper
=
nullptr
;
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll在bin文件夹
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperLocal
:
PathHelper
{
PathHelperLocal
()
:
PathHelper
()
{
exePath_
=
getExePathA
();
programPath_
=
getFolder
(
getFolder
(
exePath_
));
}
};
/*
* @brief
路径辅助类,数据保存在安装目录,程序和dll也在安装目录
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- dumps
* @note | |-- log
* @note | |-- data
* @note | | |-- config
* @note | | |-- db
* @note | |-- program.exe
* @note | |-- *.dlls
*/
struct
PathHelperLocalWithoutBin
:
PathHelper
{
PathHelperLocalWithoutBin
()
:
PathHelper
()
{
exePath_
=
getExePathA
();
programPath_
=
getFolder
(
exePath_
);
}
virtual
std
::
string
bin
()
const
override
{
return
program
();
}
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- bin
* @note | | |-- program.exe
* @note | | |-- *.dlls
* @note
* @note |-- C:/Users/[USER]/AppData/Roaming
* @note | |-- program-name
* @note | |-- log
* @note | |-- dumps
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperDataSeperated
:
PathHelperLocal
{
PathHelperDataSeperated
(
const
std
::
string
&
appName
,
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocal
(),
appName
(
appName
),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
std
::
string
data
()
const
override
{
auto
path
=
getAppDataPathA
()
+
"
\\
"
+
appName
;
mkpath
(
path
);
return
path
;
}
virtual
std
::
string
log
()
const
override
{
return
useTmpAsLogFolder
?
getTempPathA
()
:
(
data
()
+
"
\\
log"
);
}
virtual
std
::
string
dumps
()
const
override
{
return
data
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
override
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
override
{
return
data
()
+
"
\\
db"
;
}
protected
:
std
::
string
appName
=
{};
bool
useTmpAsLogFolder
=
false
;
};
/*
* @brief
路径辅助类,数据保存在其他可写目录,如 C:/Users/[USER]/AppData/Roaming
* @note
大致结构树为:
* @note |-- program-install-dir
* @note | |-- program.exe
* @note | |-- *.dlls
* @note
* @note |-- C:/Users/[USER]/AppData/Roaming
* @note | |-- program-name
* @note | |-- log
* @note | |-- dumps
* @note | |-- config
* @note | |-- db
*/
struct
PathHelperDataSeperatedWithoutBin
:
PathHelperLocalWithoutBin
{
PathHelperDataSeperatedWithoutBin
(
const
std
::
string
&
appName
,
bool
useTmpAsLogFolder
=
false
)
:
PathHelperLocalWithoutBin
(),
appName
(
appName
),
useTmpAsLogFolder
(
useTmpAsLogFolder
)
{}
virtual
std
::
string
data
()
const
override
{
auto
path
=
getAppDataPathA
()
+
"
\\
"
+
appName
;
mkpath
(
path
);
return
path
;
}
virtual
std
::
string
log
()
const
override
{
return
useTmpAsLogFolder
?
getTempPathA
()
:
(
data
()
+
"
\\
log"
);
}
virtual
std
::
string
dumps
()
const
override
{
return
data
()
+
"
\\
dumps"
;
}
virtual
std
::
string
config
()
const
override
{
return
data
()
+
"
\\
config"
;
}
virtual
std
::
string
db
()
const
override
{
return
data
()
+
"
\\
db"
;
}
protected
:
std
::
string
appName
=
{};
bool
useTmpAsLogFolder
=
false
;
};
}
}
jlib/win32/path_op.h
View file @
c9174ca4
#
pragma
once
#include "../base/config.h"
#include <ShlObj.h>
#include <string>
#include <algorithm>
namespace
jlib
{
namespace
win32
{
inline
std
::
wstring
getExePath
()
{
wchar_t
path
[
1024
]
=
{
0
};
::
GetModuleFileNameW
(
nullptr
,
path
,
1024
);
return
path
;
}
inline
std
::
string
getExePathA
()
{
char
path
[
1024
]
=
{
0
};
::
GetModuleFileNameA
(
nullptr
,
path
,
1024
);
return
path
;
}
inline
std
::
wstring
getFolder
(
const
std
::
wstring
&
path
)
{
auto
pos
=
path
.
find_last_of
(
L"
\\
/"
);
return
pos
!=
path
.
npos
?
path
.
substr
(
0
,
pos
)
:
path
;
}
inline
std
::
string
getFolder
(
const
std
::
string
&
path
)
{
auto
pos
=
path
.
find_last_of
(
"
\\
/"
);
return
pos
!=
path
.
npos
?
path
.
substr
(
0
,
pos
)
:
path
;
}
inline
std
::
wstring
getExeFolderPath
()
{
return
getFolder
(
getExePath
());
}
inline
std
::
string
getExeFolderPathA
()
{
return
getFolder
(
getExePathA
());
}
static
constexpr
const
wchar_t
*
DEFAULT_PATH_FILTERW
=
L"
\\
/:*?
\"
<>| "
;
static
constexpr
const
char
*
DEFAULT_PATH_FILTER
=
"
\\
/:*?
\"
<>| "
;
inline
std
::
wstring
integrateFileName
(
const
std
::
wstring
&
name
,
const
std
::
wstring
&
filter
=
DEFAULT_PATH_FILTERW
,
wchar_t
replace_by
=
L'_'
)
{
auto
ret
=
name
;
for
(
auto
c
:
filter
)
{
std
::
replace
(
ret
.
begin
(),
ret
.
end
(),
c
,
replace_by
);
}
return
ret
;
}
inline
std
::
string
integrateFileName
(
const
std
::
string
&
name
,
const
std
::
string
&
filter
=
DEFAULT_PATH_FILTER
,
char
replace_by
=
'_'
)
{
auto
ret
=
name
;
for
(
auto
c
:
filter
)
{
std
::
replace
(
ret
.
begin
(),
ret
.
end
(),
c
,
replace_by
);
}
return
ret
;
}
inline
std
::
wstring
getSpecialFolder
(
int
csidl
)
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
return
::
SHGetSpecialFolderPathW
(
nullptr
,
path
,
csidl
,
false
)
?
std
::
wstring
(
path
)
:
std
::
wstring
();
}
inline
std
::
string
getSpecialFolderA
(
int
csidl
)
{
char
path
[
MAX_PATH
]
=
{
0
};
return
::
SHGetSpecialFolderPathA
(
nullptr
,
path
,
csidl
,
false
)
?
std
::
string
(
path
)
:
std
::
string
();
}
/**
* @brief 获取%APPDATA%路径,一般用于存储程序配置文件
* @note 一般xp的结果为: C:\Documents and Setting\[UserName]\Application Data
* @note 一般vista及以上的结果为:C:\Users\[UserName]\AppData\Roaming
*/
inline
std
::
wstring
getAppDataPath
()
{
return
getSpecialFolder
(
CSIDL_APPDATA
);
}
inline
std
::
string
getAppDataPathA
()
{
return
getSpecialFolderA
(
CSIDL_APPDATA
);
}
inline
std
::
wstring
getTempPath
()
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
::
GetTempPathW
(
MAX_PATH
,
path
);
return
path
;
}
inline
std
::
string
getTempPathA
()
{
char
path
[
MAX_PATH
]
=
{
0
};
::
GetTempPathA
(
MAX_PATH
,
path
);
return
path
;
}
inline
std
::
wstring
getMyDocumentsPath
()
{
return
getSpecialFolder
(
CSIDL_MYDOCUMENTS
);
}
inline
std
::
string
getMyDocumentsPathA
()
{
return
getSpecialFolderA
(
CSIDL_MYDOCUMENTS
);
}
inline
std
::
wstring
getTempFileName
(
const
std
::
wstring
&
folder
,
const
std
::
wstring
&
pre
)
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
UINT
ret
=
::
GetTempFileNameW
(
folder
.
c_str
(),
pre
.
c_str
(),
0
,
path
);
if
(
ret
!=
0
)
{
return
path
;
}
return
std
::
wstring
();
}
inline
std
::
string
getTempFileName
(
const
std
::
string
&
folder
,
const
std
::
string
&
pre
)
{
char
path
[
MAX_PATH
]
=
{
0
};
UINT
ret
=
::
GetTempFileNameA
(
folder
.
c_str
(),
pre
.
c_str
(),
0
,
path
);
if
(
ret
!=
0
)
{
return
path
;
}
return
std
::
string
();
}
inline
std
::
wstring
getTempFileName
(
const
std
::
wstring
&
pre
=
L"JLIB"
)
{
return
getTempFileName
(
getTempPath
(),
pre
);
}
inline
std
::
string
getTempFileNameA
(
const
std
::
string
&
pre
=
"JLIB"
)
{
return
getTempFileName
(
getTempPathA
(),
pre
);
}
inline
bool
folderExists
(
const
std
::
wstring
&
folderPath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesW
(
folderPath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
folderExists
(
const
std
::
string
&
folderPath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesA
(
folderPath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
fileExists
(
const
std
::
wstring
&
filePath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesW
(
filePath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
!
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
fileExists
(
const
std
::
string
&
filePath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesA
(
filePath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
!
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
createDirectory
(
const
std
::
wstring
&
path
)
{
return
::
CreateDirectoryW
(
path
.
data
(),
nullptr
)
?
true
:
false
;
}
inline
bool
createDirectory
(
const
std
::
string
&
path
)
{
return
::
CreateDirectoryA
(
path
.
data
(),
nullptr
)
?
true
:
false
;
}
//! 应用程序典型路径辅助
//struct PathHelper {
//
//
//};
}
}
#pragma once
#include "../base/config.h"
#include <ShlObj.h>
#include <string>
#include <algorithm>
namespace
jlib
{
namespace
win32
{
inline
std
::
wstring
getExePath
()
{
wchar_t
path
[
1024
]
=
{
0
};
::
GetModuleFileNameW
(
nullptr
,
path
,
1024
);
return
path
;
}
inline
std
::
string
getExePathA
()
{
char
path
[
1024
]
=
{
0
};
::
GetModuleFileNameA
(
nullptr
,
path
,
1024
);
return
path
;
}
inline
std
::
wstring
getFolder
(
const
std
::
wstring
&
path
)
{
auto
pos
=
path
.
find_last_of
(
L"
\\
/"
);
return
pos
!=
path
.
npos
?
path
.
substr
(
0
,
pos
)
:
path
;
}
inline
std
::
string
getFolder
(
const
std
::
string
&
path
)
{
auto
pos
=
path
.
find_last_of
(
"
\\
/"
);
return
pos
!=
path
.
npos
?
path
.
substr
(
0
,
pos
)
:
path
;
}
inline
std
::
wstring
getExeFolderPath
()
{
return
getFolder
(
getExePath
());
}
inline
std
::
string
getExeFolderPathA
()
{
return
getFolder
(
getExePathA
());
}
static
constexpr
const
wchar_t
*
DEFAULT_PATH_FILTERW
=
L"
\\
/:*?
\"
<>| "
;
static
constexpr
const
char
*
DEFAULT_PATH_FILTER
=
"
\\
/:*?
\"
<>| "
;
inline
std
::
wstring
integrateFileName
(
const
std
::
wstring
&
name
,
const
std
::
wstring
&
filter
=
DEFAULT_PATH_FILTERW
,
wchar_t
replace_by
=
L'_'
)
{
auto
ret
=
name
;
for
(
auto
c
:
filter
)
{
std
::
replace
(
ret
.
begin
(),
ret
.
end
(),
c
,
replace_by
);
}
return
ret
;
}
inline
std
::
string
integrateFileName
(
const
std
::
string
&
name
,
const
std
::
string
&
filter
=
DEFAULT_PATH_FILTER
,
char
replace_by
=
'_'
)
{
auto
ret
=
name
;
for
(
auto
c
:
filter
)
{
std
::
replace
(
ret
.
begin
(),
ret
.
end
(),
c
,
replace_by
);
}
return
ret
;
}
inline
std
::
wstring
getSpecialFolder
(
int
csidl
)
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
return
::
SHGetSpecialFolderPathW
(
nullptr
,
path
,
csidl
,
false
)
?
std
::
wstring
(
path
)
:
std
::
wstring
();
}
inline
std
::
string
getSpecialFolderA
(
int
csidl
)
{
char
path
[
MAX_PATH
]
=
{
0
};
return
::
SHGetSpecialFolderPathA
(
nullptr
,
path
,
csidl
,
false
)
?
std
::
string
(
path
)
:
std
::
string
();
}
/**
* @brief 获取%APPDATA%路径,一般用于存储程序配置文件
* @note 一般xp的结果为: C:\Documents and Setting\[UserName]\Application Data
* @note 一般vista及以上的结果为:C:\Users\[UserName]\AppData\Roaming
*/
inline
std
::
wstring
getAppDataPath
()
{
return
getSpecialFolder
(
CSIDL_APPDATA
);
}
inline
std
::
string
getAppDataPathA
()
{
return
getSpecialFolderA
(
CSIDL_APPDATA
);
}
inline
std
::
wstring
getTempPath
()
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
::
GetTempPathW
(
MAX_PATH
,
path
);
return
path
;
}
inline
std
::
string
getTempPathA
()
{
char
path
[
MAX_PATH
]
=
{
0
};
::
GetTempPathA
(
MAX_PATH
,
path
);
return
path
;
}
inline
std
::
wstring
getMyDocumentsPath
()
{
return
getSpecialFolder
(
CSIDL_MYDOCUMENTS
);
}
inline
std
::
string
getMyDocumentsPathA
()
{
return
getSpecialFolderA
(
CSIDL_MYDOCUMENTS
);
}
inline
std
::
wstring
getTempFileName
(
const
std
::
wstring
&
folder
,
const
std
::
wstring
&
pre
)
{
wchar_t
path
[
MAX_PATH
]
=
{
0
};
UINT
ret
=
::
GetTempFileNameW
(
folder
.
c_str
(),
pre
.
c_str
(),
0
,
path
);
if
(
ret
!=
0
)
{
return
path
;
}
return
std
::
wstring
();
}
inline
std
::
string
getTempFileName
(
const
std
::
string
&
folder
,
const
std
::
string
&
pre
)
{
char
path
[
MAX_PATH
]
=
{
0
};
UINT
ret
=
::
GetTempFileNameA
(
folder
.
c_str
(),
pre
.
c_str
(),
0
,
path
);
if
(
ret
!=
0
)
{
return
path
;
}
return
std
::
string
();
}
inline
std
::
wstring
getTempFileName
(
const
std
::
wstring
&
pre
=
L"JLIB"
)
{
return
getTempFileName
(
getTempPath
(),
pre
);
}
inline
std
::
string
getTempFileNameA
(
const
std
::
string
&
pre
=
"JLIB"
)
{
return
getTempFileName
(
getTempPathA
(),
pre
);
}
inline
bool
folderExists
(
const
std
::
wstring
&
folderPath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesW
(
folderPath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
folderExists
(
const
std
::
string
&
folderPath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesA
(
folderPath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
fileExists
(
const
std
::
wstring
&
filePath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesW
(
filePath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
!
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
fileExists
(
const
std
::
string
&
filePath
)
{
DWORD
dwAttrib
=
::
GetFileAttributesA
(
filePath
.
data
());
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
)
&&
!
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
);
}
inline
bool
createDirectory
(
const
std
::
wstring
&
path
)
{
return
::
CreateDirectoryW
(
path
.
data
(),
nullptr
)
?
true
:
false
;
}
inline
bool
createDirectory
(
const
std
::
string
&
path
)
{
return
::
CreateDirectoryA
(
path
.
data
(),
nullptr
)
?
true
:
false
;
}
//! 应用程序典型路径辅助
//struct PathHelper {
//
//
//};
}
}
jlib/win32/process.h
View file @
c9174ca4
#
pragma
once
#include <Windows.h>
#include <tlhelp32.h>
#include <string>
#include <vector>
#include <functional>
#include <unordered_set>
#include "lasterror.h"
#include "UnicodeTool.h"
namespace
jlib
{
namespace
win32
{
/**
* @brief 启动程序
* @param path 启动命令
* @param wait_app_exit 是否阻塞等待程序退出
* @param show 是否显示程序
* @return 启动程序失败返回0xFFFFFFFF;当 wait_app_exit 为真,返回程序的进程返回值;否则返回程序进程ID;
*/
inline
DWORD
daemon
(
const
std
::
wstring
&
path
,
bool
wait_app_exit
=
true
,
bool
show
=
true
)
{
STARTUPINFOW
si
=
{
0
};
si
.
cb
=
sizeof
(
si
);
si
.
dwFlags
|=
STARTF_USESHOWWINDOW
;
si
.
wShowWindow
=
show
?
SW_SHOW
:
SW_HIDE
;
PROCESS_INFORMATION
pi
;
DWORD
dwCreationFlags
=
show
?
0
:
CREATE_NO_WINDOW
;
BOOL
bRet
=
CreateProcessW
(
NULL
,
(
LPWSTR
)(
path
.
c_str
()),
NULL
,
NULL
,
FALSE
,
dwCreationFlags
,
NULL
,
NULL
,
&
si
,
&
pi
);
if
(
bRet
)
{
if
(
wait_app_exit
)
{
WaitForSingleObject
(
pi
.
hProcess
,
INFINITE
);
DWORD
dwExit
;
::
GetExitCodeProcess
(
pi
.
hProcess
,
&
dwExit
);
CloseHandle
(
pi
.
hThread
);
CloseHandle
(
pi
.
hProcess
);
return
dwExit
;
}
else
{
return
pi
.
dwProcessId
;
}
}
else
{
auto
msg
=
formatLastError
(
""
);
(
void
)
msg
.
length
();
}
return
0xFFFFFFFF
;
}
/**
* @brief 启动程序
* @param path 启动命令
* @param wait_app_exit 是否阻塞等待程序退出
* @param show 是否显示程序
* @return 启动程序失败返回0xFFFFFFFF;当 wait_app_exit 为真,返回程序的进程返回值;否则返回程序进程ID;
*/
inline
DWORD
daemon
(
const
std
::
string
&
path
,
bool
wait_app_exit
=
true
,
bool
show
=
true
)
{
return
daemon
(
win32
::
mbcs_to_utf16
(
path
),
wait_app_exit
,
show
);
}
/**
* @brief 获取父进程ID
* @return 成功返回父进程ID,否则返回0
*/
inline
DWORD
getppid
()
{
HANDLE
hSnapshot
;
PROCESSENTRY32W
pe32
;
DWORD
ppid
=
0
,
pid
=
GetCurrentProcessId
();
hSnapshot
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS
,
pid
);
__try
{
if
(
hSnapshot
==
INVALID_HANDLE_VALUE
)
__leave
;
ZeroMemory
(
&
pe32
,
sizeof
(
pe32
));
pe32
.
dwSize
=
sizeof
(
pe32
);
if
(
!
Process32FirstW
(
hSnapshot
,
&
pe32
))
__leave
;
do
{
if
(
pe32
.
th32ProcessID
==
pid
)
{
ppid
=
pe32
.
th32ParentProcessID
;
break
;
}
}
while
(
Process32NextW
(
hSnapshot
,
&
pe32
));
}
__finally
{
if
(
hSnapshot
!=
INVALID_HANDLE_VALUE
)
CloseHandle
(
hSnapshot
);
}
return
ppid
;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// https://docs.microsoft.com/zh-cn/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
struct
ProcessInfo
{
struct
ModuleInfo
{
std
::
wstring
name
;
std
::
wstring
path
;
DWORD
pid
;
DWORD
base_address
;
DWORD
base_size
;
};
struct
ThreadInfo
{
DWORD
tid
;
DWORD
base_priority
;
DWORD
delta_priority
;
};
std
::
wstring
name
;
std
::
wstring
path
;
DWORD
pid
;
DWORD
ppid
;
DWORD
thread_count
;
DWORD
priority_base
;
DWORD
priority_class
;
std
::
vector
<
ModuleInfo
>
modules
;
std
::
vector
<
ThreadInfo
>
threads
;
template
<
typename
JsonValue
>
JsonValue
toJson
()
const
{
JsonValue
v
;
v
[
"name"
]
=
utf16_to_mbcs
(
name
);
v
[
"path"
]
=
utf16_to_mbcs
(
path
);
v
[
"pid"
]
=
(
size_t
)
pid
;
v
[
"ppid"
]
=
(
size_t
)
ppid
;
v
[
"thread_count"
]
=
(
size_t
)
thread_count
;
v
[
"priority_base"
]
=
(
size_t
)
priority_base
;
v
[
"priority_class"
]
=
(
size_t
)
priority_class
;
auto
&
ms
=
v
[
"modules"
];
for
(
const
auto
&
m
:
modules
)
{
JsonValue
jm
;
jm
[
"name"
]
=
utf16_to_mbcs
(
m
.
name
);
jm
[
"path"
]
=
utf16_to_mbcs
(
m
.
path
);
jm
[
"pid"
]
=
(
size_t
)
m
.
pid
;
jm
[
"base_address"
]
=
(
size_t
)
m
.
base_address
;
jm
[
"base_size"
]
=
(
size_t
)
m
.
base_size
;
ms
.
append
(
jm
);
}
auto
&
ts
=
v
[
"threads"
];
for
(
const
auto
&
t
:
threads
)
{
JsonValue
jt
;
jt
[
"tid"
]
=
(
size_t
)
t
.
tid
;
jt
[
"base_priority"
]
=
(
size_t
)
t
.
base_priority
;
jt
[
"delta_priority"
]
=
(
size_t
)
t
.
delta_priority
;
ts
.
append
(
jt
);
}
return
v
;
}
};
typedef
std
::
vector
<
ProcessInfo
>
ProcessInfos
;
template
<
typename
JsonValue
>
inline
JsonValue
toJson
(
const
ProcessInfos
&
pinfos
)
{
JsonValue
v
;
for
(
const
auto
&
pinfo
:
pinfos
)
{
v
.
append
(
pinfo
.
toJson
<
JsonValue
>
());
}
return
v
;
}
typedef
std
::
function
<
void
(
const
std
::
wstring
&
)
>
ErrorOutputFunc
;
inline
void
dummyErrorOutputFunc
(
const
std
::
wstring
&
msg
)
{
printf
(
"%ls
\n
"
,
msg
.
data
());
}
inline
void
outputLastErrorHelper
(
const
std
::
wstring
&
msg
,
ErrorOutputFunc
func
=
nullptr
)
{
if
(
!
func
)
{
return
;
}
func
(
formatLastError
(
msg
));
}
inline
std
::
vector
<
ProcessInfo
::
ModuleInfo
>
getProcessModules
(
DWORD
dwPID
,
ErrorOutputFunc
output
=
dummyErrorOutputFunc
)
{
std
::
vector
<
ProcessInfo
::
ModuleInfo
>
modules
=
{};
HANDLE
hModuleSnap
=
INVALID_HANDLE_VALUE
;
MODULEENTRY32
me32
;
// Take a snapshot of all modules in the specified process.
hModuleSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPMODULE
,
dwPID
);
if
(
hModuleSnap
==
INVALID_HANDLE_VALUE
)
{
outputLastErrorHelper
((
L"CreateToolhelp32Snapshot (of modules)"
),
output
);
return
(
modules
);
}
// Set the size of the structure before using it.
me32
.
dwSize
=
sizeof
(
MODULEENTRY32
);
// Retrieve information about the first module,
// and exit if unsuccessful
if
(
!
Module32First
(
hModuleSnap
,
&
me32
))
{
outputLastErrorHelper
((
L"Module32First"
),
output
);
// show cause of failure
CloseHandle
(
hModuleSnap
);
// clean the snapshot object
return
(
modules
);
}
// Now walk the module list of the process,
// and display information about each module
do
{
ProcessInfo
::
ModuleInfo
info
;
info
.
name
=
me32
.
szModule
;
info
.
path
=
me32
.
szExePath
;
info
.
pid
=
me32
.
th32ProcessID
;
info
.
base_address
=
(
DWORD
)
me32
.
modBaseAddr
;
info
.
base_size
=
me32
.
modBaseSize
;
modules
.
emplace_back
(
info
);
}
while
(
Module32Next
(
hModuleSnap
,
&
me32
));
CloseHandle
(
hModuleSnap
);
return
(
modules
);
}
inline
std
::
vector
<
ProcessInfo
::
ThreadInfo
>
getProcessThreads
(
DWORD
dwOwnerPID
,
ErrorOutputFunc
output
=
dummyErrorOutputFunc
)
{
std
::
vector
<
ProcessInfo
::
ThreadInfo
>
threads
=
{};
HANDLE
hThreadSnap
=
INVALID_HANDLE_VALUE
;
THREADENTRY32
te32
;
// Take a snapshot of all running threads
hThreadSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPTHREAD
,
dwOwnerPID
);
if
(
hThreadSnap
==
INVALID_HANDLE_VALUE
)
return
(
threads
);
// Fill in the size of the structure before using it.
te32
.
dwSize
=
sizeof
(
THREADENTRY32
);
// Retrieve information about the first thread,
// and exit if unsuccessful
if
(
!
Thread32First
(
hThreadSnap
,
&
te32
))
{
outputLastErrorHelper
((
L"Thread32First"
),
output
);
// show cause of failure
CloseHandle
(
hThreadSnap
);
// clean the snapshot object
return
(
threads
);
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if
(
te32
.
th32OwnerProcessID
==
dwOwnerPID
)
{
ProcessInfo
::
ThreadInfo
tinfo
;
tinfo
.
tid
=
te32
.
th32ThreadID
;
tinfo
.
base_priority
=
te32
.
tpBasePri
;
tinfo
.
delta_priority
=
te32
.
tpDeltaPri
;
threads
.
emplace_back
(
tinfo
);
}
}
while
(
Thread32Next
(
hThreadSnap
,
&
te32
));
CloseHandle
(
hThreadSnap
);
return
(
threads
);
}
static
const
wchar_t
*
PROCESS_FILTER
[]
=
{
L"[System Process]"
,
L"ApplicationFrameHost.exe"
,
L"AppVShNotify.exe"
,
L"audiodg.exe"
,
L"backgroundTaskHost.exe"
,
L"ChsIME.exe"
,
L"CompPkgSrv.exe"
,
L"conhost.exe"
,
L"csrss.exe"
,
L"ctfmon.exe"
,
L"dasHost.exe"
,
L"dllhost.exe"
,
L"dwm.exe"
,
L"fontdrvhost.exe"
,
L"GameBarFTServer.exe"
,
L"LockApp.exe"
,
L"LogonUI.exe"
,
L"lsass.exe"
,
L"lsm.exe"
,
L"Memory Compression"
,
L"Microsoft.Photos.exe"
,
L"msdtc.exe"
,
L"mstsc.exe"
,
L"pacjsworker.exe"
,
L"PresentationFontCache.exe"
,
L"rdpclip.exe"
,
L"Registry"
,
L"RemindersServer.exe"
,
L"rundll32.exe"
,
L"RuntimeBroker.exe"
,
L"schtasks.exe"
,
L"SearchFilterHost.exe"
,
L"SearchIndexer.exe"
,
L"SearchProtocolHost.exe"
,
L"SearchUI.exe"
,
L"SecurityHealthService.exe"
,
L"SecurityHealthSystray.exe"
,
L"services.exe"
,
L"SettingSyncHost.exe"
,
L"ShellExperienceHost.exe"
,
L"sihost.exe"
,
L"SkypeApp.exe"
,
L"SkypeBackgroundHost.exe"
,
L"SkypeBridge.exe"
,
L"smartscreen.exe"
,
L"smss.exe"
,
L"SgrmBroker.exe"
,
L"spoolsv.exe"
,
L"StartMenuExperienceHost.exe"
,
L"svchost.exe"
,
L"System"
,
L"SystemSettingsBroker.exe"
,
L"TabTip.exe"
,
L"taskhost.exe"
,
L"taskhostw.exe"
,
L"TiWorker.exe"
,
L"TrustedInstaller.exe"
,
L"Video.UI.exe"
,
L"WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe"
,
L"wininit.exe"
,
L"winlogon.exe"
,
L"WinStore.App.exe"
,
L"WmiPrvSE.exe"
,
L"wmpnetwk.exe"
,
L"WUDFHost.exe"
,
L"YourPhone.exe"
,
};
inline
ProcessInfos
getProcessesInfo
(
ErrorOutputFunc
output
=
dummyErrorOutputFunc
,
bool
withModules
=
false
,
bool
withThreads
=
false
,
const
wchar_t
**
filter
=
PROCESS_FILTER
,
size_t
filter_count
=
_countof
(
PROCESS_FILTER
))
{
// pre-process filter
std
::
unordered_set
<
std
::
wstring
>
filterset
;
for
(
size_t
i
=
0
;
i
<
filter_count
;
i
++
)
{
filterset
.
insert
(
filter
[
i
]);
}
HANDLE
hProcessSnap
;
HANDLE
hProcess
;
PROCESSENTRY32
pe32
;
DWORD
dwPriorityClass
;
ProcessInfos
pinfos
=
{};
// Take a snapshot of all processes in the system.
hProcessSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS
,
0
);
if
(
hProcessSnap
==
INVALID_HANDLE_VALUE
)
{
outputLastErrorHelper
(
L"CreateToolhelp32Snapshot (of processes)"
,
output
);
return
(
pinfos
);
}
// Set the size of the structure before using it.
pe32
.
dwSize
=
sizeof
(
PROCESSENTRY32
);
// Retrieve information about the first process,
// and exit if unsuccessful
if
(
!
Process32First
(
hProcessSnap
,
&
pe32
))
{
outputLastErrorHelper
((
L"Process32First"
),
output
);
// show cause of failure
CloseHandle
(
hProcessSnap
);
// clean the snapshot object
return
(
pinfos
);
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
if
(
filterset
.
find
(
pe32
.
szExeFile
)
!=
filterset
.
end
())
{
continue
;
}
ProcessInfo
pinfo
=
{};
pinfo
.
name
=
pe32
.
szExeFile
;
// Retrieve the priority class.
dwPriorityClass
=
0
;
hProcess
=
OpenProcess
(
PROCESS_ALL_ACCESS
,
FALSE
,
pe32
.
th32ProcessID
);
if
(
hProcess
==
NULL
)
outputLastErrorHelper
((
L"OpenProcess"
),
output
);
else
{
dwPriorityClass
=
GetPriorityClass
(
hProcess
);
if
(
!
dwPriorityClass
)
outputLastErrorHelper
((
L"GetPriorityClass"
),
output
);
}
pinfo
.
pid
=
pe32
.
th32ProcessID
;
pinfo
.
ppid
=
pe32
.
th32ParentProcessID
;
pinfo
.
thread_count
=
pe32
.
cntThreads
;
pinfo
.
priority_base
=
pe32
.
pcPriClassBase
;
if
(
dwPriorityClass
)
{
pinfo
.
priority_class
=
dwPriorityClass
;
}
// List the modules and threads associated with this process
pinfo
.
modules
=
getProcessModules
(
pe32
.
th32ProcessID
,
output
);
// try to get process exe path
if
(
!
pinfo
.
modules
.
empty
())
{
pinfo
.
path
=
pinfo
.
modules
.
front
().
path
;
}
if
(
!
withModules
)
{
pinfo
.
modules
.
clear
();
}
if
(
withThreads
)
{
pinfo
.
threads
=
getProcessThreads
(
pe32
.
th32ProcessID
,
output
);
}
// try to get process exe path again
if
(
pinfo
.
path
.
empty
())
{
if
(
!
hProcess
)
{
hProcess
=
OpenProcess
(
PROCESS_QUERY_LIMITED_INFORMATION
,
FALSE
,
pe32
.
th32ProcessID
);
}
if
(
hProcess
)
{
wchar_t
path
[
4096
];
DWORD
len
=
4096
;
if
(
QueryFullProcessImageNameW
(
hProcess
,
0
,
path
,
&
len
))
{
pinfo
.
path
=
path
;
}
else
{
outputLastErrorHelper
(
L"QueryFullProcessImageNameW"
,
output
);
}
}
else
{
outputLastErrorHelper
(
L"OpenProcess"
,
output
);
}
}
pinfos
.
emplace_back
(
pinfo
);
if
(
hProcess
){
CloseHandle
(
hProcess
);
}
}
while
(
Process32Next
(
hProcessSnap
,
&
pe32
));
CloseHandle
(
hProcessSnap
);
return
(
pinfos
);
}
}
// namespace win32
}
// namespace jlib
#pragma once
#include <Windows.h>
#include <tlhelp32.h>
#include <string>
#include <vector>
#include <functional>
#include <unordered_set>
#include "lasterror.h"
#include "UnicodeTool.h"
namespace
jlib
{
namespace
win32
{
/**
* @brief 启动程序
* @param path 启动命令
* @param wait_app_exit 是否阻塞等待程序退出
* @param show 是否显示程序
* @return 启动程序失败返回0xFFFFFFFF;当 wait_app_exit 为真,返回程序的进程返回值;否则返回程序进程ID;
*/
inline
DWORD
daemon
(
const
std
::
wstring
&
path
,
bool
wait_app_exit
=
true
,
bool
show
=
true
)
{
STARTUPINFOW
si
=
{
0
};
si
.
cb
=
sizeof
(
si
);
si
.
dwFlags
|=
STARTF_USESHOWWINDOW
;
si
.
wShowWindow
=
show
?
SW_SHOW
:
SW_HIDE
;
PROCESS_INFORMATION
pi
;
DWORD
dwCreationFlags
=
show
?
0
:
CREATE_NO_WINDOW
;
BOOL
bRet
=
CreateProcessW
(
NULL
,
(
LPWSTR
)(
path
.
c_str
()),
NULL
,
NULL
,
FALSE
,
dwCreationFlags
,
NULL
,
NULL
,
&
si
,
&
pi
);
if
(
bRet
)
{
if
(
wait_app_exit
)
{
WaitForSingleObject
(
pi
.
hProcess
,
INFINITE
);
DWORD
dwExit
;
::
GetExitCodeProcess
(
pi
.
hProcess
,
&
dwExit
);
CloseHandle
(
pi
.
hThread
);
CloseHandle
(
pi
.
hProcess
);
return
dwExit
;
}
else
{
return
pi
.
dwProcessId
;
}
}
else
{
auto
msg
=
formatLastError
(
""
);
(
void
)
msg
.
length
();
}
return
0xFFFFFFFF
;
}
/**
* @brief 启动程序
* @param path 启动命令
* @param wait_app_exit 是否阻塞等待程序退出
* @param show 是否显示程序
* @return 启动程序失败返回0xFFFFFFFF;当 wait_app_exit 为真,返回程序的进程返回值;否则返回程序进程ID;
*/
inline
DWORD
daemon
(
const
std
::
string
&
path
,
bool
wait_app_exit
=
true
,
bool
show
=
true
)
{
return
daemon
(
win32
::
mbcs_to_utf16
(
path
),
wait_app_exit
,
show
);
}
/**
* @brief 获取父进程ID
* @return 成功返回父进程ID,否则返回0
*/
inline
DWORD
getppid
()
{
HANDLE
hSnapshot
;
PROCESSENTRY32W
pe32
;
DWORD
ppid
=
0
,
pid
=
GetCurrentProcessId
();
hSnapshot
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS
,
pid
);
__try
{
if
(
hSnapshot
==
INVALID_HANDLE_VALUE
)
__leave
;
ZeroMemory
(
&
pe32
,
sizeof
(
pe32
));
pe32
.
dwSize
=
sizeof
(
pe32
);
if
(
!
Process32FirstW
(
hSnapshot
,
&
pe32
))
__leave
;
do
{
if
(
pe32
.
th32ProcessID
==
pid
)
{
ppid
=
pe32
.
th32ParentProcessID
;
break
;
}
}
while
(
Process32NextW
(
hSnapshot
,
&
pe32
));
}
__finally
{
if
(
hSnapshot
!=
INVALID_HANDLE_VALUE
)
CloseHandle
(
hSnapshot
);
}
return
ppid
;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// https://docs.microsoft.com/zh-cn/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
struct
ProcessInfo
{
struct
ModuleInfo
{
std
::
wstring
name
;
std
::
wstring
path
;
DWORD
pid
;
DWORD
base_address
;
DWORD
base_size
;
};
struct
ThreadInfo
{
DWORD
tid
;
DWORD
base_priority
;
DWORD
delta_priority
;
};
std
::
wstring
name
;
std
::
wstring
path
;
DWORD
pid
;
DWORD
ppid
;
DWORD
thread_count
;
DWORD
priority_base
;
DWORD
priority_class
;
std
::
vector
<
ModuleInfo
>
modules
;
std
::
vector
<
ThreadInfo
>
threads
;
template
<
typename
JsonValue
>
JsonValue
toJson
()
const
{
JsonValue
v
;
v
[
"name"
]
=
utf16_to_mbcs
(
name
);
v
[
"path"
]
=
utf16_to_mbcs
(
path
);
v
[
"pid"
]
=
(
size_t
)
pid
;
v
[
"ppid"
]
=
(
size_t
)
ppid
;
v
[
"thread_count"
]
=
(
size_t
)
thread_count
;
v
[
"priority_base"
]
=
(
size_t
)
priority_base
;
v
[
"priority_class"
]
=
(
size_t
)
priority_class
;
auto
&
ms
=
v
[
"modules"
];
for
(
const
auto
&
m
:
modules
)
{
JsonValue
jm
;
jm
[
"name"
]
=
utf16_to_mbcs
(
m
.
name
);
jm
[
"path"
]
=
utf16_to_mbcs
(
m
.
path
);
jm
[
"pid"
]
=
(
size_t
)
m
.
pid
;
jm
[
"base_address"
]
=
(
size_t
)
m
.
base_address
;
jm
[
"base_size"
]
=
(
size_t
)
m
.
base_size
;
ms
.
append
(
jm
);
}
auto
&
ts
=
v
[
"threads"
];
for
(
const
auto
&
t
:
threads
)
{
JsonValue
jt
;
jt
[
"tid"
]
=
(
size_t
)
t
.
tid
;
jt
[
"base_priority"
]
=
(
size_t
)
t
.
base_priority
;
jt
[
"delta_priority"
]
=
(
size_t
)
t
.
delta_priority
;
ts
.
append
(
jt
);
}
return
v
;
}
};
typedef
std
::
vector
<
ProcessInfo
>
ProcessInfos
;
template
<
typename
JsonValue
>
inline
JsonValue
toJson
(
const
ProcessInfos
&
pinfos
)
{
JsonValue
v
;
for
(
const
auto
&
pinfo
:
pinfos
)
{
v
.
append
(
pinfo
.
toJson
<
JsonValue
>
());
}
return
v
;
}
typedef
std
::
function
<
void
(
const
std
::
wstring
&
)
>
ErrorOutputFunc
;
inline
void
dummyErrorOutputFunc
(
const
std
::
wstring
&
msg
)
{
printf
(
"%ls
\n
"
,
msg
.
data
());
}
inline
void
outputLastErrorHelper
(
const
std
::
wstring
&
msg
,
ErrorOutputFunc
func
=
nullptr
)
{
if
(
!
func
)
{
return
;
}
func
(
formatLastError
(
msg
));
}
inline
std
::
vector
<
ProcessInfo
::
ModuleInfo
>
getProcessModules
(
DWORD
dwPID
,
ErrorOutputFunc
output
=
dummyErrorOutputFunc
)
{
std
::
vector
<
ProcessInfo
::
ModuleInfo
>
modules
=
{};
HANDLE
hModuleSnap
=
INVALID_HANDLE_VALUE
;
MODULEENTRY32
me32
;
// Take a snapshot of all modules in the specified process.
hModuleSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPMODULE
,
dwPID
);
if
(
hModuleSnap
==
INVALID_HANDLE_VALUE
)
{
outputLastErrorHelper
((
L"CreateToolhelp32Snapshot (of modules)"
),
output
);
return
(
modules
);
}
// Set the size of the structure before using it.
me32
.
dwSize
=
sizeof
(
MODULEENTRY32
);
// Retrieve information about the first module,
// and exit if unsuccessful
if
(
!
Module32First
(
hModuleSnap
,
&
me32
))
{
outputLastErrorHelper
((
L"Module32First"
),
output
);
// show cause of failure
CloseHandle
(
hModuleSnap
);
// clean the snapshot object
return
(
modules
);
}
// Now walk the module list of the process,
// and display information about each module
do
{
ProcessInfo
::
ModuleInfo
info
;
info
.
name
=
me32
.
szModule
;
info
.
path
=
me32
.
szExePath
;
info
.
pid
=
me32
.
th32ProcessID
;
info
.
base_address
=
(
DWORD
)
me32
.
modBaseAddr
;
info
.
base_size
=
me32
.
modBaseSize
;
modules
.
emplace_back
(
info
);
}
while
(
Module32Next
(
hModuleSnap
,
&
me32
));
CloseHandle
(
hModuleSnap
);
return
(
modules
);
}
inline
std
::
vector
<
ProcessInfo
::
ThreadInfo
>
getProcessThreads
(
DWORD
dwOwnerPID
,
ErrorOutputFunc
output
=
dummyErrorOutputFunc
)
{
std
::
vector
<
ProcessInfo
::
ThreadInfo
>
threads
=
{};
HANDLE
hThreadSnap
=
INVALID_HANDLE_VALUE
;
THREADENTRY32
te32
;
// Take a snapshot of all running threads
hThreadSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPTHREAD
,
dwOwnerPID
);
if
(
hThreadSnap
==
INVALID_HANDLE_VALUE
)
return
(
threads
);
// Fill in the size of the structure before using it.
te32
.
dwSize
=
sizeof
(
THREADENTRY32
);
// Retrieve information about the first thread,
// and exit if unsuccessful
if
(
!
Thread32First
(
hThreadSnap
,
&
te32
))
{
outputLastErrorHelper
((
L"Thread32First"
),
output
);
// show cause of failure
CloseHandle
(
hThreadSnap
);
// clean the snapshot object
return
(
threads
);
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if
(
te32
.
th32OwnerProcessID
==
dwOwnerPID
)
{
ProcessInfo
::
ThreadInfo
tinfo
;
tinfo
.
tid
=
te32
.
th32ThreadID
;
tinfo
.
base_priority
=
te32
.
tpBasePri
;
tinfo
.
delta_priority
=
te32
.
tpDeltaPri
;
threads
.
emplace_back
(
tinfo
);
}
}
while
(
Thread32Next
(
hThreadSnap
,
&
te32
));
CloseHandle
(
hThreadSnap
);
return
(
threads
);
}
static
const
wchar_t
*
PROCESS_FILTER
[]
=
{
L"[System Process]"
,
L"ApplicationFrameHost.exe"
,
L"AppVShNotify.exe"
,
L"audiodg.exe"
,
L"backgroundTaskHost.exe"
,
L"ChsIME.exe"
,
L"CompPkgSrv.exe"
,
L"conhost.exe"
,
L"csrss.exe"
,
L"ctfmon.exe"
,
L"dasHost.exe"
,
L"dllhost.exe"
,
L"dwm.exe"
,
L"fontdrvhost.exe"
,
L"GameBarFTServer.exe"
,
L"LockApp.exe"
,
L"LogonUI.exe"
,
L"lsass.exe"
,
L"lsm.exe"
,
L"Memory Compression"
,
L"Microsoft.Photos.exe"
,
L"msdtc.exe"
,
L"mstsc.exe"
,
L"pacjsworker.exe"
,
L"PresentationFontCache.exe"
,
L"rdpclip.exe"
,
L"Registry"
,
L"RemindersServer.exe"
,
L"rundll32.exe"
,
L"RuntimeBroker.exe"
,
L"schtasks.exe"
,
L"SearchFilterHost.exe"
,
L"SearchIndexer.exe"
,
L"SearchProtocolHost.exe"
,
L"SearchUI.exe"
,
L"SecurityHealthService.exe"
,
L"SecurityHealthSystray.exe"
,
L"services.exe"
,
L"SettingSyncHost.exe"
,
L"ShellExperienceHost.exe"
,
L"sihost.exe"
,
L"SkypeApp.exe"
,
L"SkypeBackgroundHost.exe"
,
L"SkypeBridge.exe"
,
L"smartscreen.exe"
,
L"smss.exe"
,
L"SgrmBroker.exe"
,
L"spoolsv.exe"
,
L"StartMenuExperienceHost.exe"
,
L"svchost.exe"
,
L"System"
,
L"SystemSettingsBroker.exe"
,
L"TabTip.exe"
,
L"taskhost.exe"
,
L"taskhostw.exe"
,
L"TiWorker.exe"
,
L"TrustedInstaller.exe"
,
L"Video.UI.exe"
,
L"WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe"
,
L"wininit.exe"
,
L"winlogon.exe"
,
L"WinStore.App.exe"
,
L"WmiPrvSE.exe"
,
L"wmpnetwk.exe"
,
L"WUDFHost.exe"
,
L"YourPhone.exe"
,
};
inline
ProcessInfos
getProcessesInfo
(
ErrorOutputFunc
output
=
dummyErrorOutputFunc
,
bool
withModules
=
false
,
bool
withThreads
=
false
,
const
wchar_t
**
filter
=
PROCESS_FILTER
,
size_t
filter_count
=
_countof
(
PROCESS_FILTER
))
{
// pre-process filter
std
::
unordered_set
<
std
::
wstring
>
filterset
;
for
(
size_t
i
=
0
;
i
<
filter_count
;
i
++
)
{
filterset
.
insert
(
filter
[
i
]);
}
HANDLE
hProcessSnap
;
HANDLE
hProcess
;
PROCESSENTRY32
pe32
;
DWORD
dwPriorityClass
;
ProcessInfos
pinfos
=
{};
// Take a snapshot of all processes in the system.
hProcessSnap
=
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS
,
0
);
if
(
hProcessSnap
==
INVALID_HANDLE_VALUE
)
{
outputLastErrorHelper
(
L"CreateToolhelp32Snapshot (of processes)"
,
output
);
return
(
pinfos
);
}
// Set the size of the structure before using it.
pe32
.
dwSize
=
sizeof
(
PROCESSENTRY32
);
// Retrieve information about the first process,
// and exit if unsuccessful
if
(
!
Process32First
(
hProcessSnap
,
&
pe32
))
{
outputLastErrorHelper
((
L"Process32First"
),
output
);
// show cause of failure
CloseHandle
(
hProcessSnap
);
// clean the snapshot object
return
(
pinfos
);
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
if
(
filterset
.
find
(
pe32
.
szExeFile
)
!=
filterset
.
end
())
{
continue
;
}
ProcessInfo
pinfo
=
{};
pinfo
.
name
=
pe32
.
szExeFile
;
// Retrieve the priority class.
dwPriorityClass
=
0
;
hProcess
=
OpenProcess
(
PROCESS_ALL_ACCESS
,
FALSE
,
pe32
.
th32ProcessID
);
if
(
hProcess
==
NULL
)
outputLastErrorHelper
((
L"OpenProcess"
),
output
);
else
{
dwPriorityClass
=
GetPriorityClass
(
hProcess
);
if
(
!
dwPriorityClass
)
outputLastErrorHelper
((
L"GetPriorityClass"
),
output
);
}
pinfo
.
pid
=
pe32
.
th32ProcessID
;
pinfo
.
ppid
=
pe32
.
th32ParentProcessID
;
pinfo
.
thread_count
=
pe32
.
cntThreads
;
pinfo
.
priority_base
=
pe32
.
pcPriClassBase
;
if
(
dwPriorityClass
)
{
pinfo
.
priority_class
=
dwPriorityClass
;
}
// List the modules and threads associated with this process
pinfo
.
modules
=
getProcessModules
(
pe32
.
th32ProcessID
,
output
);
// try to get process exe path
if
(
!
pinfo
.
modules
.
empty
())
{
pinfo
.
path
=
pinfo
.
modules
.
front
().
path
;
}
if
(
!
withModules
)
{
pinfo
.
modules
.
clear
();
}
if
(
withThreads
)
{
pinfo
.
threads
=
getProcessThreads
(
pe32
.
th32ProcessID
,
output
);
}
// try to get process exe path again
if
(
pinfo
.
path
.
empty
())
{
if
(
!
hProcess
)
{
hProcess
=
OpenProcess
(
PROCESS_QUERY_LIMITED_INFORMATION
,
FALSE
,
pe32
.
th32ProcessID
);
}
if
(
hProcess
)
{
wchar_t
path
[
4096
];
DWORD
len
=
4096
;
if
(
QueryFullProcessImageNameW
(
hProcess
,
0
,
path
,
&
len
))
{
pinfo
.
path
=
path
;
}
else
{
outputLastErrorHelper
(
L"QueryFullProcessImageNameW"
,
output
);
}
}
else
{
outputLastErrorHelper
(
L"OpenProcess"
,
output
);
}
}
pinfos
.
emplace_back
(
pinfo
);
if
(
hProcess
){
CloseHandle
(
hProcess
);
}
}
while
(
Process32Next
(
hProcessSnap
,
&
pe32
));
CloseHandle
(
hProcessSnap
);
return
(
pinfos
);
}
}
// namespace win32
}
// namespace jlib
jlib/win32/rect.h
View file @
c9174ca4
#
pragma
once
#include <Windows.h>
#include <vector>
namespace
jlib
{
namespace
win32
{
inline
long
width
(
::
LPCRECT
rc
)
{
return
rc
->
right
-
rc
->
left
;
}
inline
long
height
(
::
LPCRECT
rc
)
{
return
rc
->
bottom
-
rc
->
top
;
}
inline
void
deflateRect
(
::
LPRECT
rc
,
int
l
,
int
t
,
int
r
,
int
b
)
{
rc
->
left
+=
l
;
rc
->
top
+=
t
;
rc
->
right
-=
r
;
rc
->
bottom
-=
b
;
}
inline
void
inflateRect
(
::
LPRECT
rc
,
int
l
,
int
t
,
int
r
,
int
b
)
{
rc
->
left
-=
l
;
rc
->
top
-=
t
;
rc
->
right
+=
r
;
rc
->
bottom
+=
b
;
}
//! 将矩形平均分割成 n 份,间距 2*gap, n 必须是平方数 x^2, x={1,2,3...}
inline
std
::
vector
<::
RECT
>
splitRect
(
::
LPCRECT
rc
,
int
n
,
int
gap
=
50
)
{
std
::
vector
<::
RECT
>
v
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
v
.
push_back
(
*
rc
);
}
double
l
=
sqrt
(
n
);
int
line
=
int
(
l
);
int
col_step
=
(
int
)(
width
(
rc
)
/
line
);
int
row_step
=
(
int
)(
height
(
rc
)
/
line
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
v
[
i
].
left
=
rc
->
left
+
(
i
%
line
)
*
col_step
;
v
[
i
].
right
=
v
[
i
].
left
+
col_step
;
v
[
i
].
top
=
rc
->
top
+
(
i
/
line
)
*
row_step
;
v
[
i
].
bottom
=
v
[
i
].
top
+
row_step
;
deflateRect
(
&
v
[
i
],
gap
,
gap
,
gap
,
gap
);
}
return
v
;
};
//! 将矩形水平平均分割为 n 份矩形, 当 hgap == -1 时,分割出的矩形与源矩形保持比例
inline
std
::
vector
<::
RECT
>
split_rect_horizontal
(
::
LPCRECT
rc
,
int
n
,
int
wgap
=
50
,
int
hgap
=
-
1
)
{
std
::
vector
<::
RECT
>
v
;
int
w
=
(
width
(
rc
)
-
(
n
+
1
)
*
wgap
)
/
n
;
if
(
hgap
==
-
1
)
{
double
ratio
=
(
rc
->
right
-
rc
->
left
)
*
1
.
0
/
(
rc
->
bottom
-
rc
->
top
);
int
h
=
static_cast
<
int
>
(
w
/
ratio
);
hgap
=
(
height
(
rc
)
-
h
)
/
2
;
}
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
::
RECT
r
=
*
rc
;
r
.
left
+=
i
*
w
+
(
i
+
1
)
*
wgap
;
r
.
right
=
r
.
left
+
w
;
r
.
top
=
rc
->
top
+
hgap
;
r
.
bottom
=
rc
->
bottom
-
hgap
;
v
.
push_back
(
r
);
}
return
v
;
}
/**
* @brief 从矩形内获取六边形顶点
* @param rc 矩形
* @param spliter 六边形的边长是矩形边长的 1/spliter
* @note rc's width / spliter = (rc's width - hexagon's side length) / 2
* @return 六边形的六个顶点坐标,从上边左侧点顺时针排列
*/
inline
std
::
vector
<::
POINT
>
getHexagonVertexesFromRect
(
::
LPCRECT
rc
,
float
spliter
=
3
.
0
)
{
if
(
!
rc
)
{
return
std
::
vector
<::
POINT
>
();
}
if
(
spliter
==
0
.
0
)
{
spliter
=
3
.
0
;
}
std
::
vector
<::
POINT
>
v
;
auto
w
=
rc
->
right
-
rc
->
left
;
auto
h
=
rc
->
bottom
-
rc
->
top
;
auto
ww
=
static_cast
<
int
>
(
w
/
spliter
);
auto
hh
=
static_cast
<
int
>
(
h
/
spliter
);
::
POINT
pt
;
pt
.
x
=
rc
->
left
;
pt
.
y
=
rc
->
top
+
hh
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
+
ww
;
pt
.
y
=
rc
->
top
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
-
ww
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
;
pt
.
y
=
rc
->
top
+
hh
;
v
.
push_back
(
pt
);
pt
.
y
=
rc
->
bottom
-
hh
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
-
ww
;
pt
.
y
=
rc
->
bottom
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
+
ww
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
;
pt
.
y
=
rc
->
bottom
-
hh
;
v
.
push_back
(
pt
);
return
v
;
}
}
}
#pragma once
#include <Windows.h>
#include <vector>
namespace
jlib
{
namespace
win32
{
inline
long
width
(
::
LPCRECT
rc
)
{
return
rc
->
right
-
rc
->
left
;
}
inline
long
height
(
::
LPCRECT
rc
)
{
return
rc
->
bottom
-
rc
->
top
;
}
inline
void
deflateRect
(
::
LPRECT
rc
,
int
l
,
int
t
,
int
r
,
int
b
)
{
rc
->
left
+=
l
;
rc
->
top
+=
t
;
rc
->
right
-=
r
;
rc
->
bottom
-=
b
;
}
inline
void
inflateRect
(
::
LPRECT
rc
,
int
l
,
int
t
,
int
r
,
int
b
)
{
rc
->
left
-=
l
;
rc
->
top
-=
t
;
rc
->
right
+=
r
;
rc
->
bottom
+=
b
;
}
//! 将矩形平均分割成 n 份,间距 2*gap, n 必须是平方数 x^2, x={1,2,3...}
inline
std
::
vector
<::
RECT
>
splitRect
(
::
LPCRECT
rc
,
int
n
,
int
gap
=
50
)
{
std
::
vector
<::
RECT
>
v
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
v
.
push_back
(
*
rc
);
}
double
l
=
sqrt
(
n
);
int
line
=
int
(
l
);
int
col_step
=
(
int
)(
width
(
rc
)
/
line
);
int
row_step
=
(
int
)(
height
(
rc
)
/
line
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
v
[
i
].
left
=
rc
->
left
+
(
i
%
line
)
*
col_step
;
v
[
i
].
right
=
v
[
i
].
left
+
col_step
;
v
[
i
].
top
=
rc
->
top
+
(
i
/
line
)
*
row_step
;
v
[
i
].
bottom
=
v
[
i
].
top
+
row_step
;
deflateRect
(
&
v
[
i
],
gap
,
gap
,
gap
,
gap
);
}
return
v
;
};
//! 将矩形水平平均分割为 n 份矩形, 当 hgap == -1 时,分割出的矩形与源矩形保持比例
inline
std
::
vector
<::
RECT
>
split_rect_horizontal
(
::
LPCRECT
rc
,
int
n
,
int
wgap
=
50
,
int
hgap
=
-
1
)
{
std
::
vector
<::
RECT
>
v
;
int
w
=
(
width
(
rc
)
-
(
n
+
1
)
*
wgap
)
/
n
;
if
(
hgap
==
-
1
)
{
double
ratio
=
(
rc
->
right
-
rc
->
left
)
*
1
.
0
/
(
rc
->
bottom
-
rc
->
top
);
int
h
=
static_cast
<
int
>
(
w
/
ratio
);
hgap
=
(
height
(
rc
)
-
h
)
/
2
;
}
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
::
RECT
r
=
*
rc
;
r
.
left
+=
i
*
w
+
(
i
+
1
)
*
wgap
;
r
.
right
=
r
.
left
+
w
;
r
.
top
=
rc
->
top
+
hgap
;
r
.
bottom
=
rc
->
bottom
-
hgap
;
v
.
push_back
(
r
);
}
return
v
;
}
/**
* @brief 从矩形内获取六边形顶点
* @param rc 矩形
* @param spliter 六边形的边长是矩形边长的 1/spliter
* @note rc's width / spliter = (rc's width - hexagon's side length) / 2
* @return 六边形的六个顶点坐标,从上边左侧点顺时针排列
*/
inline
std
::
vector
<::
POINT
>
getHexagonVertexesFromRect
(
::
LPCRECT
rc
,
float
spliter
=
3
.
0
)
{
if
(
!
rc
)
{
return
std
::
vector
<::
POINT
>
();
}
if
(
spliter
==
0
.
0
)
{
spliter
=
3
.
0
;
}
std
::
vector
<::
POINT
>
v
;
auto
w
=
rc
->
right
-
rc
->
left
;
auto
h
=
rc
->
bottom
-
rc
->
top
;
auto
ww
=
static_cast
<
int
>
(
w
/
spliter
);
auto
hh
=
static_cast
<
int
>
(
h
/
spliter
);
::
POINT
pt
;
pt
.
x
=
rc
->
left
;
pt
.
y
=
rc
->
top
+
hh
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
+
ww
;
pt
.
y
=
rc
->
top
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
-
ww
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
;
pt
.
y
=
rc
->
top
+
hh
;
v
.
push_back
(
pt
);
pt
.
y
=
rc
->
bottom
-
hh
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
right
-
ww
;
pt
.
y
=
rc
->
bottom
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
+
ww
;
v
.
push_back
(
pt
);
pt
.
x
=
rc
->
left
;
pt
.
y
=
rc
->
bottom
-
hh
;
v
.
push_back
(
pt
);
return
v
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment