From 6fb7af3d46953d02d34dcd7f6623d727fa82aff0 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 26 Jul 2025 14:29:24 +0800
Subject: [PATCH] =?UTF-8?q?add:=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?=
=?UTF-8?q?=E5=88=86=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 17 +
Ink Canvas/Helpers/AutoUpdateHelper.cs | 55 +-
Ink Canvas/Helpers/DeviceIdentifier.cs | 2655 +++++++++++++++++
Ink Canvas/MainWindow.xaml | 32 +
Ink Canvas/MainWindow.xaml.cs | 95 +
.../InkCanvasForClass_MarkupCompile.cache | 2 +-
6 files changed, 2847 insertions(+), 9 deletions(-)
create mode 100644 Ink Canvas/Helpers/DeviceIdentifier.cs
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index c3c3c192..e632c49d 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -432,6 +432,12 @@ namespace Ink_Canvas
LogHelper.NewLog(string.Format("Ink Canvas Starting (Version: {0})", Assembly.GetExecutingAssembly().GetName().Version.ToString()));
+ // 记录应用启动(设备标识符)
+ DeviceIdentifier.RecordAppLaunch();
+ LogHelper.WriteLogToFile($"App | 设备ID: {DeviceIdentifier.GetDeviceId()}");
+ LogHelper.WriteLogToFile($"App | 使用频率: {DeviceIdentifier.GetUsageFrequency()}");
+ LogHelper.WriteLogToFile($"App | 更新优先级: {DeviceIdentifier.GetUpdatePriority()}");
+
bool ret;
mutex = new System.Threading.Mutex(true, "InkCanvasForClass", out ret);
@@ -710,6 +716,17 @@ namespace Ink_Canvas
string exitType = IsAppExitByUser ? "用户主动退出" : "应用程序退出";
WriteCrashLog($"{exitType},退出代码: {e.ApplicationExitCode}");
+ // 记录应用退出(设备标识符)
+ try
+ {
+ DeviceIdentifier.RecordAppExit();
+ LogHelper.WriteLogToFile($"App | 应用运行时长: {(DateTime.Now - appStartTime).TotalMinutes:F1}分钟");
+ }
+ catch (Exception deviceEx)
+ {
+ LogHelper.WriteLogToFile($"记录设备标识符退出信息失败: {deviceEx.Message}", LogHelper.LogType.Error);
+ }
+
if (IsAppExitByUser)
{
// 写入退出信号文件,通知看门狗正常退出
diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs
index 30e54eae..578651c9 100644
--- a/Ink Canvas/Helpers/AutoUpdateHelper.cs
+++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs
@@ -396,7 +396,7 @@ namespace Ink_Canvas.Helpers
}
// 通过GitHub API获取最新Release信息
- private static async Task<(string version, string downloadUrl, string releaseNotes)> GetLatestGithubRelease(UpdateChannel channel)
+ private static async Task<(string version, string downloadUrl, string releaseNotes, DateTime? releaseTime)> GetLatestGithubRelease(UpdateChannel channel)
{
try
{
@@ -411,15 +411,23 @@ namespace Ink_Canvas.Helpers
string version = json["tag_name"]?.ToString();
string releaseNotes = json["body"]?.ToString();
string downloadUrl = json["assets"]?.First?["browser_download_url"]?.ToString();
+
+ // 解析发布时间
+ DateTime? releaseTime = null;
+ if (json["published_at"] != null && DateTime.TryParse(json["published_at"].ToString(), out DateTime parsedTime))
+ {
+ releaseTime = parsedTime;
+ }
+
if (!string.IsNullOrEmpty(version) && !string.IsNullOrEmpty(downloadUrl))
- return (version, downloadUrl, releaseNotes);
+ return (version, downloadUrl, releaseNotes, releaseTime);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | GitHub Releases API 获取失败: {ex.Message}", LogHelper.LogType.Warning);
}
- return (null, null, null);
+ return (null, null, null, null);
}
// 主要的更新检测方法(优先检测延迟,失败时自动切换线路组)
@@ -428,11 +436,17 @@ namespace Ink_Canvas.Helpers
{
try
{
+ // 记录更新检查时间
+ DeviceIdentifier.RecordUpdateCheck();
+
string localVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
LogHelper.WriteLogToFile($"AutoUpdate | 本地版本: {localVersion}");
+ LogHelper.WriteLogToFile($"AutoUpdate | 设备ID: {DeviceIdentifier.GetDeviceId()}");
+ LogHelper.WriteLogToFile($"AutoUpdate | 更新优先级: {DeviceIdentifier.GetUpdatePriority()}");
LogHelper.WriteLogToFile($"AutoUpdate | 优先通过GitHub Releases API检测...");
+
// 1. 优先通过GitHub Releases API获取
- var (apiVersion, _, apiReleaseNotes) = await GetLatestGithubRelease(channel);
+ var (apiVersion, _, apiReleaseNotes, apiReleaseTime) = await GetLatestGithubRelease(channel);
if (!string.IsNullOrEmpty(apiVersion))
{
Version local = new Version(localVersion);
@@ -440,15 +454,29 @@ namespace Ink_Canvas.Helpers
if (remote > local || alwaysGetRemote)
{
LogHelper.WriteLogToFile($"AutoUpdate | 通过GitHub Releases API发现新版本: {apiVersion}");
+
+ // 检查是否应该根据用户优先级推送更新
+ DateTime releaseTime = apiReleaseTime ?? DateTime.Now;
+ bool shouldPush = DeviceIdentifier.ShouldPushUpdate(apiVersion, releaseTime);
+ if (!shouldPush)
+ {
+ var priority = DeviceIdentifier.GetUpdatePriority();
+ var daysSinceRelease = (DateTime.Now - releaseTime).TotalDays;
+ LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级({priority}),暂不推送更新 {apiVersion},发布时间: {releaseTime:yyyy-MM-dd HH:mm:ss},已过 {daysSinceRelease:F1} 天");
+ var group = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
+ return (null, group, apiReleaseNotes); // 返回null表示不推送
+ }
+
+ LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级,推送更新 {apiVersion}");
// 只返回版本号和日志,不返回直链
- var group = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
- return (apiVersion, group, apiReleaseNotes);
+ var availableGroup = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
+ return (apiVersion, availableGroup, apiReleaseNotes);
}
else
{
LogHelper.WriteLogToFile($"AutoUpdate | 当前版本已是最新 (GitHub Releases API)");
- var group = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
- return (null, group, apiReleaseNotes);
+ var availableGroup = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
+ return (null, availableGroup, apiReleaseNotes);
}
}
// 2. 回退到原有txt方案
@@ -471,6 +499,17 @@ namespace Ink_Canvas.Helpers
if (remote > local || alwaysGetRemote)
{
LogHelper.WriteLogToFile($"AutoUpdate | 发现新版本或强制获取: {remoteVersion}");
+
+ // 检查是否应该根据用户优先级推送更新
+ bool shouldPush = DeviceIdentifier.ShouldPushUpdate(remoteVersion, DateTime.Now);
+ if (!shouldPush)
+ {
+ var priority = DeviceIdentifier.GetUpdatePriority();
+ LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级({priority}),暂不推送更新 {remoteVersion}");
+ return (null, group, null); // 返回null表示不推送
+ }
+
+ LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级,推送更新 {remoteVersion}");
return (remoteVersion, group, null);
}
else
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
new file mode 100644
index 00000000..f9ad2d69
--- /dev/null
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -0,0 +1,2655 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+using Microsoft.Win32;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 设备标识符和使用频率监控类
+ ///
+ internal static class DeviceIdentifier
+ {
+ // 多重备份路径策略
+ private static readonly string DeviceIdFilePath = Path.Combine(App.RootPath, "device_id.dat");
+ private static readonly string UsageStatsFilePath = Path.Combine(App.RootPath, "usage_stats.json");
+
+ // 使用频率数据的多重隐藏备份路径
+ private static readonly string BackupDeviceIdPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "ICC", ".sys", "device.dat");
+ private static readonly string BackupUsageStatsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "ICC", ".sys", "usage.dat");
+
+ // 使用频率数据的额外隐藏备份位置
+ private static readonly string SecondaryUsageBackupPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "Microsoft", "Windows", ".icc", "usage_backup.tmp");
+ private static readonly string TertiaryUsageBackupPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
+ "ICC", ".cache", "usage_cache.dat");
+ private static readonly string QuaternaryUsageBackupPath = Path.Combine(Path.GetTempPath(),
+ ".icc_temp", "usage_temp.dat");
+
+ // 数据完整性验证密钥
+ private static readonly string DataIntegrityKey = "ICC_DEVICE_INTEGRITY_2024";
+
+ private static readonly string DeviceId = null;
+ private static readonly object fileLock = new object();
+
+ static DeviceIdentifier()
+ {
+ // 在静态构造函数中初始化设备ID
+ DeviceId = GetOrCreateDeviceId();
+
+ // 执行数据完整性检查和自动修复
+ try
+ {
+ PerformDataIntegrityCheck();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 初始化时数据完整性检查失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 获取或创建设备ID
+ ///
+ /// 25字符的唯一设备标识符
+ public static string GetDeviceId()
+ {
+ return DeviceId;
+ }
+
+ ///
+ /// 获取或创建设备ID(内部方法)- 支持多重备份恢复
+ ///
+ private static string GetOrCreateDeviceId()
+ {
+ lock (fileLock)
+ {
+ try
+ {
+ // 1. 尝试从主文件读取设备ID
+ string deviceId = LoadDeviceIdFromFile(DeviceIdFilePath);
+ if (!string.IsNullOrEmpty(deviceId))
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从主文件读取设备ID: {deviceId}");
+ // 确保备份同步
+ SaveDeviceIdToAllLocations(deviceId);
+ return deviceId;
+ }
+
+ // 2. 尝试从备份文件恢复
+ deviceId = LoadDeviceIdFromFile(BackupDeviceIdPath);
+ if (!string.IsNullOrEmpty(deviceId))
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从备份文件恢复设备ID: {deviceId}");
+ SaveDeviceIdToAllLocations(deviceId);
+ return deviceId;
+ }
+
+ // 3. 尝试从注册表恢复
+ deviceId = LoadDeviceIdFromRegistry();
+ if (!string.IsNullOrEmpty(deviceId))
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表恢复设备ID: {deviceId}");
+ SaveDeviceIdToAllLocations(deviceId);
+ return deviceId;
+ }
+
+ // 4. 生成新的设备ID
+ string newDeviceId = GenerateDeviceId();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 生成新设备ID: {newDeviceId}");
+
+ // 5. 保存到所有位置
+ SaveDeviceIdToAllLocations(newDeviceId);
+
+ return newDeviceId;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取设备ID时出错: {ex.Message}", LogHelper.LogType.Error);
+ // 返回一个基于时间戳的备用ID
+ return GenerateFallbackDeviceId();
+ }
+ }
+ }
+
+ ///
+ /// 生成25字符的唯一设备ID
+ ///
+ private static string GenerateDeviceId()
+ {
+ try
+ {
+ // 收集硬件信息
+ var hardwareInfo = new StringBuilder();
+
+ // 使用反射获取硬件信息,避免直接引用System.Management
+ try
+ {
+ // 尝试加载System.Management程序集
+ var assembly = System.Reflection.Assembly.Load("System.Management");
+ if (assembly != null)
+ {
+ // CPU信息
+ try
+ {
+ var searcherType = assembly.GetType("System.Management.ManagementObjectSearcher");
+ var searcher = Activator.CreateInstance(searcherType, "SELECT ProcessorId FROM Win32_Processor");
+ var getMethod = searcherType.GetMethod("Get");
+ var enumerator = getMethod.Invoke(searcher, null);
+
+ var moveNextMethod = enumerator.GetType().GetMethod("MoveNext");
+ var currentProperty = enumerator.GetType().GetProperty("Current");
+
+ if ((bool)moveNextMethod.Invoke(enumerator, null))
+ {
+ var obj = currentProperty.GetValue(enumerator);
+ var indexer = obj.GetType().GetProperty("Item", new[] { typeof(string) });
+ var processorId = indexer.GetValue(obj, new object[] { "ProcessorId" });
+ hardwareInfo.Append(processorId?.ToString() ?? "");
+ }
+
+ var disposeMethod = searcher.GetType().GetMethod("Dispose");
+ disposeMethod?.Invoke(searcher, null);
+ }
+ catch { }
+
+ // 主板序列号
+ try
+ {
+ var searcherType = assembly.GetType("System.Management.ManagementObjectSearcher");
+ var searcher = Activator.CreateInstance(searcherType, "SELECT SerialNumber FROM Win32_BaseBoard");
+ var getMethod = searcherType.GetMethod("Get");
+ var enumerator = getMethod.Invoke(searcher, null);
+
+ var moveNextMethod = enumerator.GetType().GetMethod("MoveNext");
+ var currentProperty = enumerator.GetType().GetProperty("Current");
+
+ if ((bool)moveNextMethod.Invoke(enumerator, null))
+ {
+ var obj = currentProperty.GetValue(enumerator);
+ var indexer = obj.GetType().GetProperty("Item", new[] { typeof(string) });
+ var serialNumber = indexer.GetValue(obj, new object[] { "SerialNumber" });
+ hardwareInfo.Append(serialNumber?.ToString() ?? "");
+ }
+
+ var disposeMethod = searcher.GetType().GetMethod("Dispose");
+ disposeMethod?.Invoke(searcher, null);
+ }
+ catch { }
+
+ // BIOS序列号
+ try
+ {
+ var searcherType = assembly.GetType("System.Management.ManagementObjectSearcher");
+ var searcher = Activator.CreateInstance(searcherType, "SELECT SerialNumber FROM Win32_BIOS");
+ var getMethod = searcherType.GetMethod("Get");
+ var enumerator = getMethod.Invoke(searcher, null);
+
+ var moveNextMethod = enumerator.GetType().GetMethod("MoveNext");
+ var currentProperty = enumerator.GetType().GetProperty("Current");
+
+ if ((bool)moveNextMethod.Invoke(enumerator, null))
+ {
+ var obj = currentProperty.GetValue(enumerator);
+ var indexer = obj.GetType().GetProperty("Item", new[] { typeof(string) });
+ var serialNumber = indexer.GetValue(obj, new object[] { "SerialNumber" });
+ hardwareInfo.Append(serialNumber?.ToString() ?? "");
+ }
+
+ var disposeMethod = searcher.GetType().GetMethod("Dispose");
+ disposeMethod?.Invoke(searcher, null);
+ }
+ catch { }
+
+ // 主硬盘序列号
+ try
+ {
+ var searcherType = assembly.GetType("System.Management.ManagementObjectSearcher");
+ var searcher = Activator.CreateInstance(searcherType, "SELECT SerialNumber FROM Win32_DiskDrive WHERE MediaType='Fixed hard disk media'");
+ var getMethod = searcherType.GetMethod("Get");
+ var enumerator = getMethod.Invoke(searcher, null);
+
+ var moveNextMethod = enumerator.GetType().GetMethod("MoveNext");
+ var currentProperty = enumerator.GetType().GetProperty("Current");
+
+ if ((bool)moveNextMethod.Invoke(enumerator, null))
+ {
+ var obj = currentProperty.GetValue(enumerator);
+ var indexer = obj.GetType().GetProperty("Item", new[] { typeof(string) });
+ var serialNumber = indexer.GetValue(obj, new object[] { "SerialNumber" });
+ hardwareInfo.Append(serialNumber?.ToString() ?? "");
+ }
+
+ var disposeMethod = searcher.GetType().GetMethod("Dispose");
+ disposeMethod?.Invoke(searcher, null);
+ }
+ catch { }
+ }
+ }
+ catch { }
+
+ // 如果硬件信息不足,添加系统信息
+ if (hardwareInfo.Length < 10)
+ {
+ hardwareInfo.Append(Environment.MachineName);
+ hardwareInfo.Append(Environment.UserName);
+ hardwareInfo.Append(Environment.OSVersion.ToString());
+ }
+
+ // 生成哈希
+ using (var sha256 = SHA256.Create())
+ {
+ byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(hardwareInfo.ToString()));
+ string hashString = BitConverter.ToString(hashBytes).Replace("-", "");
+
+ // 取前25个字符,确保唯一性
+ string deviceId = hashString.Substring(0, 25);
+
+ // 添加校验位(第25位)
+ int checksum = 0;
+ for (int i = 0; i < 24; i++)
+ {
+ checksum += Convert.ToInt32(deviceId[i]);
+ }
+ checksum %= 36; // 0-9, A-Z
+ char checksumChar = checksum < 10 ? (char)(checksum + '0') : (char)(checksum - 10 + 'A');
+
+ return deviceId.Substring(0, 24) + checksumChar;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 生成设备ID时出错: {ex.Message}", LogHelper.LogType.Error);
+ return GenerateFallbackDeviceId();
+ }
+ }
+
+ ///
+ /// 生成备用设备ID(基于时间戳)
+ ///
+ private static string GenerateFallbackDeviceId()
+ {
+ try
+ {
+ string timestamp = DateTime.Now.Ticks.ToString("X");
+ string random = Guid.NewGuid().ToString("N").Substring(0, 8);
+ string combined = timestamp + random;
+
+ using (var sha256 = SHA256.Create())
+ {
+ byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(combined));
+ string hashString = BitConverter.ToString(hashBytes).Replace("-", "");
+ return hashString.Substring(0, 25);
+ }
+ }
+ catch
+ {
+ // 最后的备用方案
+ return "ICC" + DateTime.Now.ToString("yyyyMMddHHmmss") + "000000000";
+ }
+ }
+
+ ///
+ /// 验证设备ID格式
+ ///
+ private static bool IsValidDeviceId(string deviceId)
+ {
+ if (string.IsNullOrEmpty(deviceId) || deviceId.Length != 25)
+ return false;
+
+ // 验证字符集(只允许数字和大写字母)
+ if (!deviceId.All(c => char.IsLetterOrDigit(c) && (char.IsDigit(c) || char.IsUpper(c))))
+ return false;
+
+ // 验证校验位
+ try
+ {
+ int checksum = 0;
+ for (int i = 0; i < 24; i++)
+ {
+ checksum += Convert.ToInt32(deviceId[i]);
+ }
+ checksum %= 36;
+ char expectedChecksum = checksum < 10 ? (char)(checksum + '0') : (char)(checksum - 10 + 'A');
+ return deviceId[24] == expectedChecksum;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// 从文件加载设备ID
+ ///
+ private static string LoadDeviceIdFromFile(string filePath)
+ {
+ try
+ {
+ if (File.Exists(filePath))
+ {
+ string content = File.ReadAllText(filePath).Trim();
+ if (IsValidDeviceId(content))
+ {
+ return content;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从文件加载设备ID失败 ({filePath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 从注册表加载设备ID
+ ///
+ private static string LoadDeviceIdFromRegistry()
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ if (key != null)
+ {
+ var value = key.GetValue("DeviceId") as string;
+ if (IsValidDeviceId(value))
+ {
+ return value;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表加载设备ID失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 保存设备ID到所有位置
+ ///
+ private static void SaveDeviceIdToAllLocations(string deviceId)
+ {
+ // 保存到主文件
+ SaveDeviceIdToFile(DeviceIdFilePath, deviceId);
+
+ // 保存到备份文件
+ SaveDeviceIdToFile(BackupDeviceIdPath, deviceId);
+
+ // 保存到注册表
+ SaveDeviceIdToRegistry(deviceId);
+ }
+
+ ///
+ /// 保存设备ID到文件
+ ///
+ private static void SaveDeviceIdToFile(string filePath, string deviceId)
+ {
+ try
+ {
+ // 确保目录存在
+ var directory = Path.GetDirectoryName(filePath);
+ if (!Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ // 设置隐藏属性
+ if (filePath.Contains(".sys"))
+ {
+ var dirInfo = new DirectoryInfo(directory);
+ dirInfo.Attributes |= FileAttributes.Hidden | FileAttributes.System;
+ }
+ }
+
+ File.WriteAllText(filePath, deviceId);
+
+ // 设置文件属性为隐藏和系统文件
+ if (filePath.Contains(".sys"))
+ {
+ var fileInfo = new FileInfo(filePath);
+ fileInfo.Attributes |= FileAttributes.Hidden | FileAttributes.System;
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 设备ID已保存到: {filePath}");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存设备ID到文件失败 ({filePath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 保存设备ID到注册表
+ ///
+ private static void SaveDeviceIdToRegistry(string deviceId)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.CreateSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ key?.SetValue("DeviceId", deviceId);
+ key?.SetValue("LastUpdate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
+ }
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 设备ID已保存到注册表");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存设备ID到注册表失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 使用频率统计数据结构
+ ///
+ private class UsageStats
+ {
+ [JsonProperty("deviceId")]
+ public string DeviceId { get; set; }
+
+ [JsonProperty("lastLaunchTime")]
+ public DateTime LastLaunchTime { get; set; }
+
+ [JsonProperty("launchCount")]
+ public int LaunchCount { get; set; }
+
+ [JsonProperty("totalUsageMinutes")]
+ public long TotalUsageMinutes { get; set; }
+
+ [JsonProperty("averageSessionMinutes")]
+ public double AverageSessionMinutes { get; set; }
+
+ [JsonProperty("lastUpdateCheck")]
+ public DateTime LastUpdateCheck { get; set; }
+
+ [JsonProperty("updatePriority")]
+ public UpdatePriority UpdatePriority { get; set; }
+
+ [JsonProperty("usageFrequency")]
+ public UsageFrequency UsageFrequency { get; set; }
+
+ [JsonProperty("dataHash")]
+ public string DataHash { get; set; }
+
+ [JsonProperty("lastModified")]
+ public DateTime LastModified { get; set; }
+
+ ///
+ /// 计算数据哈希值用于完整性验证
+ ///
+ public void UpdateDataHash()
+ {
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{DataIntegrityKey}";
+ using (var sha256 = SHA256.Create())
+ {
+ var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
+ DataHash = Convert.ToBase64String(hashBytes);
+ }
+ LastModified = DateTime.Now;
+ }
+
+ ///
+ /// 验证数据完整性
+ ///
+ public bool VerifyDataIntegrity()
+ {
+ try
+ {
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{DataIntegrityKey}";
+ using (var sha256 = SHA256.Create())
+ {
+ var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
+ var expectedHash = Convert.ToBase64String(hashBytes);
+ return DataHash == expectedHash;
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// 更新优先级枚举
+ ///
+ public enum UpdatePriority
+ {
+ High = 1, // 高频用户,优先推送
+ Medium = 2, // 中频用户,正常推送
+ Low = 3 // 低频用户,延迟推送
+ }
+
+ ///
+ /// 使用频率枚举
+ ///
+ public enum UsageFrequency
+ {
+ High = 1, // 高频用户:每周使用超过5次或总时长超过10小时
+ Medium = 2, // 中频用户:每周使用2-5次或总时长2-10小时
+ Low = 3 // 低频用户:每周使用少于2次或总时长少于2小时
+ }
+
+ ///
+ /// 记录应用启动
+ ///
+ public static void RecordAppLaunch()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ var stats = LoadUsageStats();
+ stats.LastLaunchTime = DateTime.Now;
+ stats.LaunchCount++;
+ stats.DeviceId = DeviceId;
+
+ // 计算使用频率
+ CalculateUsageFrequency(stats);
+
+ // 更新数据完整性哈希
+ stats.UpdateDataHash();
+
+ SaveUsageStats(stats);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用启动 - 设备ID: {DeviceId}, 启动次数: {stats.LaunchCount}");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用启动失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 记录应用退出(计算使用时长)
+ ///
+ public static void RecordAppExit()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ var stats = LoadUsageStats();
+
+ // 计算本次会话时长
+ if (stats.LastLaunchTime != DateTime.MinValue)
+ {
+ var sessionDuration = DateTime.Now - stats.LastLaunchTime;
+ stats.TotalUsageMinutes += (long)sessionDuration.TotalMinutes;
+
+ // 更新平均会话时长
+ if (stats.LaunchCount > 0)
+ {
+ stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ }
+ }
+
+ // 重新计算使用频率
+ CalculateUsageFrequency(stats);
+
+ // 更新数据完整性哈希
+ stats.UpdateDataHash();
+
+ SaveUsageStats(stats);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出 - 总使用时长: {stats.TotalUsageMinutes}分钟, 平均会话: {stats.AverageSessionMinutes:F1}分钟");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 计算使用频率和更新优先级(综合考虑时间和使用模式)
+ ///
+ private static void CalculateUsageFrequency(UsageStats stats)
+ {
+ try
+ {
+ // 计算最近活跃度
+ var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
+
+ // 计算平均使用强度
+ var avgMinutesPerLaunch = stats.LaunchCount > 0 ? (double)stats.TotalUsageMinutes / stats.LaunchCount : 0;
+
+ // 估算最近使用情况(基于历史模式)
+ var estimatedRecentLaunches = EstimateRecentActivity(stats, daysSinceLastUse);
+ var estimatedRecentMinutes = estimatedRecentLaunches * avgMinutesPerLaunch;
+
+ // 综合评分系统
+ var frequencyScore = CalculateFrequencyScore(stats, daysSinceLastUse, estimatedRecentLaunches, estimatedRecentMinutes);
+
+ // 根据综合评分确定频率和优先级
+ if (frequencyScore >= 80)
+ {
+ stats.UsageFrequency = UsageFrequency.High;
+ stats.UpdatePriority = UpdatePriority.High;
+ }
+ else if (frequencyScore >= 40)
+ {
+ stats.UsageFrequency = UsageFrequency.Medium;
+ stats.UpdatePriority = UpdatePriority.Medium;
+ }
+ else
+ {
+ stats.UsageFrequency = UsageFrequency.Low;
+ stats.UpdatePriority = UpdatePriority.Low;
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率计算 - 评分: {frequencyScore}, 频率: {stats.UsageFrequency}, " +
+ $"优先级: {stats.UpdatePriority}, 最后使用: {daysSinceLastUse:F1}天前");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 计算使用频率失败: {ex.Message}", LogHelper.LogType.Error);
+ // 默认设置为中等优先级
+ stats.UsageFrequency = UsageFrequency.Medium;
+ stats.UpdatePriority = UpdatePriority.Medium;
+ }
+ }
+
+ ///
+ /// 估算最近活跃度
+ ///
+ private static int EstimateRecentActivity(UsageStats stats, double daysSinceLastUse)
+ {
+ if (daysSinceLastUse > 30) return 0; // 超过30天未使用
+ if (daysSinceLastUse > 14) return Math.Min(1, stats.LaunchCount / 50); // 14-30天,很少活动
+ if (daysSinceLastUse > 7) return Math.Min(3, stats.LaunchCount / 20); // 7-14天,少量活动
+ if (daysSinceLastUse > 3) return Math.Min(7, stats.LaunchCount / 10); // 3-7天,中等活动
+ return Math.Min(15, stats.LaunchCount / 5); // 3天内,高活动
+ }
+
+ ///
+ /// 计算综合频率评分(0-100分)
+ ///
+ private static int CalculateFrequencyScore(UsageStats stats, double daysSinceLastUse,
+ int estimatedRecentLaunches, double estimatedRecentMinutes)
+ {
+ var score = 0;
+
+ // 最近活跃度评分(40分)
+ if (daysSinceLastUse <= 1) score += 40;
+ else if (daysSinceLastUse <= 3) score += 35;
+ else if (daysSinceLastUse <= 7) score += 25;
+ else if (daysSinceLastUse <= 14) score += 15;
+ else if (daysSinceLastUse <= 30) score += 5;
+
+ // 使用频率评分(30分)
+ if (estimatedRecentLaunches >= 10) score += 30;
+ else if (estimatedRecentLaunches >= 5) score += 20;
+ else if (estimatedRecentLaunches >= 2) score += 10;
+ else if (estimatedRecentLaunches >= 1) score += 5;
+
+ // 使用时长评分(20分)
+ if (estimatedRecentMinutes >= 600) score += 20; // 10小时以上
+ else if (estimatedRecentMinutes >= 300) score += 15; // 5小时以上
+ else if (estimatedRecentMinutes >= 120) score += 10; // 2小时以上
+ else if (estimatedRecentMinutes >= 60) score += 5; // 1小时以上
+
+ // 历史使用深度评分(10分)
+ if (stats.TotalUsageMinutes >= 3000) score += 10; // 重度用户
+ else if (stats.TotalUsageMinutes >= 1200) score += 7; // 中度用户
+ else if (stats.TotalUsageMinutes >= 300) score += 4; // 轻度用户
+
+ return Math.Min(100, score);
+ }
+
+ ///
+ /// 获取当前更新优先级
+ ///
+ public static UpdatePriority GetUpdatePriority()
+ {
+ try
+ {
+ var stats = LoadUsageStats();
+ return stats.UpdatePriority;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取更新优先级失败: {ex.Message}", LogHelper.LogType.Error);
+ return UpdatePriority.Medium; // 默认中等优先级
+ }
+ }
+
+ ///
+ /// 获取使用频率
+ ///
+ public static UsageFrequency GetUsageFrequency()
+ {
+ try
+ {
+ var stats = LoadUsageStats();
+ return stats.UsageFrequency;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取使用频率失败: {ex.Message}", LogHelper.LogType.Error);
+ return UsageFrequency.Medium; // 默认中等频率
+ }
+ }
+
+ ///
+ /// 获取使用统计信息
+ ///
+ public static (int launchCount, long totalMinutes, double avgSession, UpdatePriority priority) GetUsageStats()
+ {
+ try
+ {
+ var stats = LoadUsageStats();
+ return (stats.LaunchCount, stats.TotalUsageMinutes, stats.AverageSessionMinutes, stats.UpdatePriority);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取使用统计失败: {ex.Message}", LogHelper.LogType.Error);
+ return (0, 0, 0, UpdatePriority.Medium);
+ }
+ }
+
+ ///
+ /// 加载使用统计 - 支持多重备份恢复和智能反篡改(强化版本)
+ ///
+ private static UsageStats LoadUsageStats()
+ {
+ try
+ {
+ // 智能恢复:收集所有可用的数据源,选择最可信的
+ var allDataSources = CollectAllUsageDataSources();
+
+ // 如果找到有效数据,返回最可信的
+ if (allDataSources.Count > 0)
+ {
+ var bestData = SelectMostTrustedData(allDataSources);
+ if (bestData != null)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用最可信数据源恢复使用统计: {bestData.Source}");
+
+ // 确保备份同步
+ SaveUsageStatsToAllLocations(bestData.Stats);
+ return bestData.Stats;
+ }
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 所有数据源都不可用,检查是否有部分可恢复数据", LogHelper.LogType.Warning);
+
+ // 如果没有完全可信的数据,尝试从部分损坏的数据中恢复
+ var partiallyRecoveredData = AttemptPartialDataRecovery(allDataSources);
+ if (partiallyRecoveredData != null)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从部分损坏数据中恢复使用统计");
+ SaveUsageStatsToAllLocations(partiallyRecoveredData);
+ return partiallyRecoveredData;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 加载使用统计失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+
+ // 返回新的统计对象
+ var newStats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LastLaunchTime = DateTime.Now,
+ LaunchCount = 0,
+ TotalUsageMinutes = 0,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue,
+ UpdatePriority = UpdatePriority.Medium,
+ UsageFrequency = UsageFrequency.Medium
+ };
+
+ // 更新数据完整性哈希
+ newStats.UpdateDataHash();
+
+ // 保存新统计到所有位置
+ SaveUsageStatsToAllLocations(newStats);
+ return newStats;
+ }
+
+ ///
+ /// 保存使用统计 - 多重备份
+ ///
+ private static void SaveUsageStats(UsageStats stats)
+ {
+ SaveUsageStatsToAllLocations(stats);
+ }
+
+ ///
+ /// 数据源信息结构
+ ///
+ private class DataSourceInfo
+ {
+ public UsageStats Stats { get; set; }
+ public string Source { get; set; }
+ public bool IsIntegrityValid { get; set; }
+ public DateTime LastModified { get; set; }
+ public int TrustScore { get; set; }
+ }
+
+ ///
+ /// 从文件加载使用统计(带完整性验证,但不丢弃篡改数据)
+ ///
+ private static UsageStats LoadUsageStatsFromFile(string filePath)
+ {
+ try
+ {
+ if (File.Exists(filePath))
+ {
+ string json = File.ReadAllText(filePath);
+ var stats = JsonConvert.DeserializeObject(json);
+ if (stats != null && !string.IsNullOrEmpty(stats.DeviceId))
+ {
+ // 验证数据完整性
+ if (!string.IsNullOrEmpty(stats.DataHash))
+ {
+ if (stats.VerifyDataIntegrity())
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据完整性验证通过: {filePath}");
+ return stats;
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据完整性验证失败,可能被篡改: {filePath}", LogHelper.LogType.Warning);
+ return null; // 数据被篡改,不使用
+ }
+ }
+ else
+ {
+ // 旧版本数据,没有哈希值,更新哈希后返回
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 检测到旧版本数据,正在更新完整性哈希: {filePath}");
+ stats.UpdateDataHash();
+ return stats;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从文件加载使用统计失败 ({filePath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 从文件加载使用统计(包括被篡改的数据,用于恢复分析)
+ ///
+ private static DataSourceInfo LoadUsageStatsFromFileWithInfo(string filePath, string sourceName)
+ {
+ try
+ {
+ if (File.Exists(filePath))
+ {
+ string json = File.ReadAllText(filePath);
+ var stats = JsonConvert.DeserializeObject(json);
+ if (stats != null && !string.IsNullOrEmpty(stats.DeviceId))
+ {
+ var fileInfo = new FileInfo(filePath);
+ var dataSource = new DataSourceInfo
+ {
+ Stats = stats,
+ Source = sourceName,
+ LastModified = stats.LastModified != DateTime.MinValue ? stats.LastModified : fileInfo.LastWriteTime,
+ IsIntegrityValid = false,
+ TrustScore = 0
+ };
+
+ // 验证数据完整性
+ if (!string.IsNullOrEmpty(stats.DataHash))
+ {
+ dataSource.IsIntegrityValid = stats.VerifyDataIntegrity();
+ dataSource.TrustScore = dataSource.IsIntegrityValid ? 100 : 20; // 完整数据100分,篡改数据20分
+ }
+ else
+ {
+ // 旧版本数据,中等信任度
+ dataSource.IsIntegrityValid = true;
+ dataSource.TrustScore = 60;
+ stats.UpdateDataHash();
+ }
+
+ return dataSource;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从文件加载数据源信息失败 ({filePath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 收集所有可用的使用统计数据源
+ ///
+ private static List CollectAllUsageDataSources()
+ {
+ var dataSources = new List();
+
+ try
+ {
+ // 1. 收集文件数据源
+ var fileSources = new[]
+ {
+ new { Path = UsageStatsFilePath, Name = "主文件" },
+ new { Path = BackupUsageStatsPath, Name = "第一备份" },
+ new { Path = SecondaryUsageBackupPath, Name = "第二备份" },
+ new { Path = TertiaryUsageBackupPath, Name = "第三备份" },
+ new { Path = QuaternaryUsageBackupPath, Name = "第四备份" }
+ };
+
+ foreach (var source in fileSources)
+ {
+ var dataSource = LoadUsageStatsFromFileWithInfo(source.Path, source.Name);
+ if (dataSource != null)
+ {
+ dataSources.Add(dataSource);
+ }
+ }
+
+ // 2. 收集注册表数据源
+ var registrySource = LoadUsageStatsFromRegistryWithInfo(@"Software\ICC\DeviceInfo", "主注册表");
+ if (registrySource != null)
+ {
+ dataSources.Add(registrySource);
+ }
+
+ // 3. 收集备用注册表数据源
+ var backupRegistryPaths = new[]
+ {
+ new { Path = @"Software\Microsoft\Windows\CurrentVersion\ICC", Name = "备用注册表1" },
+ new { Path = @"Software\Classes\.icc\UsageData", Name = "备用注册表2" },
+ new { Path = @"Software\ICC\Config\Usage", Name = "备用注册表3" }
+ };
+
+ foreach (var regPath in backupRegistryPaths)
+ {
+ var regSource = LoadUsageStatsFromBackupRegistryWithInfo(regPath.Path, regPath.Name);
+ if (regSource != null)
+ {
+ dataSources.Add(regSource);
+ }
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 收集到 {dataSources.Count} 个数据源");
+ return dataSources;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 收集数据源失败: {ex.Message}", LogHelper.LogType.Error);
+ return dataSources;
+ }
+ }
+
+ ///
+ /// 选择最可信的数据源
+ ///
+ private static DataSourceInfo SelectMostTrustedData(List dataSources)
+ {
+ try
+ {
+ // 首先尝试找到完整性验证通过的数据
+ var validSources = dataSources.Where(d => d.IsIntegrityValid).ToList();
+
+ if (validSources.Count > 0)
+ {
+ // 在有效数据中选择最新的
+ var bestValid = validSources.OrderByDescending(d => d.LastModified).First();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 选择完整性验证通过的最新数据: {bestValid.Source}");
+ return bestValid;
+ }
+
+ // 如果没有完整性验证通过的数据,选择信任度最高的
+ var bestByTrust = dataSources.OrderByDescending(d => d.TrustScore).ThenByDescending(d => d.LastModified).FirstOrDefault();
+ if (bestByTrust != null)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 选择信任度最高的数据: {bestByTrust.Source} (信任度: {bestByTrust.TrustScore})", LogHelper.LogType.Warning);
+ return bestByTrust;
+ }
+
+ return null;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 选择最可信数据失败: {ex.Message}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
+ ///
+ /// 尝试从部分损坏的数据中恢复
+ ///
+ private static UsageStats AttemptPartialDataRecovery(List dataSources)
+ {
+ try
+ {
+ if (dataSources.Count == 0)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 没有可用数据源进行部分恢复");
+ return null;
+ }
+
+ // 从所有数据源中提取可信的字段
+ var recoveredStats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LastLaunchTime = DateTime.Now,
+ LaunchCount = 0,
+ TotalUsageMinutes = 0,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue,
+ UpdatePriority = UpdatePriority.Medium,
+ UsageFrequency = UsageFrequency.Medium
+ };
+
+ // 使用多数投票或最大值策略恢复关键数据
+ var launchCounts = dataSources.Where(d => d.Stats.LaunchCount > 0).Select(d => d.Stats.LaunchCount).ToList();
+ var usageMinutes = dataSources.Where(d => d.Stats.TotalUsageMinutes > 0).Select(d => d.Stats.TotalUsageMinutes).ToList();
+
+ if (launchCounts.Count > 0)
+ {
+ recoveredStats.LaunchCount = (int)launchCounts.Average(); // 使用平均值
+ }
+
+ if (usageMinutes.Count > 0)
+ {
+ recoveredStats.TotalUsageMinutes = (long)usageMinutes.Average(); // 使用平均值
+ }
+
+ // 重新计算平均会话时长
+ if (recoveredStats.LaunchCount > 0)
+ {
+ recoveredStats.AverageSessionMinutes = (double)recoveredStats.TotalUsageMinutes / recoveredStats.LaunchCount;
+ }
+
+ // 重新计算使用频率
+ CalculateUsageFrequency(recoveredStats);
+
+ // 更新数据完整性哈希
+ recoveredStats.UpdateDataHash();
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复完成 - 启动次数: {recoveredStats.LaunchCount}, 使用时长: {recoveredStats.TotalUsageMinutes}分钟");
+ return recoveredStats;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复失败: {ex.Message}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
+ ///
+ /// 从注册表加载使用统计(带数据源信息)
+ ///
+ private static DataSourceInfo LoadUsageStatsFromRegistryWithInfo(string registryPath, string sourceName)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(registryPath))
+ {
+ if (key != null)
+ {
+ var deviceId = key.GetValue("DeviceId") as string;
+ var launchCount = key.GetValue("LaunchCount");
+ var totalMinutes = key.GetValue("TotalUsageMinutes");
+ var lastLaunch = key.GetValue("LastLaunchTime") as string;
+ var priority = key.GetValue("UpdatePriority");
+ var frequency = key.GetValue("UsageFrequency");
+ var dataHash = key.GetValue("DataHash") as string;
+ var lastUpdate = key.GetValue("LastUpdate") as string;
+
+ if (!string.IsNullOrEmpty(deviceId) && launchCount != null)
+ {
+ var stats = new UsageStats
+ {
+ DeviceId = deviceId,
+ LaunchCount = Convert.ToInt32(launchCount),
+ TotalUsageMinutes = totalMinutes != null ? Convert.ToInt64(totalMinutes) : 0,
+ LastLaunchTime = DateTime.TryParse(lastLaunch, out var dt) ? dt : DateTime.Now,
+ UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
+ UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
+ DataHash = dataHash,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue
+ };
+
+ // 重新计算平均会话时长
+ if (stats.LaunchCount > 0)
+ {
+ stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ }
+
+ var dataSource = new DataSourceInfo
+ {
+ Stats = stats,
+ Source = sourceName,
+ LastModified = DateTime.TryParse(lastUpdate, out var updateTime) ? updateTime : DateTime.Now,
+ IsIntegrityValid = false,
+ TrustScore = 80 // 注册表数据信任度较高
+ };
+
+ // 验证数据完整性
+ if (!string.IsNullOrEmpty(stats.DataHash))
+ {
+ dataSource.IsIntegrityValid = stats.VerifyDataIntegrity();
+ dataSource.TrustScore = dataSource.IsIntegrityValid ? 100 : 30;
+ }
+
+ return dataSource;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表加载数据源信息失败 ({registryPath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 从备用注册表位置加载使用统计(带数据源信息)
+ ///
+ private static DataSourceInfo LoadUsageStatsFromBackupRegistryWithInfo(string registryPath, string sourceName)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(registryPath))
+ {
+ if (key != null)
+ {
+ var launchCount = key.GetValue("LC");
+ var totalMinutes = key.GetValue("TUM");
+ var lastLaunchBinary = key.GetValue("LLT");
+ var priority = key.GetValue("UP");
+ var frequency = key.GetValue("UF");
+ var dataHash = key.GetValue("DH") as string;
+ var lastUpdateBinary = key.GetValue("LU");
+
+ if (launchCount != null && totalMinutes != null)
+ {
+ var stats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LaunchCount = Convert.ToInt32(launchCount),
+ TotalUsageMinutes = Convert.ToInt64(totalMinutes),
+ LastLaunchTime = lastLaunchBinary != null ? DateTime.FromBinary(Convert.ToInt64(lastLaunchBinary)) : DateTime.Now,
+ UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
+ UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
+ DataHash = dataHash,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue
+ };
+
+ // 重新计算平均会话时长
+ if (stats.LaunchCount > 0)
+ {
+ stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ }
+
+ var dataSource = new DataSourceInfo
+ {
+ Stats = stats,
+ Source = sourceName,
+ LastModified = lastUpdateBinary != null ? DateTime.FromBinary(Convert.ToInt64(lastUpdateBinary)) : DateTime.Now,
+ IsIntegrityValid = false,
+ TrustScore = 75 // 备用注册表数据信任度中等
+ };
+
+ // 验证数据完整性
+ if (!string.IsNullOrEmpty(stats.DataHash))
+ {
+ dataSource.IsIntegrityValid = stats.VerifyDataIntegrity();
+ dataSource.TrustScore = dataSource.IsIntegrityValid ? 100 : 25;
+ }
+
+ return dataSource;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从备用注册表加载数据源信息失败 ({registryPath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ return null;
+ }
+
+ ///
+ /// 从注册表加载使用统计(保持向后兼容)
+ ///
+ private static UsageStats LoadUsageStatsFromRegistry()
+ {
+ var dataSource = LoadUsageStatsFromRegistryWithInfo(@"Software\ICC\DeviceInfo", "主注册表");
+ return dataSource?.Stats;
+ }
+
+ ///
+ /// 从多个注册表位置加载使用统计(强化恢复)
+ ///
+ private static UsageStats LoadUsageStatsFromMultipleRegistryLocations()
+ {
+ var registryPaths = new[]
+ {
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(path))
+ {
+ if (key != null)
+ {
+ var launchCount = key.GetValue("LC");
+ var totalMinutes = key.GetValue("TUM");
+ var lastLaunchBinary = key.GetValue("LLT");
+ var priority = key.GetValue("UP");
+ var frequency = key.GetValue("UF");
+ var dataHash = key.GetValue("DH") as string;
+
+ if (launchCount != null && totalMinutes != null)
+ {
+ var stats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LaunchCount = Convert.ToInt32(launchCount),
+ TotalUsageMinutes = Convert.ToInt64(totalMinutes),
+ LastLaunchTime = lastLaunchBinary != null ? DateTime.FromBinary(Convert.ToInt64(lastLaunchBinary)) : DateTime.Now,
+ UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
+ UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
+ DataHash = dataHash,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue
+ };
+
+ // 重新计算平均会话时长
+ if (stats.LaunchCount > 0)
+ {
+ stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ }
+
+ // 验证数据完整性(如果有哈希值)
+ if (!string.IsNullOrEmpty(stats.DataHash))
+ {
+ if (stats.VerifyDataIntegrity())
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表位置恢复数据并验证完整性通过: {path}");
+ return stats;
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 注册表位置数据完整性验证失败: {path}", LogHelper.LogType.Warning);
+ continue; // 尝试下一个位置
+ }
+ }
+ else
+ {
+ // 没有哈希值的旧数据,更新哈希后返回
+ stats.UpdateDataHash();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表位置恢复旧版本数据: {path}");
+ return stats;
+ }
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 从注册表位置加载失败 ({path}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// 保存使用统计到所有位置(强化版本 - 多重隐藏备份)
+ ///
+ private static void SaveUsageStatsToAllLocations(UsageStats stats)
+ {
+ // 保存到主文件
+ SaveUsageStatsToFile(UsageStatsFilePath, stats);
+
+ // 保存到第一备份文件
+ SaveUsageStatsToFile(BackupUsageStatsPath, stats);
+
+ // 保存到多个隐藏备份位置(专门针对使用频率数据保护)
+ SaveUsageStatsToFile(SecondaryUsageBackupPath, stats);
+ SaveUsageStatsToFile(TertiaryUsageBackupPath, stats);
+ SaveUsageStatsToFile(QuaternaryUsageBackupPath, stats);
+
+ // 保存到注册表
+ SaveUsageStatsToRegistry(stats);
+
+ // 保存到注册表的多个位置
+ SaveUsageStatsToMultipleRegistryLocations(stats);
+ }
+
+ ///
+ /// 保存使用统计到文件
+ ///
+ private static void SaveUsageStatsToFile(string filePath, UsageStats stats)
+ {
+ try
+ {
+ // 确保目录存在
+ var directory = Path.GetDirectoryName(filePath);
+ if (!Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ // 设置隐藏属性
+ if (filePath.Contains(".sys"))
+ {
+ var dirInfo = new DirectoryInfo(directory);
+ dirInfo.Attributes |= FileAttributes.Hidden | FileAttributes.System;
+ }
+ }
+
+ string json = JsonConvert.SerializeObject(stats, Formatting.Indented);
+ File.WriteAllText(filePath, json);
+
+ // 设置文件属性为隐藏和系统文件
+ if (filePath.Contains(".sys"))
+ {
+ var fileInfo = new FileInfo(filePath);
+ fileInfo.Attributes |= FileAttributes.Hidden | FileAttributes.System;
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到: {filePath}");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存使用统计到文件失败 ({filePath}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 保存使用统计到注册表
+ ///
+ private static void SaveUsageStatsToRegistry(UsageStats stats)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始保存使用统计到主注册表位置");
+
+ using (var key = Registry.CurrentUser.CreateSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ if (key != null)
+ {
+ key.SetValue("DeviceId", stats.DeviceId);
+ key.SetValue("LaunchCount", stats.LaunchCount);
+ key.SetValue("TotalUsageMinutes", stats.TotalUsageMinutes);
+ key.SetValue("LastLaunchTime", stats.LastLaunchTime.ToString("yyyy-MM-dd HH:mm:ss"));
+ key.SetValue("UpdatePriority", (int)stats.UpdatePriority);
+ key.SetValue("UsageFrequency", (int)stats.UsageFrequency);
+ key.SetValue("DataHash", stats.DataHash ?? "");
+ key.SetValue("LastUpdate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到主注册表 - 启动次数: {stats.LaunchCount}, 使用时长: {stats.TotalUsageMinutes}分钟");
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 创建主注册表键失败", LogHelper.LogType.Error);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存使用统计到主注册表失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 保存使用统计到多个注册表位置(强化保护)
+ ///
+ private static void SaveUsageStatsToMultipleRegistryLocations(UsageStats stats)
+ {
+ var registryPaths = new[]
+ {
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始保存使用统计到{registryPaths.Length}个备用注册表位置");
+ var successCount = 0;
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.CreateSubKey(path))
+ {
+ if (key != null)
+ {
+ // 使用编码的键名来隐藏数据
+ key.SetValue("LC", stats.LaunchCount); // LaunchCount
+ key.SetValue("TUM", stats.TotalUsageMinutes); // TotalUsageMinutes
+ key.SetValue("LLT", stats.LastLaunchTime.ToBinary()); // LastLaunchTime
+ key.SetValue("UP", (int)stats.UpdatePriority); // UpdatePriority
+ key.SetValue("UF", (int)stats.UsageFrequency); // UsageFrequency
+ key.SetValue("DH", stats.DataHash ?? ""); // DataHash
+ key.SetValue("LU", DateTime.Now.ToBinary()); // LastUpdate
+
+ successCount++;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 成功保存到备用注册表位置: {path}");
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 创建备用注册表键失败: {path}", LogHelper.LogType.Error);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存到备用注册表位置失败 ({path}): {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 备用注册表保存完成: {successCount}/{registryPaths.Length} 成功");
+ }
+
+ ///
+ /// 记录更新检查时间(同时执行数据保护检查)
+ ///
+ public static void RecordUpdateCheck()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ var stats = LoadUsageStats();
+ stats.LastUpdateCheck = DateTime.Now;
+ stats.UpdateDataHash();
+ SaveUsageStats(stats);
+
+ // 定期执行数据保护检查(每10次更新检查执行一次)
+ if (stats.LaunchCount % 10 == 0)
+ {
+ PerformUsageDataProtectionCheck();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录更新检查失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 执行使用频率数据保护检查和自动修复
+ ///
+ public static bool PerformUsageDataProtectionCheck()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始使用频率数据保护检查");
+
+ var issues = new List();
+ var repaired = new List();
+ var backupPaths = new[]
+ {
+ new { Path = UsageStatsFilePath, Name = "主文件" },
+ new { Path = BackupUsageStatsPath, Name = "第一备份" },
+ new { Path = SecondaryUsageBackupPath, Name = "第二备份" },
+ new { Path = TertiaryUsageBackupPath, Name = "第三备份" },
+ new { Path = QuaternaryUsageBackupPath, Name = "第四备份" }
+ };
+
+ // 检查所有备份文件
+ UsageStats validStats = null;
+ var missingFiles = new List();
+
+ foreach (var backup in backupPaths)
+ {
+ if (!File.Exists(backup.Path))
+ {
+ issues.Add($"{backup.Name}丢失");
+ missingFiles.Add(backup.Path);
+ }
+ else
+ {
+ var stats = LoadUsageStatsFromFile(backup.Path);
+ if (stats != null && stats.VerifyDataIntegrity() && validStats == null)
+ {
+ validStats = stats;
+ }
+ }
+ }
+
+ // 如果找到有效数据,修复丢失的文件
+ if (validStats != null && missingFiles.Count > 0)
+ {
+ foreach (var missingFile in missingFiles)
+ {
+ SaveUsageStatsToFile(missingFile, validStats);
+ repaired.Add($"恢复文件: {Path.GetFileName(missingFile)}");
+ }
+ }
+
+ // 检查注册表备份
+ var registryPaths = new[]
+ {
+ @"Software\ICC\DeviceInfo",
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ var missingRegistryBackups = 0;
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(path))
+ {
+ if (key == null) missingRegistryBackups++;
+ }
+ }
+ catch
+ {
+ missingRegistryBackups++;
+ }
+ }
+
+ if (missingRegistryBackups > 0)
+ {
+ issues.Add($"{missingRegistryBackups}个注册表备份丢失");
+ if (validStats != null)
+ {
+ SaveUsageStatsToMultipleRegistryLocations(validStats);
+ repaired.Add("重建注册表备份");
+ }
+ }
+
+ // 如果没有找到任何有效数据,尝试从注册表恢复
+ if (validStats == null)
+ {
+ validStats = LoadUsageStatsFromRegistry();
+ if (validStats == null)
+ {
+ validStats = LoadUsageStatsFromMultipleRegistryLocations();
+ }
+
+ if (validStats != null)
+ {
+ SaveUsageStatsToAllLocations(validStats);
+ repaired.Add("从注册表完全恢复数据");
+ }
+ else
+ {
+ // 最后手段:强制重建
+ ForceRebuildUsageDataBackups();
+ repaired.Add("强制重建所有备份");
+ }
+ }
+
+ // 记录检查结果
+ if (issues.Count > 0)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率数据保护检查发现问题: {string.Join(", ", issues)}", LogHelper.LogType.Warning);
+ }
+
+ if (repaired.Count > 0)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率数据保护修复: {string.Join(", ", repaired)}");
+ }
+
+ var protectionScore = CalculateUsageDataProtectionScore();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率数据保护检查完成 - 问题: {issues.Count}, 修复: {repaired.Count}, 保护强度: {protectionScore}/100");
+
+ return protectionScore >= 80;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率数据保护检查失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 根据优先级决定是否应该推送更新(综合时间和使用频率判断)
+ ///
+ /// 更新版本号
+ /// 发布时间
+ /// 是否应该推送更新
+ public static bool ShouldPushUpdate(string updateVersion, DateTime releaseTime)
+ {
+ try
+ {
+ var priority = GetUpdatePriority();
+ var frequency = GetUsageFrequency();
+ var stats = LoadUsageStats();
+
+ // 计算发布时间到现在的天数
+ var daysSinceRelease = (DateTime.Now - releaseTime).TotalDays;
+
+ // 计算最近活跃度(最后一次使用距今的天数)
+ var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
+
+ // 判断更新类型(基于版本号)
+ var updateType = DetermineUpdateType(updateVersion);
+
+ // 综合判断逻辑
+ var shouldPush = ShouldPushUpdateComprehensive(priority, frequency, daysSinceRelease, daysSinceLastUse, stats, updateType);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 更新推送判断 - 版本: {updateVersion}, 类型: {updateType}, " +
+ $"优先级: {priority}, 频率: {frequency}, 发布天数: {daysSinceRelease:F1}, " +
+ $"最后使用: {daysSinceLastUse:F1}天前, 结果: {shouldPush}");
+
+ return shouldPush;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 判断是否推送更新失败: {ex.Message}", LogHelper.LogType.Error);
+ return true; // 出错时默认推送
+ }
+ }
+
+ ///
+ /// 更新类型枚举
+ ///
+ private enum UpdateType
+ {
+ Major, // 主版本更新 (x.0.0)
+ Minor, // 次版本更新 (x.y.0)
+ Patch, // 补丁更新 (x.y.z)
+ Hotfix, // 热修复更新
+ Unknown // 未知类型
+ }
+
+ ///
+ /// 根据版本号判断更新类型
+ ///
+ private static UpdateType DetermineUpdateType(string version)
+ {
+ if (string.IsNullOrEmpty(version)) return UpdateType.Unknown;
+
+ try
+ {
+ // 移除可能的前缀(如 "v")
+ var cleanVersion = version.TrimStart('v', 'V');
+
+ // 检查是否包含热修复标识
+ if (cleanVersion.ToLower().Contains("hotfix") || cleanVersion.ToLower().Contains("fix"))
+ {
+ return UpdateType.Hotfix;
+ }
+
+ // 解析版本号
+ var parts = cleanVersion.Split('.');
+ if (parts.Length >= 3)
+ {
+ if (int.TryParse(parts[1], out int minor) && int.TryParse(parts[2], out int patch))
+ {
+ if (minor == 0 && patch == 0) return UpdateType.Major;
+ if (patch == 0) return UpdateType.Minor;
+ return UpdateType.Patch;
+ }
+ }
+
+ return UpdateType.Unknown;
+ }
+ catch
+ {
+ return UpdateType.Unknown;
+ }
+ }
+
+ ///
+ /// 综合时间和使用频率的更新推送判断逻辑
+ ///
+ private static bool ShouldPushUpdateComprehensive(UpdatePriority priority, UsageFrequency frequency,
+ double daysSinceRelease, double daysSinceLastUse, UsageStats stats, UpdateType updateType)
+ {
+ // 考虑用户的总体使用模式
+ var isHeavyUser = stats.TotalUsageMinutes > 3000; // 超过50小时的重度用户
+ var isFrequentUser = stats.LaunchCount > 100; // 启动超过100次的频繁用户
+
+ // 根据更新类型调整推送策略
+ var urgencyMultiplier = GetUpdateUrgencyMultiplier(updateType);
+
+ // 如果用户长时间未使用(超过30天),降低推送优先级
+ if (daysSinceLastUse > 30)
+ {
+ // 热修复和重要更新优先推送
+ if (updateType == UpdateType.Hotfix)
+ {
+ return daysSinceRelease >= 1; // 热修复1天后推送
+ }
+
+ // 但如果是重度用户,仍然要适当推送
+ var baseDelay = isHeavyUser ? 7 : 14;
+ return daysSinceRelease >= (baseDelay / urgencyMultiplier);
+ }
+
+ // 如果用户最近很活跃(3天内使用过)
+ if (daysSinceLastUse <= 3)
+ {
+ // 热修复立即推送给活跃用户
+ if (updateType == UpdateType.Hotfix)
+ {
+ return true;
+ }
+
+ // 结合使用频率和优先级判断
+ if (frequency == UsageFrequency.High || isHeavyUser)
+ {
+ return daysSinceRelease >= Math.Max(0, 1 / urgencyMultiplier); // 高频用户优先推送
+ }
+
+ switch (priority)
+ {
+ case UpdatePriority.High:
+ return daysSinceRelease >= Math.Max(0, 1 / urgencyMultiplier);
+
+ case UpdatePriority.Medium:
+ return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
+
+ case UpdatePriority.Low:
+ return daysSinceRelease >= Math.Max(2, 3 / urgencyMultiplier);
+ }
+ }
+
+ // 中等活跃度用户(3-14天内使用过)
+ if (daysSinceLastUse <= 14)
+ {
+ // 热修复优先推送
+ if (updateType == UpdateType.Hotfix)
+ {
+ return daysSinceRelease >= 1;
+ }
+
+ // 频繁用户优先推送
+ if (isFrequentUser && frequency == UsageFrequency.High)
+ {
+ return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
+ }
+
+ switch (priority)
+ {
+ case UpdatePriority.High:
+ return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
+
+ case UpdatePriority.Medium:
+ return daysSinceRelease >= Math.Max(2, 4 / urgencyMultiplier);
+
+ case UpdatePriority.Low:
+ return daysSinceRelease >= Math.Max(4, 7 / urgencyMultiplier);
+ }
+ }
+
+ // 较不活跃用户(14-30天内使用过)
+ // 对于低频率用户,进一步延迟推送
+ var delayMultiplier = frequency == UsageFrequency.Low ? 2 : 1;
+
+ switch (priority)
+ {
+ case UpdatePriority.High:
+ return daysSinceRelease >= Math.Max(2, 3 * delayMultiplier / urgencyMultiplier);
+
+ case UpdatePriority.Medium:
+ return daysSinceRelease >= Math.Max(4, 7 * delayMultiplier / urgencyMultiplier);
+
+ case UpdatePriority.Low:
+ return daysSinceRelease >= Math.Max(7, 14 * delayMultiplier / urgencyMultiplier);
+
+ default:
+ return daysSinceRelease >= 7;
+ }
+ }
+
+ ///
+ /// 根据更新类型获取紧急程度倍数
+ ///
+ private static double GetUpdateUrgencyMultiplier(UpdateType updateType)
+ {
+ switch (updateType)
+ {
+ case UpdateType.Hotfix:
+ return 3.0; // 热修复最紧急,3倍速度推送
+ case UpdateType.Major:
+ return 0.5; // 主版本更新较慢推送
+ case UpdateType.Minor:
+ return 1.0; // 次版本正常推送
+ case UpdateType.Patch:
+ return 1.5; // 补丁更新稍快推送
+ case UpdateType.Unknown:
+ return 1.0; // 未知类型正常推送
+ default:
+ return 1.0;
+ }
+ }
+
+ ///
+ /// 获取设备信息摘要(用于调试)
+ ///
+ public static string GetDeviceInfoSummary()
+ {
+ try
+ {
+ var (launchCount, totalMinutes, avgSession, priority) = GetUsageStats();
+ var frequency = GetUsageFrequency();
+ var stats = LoadUsageStats();
+ var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
+
+ return $"设备ID: {DeviceId}\n" +
+ $"启动次数: {launchCount}\n" +
+ $"总使用时长: {totalMinutes}分钟 ({totalMinutes / 60.0:F1}小时)\n" +
+ $"平均会话时长: {avgSession:F1}分钟\n" +
+ $"使用频率: {frequency}\n" +
+ $"更新优先级: {priority}\n" +
+ $"最后使用: {daysSinceLastUse:F1}天前\n" +
+ $"用户类型: {GetUserTypeDescription(stats)}";
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取设备信息摘要失败: {ex.Message}", LogHelper.LogType.Error);
+ return $"设备ID: {DeviceId}\n获取详细信息失败";
+ }
+ }
+
+ ///
+ /// 获取用户类型描述
+ ///
+ private static string GetUserTypeDescription(UsageStats stats)
+ {
+ var isHeavyUser = stats.TotalUsageMinutes > 3000;
+ var isFrequentUser = stats.LaunchCount > 100;
+ var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
+
+ var descriptions = new List();
+
+ if (isHeavyUser) descriptions.Add("重度用户");
+ if (isFrequentUser) descriptions.Add("频繁用户");
+
+ if (daysSinceLastUse <= 3) descriptions.Add("高活跃");
+ else if (daysSinceLastUse <= 14) descriptions.Add("中活跃");
+ else if (daysSinceLastUse <= 30) descriptions.Add("低活跃");
+ else descriptions.Add("非活跃");
+
+ return descriptions.Count > 0 ? string.Join(", ", descriptions) : "普通用户";
+ }
+
+ ///
+ /// 模拟更新推送判断(用于测试)
+ ///
+ /// 更新版本号
+ /// 发布时间
+ /// 推送判断详情
+ public static string SimulateUpdatePushDecision(string updateVersion, DateTime releaseTime)
+ {
+ try
+ {
+ var priority = GetUpdatePriority();
+ var frequency = GetUsageFrequency();
+ var stats = LoadUsageStats();
+ var daysSinceRelease = (DateTime.Now - releaseTime).TotalDays;
+ var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
+ var updateType = DetermineUpdateType(updateVersion);
+ var urgencyMultiplier = GetUpdateUrgencyMultiplier(updateType);
+ var shouldPush = ShouldPushUpdate(updateVersion, releaseTime);
+
+ return $"更新推送判断详情:\n" +
+ $"版本号: {updateVersion}\n" +
+ $"更新类型: {updateType}\n" +
+ $"发布时间: {releaseTime:yyyy-MM-dd HH:mm}\n" +
+ $"发布天数: {daysSinceRelease:F1}天\n" +
+ $"最后使用: {daysSinceLastUse:F1}天前\n" +
+ $"使用频率: {frequency}\n" +
+ $"更新优先级: {priority}\n" +
+ $"紧急程度倍数: {urgencyMultiplier:F1}x\n" +
+ $"用户类型: {GetUserTypeDescription(stats)}\n" +
+ $"推送决定: {(shouldPush ? "是" : "否")}";
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 模拟更新推送判断失败: {ex.Message}", LogHelper.LogType.Error);
+ return "模拟判断失败";
+ }
+ }
+
+ ///
+ /// 数据自检和修复
+ ///
+ public static bool PerformDataIntegrityCheck()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始数据完整性检查");
+
+ var issues = new List();
+ var repaired = new List();
+
+ // 检查设备ID文件
+ if (!File.Exists(DeviceIdFilePath))
+ {
+ issues.Add("主设备ID文件丢失");
+ if (File.Exists(BackupDeviceIdPath))
+ {
+ var backupId = LoadDeviceIdFromFile(BackupDeviceIdPath);
+ if (!string.IsNullOrEmpty(backupId))
+ {
+ SaveDeviceIdToFile(DeviceIdFilePath, backupId);
+ repaired.Add("从备份恢复主设备ID文件");
+ }
+ }
+ }
+
+ // 检查备份设备ID文件
+ if (!File.Exists(BackupDeviceIdPath))
+ {
+ issues.Add("备份设备ID文件丢失");
+ var mainId = LoadDeviceIdFromFile(DeviceIdFilePath);
+ if (!string.IsNullOrEmpty(mainId))
+ {
+ SaveDeviceIdToFile(BackupDeviceIdPath, mainId);
+ repaired.Add("重建备份设备ID文件");
+ }
+ }
+
+ // 检查使用统计文件
+ if (!File.Exists(UsageStatsFilePath))
+ {
+ issues.Add("主使用统计文件丢失");
+ var backupStatsForRestore = LoadUsageStatsFromFile(BackupUsageStatsPath);
+ if (backupStatsForRestore != null)
+ {
+ SaveUsageStatsToFile(UsageStatsFilePath, backupStatsForRestore);
+ repaired.Add("从备份恢复主使用统计文件");
+ }
+ }
+
+ // 检查备份使用统计文件
+ if (!File.Exists(BackupUsageStatsPath))
+ {
+ issues.Add("备份使用统计文件丢失");
+ var mainStatsForBackup = LoadUsageStatsFromFile(UsageStatsFilePath);
+ if (mainStatsForBackup != null)
+ {
+ SaveUsageStatsToFile(BackupUsageStatsPath, mainStatsForBackup);
+ repaired.Add("重建备份使用统计文件");
+ }
+ }
+
+ // 验证数据一致性
+ var mainStats = LoadUsageStatsFromFile(UsageStatsFilePath);
+ var backupStats = LoadUsageStatsFromFile(BackupUsageStatsPath);
+
+ if (mainStats != null && backupStats != null)
+ {
+ if (mainStats.LaunchCount != backupStats.LaunchCount ||
+ mainStats.TotalUsageMinutes != backupStats.TotalUsageMinutes)
+ {
+ issues.Add("主备份数据不一致");
+ // 使用最新的数据
+ var newerStats = mainStats.LastModified > backupStats.LastModified ? mainStats : backupStats;
+ SaveUsageStatsToAllLocations(newerStats);
+ repaired.Add("同步主备份数据");
+ }
+ }
+
+ // 记录检查结果
+ if (issues.Count > 0)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 发现问题: {string.Join(", ", issues)}", LogHelper.LogType.Warning);
+ }
+
+ if (repaired.Count > 0)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 已修复: {string.Join(", ", repaired)}");
+ }
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据完整性检查完成 - 问题: {issues.Count}, 修复: {repaired.Count}");
+ return issues.Count == 0 || repaired.Count > 0;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据完整性检查失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 获取使用频率数据保护状态摘要(强化版本)
+ ///
+ public static string GetUsageDataProtectionSummary()
+ {
+ try
+ {
+ var summary = new StringBuilder();
+ summary.AppendLine("使用频率数据保护状态摘要:");
+
+ // 检查主要文件
+ summary.AppendLine($"主使用统计文件: {(File.Exists(UsageStatsFilePath) ? "✓" : "✗")}");
+ summary.AppendLine($"第一备份文件: {(File.Exists(BackupUsageStatsPath) ? "✓" : "✗")}");
+
+ // 检查多重隐藏备份
+ summary.AppendLine($"第二备份文件: {(File.Exists(SecondaryUsageBackupPath) ? "✓" : "✗")}");
+ summary.AppendLine($"第三备份文件: {(File.Exists(TertiaryUsageBackupPath) ? "✓" : "✗")}");
+ summary.AppendLine($"第四备份文件: {(File.Exists(QuaternaryUsageBackupPath) ? "✓" : "✗")}");
+
+ // 检查注册表备份
+ var registryBackups = 0;
+ var registryPaths = new[]
+ {
+ @"Software\ICC\DeviceInfo",
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(path))
+ {
+ if (key != null) registryBackups++;
+ }
+ }
+ catch { }
+ }
+
+ summary.AppendLine($"注册表备份位置: {registryBackups}/4 ✓");
+
+ // 检查数据完整性和可恢复性
+ var stats = LoadUsageStats();
+ if (stats != null)
+ {
+ summary.AppendLine($"数据完整性: {(stats.VerifyDataIntegrity() ? "✓" : "✗")}");
+ summary.AppendLine($"启动次数: {stats.LaunchCount}");
+ summary.AppendLine($"总使用时长: {stats.TotalUsageMinutes}分钟");
+ summary.AppendLine($"使用频率: {stats.UsageFrequency}");
+ summary.AppendLine($"更新优先级: {stats.UpdatePriority}");
+ summary.AppendLine($"最后修改: {stats.LastModified:yyyy-MM-dd HH:mm:ss}");
+ }
+
+ // 计算保护强度评分
+ var protectionScore = CalculateUsageDataProtectionScore();
+ summary.AppendLine($"保护强度评分: {protectionScore}/100");
+
+ return summary.ToString();
+ }
+ catch (Exception ex)
+ {
+ return $"获取使用频率数据保护状态失败: {ex.Message}";
+ }
+ }
+
+ ///
+ /// 计算使用频率数据保护强度评分
+ ///
+ private static int CalculateUsageDataProtectionScore()
+ {
+ var score = 0;
+
+ try
+ {
+ // 文件备份评分(50分)
+ if (File.Exists(UsageStatsFilePath)) score += 15;
+ if (File.Exists(BackupUsageStatsPath)) score += 10;
+ if (File.Exists(SecondaryUsageBackupPath)) score += 8;
+ if (File.Exists(TertiaryUsageBackupPath)) score += 8;
+ if (File.Exists(QuaternaryUsageBackupPath)) score += 9;
+
+ // 注册表备份评分(30分)
+ var registryPaths = new[]
+ {
+ @"Software\ICC\DeviceInfo",
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(path))
+ {
+ if (key != null) score += 7;
+ }
+ }
+ catch { }
+ }
+
+ // 数据完整性评分(20分)
+ var stats = LoadUsageStats();
+ if (stats != null)
+ {
+ if (!string.IsNullOrEmpty(stats.DataHash)) score += 10;
+ if (stats.VerifyDataIntegrity()) score += 10;
+ }
+ }
+ catch { }
+
+ return Math.Min(100, score);
+ }
+
+ ///
+ /// 强制重建所有使用频率数据备份
+ ///
+ public static bool ForceRebuildUsageDataBackups()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始强制重建使用频率数据备份");
+
+ var stats = LoadUsageStats();
+ if (stats == null)
+ {
+ // 如果无法加载任何数据,创建基础数据
+ stats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LastLaunchTime = DateTime.Now,
+ LaunchCount = 1,
+ TotalUsageMinutes = 0,
+ AverageSessionMinutes = 0,
+ LastUpdateCheck = DateTime.MinValue,
+ UpdatePriority = UpdatePriority.Medium,
+ UsageFrequency = UsageFrequency.Medium
+ };
+ stats.UpdateDataHash();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 创建新的基础使用数据");
+ }
+
+ // 强制保存到所有位置
+ SaveUsageStatsToAllLocations(stats);
+
+ // 验证重建结果
+ var protectionScore = CalculateUsageDataProtectionScore();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率数据备份重建完成,保护强度: {protectionScore}/100");
+
+ return protectionScore >= 80; // 80分以上认为重建成功
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 强制重建使用频率数据备份失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 获取数据保护状态摘要(保持向后兼容)
+ ///
+ public static string GetDataProtectionSummary()
+ {
+ return GetUsageDataProtectionSummary();
+ }
+
+ ///
+ /// 测试注册表写入操作
+ ///
+ public static string TestRegistryOperations()
+ {
+ var results = new StringBuilder();
+ results.AppendLine("注册表操作测试结果:");
+
+ try
+ {
+ // 测试设备ID写入
+ var testDeviceId = "TEST" + DateTime.Now.ToString("yyyyMMddHHmmss");
+ results.AppendLine($"测试设备ID: {testDeviceId}");
+
+ try
+ {
+ using (var key = Registry.CurrentUser.CreateSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ if (key != null)
+ {
+ key.SetValue("TestDeviceId", testDeviceId);
+ key.SetValue("TestTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
+ results.AppendLine("✓ 主注册表位置写入成功");
+ }
+ else
+ {
+ results.AppendLine("✗ 主注册表位置创建失败");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 主注册表位置写入失败: {ex.Message}");
+ }
+
+ // 测试多个注册表位置写入
+ var registryPaths = new[]
+ {
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.CreateSubKey(path))
+ {
+ if (key != null)
+ {
+ key.SetValue("TestData", "TestValue");
+ key.SetValue("TestTime", DateTime.Now.ToBinary());
+ results.AppendLine($"✓ 注册表位置写入成功: {path}");
+ }
+ else
+ {
+ results.AppendLine($"✗ 注册表位置创建失败: {path}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 注册表位置写入失败 ({path}): {ex.Message}");
+ }
+ }
+
+ // 测试读取操作
+ results.AppendLine("\n注册表读取测试:");
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ if (key != null)
+ {
+ var readValue = key.GetValue("TestDeviceId") as string;
+ if (readValue == testDeviceId)
+ {
+ results.AppendLine("✓ 注册表读取验证成功");
+ }
+ else
+ {
+ results.AppendLine($"✗ 注册表读取验证失败: 期望 {testDeviceId}, 实际 {readValue}");
+ }
+ }
+ else
+ {
+ results.AppendLine("✗ 注册表读取失败: 键不存在");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 注册表读取失败: {ex.Message}");
+ }
+
+ // 测试实际数据保存
+ results.AppendLine("\n实际数据保存测试:");
+ var stats = LoadUsageStats();
+ if (stats != null)
+ {
+ try
+ {
+ SaveUsageStatsToRegistry(stats);
+ SaveUsageStatsToMultipleRegistryLocations(stats);
+ results.AppendLine("✓ 实际使用统计数据保存到注册表成功");
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 实际使用统计数据保存失败: {ex.Message}");
+ }
+ }
+
+ return results.ToString();
+ }
+ catch (Exception ex)
+ {
+ return $"注册表操作测试失败: {ex.Message}";
+ }
+ }
+
+ ///
+ /// 强制执行一次完整的数据保存操作(包括注册表)
+ ///
+ public static bool ForceCompleteDataSave()
+ {
+ try
+ {
+ lock (fileLock)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始强制完整数据保存");
+
+ // 保存设备ID到所有位置
+ SaveDeviceIdToAllLocations(DeviceId);
+
+ // 加载并保存使用统计到所有位置
+ var stats = LoadUsageStats();
+ if (stats != null)
+ {
+ stats.UpdateDataHash();
+ SaveUsageStatsToAllLocations(stats);
+
+ // 验证注册表保存是否成功
+ var verificationResult = VerifyRegistryData();
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 注册表数据验证结果: {verificationResult}");
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 强制完整数据保存完成");
+ return true;
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 强制完整数据保存失败: 无法加载使用统计", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 强制完整数据保存失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 验证注册表中的数据是否存在
+ ///
+ public static string VerifyRegistryData()
+ {
+ var results = new StringBuilder();
+ results.AppendLine("注册表数据验证结果:");
+
+ try
+ {
+ // 验证主注册表位置
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(@"Software\ICC\DeviceInfo"))
+ {
+ if (key != null)
+ {
+ var deviceId = key.GetValue("DeviceId") as string;
+ var launchCount = key.GetValue("LaunchCount");
+ var totalMinutes = key.GetValue("TotalUsageMinutes");
+ var lastUpdate = key.GetValue("LastUpdate") as string;
+
+ results.AppendLine($"✓ 主注册表位置存在");
+ results.AppendLine($" 设备ID: {deviceId ?? "未找到"}");
+ results.AppendLine($" 启动次数: {launchCount ?? "未找到"}");
+ results.AppendLine($" 使用时长: {totalMinutes ?? "未找到"}分钟");
+ results.AppendLine($" 最后更新: {lastUpdate ?? "未找到"}");
+ }
+ else
+ {
+ results.AppendLine("✗ 主注册表位置不存在");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 主注册表位置访问失败: {ex.Message}");
+ }
+
+ // 验证备用注册表位置
+ var registryPaths = new[]
+ {
+ @"Software\Microsoft\Windows\CurrentVersion\ICC",
+ @"Software\Classes\.icc\UsageData",
+ @"Software\ICC\Config\Usage"
+ };
+
+ foreach (var path in registryPaths)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(path))
+ {
+ if (key != null)
+ {
+ var launchCount = key.GetValue("LC");
+ var totalMinutes = key.GetValue("TUM");
+ var lastUpdate = key.GetValue("LU");
+
+ results.AppendLine($"✓ 备用注册表位置存在: {path}");
+ results.AppendLine($" 启动次数: {launchCount ?? "未找到"}");
+ results.AppendLine($" 使用时长: {totalMinutes ?? "未找到"}");
+ results.AppendLine($" 最后更新: {(lastUpdate != null ? DateTime.FromBinary(Convert.ToInt64(lastUpdate)).ToString("yyyy-MM-dd HH:mm:ss") : "未找到")}");
+ }
+ else
+ {
+ results.AppendLine($"✗ 备用注册表位置不存在: {path}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"✗ 备用注册表位置访问失败 ({path}): {ex.Message}");
+ }
+ }
+
+ return results.ToString();
+ }
+ catch (Exception ex)
+ {
+ return $"注册表数据验证失败: {ex.Message}";
+ }
+ }
+
+ ///
+ /// 立即执行一次数据保存并验证注册表写入
+ ///
+ public static string SaveAndVerifyRegistryData()
+ {
+ try
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 开始保存并验证注册表数据");
+
+ // 强制保存数据
+ var saveSuccess = ForceCompleteDataSave();
+
+ // 验证注册表数据
+ var verificationResult = VerifyRegistryData();
+
+ var result = $"保存操作: {(saveSuccess ? "成功" : "失败")}\n\n{verificationResult}";
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存并验证注册表数据完成");
+ return result;
+ }
+ catch (Exception ex)
+ {
+ var errorMsg = $"保存并验证注册表数据失败: {ex.Message}";
+ LogHelper.WriteLogToFile($"DeviceIdentifier | {errorMsg}", LogHelper.LogType.Error);
+ return errorMsg;
+ }
+ }
+
+ ///
+ /// 测试反篡改恢复机制
+ ///
+ public static string TestAntiTamperingRecovery()
+ {
+ var results = new StringBuilder();
+ results.AppendLine("反篡改恢复机制测试结果:");
+
+ try
+ {
+ lock (fileLock)
+ {
+ // 1. 收集所有数据源
+ results.AppendLine("\n1. 收集数据源:");
+ var allSources = CollectAllUsageDataSources();
+ results.AppendLine($" 找到 {allSources.Count} 个数据源");
+
+ foreach (var source in allSources)
+ {
+ results.AppendLine($" - {source.Source}: 完整性={source.IsIntegrityValid}, 信任度={source.TrustScore}, 修改时间={source.LastModified:yyyy-MM-dd HH:mm:ss}");
+ results.AppendLine($" 启动次数={source.Stats.LaunchCount}, 使用时长={source.Stats.TotalUsageMinutes}分钟");
+ }
+
+ // 2. 选择最可信数据
+ results.AppendLine("\n2. 选择最可信数据:");
+ var bestData = SelectMostTrustedData(allSources);
+ if (bestData != null)
+ {
+ results.AppendLine($" 选择: {bestData.Source}");
+ results.AppendLine($" 完整性: {bestData.IsIntegrityValid}");
+ results.AppendLine($" 信任度: {bestData.TrustScore}");
+ results.AppendLine($" 数据: 启动{bestData.Stats.LaunchCount}次, 使用{bestData.Stats.TotalUsageMinutes}分钟");
+ }
+ else
+ {
+ results.AppendLine(" 未找到可信数据");
+ }
+
+ // 3. 测试部分恢复
+ results.AppendLine("\n3. 部分数据恢复测试:");
+ var partialRecovery = AttemptPartialDataRecovery(allSources);
+ if (partialRecovery != null)
+ {
+ results.AppendLine($" 恢复成功: 启动{partialRecovery.LaunchCount}次, 使用{partialRecovery.TotalUsageMinutes}分钟");
+ results.AppendLine($" 完整性验证: {partialRecovery.VerifyDataIntegrity()}");
+ }
+ else
+ {
+ results.AppendLine(" 部分恢复失败");
+ }
+
+ // 4. 测试实际加载
+ results.AppendLine("\n4. 实际加载测试:");
+ var loadedStats = LoadUsageStats();
+ if (loadedStats != null)
+ {
+ results.AppendLine($" 加载成功: 启动{loadedStats.LaunchCount}次, 使用{loadedStats.TotalUsageMinutes}分钟");
+ results.AppendLine($" 完整性验证: {loadedStats.VerifyDataIntegrity()}");
+ results.AppendLine($" 使用频率: {loadedStats.UsageFrequency}");
+ results.AppendLine($" 更新优先级: {loadedStats.UpdatePriority}");
+ }
+ else
+ {
+ results.AppendLine(" 加载失败");
+ }
+
+ return results.ToString();
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"\n测试失败: {ex.Message}");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 反篡改恢复测试失败: {ex.Message}", LogHelper.LogType.Error);
+ return results.ToString();
+ }
+ }
+
+ ///
+ /// 模拟数据篡改并测试恢复
+ ///
+ public static string SimulateDataTamperingAndRecover()
+ {
+ var results = new StringBuilder();
+ results.AppendLine("数据篡改模拟和恢复测试:");
+
+ try
+ {
+ lock (fileLock)
+ {
+ // 1. 保存当前正常数据
+ results.AppendLine("\n1. 保存当前正常数据作为备份...");
+ var originalStats = LoadUsageStats();
+ if (originalStats == null)
+ {
+ results.AppendLine(" 无法获取原始数据,创建测试数据");
+ originalStats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LaunchCount = 50,
+ TotalUsageMinutes = 1200,
+ LastLaunchTime = DateTime.Now.AddDays(-1),
+ UpdatePriority = UpdatePriority.Medium,
+ UsageFrequency = UsageFrequency.Medium
+ };
+ originalStats.UpdateDataHash();
+ }
+
+ SaveUsageStatsToAllLocations(originalStats);
+ results.AppendLine($" 原始数据: 启动{originalStats.LaunchCount}次, 使用{originalStats.TotalUsageMinutes}分钟");
+
+ // 2. 模拟篡改主文件
+ results.AppendLine("\n2. 模拟篡改主文件...");
+ try
+ {
+ var tamperedStats = new UsageStats
+ {
+ DeviceId = DeviceId,
+ LaunchCount = 1, // 篡改为很小的值
+ TotalUsageMinutes = 5,
+ LastLaunchTime = DateTime.Now,
+ UpdatePriority = UpdatePriority.Low,
+ UsageFrequency = UsageFrequency.Low,
+ DataHash = "TAMPERED_HASH", // 错误的哈希值
+ LastModified = DateTime.Now
+ };
+
+ var tamperedJson = JsonConvert.SerializeObject(tamperedStats, Formatting.Indented);
+ File.WriteAllText(UsageStatsFilePath, tamperedJson);
+ results.AppendLine(" 主文件已被篡改");
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($" 篡改主文件失败: {ex.Message}");
+ }
+
+ // 3. 测试恢复机制
+ results.AppendLine("\n3. 测试智能恢复机制...");
+ var recoveredStats = LoadUsageStats();
+ if (recoveredStats != null)
+ {
+ results.AppendLine($" 恢复成功: 启动{recoveredStats.LaunchCount}次, 使用{recoveredStats.TotalUsageMinutes}分钟");
+ results.AppendLine($" 完整性验证: {recoveredStats.VerifyDataIntegrity()}");
+
+ // 检查是否恢复了正确的数据
+ if (Math.Abs(recoveredStats.LaunchCount - originalStats.LaunchCount) <= 5 &&
+ Math.Abs(recoveredStats.TotalUsageMinutes - originalStats.TotalUsageMinutes) <= 100)
+ {
+ results.AppendLine(" ✓ 数据恢复正确,反篡改机制工作正常");
+ }
+ else
+ {
+ results.AppendLine(" ✗ 数据恢复不完全正确,但避免了使用篡改数据");
+ }
+ }
+ else
+ {
+ results.AppendLine(" ✗ 恢复失败");
+ }
+
+ // 4. 恢复正常状态
+ results.AppendLine("\n4. 恢复正常状态...");
+ SaveUsageStatsToAllLocations(originalStats);
+ results.AppendLine(" 系统已恢复到正常状态");
+
+ return results.ToString();
+ }
+ }
+ catch (Exception ex)
+ {
+ results.AppendLine($"\n模拟测试失败: {ex.Message}");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据篡改模拟测试失败: {ex.Message}", LogHelper.LogType.Error);
+ return results.ToString();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 81ddbb30..eb456c64 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -2594,6 +2594,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index b30ba004..94011d37 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -854,6 +854,8 @@ namespace Ink_Canvas {
{
// 切换到关于页面
ShowSettingsSection("about");
+ // 刷新设备信息
+ RefreshDeviceInfo();
}
// 新增:个性化设置
@@ -881,6 +883,99 @@ namespace Ink_Canvas {
BorderSettingsMask.Background = null; // 确保清除蒙层背景
}
+ ///
+ /// 刷新设备信息按钮点击事件
+ ///
+ private void RefreshDeviceInfo_Click(object sender, RoutedEventArgs e)
+ {
+ RefreshDeviceInfo();
+ }
+
+ ///
+ /// 刷新设备信息显示
+ ///
+ private void RefreshDeviceInfo()
+ {
+ try
+ {
+ // 获取设备ID
+ string deviceId = DeviceIdentifier.GetDeviceId();
+ DeviceIdTextBlock.Text = deviceId;
+
+ // 获取使用频率
+ var usageFrequency = DeviceIdentifier.GetUsageFrequency();
+ string frequencyText;
+ switch (usageFrequency)
+ {
+ case DeviceIdentifier.UsageFrequency.High:
+ frequencyText = "高频用户";
+ break;
+ case DeviceIdentifier.UsageFrequency.Medium:
+ frequencyText = "中频用户";
+ break;
+ case DeviceIdentifier.UsageFrequency.Low:
+ frequencyText = "低频用户";
+ break;
+ default:
+ frequencyText = "未知";
+ break;
+ }
+ UsageFrequencyTextBlock.Text = frequencyText;
+
+ // 获取更新优先级
+ var updatePriority = DeviceIdentifier.GetUpdatePriority();
+ string priorityText;
+ switch (updatePriority)
+ {
+ case DeviceIdentifier.UpdatePriority.High:
+ priorityText = "高优先级(优先推送更新)";
+ break;
+ case DeviceIdentifier.UpdatePriority.Medium:
+ priorityText = "中优先级(正常推送更新)";
+ break;
+ case DeviceIdentifier.UpdatePriority.Low:
+ priorityText = "低优先级(延迟推送更新)";
+ break;
+ default:
+ priorityText = "未知";
+ break;
+ }
+ UpdatePriorityTextBlock.Text = priorityText;
+
+ // 获取使用统计
+ var (launchCount, totalMinutes, avgSession, _) = DeviceIdentifier.GetUsageStats();
+ LaunchCountTextBlock.Text = launchCount.ToString();
+
+ string totalUsageText;
+ if (totalMinutes < 60)
+ {
+ totalUsageText = $"{totalMinutes}分钟";
+ }
+ else if (totalMinutes < 1440)
+ {
+ totalUsageText = $"{totalMinutes / 60}小时{totalMinutes % 60}分钟";
+ }
+ else
+ {
+ totalUsageText = $"{totalMinutes / 1440}天{(totalMinutes % 1440) / 60}小时";
+ }
+ TotalUsageTextBlock.Text = totalUsageText;
+
+ LogHelper.WriteLogToFile($"MainWindow | 设备信息已刷新 - ID: {deviceId}, 频率: {frequencyText}, 优先级: {priorityText}");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"MainWindow | 刷新设备信息失败: {ex.Message}", LogHelper.LogType.Error);
+
+ // 显示错误信息
+ DeviceIdTextBlock.Text = "获取失败";
+ UsageFrequencyTextBlock.Text = "获取失败";
+ UpdatePriorityTextBlock.Text = "获取失败";
+ LaunchCountTextBlock.Text = "获取失败";
+ TotalUsageTextBlock.Text = "获取失败";
+ }
+ }
+
// 新增:折叠侧边栏
private void CollapseNavSidebar_Click(object sender, RoutedEventArgs e)
{
diff --git a/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache b/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
index 9faa8f50..fc9b1fcc 100644
--- a/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
+++ b/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
@@ -12,7 +12,7 @@ TRACE;DEBUG;NETFRAMEWORK;NET472;;NET30_OR_GREATER;NET35_OR_GREATER;NET40_OR_GREA
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
22-2143008179
-76-141727233
+77-1409555929
471037513499
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\HistoryRollbackWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;