diff --git a/App.config b/App.config
index 4a166e8..a0e6050 100644
--- a/App.config
+++ b/App.config
@@ -61,7 +61,7 @@
-
+
@@ -70,6 +70,7 @@
+
diff --git a/App.xaml.cs b/App.xaml.cs
index 1701231..4a63eea 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -1,8 +1,14 @@
using GeekDesk.Constant;
+using GeekDesk.MyThread;
using GeekDesk.Util;
+using GeekDesk.ViewModel;
+using Microsoft.Win32;
using System;
+using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
+using System.Windows.Interop;
+using System.Windows.Media;
using System.Windows.Threading;
namespace GeekDesk
@@ -20,10 +26,13 @@ namespace GeekDesk
this.Startup += new StartupEventHandler(App_Startup);
Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ SystemEvents.PowerModeChanged += OnPowerModeChanged;
}
+
private void App_Startup(object sender, StartupEventArgs e)
{
+ //RenderOptions.ProcessRenderMode = System.Windows.Interop.RenderMode.SoftwareOnly; //禁用硬件加速
mutex = new System.Threading.Mutex(true, Constants.MY_NAME, out bool ret);
if (!ret)
{
@@ -40,6 +49,25 @@ namespace GeekDesk
}
}
+
+ //电源监听
+ private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ switch (e.Mode)
+ {
+ case PowerModes.Resume:
+ // 系统从休眠状态唤醒
+ LogUtil.WriteLog("System resumed from sleep.");
+ ProcessUtil.ReStartApp();
+ break;
+ case PowerModes.Suspend:
+ // 系统进入休眠状态
+ LogUtil.WriteLog("System is going to sleep.");
+ break;
+ }
+ }
+
+
void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;//使用这一行代码告诉运行时,该异常被处理了,不再作为UnhandledException抛出了。
diff --git a/Constant/Constants.cs b/Constant/Constants.cs
index 40b117e..2016dc5 100644
--- a/Constant/Constants.cs
+++ b/Constant/Constants.cs
@@ -22,7 +22,11 @@ namespace GeekDesk.Constant
///
/// 备份文件路径
///
- public static string DATA_FILE_BAK_PATH = APP_DIR + "bak\\Data.bak"; //app备份数据文件路径
+ public static string DATA_FILE_BAK_DIR_PATH = APP_DIR + "bak"; //app备份数据文件路径
+ public static string DATA_FILE_TEMP_DIR_PATH = APP_DIR + "temp"; //app临时缓存文件路径
+
+ //public static string DATA_FILE_BAK_PATH = DATA_FILE_BAK_DIR_PATH + "\\Data.bak"; //app备份数据文件路径
+
public static string PW_FILE_BAK_PATH = APP_DIR + "bak\\pw.txt"; //密码文件路径
diff --git a/GeekDesk.csproj b/GeekDesk.csproj
index 7cc64cc..8f452c5 100644
--- a/GeekDesk.csproj
+++ b/GeekDesk.csproj
@@ -290,7 +290,7 @@
SecondsWindow.xaml
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index f86b1db..49fceaa 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -73,8 +73,11 @@ namespace GeekDesk
MarginHide.StartHide();
}
+
+
}
+
private void Window_SourceInitialized(object sender, EventArgs e)
{
try
@@ -85,6 +88,8 @@ namespace GeekDesk
catch (Exception) { }
}
+
+
///
@@ -379,6 +384,9 @@ namespace GeekDesk
EveryThingUtil.EnableEveryThing();
}
+ //启动文件备份任务
+ BakTask.Start();
+
Keyboard.Focus(SearchBox);
MessageUtil.ChangeWindowMessageFilter(MessageUtil.WM_COPYDATA, 1);
@@ -388,6 +396,7 @@ namespace GeekDesk
{
Guide();
}
+
}
@@ -596,6 +605,7 @@ namespace GeekDesk
if (appData.AppConfig.FollowMouse)
{
ShowWindowFollowMouse.Show(mainWindow, MousePosition.CENTER, 0, 0);
+ //ShowWindowFollowMouse.FollowMouse(mainWindow);
}
@@ -853,19 +863,9 @@ namespace GeekDesk
///
///
///
- private void ReStartApp(object sender, RoutedEventArgs e)
+ public void ReStartApp(object sender, RoutedEventArgs e)
{
- if (appData.AppConfig.MouseMiddleShow || 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();
+ ProcessUtil.ReStartApp();
}
///
diff --git a/MyThread/RelativePathThread.cs b/MyThread/RelativePathThread.cs
index bfd4ac0..c454571 100644
--- a/MyThread/RelativePathThread.cs
+++ b/MyThread/RelativePathThread.cs
@@ -36,7 +36,7 @@ namespace GeekDesk.MyThread
}
}
CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_PATH);
- CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_BAK_PATH);
+ //CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_BAK_PATH);
}
catch (Exception ex)
{
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index 01baf68..96bd551 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.5.1.3")]
-[assembly: AssemblyFileVersion("2.5.1.3")]
+[assembly: AssemblyVersion("2.5.1.5")]
+[assembly: AssemblyFileVersion("2.5.1.5")]
diff --git a/Task/BakTask.cs b/Task/BakTask.cs
new file mode 100644
index 0000000..5b434db
--- /dev/null
+++ b/Task/BakTask.cs
@@ -0,0 +1,92 @@
+using GeekDesk.Constant;
+using GeekDesk.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace GeekDesk.Task
+{
+ internal class BakTask
+ {
+
+ public static void Start()
+ {
+ System.Timers.Timer timer = new System.Timers.Timer
+ {
+ Enabled = true,
+ Interval = 60 * 1000 * 60, //60秒 * 60分钟
+ //Interval = 6000,
+ };
+ timer.Start();
+ timer.Elapsed += Timer_Elapsed;
+ }
+
+ private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ DirectoryInfo dirInfo = new DirectoryInfo(Constants.DATA_FILE_BAK_DIR_PATH);
+
+ string todayBakName = DateTime.Now.ToString("yyyy-MM-dd") + ".bak";
+
+ string bakDaysStr = ConfigurationManager.AppSettings["BakDays"];
+ int bakDays = 7;
+ if (bakDaysStr != null && !"".Equals(bakDaysStr.Trim()))
+ {
+ bakDays = Int32.Parse(bakDaysStr.Trim());
+ }
+
+ string bakFilePath = Constants.DATA_FILE_BAK_DIR_PATH + "\\" + todayBakName;
+ if (dirInfo.Exists)
+ {
+ // 获取文件信息并按创建时间倒序排序
+ FileInfo[] files = dirInfo.GetFiles();
+ if (files.Length > 0)
+ {
+ FileInfo[] sortedFiles = files.OrderByDescending(file => file.CreationTime).ToArray();
+ if (!sortedFiles[0].Name.Equals(todayBakName))
+ {
+ //今天未创建备份 开始创建今天的备份
+ createBakFile(bakFilePath);
+ }
+
+ //判断文件是否超过了7个 超过7个就删除
+ if (sortedFiles.Length > bakDays)
+ {
+ for (int i = bakDays; i < sortedFiles.Length; i++)
+ {
+ sortedFiles[i].Delete();
+ }
+ }
+
+ } else
+ {
+ //没有文件 直接创建今天的备份
+ createBakFile(bakFilePath);
+ }
+
+ }
+ else
+ {
+ dirInfo.Create();
+ }
+ }
+
+ //创建备份文件
+ private static void createBakFile(string filePath)
+ {
+ using (FileStream fs = new FileStream(filePath, FileMode.Create))
+ {
+ BinaryFormatter bf = new BinaryFormatter();
+ bf.Serialize(fs, MainWindow.appData);
+ }
+ }
+
+
+ }
+}
diff --git a/Task/ShowSecondTask.cs b/Task/ShowSecondTask.cs
deleted file mode 100644
index 8cd3186..0000000
--- a/Task/ShowSecondTask.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace GeekDesk.Task
-{
- internal class ShowSecondTask
- {
-
- public static void SHowSecond()
- {
- System.Timers.Timer timer = new System.Timers.Timer
- {
- Enabled = true,
- Interval = 5000
- };
- timer.Start();
- timer.Elapsed += Timer_Elapsed;
- }
-
- private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
- {
- Process[] pcArr = Process.GetProcessesByName("ShellExperienceHost.exe");
- Thread.Sleep(1000);
- }
- }
-}
diff --git a/Update.json b/Update.json
index 9459f9b..45b404b 100644
--- a/Update.json
+++ b/Update.json
@@ -1,10 +1,10 @@
{
"title": "GeekDesk版本更新",
- "subTitle": "V2.5.14",
+ "subTitle": "V2.5.15",
"msgTitle": "本次更新内容如下",
- "msg": "['好久不见, 别来无恙, 辞职回老家了, 我是个多愁善感的人, 心里有些仿徨和迷茫, 祝所有人都前程似锦, 世界和平.', 'GeekDesk准备冲击一下Gitee GVP, 希望大家能给我点一下码云(Gitee)和GitHub的star❤❤❤', '之后我会抽时间编写一下开发者文档, 方便大家更清楚的了解项目结构, 从而有更多的人参与进来开发(一直没有编写是因为太懒了), 不多说了, 看下这次更新内容吧', '集成Everything搜索,设置-->其它-->勾选Everything插件开启', '增加了关联文件夹功能, 右键点击左侧栏-->新建关联菜单', '增加强制置顶开关,设置-->显示设置-->勾选/取消 置于顶层', '右侧栏图标列表增加了自适应列宽, 不会出现图标显示一半的情况了', '简单添加了新手引导提示', '加密菜单bug修复 By @1062406901', '多显示器拾色器bug修复 By @1062406901', '拖动图标到菜单的异常修复 By @Hsxxxxxx', '优化部分UI', '其它bug修复及功能优化','关注微信公众号\\'抓几个娃\\'可以第一时间收到更新通知(公众号也是佛系维护, 希望能关注的人多一点吧, 让作者这个穷B挣口饭吃)']",
+ "msg": "['鸽了挺久, 我终于又来更新了, 废话不多说, 看下本次更新内容', '增加多文件备份, 数据文件损坏会自动寻找最近的一次备份数据, 不用担心数据文件损坏了, 备份数据默认为最近7天, 可以通过打开根目录下GeekDesk.exe.config, 找到BakDays修改', '修复高分屏缩放导致的鼠标追随bug', 'UI假死的情况, 由于并不是每个用户都出现这个bug, 这次做了尝试性修复, 各位可以看下是否还会出现切换菜单出现不会出现图标的情况']",
"githubUrl": "https://github.com/BookerLiu/GeekDesk/releases",
"giteeUrl": "https://gitee.com/BookerLiu/GeekDesk/releases",
"statisticUrl": "http://43.138.23.39:8989/bookerService/geekDeskController/userCountStatistic",
- "version": "2.5.14"
+ "version": "2.5.15"
}
diff --git a/Util/CommonCode.cs b/Util/CommonCode.cs
index 92345f6..cc511a6 100644
--- a/Util/CommonCode.cs
+++ b/Util/CommonCode.cs
@@ -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("\\")));
diff --git a/Util/ProcessUtil.cs b/Util/ProcessUtil.cs
index 278c935..f8cbd07 100644
--- a/Util/ProcessUtil.cs
+++ b/Util/ProcessUtil.cs
@@ -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
{
diff --git a/Util/ShowWindowFollowMouse.cs b/Util/ShowWindowFollowMouse.cs
index b5fb787..64e9373 100644
--- a/Util/ShowWindowFollowMouse.cs
+++ b/Util/ShowWindowFollowMouse.cs
@@ -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;
+
+
+
///
/// 随鼠标位置显示面板
///
@@ -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;
diff --git a/Util/WindowUtil.cs b/Util/WindowUtil.cs
index 941b39c..c0ec024 100644
--- a/Util/WindowUtil.cs
+++ b/Util/WindowUtil.cs
@@ -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
+ ///
+ /// 枚举窗口时的委托参数
+ ///
+ ///
+ ///
+ ///
+ public delegate bool WndEnumProc(IntPtr hWnd, int lParam);
+ ///
+ /// 枚举所有窗口
+ ///
+ ///
+ ///
+ ///
+ [DllImport("user32.dll")]
+ public static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam);
+
+ ///
+ /// 获取窗口的父窗口句柄
+ ///
+ ///
+ ///
+ [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));
}
+ ///
+ /// 获取 Win32 窗口的一些基本信息。
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取窗口句柄。
+ ///
+ public IntPtr Hwnd { get; }
+
+ ///
+ /// 获取窗口类名。
+ ///
+ public string ClassName { get; }
+
+ ///
+ /// 获取窗口标题。
+ ///
+ public string Title { get; }
+
+ ///
+ /// 获取当前窗口是否可见。
+ ///
+ public bool IsVisible { get; }
+
+ ///
+ /// 获取窗口当前的位置和尺寸。
+ ///
+ public Rectangle Bounds { get; }
+
+ ///
+ /// 获取窗口当前是否是最小化的。
+ ///
+ public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
+ }
+
+
+ ///
+ /// 遍历窗体处理的函数
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
+ ///
+ /// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
+ ///
+ private static readonly Predicate DefaultPredicate = x => x.IsVisible && !x.IsMinimized && x.Title.Length > 0;
+ ///
+ /// 窗体列表
+ ///
+ private static List windowList;
+
+
+ ///
+ /// 查找当前用户空间下所有符合条件的(顶层)窗口。如果不指定条件,将仅查找可见且有标题栏的窗口。
+ ///
+ /// 过滤窗口的条件。如果设置为 null,将仅查找可见和标题栏不为空的窗口。
+ /// 找到的所有窗口信息
+ public static IReadOnlyList FindAllWindows(Predicate match = null)
+ {
+ windowList = new List();
+ //遍历窗口并查找窗口相关WindowInfo信息
+ EnumWindows(OnWindowEnum, 0);
+ return windowList;
+ }
+
+
public static void SetOwner(Window window, Window parentWindow)
{