Skip to content

Commit a9451c7

Browse files
committed
Add AppRuntime, UI polish, and thread safety improvements
- Introduce AppRuntime for device ID, display name, and WebView2 version detection - Show app name in tray menu via AppRuntime - Improve DownloadManager thread safety with m_initializing flag and mutexes - Add IsDebug property and "Invert Theme" button to MainWindow (debug only) - Replace settings FontIcon with AnimatedIcon in MainView, add pointer event handlers - Refactor HttpDownloadDialog clipboard logic with fire_and_forget and event revoker - Fix XAML: ComboBox content, resource keys, and namespaces - Update project files for new/removed sources - Add WebView2Version struct for version encapsulation - Apply code style and exception handling improvements
1 parent a1e045b commit a9451c7

25 files changed

Lines changed: 594 additions & 197 deletions

‎.github/workflows/canary.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
strategy:
5959
matrix:
6060
configuration: [Release]
61-
platform: [x64]
61+
platform: [x64, ARM64]
6262

6363
steps:
6464
- name: Checkout

‎OpenNet/App.xaml.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ namespace winrt::OpenNet::implementation
356356
ApplyBackdropFromSettings(window);
357357
}
358358

359+
void App::Exit()
360+
{
361+
s_isExiting = true;
362+
Microsoft::UI::Xaml::Application::Current().Exit();
363+
}
364+
359365
// To do: Custom activation, Windows integration
360366
void App::HandleActivation(winrt::Microsoft::Windows::AppLifecycle::AppActivationArguments const& args)
361367
{

‎OpenNet/App.xaml.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace winrt::OpenNet::implementation
1313
~App();
1414

1515
void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
16+
void Exit();
1617

1718
static void HandleActivation(winrt::Microsoft::Windows::AppLifecycle::AppActivationArguments const&);
1819

‎OpenNet/Core/AppRuntime.cpp‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "pch.h"
2+
#include "AppRuntime.h"
3+
4+
#include "Core/Utils/Message.h"
5+
#include <openssl/evp.h>
6+
#include <wil/registry.h>
7+
#include <winrt/Microsoft.Web.WebView2.Core.h>
8+
9+
namespace OpenNet::Core
10+
{
11+
::OpenNet::Web::WebView2::WebView2Version AppRuntime::WebView2Version()
12+
{
13+
return ::OpenNet::Core::AppRuntime::InitializeWebView2();
14+
}
15+
16+
winrt::hstring AppRuntime::GetDisplayName()
17+
{
18+
return L"OpenNet";
19+
}
20+
21+
winrt::hstring AppRuntime::InitializeDeviceId()
22+
{
23+
wchar_t userNameBuffer[256];
24+
DWORD userNameSize = _countof(userNameBuffer);
25+
GetUserNameW(userNameBuffer, &userNameSize);
26+
27+
std::wstring userName = userNameBuffer;
28+
std::wstring machineGuid;
29+
30+
try
31+
{
32+
wil::unique_hkey hKey;
33+
if (hKey = wil::reg::open_unique_key(
34+
HKEY_LOCAL_MACHINE,
35+
L"SOFTWARE\\Microsoft\\Cryptography",
36+
wil::reg::key_access::read))
37+
{
38+
machineGuid = wil::reg::get_value_string<std::wstring>(
39+
hKey.get(),
40+
L"MachineGuid");
41+
}
42+
}
43+
catch (...)
44+
{
45+
machineGuid = userName;
46+
}
47+
48+
std::wstring combined = userName + machineGuid;
49+
50+
// 转 UTF-8(关键)
51+
int len = WideCharToMultiByte(CP_UTF8, 0, combined.c_str(), -1, nullptr, 0, nullptr, nullptr);
52+
std::vector<char> utf8(len - 1);
53+
WideCharToMultiByte(CP_UTF8, 0, combined.c_str(), -1, utf8.data(), len, nullptr, nullptr);
54+
55+
// EVP 接口
56+
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
57+
const EVP_MD* md = EVP_blake2b512();
58+
59+
unsigned char digest[64];
60+
unsigned int digestLen = 0;
61+
62+
EVP_DigestInit_ex(ctx, md, nullptr);
63+
EVP_DigestUpdate(ctx, utf8.data(), utf8.size());
64+
EVP_DigestFinal_ex(ctx, digest, &digestLen);
65+
66+
EVP_MD_CTX_free(ctx);
67+
68+
// hex
69+
static const char hex[] = "0123456789abcdef";
70+
std::string out;
71+
out.resize(digestLen * 2);
72+
73+
for (unsigned int i = 0; i < digestLen; ++i)
74+
{
75+
out[2 * i] = hex[digest[i] >> 4];
76+
out[2 * i + 1] = hex[digest[i] & 0xF];
77+
}
78+
79+
return winrt::to_hstring(out);
80+
}
81+
82+
OpenNet::Web::WebView2::WebView2Version AppRuntime::InitializeWebView2()
83+
{
84+
try
85+
{
86+
winrt::hstring version = winrt::Microsoft::Web::WebView2::Core::CoreWebView2Environment::GetAvailableBrowserVersionString();
87+
return OpenNet::Web::WebView2::WebView2Version(version, version, true);
88+
}
89+
catch (...)
90+
{
91+
return OpenNet::Web::WebView2::WebView2Version(winrt::hstring(), ResourceGetString(L"CoreWebView2HelperVersionUndetected"), false);
92+
}
93+
94+
}
95+
96+
}

‎OpenNet/Core/AppRuntime.h‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include "Web/WebView2/WebView2Version.h"
4+
5+
namespace OpenNet::Core
6+
{
7+
class AppRuntime
8+
{
9+
public:
10+
static winrt::hstring DeviceId()
11+
{
12+
return InitializeDeviceId();
13+
}
14+
static ::OpenNet::Web::WebView2::WebView2Version WebView2Version();
15+
static winrt::hstring GetDisplayName();
16+
17+
private:
18+
static winrt::hstring InitializeDeviceId();
19+
static ::OpenNet::Web::WebView2::WebView2Version InitializeWebView2();
20+
};
21+
}

‎OpenNet/Core/DownloadManager.cpp‎

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ namespace OpenNet::Core
4545
if (m_aria2)
4646
m_aria2->ForceTerminate();
4747
}
48-
catch (...) {}
48+
catch (...)
49+
{
50+
}
4951
}
5052

5153
// ------------------------------------------------------------------
@@ -55,40 +57,58 @@ namespace OpenNet::Core
5557
{
5658
co_await winrt::resume_background();
5759

58-
std::lock_guard lock(m_mutex);
59-
if (m_initialized)
60-
co_return;
60+
{
61+
std::lock_guard<std::mutex> lock(m_mutex);
62+
if (m_initialized || m_initializing)
63+
co_return;
64+
m_initializing = true;
65+
}
6166

62-
// Create the local Aria2 instance
63-
m_aria2 = std::make_unique<Aria2::LocalAria2Instance>();
67+
std::unique_ptr<Aria2::LocalAria2Instance> aria2 = std::make_unique<Aria2::LocalAria2Instance>();
6468

65-
// Async startup: locate aria2c, prepare process, and start
66-
co_await m_aria2->StartupAsync();
69+
try
70+
{
71+
// Async startup: locate aria2c, prepare process, and start
72+
co_await aria2->StartupAsync();
6773

68-
// Initialize HTTP download record persistence
69-
HttpStateManager::Instance().Initialize();
74+
// Initialize HTTP download record persistence
75+
HttpStateManager::Instance().Initialize();
7076

71-
// Rebuild GID→recordId mapping from persisted records so that
72-
// GetRecordIdForGid() works correctly after an app restart.
73-
{
77+
// Rebuild GID→recordId mapping from persisted records so that
78+
// GetRecordIdForGid() works correctly after an app restart.
7479
auto records = HttpStateManager::Instance().LoadAllRecords();
75-
for (auto const& rec : records)
80+
7681
{
77-
if (!rec.lastGid.empty())
82+
std::lock_guard<std::mutex> lock(m_mutex);
83+
m_aria2 = std::move(aria2);
84+
85+
for (auto const& rec : records)
7886
{
79-
m_gidToRecordId[rec.lastGid] = rec.recordId;
87+
if (!rec.lastGid.empty())
88+
{
89+
m_gidToRecordId[rec.lastGid] = rec.recordId;
90+
}
8091
}
92+
93+
// Start periodic refresh thread
94+
m_stopRefresh.store(false);
95+
m_refreshThread = std::thread([this]()
96+
{
97+
RefreshThreadEntry();
98+
});
99+
100+
m_initialized = true;
101+
m_initializing = false;
81102
}
82103
}
83-
84-
// Start periodic refresh thread
85-
m_stopRefresh.store(false);
86-
m_refreshThread = std::thread([this]()
104+
catch (...)
87105
{
88-
RefreshThreadEntry();
89-
});
90-
91-
m_initialized = true;
106+
{
107+
std::lock_guard<std::mutex> lock(m_mutex);
108+
m_initializing = false;
109+
}
110+
throw;
111+
}
92112
}
93113

94114
void DownloadManager::Shutdown()
@@ -341,7 +361,10 @@ namespace OpenNet::Core
341361
// Sleep remainder of interval, wake immediately if stopped
342362
{
343363
std::unique_lock<std::mutex> lock(m_stopMutex);
344-
m_stopCv.wait_for(lock, kInterval, [this] { return m_stopRefresh.load(); });
364+
m_stopCv.wait_for(lock, kInterval, [this]
365+
{
366+
return m_stopRefresh.load();
367+
});
345368
}
346369
}
347370
}

‎OpenNet/Core/DownloadManager.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ namespace OpenNet::Core
108108
private:
109109
std::unique_ptr<Aria2::LocalAria2Instance> m_aria2;
110110
bool m_initialized = false;
111+
bool m_initializing = false;
111112

112113
std::thread m_refreshThread;
113114
std::atomic<bool> m_stopRefresh{ false };

‎OpenNet/MainWindow.idl‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace OpenNet
66
runtimeclass MainWindow : Microsoft.UI.Xaml.Window
77
{
88
MainWindow();
9+
Microsoft.UI.Xaml.Visibility IsDebug { get; };
910
OpenNet.ViewModels.MainViewModel ViewModel { get; };
1011
void Navigate(String tag);
1112
}

‎OpenNet/MainWindow.xaml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@
4040
AutomationProperties.AccessibilityView="Raw"
4141
Source="ms-appx:///Assets/AppIcons/Square44x44Logo.altform-lightunplated_targetsize-256.png" />
4242
</TitleBar.LeftHeader>
43+
<TitleBar.RightHeader>
44+
<StackPanel
45+
Margin="0,0,6,0"
46+
Orientation="Horizontal"
47+
Spacing="6">
48+
<StackPanel.Resources>
49+
<Style
50+
x:Key="SettingButtonStyle"
51+
BasedOn="{StaticResource DefaultButtonStyle}"
52+
TargetType="Button">
53+
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
54+
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
55+
<Setter Property="HorizontalAlignment" Value="Stretch" />
56+
<Setter Property="HorizontalContentAlignment" Value="Center" />
57+
<Setter Property="MinWidth" Value="120" />
58+
<Setter Property="Padding" Value="16,6,16,6" />
59+
</Style>
60+
</StackPanel.Resources>
61+
<Button
62+
Padding="6"
63+
Click="InvertAppThemeButton_Click"
64+
Content="[Dev] Invert Theme"
65+
Style="{ThemeResource SettingButtonStyle}"
66+
Visibility="{x:Bind IsDebug, Mode=OneTime}" />
67+
</StackPanel>
68+
</TitleBar.RightHeader>
4369
</TitleBar>
4470

4571
<!-- Main content: NavigationView + StatusBar -->

0 commit comments

Comments
 (0)