增加多文件备份, 尝试修复UI假死状态, 修复高分屏缩放导致的鼠标追随bug

This commit is contained in:
BookerLiu
2024-08-07 11:04:48 +08:00
parent 8fea77c304
commit a61c69aa0b
14 changed files with 504 additions and 85 deletions

View File

@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows;
@@ -34,6 +35,7 @@ namespace GeekDesk.Util
using (FileStream fs = File.Create(Constants.DATA_FILE_PATH)) { }
appData = new AppData();
SaveAppData(appData, Constants.DATA_FILE_PATH);
return appData;
}
else
{
@@ -49,51 +51,103 @@ namespace GeekDesk.Util
{
SavePassword(appData.AppConfig.MenuPassword);
}
return appData;
}
}
catch
{
if (File.Exists(Constants.DATA_FILE_BAK_PATH))
DirectoryInfo dirInfo = new DirectoryInfo(Constants.DATA_FILE_BAK_DIR_PATH);
FileInfo[] files = dirInfo.GetFiles();
if (files.Length > 0)
{
try
FileInfo[] sortedFiles = files.OrderByDescending(file => file.CreationTime).ToArray();
//循环获取可用备份文件
string bakFilePath = "";
foreach (FileInfo bakFile in sortedFiles)
{
using (FileStream fs = new FileStream(Constants.DATA_FILE_BAK_PATH, FileMode.Open))
if (!Directory.Exists(Constants.DATA_FILE_TEMP_DIR_PATH)) { Directory.CreateDirectory(Constants.DATA_FILE_TEMP_DIR_PATH); }
bakFilePath = Constants.DATA_FILE_TEMP_DIR_PATH + "\\" + bakFile.Name;
try
{
BinaryFormatter bf = new BinaryFormatter();
appData = bf.Deserialize(fs) as AppData;
File.Copy(bakFile.FullName, bakFilePath, true);
using (FileStream fs = new FileStream(bakFilePath, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
appData = bf.Deserialize(fs) as AppData;
}
DialogMsg msg = new DialogMsg();
msg.msg = "不幸的是, GeekDesk当前的数据文件已经损坏, " +
"现在已经启用系统自动备份的数据\n\n" +
"如果你有较新的备份, " +
"请退出GeekDesk, " +
"将备份文件重命名为:Data, " +
"然后将Data覆盖到GeekDesk的根目录即可\n\n" +
"启用的备份文件为: \n" + bakFilePath +
"\n\n如果当前数据就是你想要的数据, 那么请不用管它";
GlobalMsgNotification gm = new GlobalMsgNotification(msg);
HandyControl.Controls.Notification ntf = HandyControl.Controls.Notification.Show(gm, ShowAnimation.Fade, true);
gm.ntf = ntf;
File.Delete(bakFilePath);
SaveAppData(appData, Constants.DATA_FILE_PATH);
return appData;
}
catch {
if (File.Exists(bakFilePath))
{
File.Delete(bakFilePath);
}
}
DialogMsg msg = new DialogMsg();
msg.msg = "不幸的是, GeekDesk当前的数据文件已经损坏, " +
"现在已经启用系统自动备份的数据\n\n" +
"如果你有较新的备份, " +
"请退出GeekDesk, " +
"将备份文件重命名为:Data, " +
"然后将Data覆盖到GeekDesk的根目录即可\n\n" +
"系统上次备份时间: \n" + appData.AppConfig.SysBakTime +
"\n\n如果当前数据就是你想要的数据, 那么请不用管它";
GlobalMsgNotification gm = new GlobalMsgNotification(msg);
HandyControl.Controls.Notification ntf = HandyControl.Controls.Notification.Show(gm, ShowAnimation.Fade, true);
gm.ntf = ntf;
}
catch
{
MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
Application.Current.Shutdown();
return null;
}
}
else
MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
Application.Current.Shutdown();
return new AppData();
} else
{
MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
Application.Current.Shutdown();
return null;
return new AppData();
}
// if (File.Exists(Constants.DATA_FILE_BAK_PATH))
//{
// try
// {
// using (FileStream fs = new FileStream(Constants.DATA_FILE_BAK_PATH, FileMode.Open))
// {
// BinaryFormatter bf = new BinaryFormatter();
// appData = bf.Deserialize(fs) as AppData;
// }
// DialogMsg msg = new DialogMsg();
// msg.msg = "不幸的是, GeekDesk当前的数据文件已经损坏, " +
// "现在已经启用系统自动备份的数据\n\n" +
// "如果你有较新的备份, " +
// "请退出GeekDesk, " +
// "将备份文件重命名为:Data, " +
// "然后将Data覆盖到GeekDesk的根目录即可\n\n" +
// "系统上次备份时间: \n" + appData.AppConfig.SysBakTime +
// "\n\n如果当前数据就是你想要的数据, 那么请不用管它";
// GlobalMsgNotification gm = new GlobalMsgNotification(msg);
// HandyControl.Controls.Notification ntf = HandyControl.Controls.Notification.Show(gm, ShowAnimation.Fade, true);
// gm.ntf = ntf;
// }
// catch
// {
// MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
// Application.Current.Shutdown();
// return null;
// }
//}
//else
//{
// MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
// Application.Current.Shutdown();
// return null;
//}
}
}
return appData;
}
private readonly static object _MyLock = new object();
@@ -105,10 +159,10 @@ namespace GeekDesk.Util
{
lock (_MyLock)
{
if (filePath.Equals(Constants.DATA_FILE_BAK_PATH))
{
appData.AppConfig.SysBakTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
//if (filePath.Equals(Constants.DATA_FILE_BAK_PATH))
//{
// appData.AppConfig.SysBakTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//}
if (!Directory.Exists(filePath.Substring(0, filePath.LastIndexOf("\\"))))
{
Directory.CreateDirectory(filePath.Substring(0, filePath.LastIndexOf("\\")));

View File

@@ -1,4 +1,5 @@
using GeekDesk.Constant;
using GeekDesk.MyThread;
using GeekDesk.ViewModel;
using HandyControl.Controls;
using System;
@@ -9,6 +10,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace GeekDesk.Util
{
@@ -241,6 +243,21 @@ namespace GeekDesk.Util
}
public static void ReStartApp()
{
if (MainWindow.appData.AppConfig.MouseMiddleShow || MainWindow.appData.AppConfig.SecondsWindow == true)
{
MouseHookThread.Dispose();
}
Process p = new Process();
p.StartInfo.FileName = Constants.APP_DIR + "GeekDesk.exe";
p.StartInfo.WorkingDirectory = Constants.APP_DIR;
p.Start();
Application.Current.Shutdown();
}
[Flags]
private enum ProcessAccessFlags : uint
{

View File

@@ -1,6 +1,9 @@
using GeekDesk.Constant;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
namespace GeekDesk.Util
{
@@ -18,6 +21,86 @@ namespace GeekDesk.Util
RIGHT_CENTER = 7
}
public static void FollowMouse(Window window)
{
// Get the mouse position
var mousePosition = System.Windows.Forms.Control.MousePosition;
// Get the window size
var windowWidth = window.Width;
var windowHeight = window.Height;
Console.WriteLine("windowWidth + windowHeight:" + windowWidth + "+" + windowHeight);
// Get the screen where the mouse is located
var screen = System.Windows.Forms.Screen.FromPoint(new System.Drawing.Point(mousePosition.X, mousePosition.Y));
var workingArea = screen.WorkingArea;
// Get the DPI scaling factor for the screen
//float dpiX, dpiY;
//using (var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero))
//{
// dpiX = graphics.DpiX / 96f; // 96 is the default DPI
// dpiY = graphics.DpiY / 96f; // 96 is the default DPI
//}
float dpiX = GetDpi( true);
float dpiY = GetDpi(false);
// Convert mouse position to logical pixels based on DPI
double mouseX = mousePosition.X / dpiX;
double mouseY = mousePosition.Y / dpiY;
// Calculate target position to center the window on the mouse
double targetLeft = mouseX - windowWidth / 2;
double targetTop = mouseY - windowHeight / 2;
// Ensure the window does not exceed the screen boundaries
if (targetLeft < workingArea.Left / dpiX)
targetLeft = workingArea.Left / dpiX;
if (targetLeft + windowWidth / dpiX > workingArea.Right / dpiX)
targetLeft = workingArea.Right / dpiX - windowWidth / dpiX;
if (targetTop < workingArea.Top / dpiY)
targetTop = workingArea.Top / dpiY;
if (targetTop + windowHeight / dpiY > workingArea.Bottom / dpiY)
targetTop = workingArea.Bottom / dpiY - windowHeight / dpiY;
// Update window position
window.Left = targetLeft * dpiX;
window.Top = targetTop * dpiY;
}
private static float GetDpi(bool isX)
{
IntPtr hdc = WindowUtil.GetDC(IntPtr.Zero);
int dpi = isX ? WindowUtil.GetDeviceCaps(hdc, LOGPIXELSX) : WindowUtil.GetDeviceCaps(hdc, LOGPIXELSY);
WindowUtil.ReleaseDC(IntPtr.Zero, hdc);
return dpi / 96f;
}
private static IntPtr GetScreenHandleFromMouse()
{
// Get the mouse position
var mousePosition = System.Windows.Forms.Control.MousePosition;
// Convert mouse position to a POINT structure
System.Drawing.Point point = new System.Drawing.Point(mousePosition.X, mousePosition.Y);
// Get the window handle from the point
IntPtr windowHandle = WindowUtil.WindowFromPoint(point);
return windowHandle;
}
// Constants for DPI
private const int HORZRES = 8;
private const int VERTRES = 10;
private const int LOGPIXELSX = 88;
private const int LOGPIXELSY = 90;
/// <summary>
/// 随鼠标位置显示面板
/// </summary>
@@ -25,6 +108,12 @@ namespace GeekDesk.Util
{
//获取鼠标位置
System.Windows.Point p = MouseUtil.GetMousePosition();
float dpiX = GetDpi(true);
float dpiY = GetDpi(false);
p.X = p.X / dpiX;
p.Y = p.Y / dpiY;
double left = SystemParameters.VirtualScreenLeft;
double top = SystemParameters.VirtualScreenTop;
double width = SystemParameters.VirtualScreenWidth;

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@@ -9,6 +10,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Interop;
using static GeekDesk.Util.FileIcon;
namespace GeekDesk.Util
{
@@ -42,6 +44,9 @@ namespace GeekDesk.Util
SWP_NOSENDCHANGING = 0x0400
}
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(System.Drawing.Point p);
//取得前台窗口句柄函数
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
@@ -71,6 +76,60 @@ namespace GeekDesk.Util
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID); //获取线程ID
/// <summary>
/// 枚举窗口时的委托参数
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
public delegate bool WndEnumProc(IntPtr hWnd, int lParam);
/// <summary>
/// 枚举所有窗口
/// </summary>
/// <param name="lpEnumFunc"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam);
/// <summary>
/// 获取窗口的父窗口句柄
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect);
// Import GetDC and ReleaseDC functions from user32.dll
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[StructLayout(LayoutKind.Sequential)]
public readonly struct LPRECT
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
private const int GWL_STYLE = -16;
@@ -82,6 +141,112 @@ namespace GeekDesk.Util
SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX));
}
/// <summary>
/// 获取 Win32 窗口的一些基本信息。
/// </summary>
public struct WindowInfo
{
public WindowInfo(IntPtr hWnd, string className, string title, bool isVisible, Rectangle bounds) : this()
{
Hwnd = hWnd;
ClassName = className;
Title = title;
IsVisible = isVisible;
Bounds = bounds;
}
/// <summary>
/// 获取窗口句柄。
/// </summary>
public IntPtr Hwnd { get; }
/// <summary>
/// 获取窗口类名。
/// </summary>
public string ClassName { get; }
/// <summary>
/// 获取窗口标题。
/// </summary>
public string Title { get; }
/// <summary>
/// 获取当前窗口是否可见。
/// </summary>
public bool IsVisible { get; }
/// <summary>
/// 获取窗口当前的位置和尺寸。
/// </summary>
public Rectangle Bounds { get; }
/// <summary>
/// 获取窗口当前是否是最小化的。
/// </summary>
public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
}
/// <summary>
/// 遍历窗体处理的函数
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lparam"></param>
/// <returns></returns>
private static bool OnWindowEnum(IntPtr hWnd, int lparam)
{
// 仅查找顶层窗口。
//if (GetParent(hWnd) == IntPtr.Zero)
//{
// 获取窗口类名。
var lpString = new StringBuilder(512);
GetClassName(hWnd, lpString, lpString.Capacity);
var className = lpString.ToString();
// 获取窗口标题。
var lptrString = new StringBuilder(512);
GetWindowText(hWnd, lptrString, lptrString.Capacity);
var title = lptrString.ToString().Trim();
// 获取窗口可见性。
var isVisible = IsWindowVisible(hWnd);
// 获取窗口位置和尺寸。
LPRECT rect = default;
GetWindowRect(hWnd, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
// 添加到已找到的窗口列表。
windowList.Add(new WindowInfo(hWnd, className, title, isVisible, bounds));
//}
return true;
}
/// <summary>
/// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
/// </summary>
private static readonly Predicate<WindowInfo> DefaultPredicate = x => x.IsVisible && !x.IsMinimized && x.Title.Length > 0;
/// <summary>
/// 窗体列表
/// </summary>
private static List<WindowInfo> windowList;
/// <summary>
/// 查找当前用户空间下所有符合条件的(顶层)窗口。如果不指定条件,将仅查找可见且有标题栏的窗口。
/// </summary>
/// <param name="match">过滤窗口的条件。如果设置为 null将仅查找可见和标题栏不为空的窗口。</param>
/// <returns>找到的所有窗口信息</returns>
public static IReadOnlyList<WindowInfo> FindAllWindows(Predicate<WindowInfo> match = null)
{
windowList = new List<WindowInfo>();
//遍历窗口并查找窗口相关WindowInfo信息
EnumWindows(OnWindowEnum, 0);
return windowList;
}
public static void SetOwner(Window window, Window parentWindow)
{