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);
}
};