mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 01:44:26 +08:00
0.6.3.1
最近文件查看优化,课程表组件优化,插件安装优化。
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LanMountainDesktop.Services;
|
||||
@@ -42,11 +43,14 @@ public sealed class LocalizationService
|
||||
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(AppContext.BaseDirectory, "Localization", $"{languageCode}.json");
|
||||
if (File.Exists(filePath))
|
||||
var json = TryLoadFromFileSystem(languageCode);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
json = TryLoadFromEmbeddedResource(languageCode);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
// Defensive: tolerate accidentally duplicated UTF-8 BOM characters at file start.
|
||||
json = json.TrimStart('\uFEFF');
|
||||
var data = JsonSerializer.Deserialize<Dictionary<string, string>>(json, JsonOptions);
|
||||
if (data is not null)
|
||||
@@ -63,4 +67,41 @@ public sealed class LocalizationService
|
||||
_cache[languageCode] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private string? TryLoadFromFileSystem(string languageCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(AppContext.BaseDirectory, "Localization", $"{languageCode}.json");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
return File.ReadAllText(filePath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Continue to next method
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? TryLoadFromEmbeddedResource(string languageCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = $"LanMountainDesktop.Localization.{languageCode}.json";
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream != null)
|
||||
{
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Continue to next method
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace LanMountainDesktop.Services;
|
||||
|
||||
@@ -35,66 +36,19 @@ public sealed class OfficeRecentDocumentsService : IOfficeRecentDocumentsService
|
||||
public List<OfficeRecentDocument> GetRecentDocuments(int maxCount = 20)
|
||||
{
|
||||
var documents = new List<OfficeRecentDocument>();
|
||||
var recentPaths = GetRecentFolders();
|
||||
|
||||
foreach (var recentPath in recentPaths)
|
||||
{
|
||||
if (!Directory.Exists(recentPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 方法1: 从注册表读取Office最近文档(最可靠)
|
||||
TryGetFromRegistry(documents);
|
||||
|
||||
try
|
||||
{
|
||||
var files = Directory.GetFiles(recentPath, "*.lnk");
|
||||
foreach (var lnkPath in files)
|
||||
{
|
||||
var targetPath = GetShortcutTarget(lnkPath);
|
||||
if (string.IsNullOrEmpty(targetPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 方法2: 从Recent文件夹读取快捷方式(备用)
|
||||
TryGetFromRecentFolders(documents);
|
||||
|
||||
var extension = Path.GetExtension(targetPath).ToLowerInvariant();
|
||||
if (!IsOfficeFile(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(targetPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(targetPath);
|
||||
var doc = new OfficeRecentDocument
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(targetPath),
|
||||
FilePath = targetPath,
|
||||
Extension = extension,
|
||||
LastModifiedTime = fileInfo.LastWriteTime,
|
||||
FileSizeBytes = fileInfo.Length,
|
||||
IconGlyph = GetIconGlyph(extension)
|
||||
};
|
||||
|
||||
if (!documents.Any(d => d.FilePath == targetPath))
|
||||
{
|
||||
documents.Add(doc);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
// 方法3: 从Windows Jump List读取(如果可用)
|
||||
TryGetFromJumpList(documents);
|
||||
|
||||
return documents
|
||||
.GroupBy(d => d.FilePath, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(g => g.OrderByDescending(d => d.LastModifiedTime).First())
|
||||
.OrderByDescending(d => d.LastModifiedTime)
|
||||
.Take(maxCount)
|
||||
.ToList();
|
||||
@@ -116,6 +70,231 @@ public sealed class OfficeRecentDocumentsService : IOfficeRecentDocumentsService
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416 // 平台兼容性警告
|
||||
private void TryGetFromRegistry(List<OfficeRecentDocument> documents)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Word最近文档
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\Word\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\Word\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\15.0\Word\Reading Locations");
|
||||
|
||||
// Excel最近文档
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\Excel\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\Excel\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\15.0\Excel\Reading Locations");
|
||||
|
||||
// PowerPoint最近文档
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\PowerPoint\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\PowerPoint\Reading Locations");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\15.0\PowerPoint\Reading Locations");
|
||||
|
||||
// 通用Office最近文档
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\Common\Open Find\Microsoft Office Word");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\Common\Open Find\Microsoft Office Excel");
|
||||
TryGetFromOfficeRegistry(documents, @"Software\Microsoft\Office\16.0\Common\Open Find\Microsoft Office PowerPoint");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略注册表访问错误
|
||||
}
|
||||
}
|
||||
|
||||
private void TryGetFromOfficeRegistry(List<OfficeRecentDocument> documents, string registryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(registryPath);
|
||||
if (key == null) return;
|
||||
|
||||
foreach (var subKeyName in key.GetSubKeyNames())
|
||||
{
|
||||
try
|
||||
{
|
||||
using var subKey = key.OpenSubKey(subKeyName);
|
||||
if (subKey == null) continue;
|
||||
|
||||
var filePath = subKey.GetValue("Path") as string;
|
||||
if (string.IsNullOrEmpty(filePath)) continue;
|
||||
|
||||
AddDocumentIfExists(documents, filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略单个子键访问错误
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略注册表访问错误
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1416 // 平台兼容性警告
|
||||
|
||||
private void TryGetFromRecentFolders(List<OfficeRecentDocument> documents)
|
||||
{
|
||||
var recentPaths = GetRecentFolders();
|
||||
|
||||
foreach (var recentPath in recentPaths)
|
||||
{
|
||||
if (!Directory.Exists(recentPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var files = Directory.GetFiles(recentPath, "*.lnk");
|
||||
foreach (var lnkPath in files)
|
||||
{
|
||||
var targetPath = GetShortcutTarget(lnkPath);
|
||||
if (string.IsNullOrEmpty(targetPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddDocumentIfExists(documents, targetPath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略文件夹访问错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryGetFromJumpList(List<OfficeRecentDocument> documents)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Windows Jump List存储在以下位置
|
||||
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var jumpListPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Microsoft", "Windows", "Recent", "AutomaticDestinations");
|
||||
|
||||
if (!Directory.Exists(jumpListPath)) return;
|
||||
|
||||
// Office应用的Jump List文件
|
||||
var officeJumpListFiles = new[]
|
||||
{
|
||||
"a7bd7a3f3d5a4c74.automaticDestinations-ms", // Word
|
||||
"9b524fe3be704a4d.automaticDestinations-ms", // Excel
|
||||
"d0063c4c7de64e5e.automaticDestinations-ms" // PowerPoint
|
||||
};
|
||||
|
||||
foreach (var jumpFile in officeJumpListFiles)
|
||||
{
|
||||
var fullPath = Path.Combine(jumpListPath, jumpFile);
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
TryParseJumpListFile(fullPath, documents);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Jump List解析失败,忽略
|
||||
}
|
||||
}
|
||||
|
||||
private void TryParseJumpListFile(string jumpListPath, List<OfficeRecentDocument> documents)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Jump List文件是二进制格式,这里使用简化的方法
|
||||
// 读取文件并尝试提取文件路径
|
||||
var bytes = File.ReadAllBytes(jumpListPath);
|
||||
var text = Encoding.Unicode.GetString(bytes);
|
||||
|
||||
// 查找可能的文件路径(简化实现)
|
||||
var possiblePaths = ExtractPossiblePaths(text);
|
||||
foreach (var path in possiblePaths)
|
||||
{
|
||||
AddDocumentIfExists(documents, path);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Jump List解析失败,忽略
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> ExtractPossiblePaths(string text)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
// 查找常见的文件路径模式
|
||||
var patterns = new[]
|
||||
{
|
||||
@"[A-Z]:\\[^\x00-\x1F""<>|]*\.(docx?|xlsx?|pptx?|rtf|csv)",
|
||||
@"\\\\[^\\]+\\[^\x00-\x1F""<>|]*\.(docx?|xlsx?|pptx?|rtf|csv)"
|
||||
};
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matches = System.Text.RegularExpressions.Regex.Matches(text, pattern,
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||
|
||||
foreach (System.Text.RegularExpressions.Match match in matches)
|
||||
{
|
||||
var path = match.Value.Trim('\0', ' ', '"');
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
paths.Add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略正则表达式错误
|
||||
}
|
||||
}
|
||||
|
||||
return paths.Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void AddDocumentIfExists(List<OfficeRecentDocument> documents, string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var extension = Path.GetExtension(filePath).ToLowerInvariant();
|
||||
if (!IsOfficeFile(extension))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
var doc = new OfficeRecentDocument
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(filePath),
|
||||
FilePath = filePath,
|
||||
Extension = extension,
|
||||
LastModifiedTime = fileInfo.LastWriteTime,
|
||||
FileSizeBytes = fileInfo.Length,
|
||||
IconGlyph = GetIconGlyph(extension)
|
||||
};
|
||||
|
||||
if (!documents.Any(d => string.Equals(d.FilePath, filePath, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
documents.Add(doc);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略单个文件处理错误
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> GetRecentFolders()
|
||||
{
|
||||
var folders = new List<string>();
|
||||
@@ -125,6 +304,12 @@ public sealed class OfficeRecentDocumentsService : IOfficeRecentDocumentsService
|
||||
folders.Add(Path.Combine(appData, "Microsoft", "Excel", "Recent"));
|
||||
folders.Add(Path.Combine(appData, "Microsoft", "PowerPoint", "Recent"));
|
||||
|
||||
// 添加Office 365路径
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
folders.Add(Path.Combine(localAppData, "Microsoft", "Office", "Word", "Recent"));
|
||||
folders.Add(Path.Combine(localAppData, "Microsoft", "Office", "Excel", "Recent"));
|
||||
folders.Add(Path.Combine(localAppData, "Microsoft", "Office", "PowerPoint", "Recent"));
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user