Update Shell and Fix Bugs

This commit is contained in:
Bruce
2025-12-07 15:18:40 +08:00
parent 98c0f91b8c
commit bb6b2b7521
51 changed files with 46468 additions and 12601 deletions

View File

@@ -1,20 +1,19 @@
#pragma once
#include <Windows.h>
#include <WinInet.h>
#include <winhttp.h>
#include <string>
#include "strcode.h"
#include "mpstr.h"
#include <chrono>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include "syncutil.h"
// Generated by ChatGTP
using namespace System;
using namespace System::Threading;
using namespace System::Reflection;
#include <Windows.h>
#include <string>
std::wstring GetLastErrorString ()
{
@@ -50,6 +49,8 @@ std::wstring GetLastErrorString ()
return msg;
}
CriticalSection g_download_cs;
public ref class DownloadHelper
{
public:
@@ -72,49 +73,163 @@ public ref class DownloadHelper
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:
void Worker ()
{
CreateScopedLock (g_download_cs);
std::wstring url = MPStringToStdW (m_url);
std::wstring outPath = MPStringToStdW (m_savePath);
HINTERNET hInternet = InternetOpenW (L"MyDownloader",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
URL_COMPONENTS urlComp = {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;
}
HINTERNET hFile = InternetOpenUrlW (
hInternet,
url.c_str (),
NULL,
0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
0
BOOL isHttps = (urlComp.nScheme == INTERNET_SCHEME_HTTPS);
hSession = WinHttpOpen (
L"MyDownloader",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
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);
ReportError (outPath, L"InternetOpenUrlW Failed: " + GetLastErrorString ());
CancelHttpHandle (hSession); hSession = nullptr;
ReportError (outPath, L"WinHttpConnect failed: " + GetLastErrorString ());
return;
}
DWORD fileSize = 0;
DWORD len = sizeof (fileSize);
HttpQueryInfoW (hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&fileSize, &len, NULL);
hRequest = WinHttpOpenRequest (
hConnect,
L"GET",
urlComp.lpszUrlPath,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
isHttps ? WINHTTP_FLAG_SECURE : 0);
HANDLE hOut = CreateFileW (outPath.c_str (), GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hRequest)
{
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)
{
InternetCloseHandle (hFile);
InternetCloseHandle (hInternet);
CancelHttpHandle (hRequest); hRequest = nullptr;
CancelHttpHandle (hConnect); hConnect = nullptr;
CancelHttpHandle (hSession); hSession = nullptr;
ReportError (outPath, L"Cannot create output file: " + GetLastErrorString ());
return;
}
@@ -125,23 +240,38 @@ public ref class DownloadHelper
long long received = 0;
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);
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));
auto now = std::chrono::high_resolution_clock::now ();
double intervalSec = std::chrono::duration<double> (now - lastCheck).count ();
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);
}
CloseHandle (hOut);
InternetCloseHandle (hFile);
InternetCloseHandle (hInternet);
CancelHttpHandle (hRequest); hRequest = nullptr;
CancelHttpHandle (hConnect); hConnect = nullptr;
CancelHttpHandle (hSession); hSession = nullptr;
ReportComplete (outPath, received);
}
@@ -158,7 +288,12 @@ public ref class DownloadHelper
w.StartObject ();
w.Key ("received"); w.Uint64 (received);
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.EndObject ();