Update Settings Shell.

This commit is contained in:
Bruce
2025-12-01 22:51:46 +08:00
parent 5796fb40e1
commit 98c0f91b8c
28 changed files with 38814 additions and 382 deletions
+239
View File
@@ -0,0 +1,239 @@
#pragma once
#include <Windows.h>
#include <WinInet.h>
#include <string>
#include "strcode.h"
#include "mpstr.h"
#include <chrono>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
// Generated by ChatGTP
using namespace System;
using namespace System::Threading;
using namespace System::Reflection;
#include <Windows.h>
#include <string>
std::wstring GetLastErrorString ()
{
DWORD errCode = GetLastError ();
if (errCode == 0)
return L"No error";
wchar_t* msgBuffer = nullptr;
// FORMAT_MESSAGE_ALLOCATE_BUFFER: 让系统分配缓冲区
// FORMAT_MESSAGE_FROM_SYSTEM: 从系统获取错误信息
// FORMAT_MESSAGE_IGNORE_INSERTS: 忽略 %1 %2
DWORD size = FormatMessageW (
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
errCode,
0, // 默认语言
(LPWSTR)&msgBuffer,
0,
nullptr
);
std::wstring msg;
if (size && msgBuffer)
{
msg = msgBuffer;
LocalFree (msgBuffer); // 释放缓冲区
}
else
{
msg = L"Unknown error code: " + std::to_wstring (errCode);
}
return msg;
}
public ref class DownloadHelper
{
public:
static void DownloadFile (
String^ httpUrl,
String^ savePath,
Object^ onProgress,
Object^ onComplete,
Object^ onError)
{
DownloadHelper^ obj = gcnew DownloadHelper ();
obj->m_url = httpUrl;
obj->m_savePath = savePath;
obj->cbProgress = onProgress;
obj->cbComplete = onComplete;
obj->cbError = onError;
Thread^ th = gcnew Thread (gcnew ThreadStart (obj, &DownloadHelper::Worker));
th->IsBackground = true;
th->Start ();
}
private:
void Worker ()
{
std::wstring url = MPStringToStdW (m_url);
std::wstring outPath = MPStringToStdW (m_savePath);
HINTERNET hInternet = InternetOpenW (L"MyDownloader",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet)
{
ReportError (outPath, L"InternetOpenW Failed: " + GetLastErrorString ());
return;
}
HINTERNET hFile = InternetOpenUrlW (
hInternet,
url.c_str (),
NULL,
0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
0
);
if (!hFile)
{
InternetCloseHandle (hInternet);
ReportError (outPath, L"InternetOpenUrlW Failed: " + GetLastErrorString ());
return;
}
DWORD fileSize = 0;
DWORD len = sizeof (fileSize);
HttpQueryInfoW (hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&fileSize, &len, NULL);
HANDLE hOut = CreateFileW (outPath.c_str (), GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOut == INVALID_HANDLE_VALUE)
{
InternetCloseHandle (hFile);
InternetCloseHandle (hInternet);
ReportError (outPath, L"Cannot create output file: " + GetLastErrorString ());
return;
}
BYTE buffer [8192];
DWORD bytesRead = 0;
DWORD bytesWritten = 0;
long long received = 0;
auto t0 = std::chrono::high_resolution_clock::now ();
while (InternetReadFile (hFile, buffer, sizeof (buffer), &bytesRead) && bytesRead > 0)
{
WriteFile (hOut, buffer, bytesRead, &bytesWritten, NULL);
received += bytesRead;
// 计算速度
auto t1 = std::chrono::high_resolution_clock::now ();
double sec = std::chrono::duration<double> (t1 - t0).count ();
long long speed = (long long)(received / (sec > 0 ? sec : 1));
ReportProgress (received, fileSize, speed);
}
CloseHandle (hOut);
InternetCloseHandle (hFile);
InternetCloseHandle (hInternet);
ReportComplete (outPath, received);
}
// ---------------- 回调组装 JSON ----------------
void ReportProgress (long long received, long long total, long long speed)
{
if (!cbProgress) return;
rapidjson::StringBuffer buf;
rapidjson::Writer<rapidjson::StringBuffer> w (buf);
w.StartObject ();
w.Key ("received"); w.Uint64 (received);
w.Key ("total"); w.Uint64 (total);
w.Key ("speed"); w.Uint64 (speed);
w.Key ("progress"); w.Double (received / (double)total * 100);
w.EndObject ();
CallJS (cbProgress, CStringToMPString (StringToWString (buf.GetString (), CP_UTF8)));
}
void ReportComplete (const std::wstring& file, long long size)
{
if (!cbComplete) return;
rapidjson::StringBuffer buf;
rapidjson::Writer<rapidjson::StringBuffer> w (buf);
w.StartObject ();
w.Key ("file"); w.String (WStringToString (file, CP_UTF8).c_str ());
w.Key ("status"); w.String ("ok");
w.Key ("size"); w.Uint64 (size);
w.EndObject ();
CallJS (cbComplete, CStringToMPString (StringToWString (buf.GetString (), CP_UTF8)));
}
void ReportError (const std::wstring& file, const std::wstring &reason)
{
if (!cbError) return;
rapidjson::StringBuffer buf;
rapidjson::Writer<rapidjson::StringBuffer> w (buf);
w.StartObject ();
w.Key ("file"); w.String (WStringToString (file, CP_UTF8).c_str ());
w.Key ("status"); w.String ("failed");
w.Key ("reason"); w.String (WStringToString (reason, CP_UTF8).c_str ());
w.EndObject ();
CallJS (cbError, CStringToMPString (StringToWString (buf.GetString (), CP_UTF8)));
}
// ---------------- 调用 JS 回调 ----------------
void CallJS (Object^ jsFunc, String^ arg)
{
if (!jsFunc) return;
try
{
jsFunc->GetType ()->InvokeMember (
"call",
BindingFlags::InvokeMethod,
nullptr,
jsFunc,
gcnew array<Object^>{ 1, arg }
);
}
catch (...)
{
// 失败可忽略
}
}
private:
String^ m_url;
String^ m_savePath;
Object^ cbProgress;
Object^ cbComplete;
Object^ cbError;
};
using namespace System::Runtime::InteropServices;
[ComVisible (true)]
public ref class _I_Download
{
public:
void WorkAsync (String ^httpurl, String ^saveFilePath, Object ^onComplete, Object ^onError, Object ^onProgress)
{
auto download = gcnew DownloadHelper ();
download->DownloadFile (httpurl, saveFilePath, onProgress, onComplete, onError);
}
};
+5 -1
View File
@@ -12,6 +12,7 @@
#include <rapidjson\document.h>
#include <rapidjson\writer.h>
#include <rapidjson\stringbuffer.h>
#include "download.h"
#include "module.h"
#include "themeinfo.h"
#include "mpstr.h"
@@ -234,7 +235,7 @@ public ref class _I_Bridge_Base
protected:
_I_String ^str = gcnew _I_String ();
_I_InitConfig ^initconfig = gcnew _I_InitConfig ();
_I_Storage ^storage;
_I_Storage ^storage = gcnew _I_Storage ();
public:
property _I_String ^String { _I_String ^get () { return str; }}
property _I_InitConfig ^Config { _I_InitConfig ^get () { return initconfig; }}
@@ -682,6 +683,7 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form, public IScrip
_I_IEFrame ^ieframe;
_I_System3 ^sys;
_I_VisualElements2 ^ve;
_I_Download ^download;
public:
IBridge (MainHtmlWnd ^wnd): wndinst (wnd), _I_Bridge_Base2 (wnd)
{
@@ -689,10 +691,12 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form, public IScrip
sys = gcnew _I_System3 (wnd);
storage = gcnew _I_Storage ();
ve = gcnew _I_VisualElements2 ();
download = gcnew _I_Download ();
}
property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }}
property _I_System3 ^System { _I_System3 ^get () { return sys; }}
property _I_VisualElements2 ^VisualElements { _I_VisualElements2 ^get () { return ve; } }
property _I_Download ^Download { _I_Download ^get () { return download; }}
};
protected:
property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } }
+3 -2
View File
@@ -97,7 +97,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -130,7 +130,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>shlwapi.lib;version.lib;dwmapi.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -184,6 +184,7 @@
<ClInclude Include="..\appinstaller\typestrans.h" />
<ClInclude Include="..\appinstaller\vemani.h" />
<ClInclude Include="..\appinstaller\version.h" />
<ClInclude Include="download.h" />
<ClInclude Include="resmap.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
+3
View File
@@ -77,6 +77,9 @@
<ClInclude Include="resmap.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="download.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="settings.rc">