mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-06-14 03:16:38 +10:00
Update Shell.
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F0C84812-0CDF-4AA0-A0F8-F37AC833F39B}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>appinstaller</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;HMODULE_MODE_EXE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;$(OutDir)pkgread.lib;$(OutDir)pkgmgr.lib;$(OutDir)certmgr.lib;$(OutDir)priformatcli.lib;$(OutDir)notice.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;HMODULE_MODE_EXE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;$(OutDir)pkgread.lib;$(OutDir)pkgmgr.lib;$(OutDir)certmgr.lib;$(OutDir)priformatcli.lib;$(OutDir)notice.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cmdargs.h" />
|
||||
<ClInclude Include="dynarr.h" />
|
||||
<ClInclude Include="filepath.h" />
|
||||
<ClInclude Include="ieshell.h" />
|
||||
<ClInclude Include="initfile.h" />
|
||||
<ClInclude Include="module.h" />
|
||||
<ClInclude Include="mpstr.h" />
|
||||
<ClInclude Include="nstring.h" />
|
||||
<ClInclude Include="raii.h" />
|
||||
<ClInclude Include="rctools.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="strcmp.h" />
|
||||
<ClInclude Include="strcode.h" />
|
||||
<ClInclude Include="themeinfo.h" />
|
||||
<ClInclude Include="typestrans.h" />
|
||||
<ClInclude Include="vemani.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="appinstaller.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\icons\color.ico" />
|
||||
<Image Include="res\icons\file.ico" />
|
||||
<Image Include="res\icons\main.ico" />
|
||||
<Image Include="res\icons\taskbar.ico" />
|
||||
<Image Include="res\icons\white.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\packages\pugixml.1.15.0\build\native\pugixml.targets" Condition="Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\pugixml.1.15.0\build\native\pugixml.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cmdargs.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filepath.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="initfile.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="module.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mpstr.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nstring.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rctools.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="strcmp.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="typestrans.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="raii.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="themeinfo.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="strcode.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vemani.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dynarr.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ieshell.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="appinstaller.rc">
|
||||
<Filter>资源文件</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\icons\color.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
<Image Include="res\icons\file.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
<Image Include="res\icons\taskbar.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
<Image Include="res\icons\white.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
<Image Include="res\icons\main.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "nstring.h"
|
||||
#include "rctools.h"
|
||||
#include "filepath.h"
|
||||
#include "raii.h"
|
||||
|
||||
// 允许忽视命令行前缀。如当命令行前缀为“-”"/"时,且开启此项,则输入“-args”与"/args"和"args" 是等效的
|
||||
#define CMDARG_IGNOREPREFIXS 0b001
|
||||
// 允许参数后跟着值,如“/args=file”,但要求必须配置后缀,且是有效的字符
|
||||
#define CMDARG_ENABLEPARAMS 0b010
|
||||
// 当 CMDARG_ENABLEPARAMS 开启时允许参数为空。如 “/args=file”和"/args"都是允许的
|
||||
#define CMDARG_IGNOREPARAMS 0b100
|
||||
// 命令行参数
|
||||
struct cmdarg
|
||||
{
|
||||
std::vector <std::wstring> prefixs; // 允许无前缀(长度为 0)
|
||||
std::vector <std::wstring> commands; // 参数(长度不能为 0,不能为空)
|
||||
std::vector <std::wstring> postfixs; // 允许无后缀(长度为 0)
|
||||
std::wstring uniquelabel; // 唯一标识,参数名
|
||||
std::wstring description; // 描述,用于生成帮助文本
|
||||
DWORD flags; // 标志
|
||||
};
|
||||
#define CMDARG_PREFIXS_DEFAULT {L"-", L"/"}
|
||||
#define CMDARG_POSTFIXS_DEFAULT {}
|
||||
std::vector <cmdarg> g_argslist = {
|
||||
{CMDARG_PREFIXS_DEFAULT, {L"silent", L"quiet", L"passive"}, CMDARG_POSTFIXS_DEFAULT, L"silent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
|
||||
{CMDARG_PREFIXS_DEFAULT, {L"verysilent", L"veryquiet"}, CMDARG_POSTFIXS_DEFAULT, L"verysilent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
|
||||
{CMDARG_PREFIXS_DEFAULT, {L"multiple", L"filelist"}, {L"="}, L"multiple", GetRCStringSW (0), CMDARG_IGNOREPREFIXS | CMDARG_ENABLEPARAMS}
|
||||
};
|
||||
bool IsFile (const std::wstring &path)
|
||||
{
|
||||
return IsPathExists (path);
|
||||
}
|
||||
bool IsURI (const std::wstring &str)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto uristr = gcnew System::String (str.c_str ());
|
||||
auto uri = gcnew System::Uri (uristr);
|
||||
return uri != nullptr;
|
||||
}
|
||||
catch (...) { return false; }
|
||||
}
|
||||
enum class paramtype
|
||||
{
|
||||
string,
|
||||
file,
|
||||
uri
|
||||
};
|
||||
struct cmdkey
|
||||
{
|
||||
std::wnstring key; // 键
|
||||
paramtype type; // 键类型,当传入的参数是存在的文件路径时(如“C:\1.txt”)则键的类型为文件。同理也可设置为 uri
|
||||
operator std::wnstring () { return key; }
|
||||
operator LPCWSTR () { return key.c_str (); }
|
||||
cmdkey (const std::wstring &k): key (k)
|
||||
{
|
||||
if (IsFile (k)) type = paramtype::file;
|
||||
else if (IsURI (k)) type = paramtype::uri;
|
||||
else type = paramtype::string;
|
||||
}
|
||||
cmdkey (const std::wstring &k, paramtype pt): key (k), type (pt) {}
|
||||
bool operator == (const cmdkey &r) const { return key == r.key; }
|
||||
bool operator > (const cmdkey &r) const { return key > r.key; }
|
||||
bool operator < (const cmdkey &r) const { return key < r.key; }
|
||||
};
|
||||
struct cmdvalue
|
||||
{
|
||||
std::wstring value; // 值
|
||||
paramtype type;
|
||||
bool isnull; // 当参数不支持跟着值时,或允许时值为空时设置为真。
|
||||
};
|
||||
// 对于从命令行获取到的 argv 和 argc,argc 最小为 1,argv 的第一个元素指向程序。所以 startpos 为 1。
|
||||
void ParseCmdArgs (LPWSTR *argv, DWORD argc, std::map <cmdkey, cmdvalue> &parseresult, DWORD startpos = 1)
|
||||
{
|
||||
for (size_t i = startpos; i < argc; i ++)
|
||||
{
|
||||
std::wnstring arg = argv [i];
|
||||
arg = arg.trim ();
|
||||
if (IsFile (arg)) parseresult [cmdkey (arg, paramtype::file)] = cmdvalue {L"", paramtype::file, true};
|
||||
else if (IsURI (arg)) parseresult [cmdkey (arg, paramtype::uri)] = cmdvalue {L"", paramtype::uri, true};
|
||||
else
|
||||
{
|
||||
for (auto &it : g_argslist)
|
||||
{
|
||||
std::set <std::wnstring> prefixs;
|
||||
for (auto &it_s : it.prefixs) prefixs.insert (it_s);
|
||||
int cmdhead = -1;
|
||||
for (auto &it_s : prefixs)
|
||||
{
|
||||
auto plen = GetNormalizeStringLength (it_s);
|
||||
auto parg = GetStringLeft (arg, plen);
|
||||
if (it_s == parg) { cmdhead = plen; break; }
|
||||
}
|
||||
if (((it.flags & CMDARG_IGNOREPREFIXS) || !it.prefixs.size () || !prefixs.size ()) && cmdhead < 0)
|
||||
{
|
||||
if (!arg.length ()) continue;
|
||||
cmdhead = 0;
|
||||
}
|
||||
if (cmdhead < 0) continue;
|
||||
int postfixhead = -1;
|
||||
std::set <std::wnstring> commands;
|
||||
for (auto &it_s : it.commands) if (GetNormalizeStringLength (it_s)) commands.insert (it_s);
|
||||
if (commands.empty ()) continue;
|
||||
for (auto &it_s : commands)
|
||||
{
|
||||
auto clen = it_s.length ();
|
||||
auto carg = GetStringLeft (arg.substr (cmdhead), clen);
|
||||
if (it_s == carg) { postfixhead = cmdhead + clen; }
|
||||
}
|
||||
if (postfixhead < 0) continue;
|
||||
std::set <std::wnstring> postfixs;
|
||||
for (auto &it_s : it.postfixs) if (GetNormalizeStringLength (it_s)) postfixs.insert (it_s);
|
||||
if (!(it.flags & CMDARG_ENABLEPARAMS)) it.postfixs.clear ();
|
||||
if ((it.flags & CMDARG_ENABLEPARAMS) && postfixs.size ())
|
||||
{
|
||||
int valuehead = -1;
|
||||
auto rightpart = StringTrim (GetStringRight (arg, lstrlenW (arg.c_str ()) - postfixhead));
|
||||
if (it.flags & CMDARG_IGNOREPARAMS)
|
||||
{
|
||||
if (!rightpart.length ()) { parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true}; break; }
|
||||
}
|
||||
for (auto &it_s : postfixs)
|
||||
{
|
||||
auto plen = it_s.length ();
|
||||
auto parg = GetStringLeft (rightpart, plen);
|
||||
if (it_s == parg) { valuehead = plen; break; }
|
||||
}
|
||||
if (valuehead < 0) continue;
|
||||
else
|
||||
{
|
||||
auto value = rightpart.substr (valuehead);
|
||||
paramtype ptype = paramtype::string;
|
||||
if (IsFile (value)) ptype = paramtype::file;
|
||||
else if (IsURI (StringTrim (value))) ptype = paramtype::uri;
|
||||
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {value, ptype, false};
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void ParseCmdLine (LPCWSTR lpCommandLine, std::map <cmdkey, cmdvalue> &parseresult)
|
||||
{
|
||||
int argc = 0;
|
||||
LPWSTR *alpstr = CommandLineToArgvW (lpCommandLine, &argc);
|
||||
destruct relt ([&alpstr] () {
|
||||
if (alpstr) LocalFree (alpstr);
|
||||
});
|
||||
ParseCmdArgs (alpstr, argc, parseresult, 0);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
template <class T> bool compare_default (const T &l, const T &r) { return l == r; }
|
||||
template <class T> bool find_vec (std::vector <T> &vec, const T &value, const std::function <void (size_t)> &callback, std::function<bool (const T &, const T &)> compare = compare_default <T>, bool sorted = false)
|
||||
{
|
||||
const size_t n = vec.size ();
|
||||
if (!compare) compare = compare_default<T>;
|
||||
if (sorted)
|
||||
{
|
||||
size_t left = 0, right = n;
|
||||
while (left < right)
|
||||
{
|
||||
size_t mid = left + (right - left) / 2;
|
||||
if (compare (vec [mid], value))
|
||||
{
|
||||
callback (mid);
|
||||
return true;
|
||||
}
|
||||
if (vec [mid] < value) left = mid + 1;
|
||||
else right = mid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (n < 64)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
if (compare (vec [i], value))
|
||||
{
|
||||
callback (i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const size_t blockSize = 8;
|
||||
size_t i = 0;
|
||||
for (; i + blockSize <= n; i += blockSize)
|
||||
{
|
||||
for (size_t j = 0; j < blockSize; j ++)
|
||||
{
|
||||
if (compare (vec [i + j], value))
|
||||
{
|
||||
callback (i + j);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < n; i ++)
|
||||
{
|
||||
if (compare (vec [i], value))
|
||||
{
|
||||
callback (i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T> void push_unique (std::vector <T> &vec, const T &value, std::function <bool (const T &, const T &)> compare = compare_default <T>)
|
||||
{
|
||||
bool found = find_vec <T> (
|
||||
vec, value,
|
||||
[] (size_t) {},
|
||||
compare);
|
||||
if (!found) vec.push_back (value);
|
||||
}
|
||||
template <class T> void push_normal (std::vector <T> &vec, const T &value)
|
||||
{
|
||||
vec.push_back (value);
|
||||
}
|
||||
template <class T> void push_normal (std::vector <T> &target, const std::vector <T> &another)
|
||||
{
|
||||
target.insert (target.end (), another.begin (), another.end ());
|
||||
}
|
||||
@@ -0,0 +1,871 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <shlwapi.h>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include "strcmp.h"
|
||||
#include "version.h"
|
||||
#include "module.h"
|
||||
typedef version VERSION;
|
||||
template <typename T> constexpr T Max (T l, T r) { return l > r ? l : r; }
|
||||
template <typename T> constexpr T Max (T l, T m, T r) { return Max (Max (l, r), m); }
|
||||
template <typename T> constexpr T Max (T l, T ml, T mr, T r) { return Max (Max (l, ml), Max (mr, r)); }
|
||||
template <typename CharT> std::basic_string <CharT> replace_substring
|
||||
(
|
||||
const std::basic_string <CharT> &str,
|
||||
const std::basic_string <CharT> &from,
|
||||
const std::basic_string <CharT> &to
|
||||
)
|
||||
{
|
||||
if (from.empty ()) return str;
|
||||
std::basic_string <CharT> result;
|
||||
size_t pos = 0;
|
||||
size_t start_pos;
|
||||
while ((start_pos = str.find (from, pos)) != std::basic_string<CharT>::npos)
|
||||
{
|
||||
result.append (str, pos, start_pos - pos);
|
||||
result.append (to);
|
||||
pos = start_pos + from.length ();
|
||||
}
|
||||
result.append (str, pos, str.length () - pos);
|
||||
return result;
|
||||
}
|
||||
std::string GetProgramRootDirectoryA (HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
char path [MAX_PATH];
|
||||
if (GetModuleFileNameA (hModule, path, MAX_PATH))
|
||||
{
|
||||
std::string dir (path);
|
||||
size_t pos = dir.find_last_of ("\\/");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
dir = dir.substr (0, pos);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
std::wstring GetProgramRootDirectoryW (HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
wchar_t path [MAX_PATH];
|
||||
if (GetModuleFileNameW (hModule, path, MAX_PATH))
|
||||
{
|
||||
std::wstring dir (path);
|
||||
size_t pos = dir.find_last_of (L"\\/");
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
dir = dir.substr (0, pos);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
std::string EnsureTrailingSlash (const std::string &path)
|
||||
{
|
||||
if (path.empty ()) return path; // 空路径直接返回
|
||||
|
||||
char lastChar = path.back ();
|
||||
if (lastChar == '\\' || lastChar == '/')
|
||||
return path; // 已有分隔符,直接返回
|
||||
// 根据系统或原路径格式添加适当的分隔符
|
||||
char separator = (path.find ('/') != std::string::npos) ? '/' : '\\';
|
||||
return path + separator;
|
||||
}
|
||||
std::wstring EnsureTrailingSlash (const std::wstring &path)
|
||||
{
|
||||
if (path.empty ()) return path;
|
||||
|
||||
wchar_t lastChar = path.back ();
|
||||
if (lastChar == L'\\' || lastChar == L'/')
|
||||
return path;
|
||||
|
||||
wchar_t separator = (path.find (L'/') != std::wstring::npos) ? L'/' : L'\\';
|
||||
return path + separator;
|
||||
}
|
||||
bool IsFileExistsW (LPCWSTR filename)
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesW (filename);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
bool IsFileExistsA (LPCSTR filename)
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesA (filename);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
bool IsFileExists (LPWSTR filePath) { return IsFileExistsW (filePath); }
|
||||
bool IsFileExists (LPCSTR filePath) { return IsFileExistsA (filePath); }
|
||||
bool IsFileExists (const std::string &filePath) { return IsFileExistsA (filePath.c_str ()); }
|
||||
bool IsFileExists (const std::wstring &filePath) { return IsFileExistsW (filePath.c_str ()); }
|
||||
bool IsDirectoryExistsA (LPCSTR path)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesA (path);
|
||||
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
bool IsDirectoryExistsW (LPCWSTR path)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW (path);
|
||||
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
bool IsDirectoryExists (const std::string &path) { return IsDirectoryExistsA (path.c_str ()); }
|
||||
bool IsDirectoryExists (const std::wstring &path) { return IsDirectoryExistsW (path.c_str ()); }
|
||||
bool IsDirectoryExists (LPCSTR path) { return IsDirectoryExistsA (path); }
|
||||
bool IsDirectoryExists (LPCWSTR path) { return IsDirectoryExistsW (path); }
|
||||
bool IsPathExistsW (LPCWSTR filename)
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesW (filename);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
bool IsPathExistsA (LPCSTR filename)
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributesA (filename);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
bool IsPathExists (const std::string &path) { return IsPathExistsA (path.c_str ()); }
|
||||
bool IsPathExists (const std::wstring &path) { return IsPathExistsW (path.c_str ()); }
|
||||
bool IsPathExists (LPCSTR path) { return IsPathExistsA (path); }
|
||||
bool IsPathExists (LPCWSTR path) { return IsPathExistsW (path); }
|
||||
std::string NormalizePath (const std::string &path)
|
||||
{
|
||||
if (!path.empty () && path.back () == '\\')
|
||||
return path.substr (0, path.size () - 1);
|
||||
return path.c_str ();
|
||||
}
|
||||
std::wstring NormalizePath (const std::wstring &path)
|
||||
{
|
||||
if (!path.empty () && path.back () == L'\\')
|
||||
return path.substr (0, path.size () - 1);
|
||||
return path.c_str ();
|
||||
}
|
||||
std::vector <std::string> EnumSubdirectories (const std::string &directory, bool includeParentPath)
|
||||
{
|
||||
std::vector<std::string> subdirs;
|
||||
std::string normPath = NormalizePath (directory);
|
||||
std::string searchPath = normPath + "\\*";
|
||||
WIN32_FIND_DATAA findData;
|
||||
HANDLE hFind = FindFirstFileA (searchPath.c_str (), &findData);
|
||||
if (hFind == INVALID_HANDLE_VALUE) return subdirs;
|
||||
do
|
||||
{
|
||||
// 过滤 "." 和 ".."
|
||||
if (strcmp (findData.cFileName, ".") == 0 || strcmp (findData.cFileName, "..") == 0)
|
||||
continue;
|
||||
// 判断是否为目录
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (includeParentPath)
|
||||
subdirs.push_back (normPath + "\\" + findData.cFileName);
|
||||
else
|
||||
subdirs.push_back (findData.cFileName);
|
||||
}
|
||||
} while (FindNextFileA (hFind, &findData));
|
||||
FindClose (hFind);
|
||||
return subdirs;
|
||||
}
|
||||
std::vector <std::wstring> EnumSubdirectories (const std::wstring &directory, bool includeParentPath)
|
||||
{
|
||||
std::vector<std::wstring> subdirs;
|
||||
std::wstring normPath = NormalizePath (directory);
|
||||
std::wstring searchPath = normPath + L"\\*";
|
||||
WIN32_FIND_DATAW findData;
|
||||
HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData);
|
||||
if (hFind == INVALID_HANDLE_VALUE) return subdirs;
|
||||
do
|
||||
{
|
||||
if (wcscmp (findData.cFileName, L".") == 0 || wcscmp (findData.cFileName, L"..") == 0)
|
||||
continue;
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (includeParentPath)
|
||||
subdirs.push_back (normPath + L"\\" + findData.cFileName);
|
||||
else
|
||||
subdirs.push_back (findData.cFileName);
|
||||
}
|
||||
} while (FindNextFileW (hFind, &findData));
|
||||
FindClose (hFind);
|
||||
return subdirs;
|
||||
}
|
||||
std::string GetCurrentProgramPathA (HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <CHAR> buf (Max <size_t> (MAX_PATH, GetModuleFileNameA (hModule, nullptr, 0)) + 1);
|
||||
GetModuleFileNameA (hModule, buf.data (), buf.capacity ());
|
||||
return buf.data ();
|
||||
}
|
||||
std::wstring GetCurrentProgramPathW (HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <WCHAR> buf (Max <size_t> (MAX_PATH, GetModuleFileNameW (hModule, nullptr, 0)) + 1);
|
||||
GetModuleFileNameW (hModule, buf.data (), buf.capacity ());
|
||||
return buf.data ();
|
||||
}
|
||||
std::string GetCurrentProgramNameA (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameA (GetCurrentProgramPathA (hModule).c_str ()); }
|
||||
std::wstring GetCurrentProgramNameW (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameW (GetCurrentProgramPathW (hModule).c_str ()); }
|
||||
VERSION GetExeFileVersion (LPCSTR lpszFilePath)
|
||||
{
|
||||
VERSION ver (0);
|
||||
DWORD dummy;
|
||||
DWORD size = GetFileVersionInfoSizeA (lpszFilePath, &dummy);
|
||||
std::vector <BYTE> pVersionInfo (size);
|
||||
if (!GetFileVersionInfoA (lpszFilePath, 0, size, pVersionInfo.data ()))
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
VS_FIXEDFILEINFO* pFileInfo = nullptr;
|
||||
UINT len = 0;
|
||||
if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len))
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
if (len == 0 || pFileInfo == nullptr)
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
ver = VERSION (
|
||||
HIWORD (pFileInfo->dwFileVersionMS),
|
||||
LOWORD (pFileInfo->dwFileVersionMS),
|
||||
HIWORD (pFileInfo->dwFileVersionLS),
|
||||
LOWORD (pFileInfo->dwFileVersionLS)
|
||||
);
|
||||
return ver;
|
||||
}
|
||||
VERSION GetExeFileVersion (LPCWSTR lpswFilePath)
|
||||
{
|
||||
VERSION ver (0);
|
||||
DWORD dummy;
|
||||
DWORD size = GetFileVersionInfoSizeW (lpswFilePath, &dummy);
|
||||
std::vector <BYTE> pVersionInfo (size);
|
||||
if (!GetFileVersionInfoW (lpswFilePath, 0, size, pVersionInfo.data ()))
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
VS_FIXEDFILEINFO* pFileInfo = nullptr;
|
||||
UINT len = 0;
|
||||
if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len))
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
if (len == 0 || pFileInfo == nullptr)
|
||||
{
|
||||
return ver;
|
||||
}
|
||||
ver = VERSION (
|
||||
HIWORD (pFileInfo->dwFileVersionMS),
|
||||
LOWORD (pFileInfo->dwFileVersionMS),
|
||||
HIWORD (pFileInfo->dwFileVersionLS),
|
||||
LOWORD (pFileInfo->dwFileVersionLS)
|
||||
);
|
||||
return ver;
|
||||
}
|
||||
VERSION GetExeFileVersion (std::wstring objswFilePath)
|
||||
{
|
||||
return GetExeFileVersion (objswFilePath.c_str ());
|
||||
}
|
||||
VERSION GetExeFileVersion (std::string objszFilePath)
|
||||
{
|
||||
return GetExeFileVersion (objszFilePath.c_str ());
|
||||
}
|
||||
// 设置当前进程的环境变量RunPath和ProgramPath
|
||||
void SetupInstanceEnvironment (HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
// 设置RunPath为当前工作目录(无结尾反斜杠)
|
||||
std::vector <WCHAR> currentDir (Max <size_t> (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1);
|
||||
DWORD len = GetCurrentDirectoryW (currentDir.capacity (), currentDir.data ());
|
||||
if (len > 0)
|
||||
{
|
||||
std::wstring runPath (currentDir.data ());
|
||||
if (!runPath.empty () && (runPath.back () == L'\\' || runPath.back () == L'/'))
|
||||
{
|
||||
runPath.pop_back ();
|
||||
}
|
||||
SetEnvironmentVariableW (L"RunPath", runPath.c_str ());
|
||||
}
|
||||
// 设置ProgramPath为程序所在目录(无结尾反斜杠)
|
||||
std::vector <WCHAR> modulePath (Max <size_t> (GetModuleFileNameW (hModule, nullptr, 0), MAX_PATH) + 1);
|
||||
len = GetModuleFileNameW (hModule, modulePath.data (), MAX_PATH);
|
||||
if (len > 0 && len < MAX_PATH)
|
||||
{
|
||||
wchar_t* lastSlash = wcsrchr (modulePath.data (), L'\\');
|
||||
if (!lastSlash) lastSlash = wcsrchr (modulePath.data (), L'/');
|
||||
if (lastSlash) *lastSlash = L'\0';
|
||||
std::wstring programPath (modulePath.data ());
|
||||
if (!programPath.empty () && (programPath.back () == L'\\' || programPath.back () == L'/'))
|
||||
{
|
||||
programPath.pop_back ();
|
||||
}
|
||||
SetEnvironmentVariableW (L"ProgramPath", programPath.c_str ());
|
||||
}
|
||||
}
|
||||
// 处理宽字符串环境变量展开
|
||||
std::wstring ProcessEnvVars (const std::wstring &input)
|
||||
{
|
||||
DWORD requiredSize = ExpandEnvironmentStringsW (input.c_str (), nullptr, 0);
|
||||
if (requiredSize == 0) return input;
|
||||
std::wstring buffer (requiredSize, L'\0');
|
||||
if (!ExpandEnvironmentStringsW (input.c_str (), &buffer [0], requiredSize))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
buffer.resize (requiredSize - 1); // 去除终止空字符
|
||||
return buffer.c_str ();
|
||||
}
|
||||
std::wstring ProcessEnvVars (LPCWSTR input)
|
||||
{
|
||||
return ProcessEnvVars (std::wstring (input));
|
||||
}
|
||||
// 处理ANSI字符串环境变量展开
|
||||
std::string ProcessEnvVars (const std::string &input)
|
||||
{
|
||||
DWORD requiredSize = ExpandEnvironmentStringsA (input.c_str (), nullptr, 0);
|
||||
if (requiredSize == 0) return input;
|
||||
std::string buffer (requiredSize, '\0');
|
||||
if (!ExpandEnvironmentStringsA (input.c_str (), &buffer [0], requiredSize))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
buffer.resize (requiredSize - 1); // 去除终止空字符
|
||||
return buffer.c_str ();
|
||||
}
|
||||
std::string ProcessEnvVars (LPCSTR input)
|
||||
{
|
||||
return ProcessEnvVars (std::string (input));
|
||||
}
|
||||
std::string GetCurrentDirectoryA ()
|
||||
{
|
||||
std::vector <CHAR> buf (Max <size_t> (GetCurrentDirectoryA (0, nullptr), MAX_PATH) + 1);
|
||||
GetCurrentDirectoryA (buf.size (), buf.data ());
|
||||
return buf.data ();
|
||||
}
|
||||
std::wstring GetCurrentDirectoryW ()
|
||||
{
|
||||
std::vector <WCHAR> buf (Max <size_t> (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1);
|
||||
GetCurrentDirectoryW (buf.size (), buf.data ());
|
||||
return buf.data ();
|
||||
}
|
||||
std::wstring GetFileDirectoryW (const std::wstring &filePath)
|
||||
{
|
||||
std::vector <WCHAR> buf (filePath.capacity () + 1);
|
||||
lstrcpyW (buf.data (), filePath.c_str ());
|
||||
PathRemoveFileSpecW (buf.data ());
|
||||
return buf.data ();
|
||||
}
|
||||
std::string GetFileDirectoryA (const std::string &filePath)
|
||||
{
|
||||
std::vector <CHAR> buf (filePath.capacity () + 1);
|
||||
lstrcpyA (buf.data (), filePath.c_str ());
|
||||
PathRemoveFileSpecA (buf.data ());
|
||||
return buf.data ();
|
||||
}
|
||||
size_t EnumerateFilesW (const std::wstring &directory, const std::wstring &filter,
|
||||
std::vector <std::wstring> &outFiles, bool recursive = false)
|
||||
{
|
||||
std::wstring searchPath = directory;
|
||||
if (!searchPath.empty () && searchPath.back () != L'\\')
|
||||
{
|
||||
searchPath += L'\\';
|
||||
}
|
||||
searchPath += filter;
|
||||
WIN32_FIND_DATAW findData;
|
||||
HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do {
|
||||
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
outFiles.push_back (directory + L"\\" + findData.cFileName);
|
||||
}
|
||||
} while (FindNextFileW (hFind, &findData));
|
||||
FindClose (hFind);
|
||||
}
|
||||
if (recursive) {
|
||||
std::wstring subDirSearchPath = directory + L"\\*";
|
||||
hFind = FindFirstFileW (subDirSearchPath.c_str (), &findData);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do {
|
||||
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
wcscmp (findData.cFileName, L".") != 0 && wcscmp (findData.cFileName, L"..") != 0)
|
||||
{
|
||||
EnumerateFilesW (directory + L"\\" + findData.cFileName, filter, outFiles, true);
|
||||
}
|
||||
} while (FindNextFileW (hFind, &findData));
|
||||
FindClose (hFind);
|
||||
}
|
||||
}
|
||||
return outFiles.size ();
|
||||
}
|
||||
// 检查是否为 Windows 设备名(大小写不敏感)
|
||||
bool IsReservedName (const std::wstring &name)
|
||||
{
|
||||
static const wchar_t* reserved [] = {
|
||||
L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9",
|
||||
L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9"
|
||||
};
|
||||
std::wstring upperName = StringToUpper (name);
|
||||
for (const auto& res : reserved)
|
||||
{
|
||||
if (upperName == res || (upperName.rfind (res, 0) == 0 && upperName.length () > wcslen (res) && upperName [wcslen (res)] == L'.'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Windows 文件命名规范检查 (Unicode)
|
||||
bool IsValidWindowsNameW (LPCWSTR name)
|
||||
{
|
||||
if (!name || !*name) return false;
|
||||
std::wstring wname (name);
|
||||
if (wname.find_first_of (L"<>:\"/\\|?*") != std::wstring::npos) return false;
|
||||
if (IsReservedName (wname)) return false;
|
||||
if (wname.back () == L' ' || wname.back () == L'.') return false;
|
||||
return true;
|
||||
}
|
||||
// Windows 文件命名规范检查 (ANSI)
|
||||
bool IsValidWindowsNameA (LPCSTR name)
|
||||
{
|
||||
if (!name || !*name) return false;
|
||||
std::string str (name);
|
||||
if (str.find_first_of ("<>:\"/\\|?*") != std::string::npos) return false;
|
||||
|
||||
// 转换 ANSI 到宽字符
|
||||
int len = MultiByteToWideChar (CP_ACP, 0, name, -1, NULL, 0);
|
||||
if (len <= 0) return false;
|
||||
std::wstring wname (len - 1, L'\0');
|
||||
MultiByteToWideChar (CP_ACP, 0, name, -1, &wname [0], len);
|
||||
if (IsReservedName (wname)) return false;
|
||||
if (str.back () == ' ' || str.back () == '.') return false;
|
||||
return true;
|
||||
}
|
||||
bool IsValidWindowsName (LPCSTR name) { return IsValidWindowsNameA (name); }
|
||||
bool IsValidWindowsName (LPCWSTR name) { return IsValidWindowsNameW (name); }
|
||||
bool IsValidWindowsName (const std::wstring &name) { return IsValidWindowsName (name.c_str ()); }
|
||||
bool IsValidWindowsName (const std::string &name) { return IsValidWindowsName (name.c_str ()); }
|
||||
std::wstring GetRootFolderNameFromFilePath (const std::wstring &lpFilePath)
|
||||
{
|
||||
std::vector <WCHAR> szPath (Max <size_t> (lpFilePath.length (), MAX_PATH) + 1);
|
||||
if (!PathCanonicalizeW (szPath.data (), lpFilePath.c_str ())) return L"";
|
||||
if (PathRemoveFileSpecW (szPath.data ()) == FALSE) return L"";
|
||||
LPCWSTR pszFolder = PathFindFileNameW (szPath.data ());
|
||||
if (*pszFolder != L'\0') return std::wstring (pszFolder);
|
||||
WCHAR rootName [3] = {szPath [0], L':', L'\0'};
|
||||
return std::wstring (rootName);
|
||||
}
|
||||
std::wstring GetSafeTimestampForFilename ()
|
||||
{
|
||||
::FILETIME ft;
|
||||
GetSystemTimeAsFileTime (&ft);
|
||||
SYSTEMTIME st;
|
||||
FileTimeToSystemTime (&ft, &st);
|
||||
std::wstringstream wss;
|
||||
wss << std::setfill (L'0')
|
||||
<< st.wYear
|
||||
<< std::setw (2) << st.wMonth
|
||||
<< std::setw (2) << st.wDay << L"_"
|
||||
<< std::setw (2) << st.wHour
|
||||
<< std::setw (2) << st.wMinute
|
||||
<< std::setw (2) << st.wSecond
|
||||
<< std::setw (3) << st.wMilliseconds;
|
||||
return wss.str ();
|
||||
}
|
||||
size_t EnumFiles (
|
||||
const std::wstring &lpDir,
|
||||
const std::wstring &lpFilter,
|
||||
std::vector <std::wstring> &aszOutput,
|
||||
bool bOutputWithPath = false,
|
||||
bool bSortByLetter = false,
|
||||
bool bIncludeSubDir = false
|
||||
) {
|
||||
if (!bIncludeSubDir) aszOutput.clear ();
|
||||
std::vector<std::wstring> filters;
|
||||
size_t start = 0;
|
||||
while (start < lpFilter.length ())
|
||||
{
|
||||
size_t pos = lpFilter.find (L'\\', start);
|
||||
if (pos == std::wstring::npos) pos = lpFilter.length ();
|
||||
filters.emplace_back (lpFilter.substr (start, pos - start));
|
||||
start = pos + 1;
|
||||
}
|
||||
|
||||
std::function <void (const std::wstring &, std::wstring)> enumDir;
|
||||
enumDir = [&] (const std::wstring &physicalPath, std::wstring relativePath)
|
||||
{
|
||||
WIN32_FIND_DATAW ffd;
|
||||
HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd);
|
||||
if (hFind == INVALID_HANDLE_VALUE) return;
|
||||
do {
|
||||
if (wcscmp (ffd.cFileName, L".") == 0 ||
|
||||
wcscmp (ffd.cFileName, L"..") == 0) continue;
|
||||
const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
const std::wstring newPhysical = physicalPath + L"\\" + ffd.cFileName;
|
||||
std::wstring newRelative = relativePath;
|
||||
if (isDir) {
|
||||
if (bIncludeSubDir) {
|
||||
newRelative += ffd.cFileName;
|
||||
newRelative += L"\\";
|
||||
enumDir (newPhysical, newRelative);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &filter : filters)
|
||||
{
|
||||
if (PathMatchSpecW (ffd.cFileName, filter.c_str ()))
|
||||
{
|
||||
aszOutput.push_back
|
||||
(
|
||||
bOutputWithPath ? newPhysical : (relativePath + ffd.cFileName)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW (hFind, &ffd));
|
||||
FindClose (hFind);
|
||||
};
|
||||
enumDir (lpDir, L"");
|
||||
if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ());
|
||||
return aszOutput.size ();
|
||||
}
|
||||
std::wstring GetRelativePath (
|
||||
const std::wstring &pszBaseDir,
|
||||
const std::wstring &pszFullPath,
|
||||
DWORD cchRelative
|
||||
) {
|
||||
std::vector <WCHAR> szBase (Max <size_t> (pszBaseDir.length (), pszFullPath.length (), MAX_PATH) + 1);
|
||||
wcscpy_s (szBase.data (), MAX_PATH, pszBaseDir.c_str ());
|
||||
if (szBase [wcslen (szBase.data ()) - 1] != L'\\')
|
||||
{
|
||||
wcscat_s (szBase.data (), MAX_PATH, L"\\");
|
||||
}
|
||||
std::vector <WCHAR> buf (Max <size_t> (MAX_PATH, szBase.size ()) + 1);
|
||||
BOOL res = PathRelativePathToW (
|
||||
buf.data (),
|
||||
szBase.data (),
|
||||
FILE_ATTRIBUTE_DIRECTORY,
|
||||
pszFullPath.c_str (),
|
||||
FILE_ATTRIBUTE_NORMAL
|
||||
);
|
||||
if (res) return buf.data ();
|
||||
else return L"";
|
||||
}
|
||||
size_t EnumDirectory (
|
||||
const std::wstring &lpDir,
|
||||
std::vector<std::wstring> &aszOutput,
|
||||
bool bOutputWithPath = false,
|
||||
bool bSortByLetter = false,
|
||||
bool bIncludeSubDir = false
|
||||
) {
|
||||
aszOutput.clear ();
|
||||
std::function <void (const std::wstring &, const std::wstring &)> enumDir;
|
||||
enumDir = [&] (const std::wstring &physicalPath, const std::wstring &relativePath) {
|
||||
WIN32_FIND_DATAW ffd;
|
||||
HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd);
|
||||
if (hFind == INVALID_HANDLE_VALUE) return;
|
||||
do
|
||||
{
|
||||
const std::wstring name = ffd.cFileName;
|
||||
if (name == L"." || name == L"..") continue;
|
||||
const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
std::wstring newPhysical = physicalPath + L"\\" + name;
|
||||
std::wstring newRelative = relativePath + name;
|
||||
if (isDir)
|
||||
{
|
||||
if (bIncludeSubDir) enumDir (newPhysical, newRelative + L"\\");
|
||||
if (bOutputWithPath) aszOutput.push_back (newPhysical);
|
||||
else aszOutput.push_back (newRelative);
|
||||
}
|
||||
} while (FindNextFileW (hFind, &ffd));
|
||||
FindClose (hFind);
|
||||
};
|
||||
enumDir (lpDir, L"");
|
||||
if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ());
|
||||
return aszOutput.size ();
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ProgressRoutine (
|
||||
LARGE_INTEGER TotalFileSize,
|
||||
LARGE_INTEGER TotalBytesTransferred,
|
||||
LARGE_INTEGER /*StreamSize*/,
|
||||
LARGE_INTEGER /*StreamBytesTransferred*/,
|
||||
DWORD /*dwStreamNumber*/,
|
||||
DWORD /*dwCallbackReason*/,
|
||||
HANDLE /*hSourceFile*/,
|
||||
HANDLE /*hDestinationFile*/,
|
||||
LPVOID lpData
|
||||
) {
|
||||
auto *pCallback = reinterpret_cast <std::function <void (int)> *> (lpData);
|
||||
if (pCallback && *pCallback)
|
||||
{
|
||||
int progress = static_cast <int> (
|
||||
(TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart
|
||||
);
|
||||
(*pCallback) (progress);
|
||||
}
|
||||
return PROGRESS_CONTINUE;
|
||||
}
|
||||
bool RenameFileW (
|
||||
const std::wstring &lpSrcPath,
|
||||
const std::wstring &lpDestPath,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
LPPROGRESS_ROUTINE pRoutine = nullptr;
|
||||
LPVOID pData = nullptr;
|
||||
if (fProgress)
|
||||
{
|
||||
pRoutine = ProgressRoutine;
|
||||
pData = &fProgress;
|
||||
}
|
||||
DWORD flags = MOVEFILE_COPY_ALLOWED;
|
||||
BOOL ok = MoveFileWithProgressW (
|
||||
lpSrcPath.c_str (),
|
||||
lpDestPath.c_str (),
|
||||
pRoutine,
|
||||
pData,
|
||||
flags
|
||||
);
|
||||
return ok != FALSE;
|
||||
}
|
||||
bool RenameFileA (
|
||||
const std::string &lpSrcPath,
|
||||
const std::string &lpDestPath,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
LPPROGRESS_ROUTINE pRoutine = nullptr;
|
||||
LPVOID pData = nullptr;
|
||||
if (fProgress)
|
||||
{
|
||||
pRoutine = ProgressRoutine;
|
||||
pData = &fProgress;
|
||||
}
|
||||
DWORD flags = MOVEFILE_COPY_ALLOWED;
|
||||
BOOL ok = MoveFileWithProgressA (
|
||||
lpSrcPath.c_str (),
|
||||
lpDestPath.c_str (),
|
||||
pRoutine,
|
||||
pData,
|
||||
flags
|
||||
);
|
||||
return ok != FALSE;
|
||||
}
|
||||
bool RenameFileW (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
struct BuildTask
|
||||
{
|
||||
LPWSTR src = nullptr, dest = nullptr;
|
||||
~BuildTask ()
|
||||
{
|
||||
if (src != nullptr)
|
||||
{
|
||||
delete [] src;
|
||||
src = nullptr;
|
||||
}
|
||||
if (dest != nullptr)
|
||||
{
|
||||
delete [] dest;
|
||||
dest = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
BuildTask bt;
|
||||
bt.src = new WCHAR [lpSrcDir.length () + lpSrcName.length () + 2];
|
||||
bt.dest = new WCHAR [lpSrcDir.length () + lpDestName.length () + 2];
|
||||
PathCombineW (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ());
|
||||
PathCombineW (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ());
|
||||
return RenameFileW (bt.src, bt.dest, fProgress);
|
||||
}
|
||||
bool RenameFileA (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
struct BuildTask
|
||||
{
|
||||
LPSTR src = nullptr, dest = nullptr;
|
||||
~BuildTask ()
|
||||
{
|
||||
if (src != nullptr)
|
||||
{
|
||||
delete [] src;
|
||||
src = nullptr;
|
||||
}
|
||||
if (dest != nullptr)
|
||||
{
|
||||
delete [] dest;
|
||||
dest = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
BuildTask bt;
|
||||
bt.src = new CHAR [lpSrcDir.length () + lpSrcName.length () + 2];
|
||||
bt.dest = new CHAR [lpSrcDir.length () + lpDestName.length () + 2];
|
||||
PathCombineA (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ());
|
||||
PathCombineA (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ());
|
||||
return RenameFileA (bt.src, bt.dest, fProgress);
|
||||
}
|
||||
bool RenameFile (const std::wstring &lpSrcPath, const std::wstring &lpDestPath, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
return RenameFileW (lpSrcPath, lpDestPath, fProgress);
|
||||
}
|
||||
bool RenameFile (const std::string &lpSrcPath, const std::string &lpDestPath, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
return RenameFileA (lpSrcPath, lpDestPath, fProgress);
|
||||
}
|
||||
bool RenameFile (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
return RenameFileW (lpSrcDir, lpSrcName, lpDestName, fProgress);
|
||||
}
|
||||
bool RenameFile (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function <void (int)> fProgress = nullptr)
|
||||
{
|
||||
return RenameFileA (lpSrcDir, lpSrcName, lpDestName, fProgress);
|
||||
}
|
||||
bool RenameDirectoryW (
|
||||
const std::wstring &lpSrcPath,
|
||||
const std::wstring &lpDestPath,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
LPPROGRESS_ROUTINE pRoutine = nullptr;
|
||||
LPVOID pData = nullptr;
|
||||
if (fProgress)
|
||||
{
|
||||
pRoutine = ProgressRoutine;
|
||||
pData = &fProgress;
|
||||
}
|
||||
DWORD flags = MOVEFILE_COPY_ALLOWED;
|
||||
BOOL ok = MoveFileWithProgressW (
|
||||
lpSrcPath.c_str (),
|
||||
lpDestPath.c_str (),
|
||||
pRoutine,
|
||||
pData,
|
||||
flags
|
||||
);
|
||||
return ok != FALSE;
|
||||
}
|
||||
bool RenameDirectoryA (
|
||||
const std::string &lpSrcPath,
|
||||
const std::string &lpDestPath,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
LPPROGRESS_ROUTINE pRoutine = nullptr;
|
||||
LPVOID pData = nullptr;
|
||||
if (fProgress)
|
||||
{
|
||||
pRoutine = ProgressRoutine;
|
||||
pData = &fProgress;
|
||||
}
|
||||
DWORD flags = MOVEFILE_COPY_ALLOWED;
|
||||
BOOL ok = MoveFileWithProgressA (
|
||||
lpSrcPath.c_str (),
|
||||
lpDestPath.c_str (),
|
||||
pRoutine,
|
||||
pData,
|
||||
flags
|
||||
);
|
||||
return ok != FALSE;
|
||||
}
|
||||
bool RenameDirectoryW (
|
||||
const std::wstring &lpParentDir,
|
||||
const std::wstring &lpSrcName,
|
||||
const std::wstring &lpDestName,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
struct PathBuilder
|
||||
{
|
||||
LPWSTR src = nullptr;
|
||||
LPWSTR dest = nullptr;
|
||||
~PathBuilder ()
|
||||
{
|
||||
delete [] src;
|
||||
delete [] dest;
|
||||
}
|
||||
} pb;
|
||||
pb.src = new WCHAR [lpParentDir.length () + lpSrcName.length () + 2];
|
||||
pb.dest = new WCHAR [lpParentDir.length () + lpDestName.length () + 2];
|
||||
PathCombineW (pb.src, lpParentDir.c_str (), lpSrcName.c_str ());
|
||||
PathCombineW (pb.dest, lpParentDir.c_str (), lpDestName.c_str ());
|
||||
return RenameDirectoryW (pb.src, pb.dest, fProgress);
|
||||
}
|
||||
bool RenameDirectoryA (
|
||||
const std::string &lpParentDir,
|
||||
const std::string &lpSrcName,
|
||||
const std::string &lpDestName,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
struct PathBuilder
|
||||
{
|
||||
LPSTR src = nullptr;
|
||||
LPSTR dest = nullptr;
|
||||
~PathBuilder ()
|
||||
{
|
||||
delete [] src;
|
||||
delete [] dest;
|
||||
}
|
||||
} pb;
|
||||
pb.src = new CHAR [lpParentDir.length () + lpSrcName.length () + 2];
|
||||
pb.dest = new CHAR [lpParentDir.length () + lpDestName.length () + 2];
|
||||
PathCombineA (pb.src, lpParentDir.c_str (), lpSrcName.c_str ());
|
||||
PathCombineA (pb.dest, lpParentDir.c_str (), lpDestName.c_str ());
|
||||
return RenameDirectoryA (pb.src, pb.dest, fProgress);
|
||||
}
|
||||
bool RenameDirectory (
|
||||
const std::wstring &src,
|
||||
const std::wstring &dst,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
return RenameDirectoryW (src, dst, fProgress);
|
||||
}
|
||||
bool RenameDirectory (
|
||||
const std::string &src,
|
||||
const std::string &dst,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
return RenameDirectoryA (src, dst, fProgress);
|
||||
}
|
||||
bool RenameDirectory (
|
||||
const std::wstring &parentDir,
|
||||
const std::wstring &srcName,
|
||||
const std::wstring &dstName,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
return RenameDirectoryW (parentDir, srcName, dstName, fProgress);
|
||||
}
|
||||
bool RenameDirectory (
|
||||
const std::string &parentDir,
|
||||
const std::string &srcName,
|
||||
const std::string &dstName,
|
||||
std::function <void (int)> fProgress = nullptr
|
||||
) {
|
||||
return RenameDirectoryA (parentDir, srcName, dstName, fProgress);
|
||||
}
|
||||
std::wstring CombinePath (const std::wstring &left, const std::wstring &right)
|
||||
{
|
||||
std::vector <WCHAR> buf (left.capacity () + right.capacity () + 2);
|
||||
PathCombineW (buf.data (), left.c_str (), right.c_str ());
|
||||
return buf.data ();
|
||||
}
|
||||
#ifdef PathCommonPrefix
|
||||
#undef PathCommonPrefix
|
||||
#endif
|
||||
std::wstring PathCommonPrefix (const std::wstring &file1, const std::wstring &file2)
|
||||
{
|
||||
std::vector <WCHAR> buf (Max <size_t> (file1.capacity (), file2.capacity (), MAX_PATH) + 2);
|
||||
PathCommonPrefixW (file1.c_str (), file2.c_str (), buf.data ());
|
||||
return buf.data ();
|
||||
}
|
||||
#undef GetFullPathName
|
||||
std::wstring GetFullPathName (const std::wstring &lpFileName)
|
||||
{
|
||||
if (lpFileName.empty ()) return L"";
|
||||
DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr);
|
||||
if (length == 0) return L"";
|
||||
std::vector <WCHAR> buffer (length + 1, L'\0');
|
||||
DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr);
|
||||
if (result == 0) return L"";
|
||||
return std::wstring (buffer.data (), result);
|
||||
}
|
||||
bool PathEquals (const std::wstring &path1, const std::wstring &path2)
|
||||
{
|
||||
size_t maxlen = Max <size_t> (path1.capacity () + 1, path2.capacity () + 1, MAX_PATH);
|
||||
std::vector <WCHAR> buf1 (maxlen), buf2 (maxlen);
|
||||
PathCanonicalizeW (buf1.data (), path1.c_str ());
|
||||
PathCanonicalizeW (buf2.data (), path2.c_str ());
|
||||
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include "filepath.h"
|
||||
void SetWebBrowserEmulation ()
|
||||
{
|
||||
std::wstring instname = GetCurrentProgramNameW ();
|
||||
BOOL isWow64 = FALSE;
|
||||
IsWow64Process (GetCurrentProcess (), &isWow64);
|
||||
HKEY hKey;
|
||||
LPCWSTR keyPath = isWow64
|
||||
? L"SOFTWARE\\WOW6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"
|
||||
: L"SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION";
|
||||
LONG result = RegOpenKeyExW (HKEY_CURRENT_USER, keyPath, 0, KEY_WRITE, &hKey);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD value = 11001;
|
||||
RegSetValueExW (hKey, instname.c_str (), 0, REG_DWORD, reinterpret_cast <const BYTE*> (&value), sizeof (value));
|
||||
RegCloseKey (hKey);
|
||||
}
|
||||
}
|
||||
// 返回系统安装的 Internet Explorer 主版本号(如 8、9、10、11)
|
||||
int GetInternetExplorerVersionMajor ()
|
||||
{
|
||||
HKEY hKey;
|
||||
LPCWSTR IEKeyPath = L"SOFTWARE\\Microsoft\\Internet Explorer";
|
||||
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, IEKeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return 0;
|
||||
WCHAR buffer [128] = {0};
|
||||
DWORD bufferSize = sizeof (buffer);
|
||||
DWORD type = 0;
|
||||
std::wstring versionStr;
|
||||
if (RegQueryValueExW (hKey, L"svcVersion", NULL, &type, (LPBYTE)buffer, &bufferSize) == ERROR_SUCCESS) versionStr = buffer;
|
||||
else
|
||||
{
|
||||
bufferSize = sizeof (buffer);
|
||||
if (RegQueryValueExW (hKey, L"Version", NULL, &type, (LPBYTE)buffer, &bufferSize) == ERROR_SUCCESS) versionStr = buffer;
|
||||
}
|
||||
RegCloseKey (hKey);
|
||||
if (versionStr.empty ()) return 0;
|
||||
int major = 0;
|
||||
swscanf_s (versionStr.c_str (), L"%d", &major);
|
||||
return major;
|
||||
}
|
||||
bool IsInternetExplorer10 () { return GetInternetExplorerVersionMajor () == 10; }
|
||||
bool IsInternetExplorer11AndLater () { return GetInternetExplorerVersionMajor () >= 11; }
|
||||
@@ -0,0 +1,488 @@
|
||||
#pragma once
|
||||
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
|
||||
#define _CRT_NON_CONFORMING_SWPRINTFS
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <cwchar>
|
||||
#include <type_traits>
|
||||
#include "strcode.h"
|
||||
#include "nstring.h"
|
||||
#include "typestrans.h"
|
||||
|
||||
template <typename T> std::wstring TypeToString (T value, const std::wstring &reserve = L"") { return std::to_wstring (value); }
|
||||
template <typename T> std::string TypeToString (T value, const std::string &reserve = "") { return std::to_string (value); }
|
||||
|
||||
std::string GetPrivateProfileStringA (const std::string &filePath, const std::string §ion, const std::string &key, LPCSTR defaultValue = "")
|
||||
{
|
||||
char buf [32768] = {0};
|
||||
GetPrivateProfileStringA (section.c_str (), key.c_str (), defaultValue, buf, 32767, filePath.c_str ());
|
||||
return buf;
|
||||
}
|
||||
std::wstring GetPrivateProfileStringW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key, LPCWSTR defaultValue = L"")
|
||||
{
|
||||
WCHAR buf [32768] = {0};
|
||||
GetPrivateProfileStringW (section.c_str (), key.c_str (), defaultValue, buf, 32767, filePath.c_str ());
|
||||
return buf;
|
||||
}
|
||||
UINT GetPrivateProfileIntA (const std::string &filePath, const std::string §ion, const std::string &key, INT defaultValue = 0)
|
||||
{
|
||||
return GetPrivateProfileIntA (section.c_str (), key.c_str (), defaultValue, filePath.c_str ());
|
||||
}
|
||||
UINT GetPrivateProfileIntW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key, INT defaultValue = 0)
|
||||
{
|
||||
return GetPrivateProfileIntW (section.c_str (), key.c_str (), defaultValue, filePath.c_str ());
|
||||
}
|
||||
BOOL WritePrivateProfileStringA (const std::string &filePath, const std::string §ion, const std::string &key, const std::string &value)
|
||||
{
|
||||
return WritePrivateProfileStringA (section.c_str (), key.c_str (), value.c_str (), filePath.c_str ());
|
||||
}
|
||||
BOOL WritePrivateProfileStringW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key, const std::wstring &value)
|
||||
{
|
||||
return WritePrivateProfileStringW ( section.c_str (), key.c_str (), value.c_str (), filePath.c_str ());
|
||||
}
|
||||
size_t GetPrivateProfileSectionA (const std::string &filePath, const std::string §ion, std::vector <std::string> &output)
|
||||
{
|
||||
char buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionA (section.c_str (), buf, sizeof (buf), filePath.c_str ());
|
||||
output.clear ();
|
||||
if (len == 0) return 0;
|
||||
char *ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
output.emplace_back (ptr);
|
||||
ptr += strlen (ptr) + 1;
|
||||
}
|
||||
return output.size ();
|
||||
}
|
||||
size_t GetPrivateProfileSectionW (const std::wstring &filePath, const std::wstring §ion, std::vector <std::wstring> &output)
|
||||
{
|
||||
WCHAR buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionW (section.c_str (), buf, sizeof (buf) / sizeof (WCHAR), filePath.c_str ());
|
||||
output.clear ();
|
||||
if (len == 0) return 0;
|
||||
WCHAR *ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
output.emplace_back (ptr);
|
||||
ptr += wcslen (ptr) + 1;
|
||||
}
|
||||
return output.size ();
|
||||
}
|
||||
size_t GetPrivateProfileSectionNamesA (const std::string &filePath, std::vector <std::string> &output)
|
||||
{
|
||||
char buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionNamesA (buf, sizeof (buf), filePath.c_str ());
|
||||
output.clear ();
|
||||
if (len == 0) return 0;
|
||||
char *ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
output.emplace_back (ptr);
|
||||
ptr += strlen (ptr) + 1;
|
||||
}
|
||||
return output.size ();
|
||||
}
|
||||
size_t GetPrivateProfileSectionNamesW (const std::wstring &filePath, std::vector <std::wstring> &output)
|
||||
{
|
||||
WCHAR buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionNamesW (buf, sizeof (buf) / sizeof (WCHAR), filePath.c_str ());
|
||||
output.clear ();
|
||||
if (len == 0) return 0;
|
||||
WCHAR *ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
output.emplace_back (ptr);
|
||||
ptr += wcslen (ptr) + 1;
|
||||
}
|
||||
return output.size ();
|
||||
}
|
||||
bool WritePrivateProfileSectionA (const std::string &filePath, const std::string §ion, const std::vector <std::string> &lines)
|
||||
{
|
||||
std::string buf;
|
||||
for (const auto &line : lines) buf.append (line).push_back ('\0');
|
||||
buf.push_back ('\0');
|
||||
return WritePrivateProfileSectionA (section.c_str (), buf.c_str (), filePath.c_str ()) != 0;
|
||||
}
|
||||
bool WritePrivateProfileSectionW (const std::wstring &filePath, const std::wstring §ion, const std::vector <std::wstring> &lines)
|
||||
{
|
||||
std::wstring buf;
|
||||
for (const auto &line : lines) buf.append (line).push_back (L'\0');
|
||||
buf.push_back (L'\0'); // Ë« \0 ½áβ
|
||||
return WritePrivateProfileSectionW (section.c_str (), buf.c_str (), filePath.c_str ()) != 0;
|
||||
}
|
||||
bool GetPrivateProfileStructA (const std::string &filePath, const std::string §ion, const std::string &key, void *output, UINT size)
|
||||
{
|
||||
return GetPrivateProfileStructA (section.c_str (), key.c_str (), output, size, filePath.c_str ()) != 0;
|
||||
}
|
||||
bool WritePrivateProfileStructA (const std::string &filePath, const std::string §ion, const std::string &key, void *data, UINT size)
|
||||
{
|
||||
return WritePrivateProfileStructA (section.c_str (), key.c_str (), data, size, filePath.c_str ()) != 0;
|
||||
}
|
||||
bool GetPrivateProfileStructW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key, void *output, UINT size)
|
||||
{
|
||||
return GetPrivateProfileStructW (section.c_str (), key.c_str (), output, size, filePath.c_str ()) != 0;
|
||||
}
|
||||
bool WritePrivateProfileStructW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key, void *data, UINT size)
|
||||
{
|
||||
return WritePrivateProfileStructW (section.c_str (), key.c_str (), data, size, filePath.c_str ()) != 0;
|
||||
}
|
||||
size_t GetPrivateProfileKeysW (const std::wstring &filePath, const std::wstring §ion, std::vector <std::wstring> &keys)
|
||||
{
|
||||
WCHAR buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionW (section.c_str (), buf, sizeof (buf) / sizeof (WCHAR), filePath.c_str ());
|
||||
keys.clear ();
|
||||
if (len == 0) return 0;
|
||||
WCHAR* ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
std::wstring line = ptr;
|
||||
size_t pos = line.find (L'=');
|
||||
if (pos != std::wstring::npos) keys.push_back (line.substr (0, pos));
|
||||
ptr += wcslen (ptr) + 1;
|
||||
}
|
||||
return keys.size ();
|
||||
}
|
||||
size_t GetPrivateProfileKeysA (const std::string &filePath, const std::string §ion, std::vector <std::string> &keys)
|
||||
{
|
||||
char buf [32768] = {0};
|
||||
DWORD len = GetPrivateProfileSectionA (section.c_str (), buf, sizeof (buf), filePath.c_str ());
|
||||
keys.clear ();
|
||||
if (len == 0)
|
||||
return 0;
|
||||
char *ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
std::string line = ptr;
|
||||
size_t pos = line.find ('=');
|
||||
if (pos != std::string::npos) keys.push_back (line.substr (0, pos));
|
||||
ptr += strlen (ptr) + 1;
|
||||
}
|
||||
return keys.size ();
|
||||
}
|
||||
bool DeletePrivateProfileKeyA (const std::string &filePath, const std::string §ion, const std::string &key)
|
||||
{
|
||||
return WritePrivateProfileStringA (section.c_str (), key.c_str (), NULL, filePath.c_str ()) != FALSE;
|
||||
}
|
||||
bool DeletePrivateProfileKeyW (const std::wstring &filePath, const std::wstring §ion, const std::wstring &key)
|
||||
{
|
||||
return WritePrivateProfileStringW (section.c_str (), key.c_str (), NULL, filePath.c_str ()) != FALSE;
|
||||
}
|
||||
bool DeletePrivateProfileSectionA (const std::string &filePath, const std::string §ion)
|
||||
{
|
||||
return WritePrivateProfileStringA (section.c_str (), NULL, NULL, filePath.c_str ()) != FALSE;
|
||||
}
|
||||
bool DeletePrivateProfileSectionW (const std::wstring &filePath, const std::wstring §ion)
|
||||
{
|
||||
return WritePrivateProfileStringW (section.c_str (), NULL, NULL, filePath.c_str ()) != FALSE;
|
||||
}
|
||||
|
||||
class initkey
|
||||
{
|
||||
public:
|
||||
using pstring = std::string &;
|
||||
using pwstring = std::wstring &;
|
||||
using pcstring = const std::string &;
|
||||
using pcwstring = const std::wstring &;
|
||||
private:
|
||||
pcwstring filepath;
|
||||
pcwstring section;
|
||||
template <typename T, typename Trans = T, typename Func> T read_t (T defaultvalue, Func process) const
|
||||
{
|
||||
auto res = read_wstring (std::to_wstring ((Trans)defaultvalue));
|
||||
if (IsNormalizeStringEmpty (res)) return defaultvalue;
|
||||
return (T)process (res.c_str ());
|
||||
}
|
||||
template <typename T> bool write_t (T value) { return write_string (std::to_wstring (value)); }
|
||||
public:
|
||||
std::wstring key;
|
||||
initkey (pcwstring path, pcwstring sect, pcwstring k): filepath (path), section (sect), key (k) {}
|
||||
std::wstring read_wstring (pcwstring defaultvalue = L"") const { return GetPrivateProfileStringW (filepath, section, key, defaultvalue.c_str ()); }
|
||||
std::string read_string (pcstring defaultvalue = "") const { return WStringToString (read_wstring (StringToWString (defaultvalue))); }
|
||||
short read_short (short defaultvalue = 0) const { return read_t (defaultvalue, _wtoi16); }
|
||||
unsigned short read_ushort (unsigned short defaultvalue = 0) const { return read_t (defaultvalue, _wtoui16); }
|
||||
int read_int (int defaultvalue = 0) const { return read_t (defaultvalue, _wtoi); }
|
||||
unsigned int read_uint (unsigned int defaultvalue = 0) const { return read_t (defaultvalue, _wtou); }
|
||||
long read_long (long defaultvalue = 0) const { return read_t (defaultvalue, _wtol); }
|
||||
unsigned long read_ulong (unsigned long defaultvalue = 0) const { return read_t (defaultvalue, _wtoul); }
|
||||
long long read_llong (long long defaultvalue = 0) const { return read_t (defaultvalue, _wtoll); }
|
||||
unsigned long long read_ullong (unsigned long long defaultvalue = 0) const { return read_t (defaultvalue, _wtou64); }
|
||||
float read_float (float defaultvalue = 0) const { return read_t (defaultvalue, _wtof); }
|
||||
double read_double (double defaultvalue = 0) const { return read_t (defaultvalue, _wtod); }
|
||||
bool read_bool (bool defaultvalue = false) const
|
||||
{
|
||||
std::wnstring res = read_wstring (defaultvalue ? L"true" : L"false");
|
||||
if (res.empty ()) return defaultvalue;
|
||||
if (res.equals (L"true") || res.equals (L"yes") || res.equals (L"zhen") || res.equals (L"Õæ") || res.equals (L"1") || _wtoi (res.c_str ()) != 0) return true;
|
||||
else if (res.equals (L"false") || res.equals (L"no") || res.equals (L"jia") || res.equals (L"¼Ù") || res.equals (L"0")) return false;
|
||||
else return defaultvalue;
|
||||
}
|
||||
int8_t read_i8 (int8_t defaultvalue = 0) const { return read_t <int8_t, int16_t> (defaultvalue, _wtoi8); }
|
||||
uint8_t read_u8 (uint8_t defaultvalue = 0) const { return read_t <uint8_t, uint16_t> (defaultvalue, _wtoui8); }
|
||||
int16_t read_i16 (int16_t defaultvalue = 0) const { return read_t (defaultvalue, _wtoi16); }
|
||||
uint16_t read_u16 (uint16_t defaultvalue = 0) const { return read_t (defaultvalue, _wtoui16); }
|
||||
int32_t read_i32 (int32_t defaultvalue = 0) const { return read_t (defaultvalue, _wtoi32); }
|
||||
uint32_t read_u32 (uint32_t defaultvalue = 0) const { return read_t (defaultvalue, _wtoui32); }
|
||||
int64_t read_i64 (int64_t defaultvalue = 0) const { return read_t (defaultvalue, _wtoi64); }
|
||||
uint64_t read_u64 (uint64_t defaultvalue = 0) const { return read_t (defaultvalue, _wtou64); }
|
||||
bool read_struct (void *output, size_t size) const { return GetPrivateProfileStructW (filepath, section, key, output, size); }
|
||||
template <typename T> bool read_struct (T &structinst) const { return read_struct (&structinst, sizeof (structinst)); }
|
||||
bool write_string (pcwstring value) { return write (value); }
|
||||
bool write_string (pcstring value) { return write (value); }
|
||||
bool write (pcwstring value) { return WritePrivateProfileStringW (filepath, section, key, value); }
|
||||
bool write (pcstring value) { return write (StringToWString (value)); }
|
||||
bool write (int value) { return write_t (value); }
|
||||
bool write (unsigned int value) { return write_t (value); }
|
||||
bool write (short value) { return write_t (value); }
|
||||
bool write (unsigned short value) { return write_t (value); }
|
||||
bool write (long value) { return write_t (value); }
|
||||
bool write (unsigned long value) { return write_t (value); }
|
||||
bool write (long long value) { return write_t (value); }
|
||||
bool write (unsigned long long value) { return write_t (value); }
|
||||
bool write (int8_t value) { return write_t ((int16_t)value); }
|
||||
bool write (uint8_t value) { return write_t ((uint16_t)value); }
|
||||
bool write (float value) { return write_t (value); }
|
||||
bool write (double value) { return write_t (value); }
|
||||
bool write (bool value) { return write (value ? L"true" : L"false"); }
|
||||
bool write (void *buf, size_t bufsize) { return WritePrivateProfileStructW (filepath, section, key, buf, bufsize); }
|
||||
operator std::wstring () { return read_wstring (); }
|
||||
operator std::string () { return read_string (); }
|
||||
template <typename T> initkey &operator = (T value) { write (value); return *this; }
|
||||
initkey &operator = (const initkey &) = delete;
|
||||
// ɾ³ýÏî
|
||||
bool clear () { return DeletePrivateProfileKeyW (filepath, section, key); }
|
||||
bool empty () const { return read_wstring ().empty (); }
|
||||
#define OPERATOR_TYPE_READ(_type_, _method_) \
|
||||
operator _type_ () { return _method_ (); }
|
||||
OPERATOR_TYPE_READ (int, read_int)
|
||||
OPERATOR_TYPE_READ (unsigned int, read_uint)
|
||||
OPERATOR_TYPE_READ (long, read_long)
|
||||
OPERATOR_TYPE_READ (unsigned long, read_ulong)
|
||||
OPERATOR_TYPE_READ (long long, read_llong)
|
||||
OPERATOR_TYPE_READ (unsigned long long, read_ullong)
|
||||
OPERATOR_TYPE_READ (short, read_short)
|
||||
OPERATOR_TYPE_READ (unsigned short, read_ushort)
|
||||
OPERATOR_TYPE_READ (float, read_float)
|
||||
OPERATOR_TYPE_READ (double, read_double)
|
||||
OPERATOR_TYPE_READ (bool, read_bool)
|
||||
#ifdef OPERATOR_TYPE_READ
|
||||
#undef OPERATOR_TYPE_READ
|
||||
#endif
|
||||
};
|
||||
class initsection
|
||||
{
|
||||
private:
|
||||
const std::wstring &filepath;
|
||||
template <typename T, typename Trans = T, typename CT, typename Func> T read_t (const std::basic_string <CT> &key, T defaultvalue, Func process) const
|
||||
{
|
||||
std::basic_string <CT> temp;
|
||||
auto res = read_string (key, TypeToString ((Trans)defaultvalue, temp));
|
||||
if (IsNormalizeStringEmpty (res)) return defaultvalue;
|
||||
return (T)process (res.c_str ());
|
||||
}
|
||||
template <typename T, typename CT> bool write_t (const std::basic_string <CT> &key, T value)
|
||||
{
|
||||
std::basic_string <CT> temp;
|
||||
return write_string (key, TypeToString (value, temp));
|
||||
}
|
||||
public:
|
||||
using pcstring = const std::string &;
|
||||
using pcwstring = const std::wstring &;
|
||||
std::wstring section;
|
||||
initsection (const std::wstring &path, const std::wstring §): filepath (path), section (sect) {}
|
||||
size_t keys (std::vector <std::wstring> &output) const { return GetPrivateProfileKeysW (filepath, section, output); }
|
||||
size_t keys (std::vector <std::string> &output) const { return GetPrivateProfileKeysA (WStringToString (filepath), WStringToString (section), output); }
|
||||
bool key_values (const std::vector <std::wstring> &lines) { return WritePrivateProfileSectionW (filepath, section, lines); }
|
||||
bool key_values (const std::vector <std::string> &lines) { return WritePrivateProfileSectionA (WStringToString (filepath), WStringToString (section), lines); }
|
||||
size_t key_values (std::vector <std::wstring> &output) const { return GetPrivateProfileSectionW (filepath, section, output); }
|
||||
size_t key_values (std::vector <std::string> &output) const { return GetPrivateProfileSectionA (WStringToString (filepath), WStringToString (section), output); }
|
||||
std::wstring read_string (const std::wstring &key, const std::wstring &defaultvalue = L"") const { return GetPrivateProfileStringW (filepath, section, key, defaultvalue.c_str ()); }
|
||||
std::string read_string (const std::string &key, const std::string &defaultvalue = "") const { return WStringToString (read_string (StringToWString (key), StringToWString (defaultvalue))); }
|
||||
std::wstring read_wstring (const std::wstring &key, const std::wstring &defaultvalue = L"") const { return read_string (key, defaultvalue); }
|
||||
int read_int (const std::wstring &key, int defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoi); }
|
||||
int read_int (const std::string &key, int defaultvalue = 0) const { return read_t (key, defaultvalue, atoi); }
|
||||
unsigned int read_uint (const std::wstring &key, unsigned int defaultvalue = 0) const { return read_t (key, defaultvalue, _wtou); }
|
||||
unsigned int read_uint (const std::string &key, unsigned int defaultvalue = 0) const { return read_t (key, defaultvalue, atou); }
|
||||
long read_long (const std::wstring &key, long defaultvalue = 0) const { return read_t (key, defaultvalue, _wtol); }
|
||||
long read_long (const std::string &key, long defaultvalue = 0) const { return read_t (key, defaultvalue, atol); }
|
||||
unsigned long read_ulong (const std::wstring &key, unsigned long defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoul); }
|
||||
unsigned long read_ulong (const std::string &key, unsigned long defaultvalue = 0) const { return read_t (key, defaultvalue, atoul); }
|
||||
long long read_llong (const std::wstring &key, long long defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoll); }
|
||||
long long read_llong (const std::string &key, long long defaultvalue = 0) const { return read_t (key, defaultvalue, atoll); }
|
||||
unsigned long long read_ullong (const std::wstring &key, unsigned long long defaultvalue = 0) const { return read_t (key, defaultvalue, _wtou64); }
|
||||
unsigned long long read_ullong (const std::string &key, unsigned long long defaultvalue = 0) const { return read_t (key, defaultvalue, atou64); }
|
||||
int8_t read_i8 (const std::wstring &key, int8_t defaultvalue = 0) const { return read_t <int8_t, int16_t> (key, defaultvalue, _wtoi8); }
|
||||
int8_t read_i8 (const std::string &key, int8_t defaultvalue = 0) const { return read_t <int8_t, int16_t> (key, defaultvalue, atoi8); }
|
||||
uint8_t read_u8 (const std::wstring &key, uint8_t defaultvalue = 0) const { return read_t <uint8_t, uint16_t> (key, defaultvalue, _wtoui8); }
|
||||
uint8_t read_u8 (const std::string &key, uint8_t defaultvalue = 0) const { return read_t <uint8_t, uint16_t> (key, defaultvalue, atoui8); }
|
||||
int16_t read_i16 (const std::wstring &key, int16_t defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoi16); }
|
||||
int16_t read_i16 (const std::string &key, int16_t defaultvalue = 0) const { return read_t (key, defaultvalue, atoi16); }
|
||||
short read_short (pcwstring key, short defaultvalue = 0) const { return read_i16 (key, defaultvalue); }
|
||||
short read_short (pcstring key, short defaultvalue = 0) const { return read_i16 (key, defaultvalue); }
|
||||
unsigned short read_ushort (pcwstring key, unsigned short defaultvalue = 0) const { return read_u16 (key, defaultvalue); }
|
||||
unsigned short read_ushort (pcstring key, unsigned short defaultvalue = 0) const { return read_u16 (key, defaultvalue); }
|
||||
uint16_t read_u16 (const std::wstring &key, uint16_t defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoui16); }
|
||||
uint16_t read_u16 (const std::string &key, uint16_t defaultvalue = 0) const { return read_t (key, defaultvalue, atoui16); }
|
||||
int32_t read_i32 (const std::wstring &key, int32_t defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoi32); }
|
||||
int32_t read_i32 (const std::string &key, int32_t defaultvalue = 0) const { return read_t (key, defaultvalue, atoi32); }
|
||||
uint32_t read_u32 (const std::wstring &key, uint32_t defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoui32); }
|
||||
uint32_t read_u32 (const std::string &key, uint32_t defaultvalue = 0) const { return read_t (key, defaultvalue, atoui32); }
|
||||
int64_t read_i64 (const std::wstring &key, int64_t defaultvalue = 0) const { return read_t (key, defaultvalue, _wtoi64); }
|
||||
int64_t read_i64 (const std::string &key, int64_t defaultvalue = 0) const { return read_t (key, defaultvalue, atoi64); }
|
||||
uint64_t read_u64 (const std::wstring &key, uint64_t defaultvalue = 0) const { return read_ullong (key, defaultvalue); }
|
||||
uint64_t read_u64 (const std::string &key, uint64_t defaultvalue = 0) const { return read_ullong (key, defaultvalue); }
|
||||
float read_float (const std::wstring &key, float defaultvalue = 0) const { return read_t (key, defaultvalue, _wtof); }
|
||||
double read_double (const std::wstring &key, double defaultvalue = 0) const { return read_t (key, defaultvalue, _wtod); }
|
||||
bool read_bool (const std::wstring &key, bool defaultvalue = false) const
|
||||
{
|
||||
std::wnstring res = read_string (key, defaultvalue ? L"true" : L"false");
|
||||
if (res.empty ()) return defaultvalue;
|
||||
if (res.equals (L"true") || res.equals (L"yes") || res.equals (L"zhen") || res.equals (L"Õæ") || res.equals (L"1") || _wtoi (res.c_str ()) != 0) return true;
|
||||
else if (res.equals (L"false") || res.equals (L"no") || res.equals (L"jia") || res.equals (L"¼Ù") || res.equals (L"0")) return false;
|
||||
else return defaultvalue;
|
||||
}
|
||||
bool read_bool (const std::string &key, bool defaultvalue = false) const { return read_bool (StringToWString (key), defaultvalue); }
|
||||
bool read_struct (const std::wstring &key, void *output, size_t size) const { return GetPrivateProfileStructW (filepath, section, key, output, size); }
|
||||
template <typename T> bool read_struct (const std::wstring &key, T &structinst) const { return read_struct (key, &structinst, sizeof (structinst)); }
|
||||
bool write_string (const std::wstring &key, const std::wstring &value) { return WritePrivateProfileStringW (filepath, section, key, value); }
|
||||
bool write_string (const std::string &key, const std::string &value) { return write_string (StringToWString (key), StringToWString (value)); }
|
||||
bool write (const std::wstring &key, const std::wstring &value) { return write_string (key, value); }
|
||||
bool write (const std::string &key, const std::string &value) { return write_string (key, value); }
|
||||
bool write (pcwstring key, short value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, unsigned short value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, int value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, unsigned int value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, long value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, unsigned long value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, long long value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, unsigned long long value) { return write_t (key, value); }
|
||||
bool write (pcwstring key, int8_t value) { return write_t (key, (int16_t)value); }
|
||||
bool write (pcwstring key, uint8_t value) { return write_t (key, (uint16_t)value); }
|
||||
bool write (pcwstring key, bool value) { return write (key, value ? L"true" : L"false"); }
|
||||
bool write (pcstring key, short value) { return write_t (key, value); }
|
||||
bool write (pcstring key, unsigned short value) { return write_t (key, value); }
|
||||
bool write (pcstring key, int value) { return write_t (key, value); }
|
||||
bool write (pcstring key, unsigned int value) { return write_t (key, value); }
|
||||
bool write (pcstring key, long value) { return write_t (key, value); }
|
||||
bool write (pcstring key, unsigned long value) { return write_t (key, value); }
|
||||
bool write (pcstring key, long long value) { return write_t (key, value); }
|
||||
bool write (pcstring key, unsigned long long value) { return write_t (key, value); }
|
||||
bool write (pcstring key, int8_t value) { return write_t (key, (int16_t)value); }
|
||||
bool write (pcstring key, uint8_t value) { return write_t (key, (uint16_t)value); }
|
||||
bool write (pcstring key, bool value) { return write (StringToWString (key), value ? L"true" : L"false"); }
|
||||
bool write (pcwstring key, void *buf, size_t bufsize) { return WritePrivateProfileStructW (filepath, section, key, buf, bufsize); }
|
||||
bool write (pcstring key, void *buf, size_t bufsize) { return write (StringToWString (key), buf, bufsize); }
|
||||
initkey operator [] (pcwstring key) { return initkey (filepath, section, key); }
|
||||
initkey operator [] (pcstring key) { return initkey (filepath, section, StringToWString (key)); }
|
||||
std::wstring operator [] (pcwstring key) const { return read_string (key); }
|
||||
std::wstring operator [] (pcstring key) const { return read_string (StringToWString (key)); }
|
||||
bool delete_key (pcwstring key) { return DeletePrivateProfileKeyW (filepath, section, key); }
|
||||
bool delete_key (pcstring key) { return delete_key (StringToWString (key)); }
|
||||
bool clear () { return DeletePrivateProfileSectionW (filepath, section); }
|
||||
initkey get_key (pcwstring key) const { return initkey (filepath, section, key); }
|
||||
initkey get_key (pcwstring key) { return initkey (filepath, section, key); }
|
||||
initkey get_key (pcstring key) const { return initkey (filepath, section, StringToWString (key)); }
|
||||
initkey get_key (pcstring key) { return initkey (filepath, section, StringToWString (key)); }
|
||||
initsection &operator = (const initsection &) = delete;
|
||||
};
|
||||
class initfile
|
||||
{
|
||||
public:
|
||||
using pstring = std::string &;
|
||||
using pwstring = std::wstring &;
|
||||
using pcstring = const std::string &;
|
||||
using pcwstring = const std::wstring &;
|
||||
std::wstring filepath;
|
||||
private:
|
||||
template <typename T, typename TRANS = T, typename FN> T read_t (pcwstring section, pcwstring key, T defaultvalue, FN process) const
|
||||
{
|
||||
auto res = read_wstring (section, key, std::to_wstring ((TRANS)defaultvalue));
|
||||
if (IsNormalizeStringEmpty (res)) return defaultvalue;
|
||||
return (T)process (res.c_str ());
|
||||
}
|
||||
template <typename T> bool write_t (pcwstring section, pcwstring key, T value) { return write (section, key, std::to_wstring (value)); }
|
||||
public:
|
||||
initfile (const std::wstring &initpath): filepath (initpath) {}
|
||||
size_t sections (std::vector <std::wstring> §) const { return GetPrivateProfileSectionNamesW (filepath, sect); }
|
||||
size_t sections (std::vector <std::string> §) const { return GetPrivateProfileSectionNamesA (WStringToString (filepath), sect); }
|
||||
bool delete_section (pcwstring section) { return DeletePrivateProfileSectionW (filepath, section); }
|
||||
bool delete_section (pcstring section) { return delete_section (StringToWString (section)); }
|
||||
size_t key_values (pcwstring section, std::vector <std::wstring> &keyvalues) const { return GetPrivateProfileSectionW (filepath, section, keyvalues); }
|
||||
size_t key_values (pcstring section, std::vector <std::string> &keyvalues) const { return GetPrivateProfileSectionA (WStringToString (filepath), section, keyvalues); }
|
||||
size_t keys (pcwstring section, std::vector <std::wstring> &keyvalues) const { return GetPrivateProfileKeysW (filepath, section, keyvalues); }
|
||||
size_t keys (pcstring section, std::vector <std::string> &keyvalues) const { return GetPrivateProfileKeysA (WStringToString (filepath), section, keyvalues); }
|
||||
initsection get_section (pcwstring section) { return initsection (filepath, section); }
|
||||
initsection get_section (pcwstring section) const { return initsection (filepath, section); }
|
||||
std::wstring read_wstring (pcwstring section, pcwstring key, pcwstring dflt = L"") const { return GetPrivateProfileStringW (filepath, section, key, dflt.c_str ()); }
|
||||
std::string read_string (pcwstring section, pcwstring key, pcstring dflt = "") const { return WStringToString (read_wstring (section, key, StringToWString (dflt))); }
|
||||
#define INIT_READ_WARGS(_type_, _dfltvalue_) pcwstring section, pcwstring key, _type_ dflt = _dfltvalue_
|
||||
#define METHOD_INIT_READ(_type_, _typename_, _dfltvalue_, _process_) \
|
||||
_type_ read_##_typename_ (INIT_READ_WARGS (_type_, _dfltvalue_)) const { return read_t (section, key, dflt, _process_); }
|
||||
METHOD_INIT_READ (int, int, 0, _wtoi)
|
||||
METHOD_INIT_READ (unsigned int, uint, 0, _wtou)
|
||||
METHOD_INIT_READ (long, long, 0, _wtol)
|
||||
METHOD_INIT_READ (unsigned long, ulong, 0, _wtoul)
|
||||
METHOD_INIT_READ (long long, llong, 0, _wtoll)
|
||||
METHOD_INIT_READ (unsigned long, ullong, 0, _wtou64)
|
||||
METHOD_INIT_READ (short, short, 0, _wtoi16)
|
||||
METHOD_INIT_READ (unsigned short, ushort, 0, _wtoui16)
|
||||
METHOD_INIT_READ (int16_t, i16, 0, _wtoi16)
|
||||
METHOD_INIT_READ (uint16_t, u16, 0, _wtoui16)
|
||||
METHOD_INIT_READ (int32_t, i32, 0, _wtoi32)
|
||||
METHOD_INIT_READ (uint32_t, u32, 0, _wtoui32)
|
||||
METHOD_INIT_READ (int64_t, i64, 0, _wtoi64)
|
||||
METHOD_INIT_READ (uint64_t, u64, 0, _wtou64)
|
||||
METHOD_INIT_READ (float, float , 0, _wtof)
|
||||
METHOD_INIT_READ (double, double, 0, _wtod)
|
||||
int8_t read_i8 (INIT_READ_WARGS (int8_t, 0)) const { return read_t <int8_t, int16_t> (section, key, dflt, _wtoi8); }
|
||||
uint8_t read_u8 (INIT_READ_WARGS (uint8_t, 0)) const { return read_t <uint8_t, uint16_t> (section, key, dflt, _wtoui8); }
|
||||
bool read_bool (INIT_READ_WARGS (bool, false)) const
|
||||
{
|
||||
std::wnstring res = read_wstring (section, key, dflt ? L"true" : L"false");
|
||||
if (res.empty ()) return dflt;
|
||||
if (res.equals (L"true") || res.equals (L"yes") || res.equals (L"zhen") || res.equals (L"Õæ") || res.equals (L"1") || _wtoi (res.c_str ()) != 0) return true;
|
||||
else if (res.equals (L"false") || res.equals (L"no") || res.equals (L"jia") || res.equals (L"¼Ù") || res.equals (L"0")) return false;
|
||||
else return dflt;
|
||||
}
|
||||
bool read_struct (pcwstring section, pcwstring key, void *output, size_t size) const { return GetPrivateProfileStructW (filepath, section, key, output, size); }
|
||||
template <typename T> bool read_struct (pcwstring section, pcwstring key, T &structinst) const { return read_struct (key, &structinst, sizeof (structinst)); }
|
||||
#ifdef INIT_READ_WARGS
|
||||
#undef INIT_READ_WARGS
|
||||
#endif
|
||||
#ifdef METHOD_INIT_READ
|
||||
#undef METHOD_INIT_READ
|
||||
#endif
|
||||
#define INIT_WRITE_WARGS(_type_) pcwstring section, pcwstring key, _type_ value
|
||||
bool write (INIT_WRITE_WARGS (pcwstring)) { return WritePrivateProfileStringW (filepath, section, key, value); }
|
||||
#define METHOD_INIT_WRITE(_type_) \
|
||||
bool write (INIT_WRITE_WARGS (_type_)) { return write_t (section, key, value); }
|
||||
METHOD_INIT_WRITE (short)
|
||||
METHOD_INIT_WRITE (unsigned short)
|
||||
METHOD_INIT_WRITE (int)
|
||||
METHOD_INIT_WRITE (unsigned int)
|
||||
METHOD_INIT_WRITE (long)
|
||||
METHOD_INIT_WRITE (unsigned long)
|
||||
METHOD_INIT_WRITE (long long)
|
||||
METHOD_INIT_WRITE (unsigned long long)
|
||||
METHOD_INIT_WRITE (float)
|
||||
METHOD_INIT_WRITE (double)
|
||||
bool write (INIT_WRITE_WARGS (bool)) { return write (section, key, value ? L"true" : L"false"); }
|
||||
bool write (INIT_WRITE_WARGS (int8_t)) { return write_t (section, key, (int16_t)value); }
|
||||
bool write (INIT_WRITE_WARGS (uint8_t)) { return write_t (section, key, (uint16_t)value); }
|
||||
bool write (pcwstring section, pcwstring key, void *buf, size_t bufsize) { return WritePrivateProfileStructW (filepath, section, key, buf, bufsize); }
|
||||
initsection operator [] (pcwstring section) { return initsection (filepath, section); }
|
||||
initsection operator [] (pcstring section) { return initsection (filepath, StringToWString (section)); }
|
||||
initsection operator [] (pcwstring section) const { return initsection (filepath, section); }
|
||||
initsection operator [] (pcstring section) const { return initsection (filepath, StringToWString (section)); }
|
||||
#ifdef METHOD_INIT_WRITE
|
||||
#undef METHOD_INIT_WRITE
|
||||
#endif
|
||||
#ifdef INIT_WRITE_WARGS
|
||||
#undef INIT_WRITE_WARGS
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,595 @@
|
||||
#include <Windows.h>
|
||||
#include <set>
|
||||
#include <msclr/marshal_cppstd.h>
|
||||
#include <ShObjIdl.h>
|
||||
#include <MsHTML.h>
|
||||
#include <ExDisp.h>
|
||||
#include <atlbase.h>
|
||||
#include "cmdargs.h"
|
||||
#include "themeinfo.h"
|
||||
#include "mpstr.h"
|
||||
#include "initfile.h"
|
||||
#include "resource.h"
|
||||
#include "vemani.h"
|
||||
#include "ieshell.h"
|
||||
using namespace System;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DEBUGMODE true
|
||||
#else
|
||||
#define DEBUGMODE false
|
||||
#endif
|
||||
|
||||
LPCWSTR g_lpAppId = L"Microsoft.DesktopAppInstaller";
|
||||
auto &g_identity = g_lpAppId;
|
||||
auto &m_idenName = g_lpAppId;
|
||||
struct iconhandle
|
||||
{
|
||||
HICON hIcon = nullptr;
|
||||
iconhandle (HICON hIcon = nullptr): hIcon (hIcon) {}
|
||||
~iconhandle () { try { if (hIcon) DestroyIcon (hIcon); hIcon = nullptr; } catch (...) {} }
|
||||
};
|
||||
iconhandle g_hIconMain (LoadRCIcon (IDI_ICON_MAIN));
|
||||
initfile g_initfile (CombinePath (GetProgramRootDirectoryW (), L"config.ini"));
|
||||
ref class MainHtmlWnd;
|
||||
msclr::gcroot <MainHtmlWnd ^> g_mainwnd;
|
||||
vemanifest g_vemani (
|
||||
IsFileExists (CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml")) ?
|
||||
CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml") :
|
||||
CombinePath (GetProgramRootDirectoryW (), L"AppInstaller.VisualElementsManifest.xml")
|
||||
);
|
||||
resxmldoc g_scaleres (
|
||||
IsFileExists (CombinePath (GetProgramRootDirectoryW (), L"VisualElements\\scale.xml")) ?
|
||||
CombinePath (GetProgramRootDirectoryW (), L"VisualElements\\scale.xml") :
|
||||
CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml")
|
||||
);
|
||||
|
||||
HRESULT GetWebBrowser2Interface (System::Windows::Forms::WebBrowser ^fwb, IWebBrowser2 **output)
|
||||
{
|
||||
if (fwb == nullptr || output == nullptr) return E_INVALIDARG;
|
||||
*output = nullptr;
|
||||
Object ^activeX = fwb->ActiveXInstance;
|
||||
if (activeX == nullptr) return E_FAIL;
|
||||
IntPtr pUnk = Marshal::GetIUnknownForObject (activeX);
|
||||
if (pUnk == IntPtr::Zero) return E_FAIL;
|
||||
HRESULT hr = ((IUnknown *)pUnk.ToPointer ())->QueryInterface (IID_IWebBrowser2, (void **)output);
|
||||
Marshal::Release (pUnk);
|
||||
return hr;
|
||||
}
|
||||
|
||||
public ref class SplashForm: public System::Windows::Forms::Form
|
||||
{
|
||||
public:
|
||||
using PictureBox = System::Windows::Forms::PictureBox;
|
||||
using Timer = System::Windows::Forms::Timer;
|
||||
private:
|
||||
PictureBox ^picbox;
|
||||
Timer ^timer;
|
||||
double opastep = 0.05;
|
||||
void InitForm ()
|
||||
{
|
||||
this->DoubleBuffered = true;
|
||||
InitializeComponent ();
|
||||
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
|
||||
this->StartPosition = System::Windows::Forms::FormStartPosition::Manual;
|
||||
this->ShowInTaskbar = false;
|
||||
this->AllowTransparency = true;
|
||||
this->Opacity = 1.0;
|
||||
}
|
||||
void InitializeComponent ()
|
||||
{
|
||||
double dDpi = GetDPI () * 0.01;
|
||||
this->picbox = gcnew System::Windows::Forms::PictureBox ();
|
||||
this->picbox->Size = System::Drawing::Size (620 * dDpi, 300 * dDpi);
|
||||
this->picbox->BackColor = System::Drawing::Color::Transparent;
|
||||
picbox->Anchor = System::Windows::Forms::AnchorStyles::None;
|
||||
picbox->SizeMode = System::Windows::Forms::PictureBoxSizeMode::Zoom;
|
||||
}
|
||||
void OnFadeTimer (Object ^sender, EventArgs ^e)
|
||||
{
|
||||
auto fadeTimer = timer;
|
||||
auto opacityStep = opastep;
|
||||
if (this->Opacity > 0)
|
||||
{
|
||||
this->Opacity -= opacityStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeTimer->Stop ();
|
||||
this->Close ();
|
||||
}
|
||||
}
|
||||
void OnLoad (Object ^sender, EventArgs ^e)
|
||||
{
|
||||
this->ChangePosAndSize ();
|
||||
this->Visible = true;
|
||||
}
|
||||
void OnResize (Object ^sender, EventArgs ^e)
|
||||
{
|
||||
if (IsHandleCreated && picbox->IsHandleCreated)
|
||||
{
|
||||
Drawing::Size sz = this->ClientSize;
|
||||
this->picbox->Location = Drawing::Point (
|
||||
(sz.Width - picbox->Width) * 0.5,
|
||||
(sz.Height - picbox->Height) * 0.5
|
||||
);
|
||||
}
|
||||
}
|
||||
void OnResizeOwner (Object ^sender, EventArgs ^e) { this->ChangePosAndSize (); }
|
||||
void OnLocationChangedOwner (Object ^sender, EventArgs ^e) { this->ChangePosAndSize (); }
|
||||
protected:
|
||||
virtual void OnHandleCreated (EventArgs^ e) override
|
||||
{
|
||||
Form::OnHandleCreated (e);
|
||||
if (Environment::OSVersion->Version->Major >= 6)
|
||||
{
|
||||
INT mr = 0;
|
||||
MARGINS margins = {mr, mr, mr, mr};
|
||||
HRESULT hr = DwmExtendFrameIntoClientArea ((HWND)this->Handle.ToPointer (), &margins);
|
||||
}
|
||||
}
|
||||
public:
|
||||
SplashForm (System::String ^imgpath, System::Drawing::Color backcolor, System::Windows::Forms::Form ^owner)
|
||||
{
|
||||
if (owner != nullptr) this->Owner = owner;
|
||||
InitForm ();
|
||||
std::wstring filefullpath = MPStringToStdW (imgpath);
|
||||
if (filefullpath.find (L'%') != filefullpath.npos) filefullpath = ProcessEnvVars (filefullpath);
|
||||
filefullpath = GetFullPathName (imgpath ? MPStringToStdW (imgpath) : L"");
|
||||
try
|
||||
{
|
||||
auto img = System::Drawing::Image::FromFile (gcnew System::String (filefullpath.c_str ()));
|
||||
if (img != nullptr) picbox->Image = img;
|
||||
}
|
||||
catch (...) { }
|
||||
if (backcolor != Drawing::Color::Transparent)
|
||||
{
|
||||
picbox->BackColor = backcolor;
|
||||
this->BackColor = backcolor;
|
||||
}
|
||||
if (this->Owner != nullptr)
|
||||
{
|
||||
this->Owner->Resize += gcnew System::EventHandler (this, &SplashForm::OnResizeOwner);
|
||||
this->Owner->LocationChanged += gcnew System::EventHandler (this, &SplashForm::OnLocationChangedOwner);
|
||||
}
|
||||
this->Controls->Add (picbox);
|
||||
this->Resize += gcnew EventHandler (this, &SplashForm::OnResize);
|
||||
timer = gcnew System::Windows::Forms::Timer ();
|
||||
timer->Interval = 15;
|
||||
timer->Tick += gcnew System::EventHandler (this, &SplashForm::OnFadeTimer);
|
||||
this->Load += gcnew EventHandler (this, &SplashForm::OnLoad);
|
||||
}
|
||||
void ChangePosAndSize ()
|
||||
{
|
||||
if (this->Owner && this->Owner->IsHandleCreated)
|
||||
{
|
||||
this->Owner->Update ();
|
||||
System::Drawing::Point pt = this->Owner->PointToScreen (this->Owner->ClientRectangle.Location);
|
||||
this->Location = pt;
|
||||
this->Size = this->Owner->ClientSize;
|
||||
}
|
||||
else if (this->Parent && this->Parent->IsHandleCreated)
|
||||
{
|
||||
this->Parent->Update ();
|
||||
System::Drawing::Point pt = this->Parent->PointToScreen (this->Parent->ClientRectangle.Location);
|
||||
this->Location = pt;
|
||||
this->Size = this->Parent->ClientSize;
|
||||
}
|
||||
if (IsHandleCreated && picbox->IsHandleCreated)
|
||||
{
|
||||
Drawing::Size sz = this->ClientSize;
|
||||
this->picbox->Location = Drawing::Point (
|
||||
(sz.Width - picbox->Width) * 0.5,
|
||||
(sz.Height - picbox->Height) * 0.5
|
||||
);
|
||||
}
|
||||
}
|
||||
void SetSplashImage (System::Drawing::Image ^img) { if (picbox) picbox->Image = img; }
|
||||
void SetSplashImage (System::String ^imgpath) { try { SetSplashImage (System::Drawing::Image::FromFile (imgpath)); } catch (...) {} }
|
||||
void SetSplashImage (const std::wstring &imgpath) { SetSplashImage (CStringToMPString (imgpath)); }
|
||||
void SetSplashBackgroundColor (System::Drawing::Color color) { picbox->BackColor = color; this->BackColor = color; }
|
||||
// 渐变消失
|
||||
void FadeOut () { timer->Start (); }
|
||||
// 立即消失
|
||||
void FadeAway () { this->Visible = false; this->Close (); }
|
||||
~SplashForm ()
|
||||
{
|
||||
if (this->Owner != nullptr)
|
||||
{
|
||||
this->Owner->Resize -= gcnew System::EventHandler (this, &SplashForm::OnResizeOwner);
|
||||
this->Owner->LocationChanged -= gcnew System::EventHandler (this, &SplashForm::OnLocationChangedOwner);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[ComVisible (true)]
|
||||
public ref class MainHtmlWnd: public System::Windows::Forms::Form
|
||||
{
|
||||
public:
|
||||
using WebBrowser = System::Windows::Forms::WebBrowser;
|
||||
private:
|
||||
WebBrowser ^webui;
|
||||
SplashForm ^splash;
|
||||
public:
|
||||
[ComVisible (true)]
|
||||
ref class IBridge
|
||||
{
|
||||
private:
|
||||
MainHtmlWnd ^wndinst = nullptr;
|
||||
public:
|
||||
IBridge (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||||
ref class _I_System
|
||||
{
|
||||
private:
|
||||
MainHtmlWnd ^wndinst = nullptr;
|
||||
public:
|
||||
ref class _I_UI
|
||||
{
|
||||
private:
|
||||
MainHtmlWnd ^wndinst = nullptr;
|
||||
public:
|
||||
_I_UI (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||||
property int DPIPercent { int get () { return GetDPI (); }}
|
||||
property double DPI { double get () { return DPIPercent * 0.01; }}
|
||||
void showSplash () { wndinst->SplashScreen->Show (); }
|
||||
void fadeAwaySplash () { wndinst->SplashScreen->FadeAway (); }
|
||||
void fadeOutSplash () { wndinst->SplashScreen->FadeOut (); }
|
||||
};
|
||||
private:
|
||||
_I_UI ^ui = gcnew _I_UI (wndinst);
|
||||
public:
|
||||
_I_System (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||||
property _I_UI ^UI { _I_UI ^get () { return ui; } }
|
||||
};
|
||||
ref class _I_IEFrame
|
||||
{
|
||||
private:
|
||||
MainHtmlWnd ^wndinst = nullptr;
|
||||
public:
|
||||
_I_IEFrame (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||||
property int Scale
|
||||
{
|
||||
int get () { return wndinst->PageScale; }
|
||||
void set (int value) { return wndinst->PageScale = value; }
|
||||
}
|
||||
property int Version { int get () { return GetInternetExplorerVersionMajor (); }}
|
||||
};
|
||||
ref class _I_Storage
|
||||
{
|
||||
private:
|
||||
MainHtmlWnd ^wndinst = nullptr;
|
||||
public:
|
||||
_I_Storage (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||||
ref class Path
|
||||
{
|
||||
|
||||
};
|
||||
};
|
||||
ref class _I_String
|
||||
{
|
||||
public:
|
||||
ref class _I_NString
|
||||
{
|
||||
public:
|
||||
bool NEquals (String ^l, String ^r) { return IsNormalizeStringEquals (MPStringToPtrW (l), MPStringToPtrW (r)); }
|
||||
bool Empty (String ^l) { return IsNormalizeStringEmpty (MPStringToStdW (l)); }
|
||||
int Compare (String ^l, String ^r) { return NormalizeStringCompare (MPStringToPtrW (l), MPStringToPtrW (r)); }
|
||||
int Length (String ^l) { return GetNormalizeStringLength (MPStringToStdW (l)); }
|
||||
};
|
||||
private:
|
||||
_I_NString ^nstr = gcnew _I_NString ();
|
||||
public:
|
||||
property _I_NString ^NString { _I_NString ^get () { return nstr; }}
|
||||
String ^Trim (String ^src)
|
||||
{
|
||||
std::wstring csrc = MPStringToStdW (src);
|
||||
return CStringToMPString (::StringTrim (csrc));
|
||||
}
|
||||
String ^ToLower (String ^src) { return CStringToMPString (StringToLower (MPStringToStdW (src))); }
|
||||
String ^ToUpper (String ^src) { return CStringToMPString (StringToUpper (MPStringToStdW (src))); }
|
||||
};
|
||||
private:
|
||||
_I_System ^system = gcnew _I_System (wndinst);
|
||||
_I_IEFrame ^ieframe = gcnew _I_IEFrame (wndinst);
|
||||
_I_Storage ^storage = gcnew _I_Storage (wndinst);
|
||||
_I_String ^str = gcnew _I_String ();
|
||||
public:
|
||||
property _I_System ^System { _I_System ^get () { return system; }}
|
||||
property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }}
|
||||
property _I_Storage ^Storage { _I_Storage ^get () { return storage; }}
|
||||
property _I_String ^String { _I_String ^get () { return str; }}
|
||||
};
|
||||
protected:
|
||||
property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } }
|
||||
property SplashForm ^SplashScreen { SplashForm ^get () { return this->splash; } }
|
||||
property int DPIPercent { int get () { return GetDPI (); }}
|
||||
property double DPI { double get () { return DPIPercent * 0.01; }}
|
||||
void Init ()
|
||||
{
|
||||
this->Visible = false;
|
||||
this->webui = gcnew System::Windows::Forms::WebBrowser ();
|
||||
this->SuspendLayout ();
|
||||
this->webui->Dock = System::Windows::Forms::DockStyle::Fill;
|
||||
this->webui->IsWebBrowserContextMenuEnabled = DEBUGMODE;
|
||||
this->webui->AllowWebBrowserDrop = false;
|
||||
this->Controls->Add (this->webui);
|
||||
if (g_hIconMain.hIcon)
|
||||
{
|
||||
try { this->Icon = System::Drawing::Icon::FromHandle (IntPtr (g_hIconMain.hIcon)); }
|
||||
catch (...) {}
|
||||
}
|
||||
unsigned ww = 0, wh = 0;
|
||||
auto &ini = g_initfile;
|
||||
auto setsect = ini ["Settings"];
|
||||
if (setsect [L"SavePosAndSizeBeforeCancel"].read_bool ())
|
||||
{
|
||||
ww = setsect [L"LastWidth"].read_uint (setsect [L"DefaultWidth"].read_uint (rcInt (IDS_DEFAULTWIDTH)));
|
||||
wh = setsect [L"LastHeight"].read_uint (setsect [L"DefaultHeight"].read_uint (rcInt (IDS_DEFAULTHEIGHT)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ww = setsect [L"DefaultWidth"].read_uint (rcInt (IDS_DEFAULTWIDTH));
|
||||
wh = setsect [L"DefaultHeight"].read_uint (rcInt (IDS_DEFAULTHEIGHT));
|
||||
}
|
||||
this->MinimumSize = System::Drawing::Size (
|
||||
setsect [L"MinimumWidth"].read_uint (rcInt (IDS_MINWIDTH)) * DPI,
|
||||
setsect [L"MinimumHeight"].read_uint (rcInt (IDS_MINHIEHGT)) * DPI
|
||||
);
|
||||
this->ClientSize = System::Drawing::Size (ww * DPI, wh * DPI);
|
||||
this->WindowState = (System::Windows::Forms::FormWindowState)setsect [L"LastWndState"].read_int ((int)System::Windows::Forms::FormWindowState::Normal);
|
||||
this->Text = rcString (IDS_WINTITLE);
|
||||
this->ResumeLayout (false);
|
||||
webui->ObjectForScripting = gcnew IBridge (this);
|
||||
this->webui->DocumentCompleted += gcnew System::Windows::Forms::WebBrowserDocumentCompletedEventHandler (this, &MainHtmlWnd::OnDocumentCompleted);
|
||||
this->webui->PreviewKeyDown += gcnew System::Windows::Forms::PreviewKeyDownEventHandler (this, &MainHtmlWnd::OnPreviewKeyDown_WebBrowser);
|
||||
this->Resize += gcnew System::EventHandler (this, &MainHtmlWnd::OnResize);
|
||||
this->Load += gcnew EventHandler (this, &MainHtmlWnd::OnCreate);
|
||||
this->ResizeEnd += gcnew EventHandler (this, &MainHtmlWnd::OnResizeEnd);
|
||||
}
|
||||
void OnDocumentCompleted (Object ^sender, System::Windows::Forms::WebBrowserDocumentCompletedEventArgs ^e)
|
||||
{
|
||||
if (e->Url->ToString () == webui->Url->ToString ())
|
||||
{
|
||||
|
||||
ExecScript ("Windows.UI.DPI.mode = 1");
|
||||
ExecScript ("Bridge.Frame.scale = Bridge.Frame.scale * Bridge.UI.dpi");
|
||||
splash->FadeOut ();
|
||||
}
|
||||
}
|
||||
void OnCreate (System::Object ^sender, System::EventArgs ^e)
|
||||
{
|
||||
splash->Owner = this;
|
||||
splash->ChangePosAndSize ();
|
||||
splash->Show ();
|
||||
splash->Update ();
|
||||
webui->Navigate (CStringToMPString (CombinePath (GetProgramRootDirectoryW (), L"html\\install.html")));
|
||||
}
|
||||
void OnPreviewKeyDown_WebBrowser (System::Object ^sender, System::Windows::Forms::PreviewKeyDownEventArgs ^e)
|
||||
{
|
||||
if (e->KeyCode == System::Windows::Forms::Keys::F5 || (e->KeyCode == System::Windows::Forms::Keys::R && e->Control))
|
||||
e->IsInputKey = true;
|
||||
}
|
||||
void OnResize (Object ^sender, EventArgs ^e)
|
||||
{
|
||||
}
|
||||
void OnResizeEnd (Object ^sender, EventArgs ^e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
MainHtmlWnd ()
|
||||
{
|
||||
splash = gcnew SplashForm (
|
||||
gcnew String (g_vemani.splash_screen_image (L"App").c_str ()),
|
||||
StringToColor (gcnew String (g_vemani.splash_screen_backgroundcolor (L"App").c_str ())),
|
||||
this
|
||||
);
|
||||
System::Windows::Forms::Application::DoEvents ();
|
||||
Init ();
|
||||
}
|
||||
Object ^CallScriptFunction (String ^lpFuncName, ... array <Object ^> ^alpParams)
|
||||
{
|
||||
try { return this->webui->Document->InvokeScript (lpFuncName, alpParams); }
|
||||
catch (Exception ^e) {}
|
||||
return nullptr;
|
||||
}
|
||||
Object ^CallScriptFunction (String ^lpScriptName)
|
||||
{
|
||||
try { return this->webui->Document->InvokeScript (lpScriptName); }
|
||||
catch (Exception ^e) {}
|
||||
return nullptr;
|
||||
}
|
||||
Object ^InvokeCallScriptFunction (String ^lpFuncName, ... array <Object ^> ^alpParams)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this->InvokeRequired) return (Object ^)this->Invoke (gcnew Func <String ^, array <Object ^> ^, Object ^> (this, &MainHtmlWnd::CallScriptFunction), lpFuncName, alpParams);
|
||||
else return CallScriptFunction (lpFuncName, alpParams);
|
||||
}
|
||||
catch (Exception ^e) {}
|
||||
return nullptr;
|
||||
}
|
||||
Object ^InvokeCallScriptFunction (String ^lpScriptName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this->InvokeRequired) return (Object ^)this->Invoke (gcnew Func <String ^, Object ^> (this, &MainHtmlWnd::CallScriptFunction), lpScriptName);
|
||||
else return CallScriptFunction (lpScriptName);
|
||||
}
|
||||
catch (Exception ^e) {}
|
||||
return nullptr;
|
||||
}
|
||||
Object ^ExecScript (... array <Object ^> ^alpScript) { return InvokeCallScriptFunction ("eval", alpScript); }
|
||||
property int PageScale
|
||||
{
|
||||
int get ()
|
||||
{
|
||||
CComPtr <IWebBrowser2> web2;
|
||||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||||
if (FAILED (hr)) return 0;
|
||||
VARIANT v;
|
||||
VariantInit (&v);
|
||||
hr = web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DODEFAULT, nullptr, &v);
|
||||
if (FAILED (hr) || v.vt != VT_I4) return 0;
|
||||
int val = v.lVal;
|
||||
VariantClear (&v);
|
||||
return val;
|
||||
}
|
||||
void set (int value)
|
||||
{
|
||||
CComPtr <IWebBrowser2> web2;
|
||||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||||
if (FAILED (hr)) return;
|
||||
VARIANT v;
|
||||
VariantInit (&v);
|
||||
v.vt = VT_I4;
|
||||
v.lVal = value;
|
||||
web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &v, nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
using MainWnd = MainHtmlWnd;
|
||||
std::vector <std::wstring> LoadFileListW (const std::wstring &filePath)
|
||||
{
|
||||
std::vector <std::wstring> result;
|
||||
HANDLE hFile = CreateFileW (
|
||||
filePath.c_str (),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) return result;
|
||||
LARGE_INTEGER fileSize {};
|
||||
if (!GetFileSizeEx (hFile, &fileSize) || fileSize.QuadPart == 0)
|
||||
{
|
||||
CloseHandle (hFile);
|
||||
return result;
|
||||
}
|
||||
DWORD size = static_cast <DWORD> (fileSize.QuadPart);
|
||||
std::vector <WCHAR> buf;
|
||||
std::wstring buffer;
|
||||
buffer.resize (size / sizeof (wchar_t) + 2 + 2);
|
||||
DWORD readBytes = 0;
|
||||
ReadFile (hFile, buf.data (), size, &readBytes, nullptr);
|
||||
buffer += buf.data ();
|
||||
CloseHandle (hFile);
|
||||
buffer [readBytes / sizeof (wchar_t)] = L'\0';
|
||||
size_t start = 0;
|
||||
while (true)
|
||||
{
|
||||
size_t pos = buffer.find (L'\n', start);
|
||||
std::wstring line;
|
||||
if (pos == std::wstring::npos)
|
||||
{
|
||||
line = buffer.substr (start);
|
||||
}
|
||||
else
|
||||
{
|
||||
line = buffer.substr (start, pos - start);
|
||||
start = pos + 1;
|
||||
}
|
||||
if (!line.empty () && line.back () == L'\r') line.pop_back ();
|
||||
if (!line.empty ()) result.push_back (line);
|
||||
if (pos == std::wstring::npos) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
enum class CMDPARAM: DWORD
|
||||
{
|
||||
NONE = 0b000,
|
||||
SILENT = 0b001,
|
||||
VERYSILENT = 0b011,
|
||||
MULTIPLE = 0b100
|
||||
};
|
||||
DWORD CmdMapsToFlags (std::map <cmdkey, cmdvalue> cmdpairs, std::set <std::wnstring> &files, std::set <std::wnstring> &uris)
|
||||
{
|
||||
DWORD dwret = 0;
|
||||
for (auto &it : cmdpairs)
|
||||
{
|
||||
switch (it.first.type)
|
||||
{
|
||||
case paramtype::file: {
|
||||
if (IsFileExists (it.first.key)) files.insert (it.first.key);
|
||||
} break;
|
||||
case paramtype::uri: {
|
||||
uris.insert (it.first.key);
|
||||
} break;
|
||||
default:
|
||||
case paramtype::string: {
|
||||
auto &key = it.first;
|
||||
auto &value = it.second;
|
||||
if (key.key.equals (L"silent")) dwret |= (DWORD)CMDPARAM::SILENT;
|
||||
else if (key.key.equals (L"verysilent")) dwret |= (DWORD)CMDPARAM::SILENT;
|
||||
else if (key.key.equals (L"multiple"))
|
||||
{
|
||||
if (value.type == paramtype::file)
|
||||
{
|
||||
auto strlist = LoadFileListW (value.value);
|
||||
for (auto &it_s : strlist)
|
||||
{
|
||||
if (std::wnstring::empty (it_s)) continue;
|
||||
std::wnstring filepath = it_s;
|
||||
std::wstring listdir = GetFileDirectoryW (value.value);
|
||||
if (!IsFileExists (filepath)) filepath = ProcessEnvVars (filepath);
|
||||
if (!IsFileExists (filepath)) filepath = CombinePath (listdir, filepath);
|
||||
if (!IsFileExists (filepath)) filepath = CombinePath (listdir, it_s);
|
||||
if (!IsFileExists (filepath)) continue;
|
||||
else files.insert (filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (files.size () > 1) dwret |= (DWORD)CMDPARAM::MULTIPLE;
|
||||
return dwret;
|
||||
}
|
||||
HRESULT SetCurrentAppUserModelID (PCWSTR appID)
|
||||
{
|
||||
typedef HRESULT (WINAPI *SetAppUserModelIDFunc)(PCWSTR);
|
||||
HMODULE shell32 = LoadLibraryW (L"shell32.dll");
|
||||
destruct freelib ([&] () {
|
||||
if (shell32) FreeLibrary (shell32);
|
||||
});
|
||||
try
|
||||
{
|
||||
if (!shell32) return E_FAIL;
|
||||
auto SetAppUserModelID = (SetAppUserModelIDFunc)GetProcAddress (shell32, "SetCurrentProcessExplicitAppUserModelID");
|
||||
if (!SetAppUserModelID)
|
||||
{
|
||||
FreeLibrary (shell32);
|
||||
return E_FAIL;
|
||||
}
|
||||
return SetAppUserModelID (appID);
|
||||
}
|
||||
catch (...) { return E_FAIL; }
|
||||
return E_FAIL;
|
||||
}
|
||||
[STAThread]
|
||||
int APIENTRY wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
SetCurrentProcessExplicitAppUserModelID (m_idenName);
|
||||
SetProcessDPIAware ();
|
||||
{
|
||||
// 设置当前目录为程序所在目录
|
||||
std::wnstring currdir = GetCurrentProgramPathW ();
|
||||
std::wnstring rootdir = GetProgramRootDirectoryW ();
|
||||
if (!PathEquals (currdir, rootdir)) SetCurrentDirectoryW (rootdir.c_str ());
|
||||
}
|
||||
CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||||
destruct relco ([] () {
|
||||
CoUninitialize ();
|
||||
});
|
||||
System::Windows::Forms::Application::EnableVisualStyles ();
|
||||
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault (false);
|
||||
auto mwnd = gcnew MainHtmlWnd ();
|
||||
g_mainwnd = mwnd;
|
||||
System::Windows::Forms::Application::Run (mwnd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#ifdef __cplusplus
|
||||
#ifndef GetCurrentModule_bRefDefault
|
||||
// 在 C++ 中,GetCurrentModule 将会启用默认值。你可以在之前宏定义此默认值。定义宏时别忘了等号“=”
|
||||
// 用法如:HMODULE GetCurrentModule (BOOL bRef GetCurrentModule_bRefDefault)
|
||||
#define GetCurrentModule_bRefDefault = FALSE
|
||||
#endif
|
||||
#else
|
||||
#define GetCurrentModule_bRefDefault
|
||||
#endif
|
||||
HMODULE GetCurrentModule (BOOL bRef GetCurrentModule_bRefDefault)
|
||||
{
|
||||
HMODULE hModule = NULL;
|
||||
if (GetModuleHandleExW (bRef ? GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS : (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
||||
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), (LPCWSTR)GetCurrentModule, &hModule))
|
||||
{
|
||||
return hModule;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
HMODULE GetSelfModuleHandle ()
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
return ((::VirtualQuery (GetSelfModuleHandle, &mbi, sizeof (mbi)) != 0)
|
||||
? (HMODULE)mbi.AllocationBase : NULL);
|
||||
}
|
||||
#ifndef GetModuleHandleW_lpModuleNameDefault
|
||||
#define GetModuleHandleW_lpModuleNameDefault NULL
|
||||
#endif
|
||||
#ifndef DEFAULT_HMODULE
|
||||
#ifdef HMODULE_MODE_EXE
|
||||
#define DEFAULT_HMODULE GetModuleHandleW (NULL)
|
||||
#elif defined (HMODULE_MODE_DLL1)
|
||||
#define DEFAULT_HMODULE GetCurrentModule ()
|
||||
#elif defined (HMODULE_MODE_DLL2)
|
||||
#define DEFAULT_HMODULE GetSelfModuleHandle ()
|
||||
#else
|
||||
#define DEFAULT_HMODULE GetModuleHandleW (GetModuleHandleW_lpModuleNameDefault)
|
||||
#endif
|
||||
#endif
|
||||
#undef GetModuleHandleW_lpModuleNameDefault
|
||||
#ifdef __cplusplus
|
||||
#ifndef hModule_DefaultParam
|
||||
// 在 C++ 中,你可以使用此宏“hModule_DefaultParam”来用于给一些函数的形参定义默认值。你可以在之前宏定义此默认值。定义宏时别忘了等号“=”
|
||||
// 用法如:std::wstring GetRCStringSW (UINT resID, HMODULE hModule hModule_DefaultParam)。
|
||||
#define hModule_DefaultParam = DEFAULT_HMODULE
|
||||
#endif
|
||||
#else
|
||||
#define hModule_DefaultParam
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <windef.h>
|
||||
#include <string>
|
||||
#include <vcclr.h>
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Text;
|
||||
|
||||
String ^CStringToMPString (LPCSTR lpstr) { return (lpstr ? gcnew String (lpstr) : String::Empty); }
|
||||
String ^CStringToMPString (LPCWSTR lpstr) { return (lpstr ? gcnew String (lpstr) : String::Empty); }
|
||||
String ^CStringToMPString (const std::string &objstr) { return CStringToMPString (objstr.c_str ()); }
|
||||
String ^CStringToMPString (const std::wstring &objstr) { return CStringToMPString (objstr.c_str ()); }
|
||||
// 转换为 UTF-16,指针不需要释放(本质是指针转换)
|
||||
LPCWSTR MPStringToPtrW (String ^in)
|
||||
{
|
||||
if (in == nullptr) return NULL;
|
||||
pin_ptr <const wchar_t> wch = PtrToStringChars (in);
|
||||
return wch;
|
||||
}
|
||||
// 转换为 std::wstring(UTF-16)
|
||||
std::wstring MPStringToStdW (String^ in)
|
||||
{
|
||||
if (in == nullptr) return std::wstring ();
|
||||
pin_ptr <const wchar_t> wch = PtrToStringChars (in);
|
||||
return std::wstring (wch, in->Length);
|
||||
}
|
||||
// 转换为 ANSI 编码的 std::string
|
||||
std::string MPStringToStdA (String^ in)
|
||||
{
|
||||
if (in == nullptr) return std::string ();
|
||||
array <unsigned char> ^bytes = Encoding::Default->GetBytes (in);
|
||||
pin_ptr <unsigned char> pinned = &bytes [0];
|
||||
return std::string (reinterpret_cast <const char *> (pinned), bytes->Length);
|
||||
}
|
||||
// 转换为 UTF-8 编码的 std::string
|
||||
std::string MPStringToStdU8 (String^ in)
|
||||
{
|
||||
if (in == nullptr) return std::string ();
|
||||
array <unsigned char> ^bytes = Encoding::UTF8->GetBytes (in);
|
||||
pin_ptr <unsigned char> pinned = &bytes [0];
|
||||
return std::string (reinterpret_cast <const char*> (pinned), bytes->Length);
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <cctype>
|
||||
namespace l0km
|
||||
{
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> inline std::basic_string<E, TR, AL> toupper (const std::basic_string <E, TR, AL> &src)
|
||||
{
|
||||
std::basic_string <E, TR, AL> dst = src;
|
||||
static const std::locale loc;
|
||||
const std::ctype <E> &ctype = std::use_facet <std::ctype <E>> (loc);
|
||||
for (typename std::basic_string <E, TR, AL>::size_type i = 0; i < src.size (); ++ i)
|
||||
{
|
||||
dst [i] = ctype.toupper (src [i]);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> inline std::basic_string <E, TR, AL> tolower (const std::basic_string <E, TR, AL> &src)
|
||||
{
|
||||
std::basic_string <E, TR, AL> dst = src;
|
||||
static const std::locale loc;
|
||||
const std::ctype <E> &ctype = std::use_facet <std::ctype <E>> (loc);
|
||||
for (typename std::basic_string <E, TR, AL>::size_type i = 0; i < src.size (); ++ i)
|
||||
{
|
||||
dst [i] = ctype.tolower (src [i]);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
inline char toupper (char ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <char>> (loc).toupper (ch);
|
||||
}
|
||||
inline char tolower (char ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <char>> (loc).tolower (ch);
|
||||
}
|
||||
inline wchar_t toupper (wchar_t ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <wchar_t>> (loc).toupper (ch);
|
||||
}
|
||||
inline wchar_t tolower (wchar_t ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <wchar_t>> (loc).tolower (ch);
|
||||
}
|
||||
inline int toupper (int ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <int>> (loc).toupper (ch);
|
||||
}
|
||||
inline int tolower (int ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <int>> (loc).tolower (ch);
|
||||
}
|
||||
}
|
||||
template <typename ct> bool is_blank (ct &ch)
|
||||
{
|
||||
return ch == ct (' ') || ch == ct ('\t') || ch == ct ('\n');
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> std::basic_string <E, TR, AL> NormalizeString (const std::basic_string <E, TR, AL> &str, bool upper = false, bool includemidblank = false)
|
||||
{
|
||||
typedef std::basic_string <E, TR, AL> string_type;
|
||||
string_type result;
|
||||
if (str.empty ()) return result;
|
||||
auto begin_it = str.begin ();
|
||||
auto end_it = str.end ();
|
||||
while (begin_it != end_it && is_blank (*begin_it)) ++begin_it;
|
||||
while (end_it != begin_it && is_blank (*(end_it - 1))) --end_it;
|
||||
bool in_space = false;
|
||||
for (auto it = begin_it; it != end_it; ++ it)
|
||||
{
|
||||
if (is_blank (*it))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
result.push_back (E (' '));
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (*it);
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (*it);
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
if (upper) return l0km::toupper (result);
|
||||
else return l0km::tolower (result);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> bool IsNormalizeStringEquals (const std::basic_string <E, TR, AL> &l, const std::basic_string <E, TR, AL> &r, bool includemidblank = false)
|
||||
{
|
||||
auto _local_strlen = [] (const E *p) -> size_t {
|
||||
size_t cnt = 0;
|
||||
while (*(p + cnt)) { cnt ++; }
|
||||
return cnt;
|
||||
};
|
||||
const E *pl = l.c_str ();
|
||||
const E *pr = r.c_str ();
|
||||
while (*pl && is_blank (*pl)) ++ pl;
|
||||
while (*pr && is_blank (*pr)) ++ pr;
|
||||
const E *el = l.c_str () + _local_strlen (l.c_str ());
|
||||
const E *er = r.c_str () + _local_strlen (r.c_str ());
|
||||
while (el > pl && is_blank (*(el - 1))) --el;
|
||||
while (er > pr && is_blank (*(er - 1))) --er;
|
||||
while (pl < el && pr < er)
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*pl) && is_blank (*pr))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pl))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pr))
|
||||
{
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false;
|
||||
++ pl;
|
||||
++ pr;
|
||||
}
|
||||
while (pl < el && is_blank (*pl)) ++ pl;
|
||||
while (pr < er && is_blank (*pr)) ++ pr;
|
||||
return pl == el && pr == er;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> int64_t NormalizeStringCompare (const std::basic_string <E, TR, AL> &l, const std::basic_string <E, TR, AL> &r, bool includemidblank = false)
|
||||
{
|
||||
auto _local_strlen = [] (const E *p) -> size_t {
|
||||
size_t cnt = 0;
|
||||
while (*(p + cnt)) { cnt ++; }
|
||||
return cnt;
|
||||
};
|
||||
const E *pl = l.c_str ();
|
||||
const E *pr = r.c_str ();
|
||||
while (*pl && is_blank (*pl)) ++ pl;
|
||||
while (*pr && is_blank (*pr)) ++ pr;
|
||||
const E *el = l.c_str () + _local_strlen (l.c_str ());
|
||||
const E *er = r.c_str () + _local_strlen (r.c_str ());
|
||||
while (el > pl && is_blank (*(el - 1))) -- el;
|
||||
while (er > pr && is_blank (*(er - 1))) -- er;
|
||||
while (pl < el && pr < er)
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*pl) && is_blank (*pr))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pl))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pr))
|
||||
{
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
E chl = l0km::tolower (*pl);
|
||||
E chr = l0km::tolower (*pr);
|
||||
if (chl != chr) return (int64_t)chl - (int64_t)chr;
|
||||
++ pl;
|
||||
++ pr;
|
||||
}
|
||||
while (pl < el && is_blank (*pl)) ++ pl;
|
||||
while (pr < er && is_blank (*pr)) ++ pr;
|
||||
if (pl == el && pr == er) return 0;
|
||||
if (pl == el) return -1;
|
||||
if (pr == er) return 1;
|
||||
return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr);
|
||||
}
|
||||
template <typename CharT> bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false)
|
||||
{
|
||||
if (!l || !r) return l == r;
|
||||
auto skip_blank = [] (const CharT *&p)
|
||||
{
|
||||
while (*p && is_blank (*p)) ++ p;
|
||||
};
|
||||
const CharT *p1 = l;
|
||||
const CharT *p2 = r;
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
while (*p1 && *p2)
|
||||
{
|
||||
CharT ch1 = l0km::tolower (*p1);
|
||||
CharT ch2 = l0km::tolower (*p2);
|
||||
if (ch1 != ch2) return false;
|
||||
++ p1;
|
||||
++ p2;
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*p1) || is_blank (*p2))
|
||||
{
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
return *p1 == 0 && *p2 == 0;
|
||||
}
|
||||
template <typename CharT> int64_t NormalizeStringCompare (const CharT *l, const CharT *r, bool includemidblank = false)
|
||||
{
|
||||
if (!l || !r) return l ? 1 : (r ? -1 : 0);
|
||||
auto skip_blank = [] (const CharT *&p)
|
||||
{
|
||||
while (*p && is_blank (*p)) ++ p;
|
||||
};
|
||||
const CharT *p1 = l;
|
||||
const CharT *p2 = r;
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
while (*p1 && *p2)
|
||||
{
|
||||
CharT ch1 = l0km::tolower (*p1);
|
||||
CharT ch2 = l0km::tolower (*p2);
|
||||
if (ch1 != ch2) return (ch1 < ch2) ? -1 : 1;
|
||||
++ p1;
|
||||
++ p2;
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*p1) || is_blank (*p2))
|
||||
{
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
if (*p1 == 0 && *p2 == 0) return 0;
|
||||
if (*p1 == 0) return -1;
|
||||
return 1;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> bool IsNormalizeStringEmpty (const std::basic_string <E, TR, AL> &str)
|
||||
{
|
||||
return IsNormalizeStringEquals (str, std::basic_string <E, TR, AL> ());
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> std::basic_string <E, TR, AL> StringTrim (const std::basic_string <E, TR, AL> &str, bool includemidblank = false)
|
||||
{
|
||||
typedef std::basic_string <E, TR, AL> string_type;
|
||||
typedef typename string_type::size_type size_type;
|
||||
if (str.empty ()) return string_type ();
|
||||
size_type first = 0;
|
||||
size_type last = str.size ();
|
||||
while (first < last && is_blank (str [first])) ++first;
|
||||
while (last > first && is_blank (str [last - 1])) --last;
|
||||
if (first == last) return string_type ();
|
||||
string_type result;
|
||||
result.reserve (last - first);
|
||||
bool in_space = false;
|
||||
for (size_type i = first; i < last; ++ i)
|
||||
{
|
||||
if (is_blank (str [i]))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
result.push_back (E (' '));
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (str [i]);
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (str [i]);
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits<E>, typename AL = std::allocator <E>> size_t GetNormalizeStringLength (const std::basic_string <E, TR, AL> &str, bool includemidblank = false)
|
||||
{
|
||||
typedef typename std::basic_string <E, TR, AL>::size_type size_type;
|
||||
if (str.empty ()) return 0;
|
||||
size_type first = 0, last = str.size ();
|
||||
while (first < last && is_blank (str [first])) ++first;
|
||||
while (last > first && is_blank (str [last - 1])) --last;
|
||||
if (first == last) return 0;
|
||||
size_t length = 0;
|
||||
bool in_space = false;
|
||||
for (size_type i = first; i < last; ++i)
|
||||
{
|
||||
if (is_blank (str [i]))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
++ length;
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++ length;
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++ length;
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <typename ct, typename tr = std::char_traits <ct>, typename al = std::allocator <ct>> class basic_nstring: public std::basic_string <ct, tr, al>
|
||||
{
|
||||
bool default_upper = false, default_include_blank_in_str = false;
|
||||
public:
|
||||
using base = std::basic_string <ct, tr, al>;
|
||||
using derive = std::basic_nstring <ct, tr, al>;
|
||||
using typename base::size_type;
|
||||
using typename base::value_type;
|
||||
using base::base;
|
||||
using pstr = ct *;
|
||||
using pcstr = const ct *;
|
||||
basic_nstring (): base (), default_upper (false), default_include_blank_in_str (false) {}
|
||||
basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {}
|
||||
basic_nstring (const base &str): base (str) {}
|
||||
basic_nstring (base &&str): base (std::move (str)) {}
|
||||
basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {}
|
||||
// template <std::size_t N> basic_nstring (const ct (&arr) [N]) : base (arr, N - 1) {}
|
||||
template <typename InputIt> basic_nstring (InputIt first, InputIt last): base (first, last), default_upper (false), default_include_blank_in_str (false) {}
|
||||
bool upper_default () const { return this->default_upper; }
|
||||
bool upper_default (bool value) { return this->default_upper = value; }
|
||||
bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; }
|
||||
bool include_blank_in_str_middle (bool value) { return this->default_include_blank_in_str = value; }
|
||||
base normalize (bool upper, bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, upper, includemidblank);
|
||||
}
|
||||
base normalize (bool upper) const
|
||||
{
|
||||
return this->normalize (upper, default_include_blank_in_str);
|
||||
}
|
||||
base normalize () const { return this->normalize (default_upper); }
|
||||
base upper (bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, true, includemidblank);
|
||||
}
|
||||
base upper () const { return this->upper (default_include_blank_in_str); }
|
||||
base lower (bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, false, includemidblank);
|
||||
}
|
||||
base lower () const { return this->lower (default_include_blank_in_str); }
|
||||
base trim (bool includemidblank) const
|
||||
{
|
||||
return StringTrim <ct, tr, al> (*this, includemidblank);
|
||||
}
|
||||
base trim () const { return this->trim (default_include_blank_in_str); }
|
||||
size_t length (bool includemidblank) const { return GetNormalizeStringLength (*this, includemidblank); }
|
||||
size_t length () const { return length (default_include_blank_in_str); }
|
||||
bool empty () const
|
||||
{
|
||||
return IsNormalizeStringEmpty (*this);
|
||||
}
|
||||
bool equals (const base &another, bool includemidblank) const
|
||||
{
|
||||
return IsNormalizeStringEquals <ct, tr, al> (*this, another, includemidblank);
|
||||
}
|
||||
bool equals (const base &another) const { return equals (another, default_include_blank_in_str); }
|
||||
int64_t compare (const base &another, bool includemidblank) const
|
||||
{
|
||||
return NormalizeStringCompare <ct, tr, al> (*this, another, includemidblank);
|
||||
}
|
||||
int64_t compare (const base &another) const { return compare (another, default_include_blank_in_str); }
|
||||
base &string () { return *this; }
|
||||
base to_string (bool upper, bool includemidblank) const { return this->normalize (upper, includemidblank); }
|
||||
base to_string (bool upper) const { return this->normalize (upper, default_include_blank_in_str); }
|
||||
base to_string () const { return this->normalize (default_upper); }
|
||||
bool operator == (const base &other) const { return equals (other, false); }
|
||||
bool operator != (const base &other) const { return !equals (other, false); }
|
||||
bool operator < (const base &other) const { return compare (other, false) < 0; }
|
||||
bool operator > (const base &other) const { return compare (other, false) > 0; }
|
||||
bool operator <= (const base &other) const { return compare (other, false) <= 0; }
|
||||
bool operator >= (const base &other) const { return compare (other, false) >= 0; }
|
||||
int64_t operator - (const base &other) const { return compare (other, false); }
|
||||
bool operator == (pcstr &other) const { return equals (other, false); }
|
||||
bool operator != (pcstr &other) const { return !equals (other, false); }
|
||||
bool operator < (pcstr &other) const { return compare (other, false) < 0; }
|
||||
bool operator > (pcstr &other) const { return compare (other, false) > 0; }
|
||||
bool operator <= (pcstr &other) const { return compare (other, false) <= 0; }
|
||||
bool operator >= (pcstr &other) const { return compare (other, false) >= 0; }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static bool equals (const std::basic_string <E> &l, const std::basic_string <E> &r, bool remove_mid_blank = false)
|
||||
{
|
||||
return IsNormalizeStringEquals <E, TR, AL> (l, r, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static int64_t compare (const std::basic_string <E> &l, const std::basic_string <E> &r, bool remove_mid_blank = false)
|
||||
{
|
||||
return NormalizeStringCompare <E, TR, AL> (l, r, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_string <E, TR, AL> normalize (const std::basic_string <E> &str, bool to_upper = false, bool remove_mid_blank = false)
|
||||
{
|
||||
return NormalizeString <E, TR, AL> (str, to_upper, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_string <E, TR, AL> trim (const std::basic_string <E> &str, bool remove_mid_blank = false)
|
||||
{
|
||||
return StringTrim <E, TR, AL> (str, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static size_t length (const std::basic_string <E> &str, bool remove_mid_blank = false)
|
||||
{
|
||||
return GetNormalizeStringLength <E, TR, AL> (str, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static bool empty (const std::basic_string <E> &str)
|
||||
{
|
||||
return IsNormalizeStringEmpty <E, TR, AL> (str);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> to_nstring (std::basic_string <E> &str) { return std::basic_nstring <E> (str); }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> toupper (const std::basic_nstring <E, TR, AL> &str) { return l0km::toupper (str); }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> tolower (const std::basic_nstring <E, TR, AL> &str) { return l0km::tolower (str); }
|
||||
};
|
||||
|
||||
typedef basic_nstring <char> nstring;
|
||||
typedef basic_nstring <wchar_t> wnstring;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="pugixml" version="1.15.0" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
typedef struct raii
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
raii (std::function <void ()> pFunc = nullptr): endtask (pFunc) {}
|
||||
~raii () { if (endtask) endtask (); }
|
||||
raii (const raii &) = delete;
|
||||
raii (raii &&) = delete;
|
||||
} destruct;
|
||||
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <WinBase.h>
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include "typestrans.h"
|
||||
#include "module.h"
|
||||
|
||||
// 返回的指针如果非空则一定需要用 free 释放
|
||||
LPWSTR GetRCStringW (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <WCHAR> buf (256);
|
||||
size_t cnt = 0;
|
||||
CopyStringLoop_GetRCStringW:
|
||||
{
|
||||
size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ());
|
||||
if (cnt > 1625) return _wcsdup (buf.data ());
|
||||
if (len >= buf.size () - 1)
|
||||
{
|
||||
buf.resize (buf.size () + 20);
|
||||
cnt ++;
|
||||
goto CopyStringLoop_GetRCStringW;
|
||||
}
|
||||
else return _wcsdup (buf.data ());
|
||||
}
|
||||
}
|
||||
// 返回的指针如果非空则一定需要用 free 释放
|
||||
LPSTR GetRCStringA (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <CHAR> buf (256);
|
||||
size_t cnt = 0;
|
||||
CopyStringLoop_GetRCStringA:
|
||||
{
|
||||
size_t len = LoadStringA (hModule, resID, buf.data (), buf.size ());
|
||||
if (cnt > 1625) return _strdup (buf.data ());
|
||||
if (len >= buf.size () - 1)
|
||||
{
|
||||
buf.resize (buf.size () + 20);
|
||||
cnt ++;
|
||||
goto CopyStringLoop_GetRCStringA;
|
||||
}
|
||||
else return _strdup (buf.data ());
|
||||
}
|
||||
}
|
||||
|
||||
HICON LoadRCIcon (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
return (HICON)LoadImageW (hModule, MAKEINTRESOURCEW (resID), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
|
||||
}
|
||||
HRSRC FindResourceByName (LPCWSTR resourceName, LPCWSTR resourceType, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
return FindResourceW (hModule, resourceName, resourceType);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
#include <string>
|
||||
std::wstring GetRCStringSW (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <WCHAR> buf (256);
|
||||
size_t cnt = 0;
|
||||
CopyStringLoop_GetRCStringSW:
|
||||
{
|
||||
size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ());
|
||||
if (cnt > 1625) return buf.data ();
|
||||
if (len >= buf.size () - 1)
|
||||
{
|
||||
buf.resize (buf.size () + 20);
|
||||
cnt ++;
|
||||
goto CopyStringLoop_GetRCStringSW;
|
||||
}
|
||||
else return buf.data ();
|
||||
}
|
||||
}
|
||||
std::string GetRCStringSA (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <CHAR> buf (256);
|
||||
size_t cnt = 0;
|
||||
CopyStringLoop_GetRCStringSA:
|
||||
{
|
||||
size_t len = LoadStringA (hModule, resID, buf.data (), buf.size ());
|
||||
if (cnt > 1625) return buf.data ();
|
||||
if (len >= buf.size () - 1)
|
||||
{
|
||||
buf.resize (buf.size () + 20);
|
||||
cnt ++;
|
||||
goto CopyStringLoop_GetRCStringSA;
|
||||
}
|
||||
else return buf.data ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined (__cplusplus) && defined (__cplusplus_cli)
|
||||
using namespace System;
|
||||
String ^GetRCStringCli (UINT resID, HMODULE hModule hModule_DefaultParam)
|
||||
{
|
||||
std::vector <WCHAR> buf (256);
|
||||
size_t cnt = 0;
|
||||
CopyStringLoop_GetRCStringCli:
|
||||
{
|
||||
size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ());
|
||||
if (cnt > 1625) return gcnew String (buf.data ());
|
||||
if (len >= buf.size () - 1)
|
||||
{
|
||||
buf.resize (buf.size () + 20);
|
||||
cnt ++;
|
||||
goto CopyStringLoop_GetRCStringCli;
|
||||
}
|
||||
else return gcnew String (buf.data ());
|
||||
}
|
||||
}
|
||||
#define GetRCIntValue(_UINT__resID_) toInt (GetRCStringCli (_UINT__resID_))
|
||||
#define GetRCDoubleValue(_UINT__resID_) toDouble (GetRCStringCli (_UINT__resID_))
|
||||
#define GetRCBoolValue(_UINT__resID_) toBool (GetRCStringCli (_UINT__resID_))
|
||||
#define GetRCDateTimeValue(_UINT__resID_) toDateTime (GetRCStringCli (_UINT__resID_))
|
||||
#define rcString(resID) GetRCStringCli (resID)
|
||||
#define rcInt(resID) GetRCIntValue (resID)
|
||||
#define rcDouble(resID) GetRCDoubleValue (resID)
|
||||
#define rcBool(resID) GetRCBoolValue (resID)
|
||||
#define rcDTime(resID) GetRCDateTimeValue (resID)
|
||||
#define rcIcon(resID) LoadRCIcon (resID)
|
||||
#endif
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 403 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
@@ -0,0 +1,154 @@
|
||||
#pragma once
|
||||
#include <Shlwapi.h>
|
||||
#include "nstring.h"
|
||||
#ifdef __cplusplus
|
||||
#define ptrnull(ptr) (!(ptr))
|
||||
#else
|
||||
#define ptrnull(ptr) ((ptr) == NULL)
|
||||
#endif
|
||||
#define ptrvalid(ptr) (!ptrnull (ptr))
|
||||
// 用于 char * 或 WCHAR * 字符串(结尾为 NULL),判断是否为非空字符串:指针有效且长度大于 0。千万不能是野指针,否则一定会崩溃!
|
||||
#define strvalid(strptr) (ptrvalid (strptr) && *(strptr))
|
||||
// 用于 char * 或 WCHAR * 字符串(结尾为 NULL),判断是否为空字符串:指针为 NULL 或长度为 0。千万不能是野指针,否则一定会崩溃!
|
||||
#define strnull(strptr) (ptrnull (strptr) || !*(strptr))
|
||||
typedef std::wnstring strlabel, StringLabel;
|
||||
std::wstring StringTrim (const std::wstring &str) { return std::wnstring::trim (str); }
|
||||
std::string StringTrim (const std::string &str) { return std::nstring::trim (str); }
|
||||
#define StringToUpper l0km::toupper
|
||||
#define StringToLower l0km::tolower
|
||||
int LabelCompare (const std::wstring &l1, const std::wstring &l2)
|
||||
{
|
||||
return std::wnstring::compare (l1, l2);
|
||||
}
|
||||
int LabelCompare (const std::string &l1, const std::string &l2)
|
||||
{
|
||||
return std::nstring::compare (l1, l2);
|
||||
}
|
||||
bool LabelEqual (const std::wstring &l1, const std::wstring &l2)
|
||||
{
|
||||
return std::wnstring::equals (l1, l2);
|
||||
}
|
||||
bool LabelEqual (const std::string &l1, const std::string &l2)
|
||||
{
|
||||
return std::wnstring::equals (l1, l2);
|
||||
}
|
||||
bool LabelEmpty (const std::wstring &str) { return std::wnstring::empty (str); }
|
||||
bool LabelEmpty (const std::string &str) { return std::nstring::empty (str); }
|
||||
#define LabelNoEmpty(_str_) (!LabelEmpty (_str_))
|
||||
int InStr (const std::string &text, const std::string &keyword, bool ignoreCase = false)
|
||||
{
|
||||
std::string s1, s2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
s1 = StringToUpper (text);
|
||||
s2 = StringToUpper (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = text;
|
||||
s2 = keyword;
|
||||
}
|
||||
const char *found = StrStrIA (s1.c_str (), s2.c_str ());
|
||||
if (!found)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return found - text.c_str ();
|
||||
}
|
||||
int InStr (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false)
|
||||
{
|
||||
std::wstring s1, s2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
s1 = StringToUpper (text);
|
||||
s2 = StringToUpper (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = text;
|
||||
s2 = keyword;
|
||||
}
|
||||
const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ());
|
||||
if (!found)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return found - text.c_str ();
|
||||
}
|
||||
bool StrInclude (const std::string &text, const std::string &keyword, bool ignoreCase = false)
|
||||
{
|
||||
std::string s1, s2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
s1 = StringToUpper (text);
|
||||
s2 = StringToUpper (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = text;
|
||||
s2 = keyword;
|
||||
}
|
||||
const char *found = StrStrIA (s1.c_str (), s2.c_str ());
|
||||
if (!found) return false;
|
||||
return true;
|
||||
}
|
||||
bool StrInclude (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false)
|
||||
{
|
||||
std::wstring s1, s2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
s1 = StringToUpper (text);
|
||||
s2 = StringToUpper (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = text;
|
||||
s2 = keyword;
|
||||
}
|
||||
const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ());
|
||||
if (!found) return false;
|
||||
return true;
|
||||
}
|
||||
// 该函数帮助构成 "<str1>\0<str2>\0" 这种字符串,用于通用对话框中的文件框
|
||||
LPCWSTR strcpynull (LPWSTR dest, LPCWSTR endwith, size_t bufsize)
|
||||
{
|
||||
if (!dest || !endwith || bufsize == 0)
|
||||
return dest;
|
||||
if (dest [0] == L'\0' && bufsize > 1)
|
||||
{
|
||||
dest [1] = L'\0';
|
||||
}
|
||||
size_t pos = 0;
|
||||
while (pos < bufsize - 1)
|
||||
{
|
||||
if (dest [pos] == L'\0' && dest [pos + 1] == L'\0')
|
||||
{
|
||||
if (dest [0]) pos ++;
|
||||
break;
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
size_t i = 0;
|
||||
while (pos < bufsize - 1 && endwith [i] != L'\0')
|
||||
{
|
||||
dest [pos ++] = endwith [i ++];
|
||||
}
|
||||
if (pos < bufsize)
|
||||
{
|
||||
dest [pos] = L'\0';
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
// 取文本左边,注意:长度指的是文本字符数,比如“ch”的长度为2
|
||||
std::wstring GetStringLeft (const std::wstring &str, size_t length)
|
||||
{
|
||||
std::vector <WCHAR> buf (length + 1);
|
||||
lstrcpynW (buf.data (), str.c_str (), length + 1);
|
||||
return buf.data ();
|
||||
}
|
||||
// 取文本右边
|
||||
std::wstring GetStringRight (const std::wstring &str, size_t length)
|
||||
{
|
||||
if (length >= str.length ()) return str;
|
||||
return str.substr (str.length () - length, length).c_str ();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP)
|
||||
{
|
||||
if (str.empty ()) return std::wstring ();
|
||||
int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0);
|
||||
if (len == 0) return std::wstring ();
|
||||
std::wstring wstr (len - 1, L'\0');
|
||||
MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len);
|
||||
return wstr;
|
||||
}
|
||||
std::string WStringToString (const std::wstring &wstr, UINT codePage = CP_ACP)
|
||||
{
|
||||
if (wstr.empty ()) return std::string ();
|
||||
int len = WideCharToMultiByte (codePage, 0, wstr.c_str (), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (len == 0) return std::string ();
|
||||
std::string str (len - 1, '\0');
|
||||
WideCharToMultiByte (codePage, 0, wstr.c_str (), -1, &str [0], len, nullptr, nullptr);
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <dwmapi.h>
|
||||
|
||||
bool IsHighContrastEnabled ()
|
||||
{
|
||||
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
|
||||
if (SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0;
|
||||
return false;
|
||||
}
|
||||
enum class HighContrastTheme
|
||||
{
|
||||
None,
|
||||
Black,
|
||||
White,
|
||||
Other
|
||||
};
|
||||
HighContrastTheme GetHighContrastTheme ()
|
||||
{
|
||||
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
|
||||
if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return HighContrastTheme::None;
|
||||
if (!(hc.dwFlags & HCF_HIGHCONTRASTON)) return HighContrastTheme::None;
|
||||
COLORREF bgColor = GetSysColor (COLOR_WINDOW);
|
||||
COLORREF textColor = GetSysColor (COLOR_WINDOWTEXT);
|
||||
int brightnessBg = (GetRValue (bgColor) + GetGValue (bgColor) + GetBValue (bgColor)) / 3;
|
||||
int brightnessText = (GetRValue (textColor) + GetGValue (textColor) + GetBValue (textColor)) / 3;
|
||||
if (brightnessBg < brightnessText) return HighContrastTheme::Black;
|
||||
else if (brightnessBg > brightnessText) return HighContrastTheme::White;
|
||||
else return HighContrastTheme::Other;
|
||||
}
|
||||
int GetDPI ()
|
||||
{
|
||||
HDC hDC = GetDC (NULL);
|
||||
int DPI_A = (int)(((double)GetDeviceCaps (hDC, 118) / (double)GetDeviceCaps (hDC, 8)) * 100);
|
||||
int DPI_B = (int)(((double)GetDeviceCaps (hDC, 88) / 96) * 100);
|
||||
ReleaseDC (NULL, hDC);
|
||||
if (DPI_A == 100) return DPI_B;
|
||||
else if (DPI_B == 100) return DPI_A;
|
||||
else if (DPI_A == DPI_B) return DPI_A;
|
||||
else return 0;
|
||||
}
|
||||
int GetScreenWidth () { return GetSystemMetrics (SM_CXSCREEN); }
|
||||
int GetScreenHeight () { return GetSystemMetrics (SM_CYSCREEN); }
|
||||
System::Drawing::Color GetDwmThemeColor ()
|
||||
{
|
||||
DWORD color = 0;
|
||||
BOOL opaqueBlend = FALSE;
|
||||
// 调用 DwmGetColorizationColor 获取 Aero 颜色
|
||||
HRESULT hr = DwmGetColorizationColor (&color, &opaqueBlend);
|
||||
if (SUCCEEDED (hr)) {
|
||||
BYTE r = (BYTE)((color & 0x00FF0000) >> 16);
|
||||
BYTE g = (BYTE)((color & 0x0000FF00) >> 8);
|
||||
BYTE b = (BYTE)(color & 0x000000FF);
|
||||
return System::Drawing::Color::FromArgb (r, g, b);
|
||||
}
|
||||
else {
|
||||
// 如果获取失败,返回默认颜色
|
||||
return System::Drawing::Color::FromArgb (0, 120, 215);
|
||||
}
|
||||
}
|
||||
String ^ColorToHtml (System::Drawing::Color color)
|
||||
{
|
||||
return String::Format ("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
|
||||
}
|
||||
System::Drawing::Color StringToColor (String ^colorStr)
|
||||
{
|
||||
using Color = System::Drawing::Color;
|
||||
using Regex = System::Text::RegularExpressions::Regex;
|
||||
auto Clamp = [] (int value, int min, int max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
};
|
||||
String ^normalized = colorStr->Trim ()->ToLower ();
|
||||
if (normalized == "transparent") return Color::Transparent;
|
||||
if (Color::FromName (normalized).IsKnownColor)
|
||||
{
|
||||
return Color::FromName (normalized);
|
||||
}
|
||||
if (normalized->StartsWith ("#"))
|
||||
{
|
||||
String^ hex = normalized->Substring (1);
|
||||
if (hex->Length == 3 || hex->Length == 4)
|
||||
{
|
||||
hex = String::Concat (
|
||||
hex [0].ToString () + hex [0],
|
||||
hex [1].ToString () + hex [1],
|
||||
hex [2].ToString () + hex [2],
|
||||
(hex->Length == 4) ? (hex [3].ToString () + hex [3]) : ""
|
||||
);
|
||||
}
|
||||
uint32_t argb = Convert::ToUInt32 (hex, 16);
|
||||
switch (hex->Length)
|
||||
{
|
||||
case 6: return Color::FromArgb (
|
||||
0xFF,
|
||||
(argb >> 16) & 0xFF,
|
||||
(argb >> 8) & 0xFF,
|
||||
argb & 0xFF
|
||||
);
|
||||
case 8: return Color::FromArgb (
|
||||
(argb >> 24) & 0xFF,
|
||||
(argb >> 16) & 0xFF,
|
||||
(argb >> 8) & 0xFF,
|
||||
argb & 0xFF
|
||||
);
|
||||
default: throw gcnew ArgumentException ("Invalid hex color format");
|
||||
}
|
||||
}
|
||||
System::Text::RegularExpressions::Match ^match = Regex::Match (normalized,
|
||||
"^(rgba?)\\s*\\(\\s*(\\d+%?)\\s*,\\s*(\\d+%?)\\s*,\\s*(\\d+%?)\\s*,?\\s*([\\d.]+%?)?\\s*\\)$");
|
||||
if (match->Success)
|
||||
{
|
||||
auto GetComponent = [&] (String^ val) -> int
|
||||
{
|
||||
if (val->EndsWith ("%"))
|
||||
{
|
||||
float percent = float::Parse (val->TrimEnd ('%')) / 100.0f;
|
||||
return Clamp ((int)Math::Round (percent * 255), 0, 255);
|
||||
}
|
||||
return Clamp (int::Parse (val), 0, 255);
|
||||
};
|
||||
int r = GetComponent (match->Groups [2]->Value);
|
||||
int g = GetComponent (match->Groups [3]->Value);
|
||||
int b = GetComponent (match->Groups [4]->Value);
|
||||
if (match->Groups [1]->Value == "rgba")
|
||||
{
|
||||
String^ alphaVal = match->Groups [5]->Value;
|
||||
int a = 255;
|
||||
if (alphaVal->EndsWith ("%"))
|
||||
{
|
||||
float percent = float::Parse (alphaVal->TrimEnd ('%')) / 100.0f;
|
||||
a = Clamp ((int)Math::Round (percent * 255), 0, 255);
|
||||
}
|
||||
else if (!String::IsNullOrEmpty (alphaVal))
|
||||
{
|
||||
a = Clamp ((int)Math::Round (float::Parse (alphaVal) * 255), 0, 255);
|
||||
}
|
||||
return Color::FromArgb (a, r, g, b);
|
||||
}
|
||||
return Color::FromArgb (r, g, b);
|
||||
}
|
||||
//throw gcnew ArgumentException ("Unsupported color format: " + colorStr);
|
||||
return Color::Transparent;
|
||||
}
|
||||
bool IsAppInDarkMode ()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwValue;
|
||||
if (RegOpenKeyEx (HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD dwSize = sizeof (dwValue);
|
||||
if (RegQueryValueEx (hKey, L"AppsUseLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey (hKey);
|
||||
return dwValue == 0;
|
||||
}
|
||||
RegCloseKey (hKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
#pragma once
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#ifdef __cplusplus
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
unsigned _wtou (const wchar_t *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str)
|
||||
{
|
||||
swscanf (str, L"%u", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
unsigned long _wtoul (const wchar_t *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str)
|
||||
{
|
||||
swscanf (str, L"%lu", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
unsigned long long _wtou64 (const wchar_t *str)
|
||||
{
|
||||
unsigned long long value = 0;
|
||||
if (str)
|
||||
{
|
||||
swscanf (str, L"%llu", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
double _wtod (const wchar_t *str)
|
||||
{
|
||||
if (!str || !*str) return 0.0; // 避免空指针或空字符串
|
||||
double value = 0.0;
|
||||
if (swscanf (str, L"%lg", &value) == 1)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return 0.0; // 解析失败时返回 0.0
|
||||
}
|
||||
unsigned atou (const char *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str)
|
||||
{
|
||||
sscanf (str, "%u", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
unsigned long atoul (const char *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str)
|
||||
{
|
||||
sscanf (str, "%lu", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
unsigned long long atou64 (const char *str)
|
||||
{
|
||||
unsigned long long value = 0;
|
||||
if (str)
|
||||
{
|
||||
sscanf (str, "%llu", &value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
double atod (const char *str)
|
||||
{
|
||||
if (!str || !*str) return 0.0; // 避免空指针或空字符串
|
||||
double value = 0.0;
|
||||
if (sscanf (str, "%lg", &value) == 1)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return 0.0; // 解析失败时返回 0.0
|
||||
}
|
||||
int8_t atoi8 (const char *str)
|
||||
{
|
||||
int value = 0;
|
||||
if (str) sscanf (str, "%d", &value);
|
||||
return (int8_t)value;
|
||||
}
|
||||
int16_t atoi16 (const char *str)
|
||||
{
|
||||
int value = 0;
|
||||
if (str) sscanf (str, "%d", &value);
|
||||
return (int16_t)value;
|
||||
}
|
||||
int32_t atoi32 (const char *str)
|
||||
{
|
||||
int32_t value = 0;
|
||||
if (str) sscanf (str, "%d", &value);
|
||||
return value;
|
||||
}
|
||||
uint8_t atoui8 (const char *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str) sscanf (str, "%u", &value);
|
||||
return (uint8_t)value;
|
||||
}
|
||||
uint16_t atoui16 (const char *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str) sscanf (str, "%u", &value);
|
||||
return (uint16_t)value;
|
||||
}
|
||||
uint32_t atoui32 (const char *str)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
if (str) sscanf (str, "%u", &value);
|
||||
return value;
|
||||
}
|
||||
int8_t _wtoi8 (const wchar_t *str)
|
||||
{
|
||||
int value = 0;
|
||||
if (str) swscanf (str, L"%d", &value);
|
||||
return (int8_t)value;
|
||||
}
|
||||
int16_t _wtoi16 (const wchar_t *str)
|
||||
{
|
||||
int value = 0;
|
||||
if (str) swscanf (str, L"%d", &value);
|
||||
return (int16_t)value;
|
||||
}
|
||||
int32_t _wtoi32 (const wchar_t *str)
|
||||
{
|
||||
int32_t value = 0;
|
||||
if (str) swscanf (str, L"%d", &value);
|
||||
return value;
|
||||
}
|
||||
uint8_t _wtoui8 (const wchar_t *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str) swscanf (str, L"%u", &value);
|
||||
return (uint8_t)value;
|
||||
}
|
||||
uint16_t _wtoui16 (const wchar_t *str)
|
||||
{
|
||||
unsigned value = 0;
|
||||
if (str) swscanf (str, L"%u", &value);
|
||||
return (uint16_t)value;
|
||||
}
|
||||
uint32_t _wtoui32 (const wchar_t *str)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
if (str) swscanf (str, L"%u", &value);
|
||||
return value;
|
||||
}
|
||||
int64_t atoi64 (const char *str)
|
||||
{
|
||||
int64_t value = 0;
|
||||
if (str) sscanf (str, "%lld", &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
EXTERN_C int StringToIntA (const char *str) { return atoi (str); }
|
||||
EXTERN_C int StringToIntW (const WCHAR *str) { return _wtoi (str); }
|
||||
EXTERN_C unsigned StringToUnsignedA (const char *str) { return atou (str); }
|
||||
EXTERN_C unsigned StringToUnsignedW (const WCHAR *str) { return _wtou (str); }
|
||||
EXTERN_C bool StringToBoolA (const char *str)
|
||||
{
|
||||
char buf [32] = {0};
|
||||
strcpy (buf, str);
|
||||
for (int cnt = 0; buf [cnt]; cnt ++) buf [cnt] = tolower (buf [cnt]);
|
||||
return !strcmp (buf, "true") ||
|
||||
!strcmp (buf, "yes") ||
|
||||
!strcmp (buf, "ok") ||
|
||||
!strcmp (buf, "sure") ||
|
||||
!strcmp (buf, "okay") ||
|
||||
!strcmp (buf, "zhen") ||
|
||||
!strcmp (buf, "真");
|
||||
}
|
||||
EXTERN_C bool StringToBoolW (const WCHAR *str)
|
||||
{
|
||||
WCHAR buf [32] = {0};
|
||||
lstrcpyW (buf, str);
|
||||
for (int cnt = 0; buf [cnt]; cnt ++) buf [cnt] = tolower (buf [cnt]);
|
||||
return !lstrcmpW (buf, L"true") ||
|
||||
!lstrcmpW (buf, L"yes") ||
|
||||
!lstrcmpW (buf, L"ok") ||
|
||||
!lstrcmpW (buf, L"sure") ||
|
||||
!lstrcmpW (buf, L"okay") ||
|
||||
!lstrcmpW (buf, L"zhen") ||
|
||||
!lstrcmpW (buf, L"真");
|
||||
}
|
||||
EXTERN_C long StringToLongA (const char *str) { return atol (str); }
|
||||
EXTERN_C long StringToLongW (const WCHAR *str) { return _wtol (str); }
|
||||
EXTERN_C unsigned long StringToULongA (const char *str) { return atoul (str); }
|
||||
EXTERN_C unsigned long StringToULongW (const WCHAR *str) { return _wtoul (str); }
|
||||
EXTERN_C long long StringToLongLongA (const char *str) { return atoll (str); }
|
||||
EXTERN_C long long StringToLongLongW (const WCHAR *str) { return _wtoll (str); }
|
||||
EXTERN_C unsigned long long StringToULongLongA (const char *str) { return atou64 (str); }
|
||||
EXTERN_C unsigned long long StringToULongLongW (const WCHAR *str) { return _wtou64 (str); }
|
||||
EXTERN_C float StringToFloatA (const char *str) { return atof (str); }
|
||||
EXTERN_C float StringToFloatW (const WCHAR *str) { return _wtof (str); }
|
||||
EXTERN_C double StringToDoubleA (const char *str) { return atod (str); }
|
||||
EXTERN_C double StringToDoubleW (const WCHAR *str) { return _wtod (str); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
int StringToInt (LPCSTR str) { return StringToIntA (str); }
|
||||
int StringToInt (LPCWSTR str) { return StringToIntW (str); }
|
||||
unsigned StringToUnsigned (LPCSTR str) { return StringToUnsignedA (str); }
|
||||
unsigned StringToUnsigned (LPCWSTR str) { return StringToUnsignedW (str); }
|
||||
bool StringToBool (LPCSTR str) { return StringToBoolA (str); }
|
||||
bool StringToBool (LPCWSTR str) { return StringToBoolW (str); }
|
||||
long StringToLong (LPCSTR str) { return StringToLongA (str); }
|
||||
long StringToLong (LPCWSTR str) { return StringToLongW (str); }
|
||||
unsigned long StringToULong (LPCSTR str) { return StringToULongA (str); }
|
||||
unsigned long StringToULong (LPCWSTR str) { return StringToULongW (str); }
|
||||
long long StringToLongLong (LPCSTR str) { return StringToLongLongA (str); }
|
||||
long long StringToLongLong (LPCWSTR str) { return StringToLongLongW (str); }
|
||||
unsigned long long StringToULongLong (LPCSTR str) { return StringToULongLongA (str); }
|
||||
unsigned long long StringToULongLong (LPCWSTR str) { return StringToULongLongW (str); }
|
||||
float StringToFloat (LPCSTR str) { return StringToFloatA (str); }
|
||||
float StringToFloat (LPCWSTR str) { return StringToFloatW (str); }
|
||||
double StringToDouble (LPCSTR str) { return StringToDoubleA (str); }
|
||||
double StringToDouble (LPCWSTR str) { return StringToDoubleW (str); }
|
||||
#endif
|
||||
|
||||
#if defined (__cplusplus) && defined (__cplusplus_cli)
|
||||
using namespace System;
|
||||
#define toInt(_String_Managed_Object_) Int32::Parse (_String_Managed_Object_)
|
||||
#define objToInt(_Object_Managed_) Convert::ToInt32 (_Object_Managed_)
|
||||
#define toDouble(_String_Managed_Object_) Double::Parse (_String_Managed_Object_)
|
||||
#define objToDouble(_Object_Managed_) Convert::ToDouble (_Object_Managed_)
|
||||
#define toBool(_String_Managed_Object_) Boolean::Parse (_String_Managed_Object_)
|
||||
bool objToBool (Object ^result)
|
||||
{
|
||||
if (!result) return false;
|
||||
try
|
||||
{
|
||||
String ^strValue = safe_cast <String ^> (result);
|
||||
return (strValue->ToLower () == "on");
|
||||
}
|
||||
catch (InvalidCastException ^)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert::ToBoolean (result);
|
||||
}
|
||||
catch (InvalidCastException ^)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#define toDateTime(_String_Managed_Object_) DateTime::Parse (_String_Managed_Object_)
|
||||
#define toDateTimeObj(_Object_Managed_) Convert::ToDateTime (_Object_Managed_)
|
||||
#define objectToType(_Object_Managed_, _Type_Name_) Convert::To##_Type_Name_ (_Object_Managed_)
|
||||
#endif
|
||||
@@ -0,0 +1,322 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <pugiconfig.hpp>
|
||||
#include <pugixml.hpp>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <cstdio>
|
||||
#include "strcmp.h"
|
||||
#include "dynarr.h"
|
||||
#include "themeinfo.h"
|
||||
#include "nstring.h"
|
||||
|
||||
class vemanifest
|
||||
{
|
||||
public:
|
||||
enum class TextColor { dark = 0x000000, light = 0xFFFFFF };
|
||||
vemanifest (): available (false) {}
|
||||
vemanifest (LPCSTR filename): available (false) { create (filename); }
|
||||
vemanifest (const std::string &filename): available (false) { create (filename); }
|
||||
vemanifest (LPCWSTR filename): available (false) { create (filename); }
|
||||
vemanifest (const std::wstring &filename): available (false) { create (filename); }
|
||||
vemanifest (std::ifstream &stream): available (false) { create (stream); }
|
||||
vemanifest (std::fstream &stream): available (false) { create (stream); }
|
||||
vemanifest (FILE *file): available (false) { create (file); }
|
||||
~vemanifest () { destroy (); }
|
||||
bool create (LPCSTR filename)
|
||||
{
|
||||
destroy ();
|
||||
pugi::xml_parse_result result = doc.load_file (filename);
|
||||
available = result; return available;
|
||||
}
|
||||
bool create (const std::string &filename) { return create (filename.c_str ()); }
|
||||
bool create (LPCWSTR filename)
|
||||
{
|
||||
destroy ();
|
||||
std::wstring ws (filename);
|
||||
std::string s = to_utf8 (ws);
|
||||
pugi::xml_parse_result result = doc.load_file (s.c_str ());
|
||||
available = result; return available;
|
||||
}
|
||||
bool create (const std::wstring &filename) { return create (filename.c_str ()); }
|
||||
bool create (std::ifstream &stream)
|
||||
{
|
||||
destroy ();
|
||||
std::stringstream buffer; buffer << stream.rdbuf ();
|
||||
std::string content = buffer.str ();
|
||||
pugi::xml_parse_result result = doc.load_string (content.c_str ());
|
||||
available = result; return available;
|
||||
}
|
||||
bool create (std::fstream &stream)
|
||||
{
|
||||
destroy ();
|
||||
std::stringstream buffer; buffer << stream.rdbuf ();
|
||||
std::string content = buffer.str ();
|
||||
pugi::xml_parse_result result = doc.load_string (content.c_str ());
|
||||
available = result; return available;
|
||||
}
|
||||
bool create (FILE *file)
|
||||
{
|
||||
destroy ();
|
||||
if (!file) { return false; }
|
||||
fseek (file, 0, SEEK_END);
|
||||
long length = ftell (file);
|
||||
fseek (file, 0, SEEK_SET);
|
||||
std::string content (length, '\0');
|
||||
fread (&content [0], 1, length, file);
|
||||
pugi::xml_parse_result result = doc.load_string (content.c_str ());
|
||||
available = result; return available;
|
||||
}
|
||||
void destroy () { if (!available) return; doc.reset (); available = false; }
|
||||
bool valid () const { return available; }
|
||||
std::string display_name (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
return visual ? visual.attribute ("DisplayName").as_string () : "";
|
||||
}
|
||||
std::wstring display_name (const std::wstring &id = L"App") const { return pugi::as_wide (this->display_name (pugi::as_utf8 (id))); }
|
||||
std::string logo (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return "";
|
||||
std::string logo = visual.attribute ("Logo").as_string ();
|
||||
return !logo.empty () ? logo : visual.attribute ("Square150x150Logo").as_string ();
|
||||
}
|
||||
std::wstring logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->logo (pugi::as_utf8 (id))); }
|
||||
std::string small_logo (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return "";
|
||||
std::string smallLogo = visual.attribute ("SmallLogo").as_string ();
|
||||
return !smallLogo.empty () ? smallLogo : visual.attribute ("Square70x70Logo").as_string ();
|
||||
}
|
||||
std::wstring small_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->small_logo (pugi::as_utf8 (id))); }
|
||||
TextColor foreground_text (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return TextColor::dark;
|
||||
std::string fg = visual.attribute ("ForegroundText").as_string ();
|
||||
return (fg == "light") ? TextColor::light : TextColor::dark;
|
||||
}
|
||||
TextColor foreground_text (const std::wstring &id = L"App") const { return (this->foreground_text (pugi::as_utf8 (id))); }
|
||||
std::string lnk_32x32_logo (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
return visual ? visual.attribute ("Lnk32x32Logo").as_string () : "";
|
||||
}
|
||||
std::wstring lnk_32x32_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->lnk_32x32_logo (pugi::as_utf8 (id))); }
|
||||
std::string item_display_logo (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return "";
|
||||
std::string itemLogo = visual.attribute ("ItemDisplayLogo").as_string ();
|
||||
if (!itemLogo.empty ()) return itemLogo;
|
||||
itemLogo = visual.attribute ("Lnk32x32Logo").as_string ();
|
||||
return !itemLogo.empty () ? itemLogo : visual.attribute ("Square44x44Logo").as_string ();
|
||||
}
|
||||
std::wstring item_display_logo (const std::wstring &id = L"App") const { return pugi::as_wide (this->item_display_logo (pugi::as_utf8 (id))); }
|
||||
bool show_name_on_tile (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
return visual ? (std::string (visual.attribute ("ShowNameOnSquare150x150Logo").as_string ()) == "on") : false;
|
||||
}
|
||||
bool show_name_on_tile (const std::wstring &id = L"App") const { return (this->show_name_on_tile (pugi::as_utf8 (id))); }
|
||||
std::string background_color (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
return visual ? visual.attribute ("BackgroundColor").as_string () : "";
|
||||
}
|
||||
std::wstring background_color (const std::wstring &id = L"App") const { return pugi::as_wide (this->background_color (pugi::as_utf8 (id))); }
|
||||
std::string splash_screen_image (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return "";
|
||||
pugi::xml_node splash = visual.child ("SplashScreen");
|
||||
return splash ? splash.attribute ("Image").as_string () : "";
|
||||
}
|
||||
std::wstring splash_screen_image (const std::wstring &id = L"App") const { return pugi::as_wide (this->splash_screen_image (pugi::as_utf8 (id))); }
|
||||
std::string splash_screen_backgroundcolor (const std::string &id = "App") const
|
||||
{
|
||||
pugi::xml_node visual = visual_element_node (id);
|
||||
if (!visual) return "";
|
||||
pugi::xml_node splash = visual.child ("SplashScreen");
|
||||
std::string bg = splash ? splash.attribute ("BackgroundColor").as_string () : "";
|
||||
return !bg.empty () ? bg : visual.attribute ("BackgroundColor").as_string ();
|
||||
}
|
||||
std::wstring splash_screen_backgroundcolor (const std::wstring &id = L"App") const { return pugi::as_wide (this->splash_screen_backgroundcolor (pugi::as_utf8 (id))); }
|
||||
bool is_appid_exists (const std::string &id) const
|
||||
{
|
||||
pugi::xml_node root = doc.document_element ();
|
||||
std::string rootName = root.name ();
|
||||
if (rootName == "Applications")
|
||||
{
|
||||
for (pugi::xml_node app : root.children ("Application"))
|
||||
{
|
||||
pugi::xml_attribute attr = app.attribute ("Id");
|
||||
if (attr && LabelEqual (std::string (attr.value ()), id)) return true;
|
||||
}
|
||||
return pugi::xml_node ();
|
||||
}
|
||||
else if (rootName == "Application")
|
||||
{
|
||||
pugi::xml_attribute attr = root.attribute ("Id");
|
||||
if (attr && LabelEqual (std::string (attr.value ()), id)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_appid_exists (const std::wstring &id) const { return this->is_appid_exists (pugi::as_utf8 (id)); }
|
||||
size_t app_ids (std::vector <std::string> &output) const
|
||||
{
|
||||
if (!&output) return 0;
|
||||
output.clear ();
|
||||
pugi::xml_node root = doc.document_element ();
|
||||
std::string rootName = root.name ();
|
||||
if (rootName == "Applications")
|
||||
{
|
||||
for (pugi::xml_node app : root.children ("Application"))
|
||||
{
|
||||
pugi::xml_attribute attr = app.attribute ("Id");
|
||||
if (attr)
|
||||
{
|
||||
LPCSTR lp = attr.value ();
|
||||
if (lp) push_unique (output, std::string (lp));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rootName == "Application")
|
||||
{
|
||||
pugi::xml_attribute attr = root.attribute ("Id");
|
||||
if (attr)
|
||||
{
|
||||
if (attr)
|
||||
{
|
||||
LPCSTR lp = attr.value ();
|
||||
if (lp) push_unique (output, std::string (lp));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!output.size ()) push_unique (output, std::string ("App"));
|
||||
return output.size ();
|
||||
}
|
||||
size_t app_ids (std::vector <std::wstring> &output) const
|
||||
{
|
||||
if (!&output) return 0;
|
||||
output.clear ();
|
||||
pugi::xml_node root = doc.document_element ();
|
||||
std::string rootName = root.name ();
|
||||
if (rootName == "Applications")
|
||||
{
|
||||
for (pugi::xml_node app : root.children ("Application"))
|
||||
{
|
||||
pugi::xml_attribute attr = app.attribute ("Id");
|
||||
if (attr)
|
||||
{
|
||||
LPCSTR lp = attr.value ();
|
||||
if (lp) push_unique (output, pugi::as_wide (lp));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rootName == "Application")
|
||||
{
|
||||
pugi::xml_attribute attr = root.attribute ("Id");
|
||||
if (attr)
|
||||
{
|
||||
if (attr)
|
||||
{
|
||||
LPCSTR lp = attr.value ();
|
||||
if (lp) push_unique (output, pugi::as_wide (lp));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!output.size ()) push_unique (output, std::wstring (L"App"));
|
||||
return output.size ();
|
||||
}
|
||||
private:
|
||||
pugi::xml_document doc;
|
||||
bool available;
|
||||
// 根据 id 查找 VisualElements 节点:若根节点为 <Applications>,遍历所有 <Application> 查找其 <VisualElements> 节点中属性 Id 等于 id;若根节点为 <Application>,直接返回其 <VisualElements>
|
||||
pugi::xml_node visual_element_node (const std::string &id) const
|
||||
{
|
||||
pugi::xml_node root = doc.document_element ();
|
||||
std::string rootName = root.name ();
|
||||
if (rootName == "Applications")
|
||||
{
|
||||
for (pugi::xml_node app : root.children ("Application"))
|
||||
{
|
||||
pugi::xml_attribute attr = app.attribute ("Id");
|
||||
if (attr && LabelEqual (std::string (attr.value ()), id))
|
||||
{
|
||||
pugi::xml_node visual = app.child ("VisualElements");
|
||||
if (visual) return visual;
|
||||
}
|
||||
}
|
||||
return pugi::xml_node ();
|
||||
}
|
||||
else if (rootName == "Application") return root.child ("VisualElements");
|
||||
return pugi::xml_node ();
|
||||
}
|
||||
std::string to_utf8 (const std::wstring &wstr) const
|
||||
{
|
||||
std::wstring_convert <std::codecvt_utf8 <wchar_t>> conv;
|
||||
return conv.to_bytes (wstr);
|
||||
}
|
||||
};
|
||||
|
||||
class resxmldoc
|
||||
{
|
||||
private:
|
||||
std::wstring filepath;
|
||||
pugi::xml_document doc;
|
||||
bool available = false;
|
||||
std::string to_utf8 (const std::wstring &wstr) const
|
||||
{
|
||||
std::wstring_convert <std::codecvt_utf8 <wchar_t>> conv;
|
||||
return conv.to_bytes (wstr);
|
||||
}
|
||||
public:
|
||||
resxmldoc (const std::wstring &xmlpath) { create (xmlpath); }
|
||||
void destroy () { if (!available) return; doc.reset (); available = false; }
|
||||
~resxmldoc () { destroy (); }
|
||||
bool create (const std::wstring &xmlpath)
|
||||
{
|
||||
destroy ();
|
||||
std::wstring ws (filepath = xmlpath);
|
||||
std::string s = to_utf8 (ws);
|
||||
pugi::xml_parse_result result = doc.load_file (s.c_str ());
|
||||
available = result; return available;
|
||||
}
|
||||
std::string get (const std::string &id) const
|
||||
{
|
||||
auto root = doc.first_child ();
|
||||
auto nodes = root.children ();
|
||||
for (auto it : nodes)
|
||||
{
|
||||
if (IsNormalizeStringEquals (std::string (it.attribute ("id").as_string ()), id))
|
||||
{
|
||||
auto scales = it.children ();
|
||||
std::map <int, std::string> s_v;
|
||||
for (auto it_s : scales)
|
||||
{
|
||||
std::string dpi = it_s.attribute ("dpi").as_string ();
|
||||
if (IsNormalizeStringEquals (dpi.c_str (), "default")) { s_v [0] = it_s.text ().get (); }
|
||||
else
|
||||
{
|
||||
try { s_v [it_s.attribute ("dpi").as_int ()] = it_s.text ().get (); }
|
||||
catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
std::wstring get (const std::wstring &id) const { return pugi::as_wide (get (WStringToString (id)).c_str ()); }
|
||||
std::wstring operator [] (const std::wstring &id) const { return get (id); }
|
||||
std::wstring operator [] (const std::wstring &id) { return get (id); }
|
||||
std::string operator [] (const std::string &id) const { return get (id); }
|
||||
std::string operator [] (const std::string &id) { return get (id); }
|
||||
};
|
||||
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
typedef uint64_t UINT64;
|
||||
typedef int64_t INT64;
|
||||
typedef uint16_t UINT16;
|
||||
typedef struct version
|
||||
{
|
||||
UINT16 major = 0, minor = 0, build = 0, revision = 0;
|
||||
version (UINT64 value):
|
||||
major ((value >> 0x30) & 0xFFFF), minor ((value >> 0x20) & 0xFFFF),
|
||||
build ((value >> 0x10) & 0xFFFF), revision ((value) & 0xFFFF) {}
|
||||
version (UINT16 major, UINT16 minor, UINT16 build, UINT16 revision):
|
||||
major (major), minor (minor), build (build), revision (revision) {}
|
||||
version (const std::wstring &verstr) { this->interpret (verstr); }
|
||||
version (const std::string &verstr) { this->interpret (verstr); }
|
||||
version () {}
|
||||
version (const version &other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version (version &&other) noexcept: major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version &operator = (const version &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (version &&other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (UINT64 value) { this->data (value); return *this; }
|
||||
UINT64 data () const { return (((UINT64)major) << 48) | (((UINT64)minor) << 32) | (((UINT64)build) << 16) | ((UINT64)revision); }
|
||||
UINT64 data (UINT64 value)
|
||||
{
|
||||
major = (value >> 48) & 0xFFFF;
|
||||
minor = (value >> 32) & 0xFFFF;
|
||||
build = (value >> 16) & 0xFFFF;
|
||||
revision = value & 0xFFFF;
|
||||
return value;
|
||||
}
|
||||
std::wstring stringifyw () const
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << major << L'.' << minor << L'.' << build << L'.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
std::string stringify () const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << major << '.' << minor << '.' << build << '.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
version &interpret (const std::wstring &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = _wtoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = _wtoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = _wtoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = _wtoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
version &interpret (const std::string &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = atoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = atoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = atoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = atoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
bool empty () const { return *(UINT64 *)this == 0; }
|
||||
friend bool operator == (const version &l, const version &r) { return *(UINT64 *)&l == *(UINT64 *)&r; }
|
||||
friend bool operator == (const version &l, const UINT64 &r) { return l.data () == r; }
|
||||
friend bool operator == (const UINT64 &r, const version &l) { return l.data () == r; }
|
||||
friend bool operator < (const version &l, const version &r) { return l.data () < r.data (); }
|
||||
friend bool operator > (const version &l, const version &r) { return l.data () > r.data (); }
|
||||
friend bool operator <= (const version &l, const version &r) { return l.data () <= r.data (); }
|
||||
friend bool operator >= (const version &l, const version &r) { return l.data () >= r.data (); }
|
||||
friend bool operator != (const version &l, const version &r) { return *(UINT64 *)&l != *(UINT64 *)&r; }
|
||||
explicit operator bool () const { return !this->empty (); }
|
||||
bool operator ! () { return this->empty (); }
|
||||
friend std::ostream &operator << (std::ostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
friend std::wostream &operator << (std::wostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
bool equals (const version &r) const { return *this == r; }
|
||||
INT64 compare (const version &r) const { return this->data () - r.data (); }
|
||||
static version parse (const std::wstring &value) { return version (value); }
|
||||
static version parse (const std::string &value) { return version (value); }
|
||||
static std::wstring stringifyw (const version &v) { return v.stringifyw (); }
|
||||
static std::string stringify (const version &v) { return v.stringify (); }
|
||||
static bool equals (const version &l, const version &r) { return l == r; }
|
||||
static INT64 compare (const version &l, const version &r) { return l.data () - r.data (); }
|
||||
static version decode (UINT64 value) { return version (value); }
|
||||
static UINT64 encode (const version &v) { return v.data (); }
|
||||
protected:
|
||||
template <typename StringType> std::vector <StringType> split (const StringType &str, typename StringType::value_type delimiter1 = '.', typename StringType::value_type delimiter2 = ',')
|
||||
{
|
||||
std::vector <StringType> result;
|
||||
std::basic_stringstream<typename StringType::value_type> ss (str);
|
||||
StringType segment;
|
||||
while (std::getline (ss, segment, delimiter1))
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = segment.find (delimiter2)) != StringType::npos)
|
||||
{
|
||||
result.push_back (segment.substr (0, pos));
|
||||
segment.erase (0, pos + 1);
|
||||
}
|
||||
if (!segment.empty ()) result.push_back (segment);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} Version;
|
||||
Reference in New Issue
Block a user