mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Update Shell and Fix Bugs
This commit is contained in:
@@ -34,6 +34,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings\settin
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reslib", "reslib\reslib.vcxproj", "{3AE2A022-ED83-41F1-948A-12A7593CBD00}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reslib", "reslib\reslib.vcxproj", "{3AE2A022-ED83-41F1-948A-12A7593CBD00}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shortcut", "shortcut\shortcut.vcxproj", "{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{798ED492-EECE-457D-8FD8-129DA93CE126} = {798ED492-EECE-457D-8FD8-129DA93CE126}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -132,6 +137,16 @@ Global
|
|||||||
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x64.Build.0 = Release|x64
|
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x64.Build.0 = Release|x64
|
||||||
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x86.ActiveCfg = Release|Win32
|
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x86.Build.0 = Release|Win32
|
{3AE2A022-ED83-41F1-948A-12A7593CBD00}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Release|x64.Build.0 = Release|x64
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Binary file not shown.
@@ -4,13 +4,6 @@
|
|||||||
#include "nstring.h"
|
#include "nstring.h"
|
||||||
#include "filepath.h"
|
#include "filepath.h"
|
||||||
#include <combaseapi.h>
|
#include <combaseapi.h>
|
||||||
#include <rapidjson\document.h>
|
|
||||||
#include <rapidjson\writer.h>
|
|
||||||
#include <rapidjson\stringbuffer.h>
|
|
||||||
#include <codecvt>
|
|
||||||
#include <locale>
|
|
||||||
#include "mpstr.h"
|
|
||||||
#include "strcode.h"
|
|
||||||
using namespace System;
|
using namespace System;
|
||||||
using namespace System::Runtime::InteropServices;
|
using namespace System::Runtime::InteropServices;
|
||||||
|
|
||||||
@@ -94,297 +87,3 @@ public ref class _I_String
|
|||||||
return Format (pih, newargs);
|
return Format (pih, newargs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
String ^StringArrayToJson (array <String ^> ^strs)
|
|
||||||
{
|
|
||||||
using namespace rapidjson;
|
|
||||||
Document doc;
|
|
||||||
doc.SetArray ();
|
|
||||||
Document::AllocatorType &allocator = doc.GetAllocator ();
|
|
||||||
for each (String ^s in strs)
|
|
||||||
{
|
|
||||||
std::wstring ws = MPStringToStdW (s); // String^ → std::wstring
|
|
||||||
std::string utf8 = WStringToString (ws, CP_UTF8); // 简易宽转 UTF-8,如需更严谨可用 WideCharToMultiByte
|
|
||||||
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
|
||||||
}
|
|
||||||
StringBuffer buffer;
|
|
||||||
Writer <StringBuffer> writer (buffer);
|
|
||||||
doc.Accept (writer);
|
|
||||||
std::string json = buffer.GetString ();
|
|
||||||
std::wstring wjson = StringToWString (json, CP_UTF8);
|
|
||||||
return CStringToMPString (wjson);
|
|
||||||
}
|
|
||||||
std::wstring StringArrayToJson (const std::vector<std::wstring>& arr)
|
|
||||||
{
|
|
||||||
using namespace rapidjson;
|
|
||||||
Document doc;
|
|
||||||
doc.SetArray ();
|
|
||||||
auto &allocator = doc.GetAllocator ();
|
|
||||||
for (const auto &ws : arr)
|
|
||||||
{
|
|
||||||
std::string utf8 = WStringToUtf8 (ws);
|
|
||||||
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
|
||||||
}
|
|
||||||
StringBuffer buffer;
|
|
||||||
Writer <StringBuffer> writer (buffer);
|
|
||||||
doc.Accept (writer);
|
|
||||||
return Utf8ToWString (buffer.GetString ());
|
|
||||||
}
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Path
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
property String ^Current
|
|
||||||
{
|
|
||||||
String ^get () { return CStringToMPString (GetCurrentDirectoryW ()); }
|
|
||||||
void set (String ^dir) { SetCurrentDirectoryW (MPStringToStdW (dir).c_str ()); }
|
|
||||||
}
|
|
||||||
property String ^Program { String ^get () { return CStringToMPString (GetCurrentProgramPathW ()); } }
|
|
||||||
property String ^Root { String ^get () { return CStringToMPString (GetFileDirectoryW (GetCurrentProgramPathW ())); }}
|
|
||||||
String ^Combine (String ^l, String ^r) { return CStringToMPString (CombinePath (MPStringToStdW (l), MPStringToStdW (r))); }
|
|
||||||
String ^GetName (String ^path)
|
|
||||||
{
|
|
||||||
std::wstring cpath = MPStringToStdW (path);
|
|
||||||
LPWSTR lp = PathFindFileNameW (cpath.c_str ());
|
|
||||||
return lp ? CStringToMPString (lp) : String::Empty;
|
|
||||||
}
|
|
||||||
String ^GetDirectory (String ^path) { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }
|
|
||||||
String ^GetDir (String ^path) { return GetDirectory (path); }
|
|
||||||
bool Exist (String ^path) { return IsPathExists (MPStringToStdW (path)); }
|
|
||||||
bool FileExist (String ^filepath) { return IsFileExists (MPStringToStdW (filepath)); }
|
|
||||||
bool DirectoryExist (String ^dirpath) { return IsDirectoryExists (MPStringToStdW (dirpath)); }
|
|
||||||
bool DirExist (String ^dirpath) { return DirectoryExist (dirpath); }
|
|
||||||
String ^GetEnvironmentString (String ^str) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (str))); }
|
|
||||||
bool ValidName (String ^filename) { return IsValidWindowsName (MPStringToStdW (filename)); }
|
|
||||||
// 过滤器用"\"分隔每个类型
|
|
||||||
String ^EnumFilesToJson (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumDirsToJson (String ^dir, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumSubDirsToJson (String ^dir, bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumFiles (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumDirs (String ^dir, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumSubDirs (String ^dir, bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
String ^CommonPrefix (String ^path1, String ^path2) { return CStringToMPString (PathCommonPrefix (MPStringToStdW (path1), MPStringToStdW (path2))); }
|
|
||||||
String ^EnsureDirSlash (String ^dir) { return CStringToMPString (EnsureTrailingSlash (MPStringToStdW (dir))); }
|
|
||||||
String ^Normalize (String ^path) { return CStringToMPString (NormalizePath (MPStringToStdW (path))); }
|
|
||||||
String ^FullPathName (String ^path) { return CStringToMPString (GetFullPathName (MPStringToStdW (path))); }
|
|
||||||
String ^FullPath (String ^path) { return FullPathName (path); }
|
|
||||||
String ^Expand (String ^path) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (path))); }
|
|
||||||
bool PEquals (String ^l, String ^r) { return PathEquals (MPStringToStdW (l), MPStringToStdW (r)); }
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Entry
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
String ^path;
|
|
||||||
public:
|
|
||||||
_I_Entry (String ^path): path (path) {}
|
|
||||||
_I_Entry (): path (String::Empty) {}
|
|
||||||
property String ^Path { String ^get () { return path; } void set (String ^file) { path = file; } }
|
|
||||||
property String ^Name
|
|
||||||
{
|
|
||||||
String ^get ()
|
|
||||||
{
|
|
||||||
std::wstring file = MPStringToStdW (path);
|
|
||||||
LPWSTR lpstr = PathFindFileNameW (file.c_str ());
|
|
||||||
return lpstr ? CStringToMPString (lpstr) : String::Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^Directory { String ^get () { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }}
|
|
||||||
property String ^Root { String ^get () { return Directory; }}
|
|
||||||
property bool Exist { virtual bool get () { return IsPathExists (MPStringToStdW (path)); }}
|
|
||||||
property String ^Uri
|
|
||||||
{
|
|
||||||
String ^get ()
|
|
||||||
{
|
|
||||||
using namespace System;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto uri = gcnew System::Uri (System::IO::Path::GetFullPath (path));
|
|
||||||
auto uriText = uri->AbsoluteUri;
|
|
||||||
return uriText;
|
|
||||||
}
|
|
||||||
catch (...) { return String::Empty; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^FullPath { String ^get () { return System::IO::Path::GetFullPath (path); }}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_File: public _I_Entry
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
System::Text::Encoding ^lastEncoding;
|
|
||||||
public:
|
|
||||||
_I_File (String ^filepath): _I_Entry (filepath) {}
|
|
||||||
_I_File (): _I_Entry (String::Empty) {}
|
|
||||||
String ^Get ()
|
|
||||||
{
|
|
||||||
using namespace System::IO;
|
|
||||||
if (String::IsNullOrEmpty (path)) return String::Empty;
|
|
||||||
FileStream ^fs = nullptr;
|
|
||||||
StreamReader ^sr = nullptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fs = gcnew FileStream (
|
|
||||||
path,
|
|
||||||
FileMode::OpenOrCreate,
|
|
||||||
FileAccess::ReadWrite,
|
|
||||||
FileShare::ReadWrite
|
|
||||||
);
|
|
||||||
sr = gcnew StreamReader (fs, Encoding::UTF8, true);
|
|
||||||
String ^text = sr->ReadToEnd ();
|
|
||||||
auto lastEncoding = sr->CurrentEncoding;
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sr) delete sr;
|
|
||||||
if (fs) delete fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Set (String ^content)
|
|
||||||
{
|
|
||||||
using namespace System::IO;
|
|
||||||
if (String::IsNullOrEmpty (path)) return;
|
|
||||||
Encoding ^enc = lastEncoding ? lastEncoding : Encoding::UTF8;
|
|
||||||
FileStream ^fs = nullptr;
|
|
||||||
StreamWriter ^sw = nullptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fs = gcnew FileStream (
|
|
||||||
path,
|
|
||||||
FileMode::Create,
|
|
||||||
FileAccess::ReadWrite,
|
|
||||||
FileShare::ReadWrite
|
|
||||||
);
|
|
||||||
sw = gcnew StreamWriter (fs, enc);
|
|
||||||
sw->Write (content);
|
|
||||||
sw->Flush ();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sw) delete sw;
|
|
||||||
if (fs) delete fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^Content
|
|
||||||
{
|
|
||||||
String ^get () { return Get (); }
|
|
||||||
void set (String ^value) { Set (value); }
|
|
||||||
}
|
|
||||||
property bool Exist { bool get () override { return IsFileExists (MPStringToStdW (path)); }}
|
|
||||||
property String ^FilePath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; }}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Directory: public _I_Entry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_I_Directory (String ^dirpath): _I_Entry (dirpath) {}
|
|
||||||
_I_Directory (_I_Entry ^file): _I_Entry (file->Directory) {}
|
|
||||||
_I_Directory (): _I_Entry (String::Empty) {}
|
|
||||||
property String ^DirectoryPath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; } }
|
|
||||||
property String ^DirPath { String ^get () { return this->DirectoryPath; } void set (String ^value) { this->DirectoryPath = value; } }
|
|
||||||
property bool Exist { bool get () override { return IsDirectoryExists (MPStringToStdW (path)); }}
|
|
||||||
String ^EnumFilesToJson (String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumDirsToJson (bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumSubDirsToJson (bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumFiles (String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumDirs (bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumSubDirs (bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Storage
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
_I_Path ^path = gcnew _I_Path ();
|
|
||||||
public:
|
|
||||||
property _I_Path ^Path { _I_Path ^get () { return path; }}
|
|
||||||
_I_File ^GetFile (String ^path) { return gcnew _I_File (path); }
|
|
||||||
_I_Directory ^GetDirectory (String ^path) { return gcnew _I_Directory (path); }
|
|
||||||
_I_Directory ^GetDir (String ^path) { return GetDirectory (path); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
@@ -869,3 +869,333 @@ bool PathEquals (const std::wstring &path1, const std::wstring &path2)
|
|||||||
PathCanonicalizeW (buf2.data (), path2.c_str ());
|
PathCanonicalizeW (buf2.data (), path2.c_str ());
|
||||||
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
|
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
|
||||||
}
|
}
|
||||||
|
#ifdef __cplusplus_cli
|
||||||
|
#include <rapidjson\document.h>
|
||||||
|
#include <rapidjson\writer.h>
|
||||||
|
#include <rapidjson\stringbuffer.h>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
|
#include <ShlObj.h>
|
||||||
|
#include <combaseapi.h>
|
||||||
|
#include "mpstr.h"
|
||||||
|
#include "strcode.h"
|
||||||
|
using namespace System;
|
||||||
|
using namespace System::Runtime::InteropServices;
|
||||||
|
String ^StringArrayToJson (array <String ^> ^strs)
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
Document doc;
|
||||||
|
doc.SetArray ();
|
||||||
|
Document::AllocatorType &allocator = doc.GetAllocator ();
|
||||||
|
for each (String ^s in strs)
|
||||||
|
{
|
||||||
|
std::wstring ws = MPStringToStdW (s); // String^ → std::wstring
|
||||||
|
std::string utf8 = WStringToString (ws, CP_UTF8); // 简易宽转 UTF-8,如需更严谨可用 WideCharToMultiByte
|
||||||
|
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
||||||
|
}
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer <StringBuffer> writer (buffer);
|
||||||
|
doc.Accept (writer);
|
||||||
|
std::string json = buffer.GetString ();
|
||||||
|
std::wstring wjson = StringToWString (json, CP_UTF8);
|
||||||
|
return CStringToMPString (wjson);
|
||||||
|
}
|
||||||
|
std::wstring StringArrayToJson (const std::vector<std::wstring>& arr)
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
Document doc;
|
||||||
|
doc.SetArray ();
|
||||||
|
auto &allocator = doc.GetAllocator ();
|
||||||
|
for (const auto &ws : arr)
|
||||||
|
{
|
||||||
|
std::string utf8 = WStringToUtf8 (ws);
|
||||||
|
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
||||||
|
}
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer <StringBuffer> writer (buffer);
|
||||||
|
doc.Accept (writer);
|
||||||
|
return Utf8ToWString (buffer.GetString ());
|
||||||
|
}
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Path
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
property String ^Current
|
||||||
|
{
|
||||||
|
String ^get () { return CStringToMPString (GetCurrentDirectoryW ()); }
|
||||||
|
void set (String ^dir) { SetCurrentDirectoryW (MPStringToStdW (dir).c_str ()); }
|
||||||
|
}
|
||||||
|
property String ^Program { String ^get () { return CStringToMPString (GetCurrentProgramPathW ()); } }
|
||||||
|
property String ^Root { String ^get () { return CStringToMPString (GetFileDirectoryW (GetCurrentProgramPathW ())); }}
|
||||||
|
String ^Combine (String ^l, String ^r) { return CStringToMPString (CombinePath (MPStringToStdW (l), MPStringToStdW (r))); }
|
||||||
|
String ^GetName (String ^path)
|
||||||
|
{
|
||||||
|
std::wstring cpath = MPStringToStdW (path);
|
||||||
|
LPWSTR lp = PathFindFileNameW (cpath.c_str ());
|
||||||
|
return lp ? CStringToMPString (lp) : String::Empty;
|
||||||
|
}
|
||||||
|
String ^GetDirectory (String ^path) { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }
|
||||||
|
String ^GetDir (String ^path) { return GetDirectory (path); }
|
||||||
|
bool Exist (String ^path) { return IsPathExists (MPStringToStdW (path)); }
|
||||||
|
bool FileExist (String ^filepath) { return IsFileExists (MPStringToStdW (filepath)); }
|
||||||
|
bool DirectoryExist (String ^dirpath) { return IsDirectoryExists (MPStringToStdW (dirpath)); }
|
||||||
|
bool DirExist (String ^dirpath) { return DirectoryExist (dirpath); }
|
||||||
|
String ^GetEnvironmentString (String ^str) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (str))); }
|
||||||
|
bool ValidName (String ^filename) { return IsValidWindowsName (MPStringToStdW (filename)); }
|
||||||
|
// 过滤器用"\"分隔每个类型
|
||||||
|
String ^EnumFilesToJson (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumDirsToJson (String ^dir, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumSubDirsToJson (String ^dir, bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumFiles (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumDirs (String ^dir, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumSubDirs (String ^dir, bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
String ^CommonPrefix (String ^path1, String ^path2) { return CStringToMPString (PathCommonPrefix (MPStringToStdW (path1), MPStringToStdW (path2))); }
|
||||||
|
String ^EnsureDirSlash (String ^dir) { return CStringToMPString (EnsureTrailingSlash (MPStringToStdW (dir))); }
|
||||||
|
String ^Normalize (String ^path) { return CStringToMPString (NormalizePath (MPStringToStdW (path))); }
|
||||||
|
String ^FullPathName (String ^path) { return CStringToMPString (GetFullPathName (MPStringToStdW (path))); }
|
||||||
|
String ^FullPath (String ^path) { return FullPathName (path); }
|
||||||
|
String ^Expand (String ^path) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (path))); }
|
||||||
|
String ^GetFolder (int csidl)
|
||||||
|
{
|
||||||
|
WCHAR buf [1024] = {0};
|
||||||
|
HRESULT hr = SHGetFolderPathW (NULL, csidl, NULL, 0, buf);
|
||||||
|
if (SUCCEEDED (hr)) return CStringToMPString (buf);
|
||||||
|
else return String::Empty;
|
||||||
|
}
|
||||||
|
String ^KnownFolder (String ^guidString)
|
||||||
|
{
|
||||||
|
if (String::IsNullOrWhiteSpace (guidString)) return String::Empty;
|
||||||
|
std::wstring wguid = MPStringToStdW (guidString);
|
||||||
|
KNOWNFOLDERID kfid;
|
||||||
|
HRESULT hr = CLSIDFromString (wguid.c_str (), &kfid);
|
||||||
|
if (FAILED (hr)) return String::Empty;
|
||||||
|
PWSTR path = nullptr;
|
||||||
|
hr = SHGetKnownFolderPath (kfid, 0, NULL, &path);
|
||||||
|
if (FAILED (hr) || path == nullptr) return L"";
|
||||||
|
std::wstring result (path ? path : L"");
|
||||||
|
if (path) CoTaskMemFree (path);
|
||||||
|
return CStringToMPString (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PEquals (String ^l, String ^r) { return PathEquals (MPStringToStdW (l), MPStringToStdW (r)); }
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Entry
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
String ^path;
|
||||||
|
public:
|
||||||
|
_I_Entry (String ^path): path (path) {}
|
||||||
|
_I_Entry (): path (String::Empty) {}
|
||||||
|
property String ^Path { String ^get () { return path; } void set (String ^file) { path = file; } }
|
||||||
|
property String ^Name
|
||||||
|
{
|
||||||
|
String ^get ()
|
||||||
|
{
|
||||||
|
std::wstring file = MPStringToStdW (path);
|
||||||
|
LPWSTR lpstr = PathFindFileNameW (file.c_str ());
|
||||||
|
return lpstr ? CStringToMPString (lpstr) : String::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^Directory { String ^get () { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }}
|
||||||
|
property String ^Root { String ^get () { return Directory; }}
|
||||||
|
property bool Exist { virtual bool get () { return IsPathExists (MPStringToStdW (path)); }}
|
||||||
|
property String ^Uri
|
||||||
|
{
|
||||||
|
String ^get ()
|
||||||
|
{
|
||||||
|
using namespace System;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto uri = gcnew System::Uri (System::IO::Path::GetFullPath (path));
|
||||||
|
auto uriText = uri->AbsoluteUri;
|
||||||
|
return uriText;
|
||||||
|
}
|
||||||
|
catch (...) { return String::Empty; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^FullPath { String ^get () { return System::IO::Path::GetFullPath (path); }}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_File: public _I_Entry
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
System::Text::Encoding ^lastEncoding;
|
||||||
|
public:
|
||||||
|
_I_File (String ^filepath): _I_Entry (filepath) {}
|
||||||
|
_I_File (): _I_Entry (String::Empty) {}
|
||||||
|
String ^Get ()
|
||||||
|
{
|
||||||
|
using namespace System::IO;
|
||||||
|
if (String::IsNullOrEmpty (path)) return String::Empty;
|
||||||
|
FileStream ^fs = nullptr;
|
||||||
|
StreamReader ^sr = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fs = gcnew FileStream (
|
||||||
|
path,
|
||||||
|
FileMode::OpenOrCreate,
|
||||||
|
FileAccess::ReadWrite,
|
||||||
|
FileShare::ReadWrite
|
||||||
|
);
|
||||||
|
sr = gcnew StreamReader (fs, Encoding::UTF8, true);
|
||||||
|
String ^text = sr->ReadToEnd ();
|
||||||
|
auto lastEncoding = sr->CurrentEncoding;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (sr) delete sr;
|
||||||
|
if (fs) delete fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Set (String ^content)
|
||||||
|
{
|
||||||
|
using namespace System::IO;
|
||||||
|
if (String::IsNullOrEmpty (path)) return;
|
||||||
|
Encoding ^enc = lastEncoding ? lastEncoding : Encoding::UTF8;
|
||||||
|
FileStream ^fs = nullptr;
|
||||||
|
StreamWriter ^sw = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fs = gcnew FileStream (
|
||||||
|
path,
|
||||||
|
FileMode::Create,
|
||||||
|
FileAccess::ReadWrite,
|
||||||
|
FileShare::ReadWrite
|
||||||
|
);
|
||||||
|
sw = gcnew StreamWriter (fs, enc);
|
||||||
|
sw->Write (content);
|
||||||
|
sw->Flush ();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (sw) delete sw;
|
||||||
|
if (fs) delete fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^Content
|
||||||
|
{
|
||||||
|
String ^get () { return Get (); }
|
||||||
|
void set (String ^value) { Set (value); }
|
||||||
|
}
|
||||||
|
property bool Exist { bool get () override { return IsFileExists (MPStringToStdW (path)); }}
|
||||||
|
property String ^FilePath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; }}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Directory: public _I_Entry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_I_Directory (String ^dirpath): _I_Entry (dirpath) {}
|
||||||
|
_I_Directory (_I_Entry ^file): _I_Entry (file->Directory) {}
|
||||||
|
_I_Directory (): _I_Entry (String::Empty) {}
|
||||||
|
property String ^DirectoryPath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; } }
|
||||||
|
property String ^DirPath { String ^get () { return this->DirectoryPath; } void set (String ^value) { this->DirectoryPath = value; } }
|
||||||
|
property bool Exist { bool get () override { return IsDirectoryExists (MPStringToStdW (path)); }}
|
||||||
|
String ^EnumFilesToJson (String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumDirsToJson (bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumSubDirsToJson (bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumFiles (String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumDirs (bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumSubDirs (bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Storage
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
_I_Path ^path = gcnew _I_Path ();
|
||||||
|
public:
|
||||||
|
property _I_Path ^Path { _I_Path ^get () { return path; }}
|
||||||
|
_I_File ^GetFile (String ^path) { return gcnew _I_File (path); }
|
||||||
|
_I_Directory ^GetDirectory (String ^path) { return gcnew _I_Directory (path); }
|
||||||
|
_I_Directory ^GetDir (String ^path) { return GetDirectory (path); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <msclr/marshal_cppstd.h>
|
#include <msclr/marshal_cppstd.h>
|
||||||
#include <ShObjIdl.h>
|
#include <ShObjIdl.h>
|
||||||
|
#include <ShlObj.h> // KNOWNFOLDERID, SHGetKnownFolderPath
|
||||||
|
#include <commdlg.h> // OPENFILENAME
|
||||||
|
#include <comdef.h> // _com_error
|
||||||
#include <MsHTML.h>
|
#include <MsHTML.h>
|
||||||
#include <ExDisp.h>
|
#include <ExDisp.h>
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6084
others/Autosave/autosave_2025-12-03_08-51-59.suf
Normal file
6084
others/Autosave/autosave_2025-12-03_08-51-59.suf
Normal file
File diff suppressed because it is too large
Load Diff
6042
others/Autosave/autosave_2025-12-03_09-08-40.suf
Normal file
6042
others/Autosave/autosave_2025-12-03_09-08-40.suf
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6038
others/Autosave/autosave_2025-12-03_09-17-05.suf
Normal file
6038
others/Autosave/autosave_2025-12-03_09-17-05.suf
Normal file
File diff suppressed because it is too large
Load Diff
6192
others/Autosave/autosave_2025-12-06_19-20-13.suf
Normal file
6192
others/Autosave/autosave_2025-12-06_19-20-13.suf
Normal file
File diff suppressed because it is too large
Load Diff
6192
others/Autosave/autosave_2025-12-07_13-30-34.suf
Normal file
6192
others/Autosave/autosave_2025-12-07_13-30-34.suf
Normal file
File diff suppressed because it is too large
Load Diff
6192
others/Autosave/autosave_2025-12-07_15-15-06.suf
Normal file
6192
others/Autosave/autosave_2025-12-07_15-15-06.suf
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
others/runtime.exe
Normal file
BIN
others/runtime.exe
Normal file
Binary file not shown.
BIN
pkgmgr/pkgmgr.rc
BIN
pkgmgr/pkgmgr.rc
Binary file not shown.
BIN
reslib/reslib.rc
BIN
reslib/reslib.rc
Binary file not shown.
Binary file not shown.
@@ -2,6 +2,16 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include "mpstr.h"
|
#include "mpstr.h"
|
||||||
#include "nstring.h"
|
#include "nstring.h"
|
||||||
|
#include "filepath.h"
|
||||||
|
#include <combaseapi.h>
|
||||||
|
#include <rapidjson\document.h>
|
||||||
|
#include <rapidjson\writer.h>
|
||||||
|
#include <rapidjson\stringbuffer.h>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
|
#include <ShlObj.h>
|
||||||
|
#include "mpstr.h"
|
||||||
|
#include "strcode.h"
|
||||||
using namespace System;
|
using namespace System;
|
||||||
using namespace System::Runtime::InteropServices;
|
using namespace System::Runtime::InteropServices;
|
||||||
|
|
||||||
@@ -84,4 +94,320 @@ public ref class _I_String
|
|||||||
}
|
}
|
||||||
return Format (pih, newargs);
|
return Format (pih, newargs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
String ^StringArrayToJson (array <String ^> ^strs)
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
Document doc;
|
||||||
|
doc.SetArray ();
|
||||||
|
Document::AllocatorType &allocator = doc.GetAllocator ();
|
||||||
|
for each (String ^s in strs)
|
||||||
|
{
|
||||||
|
std::wstring ws = MPStringToStdW (s); // String^ → std::wstring
|
||||||
|
std::string utf8 = WStringToString (ws, CP_UTF8); // 简易宽转 UTF-8,如需更严谨可用 WideCharToMultiByte
|
||||||
|
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
||||||
|
}
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer <StringBuffer> writer (buffer);
|
||||||
|
doc.Accept (writer);
|
||||||
|
std::string json = buffer.GetString ();
|
||||||
|
std::wstring wjson = StringToWString (json, CP_UTF8);
|
||||||
|
return CStringToMPString (wjson);
|
||||||
|
}
|
||||||
|
std::wstring StringArrayToJson (const std::vector<std::wstring>& arr)
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
Document doc;
|
||||||
|
doc.SetArray ();
|
||||||
|
auto &allocator = doc.GetAllocator ();
|
||||||
|
for (const auto &ws : arr)
|
||||||
|
{
|
||||||
|
std::string utf8 = WStringToUtf8 (ws);
|
||||||
|
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
||||||
|
}
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer <StringBuffer> writer (buffer);
|
||||||
|
doc.Accept (writer);
|
||||||
|
return Utf8ToWString (buffer.GetString ());
|
||||||
|
}
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Path
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
property String ^Current
|
||||||
|
{
|
||||||
|
String ^get () { return CStringToMPString (GetCurrentDirectoryW ()); }
|
||||||
|
void set (String ^dir) { SetCurrentDirectoryW (MPStringToStdW (dir).c_str ()); }
|
||||||
|
}
|
||||||
|
property String ^Program { String ^get () { return CStringToMPString (GetCurrentProgramPathW ()); } }
|
||||||
|
property String ^Root { String ^get () { return CStringToMPString (GetFileDirectoryW (GetCurrentProgramPathW ())); }}
|
||||||
|
String ^Combine (String ^l, String ^r) { return CStringToMPString (CombinePath (MPStringToStdW (l), MPStringToStdW (r))); }
|
||||||
|
String ^GetName (String ^path)
|
||||||
|
{
|
||||||
|
std::wstring cpath = MPStringToStdW (path);
|
||||||
|
LPWSTR lp = PathFindFileNameW (cpath.c_str ());
|
||||||
|
return lp ? CStringToMPString (lp) : String::Empty;
|
||||||
|
}
|
||||||
|
String ^GetDirectory (String ^path) { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }
|
||||||
|
String ^GetDir (String ^path) { return GetDirectory (path); }
|
||||||
|
bool Exist (String ^path) { return IsPathExists (MPStringToStdW (path)); }
|
||||||
|
bool FileExist (String ^filepath) { return IsFileExists (MPStringToStdW (filepath)); }
|
||||||
|
bool DirectoryExist (String ^dirpath) { return IsDirectoryExists (MPStringToStdW (dirpath)); }
|
||||||
|
bool DirExist (String ^dirpath) { return DirectoryExist (dirpath); }
|
||||||
|
String ^GetEnvironmentString (String ^str) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (str))); }
|
||||||
|
bool ValidName (String ^filename) { return IsValidWindowsName (MPStringToStdW (filename)); }
|
||||||
|
// 过滤器用"\"分隔每个类型
|
||||||
|
String ^EnumFilesToJson (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumDirsToJson (String ^dir, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumSubDirsToJson (String ^dir, bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumFiles (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumDirs (String ^dir, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumSubDirs (String ^dir, bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
String ^CommonPrefix (String ^path1, String ^path2) { return CStringToMPString (PathCommonPrefix (MPStringToStdW (path1), MPStringToStdW (path2))); }
|
||||||
|
String ^EnsureDirSlash (String ^dir) { return CStringToMPString (EnsureTrailingSlash (MPStringToStdW (dir))); }
|
||||||
|
String ^Normalize (String ^path) { return CStringToMPString (NormalizePath (MPStringToStdW (path))); }
|
||||||
|
String ^FullPathName (String ^path) { return CStringToMPString (GetFullPathName (MPStringToStdW (path))); }
|
||||||
|
String ^FullPath (String ^path) { return FullPathName (path); }
|
||||||
|
String ^Expand (String ^path) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (path))); }
|
||||||
|
String ^GetFolder (int csidl)
|
||||||
|
{
|
||||||
|
WCHAR buf [1024] = {0};
|
||||||
|
HRESULT hr = SHGetFolderPathW (NULL, csidl, NULL, 0, buf);
|
||||||
|
if (SUCCEEDED (hr)) return CStringToMPString (buf);
|
||||||
|
else return String::Empty;
|
||||||
|
}
|
||||||
|
String ^KnownFolder (String ^guidString)
|
||||||
|
{
|
||||||
|
if (String::IsNullOrWhiteSpace (guidString)) return String::Empty;
|
||||||
|
std::wstring wguid = MPStringToStdW (guidString);
|
||||||
|
KNOWNFOLDERID kfid;
|
||||||
|
HRESULT hr = CLSIDFromString (wguid.c_str (), &kfid);
|
||||||
|
if (FAILED (hr)) return String::Empty;
|
||||||
|
PWSTR path = nullptr;
|
||||||
|
hr = SHGetKnownFolderPath (kfid, 0, NULL, &path);
|
||||||
|
if (FAILED (hr) || path == nullptr) return L"";
|
||||||
|
std::wstring result (path ? path : L"");
|
||||||
|
if (path) CoTaskMemFree (path);
|
||||||
|
return CStringToMPString (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PEquals (String ^l, String ^r) { return PathEquals (MPStringToStdW (l), MPStringToStdW (r)); }
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Entry
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
String ^path;
|
||||||
|
public:
|
||||||
|
_I_Entry (String ^path): path (path) {}
|
||||||
|
_I_Entry (): path (String::Empty) {}
|
||||||
|
property String ^Path { String ^get () { return path; } void set (String ^file) { path = file; } }
|
||||||
|
property String ^Name
|
||||||
|
{
|
||||||
|
String ^get ()
|
||||||
|
{
|
||||||
|
std::wstring file = MPStringToStdW (path);
|
||||||
|
LPWSTR lpstr = PathFindFileNameW (file.c_str ());
|
||||||
|
return lpstr ? CStringToMPString (lpstr) : String::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^Directory { String ^get () { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }}
|
||||||
|
property String ^Root { String ^get () { return Directory; }}
|
||||||
|
property bool Exist { virtual bool get () { return IsPathExists (MPStringToStdW (path)); }}
|
||||||
|
property String ^Uri
|
||||||
|
{
|
||||||
|
String ^get ()
|
||||||
|
{
|
||||||
|
using namespace System;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto uri = gcnew System::Uri (System::IO::Path::GetFullPath (path));
|
||||||
|
auto uriText = uri->AbsoluteUri;
|
||||||
|
return uriText;
|
||||||
|
}
|
||||||
|
catch (...) { return String::Empty; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^FullPath { String ^get () { return System::IO::Path::GetFullPath (path); }}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_File: public _I_Entry
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
System::Text::Encoding ^lastEncoding;
|
||||||
|
public:
|
||||||
|
_I_File (String ^filepath): _I_Entry (filepath) {}
|
||||||
|
_I_File (): _I_Entry (String::Empty) {}
|
||||||
|
String ^Get ()
|
||||||
|
{
|
||||||
|
using namespace System::IO;
|
||||||
|
if (String::IsNullOrEmpty (path)) return String::Empty;
|
||||||
|
FileStream ^fs = nullptr;
|
||||||
|
StreamReader ^sr = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fs = gcnew FileStream (
|
||||||
|
path,
|
||||||
|
FileMode::OpenOrCreate,
|
||||||
|
FileAccess::ReadWrite,
|
||||||
|
FileShare::ReadWrite
|
||||||
|
);
|
||||||
|
sr = gcnew StreamReader (fs, Encoding::UTF8, true);
|
||||||
|
String ^text = sr->ReadToEnd ();
|
||||||
|
auto lastEncoding = sr->CurrentEncoding;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (sr) delete sr;
|
||||||
|
if (fs) delete fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Set (String ^content)
|
||||||
|
{
|
||||||
|
using namespace System::IO;
|
||||||
|
if (String::IsNullOrEmpty (path)) return;
|
||||||
|
Encoding ^enc = lastEncoding ? lastEncoding : Encoding::UTF8;
|
||||||
|
FileStream ^fs = nullptr;
|
||||||
|
StreamWriter ^sw = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fs = gcnew FileStream (
|
||||||
|
path,
|
||||||
|
FileMode::Create,
|
||||||
|
FileAccess::ReadWrite,
|
||||||
|
FileShare::ReadWrite
|
||||||
|
);
|
||||||
|
sw = gcnew StreamWriter (fs, enc);
|
||||||
|
sw->Write (content);
|
||||||
|
sw->Flush ();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (sw) delete sw;
|
||||||
|
if (fs) delete fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property String ^Content
|
||||||
|
{
|
||||||
|
String ^get () { return Get (); }
|
||||||
|
void set (String ^value) { Set (value); }
|
||||||
|
}
|
||||||
|
property bool Exist { bool get () override { return IsFileExists (MPStringToStdW (path)); }}
|
||||||
|
property String ^FilePath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; }}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Directory: public _I_Entry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_I_Directory (String ^dirpath): _I_Entry (dirpath) {}
|
||||||
|
_I_Directory (_I_Entry ^file): _I_Entry (file->Directory) {}
|
||||||
|
_I_Directory (): _I_Entry (String::Empty) {}
|
||||||
|
property String ^DirectoryPath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; } }
|
||||||
|
property String ^DirPath { String ^get () { return this->DirectoryPath; } void set (String ^value) { this->DirectoryPath = value; } }
|
||||||
|
property bool Exist { bool get () override { return IsDirectoryExists (MPStringToStdW (path)); }}
|
||||||
|
String ^EnumFilesToJson (String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumDirsToJson (bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
String ^EnumSubDirsToJson (bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
||||||
|
return CStringToMPString (StringArrayToJson (res));
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumFiles (String ^filter, bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumDirs (bool withpath, bool sort, bool includesub)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res;
|
||||||
|
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
array <String ^> ^EnumSubDirs (bool withpath)
|
||||||
|
{
|
||||||
|
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
||||||
|
auto retarr = gcnew array <String ^> (res.size ());
|
||||||
|
for (size_t i = 0; i < res.size (); i ++)
|
||||||
|
{
|
||||||
|
retarr [i] = CStringToMPString (res [i]);
|
||||||
|
}
|
||||||
|
return retarr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
public ref class _I_Storage
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
_I_Path ^path = gcnew _I_Path ();
|
||||||
|
public:
|
||||||
|
property _I_Path ^Path { _I_Path ^get () { return path; }}
|
||||||
|
_I_File ^GetFile (String ^path) { return gcnew _I_File (path); }
|
||||||
|
_I_Directory ^GetDirectory (String ^path) { return gcnew _I_Directory (path); }
|
||||||
|
_I_Directory ^GetDir (String ^path) { return GetDirectory (path); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <WinInet.h>
|
#include <winhttp.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "strcode.h"
|
#include "strcode.h"
|
||||||
#include "mpstr.h"
|
#include "mpstr.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <rapidjson/writer.h>
|
#include <rapidjson/writer.h>
|
||||||
#include <rapidjson/stringbuffer.h>
|
#include <rapidjson/stringbuffer.h>
|
||||||
|
#include "syncutil.h"
|
||||||
|
|
||||||
// Generated by ChatGTP
|
// Generated by ChatGTP
|
||||||
|
|
||||||
using namespace System;
|
using namespace System;
|
||||||
using namespace System::Threading;
|
using namespace System::Threading;
|
||||||
using namespace System::Reflection;
|
using namespace System::Reflection;
|
||||||
#include <Windows.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
std::wstring GetLastErrorString ()
|
std::wstring GetLastErrorString ()
|
||||||
{
|
{
|
||||||
@@ -50,6 +49,8 @@ std::wstring GetLastErrorString ()
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CriticalSection g_download_cs;
|
||||||
|
|
||||||
public ref class DownloadHelper
|
public ref class DownloadHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -72,49 +73,163 @@ public ref class DownloadHelper
|
|||||||
th->Start ();
|
th->Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HINTERNET hSession = nullptr,
|
||||||
|
hConnect = nullptr,
|
||||||
|
hRequest = nullptr;
|
||||||
|
void CancelHttpHandle (HINTERNET hInternet)
|
||||||
|
{
|
||||||
|
if (hInternet) WinHttpCloseHandle (hInternet);
|
||||||
|
hInternet = nullptr;
|
||||||
|
}
|
||||||
|
std::wstring FormatSpeed (long long speed)
|
||||||
|
{
|
||||||
|
if (speed < 0) return L"--/s";
|
||||||
|
|
||||||
|
const wchar_t* units [] = {L"B/s", L"KB/s", L"MB/s", L"GB/s", L"TB/s"};
|
||||||
|
double s = (double)speed;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
while (s >= 1024.0 && idx < 4) {
|
||||||
|
s /= 1024.0;
|
||||||
|
if (s / 1024.0 < 1) break;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t buf [64];
|
||||||
|
swprintf (buf, 64, L"%.2f %s", s, units [idx]);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
~DownloadHelper ()
|
||||||
|
{
|
||||||
|
if (hSession) CancelHttpHandle (hSession);
|
||||||
|
if (hConnect) CancelHttpHandle (hConnect);
|
||||||
|
if (hRequest) CancelHttpHandle (hRequest);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void Worker ()
|
void Worker ()
|
||||||
{
|
{
|
||||||
|
CreateScopedLock (g_download_cs);
|
||||||
std::wstring url = MPStringToStdW (m_url);
|
std::wstring url = MPStringToStdW (m_url);
|
||||||
std::wstring outPath = MPStringToStdW (m_savePath);
|
std::wstring outPath = MPStringToStdW (m_savePath);
|
||||||
|
|
||||||
HINTERNET hInternet = InternetOpenW (L"MyDownloader",
|
URL_COMPONENTS urlComp = {0};
|
||||||
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
urlComp.dwStructSize = sizeof (urlComp);
|
||||||
|
|
||||||
if (!hInternet)
|
wchar_t host [256];
|
||||||
|
wchar_t path [2048];
|
||||||
|
|
||||||
|
urlComp.lpszHostName = host;
|
||||||
|
urlComp.dwHostNameLength = _countof (host);
|
||||||
|
|
||||||
|
urlComp.lpszUrlPath = path;
|
||||||
|
urlComp.dwUrlPathLength = _countof (path);
|
||||||
|
|
||||||
|
if (!WinHttpCrackUrl (url.c_str (), 0, 0, &urlComp))
|
||||||
{
|
{
|
||||||
ReportError (outPath, L"InternetOpenW Failed: " + GetLastErrorString ());
|
ReportError (outPath, L"WinHttpCrackUrl failed: " + GetLastErrorString ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HINTERNET hFile = InternetOpenUrlW (
|
BOOL isHttps = (urlComp.nScheme == INTERNET_SCHEME_HTTPS);
|
||||||
hInternet,
|
|
||||||
url.c_str (),
|
hSession = WinHttpOpen (
|
||||||
NULL,
|
L"MyDownloader",
|
||||||
0,
|
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||||
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
|
WINHTTP_NO_PROXY_NAME,
|
||||||
0
|
WINHTTP_NO_PROXY_BYPASS,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (!hSession)
|
||||||
|
{
|
||||||
|
ReportError (outPath, L"WinHttpOpen failed: " + GetLastErrorString ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD protocols =
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 |
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 |
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 |
|
||||||
|
WINHTTP_FLAG_SECURE_PROTOCOL_ALL;
|
||||||
|
|
||||||
|
WinHttpSetOption (
|
||||||
|
hSession,
|
||||||
|
WINHTTP_OPTION_SECURE_PROTOCOLS,
|
||||||
|
&protocols,
|
||||||
|
sizeof (protocols)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!hFile)
|
hConnect = WinHttpConnect (
|
||||||
|
hSession,
|
||||||
|
urlComp.lpszHostName,
|
||||||
|
urlComp.nPort,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (!hConnect)
|
||||||
{
|
{
|
||||||
InternetCloseHandle (hInternet);
|
CancelHttpHandle (hSession); hSession = nullptr;
|
||||||
ReportError (outPath, L"InternetOpenUrlW Failed: " + GetLastErrorString ());
|
ReportError (outPath, L"WinHttpConnect failed: " + GetLastErrorString ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD fileSize = 0;
|
hRequest = WinHttpOpenRequest (
|
||||||
DWORD len = sizeof (fileSize);
|
hConnect,
|
||||||
HttpQueryInfoW (hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
|
L"GET",
|
||||||
&fileSize, &len, NULL);
|
urlComp.lpszUrlPath,
|
||||||
|
NULL,
|
||||||
|
WINHTTP_NO_REFERER,
|
||||||
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||||
|
isHttps ? WINHTTP_FLAG_SECURE : 0);
|
||||||
|
|
||||||
HANDLE hOut = CreateFileW (outPath.c_str (), GENERIC_WRITE, 0,
|
if (!hRequest)
|
||||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
{
|
||||||
|
CancelHttpHandle (hConnect); hConnect = nullptr;
|
||||||
|
CancelHttpHandle (hSession); hSession = nullptr;
|
||||||
|
ReportError (outPath, L"WinHttpOpenRequest failed: " + GetLastErrorString ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WinHttpSendRequest (hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
||||||
|
WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
|
||||||
|
{
|
||||||
|
CancelHttpHandle (hRequest);
|
||||||
|
CancelHttpHandle (hConnect);
|
||||||
|
CancelHttpHandle (hSession);
|
||||||
|
ReportError (outPath, L"WinHttpSendRequest failed: " + GetLastErrorString ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WinHttpReceiveResponse (hRequest, NULL))
|
||||||
|
{
|
||||||
|
CancelHttpHandle (hRequest); hRequest = nullptr;
|
||||||
|
CancelHttpHandle (hConnect); hConnect = nullptr;
|
||||||
|
CancelHttpHandle (hSession); hSession = nullptr;
|
||||||
|
ReportError (outPath, L"WinHttpReceiveResponse failed: " + GetLastErrorString ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 获取 Content-Length ----
|
||||||
|
DWORD dwSize = sizeof (DWORD);
|
||||||
|
DWORD fileSize = 0;
|
||||||
|
WinHttpQueryHeaders (
|
||||||
|
hRequest,
|
||||||
|
WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER,
|
||||||
|
NULL,
|
||||||
|
&fileSize,
|
||||||
|
&dwSize,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
HANDLE hOut = CreateFileW (outPath.c_str (), GENERIC_WRITE, 0, NULL,
|
||||||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
if (hOut == INVALID_HANDLE_VALUE)
|
if (hOut == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
InternetCloseHandle (hFile);
|
CancelHttpHandle (hRequest); hRequest = nullptr;
|
||||||
InternetCloseHandle (hInternet);
|
CancelHttpHandle (hConnect); hConnect = nullptr;
|
||||||
|
CancelHttpHandle (hSession); hSession = nullptr;
|
||||||
ReportError (outPath, L"Cannot create output file: " + GetLastErrorString ());
|
ReportError (outPath, L"Cannot create output file: " + GetLastErrorString ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -125,23 +240,38 @@ public ref class DownloadHelper
|
|||||||
long long received = 0;
|
long long received = 0;
|
||||||
|
|
||||||
auto t0 = std::chrono::high_resolution_clock::now ();
|
auto t0 = std::chrono::high_resolution_clock::now ();
|
||||||
|
auto lastCheck = t0;
|
||||||
|
unsigned long long lastBytes = 0;
|
||||||
|
|
||||||
while (InternetReadFile (hFile, buffer, sizeof (buffer), &bytesRead) && bytesRead > 0)
|
while (WinHttpReadData (hRequest, buffer, sizeof (buffer), &bytesRead) && bytesRead > 0)
|
||||||
{
|
{
|
||||||
WriteFile (hOut, buffer, bytesRead, &bytesWritten, NULL);
|
WriteFile (hOut, buffer, bytesRead, &bytesWritten, NULL);
|
||||||
received += bytesRead;
|
received += bytesRead;
|
||||||
|
|
||||||
// 计算速度
|
auto now = std::chrono::high_resolution_clock::now ();
|
||||||
auto t1 = std::chrono::high_resolution_clock::now ();
|
double intervalSec = std::chrono::duration<double> (now - lastCheck).count ();
|
||||||
double sec = std::chrono::duration<double> (t1 - t0).count ();
|
|
||||||
long long speed = (long long)(received / (sec > 0 ? sec : 1));
|
long long speed = -1; // -1 表示“保持上次速度”
|
||||||
|
|
||||||
|
// 每 0.5 秒刷新一次速度(可调)
|
||||||
|
if (intervalSec >= 0.5)
|
||||||
|
{
|
||||||
|
unsigned long long bytesInInterval = received - lastBytes;
|
||||||
|
if (intervalSec > 0)
|
||||||
|
speed = (long long)(bytesInInterval / intervalSec); // B/s
|
||||||
|
|
||||||
|
lastCheck = now;
|
||||||
|
lastBytes = received;
|
||||||
|
}
|
||||||
|
|
||||||
ReportProgress (received, fileSize, speed);
|
ReportProgress (received, fileSize, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CloseHandle (hOut);
|
CloseHandle (hOut);
|
||||||
InternetCloseHandle (hFile);
|
CancelHttpHandle (hRequest); hRequest = nullptr;
|
||||||
InternetCloseHandle (hInternet);
|
CancelHttpHandle (hConnect); hConnect = nullptr;
|
||||||
|
CancelHttpHandle (hSession); hSession = nullptr;
|
||||||
|
|
||||||
ReportComplete (outPath, received);
|
ReportComplete (outPath, received);
|
||||||
}
|
}
|
||||||
@@ -158,7 +288,12 @@ public ref class DownloadHelper
|
|||||||
w.StartObject ();
|
w.StartObject ();
|
||||||
w.Key ("received"); w.Uint64 (received);
|
w.Key ("received"); w.Uint64 (received);
|
||||||
w.Key ("total"); w.Uint64 (total);
|
w.Key ("total"); w.Uint64 (total);
|
||||||
w.Key ("speed"); w.Uint64 (speed);
|
std::wstring speedText = FormatSpeed (speed);
|
||||||
|
std::string speedUtf8 = WStringToString (speedText, CP_UTF8);
|
||||||
|
|
||||||
|
w.Key ("speed");
|
||||||
|
w.String (speedUtf8.c_str ());
|
||||||
|
|
||||||
w.Key ("progress"); w.Double (received / (double)total * 100);
|
w.Key ("progress"); w.Double (received / (double)total * 100);
|
||||||
w.EndObject ();
|
w.EndObject ();
|
||||||
|
|
||||||
|
|||||||
@@ -869,310 +869,3 @@ bool PathEquals (const std::wstring &path1, const std::wstring &path2)
|
|||||||
PathCanonicalizeW (buf2.data (), path2.c_str ());
|
PathCanonicalizeW (buf2.data (), path2.c_str ());
|
||||||
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
|
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus_cli
|
|
||||||
#include <rapidjson\document.h>
|
|
||||||
#include <rapidjson\writer.h>
|
|
||||||
#include <rapidjson\stringbuffer.h>
|
|
||||||
#include <codecvt>
|
|
||||||
#include <locale>
|
|
||||||
#include "mpstr.h"
|
|
||||||
#include "strcode.h"
|
|
||||||
using namespace System;
|
|
||||||
using namespace System::Runtime::InteropServices;
|
|
||||||
String ^StringArrayToJson (array <String ^> ^strs)
|
|
||||||
{
|
|
||||||
using namespace rapidjson;
|
|
||||||
Document doc;
|
|
||||||
doc.SetArray ();
|
|
||||||
Document::AllocatorType &allocator = doc.GetAllocator ();
|
|
||||||
for each (String ^s in strs)
|
|
||||||
{
|
|
||||||
std::wstring ws = MPStringToStdW (s); // String^ → std::wstring
|
|
||||||
std::string utf8 = WStringToString (ws, CP_UTF8); // 简易宽转 UTF-8,如需更严谨可用 WideCharToMultiByte
|
|
||||||
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
|
||||||
}
|
|
||||||
StringBuffer buffer;
|
|
||||||
Writer <StringBuffer> writer (buffer);
|
|
||||||
doc.Accept (writer);
|
|
||||||
std::string json = buffer.GetString ();
|
|
||||||
std::wstring wjson = StringToWString (json, CP_UTF8);
|
|
||||||
return CStringToMPString (wjson);
|
|
||||||
}
|
|
||||||
std::wstring StringArrayToJson (const std::vector<std::wstring>& arr)
|
|
||||||
{
|
|
||||||
using namespace rapidjson;
|
|
||||||
Document doc;
|
|
||||||
doc.SetArray ();
|
|
||||||
auto &allocator = doc.GetAllocator ();
|
|
||||||
for (const auto &ws : arr)
|
|
||||||
{
|
|
||||||
std::string utf8 = WStringToUtf8 (ws);
|
|
||||||
doc.PushBack (Value (utf8.c_str (), allocator), allocator);
|
|
||||||
}
|
|
||||||
StringBuffer buffer;
|
|
||||||
Writer <StringBuffer> writer (buffer);
|
|
||||||
doc.Accept (writer);
|
|
||||||
return Utf8ToWString (buffer.GetString ());
|
|
||||||
}
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Path
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
property String ^Current
|
|
||||||
{
|
|
||||||
String ^get () { return CStringToMPString (GetCurrentDirectoryW ()); }
|
|
||||||
void set (String ^dir) { SetCurrentDirectoryW (MPStringToStdW (dir).c_str ()); }
|
|
||||||
}
|
|
||||||
property String ^Program { String ^get () { return CStringToMPString (GetCurrentProgramPathW ()); } }
|
|
||||||
property String ^Root { String ^get () {
|
|
||||||
std::wstring program = GetCurrentProgramPathW ();
|
|
||||||
std::wstring path = GetFileDirectoryW (program);
|
|
||||||
return CStringToMPString (GetFileDirectoryW (GetCurrentProgramPathW ()));
|
|
||||||
}}
|
|
||||||
String ^Combine (String ^l, String ^r) { return CStringToMPString (CombinePath (MPStringToStdW (l), MPStringToStdW (r))); }
|
|
||||||
String ^GetName (String ^path)
|
|
||||||
{
|
|
||||||
std::wstring cpath = MPStringToStdW (path);
|
|
||||||
LPWSTR lp = PathFindFileNameW (cpath.c_str ());
|
|
||||||
return lp ? CStringToMPString (lp) : String::Empty;
|
|
||||||
}
|
|
||||||
String ^GetDirectory (String ^path) { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }
|
|
||||||
String ^GetDir (String ^path) { return GetDirectory (path); }
|
|
||||||
bool Exist (String ^path) { return IsPathExists (MPStringToStdW (path)); }
|
|
||||||
bool FileExist (String ^filepath) { return IsFileExists (MPStringToStdW (filepath)); }
|
|
||||||
bool DirectoryExist (String ^dirpath) { return IsDirectoryExists (MPStringToStdW (dirpath)); }
|
|
||||||
bool DirExist (String ^dirpath) { return DirectoryExist (dirpath); }
|
|
||||||
String ^GetEnvironmentString (String ^str) { return CStringToMPString (ProcessEnvVars (MPStringToStdW (str))); }
|
|
||||||
bool ValidName (String ^filename) { return IsValidWindowsName (MPStringToStdW (filename)); }
|
|
||||||
// 过滤器用"\"分隔每个类型
|
|
||||||
String ^EnumFilesToJson (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumDirsToJson (String ^dir, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumSubDirsToJson (String ^dir, bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumFiles (String ^dir, String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (dir), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumDirs (String ^dir, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (dir), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumSubDirs (String ^dir, bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (dir), withpath);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
String ^CommonPrefix (String ^path1, String ^path2) { return CStringToMPString (PathCommonPrefix (MPStringToStdW (path1), MPStringToStdW (path2))); }
|
|
||||||
String ^EnsureDirSlash (String ^dir) { return CStringToMPString (EnsureTrailingSlash (MPStringToStdW (dir))); }
|
|
||||||
String ^Normalize (String ^path) { return CStringToMPString (NormalizePath (MPStringToStdW (path))); }
|
|
||||||
String ^FullPathName (String ^path) { return CStringToMPString (GetFullPathName (MPStringToStdW (path))); }
|
|
||||||
bool PEquals (String ^l, String ^r) { return PathEquals (MPStringToStdW (l), MPStringToStdW (r)); }
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Entry
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
String ^path;
|
|
||||||
public:
|
|
||||||
_I_Entry (String ^path): path (path) {}
|
|
||||||
_I_Entry (): path (String::Empty) {}
|
|
||||||
property String ^Path { String ^get () { return path; } void set (String ^file) { path = file; } }
|
|
||||||
property String ^Name
|
|
||||||
{
|
|
||||||
String ^get ()
|
|
||||||
{
|
|
||||||
std::wstring file = MPStringToStdW (path);
|
|
||||||
LPWSTR lpstr = PathFindFileNameW (file.c_str ());
|
|
||||||
return lpstr ? CStringToMPString (lpstr) : String::Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^Directory { String ^get () { return CStringToMPString (GetFileDirectoryW (MPStringToStdW (path))); }}
|
|
||||||
property String ^Root { String ^get () { return Directory; }}
|
|
||||||
property bool Exist { virtual bool get () { return IsPathExists (MPStringToStdW (path)); }}
|
|
||||||
property String ^Uri
|
|
||||||
{
|
|
||||||
String ^get ()
|
|
||||||
{
|
|
||||||
using namespace System;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto uri = gcnew System::Uri (System::IO::Path::GetFullPath (path));
|
|
||||||
auto uriText = uri->AbsoluteUri;
|
|
||||||
return uriText;
|
|
||||||
}
|
|
||||||
catch (...) { return String::Empty; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^FullPath { String ^get () { return System::IO::Path::GetFullPath (path); }}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_File: public _I_Entry
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
System::Text::Encoding ^lastEncoding;
|
|
||||||
public:
|
|
||||||
_I_File (String ^filepath): _I_Entry (filepath) {}
|
|
||||||
_I_File (): _I_Entry (String::Empty) {}
|
|
||||||
String ^Get ()
|
|
||||||
{
|
|
||||||
using namespace System::IO;
|
|
||||||
if (String::IsNullOrEmpty (path)) return String::Empty;
|
|
||||||
FileStream ^fs = nullptr;
|
|
||||||
StreamReader ^sr = nullptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fs = gcnew FileStream (
|
|
||||||
path,
|
|
||||||
FileMode::OpenOrCreate,
|
|
||||||
FileAccess::ReadWrite,
|
|
||||||
FileShare::ReadWrite
|
|
||||||
);
|
|
||||||
sr = gcnew StreamReader (fs, Encoding::UTF8, true);
|
|
||||||
String ^text = sr->ReadToEnd ();
|
|
||||||
auto lastEncoding = sr->CurrentEncoding;
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sr) delete sr;
|
|
||||||
if (fs) delete fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Set (String ^content)
|
|
||||||
{
|
|
||||||
using namespace System::IO;
|
|
||||||
if (String::IsNullOrEmpty (path)) return;
|
|
||||||
Encoding ^enc = lastEncoding ? lastEncoding : Encoding::UTF8;
|
|
||||||
FileStream ^fs = nullptr;
|
|
||||||
StreamWriter ^sw = nullptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fs = gcnew FileStream (
|
|
||||||
path,
|
|
||||||
FileMode::Create,
|
|
||||||
FileAccess::ReadWrite,
|
|
||||||
FileShare::ReadWrite
|
|
||||||
);
|
|
||||||
sw = gcnew StreamWriter (fs, enc);
|
|
||||||
sw->Write (content);
|
|
||||||
sw->Flush ();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sw) delete sw;
|
|
||||||
if (fs) delete fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property String ^Content
|
|
||||||
{
|
|
||||||
String ^get () { return Get (); }
|
|
||||||
void set (String ^value) { Set (value); }
|
|
||||||
}
|
|
||||||
property bool Exist { bool get () override { return IsFileExists (MPStringToStdW (path)); }}
|
|
||||||
property String ^FilePath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; }}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Directory: public _I_Entry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_I_Directory (String ^dirpath): _I_Entry (dirpath) {}
|
|
||||||
_I_Directory (_I_Entry ^file): _I_Entry (file->Directory) {}
|
|
||||||
_I_Directory (): _I_Entry (String::Empty) {}
|
|
||||||
property String ^DirectoryPath { String ^get () { return this->Path; } void set (String ^value) { this->Path = value; } }
|
|
||||||
property String ^DirPath { String ^get () { return this->DirectoryPath; } void set (String ^value) { this->DirectoryPath = value; } }
|
|
||||||
property bool Exist { bool get () override { return IsDirectoryExists (MPStringToStdW (path)); }}
|
|
||||||
String ^EnumFilesToJson (String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumDirsToJson (bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
String ^EnumSubDirsToJson (bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
|
||||||
return CStringToMPString (StringArrayToJson (res));
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumFiles (String ^filter, bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
::EnumFiles (MPStringToStdW (DirPath), MPStringToStdW (filter), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumDirs (bool withpath, bool sort, bool includesub)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res;
|
|
||||||
EnumDirectory (MPStringToStdW (DirPath), res, withpath, sort, includesub);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
array <String ^> ^EnumSubDirs (bool withpath)
|
|
||||||
{
|
|
||||||
std::vector <std::wstring> res = EnumSubdirectories (MPStringToStdW (DirPath), withpath);
|
|
||||||
auto retarr = gcnew array <String ^> (res.size ());
|
|
||||||
for (size_t i = 0; i < res.size (); i ++)
|
|
||||||
{
|
|
||||||
retarr [i] = CStringToMPString (res [i]);
|
|
||||||
}
|
|
||||||
return retarr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
[ComVisible (true)]
|
|
||||||
public ref class _I_Storage
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
_I_Path ^path = gcnew _I_Path ();
|
|
||||||
public:
|
|
||||||
property _I_Path ^Path { _I_Path ^get () { return path; }}
|
|
||||||
_I_File ^GetFile (String ^path) { return gcnew _I_File (path); }
|
|
||||||
_I_Directory ^GetDirectory (String ^path) { return gcnew _I_Directory (path); }
|
|
||||||
_I_Directory ^GetDir (String ^path) { return GetDirectory (path); }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <msclr/marshal_cppstd.h>
|
#include <msclr/marshal_cppstd.h>
|
||||||
#include <ShObjIdl.h>
|
#include <ShObjIdl.h>
|
||||||
|
#include <ShlObj.h> // KNOWNFOLDERID, SHGetKnownFolderPath
|
||||||
|
#include <commdlg.h> // OPENFILENAME
|
||||||
|
#include <comdef.h> // _com_error
|
||||||
|
#include <winhttp.h> // WinHTTP
|
||||||
#include <MsHTML.h>
|
#include <MsHTML.h>
|
||||||
#include <ExDisp.h>
|
#include <ExDisp.h>
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
@@ -9,10 +13,12 @@
|
|||||||
#include <comdef.h>
|
#include <comdef.h>
|
||||||
#include <vcclr.h>
|
#include <vcclr.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <commdlg.h>
|
||||||
#include <rapidjson\document.h>
|
#include <rapidjson\document.h>
|
||||||
#include <rapidjson\writer.h>
|
#include <rapidjson\writer.h>
|
||||||
#include <rapidjson\stringbuffer.h>
|
#include <rapidjson\stringbuffer.h>
|
||||||
#include "download.h"
|
#include <tlhelp32.h>
|
||||||
|
#include <Psapi.h>
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "themeinfo.h"
|
#include "themeinfo.h"
|
||||||
#include "mpstr.h"
|
#include "mpstr.h"
|
||||||
@@ -20,6 +26,7 @@
|
|||||||
#include "vemani.h"
|
#include "vemani.h"
|
||||||
#include "ieshell.h"
|
#include "ieshell.h"
|
||||||
#include "localeex.h"
|
#include "localeex.h"
|
||||||
|
#include "download.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
#include "rctools.h"
|
#include "rctools.h"
|
||||||
#include "nstring.h"
|
#include "nstring.h"
|
||||||
@@ -45,6 +52,7 @@ struct iconhandle
|
|||||||
|
|
||||||
LPCWSTR g_lpAppId = L"WindowsModern.PracticalToolsProject!Settings";
|
LPCWSTR g_lpAppId = L"WindowsModern.PracticalToolsProject!Settings";
|
||||||
LPCWSTR g_idInVe = L"Settings";
|
LPCWSTR g_idInVe = L"Settings";
|
||||||
|
LPCWSTR g_wndclass = L"Win32_WebUI_WindowsModern";
|
||||||
iconhandle g_hIconMain (LoadRCIcon (IDI_ICON_MAIN));
|
iconhandle g_hIconMain (LoadRCIcon (IDI_ICON_MAIN));
|
||||||
initfile g_initfile (CombinePath (GetProgramRootDirectoryW (), L"config.ini"));
|
initfile g_initfile (CombinePath (GetProgramRootDirectoryW (), L"config.ini"));
|
||||||
vemanifest g_vemani (
|
vemanifest g_vemani (
|
||||||
@@ -61,6 +69,73 @@ ref class MainHtmlWnd;
|
|||||||
msclr::gcroot <MainHtmlWnd ^> g_mainwnd;
|
msclr::gcroot <MainHtmlWnd ^> g_mainwnd;
|
||||||
std::wstring g_lastfile;
|
std::wstring g_lastfile;
|
||||||
inline std::wstring ToStdWString (const std::wstring &str) { return str; }
|
inline std::wstring ToStdWString (const std::wstring &str) { return str; }
|
||||||
|
std::string GetSuitableLanguageValue (const std::map <std::nstring, std::string> &map, const std::nstring &localename)
|
||||||
|
{
|
||||||
|
for (auto &it : map) if (it.first == localename) return it.second;
|
||||||
|
for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (it.first), pugi::as_wide (localename))) return it.second;
|
||||||
|
for (auto &it : map) if (IsNormalizeStringEquals (GetLocaleRestrictedCodeA (it.first), GetLocaleRestrictedCodeA (localename))) return it.second;
|
||||||
|
for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (GetLocaleRestrictedCodeA (it.first)), pugi::as_wide (GetLocaleRestrictedCodeA (localename)))) return it.second;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string GetSuitableLanguageValue (const std::map <std::nstring, std::string> &map)
|
||||||
|
{
|
||||||
|
if (map.empty ()) return "";
|
||||||
|
std::string ret = GetSuitableLanguageValue (map, pugi::as_utf8 (GetComputerLocaleCodeW ()));
|
||||||
|
if (ret.empty ()) ret = GetSuitableLanguageValue (map, "en-US");
|
||||||
|
if (ret.empty ()) ret = map.begin ()->second;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
struct xmlstrres
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
bool isvalid = false;
|
||||||
|
void destroy ()
|
||||||
|
{
|
||||||
|
if (isvalid) doc.reset ();
|
||||||
|
isvalid = false;
|
||||||
|
}
|
||||||
|
bool create (const std::wstring &filepath)
|
||||||
|
{
|
||||||
|
destroy ();
|
||||||
|
auto res = doc.load_file (filepath.c_str ());
|
||||||
|
return isvalid = res;
|
||||||
|
}
|
||||||
|
xmlstrres (const std::wstring &filepath) { create (filepath); }
|
||||||
|
~xmlstrres () { destroy (); }
|
||||||
|
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 strings = it.children ();
|
||||||
|
std::map <std::nstring, std::string> lang_value;
|
||||||
|
for (auto &sub : strings)
|
||||||
|
{
|
||||||
|
std::nstring lang = sub.attribute ("name").as_string ();
|
||||||
|
if (!lang.empty ()) lang_value [lang] = sub.text ().get ();
|
||||||
|
}
|
||||||
|
return GetSuitableLanguageValue (lang_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::wstring get (const std::wstring &id) const { return pugi::as_wide (get (pugi::as_utf8 (id))); }
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
xmlstrres g_winjspri (CombinePath (GetProgramRootDirectoryW (), L"locale\\resources.xml"));
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool jump = false;
|
||||||
|
std::wstring section = L"";
|
||||||
|
std::wstring item = L"";
|
||||||
|
std::wstring arg = L"";
|
||||||
|
};
|
||||||
|
|
||||||
size_t ExploreFile (HWND hParent, std::vector <std::wstring> &results, LPWSTR lpFilter = L"Windows Store App Package (*.appx; *.appxbundle)\0*.appx;*.appxbundle", DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST, const std::wstring &swWndTitle = std::wstring (L"Please select the file(-s): "), const std::wstring &swInitDir = GetFileDirectoryW (g_lastfile))
|
size_t ExploreFile (HWND hParent, std::vector <std::wstring> &results, LPWSTR lpFilter = L"Windows Store App Package (*.appx; *.appxbundle)\0*.appx;*.appxbundle", DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST, const std::wstring &swWndTitle = std::wstring (L"Please select the file(-s): "), const std::wstring &swInitDir = GetFileDirectoryW (g_lastfile))
|
||||||
{
|
{
|
||||||
@@ -407,6 +482,104 @@ public ref class _I_IEFrame_Base
|
|||||||
return "{}";
|
return "{}";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
int ExecuteProgram (
|
||||||
|
const std::wstring &cmdline,
|
||||||
|
const std::wstring &file,
|
||||||
|
int wndshowmode,
|
||||||
|
bool wait,
|
||||||
|
const std::wstring &execdir = L"")
|
||||||
|
{
|
||||||
|
STARTUPINFOW si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
ZeroMemory (&si, sizeof (si));
|
||||||
|
ZeroMemory (&pi, sizeof (pi));
|
||||||
|
si.cb = sizeof (si);
|
||||||
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||||
|
si.wShowWindow = static_cast <WORD> (wndshowmode);
|
||||||
|
std::vector <WCHAR> buf (cmdline.capacity () + 1);
|
||||||
|
wcscpy (buf.data (), cmdline.c_str ());
|
||||||
|
LPCWSTR workdir = IsNormalizeStringEmpty (execdir) ? NULL : execdir.c_str ();
|
||||||
|
BOOL ok = CreateProcessW (
|
||||||
|
IsNormalizeStringEmpty (file) ? NULL : file.c_str (), // 应用程序路径
|
||||||
|
IsNormalizeStringEmpty (cmdline) ? NULL : buf.data (), // 命令行必须可写
|
||||||
|
NULL, // 进程安全属性
|
||||||
|
NULL, // 线程安全属性
|
||||||
|
FALSE, // 不继承句柄
|
||||||
|
0, // 创建标志
|
||||||
|
NULL, // 使用父进程环境变量
|
||||||
|
workdir, // 工作目录
|
||||||
|
&si,
|
||||||
|
&pi
|
||||||
|
);
|
||||||
|
if (!ok) return static_cast <int> (GetLastError ());
|
||||||
|
if (wait) WaitForSingleObject (pi.hProcess, INFINITE);
|
||||||
|
CloseHandle (pi.hThread);
|
||||||
|
CloseHandle (pi.hProcess);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool KillProcessByFilePath (
|
||||||
|
const std::wstring &filepath,
|
||||||
|
bool multiple = false,
|
||||||
|
bool isonlyname = false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (filepath.empty ()) return false;
|
||||||
|
std::wstring targetPath = filepath;
|
||||||
|
std::wstring targetName;
|
||||||
|
if (isonlyname)
|
||||||
|
{
|
||||||
|
size_t pos = filepath.find_last_of (L"\\/");
|
||||||
|
if (pos != std::wstring::npos) targetName = filepath.substr (pos + 1);
|
||||||
|
else targetName = filepath; // 直接是文件名
|
||||||
|
}
|
||||||
|
HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (hSnap == INVALID_HANDLE_VALUE) return false;
|
||||||
|
PROCESSENTRY32W pe;
|
||||||
|
pe.dwSize = sizeof (pe);
|
||||||
|
bool killed = false;
|
||||||
|
if (Process32FirstW (hSnap, &pe))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
bool match = false;
|
||||||
|
if (isonlyname)
|
||||||
|
{
|
||||||
|
if (PathEquals (pe.szExeFile, targetName.c_str ())) match = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 比较完整路径,需要 QueryFullProcessImageNameW
|
||||||
|
HANDLE hProc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
|
||||||
|
if (hProc)
|
||||||
|
{
|
||||||
|
wchar_t exePath [MAX_PATH] = {0};
|
||||||
|
DWORD sz = MAX_PATH;
|
||||||
|
|
||||||
|
if (QueryFullProcessImageNameW (hProc, 0, exePath, &sz))
|
||||||
|
{
|
||||||
|
if (_wcsicmp (exePath, targetPath.c_str ()) == 0)
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
CloseHandle (hProc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match)
|
||||||
|
{
|
||||||
|
HANDLE hProc = OpenProcess (PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
|
||||||
|
if (hProc)
|
||||||
|
{
|
||||||
|
TerminateProcess (hProc, 1);
|
||||||
|
CloseHandle (hProc);
|
||||||
|
killed = true;
|
||||||
|
}
|
||||||
|
if (!multiple) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (Process32NextW (hSnap, &pe));
|
||||||
|
}
|
||||||
|
CloseHandle (hSnap);
|
||||||
|
return killed;
|
||||||
|
}
|
||||||
|
|
||||||
[ComVisible (true)]
|
[ComVisible (true)]
|
||||||
public ref class SplashForm: public System::Windows::Forms::Form
|
public ref class SplashForm: public System::Windows::Forms::Form
|
||||||
@@ -679,11 +852,85 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form, public IScrip
|
|||||||
}
|
}
|
||||||
property _I_UI2 ^UI { _I_UI2 ^get () { return ui2; } }
|
property _I_UI2 ^UI { _I_UI2 ^get () { return ui2; } }
|
||||||
};
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
ref class _I_Process
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using String = System::String;
|
||||||
|
ref class ProcessWorker
|
||||||
|
{
|
||||||
|
_I_Process ^parent;
|
||||||
|
public:
|
||||||
|
ProcessWorker (_I_Process ^parent): parent (parent) {}
|
||||||
|
ProcessWorker (): parent (gcnew _I_Process ()) {}
|
||||||
|
String ^cmdline = String::Empty;
|
||||||
|
String ^filepath = String::Empty;
|
||||||
|
int wndtype = SW_NORMAL;
|
||||||
|
String ^runpath = String::Empty;
|
||||||
|
Object ^callback = nullptr;
|
||||||
|
void Work ()
|
||||||
|
{
|
||||||
|
int ret = parent->Run (cmdline, filepath, wndtype, true, runpath);
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback->GetType ()->InvokeMember (
|
||||||
|
"call",
|
||||||
|
BindingFlags::InvokeMethod,
|
||||||
|
nullptr,
|
||||||
|
callback,
|
||||||
|
gcnew array<Object^>{ 1, ret }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (...) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
int Run (String ^cmdline, String ^filepath, int wndtype, bool wait, String ^runpath)
|
||||||
|
{
|
||||||
|
return ExecuteProgram (
|
||||||
|
MPStringToStdW (cmdline),
|
||||||
|
MPStringToStdW (filepath),
|
||||||
|
wndtype,
|
||||||
|
wait,
|
||||||
|
MPStringToStdW (runpath)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void RunAsync (String ^cmdline, String ^filepath, int wndtype, String ^runpath, Object ^callback)
|
||||||
|
{
|
||||||
|
auto worker = gcnew ProcessWorker (this);
|
||||||
|
worker->cmdline = cmdline;
|
||||||
|
worker->filepath = filepath;
|
||||||
|
worker->wndtype = wndtype;
|
||||||
|
worker->runpath = runpath;
|
||||||
|
worker->callback = callback;
|
||||||
|
Thread^ th = gcnew Thread (gcnew ThreadStart (worker, &ProcessWorker::Work));
|
||||||
|
th->IsBackground = true;
|
||||||
|
th->Start ();
|
||||||
|
}
|
||||||
|
bool Kill (String ^filename, bool allproc, bool onlyname) { return KillProcessByFilePath (MPStringToStdW (filename), allproc, onlyname); }
|
||||||
|
};
|
||||||
|
[ComVisible (true)]
|
||||||
|
ref class _I_ResourcePri
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using String = System::String;
|
||||||
|
String ^GetString (String ^uri)
|
||||||
|
{
|
||||||
|
auto ret = g_winjspri.get (MPStringToStdW (uri));
|
||||||
|
auto retstr = CStringToMPString (ret);
|
||||||
|
return retstr;
|
||||||
|
}
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
_I_IEFrame ^ieframe;
|
_I_IEFrame ^ieframe;
|
||||||
_I_System3 ^sys;
|
_I_System3 ^sys;
|
||||||
_I_VisualElements2 ^ve;
|
_I_VisualElements2 ^ve;
|
||||||
_I_Download ^download;
|
_I_Download ^download;
|
||||||
|
_I_Process ^proc;
|
||||||
|
_I_ResourcePri ^winjs_res;
|
||||||
public:
|
public:
|
||||||
IBridge (MainHtmlWnd ^wnd): wndinst (wnd), _I_Bridge_Base2 (wnd)
|
IBridge (MainHtmlWnd ^wnd): wndinst (wnd), _I_Bridge_Base2 (wnd)
|
||||||
{
|
{
|
||||||
@@ -692,17 +939,30 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form, public IScrip
|
|||||||
storage = gcnew _I_Storage ();
|
storage = gcnew _I_Storage ();
|
||||||
ve = gcnew _I_VisualElements2 ();
|
ve = gcnew _I_VisualElements2 ();
|
||||||
download = gcnew _I_Download ();
|
download = gcnew _I_Download ();
|
||||||
|
proc = gcnew _I_Process ();
|
||||||
|
winjs_res = gcnew _I_ResourcePri ();
|
||||||
}
|
}
|
||||||
property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }}
|
property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }}
|
||||||
property _I_System3 ^System { _I_System3 ^get () { return sys; }}
|
property _I_System3 ^System { _I_System3 ^get () { return sys; }}
|
||||||
property _I_VisualElements2 ^VisualElements { _I_VisualElements2 ^get () { return ve; } }
|
property _I_VisualElements2 ^VisualElements { _I_VisualElements2 ^get () { return ve; } }
|
||||||
property _I_Download ^Download { _I_Download ^get () { return download; }}
|
property _I_Download ^Download { _I_Download ^get () { return download; }}
|
||||||
|
property _I_Process ^Process { _I_Process ^get () { return proc; }}
|
||||||
|
property _I_ResourcePri ^WinJsStringRes { _I_ResourcePri ^get () { return winjs_res; }}
|
||||||
|
void CloseWindow ()
|
||||||
|
{
|
||||||
|
if (wndinst && wndinst->IsHandleCreated) wndinst->Close ();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } }
|
property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } }
|
||||||
property SplashForm ^SplashScreen { SplashForm ^get () { return this->splash; } }
|
property SplashForm ^SplashScreen { SplashForm ^get () { return this->splash; } }
|
||||||
property int DPIPercent { int get () { return GetDPI (); }}
|
property int DPIPercent { int get () { return GetDPI (); }}
|
||||||
property double DPI { double get () { return DPIPercent * 0.01; }}
|
property double DPI { double get () { return DPIPercent * 0.01; }}
|
||||||
|
virtual void OnHandleCreated (EventArgs ^e) override
|
||||||
|
{
|
||||||
|
::SetClassLongPtrW ((HWND)this->Handle.ToPointer (), GCLP_HBRBACKGROUND, (LONG_PTR)g_wndclass);
|
||||||
|
Form::OnHandleCreated (e);
|
||||||
|
}
|
||||||
void InitSize ()
|
void InitSize ()
|
||||||
{
|
{
|
||||||
unsigned ww = 0, wh = 0;
|
unsigned ww = 0, wh = 0;
|
||||||
@@ -1009,10 +1269,71 @@ HRESULT SetCurrentAppUserModelID (PCWSTR appID)
|
|||||||
catch (...) { return E_FAIL; }
|
catch (...) { return E_FAIL; }
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetProgramSingleInstance (
|
||||||
|
const std::wstring &mutexName,
|
||||||
|
std::function <void ()> repeatCallback = nullptr,
|
||||||
|
bool focusMain = true)
|
||||||
|
{
|
||||||
|
HANDLE hMutex = CreateMutexW (NULL, TRUE, mutexName.c_str ());
|
||||||
|
if (hMutex == NULL) return;
|
||||||
|
destruct _mutexFree ([&] () { CloseHandle (hMutex); });
|
||||||
|
if (GetLastError () != ERROR_ALREADY_EXISTS) return;
|
||||||
|
if (repeatCallback) repeatCallback ();
|
||||||
|
wchar_t pathBuf [MAX_PATH] = {0};
|
||||||
|
GetModuleFileNameW (NULL, pathBuf, MAX_PATH);
|
||||||
|
std::wstring exeName = pathBuf;
|
||||||
|
exeName = exeName.substr (exeName.find_last_of (L"\\/") + 1);
|
||||||
|
DWORD existingPid = 0;
|
||||||
|
HANDLE snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (snap != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
PROCESSENTRY32W pe = {sizeof (pe)};
|
||||||
|
if (Process32FirstW (snap, &pe))
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if (_wcsicmp (pe.szExeFile, exeName.c_str ()) == 0 &&
|
||||||
|
pe.th32ProcessID != GetCurrentProcessId ())
|
||||||
|
{
|
||||||
|
existingPid = pe.th32ProcessID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (Process32NextW (snap, &pe));
|
||||||
|
}
|
||||||
|
CloseHandle (snap);
|
||||||
|
}
|
||||||
|
HWND targetHwnd = NULL;
|
||||||
|
if (existingPid)
|
||||||
|
{
|
||||||
|
EnumWindows ([] (HWND hwnd, LPARAM lParam) -> BOOL {
|
||||||
|
DWORD pid = 0;
|
||||||
|
GetWindowThreadProcessId (hwnd, &pid);
|
||||||
|
if (pid == (DWORD)lParam && IsWindowVisible (hwnd))
|
||||||
|
{
|
||||||
|
*((HWND *)(&lParam)) = hwnd;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}, (LPARAM)&targetHwnd);
|
||||||
|
}
|
||||||
|
if (focusMain && targetHwnd)
|
||||||
|
{
|
||||||
|
if (IsIconic (targetHwnd)) ShowWindow (targetHwnd, SW_RESTORE);
|
||||||
|
DWORD thisThread = GetCurrentThreadId ();
|
||||||
|
DWORD wndThread = GetWindowThreadProcessId (targetHwnd, NULL);
|
||||||
|
AttachThreadInput (thisThread, wndThread, TRUE);
|
||||||
|
SetActiveWindow (targetHwnd);
|
||||||
|
SetForegroundWindow (targetHwnd);
|
||||||
|
AttachThreadInput (thisThread, wndThread, FALSE);
|
||||||
|
BringWindowToTop (targetHwnd);
|
||||||
|
}
|
||||||
|
ExitProcess (0);
|
||||||
|
}
|
||||||
[STAThread]
|
[STAThread]
|
||||||
int APIENTRY wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
int APIENTRY wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
SetCurrentProcessExplicitAppUserModelID (g_lpAppId);
|
SetCurrentProcessExplicitAppUserModelID (g_lpAppId);
|
||||||
|
SetProgramSingleInstance (g_lpAppId);
|
||||||
SetProcessDPIAware ();
|
SetProcessDPIAware ();
|
||||||
{
|
{
|
||||||
// 设置当前目录为程序所在目录
|
// 设置当前目录为程序所在目录
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>settings</RootNamespace>
|
<RootNamespace>settings</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
@@ -97,7 +98,8 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;winhttp.lib;Psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@@ -130,7 +132,8 @@
|
|||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;winhttp.lib;Psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@@ -155,21 +158,7 @@
|
|||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<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">
|
|
||||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Drawing.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Windows.Forms">
|
|
||||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Windows.Forms.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="..\appinstaller\bridge.h" />
|
|
||||||
<ClInclude Include="..\appinstaller\dynarr.h" />
|
<ClInclude Include="..\appinstaller\dynarr.h" />
|
||||||
<ClInclude Include="..\appinstaller\filepath.h" />
|
|
||||||
<ClInclude Include="..\appinstaller\ieshell.h" />
|
<ClInclude Include="..\appinstaller\ieshell.h" />
|
||||||
<ClInclude Include="..\appinstaller\initfile.h" />
|
<ClInclude Include="..\appinstaller\initfile.h" />
|
||||||
<ClInclude Include="..\appinstaller\localeex.h" />
|
<ClInclude Include="..\appinstaller\localeex.h" />
|
||||||
@@ -184,9 +173,12 @@
|
|||||||
<ClInclude Include="..\appinstaller\typestrans.h" />
|
<ClInclude Include="..\appinstaller\typestrans.h" />
|
||||||
<ClInclude Include="..\appinstaller\vemani.h" />
|
<ClInclude Include="..\appinstaller\vemani.h" />
|
||||||
<ClInclude Include="..\appinstaller\version.h" />
|
<ClInclude Include="..\appinstaller\version.h" />
|
||||||
|
<ClInclude Include="bridge.h" />
|
||||||
<ClInclude Include="download.h" />
|
<ClInclude Include="download.h" />
|
||||||
|
<ClInclude Include="filepath.h" />
|
||||||
<ClInclude Include="resmap.h" />
|
<ClInclude Include="resmap.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="syncutil.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="settings.rc" />
|
<ResourceCompile Include="settings.rc" />
|
||||||
@@ -199,6 +191,22 @@
|
|||||||
<Image Include="res\icons\main.ico" />
|
<Image Include="res\icons\main.ico" />
|
||||||
<Image Include="res\icons\white.ico" />
|
<Image Include="res\icons\white.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Drawing">
|
||||||
|
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Drawing.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net">
|
||||||
|
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Http">
|
||||||
|
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.XML">
|
||||||
|
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.XML.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
<Import Project="..\packages\rapidjson.1.0.2\build\native\rapidjson.targets" Condition="Exists('..\packages\rapidjson.1.0.2\build\native\rapidjson.targets')" />
|
<Import Project="..\packages\rapidjson.1.0.2\build\native\rapidjson.targets" Condition="Exists('..\packages\rapidjson.1.0.2\build\native\rapidjson.targets')" />
|
||||||
|
|||||||
@@ -20,15 +20,9 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\appinstaller\bridge.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\appinstaller\dynarr.h">
|
<ClInclude Include="..\appinstaller\dynarr.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\appinstaller\filepath.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\appinstaller\ieshell.h">
|
<ClInclude Include="..\appinstaller\ieshell.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -80,6 +74,15 @@
|
|||||||
<ClInclude Include="download.h">
|
<ClInclude Include="download.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="bridge.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="filepath.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="syncutil.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="settings.rc">
|
<ResourceCompile Include="settings.rc">
|
||||||
|
|||||||
124
settings/syncutil.h
Normal file
124
settings/syncutil.h
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
class CriticalSection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CRITICAL_SECTION m_csection;
|
||||||
|
public:
|
||||||
|
CriticalSection (DWORD spinCount = 4000) { InitializeCriticalSectionAndSpinCount (&m_csection, spinCount); }
|
||||||
|
CriticalSection (const CriticalSection &) = delete;
|
||||||
|
CriticalSection &operator = (const CriticalSection &) = delete;
|
||||||
|
~CriticalSection () { DeleteCriticalSection (&m_csection); }
|
||||||
|
void Lock () { EnterCriticalSection (&m_csection); }
|
||||||
|
void Unlock () { LeaveCriticalSection (&m_csection); }
|
||||||
|
bool TryLock () { return TryEnterCriticalSection (&m_csection) != 0; }
|
||||||
|
class ScopedLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ScopedLock (CriticalSection &cs): m_cs (cs) { m_cs.Lock (); }
|
||||||
|
~ScopedLock () { m_cs.Unlock (); }
|
||||||
|
ScopedLock (const ScopedLock &) = delete;
|
||||||
|
ScopedLock &operator = (const ScopedLock &) = delete;
|
||||||
|
private:
|
||||||
|
CriticalSection& m_cs;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CreateScopedLock(_obj_cs_) CriticalSection::ScopedLock _obj_cs_##sl (_obj_cs_)
|
||||||
|
|
||||||
|
#ifdef __cplusplus_cli
|
||||||
|
ref struct TaskStructEvent
|
||||||
|
{
|
||||||
|
typedef array <Object ^> args;
|
||||||
|
typedef void (*eventfunc) (... args ^args);
|
||||||
|
eventfunc post;
|
||||||
|
args ^postargs;
|
||||||
|
public:
|
||||||
|
TaskStructEvent (
|
||||||
|
eventfunc prefunc,
|
||||||
|
args ^preargs,
|
||||||
|
eventfunc postfunc,
|
||||||
|
args ^postargs
|
||||||
|
): post (postfunc), postargs (postargs)
|
||||||
|
{
|
||||||
|
if (prefunc == nullptr) {
|
||||||
|
#pragma message("警告:预处理函数指针为空,可能跳过初始化操作")
|
||||||
|
}
|
||||||
|
if (prefunc)
|
||||||
|
{
|
||||||
|
if (preargs)
|
||||||
|
{
|
||||||
|
#pragma region 参数验证示例
|
||||||
|
/*
|
||||||
|
实际项目中应添加具体类型检查,例如:
|
||||||
|
ValidateArgsType<Button^>(preargs);
|
||||||
|
*/
|
||||||
|
#pragma endregion
|
||||||
|
prefunc (preargs);
|
||||||
|
}
|
||||||
|
else prefunc (gcnew args {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~TaskStructEvent ()
|
||||||
|
{
|
||||||
|
if (post == nullptr)
|
||||||
|
{
|
||||||
|
#pragma message("警告:后处理函数指针为空,资源可能无法正确释放")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (postargs) { post (postargs); }
|
||||||
|
else { post (gcnew args {}); }
|
||||||
|
}
|
||||||
|
catch (Exception ^e)
|
||||||
|
{
|
||||||
|
#pragma message("注意:后处理中的异常需手动处理")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define CreateStructEvent(_varname_taskname_, _func_construct_, _args_construct_, _func_destruct_, _args_destruct_) \
|
||||||
|
TaskStructEvent _varname_taskname_ ( \
|
||||||
|
_func_construct_, \
|
||||||
|
_args_construct_, \
|
||||||
|
_func_destruct_, \
|
||||||
|
_args_destruct_ \
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
template <typename PreCallback, typename PostCallback> class ScopedEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedEvent (PreCallback &&pre, PostCallback &&post)
|
||||||
|
: m_post (std::forward <PostCallback> (post))
|
||||||
|
{
|
||||||
|
static_assert (
|
||||||
|
std::is_constructible <std::function <void ()>, PreCallback>::value,
|
||||||
|
"预处理回调必须可转换为 void () 类型"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pre) { pre (); }
|
||||||
|
}
|
||||||
|
~ScopedEvent () noexcept
|
||||||
|
{
|
||||||
|
if (m_post) { m_post (); }
|
||||||
|
}
|
||||||
|
ScopedEvent (const ScopedEvent &) = delete;
|
||||||
|
ScopedEvent &operator = (const ScopedEvent &) = delete;
|
||||||
|
ScopedEvent (ScopedEvent &&) = default;
|
||||||
|
ScopedEvent &operator =(ScopedEvent &&) = default;
|
||||||
|
private:
|
||||||
|
PostCallback m_post;
|
||||||
|
};
|
||||||
|
template <typename PreFunc, typename PostFunc> auto make_scoped_event (PreFunc &&pre, PostFunc &&post)
|
||||||
|
{
|
||||||
|
return ScopedEvent <PreFunc, PostFunc> (
|
||||||
|
std::forward <PreFunc> (pre),
|
||||||
|
std::forward <PostFunc> (post)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Binary file not shown.
@@ -1,16 +1,3 @@
|
|||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
|
||||||
user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body * {
|
|
||||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
*,
|
||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
@@ -45,10 +32,26 @@ video,
|
|||||||
canvas,
|
canvas,
|
||||||
form,
|
form,
|
||||||
fieldset,
|
fieldset,
|
||||||
legend {
|
legend,
|
||||||
|
.win-type-x-large,
|
||||||
|
.win-type-xx-large,
|
||||||
|
.font-fix {
|
||||||
font-family: "Microsoft YaHei", "Segoe UI", "Ebrima", "Nirmala", "Gadugi", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo", "Leelawadee", "Microsoft JhengHei", "Malgun Gothic", "Estrangelo Edessa", "Microsoft Himalaya", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Tai Le", "Microsoft Yi Baiti", "Mongolian Baiti", "MV Boli", "Myanmar Text", "Javanese Text", "Cambria Math";
|
font-family: "Microsoft YaHei", "Segoe UI", "Ebrima", "Nirmala", "Gadugi", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo", "Leelawadee", "Microsoft JhengHei", "Malgun Gothic", "Estrangelo Edessa", "Microsoft Himalaya", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Tai Le", "Microsoft Yi Baiti", "Mongolian Baiti", "MV Boli", "Myanmar Text", "Javanese Text", "Cambria Math";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||||
|
user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body * {
|
||||||
|
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
.pagecontainer {
|
.pagecontainer {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -357,4 +357,47 @@ Windows.UI.Event.Util.removeEvent(window, "resize", handler);
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
module.exports = { debounce: debounce };
|
module.exports = { debounce: debounce };
|
||||||
|
})(this);
|
||||||
|
|
||||||
|
(function(global) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var eToEvent = {}; // 存储元素和回调
|
||||||
|
var lastContent = {}; // 存储上一次的 textContent
|
||||||
|
|
||||||
|
// 注册文本变化事件
|
||||||
|
global.setTextChangeEvent = function(el, fn) {
|
||||||
|
if (!el || typeof fn !== "function") return;
|
||||||
|
|
||||||
|
var id = el.__textChangeId;
|
||||||
|
if (!id) {
|
||||||
|
id = Math.random().toString(36).substr(2, 9);
|
||||||
|
el.__textChangeId = id;
|
||||||
|
lastContent[id] = el.textContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
eToEvent[id] = { el: el, callback: fn };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 定时轮询
|
||||||
|
setInterval(function() {
|
||||||
|
var keys = Object.keys(eToEvent);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var obj = eToEvent[key];
|
||||||
|
var el = obj.el;
|
||||||
|
var currentText = el.textContent;
|
||||||
|
|
||||||
|
if (currentText !== lastContent[key]) {
|
||||||
|
lastContent[key] = currentText;
|
||||||
|
try {
|
||||||
|
obj.callback.call(el, currentText);
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略回调错误
|
||||||
|
if (typeof console !== "undefined") console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
|
|
||||||
})(this);
|
})(this);
|
||||||
@@ -127,4 +127,64 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})(this);
|
})(this);
|
||||||
|
// attachEvent / detachEvent polyfill for IE11+
|
||||||
|
(function() {
|
||||||
|
if (!Element.prototype.attachEvent) {
|
||||||
|
Element.prototype.attachEvent = function(eventName, handler) {
|
||||||
|
// IE attachEvent 的事件名需要 "on" 前缀
|
||||||
|
eventName = eventName.toLowerCase();
|
||||||
|
|
||||||
|
// 包装函数,模仿旧 IE 的 event 对象
|
||||||
|
var wrapper = function(e) {
|
||||||
|
e = e || window.event;
|
||||||
|
|
||||||
|
// 兼容 IE 风格 event 属性
|
||||||
|
e.srcElement = e.target || this;
|
||||||
|
e.returnValue = true;
|
||||||
|
e.cancelBubble = false;
|
||||||
|
|
||||||
|
// 模拟 IE 的防止默认行为
|
||||||
|
Object.defineProperty(e, "cancelBubble", {
|
||||||
|
set: function(val) {
|
||||||
|
if (val) e.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(e, "returnValue", {
|
||||||
|
set: function(val) {
|
||||||
|
if (val === false) e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 调用原事件处理函数
|
||||||
|
return handler.call(this, e);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 存储 handler 映射,供 detachEvent 用
|
||||||
|
if (!this._attachEventWrappers) this._attachEventWrappers = {};
|
||||||
|
if (!this._attachEventWrappers[eventName]) this._attachEventWrappers[eventName] = [];
|
||||||
|
|
||||||
|
this._attachEventWrappers[eventName].push({
|
||||||
|
original: handler,
|
||||||
|
wrapped: wrapper
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener(eventName.replace(/^on/, ""), wrapper, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
Element.prototype.detachEvent = function(eventName, handler) {
|
||||||
|
eventName = eventName.toLowerCase();
|
||||||
|
if (!this._attachEventWrappers || !this._attachEventWrappers[eventName]) return;
|
||||||
|
|
||||||
|
var list = this._attachEventWrappers[eventName];
|
||||||
|
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].original === handler) {
|
||||||
|
this.removeEventListener(eventName.replace(/^on/, ""), list[i].wrapped, false);
|
||||||
|
list.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})();
|
||||||
209
shared/html/libs/toggle/toggle.css
Normal file
209
shared/html/libs/toggle/toggle.css
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
.toggle-switch {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 2px solid rgb(166, 166, 166);
|
||||||
|
width: 50px;
|
||||||
|
height: 19px;
|
||||||
|
max-width: 50px !important;
|
||||||
|
max-height: 19px !important;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background {
|
||||||
|
background-color: rgb(166, 166, 166);
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
left: 1px;
|
||||||
|
right: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
z-index: 1;
|
||||||
|
transition: all 0.25s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:disabled+.toggle-background {
|
||||||
|
background-color: rgb(224, 224, 224);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:disabled~.toggle-switch-border {
|
||||||
|
border-color: rgb(204, 204, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:disabled~.toggle-switch {
|
||||||
|
border-color: rgb(204, 204, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch:hover>input[type="checkbox"]:not(:disabled):not(:checked)+.toggle-background {
|
||||||
|
background-color: rgb(181, 181, 181);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch:active>input[type="checkbox"]:not(:disabled):not(:checked)+.toggle-background {
|
||||||
|
background-color: rgb(189, 189, 189);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-border {
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
left: -2px;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
border: 2px solid rgb(166, 166, 166);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background:after {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 19px;
|
||||||
|
width: 12px;
|
||||||
|
background-color: black;
|
||||||
|
transition: transform 0.25s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||||
|
top: -3px;
|
||||||
|
left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:checked+.toggle-background:after {
|
||||||
|
transform: translateX(38px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgb(70, 23, 181);
|
||||||
|
transition: all 0.25s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input[type="checkbox"]:checked+.toggle-background:before {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch:hover>input:checked:not(:disabled)+.toggle-background:before {
|
||||||
|
background-color: rgb(90, 43, 202);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch:active>input:checked:not(:disabled)+.toggle-background:before {
|
||||||
|
background-color: rgb(143, 100, 244);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-showstatus {
|
||||||
|
margin-left: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-status {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 4;
|
||||||
|
height: 100%;
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-status:before {
|
||||||
|
content: "Off";
|
||||||
|
position: absolute;
|
||||||
|
left: -92px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
font-family: "Microsoft YaHei", "Segoe UI", "Ebrima", "Nirmala", "Gadugi", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo", "Leelawadee", "Microsoft JhengHei", "Malgun Gothic", "Estrangelo Edessa", "Microsoft Himalaya", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Tai Le", "Microsoft Yi Baiti", "Mongolian Baiti", "MV Boli", "Myanmar Text", "Javanese Text", "Cambria Math";
|
||||||
|
}
|
||||||
|
|
||||||
|
label.toggle-status:has(input:checked)::before {
|
||||||
|
content: "On";
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch>input:checked~.toggle-status::before {
|
||||||
|
content: "On";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Dark Mode */
|
||||||
|
|
||||||
|
.toggle-switch-dark {
|
||||||
|
border: 2px solid rgb(87, 29, 222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background-dark {
|
||||||
|
background-color: rgb(94, 43, 213);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input[type="checkbox"]:disabled:not(:checked)+.toggle-background-dark {
|
||||||
|
background-color: rgb(97, 69, 160);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input[type="checkbox"]:disabled:checked+.toggle-background-dark {
|
||||||
|
background-color: rgb(81, 81, 81);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input[type="checkbox"]:disabled~.toggle-switch-border-dark {
|
||||||
|
border-color: rgb(79, 26, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input[type="checkbox"]:disabled~.toggle-switch-dark {
|
||||||
|
border-color: rgb(79, 26, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:hover>input[type="checkbox"]:not(:disabled):not(:checked)+.toggle-background-dark {
|
||||||
|
background-color: rgb(120, 83, 207);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:active>input[type="checkbox"]:not(:disabled):not(:checked)+.toggle-background-dark {
|
||||||
|
background-color: rgb(143, 100, 244);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-border-dark {
|
||||||
|
border: 2px solid rgb(87, 29, 222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background-dark:after {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input:disabled+.toggle-background:after {
|
||||||
|
background-color: rgb(87, 29, 222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-background-dark:before {
|
||||||
|
background-color: rgb(70, 23, 181);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:hover>input:checked:not(:disabled)+.toggle-background:before {
|
||||||
|
background-color: rgb(90, 43, 202);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:active>input:checked:not(:disabled)+.toggle-background:before {
|
||||||
|
background-color: rgb(143, 100, 244);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark>input:checked:disabled+.toggle-background:before {
|
||||||
|
background-color: rgb(81, 81, 81);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:hover>input:checked:disabled+.toggle-background:before {
|
||||||
|
background-color: rgb(81, 81, 81);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch-dark:active>input:checked:disabled+.toggle-background:before {
|
||||||
|
background-color: rgb(81, 81, 81);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-status-dark:before {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
888
shared/html/libs/toggle/toggle.js
Normal file
888
shared/html/libs/toggle/toggle.js
Normal file
@@ -0,0 +1,888 @@
|
|||||||
|
(function(global) {
|
||||||
|
/**
|
||||||
|
* 检查 CSS 选择器是否重复(精确匹配)
|
||||||
|
* @param {string} targetSelector 要检查的目标选择器(如 ".toggle-switch>input[type="checkbox"]")
|
||||||
|
* @returns {number} 返回该选择器在样式表中的出现次数
|
||||||
|
*/
|
||||||
|
function checkSelectorDuplicate(targetSelector) {
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function traverseRules(rules) {
|
||||||
|
for (var i = 0; i < rules.length; i++) {
|
||||||
|
var rule = rules[i];
|
||||||
|
if (rule.type === 1) {
|
||||||
|
if (normalizeSelector(rule.selectorText) === normalizeSelector(targetSelector)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} else if (rule.type === 4 || rule.type === 12) {
|
||||||
|
var nestedRules = rule.cssRules || rule.rules;
|
||||||
|
if (nestedRules) traverseRules(nestedRules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sheets = document.styleSheets;
|
||||||
|
for (var i = 0; i < sheets.length; i++) {
|
||||||
|
try {
|
||||||
|
var rules = sheets[i].cssRules || sheets[i].rules;
|
||||||
|
if (rules) traverseRules(rules);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('无法读取跨域样式表:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSelector(selector) {
|
||||||
|
return selector
|
||||||
|
.replace(/\s*([>+~])\s*/g, '$1')
|
||||||
|
.replace(/\s{2,}/g, ' ')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 通过选择器移除匹配的 CSS 规则
|
||||||
|
* @param {string} targetSelector 要移除的目标选择器(如 ".toggle-switch>input[type="checkbox"]")
|
||||||
|
* @returns {number} 返回实际移除的规则数量
|
||||||
|
*/
|
||||||
|
function removeCSSRulesBySelector(targetSelector) {
|
||||||
|
var removedCount = 0;
|
||||||
|
|
||||||
|
function traverseAndRemove(rules) {
|
||||||
|
for (var i = rules.length - 1; i >= 0; i--) {
|
||||||
|
var rule = rules[i];
|
||||||
|
if (rule.type === 1) {
|
||||||
|
if (rule.selectorText === targetSelector) {
|
||||||
|
if (rules.removeRule) {
|
||||||
|
rules.removeRule(i);
|
||||||
|
} else {
|
||||||
|
rules.deleteRule(i);
|
||||||
|
}
|
||||||
|
removedCount++;
|
||||||
|
}
|
||||||
|
} else if (rule.type === 4 || rule.type === 12) {
|
||||||
|
var nestedRules = rule.cssRules || rule.rules;
|
||||||
|
if (nestedRules) {
|
||||||
|
traverseAndRemove(nestedRules);
|
||||||
|
if (nestedRules.length === 0) {
|
||||||
|
if (rules.removeRule) {
|
||||||
|
rules.removeRule(i);
|
||||||
|
} else {
|
||||||
|
rules.deleteRule(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sheets = document.styleSheets;
|
||||||
|
for (var i = 0; i < sheets.length; i++) {
|
||||||
|
try {
|
||||||
|
var rules = sheets[i].cssRules || sheets[i].rules;
|
||||||
|
if (rules) traverseAndRemove(rules);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('无法操作跨域样式表:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cssPool = {};
|
||||||
|
|
||||||
|
var strutil = Bridge.External.String;
|
||||||
|
var nstrutil = Bridge.NString;
|
||||||
|
var boolTrue = ["true", "1", "yes", "on", "y", "t", "zhen", "真"];
|
||||||
|
var boolFalse = ["false", "0", "no", "off", "n", "f", "jia", "假"];
|
||||||
|
|
||||||
|
function Toggle() {
|
||||||
|
this.element = null;
|
||||||
|
Object.defineProperty(this, "value", {
|
||||||
|
get: function() {
|
||||||
|
return this.getValue();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setValue(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "checked", {
|
||||||
|
get: function() {
|
||||||
|
return this.getValue();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setValue(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "disabled", {
|
||||||
|
get: function() {
|
||||||
|
return this.getDisabled();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setDisabled(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "showlabel", {
|
||||||
|
get: function() {
|
||||||
|
return this.isShowStatus();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.showStatus(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "darkMode", {
|
||||||
|
get: function() {
|
||||||
|
return this.isDarkMode();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setDarkMode(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "id", {
|
||||||
|
get: function() {
|
||||||
|
return this.getElementId();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setElementId(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "inputId", {
|
||||||
|
get: function() {
|
||||||
|
return this.getElementInputElementId();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setElementInputElementId(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "status", {
|
||||||
|
get: function() {
|
||||||
|
return this.getElementStatus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(this, "parent", {
|
||||||
|
get: function() {
|
||||||
|
return this.getParent();
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
this.setParent(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.create = function() {
|
||||||
|
this.element = document.createElement("label");
|
||||||
|
this.element.tabIndex = 0;
|
||||||
|
this.element.classList.add("toggle-switch");
|
||||||
|
this.element.id = "toggle-switch" + (new Date()).getTime() + Math.floor(Math.random() * 1000);
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "checkbox";
|
||||||
|
input.id = this.element.id + "-input";
|
||||||
|
this.element.addEventListener("keydown", function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var back = document.createElement("div");
|
||||||
|
back.classList.add("toggle-background");
|
||||||
|
var border = document.createElement("div");
|
||||||
|
border.classList.add("toggle-switch-border");
|
||||||
|
this.element.appendChild(input);
|
||||||
|
this.element.appendChild(back);
|
||||||
|
this.element.appendChild(border);
|
||||||
|
var status = document.createElement("span");
|
||||||
|
status.classList.add("toggle-status");
|
||||||
|
this.element.appendChild(status);
|
||||||
|
status.style.display = "none";
|
||||||
|
this.element.objController = this;
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.addEventListener = function(type, listener) {
|
||||||
|
this.element.addEventListener(type, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setParent = function(parent) {
|
||||||
|
if (parent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var parentNode = null;
|
||||||
|
if (parent instanceof HTMLElement) {
|
||||||
|
parentNode = parent;
|
||||||
|
} else if (typeof parent === "string" || parent instanceof String) {
|
||||||
|
parentNode = document.getElementById(parent);
|
||||||
|
if (!parentNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Invalid parent type:", parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(this.element instanceof Node)) {
|
||||||
|
console.error("this.element is not a Node:", this.element);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parentNode.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setValue = function(value) {
|
||||||
|
var input = this.element.getElementsByTagName("input")[0];
|
||||||
|
if (input === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseBool = function(str) {
|
||||||
|
str = "" + str;
|
||||||
|
for (var i = 0; i < boolTrue.length; i++) {
|
||||||
|
if (nstrutil.equals(str, boolTrue[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0; i < boolFalse.length; i++) {
|
||||||
|
if (nstrutil.equals(str, boolFalse[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
input.checked = parseBool(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.getValue = function() {
|
||||||
|
var input = this.element.getElementsByTagName("input")[0];
|
||||||
|
if (input === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return input.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setDisabled = function(disabled) {
|
||||||
|
var input = this.element.querySelector("input");
|
||||||
|
if (input === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input.disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.getDisabled = function() {
|
||||||
|
var input = this.element.querySelector("input");
|
||||||
|
if (input === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return input.disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.isAvailable = function() {
|
||||||
|
return this.element !== null;
|
||||||
|
}
|
||||||
|
Toggle.prototype.destroy = function() {
|
||||||
|
if (this.element !== null) {
|
||||||
|
if (this.element.remove) {
|
||||||
|
this.element.remove();
|
||||||
|
} else {
|
||||||
|
this.element.removeNode(true);
|
||||||
|
}
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Toggle.prototype.getElementId = function() {
|
||||||
|
if (this.element === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.element.id;
|
||||||
|
}
|
||||||
|
Toggle.prototype.setElementId = function(elementId) {
|
||||||
|
if (this.element === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.element.id = elementId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Toggle.prototype.getElement = function() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
Toggle.prototype.getElementInput = function() {
|
||||||
|
if (this.element === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.element.getElementsByTagName("input")[0];
|
||||||
|
}
|
||||||
|
Toggle.prototype.getElementInputElementId = function() {
|
||||||
|
var input = this.getElementInput();
|
||||||
|
if (input === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return input.id;
|
||||||
|
}
|
||||||
|
Toggle.prototype.setElementInputElementId = function(elementId) {
|
||||||
|
var input = this.getElementInput();
|
||||||
|
if (input === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
input.id = elementId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Toggle.prototype.getElementStatus = function() {
|
||||||
|
if (this.element === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.element.querySelector(".toggle-status");
|
||||||
|
}
|
||||||
|
Toggle.prototype.showStatus = function(show) {
|
||||||
|
var status = this.element.querySelector(".toggle-status");
|
||||||
|
if (status === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
status.style.display = "";
|
||||||
|
if (this.element) {
|
||||||
|
if (this.element.classList.contains("toggle-showstatus")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.element.classList.add("toggle-showstatus");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status.style.display = "none";
|
||||||
|
if (this.element) {
|
||||||
|
if (!this.element.classList.contains("toggle-showstatus")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.element.classList.remove("toggle-showstatus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Toggle.prototype.isShowStatus = function() {
|
||||||
|
return this.element.classList.contains("toggle-showstatus");
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setDarkMode = function(isDark) {
|
||||||
|
if (this.element === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var element = this.element;
|
||||||
|
var background = element.querySelector(".toggle-background");
|
||||||
|
var border = element.querySelector(".toggle-switch-border");
|
||||||
|
var status = element.querySelector(".toggle-status");
|
||||||
|
if (isDark) {
|
||||||
|
element.classList.add("toggle-switch-dark");
|
||||||
|
background.classList.add("toggle-background-dark");
|
||||||
|
border.classList.add("toggle-switch-border-dark");
|
||||||
|
status.classList.add("toggle-status-dark");
|
||||||
|
} else {
|
||||||
|
element.classList.remove("toggle-dark");
|
||||||
|
background.classList.remove("toggle-background-dark");
|
||||||
|
border.classList.remove("toggle-switch-border-dark");
|
||||||
|
status.classList.remove("toggle-status-dark");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.isDarkMode = function() {
|
||||||
|
if (this.element === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.element.classList.contains("toggle-switch-dark");
|
||||||
|
}
|
||||||
|
|
||||||
|
function ColorStringToRGBA(input) {
|
||||||
|
var str = input.replace(/\s+/g, '').toLowerCase();
|
||||||
|
|
||||||
|
function hexToRgba(hex) {
|
||||||
|
hex = hex.slice(1);
|
||||||
|
if (hex.length === 3 || hex.length === 4) {
|
||||||
|
hex = hex.split('').map(function(c) { return c + c; }).join('');
|
||||||
|
}
|
||||||
|
var r = parseInt(hex.substr(0, 2), 16);
|
||||||
|
var g = parseInt(hex.substr(2, 2), 16);
|
||||||
|
var b = parseInt(hex.substr(4, 2), 16);
|
||||||
|
var a = hex.length === 8 ? parseInt(hex.substr(6, 2), 16) / 255 : 1;
|
||||||
|
return { r: r, g: g, b: b, a: a };
|
||||||
|
}
|
||||||
|
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
h = (h % 360 + 360) % 360 / 360;
|
||||||
|
s = Math.max(0, Math.min(1, s));
|
||||||
|
l = Math.max(0, Math.min(1, l));
|
||||||
|
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
|
||||||
|
var m1 = 2 * l - m2;
|
||||||
|
|
||||||
|
function hueToRgb(m1, m2, hK) {
|
||||||
|
if (hK < 0) hK += 1;
|
||||||
|
if (hK > 1) hK -= 1;
|
||||||
|
if (hK * 6 < 1) return m1 + (m2 - m1) * 6 * hK;
|
||||||
|
if (hK * 2 < 1) return m2;
|
||||||
|
if (hK * 3 < 2) return m1 + (m2 - m1) * (2 / 3 - hK) * 6;
|
||||||
|
return m1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
r: Math.round(hueToRgb(m1, m2, h + 1 / 3) * 255),
|
||||||
|
g: Math.round(hueToRgb(m1, m2, h) * 255),
|
||||||
|
b: Math.round(hueToRgb(m1, m2, h - 1 / 3) * 255),
|
||||||
|
a: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFunc(func, vals) {
|
||||||
|
var arr = vals.split(',');
|
||||||
|
if (/^hsl/.test(func)) {
|
||||||
|
var h = parseFloat(arr[0]);
|
||||||
|
var s = parseFloat(arr[1]) / 100;
|
||||||
|
var l = parseFloat(arr[2]) / 100;
|
||||||
|
var alpha = arr[3] !== undefined ? (arr[3].indexOf('%') > -1 ? parseFloat(arr[3]) / 100 : parseFloat(arr[3])) : 1;
|
||||||
|
var rgb = hslToRgb(h, s, l);
|
||||||
|
rgb.a = alpha;
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
var out = arr.slice(0, 3).map(function(v, i) {
|
||||||
|
if (v.indexOf('%') > -1) return Math.round(parseFloat(v) / 100 * 255);
|
||||||
|
return Math.round(parseFloat(v));
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
r: out[0],
|
||||||
|
g: out[1],
|
||||||
|
b: out[2],
|
||||||
|
a: arr[3] !== undefined ? (arr[3].indexOf('%') > -1 ? parseFloat(arr[3]) / 100 : parseFloat(arr[3])) : 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function hwbToRgb(h, w, b, a) {
|
||||||
|
var rgb = hslToRgb(h, 1, 0.5);
|
||||||
|
w = Math.max(0, Math.min(1, w));
|
||||||
|
b = Math.max(0, Math.min(1, b));
|
||||||
|
var sum = w + b;
|
||||||
|
if (sum > 1) {
|
||||||
|
var gray = w / sum;
|
||||||
|
return { r: Math.round(gray * 255), g: Math.round(gray * 255), b: Math.round(gray * 255), a: a };
|
||||||
|
}
|
||||||
|
var factor = 1 - w - b;
|
||||||
|
return {
|
||||||
|
r: Math.round((rgb.r / 255 * factor + w) * 255),
|
||||||
|
g: Math.round((rgb.g / 255 * factor + w) * 255),
|
||||||
|
b: Math.round((rgb.b / 255 * factor + w) * 255),
|
||||||
|
a: a
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRGBString(rgbString) {
|
||||||
|
var m = /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d*\.?\d+))?\)/.exec(rgbString);
|
||||||
|
if (m) {
|
||||||
|
return { r: +m[1], g: +m[2], b: +m[3], a: m[4] !== undefined ? +m[4] : 1 };
|
||||||
|
}
|
||||||
|
return { r: 0, g: 0, b: 0, a: 0 };
|
||||||
|
}
|
||||||
|
var m;
|
||||||
|
if ((m = /^#([0-9a-f]{3,8})$/.exec(str))) {
|
||||||
|
return hexToRgba(m[0]);
|
||||||
|
}
|
||||||
|
if ((m = /^(rgba?|hsla?)\((.+)\)$/.exec(str))) {
|
||||||
|
return parseFunc(m[1], m[2]);
|
||||||
|
}
|
||||||
|
if ((m = /^(hwb)a?\((.+)\)$/.exec(str))) {
|
||||||
|
var parts = m[2].split(',');
|
||||||
|
var h = parseFloat(parts[0]);
|
||||||
|
var w0 = parseFloat(parts[1]) / 100;
|
||||||
|
var b0 = parseFloat(parts[2]) / 100;
|
||||||
|
var a0 = parts[3] !== undefined ? (parts[3].indexOf('%') > -1 ? parseFloat(parts[3]) / 100 : parseFloat(parts[3])) : 1;
|
||||||
|
return hwbToRgb(h, w0, b0, a0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.style.color = input;
|
||||||
|
document.body.appendChild(div);
|
||||||
|
var css = window.getComputedStyle(div).color;
|
||||||
|
document.body.removeChild(div);
|
||||||
|
return parseRGBString(css);
|
||||||
|
} catch (e) {
|
||||||
|
return { r: 0, g: 0, b: 0, a: 0 };
|
||||||
|
}
|
||||||
|
return { r: 0, g: 0, b: 0, a: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function ColorRGBToString(color) {
|
||||||
|
return "#" + ((1 << 24) + (color.r << 16) + (color.g << 8) + color.b).toString(16).slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ColorRGBToHex(color) {
|
||||||
|
return "" + ((1 << 24) + (color.r << 16) + (color.g << 8) + color.b).toString(16).slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CalcLightHoverColor(_obj_rgb_) {
|
||||||
|
function rgbToHsl(r, g, b) {
|
||||||
|
r /= 255, g /= 255, b /= 255;
|
||||||
|
var max = Math.max(r, g, b),
|
||||||
|
min = Math.min(r, g, b);
|
||||||
|
var h, s, l = (max + min) / 2;
|
||||||
|
if (max == min) {
|
||||||
|
h = s = 0;
|
||||||
|
} else {
|
||||||
|
var d = max - min;
|
||||||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||||
|
switch (max) {
|
||||||
|
case r:
|
||||||
|
h = (g - b) / d + (g < b ? 6 : 0);
|
||||||
|
break;
|
||||||
|
case g:
|
||||||
|
h = (b - r) / d + 2;
|
||||||
|
break;
|
||||||
|
case b:
|
||||||
|
h = (r - g) / d + 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
h /= 6;
|
||||||
|
}
|
||||||
|
return [h * 360, s * 100, l * 100];
|
||||||
|
}
|
||||||
|
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
h = (h % 360) / 360;
|
||||||
|
s /= 100;
|
||||||
|
l /= 100;
|
||||||
|
var r, g, b;
|
||||||
|
if (s == 0) {
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
function hue2rgb(p, q, t) {
|
||||||
|
if (t < 0) t += 1;
|
||||||
|
if (t > 1) t -= 1;
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||||
|
if (t < 1 / 2) return q;
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
var p = 2 * l - q;
|
||||||
|
r = hue2rgb(p, q, h + 1 / 3);
|
||||||
|
g = hue2rgb(p, q, h);
|
||||||
|
b = hue2rgb(p, q, h - 1 / 3);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
Math.round(r * 255),
|
||||||
|
Math.round(g * 255),
|
||||||
|
Math.round(b * 255)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
var hsl = rgbToHsl(_obj_rgb_.r, _obj_rgb_.g, _obj_rgb_.b);
|
||||||
|
hsl[2] = Math.min(98, hsl[2] + 12);
|
||||||
|
var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
r: rgb[0],
|
||||||
|
g: rgb[1],
|
||||||
|
b: rgb[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function CalcLightActiveColor(_obj_rgb_) {
|
||||||
|
function rgbToHsl(r, g, b) {
|
||||||
|
r /= 255, g /= 255, b /= 255;
|
||||||
|
var max = Math.max(r, g, b),
|
||||||
|
min = Math.min(r, g, b);
|
||||||
|
var h, s, l = (max + min) / 2;
|
||||||
|
if (max === min) {
|
||||||
|
h = s = 0;
|
||||||
|
} else {
|
||||||
|
var d = max - min;
|
||||||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||||
|
switch (max) {
|
||||||
|
case r:
|
||||||
|
h = (g - b) / d + (g < b ? 6 : 0);
|
||||||
|
break;
|
||||||
|
case g:
|
||||||
|
h = (b - r) / d + 2;
|
||||||
|
break;
|
||||||
|
case b:
|
||||||
|
h = (r - g) / d + 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
h /= 6;
|
||||||
|
}
|
||||||
|
return [h * 360, s * 100, l * 100];
|
||||||
|
}
|
||||||
|
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
h = (h % 360) / 360;
|
||||||
|
s /= 100;
|
||||||
|
l /= 100;
|
||||||
|
var r, g, b;
|
||||||
|
if (s === 0) {
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
function hue2rgb(p, q, t) {
|
||||||
|
if (t < 0) t += 1;
|
||||||
|
if (t > 1) t -= 1;
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||||
|
if (t < 1 / 2) return q;
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
var p = 2 * l - q;
|
||||||
|
r = hue2rgb(p, q, h + 1 / 3);
|
||||||
|
g = hue2rgb(p, q, h);
|
||||||
|
b = hue2rgb(p, q, h - 1 / 3);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
Math.round(r * 255),
|
||||||
|
Math.round(g * 255),
|
||||||
|
Math.round(b * 255)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
var hsl = rgbToHsl(_obj_rgb_.r, _obj_rgb_.g, _obj_rgb_.b);
|
||||||
|
hsl[2] = hsl[2] < 50 ?
|
||||||
|
hsl[2] * 1.6 :
|
||||||
|
hsl[2] + (100 - hsl[2]) * 0.3;
|
||||||
|
hsl[1] = hsl[1] < 80 ?
|
||||||
|
hsl[1] * 1.3 :
|
||||||
|
Math.min(100, hsl[1] + 15);
|
||||||
|
hsl[2] = Math.min(95, Math.max(5, hsl[2]));
|
||||||
|
hsl[1] = Math.min(100, Math.max(0, hsl[1]));
|
||||||
|
var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||||
|
return { r: rgb[0], g: rgb[1], b: rgb[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetLightCSSString(_string_selector_, _obj_rgb_) {
|
||||||
|
var hover = CalcLightHoverColor(_obj_rgb_);
|
||||||
|
var active = CalcLightActiveColor(_obj_rgb_);
|
||||||
|
var background = _string_selector_ + "-background";
|
||||||
|
var css = "";
|
||||||
|
css += "." + background + ":before" + " {" +
|
||||||
|
"background-color: " + ColorRGBToString(_obj_rgb_) + ";" +
|
||||||
|
"}\n";
|
||||||
|
css += ".toggle-switch:hover>input:checked:not(:disabled)+." + background + ":before {" +
|
||||||
|
"background-color: " + ColorRGBToString(hover) + ";" +
|
||||||
|
"}\n";
|
||||||
|
css += ".toggle-switch:active>input:checked:not(:disabled)+." + background + ":before {" +
|
||||||
|
"background-color: " + ColorRGBToString(active) + ";" +
|
||||||
|
"}\n";
|
||||||
|
return css;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetDarkCSSString(_string_selector_, _obj_rgb_) {
|
||||||
|
function rgbToHsl(r, g, b) {
|
||||||
|
r /= 255;
|
||||||
|
g /= 255;
|
||||||
|
b /= 255;
|
||||||
|
var max = Math.max(r, g, b),
|
||||||
|
min = Math.min(r, g, b),
|
||||||
|
h, s, l = (max + min) / 2;
|
||||||
|
if (max === min) {
|
||||||
|
h = s = 0;
|
||||||
|
} else {
|
||||||
|
var d = max - min;
|
||||||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||||
|
switch (max) {
|
||||||
|
case r:
|
||||||
|
h = ((g - b) / d + (g < b ? 6 : 0));
|
||||||
|
break;
|
||||||
|
case g:
|
||||||
|
h = ((b - r) / d + 2);
|
||||||
|
break;
|
||||||
|
case b:
|
||||||
|
h = ((r - g) / d + 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
h /= 6;
|
||||||
|
}
|
||||||
|
return { h: h * 360, s: s * 100, l: l * 100 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
s /= 100;
|
||||||
|
l /= 100;
|
||||||
|
h /= 360;
|
||||||
|
|
||||||
|
function hue2rgb(p, q, t) {
|
||||||
|
if (t < 0) t += 1;
|
||||||
|
if (t > 1) t -= 1;
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||||
|
if (t < 1 / 2) return q;
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
var r, g, b;
|
||||||
|
if (!s) {
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
var p = 2 * l - q;
|
||||||
|
r = hue2rgb(p, q, h + 1 / 3);
|
||||||
|
g = hue2rgb(p, q, h);
|
||||||
|
b = hue2rgb(p, q, h - 1 / 3);
|
||||||
|
}
|
||||||
|
return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
|
||||||
|
}
|
||||||
|
|
||||||
|
function clamp(v, min, max) {
|
||||||
|
return v < min ? min : (v > max ? max : v);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ColorRGBToString(c) {
|
||||||
|
return "rgb(" + c.r + ", " + c.g + ", " + c.b + ")";
|
||||||
|
}
|
||||||
|
var hsl = rgbToHsl(_obj_rgb_.r, _obj_rgb_.g, _obj_rgb_.b);
|
||||||
|
var borderRGB = hslToRgb(hsl.h, hsl.s, clamp(hsl.l + 15, 0, 100));
|
||||||
|
var backgroundRGB = hslToRgb(hsl.h, clamp(hsl.s * 0.9, 0, 100), clamp(hsl.l + 12, 0, 100));
|
||||||
|
var disabledBgRGB = hslToRgb(hsl.h, clamp(hsl.s * 0.6, 0, 100), clamp(hsl.l + 5, 0, 100));
|
||||||
|
var disabledBrdRGB = hslToRgb(hsl.h, hsl.s, clamp(hsl.l + 5, 0, 100));
|
||||||
|
var hoverBgRGB = hslToRgb(hsl.h, clamp(hsl.s * 0.8, 0, 100), clamp(hsl.l + 25, 0, 100));
|
||||||
|
var activeBgRGB = hslToRgb(hsl.h, clamp(hsl.s * 1.1, 0, 100), clamp(hsl.l + 35, 0, 100));
|
||||||
|
var hoverChecked = CalcLightHoverColor(_obj_rgb_);
|
||||||
|
var activeChecked = CalcLightActiveColor(_obj_rgb_);
|
||||||
|
var base = _string_selector_;
|
||||||
|
var bgClass = base + "-background";
|
||||||
|
var brClass = base + "-border";
|
||||||
|
var css = "";
|
||||||
|
css += "." + base + " { border-color: " + ColorRGBToString(borderRGB) + "; }\n";
|
||||||
|
css += "." + bgClass + " { background-color: " + ColorRGBToString(backgroundRGB) + "; }\n";
|
||||||
|
css += "." + base + ">input[type=\"checkbox\"]:disabled:not(:checked)+." + bgClass +
|
||||||
|
" { background-color: " + ColorRGBToString(disabledBgRGB) + "; }\n";
|
||||||
|
css += "." + base + ">input[type=\"checkbox\"]:disabled~." + brClass + "," +
|
||||||
|
"." + base + ">input[type=\"checkbox\"]:disabled~." + base + "-switch" +
|
||||||
|
" { border-color: " + ColorRGBToString(disabledBrdRGB) + "; }\n";
|
||||||
|
css += "." + base + ":hover>input[type=\"checkbox\"]:not(:disabled):not(:checked)+." + bgClass +
|
||||||
|
" { background-color: " + ColorRGBToString(hoverBgRGB) + "; }\n";
|
||||||
|
css += "." + base + ":active>input[type=\"checkbox\"]:not(:disabled):not(:checked)+." + bgClass +
|
||||||
|
" { background-color: " + ColorRGBToString(activeBgRGB) + "; }\n";
|
||||||
|
css += "." + brClass + " { border-color:" + ColorRGBToString(borderRGB) + "; }\n";
|
||||||
|
css += "." + base + ">input:disabled+." + base + "-background:after" +
|
||||||
|
" { background-color: " + ColorRGBToString(borderRGB) + "; }\n";
|
||||||
|
css += "." + bgClass + ":before { background-color: " + ColorRGBToString(_obj_rgb_) + "; }\n";
|
||||||
|
css += "." + base + ":hover>input:checked:not(:disabled)+." + bgClass + ":before" +
|
||||||
|
" { background-color: " + ColorRGBToString(hoverChecked) + "; }\n";
|
||||||
|
css += "." + base + ":active>input:checked:not(:disabled)+." + bgClass + ":before" +
|
||||||
|
" { background-color: " + ColorRGBToString(activeChecked) + "; }\n";
|
||||||
|
return css;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setDarkMode = function(dark) {
|
||||||
|
var element = this.element;
|
||||||
|
if (this.isDarkMode === dark) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var background = element.querySelector(".toggle-background");
|
||||||
|
var border = element.querySelector(".toggle-switch-border");
|
||||||
|
var status = element.querySelector(".toggle-status");
|
||||||
|
if (this.color) {
|
||||||
|
var label = ColorRGBToHex(this.color);
|
||||||
|
var uniid = "toggle-theme-" + label;
|
||||||
|
var uniidlight = uniid + "-light";
|
||||||
|
var uniiddark = uniid + "-dark";
|
||||||
|
}
|
||||||
|
if (this.element === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dark) {
|
||||||
|
element.classList.add("toggle-switch-dark");
|
||||||
|
background.classList.add("toggle-background-dark");
|
||||||
|
border.classList.add("toggle-switch-border-dark");
|
||||||
|
status.classList.add("toggle-status-dark");
|
||||||
|
if (this.color) {
|
||||||
|
element.classList.add(uniiddark);
|
||||||
|
background.classList.add(uniiddark + "-background");
|
||||||
|
border.classList.add(uniiddark + "-border");
|
||||||
|
element.classList.remove(uniidlight);
|
||||||
|
background.classList.remove(uniidlight + "-background");
|
||||||
|
border.classList.remove(uniidlight + "-border");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element.classList.remove("toggle-dark");
|
||||||
|
background.classList.remove("toggle-background-dark");
|
||||||
|
border.classList.remove("toggle-switch-border-dark");
|
||||||
|
status.classList.remove("toggle-status-dark");
|
||||||
|
if (this.color) {
|
||||||
|
element.classList.remove(uniiddark);
|
||||||
|
background.classList.remove(uniiddark + "-background");
|
||||||
|
border.classList.remove(uniiddark + "-border");
|
||||||
|
element.classList.add(uniidlight);
|
||||||
|
background.classList.add(uniidlight + "-background");
|
||||||
|
border.classList.add(uniidlight + "-border");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.setColor = function(color) {
|
||||||
|
var rgb = ColorStringToRGBA(color);
|
||||||
|
this.color = rgb;
|
||||||
|
var label = ColorRGBToHex(rgb);
|
||||||
|
var uniid = "toggle-theme-" + label;
|
||||||
|
var uniidlight = uniid + "-light";
|
||||||
|
var uniiddark = uniid + "-dark";
|
||||||
|
if (cssPool[uniid] === undefined || cssPool[uniid] === null) {
|
||||||
|
cssPool[uniid] = {
|
||||||
|
light: uniidlight,
|
||||||
|
dark: uniiddark,
|
||||||
|
count: 1,
|
||||||
|
}
|
||||||
|
var lightCSS = GetLightCSSString(uniidlight, rgb);
|
||||||
|
var darkCSS = GetDarkCSSString(uniiddark, rgb);
|
||||||
|
var style = document.createElement("style");
|
||||||
|
style.type = "text/css";
|
||||||
|
style.id = uniid;
|
||||||
|
style.innerHTML = "/* Light Theme */\n" + lightCSS + "\n/* Dark Theme */\n" + darkCSS;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
cssPool[uniid].style = style;
|
||||||
|
} else {
|
||||||
|
cssPool[uniid].count++;
|
||||||
|
}
|
||||||
|
var dark = this.isDarkMode();
|
||||||
|
this.setDarkMode(!dark);
|
||||||
|
this.setDarkMode(dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.dispose = function() {
|
||||||
|
if (this.element) {
|
||||||
|
removeElement(this.element);
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
if (this.color) {
|
||||||
|
var label = ColorRGBToHex(this.color);
|
||||||
|
var uniid = "toggle-theme-" + label;
|
||||||
|
var ucss = cssPool[uniid];
|
||||||
|
if (ucss) {
|
||||||
|
ucss.count--;
|
||||||
|
if (ucss.count <= 0) {
|
||||||
|
removeElement(ucss.style);
|
||||||
|
delete cssPool[uniid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.color = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Toggle.prototype.destroy = Toggle.prototype.dispose;
|
||||||
|
|
||||||
|
Toggle.prototype.setStatusText = function(onText, offText) {
|
||||||
|
/**
|
||||||
|
* 动态插入一段 CSS 文本到页面 <head> 中
|
||||||
|
* @param {string} cssText - 要插入的完整 CSS 文本,如 "body{background:red;}"
|
||||||
|
* @param {string} [id] - 可选,为 <style> 元素指定 id,方便后面删除
|
||||||
|
*/
|
||||||
|
function addCssText(cssText, id) {
|
||||||
|
var head = document.head || document.getElementsByTagName('head')[0];
|
||||||
|
var style = document.createElement('style');
|
||||||
|
|
||||||
|
if (id) style.id = id;
|
||||||
|
style.type = 'text/css';
|
||||||
|
|
||||||
|
// 对 IE8- 兼容:style.styleSheet.cssText;其他浏览器用 textNode
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = cssText; // :contentReference[oaicite:0]{index=0}
|
||||||
|
} else {
|
||||||
|
style.appendChild(document.createTextNode(cssText));
|
||||||
|
}
|
||||||
|
head.appendChild(style);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 根据 id 移除之前插入的 <style> 标签
|
||||||
|
* @param {string} id - addCssText 时指定的 id
|
||||||
|
*/
|
||||||
|
function removeCssById(id) {
|
||||||
|
var style = document.getElementById(id);
|
||||||
|
if (style && style.parentNode) {
|
||||||
|
style.parentNode.removeChild(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeCssById("toggle-status-lang");
|
||||||
|
var status = this.element.querySelector(".toggle-status");
|
||||||
|
var csstext = ".toggle-status-lang:before { content: \"" + offText + "\"; }\n";
|
||||||
|
csstext += "label.toggle-status-lang:has(input:checked)::before { content: \"" + onText + "\"; }\n";
|
||||||
|
csstext += ".toggle-switch>input:checked~.toggle-status-lang::before { content: \"" + onText + "\"; }\n";
|
||||||
|
addCssText(csstext, "toggle-status-lang");
|
||||||
|
status.classList.add("toggle-status-lang");
|
||||||
|
}
|
||||||
|
global.Toggle = Toggle;
|
||||||
|
})(this);
|
||||||
60
shared/html/settings/appinstaller/about.html
Normal file
60
shared/html/settings/appinstaller/about.html
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>App Installer Settings</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script type="text/javascript" src="../../js/module.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/polyfill-ie.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../libs/winjs/2.0/css/ui-light.css" id="winjs-style">
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/base.js"></script>
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/ui.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/color.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/promise.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/bridge.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/dpimodes.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/resources.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/animation.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||||
|
<script type="text/javascript" src="../../js/event.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/tileback.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/load.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../libs/msgbox/msgbox.css">
|
||||||
|
<script type="text/javascript" src="../../libs/msgbox/msgbox.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/init.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../page.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../subpage.css">
|
||||||
|
<script type="text/javascript" src="preinit.js"></script>
|
||||||
|
<script type="text/javascript" src="initsame.js"></script>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
window.parent.setItemHighlight("about");
|
||||||
|
} catch (e) {}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="pagecontainer full pagesection">
|
||||||
|
<div class="section padding">
|
||||||
|
<h2 data-res-fromfile="publicRes(124)"></h2>
|
||||||
|
<p data-res-fromfile="getFileResPair(exepath, 300)"></p>
|
||||||
|
<p style="white-space: pre-wrap;"><span data-res-fromfile="publicRes (130)"></span>	<span id="current-version"></span></p>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
var storage = Bridge.External.Storage;
|
||||||
|
var path = storage.path;
|
||||||
|
var versionFilePath = path.combine(path.root, "version");
|
||||||
|
var versionFile = storage.getFile(versionFilePath);
|
||||||
|
window.currver = versionFile.content;
|
||||||
|
} catch (e) {
|
||||||
|
window.currver = "0.0.0.1";
|
||||||
|
}
|
||||||
|
document.getElementById("current-version").textContent = window.currver;
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>App Installer Settings</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script type="text/javascript" src="../../js/module.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/polyfill-ie.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../libs/winjs/2.0/css/ui-light.css" id="winjs-style">
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/base.js"></script>
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/ui.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/color.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/promise.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/bridge.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/dpimodes.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/resources.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/animation.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||||
|
<script type="text/javascript" src="../../js/event.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/tileback.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/load.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../libs/msgbox/msgbox.css">
|
||||||
|
<script type="text/javascript" src="../../libs/msgbox/msgbox.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../libs/toggle/toggle.css">
|
||||||
|
<script type="text/javascript" src="../../libs/toggle/toggle.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/init.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../page.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../subpage.css">
|
||||||
|
<script type="text/javascript" src="preinit.js"></script>
|
||||||
|
<script type="text/javascript" src="initsame.js"></script>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
window.parent.setItemHighlight("general");
|
||||||
|
} catch (e) {}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="pagecontainer full pagesection">
|
||||||
|
<div class="section padding">
|
||||||
|
<h2 id="page-title" data-res-fromfile="publicRes (101)"></h2>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label class="win-label" for="save-wnd-size" id="save-wnd-size-label" data-res-fromfile="publicRes (125)"></label>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var label = document.getElementById("save-wnd-size-label");
|
||||||
|
var toggle = new Toggle();
|
||||||
|
toggle.create();
|
||||||
|
toggle.parent = label.parentNode;
|
||||||
|
toggle.showlabel = true;
|
||||||
|
var winjsres = Bridge.External.WinJsStringRes;
|
||||||
|
toggle.setStatusText(winjsres.getString("ms-resource://Microsoft.WinJS.1.0/ui/on"), winjsres.getString("ms-resource://Microsoft.WinJS.1.0/ui/off"));
|
||||||
|
toggle.inputId = "save-wnd-size";
|
||||||
|
var ini = Bridge.External.Config.GetConfig();
|
||||||
|
toggle.addEventListener("change", function() {
|
||||||
|
ini.set("Settings", "AppInstaller:SavePosAndSizeBeforeCancel", toggle.checked);
|
||||||
|
});
|
||||||
|
toggle.checked = parseBool(ini.getSection("Settings").getKey("AppInstaller:SavePosAndSizeBeforeCancel").value);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label class="win-label" for="default-wndwidth" data-res-fromfile="publicRes(126)"></label><br>
|
||||||
|
<input type="number" id="default-wndwidth" inputmode="numeric"><br><br>
|
||||||
|
<label class="win-label" for="default-wndheight" data-res-fromfile="publicRes(127)"></label><br>
|
||||||
|
<input type="number" id="default-wndheight" inputmode="numeric">
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var ini = Bridge.External.Config.GetConfig();
|
||||||
|
var defWndWInput = document.getElementById("default-wndwidth");
|
||||||
|
var defWndHInput = document.getElementById("default-wndheight");
|
||||||
|
var setsect = ini.getSection("Settings");
|
||||||
|
var defwk = setsect.getKey("AppInstaller:DefaultWidth");
|
||||||
|
var defhk = setsect.getKey("AppInstaller:DefaultHeight");
|
||||||
|
defWndWInput.value = defwk.value;
|
||||||
|
defWndHInput.value = defhk.value;
|
||||||
|
var eventutil = Windows.UI.Event.Util;
|
||||||
|
|
||||||
|
function inputDefaultWidthChangeEvent(e) {
|
||||||
|
defwk.value = parseInt(defWndWInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputDefaultHeightChangeEvent(e) {
|
||||||
|
defhk.value = parseInt(defWndHInput.value);
|
||||||
|
}
|
||||||
|
var debounced_idwc = debounce(inputDefaultWidthChangeEvent, 500);
|
||||||
|
var debounced_idhc = debounce(inputDefaultHeightChangeEvent, 500);
|
||||||
|
eventutil.addEvent(defWndWInput, "input", debounced_idwc);
|
||||||
|
eventutil.addEvent(defWndWInput, "propertychange", debounced_idwc);
|
||||||
|
eventutil.addEvent(defWndWInput, "change", debounced_idwc);
|
||||||
|
eventutil.addEvent(defWndHInput, "input", debounced_idhc);
|
||||||
|
eventutil.addEvent(defWndHInput, "propertychange", debounced_idhc);
|
||||||
|
eventutil.addEvent(defWndHInput, "change", debounced_idhc);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label class="win-label" for="min-wndwidth" data-res-fromfile="publicRes (128)"></label><br>
|
||||||
|
<input type="number" id="min-wndwidth" inputmode="numeric"><br><br>
|
||||||
|
<label class="win-label" for="min-wndheight" data-res-fromfile="publicRes (129)"></label><br>
|
||||||
|
<input type="number" id="min-wndheight" inputmode="numeric">
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var ini = Bridge.External.Config.GetConfig();
|
||||||
|
var minWndWInput = document.getElementById("min-wndwidth");
|
||||||
|
var minWndHInput = document.getElementById("min-wndheight");
|
||||||
|
var setsect = ini.getSection("Settings");
|
||||||
|
var minwk = setsect.getKey("AppInstaller:MinimumWidth");
|
||||||
|
var minhk = setsect.getKey("AppInstaller:MinimumHeight");
|
||||||
|
minWndWInput.value = minwk.value;
|
||||||
|
minWndHInput.value = minhk.value;
|
||||||
|
var eventutil = Windows.UI.Event.Util;
|
||||||
|
|
||||||
|
function inputDefaultWidthChangeEvent(e) {
|
||||||
|
minwk.value = parseInt(minWndWInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputDefaultHeightChangeEvent(e) {
|
||||||
|
minhk.value = parseInt(minWndHInput.value);
|
||||||
|
}
|
||||||
|
var debounced_idwc = debounce(inputDefaultWidthChangeEvent, 500);
|
||||||
|
var debounced_idhc = debounce(inputDefaultHeightChangeEvent, 500);
|
||||||
|
eventutil.addEvent(minWndWInput, "input", debounced_idwc);
|
||||||
|
eventutil.addEvent(minWndWInput, "propertychange", debounced_idwc);
|
||||||
|
eventutil.addEvent(minWndWInput, "change", debounced_idwc);
|
||||||
|
eventutil.addEvent(minWndHInput, "input", debounced_idhc);
|
||||||
|
eventutil.addEvent(minWndHInput, "propertychange", debounced_idhc);
|
||||||
|
eventutil.addEvent(minWndHInput, "change", debounced_idhc);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label class="win-label" for="launch-when-ready" id="launch-when-ready-label" data-res-fromfile="getFileResPair(exepath, 330)"></label>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var label = document.getElementById("launch-when-ready-label");
|
||||||
|
var toggle = new Toggle();
|
||||||
|
toggle.create();
|
||||||
|
toggle.parent = label.parentNode;
|
||||||
|
toggle.showlabel = true;
|
||||||
|
var winjsres = Bridge.External.WinJsStringRes;
|
||||||
|
toggle.setStatusText(winjsres.getString("ms-resource://Microsoft.WinJS.1.0/ui/on"), winjsres.getString("ms-resource://Microsoft.WinJS.1.0/ui/off"));
|
||||||
|
toggle.inputId = "launch-when-ready";
|
||||||
|
var ini = Bridge.External.Config.GetConfig();
|
||||||
|
toggle.addEventListener("change", function() {
|
||||||
|
ini.set("Settings", "AppInstaller:LaunchWhenReady", toggle.checked);
|
||||||
|
});
|
||||||
|
toggle.checked = parseBool(ini.getSection("Settings").getKey("AppInstaller:LaunchWhenReady").value);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -28,6 +28,11 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="../subpage.css">
|
<link rel="stylesheet" type="text/css" href="../subpage.css">
|
||||||
<script type="text/javascript" src="preinit.js"></script>
|
<script type="text/javascript" src="preinit.js"></script>
|
||||||
<script type="text/javascript" src="initsame.js"></script>
|
<script type="text/javascript" src="initsame.js"></script>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
window.parent.setItemHighlight("guide");
|
||||||
|
} catch (e) {}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
}, 50);
|
}, 50);
|
||||||
var content = guide.querySelector(".main");
|
var content = guide.querySelector(".main");
|
||||||
var list = slide.querySelector("ul");
|
var list = slide.querySelector("ul");
|
||||||
|
var backbtn = slide.querySelector("#back");
|
||||||
|
var title = slide.querySelector("#apptitle");
|
||||||
list.innerHTML = "";
|
list.innerHTML = "";
|
||||||
var items = pages;
|
var items = pages;
|
||||||
var tags = Object.keys(items);
|
var tags = Object.keys(items);
|
||||||
@@ -21,8 +23,10 @@
|
|||||||
var item = items[tag];
|
var item = items[tag];
|
||||||
var li = document.createElement("li");
|
var li = document.createElement("li");
|
||||||
li.setAttribute("data-page", item.page);
|
li.setAttribute("data-page", item.page);
|
||||||
|
li.setAttribute("data-tag", item.tag);
|
||||||
li.innerHTML = item.title;
|
li.innerHTML = item.title;
|
||||||
eventutil.addEvent(li, "click", function() {
|
eventutil.addEvent(li, "click", function() {
|
||||||
|
if (li.hasAttribute("data-require-disabled")) return;
|
||||||
content.style.display = "none";
|
content.style.display = "none";
|
||||||
for (var j = 0; j < list.children.length; j++) {
|
for (var j = 0; j < list.children.length; j++) {
|
||||||
var child = list.children[j];
|
var child = list.children[j];
|
||||||
@@ -32,13 +36,42 @@
|
|||||||
content.src = this.getAttribute("data-page");
|
content.src = this.getAttribute("data-page");
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
content.style.display = "";
|
content.style.display = "";
|
||||||
Windows.UI.Animation.runAsync(content, Windows.UI.Animation.Keyframes.SlideInFromBottom);
|
Windows.UI.Animation.runAsync(content, [Windows.UI.Animation.Keyframes.Flyout.toLeft, Windows.UI.Animation.Keyframes.Opacity.visible]);
|
||||||
}, 0);
|
}, 0);
|
||||||
this.classList.add("selected");
|
this.classList.add("selected");
|
||||||
});
|
});
|
||||||
list.appendChild(li);
|
list.appendChild(li);
|
||||||
}
|
}
|
||||||
content.src = guidePage.page;
|
content.src = guidePage.page;
|
||||||
|
global.setDisabledForOperation = function(disabled) {
|
||||||
|
var list = document.querySelector("#settingpage .guide aside ul");
|
||||||
|
for (var i = 0; i < list.children.length; i++) {
|
||||||
|
var child = list.children[i];
|
||||||
|
if (disabled) {
|
||||||
|
child.setAttribute("data-require-disabled", "true");
|
||||||
|
} else {
|
||||||
|
child.removeAttribute("data-require-disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (disabled) {
|
||||||
|
backbtn.disabled = true;
|
||||||
|
title.style.marginLeft = backbtn.style.marginLeft;
|
||||||
|
} else {
|
||||||
|
backbtn.disabled = false;
|
||||||
|
title.style.marginLeft = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global.setItemHighlight = function(tag) {
|
||||||
|
var list = document.querySelector("#settingpage .guide aside ul");
|
||||||
|
for (var i = 0; i < list.children.length; i++) {
|
||||||
|
var child = list.children[i];
|
||||||
|
if (Bridge.NString.equals(child.getAttribute("data-tag"), tag)) {
|
||||||
|
if (!child.classList.contains("selected")) child.classList.add("selected");
|
||||||
|
} else {
|
||||||
|
if (child.classList.contains("selected")) child.classList.remove("selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OnLoad.add(ready);
|
OnLoad.add(ready);
|
||||||
})(this);
|
})(this);
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
(function(global) {
|
(function(global) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function getPage(page, display) {
|
function getPage(tag, page, display) {
|
||||||
return {
|
return {
|
||||||
|
tag: tag,
|
||||||
page: page,
|
page: page,
|
||||||
title: display
|
title: display
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var pages = {
|
var pages = {
|
||||||
general: getPage("appinstaller/general.html", getPublicRes(101)),
|
general: getPage("general", "appinstaller/general.html", getPublicRes(101)),
|
||||||
theme: getPage("appinstaller/theme.html", getPublicRes(102)),
|
theme: getPage("theme", "appinstaller/theme.html", getPublicRes(102)),
|
||||||
update: getPage("update.html", getPublicRes(103))
|
update: getPage("update", "update.html", getPublicRes(103)),
|
||||||
|
about: getPage("about", "appinstaller/about.html", getPublicRes(124))
|
||||||
};
|
};
|
||||||
Object.defineProperty(global, "pages", {
|
Object.defineProperty(global, "pages", {
|
||||||
get: function() {
|
get: function() {
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
});
|
});
|
||||||
Object.defineProperty(global, "guidePage", {
|
Object.defineProperty(global, "guidePage", {
|
||||||
get: function() {
|
get: function() {
|
||||||
return getPage("appinstaller/guide.html", "Guide");
|
return getPage("guide", "appinstaller/guide.html", "Guide");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})(this);
|
})(this);
|
||||||
@@ -9,4 +9,22 @@
|
|||||||
global.slideback = slideback;
|
global.slideback = slideback;
|
||||||
global.exepath = exepath;
|
global.exepath = exepath;
|
||||||
global.visual = ve;
|
global.visual = ve;
|
||||||
|
var strutil = Bridge.External.String;
|
||||||
|
var nstrutil = Bridge.NString;
|
||||||
|
var boolTrue = ["true", "1", "yes", "on", "y", "t", "zhen", "真"];
|
||||||
|
var boolFalse = ["false", "0", "no", "off", "n", "f", "jia", "假"];
|
||||||
|
global.parseBool = function(str) {
|
||||||
|
str = "" + str;
|
||||||
|
for (var i = 0; i < boolTrue.length; i++) {
|
||||||
|
if (nstrutil.equals(str, boolTrue[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0; i < boolFalse.length; i++) {
|
||||||
|
if (nstrutil.equals(str, boolFalse[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
})(this);
|
})(this);
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>App Installer Settings</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script type="text/javascript" src="../../js/module.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/polyfill-ie.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../libs/winjs/2.0/css/ui-light.css" id="winjs-style">
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/base.js"></script>
|
||||||
|
<script type="text/javascript" src="../../libs/winjs/1.0/js/ui.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/color.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/promise.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/bridge.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/dpimodes.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/resources.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/animation.js"></script>
|
||||||
|
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||||
|
<script type="text/javascript" src="../../js/event.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/tileback.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/load.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../libs/msgbox/msgbox.css">
|
||||||
|
<script type="text/javascript" src="../../libs/msgbox/msgbox.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../libs/toggle/toggle.css">
|
||||||
|
<script type="text/javascript" src="../../libs/toggle/toggle.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/init.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../page.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../subpage.css">
|
||||||
|
<script type="text/javascript" src="preinit.js"></script>
|
||||||
|
<script type="text/javascript" src="initsame.js"></script>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
window.parent.setItemHighlight("theme");
|
||||||
|
} catch (e) {}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="pagecontainer full pagesection">
|
||||||
|
<div class="section padding">
|
||||||
|
<h2 id="page-title" data-res-fromfile="publicRes (102)"></h2>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label>主题模式</label><br>
|
||||||
|
<select>
|
||||||
|
<option>深色</option>
|
||||||
|
<option>浅色</option>
|
||||||
|
<option>自动变换</option>
|
||||||
|
<option>自定义</option>
|
||||||
|
</select>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-section">
|
||||||
|
<br>
|
||||||
|
<label>自动变换选项</label><br>
|
||||||
|
<select>
|
||||||
|
<option>跟随系统</option>
|
||||||
|
<option>设置变换时间</option>
|
||||||
|
</select><br>
|
||||||
|
<div class="win-settings-section" id="item-automode">
|
||||||
|
<p>设置变换时间</p>
|
||||||
|
<div class="win-settings-row">
|
||||||
|
<div class="win-settings-label" style="font-weight: normal;">白天</div>
|
||||||
|
<div class="win-settings-control">
|
||||||
|
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 9, minute: 0, clock: '24HourClock' }">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-row">
|
||||||
|
<div class="win-settings-label" style="font-weight: normal;">夜晚</div>
|
||||||
|
<div class="win-settings-control">
|
||||||
|
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 18, minute: 0, clock: '24HourClock' }">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="win-settings-section" id="item-theme">
|
||||||
|
<br>
|
||||||
|
<label>主题模式</label><br>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var sect = document.getElementById("item-theme");
|
||||||
|
var toggle = new Toggle();
|
||||||
|
toggle.create();
|
||||||
|
toggle.parent = sect;
|
||||||
|
toggle.setColor("#202020");
|
||||||
|
toggle.showlabel = true;
|
||||||
|
toggle.setStatusText("深色", "浅色");
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
<label>选择主题</label>
|
||||||
|
<div id="theme-items-select" data-win-control="WinJS.UI.ListView"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
}, 50);
|
}, 50);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
content.style.display = "";
|
content.style.display = "";
|
||||||
Windows.UI.Animation.runAsync(content, Windows.UI.Animation.Keyframes.SlideInFromBottom);
|
Windows.UI.Animation.runAsync(content, [Windows.UI.Animation.Keyframes.Flyout.toLeft, Windows.UI.Animation.Keyframes.Opacity.visible]);
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
OnLoad.add(ready);
|
OnLoad.add(ready);
|
||||||
|
|||||||
@@ -179,6 +179,12 @@ aside .container ul li:focus {
|
|||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside .container ul li:disabled,
|
||||||
|
aside .container ul li[data-require-disabled] {
|
||||||
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
#back:disabled {
|
#back:disabled {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,12 @@
|
|||||||
.section .block {
|
.section .block {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
|
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
background-color: blanchedalmond;
|
/* background-color: blanchedalmond; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagesection .section {
|
.pagesection .section {
|
||||||
@@ -174,16 +172,86 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var process = Bridge.External.Process;
|
||||||
|
global.createProcessAsync = function(cmdline, filepath, wndshow, runpath) {
|
||||||
|
return new WinJS.Promise(function(resolve, reject) {
|
||||||
|
var callback = resolve || reject;
|
||||||
|
process.runAsync(cmdline, filepath, wndshow, runpath, callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
global.createProcess = function(cmdline, filepath, wndshow, wait, runpath) {
|
||||||
|
return process.run(cmdline, filepath, wndshow, wait, runpath);
|
||||||
|
};
|
||||||
|
global.wndDisplayMode = {
|
||||||
|
hide: 0, // SW_HIDE
|
||||||
|
showNormal: 1, // SW_SHOWNORMAL / SW_NORMAL
|
||||||
|
showMinimized: 2, // SW_SHOWMINIMIZED
|
||||||
|
showMaximized: 3, // SW_SHOWMAXIMIZED
|
||||||
|
showNoActivate: 4, // SW_SHOWNOACTIVATE
|
||||||
|
show: 5, // SW_SHOW
|
||||||
|
minimize: 6, // SW_MINIMIZE
|
||||||
|
showMinNoActivate: 7, // SW_SHOWMINNOACTIVE
|
||||||
|
showNA: 8, // SW_SHOWNA
|
||||||
|
restore: 9, // SW_RESTORE
|
||||||
|
showDefault: 10, // SW_SHOWDEFAULT
|
||||||
|
forceMinimize: 11 // SW_FORCEMINIMIZE
|
||||||
|
};
|
||||||
|
|
||||||
})(this);
|
})(this);
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
function formatBytesSize(bytes) {
|
||||||
|
if (isNaN(bytes) || bytes < 0) return "0 B";
|
||||||
|
|
||||||
|
var units = ["B", "KB", "MB", "GB", "TB", "PB"];
|
||||||
|
var i = 0;
|
||||||
|
var num = bytes;
|
||||||
|
|
||||||
|
while (num >= 1024 && i < units.length - 1) {
|
||||||
|
num = num / 1024;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留 2 位小数,整数不显示小数
|
||||||
|
if (num >= 100) num = Math.round(num);
|
||||||
|
else if (num >= 10) num = Math.round(num * 10) / 10;
|
||||||
|
else num = Math.round(num * 100) / 100;
|
||||||
|
|
||||||
|
return num + " " + units[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBytesTransmissionSpeed(bps) {
|
||||||
|
if (isNaN(bps) || bps < 0) return "0 B/s";
|
||||||
|
|
||||||
|
var units = ["B/s", "KB/s", "MB/s", "GB/s", "TB/s"];
|
||||||
|
var i = 0;
|
||||||
|
var num = bps;
|
||||||
|
|
||||||
|
while (num >= 1024 && i < units.length - 1) {
|
||||||
|
num = num / 1024;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num >= 100) num = Math.round(num);
|
||||||
|
else if (num >= 10) num = Math.round(num * 10) / 10;
|
||||||
|
else num = Math.round(num * 100) / 100;
|
||||||
|
|
||||||
|
return num + " " + units[i];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
try {
|
||||||
|
window.parent.setItemHighlight("update");
|
||||||
|
} catch (e) {}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="pagecontainer full pagesection" style="overflow-y: auto;">
|
<div class="pagecontainer full pagesection" style="overflow-y: auto;">
|
||||||
<div class="section padding">
|
<div class="section padding">
|
||||||
<h2 id="section-title" data-res-fromfile="publicRes (103)"></h2>
|
<h2 id="section-title" data-res-fromfile="publicRes (103)"></h2>
|
||||||
<p id="section-desc" style="white-space: pre-wrap;">在这里,检查一下应用的更新。</p>
|
<p id="section-desc" style="white-space: pre-wrap;" data-res-fromfile="publicRes (105)"></p>
|
||||||
<p><span data-res-fromfile="publicRes (104)"></span>	<span id="current-version"></span></p>
|
<p style="white-space: pre-wrap;"><span data-res-fromfile="publicRes (104)"></span>	<span id="current-version"></span></p>
|
||||||
<script>
|
<script>
|
||||||
try {
|
try {
|
||||||
var storage = Bridge.External.Storage;
|
var storage = Bridge.External.Storage;
|
||||||
@@ -199,19 +267,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="section padding" style="">
|
<div class="section padding" style="">
|
||||||
<div class="block" id="check-update-block" style="height: 0px;">
|
<div class="block" id="check-update-block" style="height: 0px;">
|
||||||
<span id="loading-amine">123</span><span id="check-update-text">正在检查更新...</span><br>
|
<span id="loading-amine">123</span><span id="check-update-text" data-res-fromfile="publicRes (106)"></span><br>
|
||||||
<progress id="progress" min="0" max="100"></progress>
|
<progress id="progress" min="0" max="100"></progress>
|
||||||
<a target="_blank" id="doc-link">查看文档</a>
|
<a target="_blank" id="doc-link" data-res-fromfile="publicRes (107)"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section padding" style="margin: 10px 0;"><button id="check-update" data-action="check">检查更新</button></div>
|
<div class="section padding" style="margin: 10px 0;"><button id="check-update" data-action="check" data-res-fromfile="publicRes (115)"></button></div>
|
||||||
<div class="section padding" style="display: none; overflow-y: auto; height: 0px; transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); margin-top: 20px;">
|
<div class="section padding" style="display: none; overflow-y: auto; height: 0px; transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); margin-top: 20px;">
|
||||||
<h2>获取到的更新信息</h2>
|
<h2 data-res-fromfile="publicRes (108)"></h2>
|
||||||
<div class="block" id="newversion-details">
|
<div class="block" id="newversion-details">
|
||||||
<h3 id="newversion-title"><span>最新版本</span>: <span id="newversion-version"></span></h3>
|
<h3 id="newversion-title"><span data-res-fromfile="publicRes (109)"></span>: <span id="newversion-version"></span></h3>
|
||||||
<span id="newversion-releasedate"></span><br>
|
<span id="newversion-releasedate"></span><br>
|
||||||
<a id="newversion-url" target="_blank">查看链接</a><br>
|
<a id="newversion-url" target="_blank" data-res-fromfile="publicRes (110)"></a><br>
|
||||||
<span>发布说明: </span><a id="newversion-desc-showall-hide">展开</a>
|
<span data-res-fromfile="publicRes (111)"></span>:
|
||||||
|
<a id="newversion-desc-showall-hide" data-res-fromfile="publicRes (122)"></a>
|
||||||
<div id="newversion-desc"></div>
|
<div id="newversion-desc"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -255,11 +324,11 @@
|
|||||||
var parentSection = newVersionBlock.parentNode;
|
var parentSection = newVersionBlock.parentNode;
|
||||||
if (parentSection.hasAttribute("data-showall") == true) {
|
if (parentSection.hasAttribute("data-showall") == true) {
|
||||||
parentSection.removeAttribute("data-showall");
|
parentSection.removeAttribute("data-showall");
|
||||||
newVersionDescShowOrHide.textContent = "展开";
|
newVersionDescShowOrHide.textContent = getPublicRes(122);
|
||||||
parentSection.style.height = parentSection.getAttribute("data-height") + "px";
|
parentSection.style.height = parentSection.getAttribute("data-height") + "px";
|
||||||
} else {
|
} else {
|
||||||
parentSection.setAttribute("data-showall", true);
|
parentSection.setAttribute("data-showall", true);
|
||||||
newVersionDescShowOrHide.textContent = "收起";
|
newVersionDescShowOrHide.textContent = getPublicRes(123);
|
||||||
parentSection.style.height = "auto";
|
parentSection.style.height = "auto";
|
||||||
}
|
}
|
||||||
debunced_resize();
|
debunced_resize();
|
||||||
@@ -270,8 +339,9 @@
|
|||||||
var self = this;
|
var self = this;
|
||||||
this.disabled = true;
|
this.disabled = true;
|
||||||
progress.removeAttribute("value");
|
progress.removeAttribute("value");
|
||||||
|
window.parent.setDisabledForOperation(true);
|
||||||
if (checkUpdateBtn.getAttribute("data-action") == "check") {
|
if (checkUpdateBtn.getAttribute("data-action") == "check") {
|
||||||
checkUpdateText.textContent = "正在检查更新...";
|
checkUpdateText.textContent = getPublicRes(106);
|
||||||
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
progress.style.display = "";
|
progress.style.display = "";
|
||||||
docLink.style.display = "none";
|
docLink.style.display = "none";
|
||||||
@@ -285,17 +355,17 @@
|
|||||||
WinJS.xhr({
|
WinJS.xhr({
|
||||||
url: "https://api.github.com/repos/modernw/App-Installer-For-Windows-8.x-Reset/releases/latest"
|
url: "https://api.github.com/repos/modernw/App-Installer-For-Windows-8.x-Reset/releases/latest"
|
||||||
}).done(function(resp) {
|
}).done(function(resp) {
|
||||||
console.log("success", resp);
|
// console.log("success", resp);
|
||||||
var json = JSON.parse(resp.responseText);
|
var json = JSON.parse(resp.responseText);
|
||||||
console.log(json);
|
// console.log(json);
|
||||||
self.disabled = false;
|
self.disabled = false;
|
||||||
newVersionVersion.textContent = json.name;
|
newVersionVersion.textContent = json.name;
|
||||||
newVersionVersion.setAttribute("data-version", json.tag_name);
|
newVersionVersion.setAttribute("data-version", json.tag_name);
|
||||||
window.newver = json.tag_name;
|
window.newver = json.tag_name;
|
||||||
newVersionReleaseDate.textContent = "发布日期: " + json.published_at;
|
newVersionReleaseDate.textContent = getPublicRes(112) + ": " + json.published_at;
|
||||||
newVersionUrl.href = json.html_url;
|
newVersionUrl.href = json.html_url;
|
||||||
newVersionDesc.innerHTML = markdown.toHTML(json.body);
|
newVersionDesc.innerHTML = markdown.toHTML(json.body);
|
||||||
checkUpdateText.textContent = "检查更新完成";
|
checkUpdateText.textContent = getPublicRes(113);
|
||||||
progress.style.display = "none";
|
progress.style.display = "none";
|
||||||
newVersionBlock.parentNode.style.display = "";
|
newVersionBlock.parentNode.style.display = "";
|
||||||
stopProcess = false;
|
stopProcess = false;
|
||||||
@@ -303,63 +373,86 @@
|
|||||||
for (var i = 0; i < json.assets.length; i++) {
|
for (var i = 0; i < json.assets.length; i++) {
|
||||||
if (json.assets[i].browser_download_url.indexOf("/InstallerSetup.exe") > -1) {
|
if (json.assets[i].browser_download_url.indexOf("/InstallerSetup.exe") > -1) {
|
||||||
window.downloadUrl = json.assets[i].browser_download_url;
|
window.downloadUrl = json.assets[i].browser_download_url;
|
||||||
|
window.fileDigest = json.assets[i].digest;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compareVersion(window.currver, window.newver) > 0) {
|
if (compareVersion(window.currver, window.newver) >= 0) {
|
||||||
checkUpdateText.textContent = "当前已是最新版本";
|
checkUpdateText.textContent = getPublicRes(114);
|
||||||
checkUpdateBtn.textContent = "检查更新";
|
checkUpdateBtn.textContent = getPublicRes(115);
|
||||||
checkUpdateBtn.setAttribute("data-action", "check");
|
checkUpdateBtn.setAttribute("data-action", "check");
|
||||||
} else {
|
} else {
|
||||||
checkUpdateText.textContent = "有新版本可用: " + window.newver;
|
checkUpdateText.textContent = Bridge.String.format(getPublicRes(116), window.newver);
|
||||||
checkUpdateBtn.textContent = "下载更新";
|
checkUpdateBtn.textContent = getPublicRes(118);
|
||||||
checkUpdateBtn.setAttribute("data-action", "download");
|
checkUpdateBtn.setAttribute("data-action", "download");
|
||||||
}
|
}
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
console.log("error", error);
|
// console.log("error", error);
|
||||||
var json = JSON.parse(error.responseText);
|
var json = JSON.parse(error.responseText);
|
||||||
checkUpdateText.textContent = json.message;
|
checkUpdateText.textContent = json.message;
|
||||||
progress.style.display = "none";
|
progress.style.display = "none";
|
||||||
docLink.style.display = "";
|
docLink.style.display = "";
|
||||||
docLink.href = json.documentation_url;
|
docLink.href = json.documentation_url;
|
||||||
self.disabled = false;
|
self.disabled = false;
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
// console.log("error", error);
|
||||||
checkUpdateText.textContent = error.message || e || "Unknown Exception"
|
checkUpdateText.textContent = error.message || e || "Unknown Exception"
|
||||||
progress.style.display = "none";
|
progress.style.display = "none";
|
||||||
docLink.style.display = "none";
|
docLink.style.display = "none";
|
||||||
docLink.href = "";
|
docLink.href = "";
|
||||||
self.disabled = false;
|
self.disabled = false;
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
}
|
}
|
||||||
} else if (checkUpdateBtn.getAttribute("data-action") == "download") {
|
} else if (checkUpdateBtn.getAttribute("data-action") == "download") {
|
||||||
|
var storage = Bridge.External.Storage;
|
||||||
|
var path = storage.path;
|
||||||
stopProcess = true;
|
stopProcess = true;
|
||||||
newVersionBlock.parentNode.style.height = "0px";
|
newVersionBlock.parentNode.style.height = "0px";
|
||||||
checkUpdateText.textContent = "正在下载更新...";
|
checkUpdateText.textContent = getPublicRes(117);
|
||||||
progress.style.display = "";
|
progress.style.display = "";
|
||||||
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
var anime = Windows.UI.Animation;
|
var anime = Windows.UI.Animation;
|
||||||
|
var strutil = Bridge.External.String;
|
||||||
|
|
||||||
function setError(error) {
|
function setError(error) {
|
||||||
console.error("download error", error);
|
//console.error("download error", error);
|
||||||
checkUpdateText.textContent = "下载失败,请重试: " + error.reason;
|
checkUpdateText.textContent = strutil.format(getPublicRes(119), error.reason);
|
||||||
progress.style.display = "none";
|
progress.style.display = "none";
|
||||||
self.disabled = false;
|
self.disabled = false;
|
||||||
self.textContent = "重试";
|
self.textContent = "重试";
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
function setException(e) {
|
function setException(e) {
|
||||||
console.error("download exception", e);
|
//console.error("download exception", e);
|
||||||
checkUpdateText.textContent = "下载出现异常,请重试: " + e.message;
|
checkUpdateText.textContent = strutil.format(getPublicRes(119), e.message);
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
}
|
}
|
||||||
|
|
||||||
function setComplete(complete) {
|
function setComplete(complete) {
|
||||||
console.log("download complete", complete);
|
// console.log("download complete", complete);
|
||||||
checkUpdateText.textContent = "下载完成,即将进行安装...";
|
checkUpdateText.textContent = getPublicRes(120);
|
||||||
|
var cmdline = strutil.format("\"{0}\" /passive", tempfile);
|
||||||
|
var appinstallerpath = path.combine(path.root, "appinstaller.exe");
|
||||||
|
var settingsapppath = path.combine(path.root, "settings.exe");
|
||||||
|
window.parent.setDisabledForOperation(false);
|
||||||
|
var process = Bridge.External.Process;
|
||||||
|
process.kill(appinstallerpath, true, false);
|
||||||
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
|
createProcess(cmdline, tempfile, wndDisplayMode.showNormal, false);
|
||||||
|
process.kill(settingsapppath, true, false);
|
||||||
|
//Bridge.External.closeWindow();
|
||||||
}
|
}
|
||||||
progress.value = 0;
|
progress.value = 0;
|
||||||
anime.loading(checkUpdateLoading, true);
|
anime.loading(checkUpdateLoading, true);
|
||||||
downloadFile(downloadUrl, "E:\\Profiles\\Bruce\\Desktop\\InstallerSetup.exe").done(
|
var tempdir = path.expand("%temp%");
|
||||||
|
var tempfile = path.combine(tempdir, "InstallerSetup.exe");
|
||||||
|
downloadFile(downloadUrl, tempfile).done(
|
||||||
function(complete) {
|
function(complete) {
|
||||||
anime.loading(checkUpdateLoading, false);
|
anime.loading(checkUpdateLoading, false);
|
||||||
if (complete.status == "ok") setComplete(complete);
|
if (complete.status == "ok") setComplete(complete);
|
||||||
@@ -370,9 +463,10 @@
|
|||||||
setError(error);
|
setError(error);
|
||||||
},
|
},
|
||||||
function(prog) {
|
function(prog) {
|
||||||
console.log("download progress", progress);
|
//console.log("download progress", prog);
|
||||||
progress.value = prog.progress;
|
progress.value = prog.progress;
|
||||||
checkUpdateText.textContent = "正在下载更新... (" + Math.round(prog.progress) + "%)";
|
checkUpdateText.textContent = strutil.format(getPublicRes(121), Math.floor(prog.progress), formatBytesSize(prog.received), formatBytesSize(prog.total));
|
||||||
|
checkUpdateBlock.style.height = checkUpdateBlock.scrollHeight + "px";
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
230
shared/locale/resources.xml
Normal file
230
shared/locale/resources.xml
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/off">
|
||||||
|
<lang name="zh-CN">关</lang>
|
||||||
|
<lang name="en-US">Off</lang>
|
||||||
|
<lang name="af-ZA">Af</lang>
|
||||||
|
<lang name="am-ET">አጥፋ</lang>
|
||||||
|
<lang name="ar-SA">إيقاف التشغيل</lang>
|
||||||
|
<lang name="as-IN">অফ</lang>
|
||||||
|
<lang name="az-LATN-AZ">Qeyri-aktiv</lang>
|
||||||
|
<lang name="be-BY">Выкл.</lang>
|
||||||
|
<lang name="bg-BG">Изключено</lang>
|
||||||
|
<lang name="bn-BD">বন্ধ</lang>
|
||||||
|
<lang name="bn-IN">বন্ধ</lang>
|
||||||
|
<lang name="bs-LATN-BA">Isključeno</lang>
|
||||||
|
<lang name="ca-ES">Inactiva</lang>
|
||||||
|
<lang name="ca-ES-VALENCIA">Inactiva</lang>
|
||||||
|
<lang name="chr-CHER-US">ᎠᏍᏚᏗ</lang>
|
||||||
|
<lang name="cs-CZ">Vypnuto</lang>
|
||||||
|
<lang name="cy-GB">Diffodd</lang>
|
||||||
|
<lang name="da-DK">Fra</lang>
|
||||||
|
<lang name="de-DE">Aus</lang>
|
||||||
|
<lang name="el-GR">Ανενεργό</lang>
|
||||||
|
<lang name="en-GB">Off</lang>
|
||||||
|
<lang name="es-ES">Desactivado</lang>
|
||||||
|
<lang name="et-EE">Väljas</lang>
|
||||||
|
<lang name="eu-ES">Desaktibatuta</lang>
|
||||||
|
<lang name="fa-IR">خاموش</lang>
|
||||||
|
<lang name="fi-FI">Ei käytössä</lang>
|
||||||
|
<lang name="fil-PH">Naka-off</lang>
|
||||||
|
<lang name="fr-FR">Inactif</lang>
|
||||||
|
<lang name="ga-IE">As</lang>
|
||||||
|
<lang name="gd-GB">Dheth</lang>
|
||||||
|
<lang name="gl-ES">Desactivado</lang>
|
||||||
|
<lang name="gu-IN">બંધ</lang>
|
||||||
|
<lang name="ha-LATN-NG">Kashe</lang>
|
||||||
|
<lang name="he-IL">לא פעיל</lang>
|
||||||
|
<lang name="hi-IN">बंद</lang>
|
||||||
|
<lang name="hr-HR">Isključeno</lang>
|
||||||
|
<lang name="hu-HU">Kikapcsolva</lang>
|
||||||
|
<lang name="hy-AM">Անջատ</lang>
|
||||||
|
<lang name="id-ID">Nonaktif</lang>
|
||||||
|
<lang name="ig-NG">Gbanyọ</lang>
|
||||||
|
<lang name="is-IS">Óvirkt</lang>
|
||||||
|
<lang name="it-IT">Disattivato</lang>
|
||||||
|
<lang name="iu-LATN-CA">Qaminngajuq</lang>
|
||||||
|
<lang name="ja-JP">オフ</lang>
|
||||||
|
<lang name="ka-GE">გამორთვა</lang>
|
||||||
|
<lang name="kk-KZ">Өшірілген</lang>
|
||||||
|
<lang name="km-KH">បិទ</lang>
|
||||||
|
<lang name="kn-IN">ಆಫ್</lang>
|
||||||
|
<lang name="ko-KR">해제</lang>
|
||||||
|
<lang name="kok-IN">ऑफ करचें</lang>
|
||||||
|
<lang name="ku-ARAB-IQ">کوژاوە</lang>
|
||||||
|
<lang name="ky-KG">Өчүрулгөн</lang>
|
||||||
|
<lang name="lb-LU">Aus</lang>
|
||||||
|
<lang name="lt-LT">Išjungta</lang>
|
||||||
|
<lang name="lv-LV">Izslēgts</lang>
|
||||||
|
<lang name="mi-NZ">Weto ana</lang>
|
||||||
|
<lang name="mk-MK">Исклучено</lang>
|
||||||
|
<lang name="ml-IN">ഓഫ്</lang>
|
||||||
|
<lang name="mn-MN">Idəvxgüĭ</lang>
|
||||||
|
<lang name="mr-IN">बंद</lang>
|
||||||
|
<lang name="ms-MY">Mati</lang>
|
||||||
|
<lang name="mt-MT">Mitfi</lang>
|
||||||
|
<lang name="nb-NO">Av</lang>
|
||||||
|
<lang name="ne-NP">निभाउनुहोस्</lang>
|
||||||
|
<lang name="nl-NL">Uit</lang>
|
||||||
|
<lang name="nn-NO">Av</lang>
|
||||||
|
<lang name="nso-ZA">Timilwe</lang>
|
||||||
|
<lang name="or-IN">ଅଫ୍</lang>
|
||||||
|
<lang name="pa-ARAB-PK">بند</lang>
|
||||||
|
<lang name="pa-IN">ਬੰਦ ਕਰੋ</lang>
|
||||||
|
<lang name="pl-PL">Wyłączone</lang>
|
||||||
|
<lang name="prs-AF">خاموش</lang>
|
||||||
|
<lang name="pt-BR">Desligado</lang>
|
||||||
|
<lang name="pt-PT">Desativado</lang>
|
||||||
|
<lang name="qps-PLOC">[3Hcgw][Ǿƒƒ ]</lang>
|
||||||
|
<lang name="qps-PLOCM">أبع[Off]לף</lang>
|
||||||
|
<lang name="qut-GT">Q'atetalik</lang>
|
||||||
|
<lang name="quz-PE">Tukuchisqa</lang>
|
||||||
|
<lang name="ro-RO">Dezactivat</lang>
|
||||||
|
<lang name="ru-RU">Откл.</lang>
|
||||||
|
<lang name="rw-RW">Irafunze</lang>
|
||||||
|
<lang name="sd-ARAB-PK">بند کوليو</lang>
|
||||||
|
<lang name="si-LK">අක්රීය</lang>
|
||||||
|
<lang name="sk-SK">Vypnuté</lang>
|
||||||
|
<lang name="sl-SI">Izklopljeno</lang>
|
||||||
|
<lang name="sq-AL">Joaktiv</lang>
|
||||||
|
<lang name="sr-CYRL-BA">Искључено</lang>
|
||||||
|
<lang name="sr-CYRL-CS">Искључено</lang>
|
||||||
|
<lang name="sr-LATN-CS">Isključeno</lang>
|
||||||
|
<lang name="sv-SE">Av</lang>
|
||||||
|
<lang name="sw-KE">Zima</lang>
|
||||||
|
<lang name="ta-IN">அணை</lang>
|
||||||
|
<lang name="te-IN">ఆఫ్ చేయి</lang>
|
||||||
|
<lang name="tg-CYRL-TJ">Хомӯш</lang>
|
||||||
|
<lang name="th-TH">ปิด</lang>
|
||||||
|
<lang name="ti-ET">ኣጥፍእ</lang>
|
||||||
|
<lang name="tk-TM">Öçürilen</lang>
|
||||||
|
<lang name="tn-ZA">Timilwe</lang>
|
||||||
|
<lang name="tr-TR">Kapalı</lang>
|
||||||
|
<lang name="tt-RU">Сүндерелгән</lang>
|
||||||
|
<lang name="ug-CN">يېپىق</lang>
|
||||||
|
<lang name="uk-UA">Вимк.</lang>
|
||||||
|
<lang name="ur-PK">آف</lang>
|
||||||
|
<lang name="uz-LATN-UZ">O‘ch</lang>
|
||||||
|
<lang name="vi-VN">Tắt</lang>
|
||||||
|
<lang name="wo-SN">Fay</lang>
|
||||||
|
<lang name="xh-ZA">Cimile</lang>
|
||||||
|
<lang name="yo-NG">Pa</lang>
|
||||||
|
<lang name="zh-HK">關閉</lang>
|
||||||
|
<lang name="zh-TW">關閉</lang>
|
||||||
|
<lang name="zu-ZA">Cishile</lang>
|
||||||
|
</resource>
|
||||||
|
|
||||||
|
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/on">
|
||||||
|
<lang name="zh-CN">开</lang>
|
||||||
|
<lang name="en-US">On</lang>
|
||||||
|
<lang name="af-ZA">Aan</lang>
|
||||||
|
<lang name="am-ET">አብራ</lang>
|
||||||
|
<lang name="ar-SA">تشغيل</lang>
|
||||||
|
<lang name="as-IN">অন</lang>
|
||||||
|
<lang name="az-LATN-AZ">Aktiv</lang>
|
||||||
|
<lang name="be-BY">Укл.</lang>
|
||||||
|
<lang name="bg-BG">Включено</lang>
|
||||||
|
<lang name="bn-BD">চালু</lang>
|
||||||
|
<lang name="bn-IN">চালু</lang>
|
||||||
|
<lang name="bs-LATN-BA">Uključeno</lang>
|
||||||
|
<lang name="ca-ES">Activa</lang>
|
||||||
|
<lang name="ca-ES-VALENCIA">Activa</lang>
|
||||||
|
<lang name="chr-CHER-US">ᎠᏍᏚᎢᏍᏗ</lang>
|
||||||
|
<lang name="cs-CZ">Zapnuto</lang>
|
||||||
|
<lang name="cy-GB">Ar waith</lang>
|
||||||
|
<lang name="da-DK">Til</lang>
|
||||||
|
<lang name="de-DE">Ein</lang>
|
||||||
|
<lang name="el-GR">Ενεργό</lang>
|
||||||
|
<lang name="en-GB">On</lang>
|
||||||
|
<lang name="es-ES">Activado</lang>
|
||||||
|
<lang name="et-EE">Sees</lang>
|
||||||
|
<lang name="eu-ES">Aktibatuta</lang>
|
||||||
|
<lang name="fa-IR">روشن</lang>
|
||||||
|
<lang name="fi-FI">Käytössä</lang>
|
||||||
|
<lang name="fil-PH">Naka-on</lang>
|
||||||
|
<lang name="fr-FR">Actif</lang>
|
||||||
|
<lang name="ga-IE">Air</lang>
|
||||||
|
<lang name="gd-GB">Air</lang>
|
||||||
|
<lang name="gl-ES">Activado</lang>
|
||||||
|
<lang name="gu-IN">ચાલુ</lang>
|
||||||
|
<lang name="ha-LATN-NG">Kunna</lang>
|
||||||
|
<lang name="he-IL">פעיל</lang>
|
||||||
|
<lang name="hi-IN">चालू</lang>
|
||||||
|
<lang name="hr-HR">Uključeno</lang>
|
||||||
|
<lang name="hu-HU">Bekapcsolva</lang>
|
||||||
|
<lang name="hy-AM">Միաց</lang>
|
||||||
|
<lang name="id-ID">Aktif</lang>
|
||||||
|
<lang name="ig-NG">Gbanye</lang>
|
||||||
|
<lang name="is-IS">Virkt</lang>
|
||||||
|
<lang name="it-IT">Attivato</lang>
|
||||||
|
<lang name="iu-LATN-CA">Ikumajuq</lang>
|
||||||
|
<lang name="ja-JP">オン</lang>
|
||||||
|
<lang name="ka-GE">ჩართვა</lang>
|
||||||
|
<lang name="kk-KZ">Қосылған</lang>
|
||||||
|
<lang name="km-KH">បើក</lang>
|
||||||
|
<lang name="kn-IN">ಆನ್</lang>
|
||||||
|
<lang name="ko-KR">설정</lang>
|
||||||
|
<lang name="kok-IN">ऑन करचें</lang>
|
||||||
|
<lang name="ku-ARAB-IQ">هەڵکراو</lang>
|
||||||
|
<lang name="ky-KG">Күйгүзүлгөн</lang>
|
||||||
|
<lang name="lb-LU">Un</lang>
|
||||||
|
<lang name="lt-LT">Įjungta</lang>
|
||||||
|
<lang name="lv-LV">Ieslēgts</lang>
|
||||||
|
<lang name="mi-NZ">Kā ana</lang>
|
||||||
|
<lang name="mk-MK">Вклученo</lang>
|
||||||
|
<lang name="ml-IN">ഓൺ</lang>
|
||||||
|
<lang name="mn-MN">Идэвхтэй</lang>
|
||||||
|
<lang name="mr-IN">चालू</lang>
|
||||||
|
<lang name="ms-MY">Hidup</lang>
|
||||||
|
<lang name="mt-MT">Mixgħul</lang>
|
||||||
|
<lang name="nb-NO">På</lang>
|
||||||
|
<lang name="ne-NP">खोल्नुहोस्</lang>
|
||||||
|
<lang name="nl-NL">Aan</lang>
|
||||||
|
<lang name="nn-NO">På</lang>
|
||||||
|
<lang name="nso-ZA">Goteditšwe</lang>
|
||||||
|
<lang name="or-IN">ଅନ୍</lang>
|
||||||
|
<lang name="pa-ARAB-PK">چالُو</lang>
|
||||||
|
<lang name="pa-IN">ਚਾਲੂ ਕਰੋ</lang>
|
||||||
|
<lang name="pl-PL">Włączone</lang>
|
||||||
|
<lang name="prs-AF">روشن</lang>
|
||||||
|
<lang name="pt-BR">Ligado</lang>
|
||||||
|
<lang name="pt-PT">Ativado</lang>
|
||||||
|
<lang name="qps-PLOC">[Aj8Pp][Őņ ]</lang>
|
||||||
|
<lang name="qps-PLOCM">أبع[On]לף</lang>
|
||||||
|
<lang name="qut-GT">Tzijtalik</lang>
|
||||||
|
<lang name="quz-PE">Kawsarichisqa</lang>
|
||||||
|
<lang name="ro-RO">Activat</lang>
|
||||||
|
<lang name="ru-RU">Вкл.</lang>
|
||||||
|
<lang name="rw-RW">Irafunguye</lang>
|
||||||
|
<lang name="sd-ARAB-PK">شروع ڪريو</lang>
|
||||||
|
<lang name="si-LK">සක්රීය</lang>
|
||||||
|
<lang name="sk-SK">Zapnuté</lang>
|
||||||
|
<lang name="sl-SI">Vklopljeno</lang>
|
||||||
|
<lang name="sq-AL">Aktiv</lang>
|
||||||
|
<lang name="sr-CYRL-BA">Укључено</lang>
|
||||||
|
<lang name="sr-CYRL-CS">Укључено</lang>
|
||||||
|
<lang name="sr-LATN-CS">Uključeno</lang>
|
||||||
|
<lang name="sv-SE">På</lang>
|
||||||
|
<lang name="sw-KE">Washa</lang>
|
||||||
|
<lang name="ta-IN">இயக்கு</lang>
|
||||||
|
<lang name="te-IN">ఆన్ చేయి</lang>
|
||||||
|
<lang name="tg-CYRL-TJ">Фаъол</lang>
|
||||||
|
<lang name="th-TH">เปิด</lang>
|
||||||
|
<lang name="ti-ET">ወልዕ</lang>
|
||||||
|
<lang name="tk-TM">Açyk</lang>
|
||||||
|
<lang name="tn-ZA">Tshubilwe</lang>
|
||||||
|
<lang name="tr-TR">Açık</lang>
|
||||||
|
<lang name="tt-RU">Кабызылган</lang>
|
||||||
|
<lang name="ug-CN">ئوچۇق</lang>
|
||||||
|
<lang name="uk-UA">Увімк.</lang>
|
||||||
|
<lang name="ur-PK">آن</lang>
|
||||||
|
<lang name="uz-LATN-UZ">Yoq</lang>
|
||||||
|
<lang name="vi-VN">Bật</lang>
|
||||||
|
<lang name="wo-SN">Taal</lang>
|
||||||
|
<lang name="xh-ZA">Layitile</lang>
|
||||||
|
<lang name="yo-NG">Tàn</lang>
|
||||||
|
<lang name="zh-HK">開啟</lang>
|
||||||
|
<lang name="zh-TW">開啟</lang>
|
||||||
|
<lang name="zu-ZA">Vuliwe</lang>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
4
shared/run_uninstall.bat
Normal file
4
shared/run_uninstall.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo on
|
||||||
|
cd /d "%~dp0"
|
||||||
|
uninstall.backup.exe /U:Uninstall\uninstall.xml
|
||||||
|
exit /b
|
||||||
BIN
shared/uninstall.backup.exe
Normal file
BIN
shared/uninstall.backup.exe
Normal file
Binary file not shown.
34
shortcut/main.cpp
Normal file
34
shortcut/main.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <locale>
|
||||||
|
#include "../notice/notice.h"
|
||||||
|
|
||||||
|
int wmain (int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
std::wcout.imbue (std::locale ("", LC_CTYPE));
|
||||||
|
if (argc < 4 && argc > 1)
|
||||||
|
{
|
||||||
|
std::wcout << L"Error: invalid args." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (argc <= 1)
|
||||||
|
{
|
||||||
|
std::wcout << L"Usage: " << std::endl <<
|
||||||
|
L"\tshortcut.exe <lnk_file_path> <target_file_path> <app_id>" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto res = CreateShortcutWithAppIdW (argv [1], argv [2], argv [3]);
|
||||||
|
if (SUCCEEDED (res.hr))
|
||||||
|
{
|
||||||
|
std::wcout << L"Create successfully!" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::wcout << L"Create failed. Reason: " << res.message << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
158
shortcut/shortcut.vcxproj
Normal file
158
shortcut/shortcut.vcxproj
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<?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>{18E0189B-F3F1-4CB2-A3AF-5606ADD5E279}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>shortcut</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>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</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;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>$(OutDir)notice.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</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;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>$(OutDir)notice.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||||
|
</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;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
22
shortcut/shortcut.vcxproj.filters
Normal file
22
shortcut/shortcut.vcxproj.filters
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user