├── Line ├── LineForm.cs ├── LineIco.ico ├── Line.csproj ├── VerticalLineForm.resx ├── HorizontalLineForm.resx ├── MonitoredAppsWindow.cs ├── VerticalLineForm.cs ├── HorizontalLineForm.cs └── BoundingBoxForm.cs ├── Line_wpf ├── LineIco.ico ├── App.xaml ├── MainWindow.xaml ├── BoundingBoxWindow.xaml ├── VerticalLineWindow.xaml ├── HorizontalLineWindow.xaml ├── Line_wpf.csproj ├── Program.cs ├── MonitoredAppsWindow.xaml ├── App.xaml.cs └── MonitoredAppsWindow.xaml.cs ├── Line.Tests ├── Line.Tests.csproj └── ConfigSaveTests.cs ├── LICENSE.txt ├── LICENSE ├── Line.sln ├── Program.cs ├── .gitattributes ├── README.md └── .gitignore /Line/LineForm.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Line/LineIco.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlyclxy/Line/master/Line/LineIco.ico -------------------------------------------------------------------------------- /Line_wpf/LineIco.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlyclxy/Line/master/Line_wpf/LineIco.ico -------------------------------------------------------------------------------- /Line_wpf/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Line.Tests/Line.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Line_wpf/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Line/Line.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WinExe 6 | net8.0-windows 7 | true 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Always 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Line_wpf/BoundingBoxWindow.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Line_wpf/VerticalLineWindow.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Line_wpf/HorizontalLineWindow.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Line_wpf/Line_wpf.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0-windows 6 | true 7 | true 8 | enable 9 | disable 10 | false 11 | false 12 | LineIco.ico 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Always 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Screen Reference Line Tool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Line.Tests/ConfigSaveTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Runtime.Serialization; 5 | using Xunit; 6 | 7 | namespace Line.Tests 8 | { 9 | public class ConfigSaveTests 10 | { 11 | private static void InvokeSave(object instance, string methodName) 12 | { 13 | var method = instance.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); 14 | method!.Invoke(instance, null); 15 | } 16 | 17 | private static string GetConfigPath(object instance) 18 | { 19 | var field = instance.GetType().GetField("configPath", BindingFlags.NonPublic | BindingFlags.Instance); 20 | return (string)field!.GetValue(instance)!; 21 | } 22 | 23 | private static void TestSaveConfig(Type type) 24 | { 25 | var instance = FormatterServices.GetUninitializedObject(type); 26 | var path = GetConfigPath(instance); 27 | var dir = Path.GetDirectoryName(path)!; 28 | if (Directory.Exists(dir)) 29 | { 30 | Directory.Delete(dir, true); 31 | } 32 | 33 | InvokeSave(instance, "SaveConfig"); 34 | 35 | Assert.True(File.Exists(path)); 36 | } 37 | 38 | [Fact] 39 | public void LineForm_SaveConfig_CreatesFile() 40 | { 41 | TestSaveConfig(typeof(Line.LineForm)); 42 | } 43 | 44 | [Fact] 45 | public void VerticalLineForm_SaveConfig_CreatesFile() 46 | { 47 | TestSaveConfig(typeof(Line.VerticalLineForm)); 48 | } 49 | 50 | [Fact] 51 | public void HorizontalLineForm_SaveConfig_CreatesFile() 52 | { 53 | TestSaveConfig(typeof(Line.HorizontalLineForm)); 54 | } 55 | 56 | [Fact] 57 | public void BoundingBoxForm_SaveConfig_CreatesFile() 58 | { 59 | TestSaveConfig(typeof(Line.BoundingBoxForm)); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Line.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34902.65 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Line", "Line\Line.csproj", "{2DC48F3A-58E9-4600-8280-D6A88F4F9DF4}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Line_wpf", "Line_wpf\Line_wpf.csproj", "{E85B9848-33D5-4485-B729-DBBC2E6D6918}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Line.Tests", "Line.Tests\Line.Tests.csproj", "{33E28D51-9686-4CBC-BC38-A956A4D2F569}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {2DC48F3A-58E9-4600-8280-D6A88F4F9DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {2DC48F3A-58E9-4600-8280-D6A88F4F9DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {2DC48F3A-58E9-4600-8280-D6A88F4F9DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {2DC48F3A-58E9-4600-8280-D6A88F4F9DF4}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {E85B9848-33D5-4485-B729-DBBC2E6D6918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E85B9848-33D5-4485-B729-DBBC2E6D6918}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E85B9848-33D5-4485-B729-DBBC2E6D6918}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E85B9848-33D5-4485-B729-DBBC2E6D6918}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {33E28D51-9686-4CBC-BC38-A956A4D2F569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {33E28D51-9686-4CBC-BC38-A956A4D2F569}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {33E28D51-9686-4CBC-BC38-A956A4D2F569}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {33E28D51-9686-4CBC-BC38-A956A4D2F569}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {71200D44-B14E-4C01-834D-6BD79FF9E5E6} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Text.Json; 6 | using System.Windows.Forms; 7 | 8 | namespace Snipaste 9 | { 10 | public partial class Program : Form 11 | { 12 | // 加载配置 13 | private void LoadConfig() 14 | { 15 | try 16 | { 17 | if (File.Exists(configPath)) 18 | { 19 | string jsonString = File.ReadAllText(configPath); 20 | var config = JsonSerializer.Deserialize(jsonString); 21 | 22 | showOnAllScreens = config.ShowOnAllScreens; 23 | lineHeight = config.LineHeight; 24 | lineColor = ColorTranslator.FromHtml(config.LineColor); 25 | lineOpacity = config.LineOpacity; 26 | displayDuration = config.DisplayDuration; 27 | currentHotKey = config.HotKey; 28 | persistentTopmost = config.PersistentTopmost; 29 | 30 | // 新增:加载置顶策略配置 31 | currentTopmostStrategy = (TopmostStrategy)config.TopmostStrategy; 32 | currentTimerInterval = config.TimerInterval; 33 | 34 | // 验证定时器间隔,确保不为0或负数 35 | if (currentTimerInterval <= 0) 36 | { 37 | currentTimerInterval = 100; // 默认值 38 | } 39 | 40 | if (config.MonitoredApplications != null && config.MonitoredApplications.Count > 0) 41 | { 42 | monitoredApplications = config.MonitoredApplications; 43 | } 44 | } 45 | } 46 | catch (Exception ex) 47 | { 48 | // 如果加载失败,使用默认值 49 | showOnAllScreens = false; 50 | lineHeight = 1; 51 | lineColor = Color.Red; 52 | lineOpacity = 100; 53 | displayDuration = 1.5; 54 | currentHotKey = Keys.F5; 55 | persistentTopmost = false; 56 | currentTopmostStrategy = TopmostStrategy.ForceTimer; 57 | currentTimerInterval = 100; 58 | monitoredApplications = new List { "Paster - Snipaste", "PixPin" }; 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Line_wpf/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Threading; 5 | using System.Windows; 6 | using MessageBox = System.Windows.MessageBox; 7 | 8 | namespace Line_wpf 9 | { 10 | internal class Program 11 | { 12 | // 用于确保应用程序只运行一个实例的互斥体 13 | private static readonly Mutex SingleInstanceMutex = new Mutex(true, "LineAppSingleInstanceMutex_WPF"); 14 | 15 | // 添加应用程序数据目录路径 16 | private static readonly string AppDataPath = Path.Combine( 17 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), 18 | "ScreenLine" 19 | ); 20 | 21 | /// 22 | /// 释放单实例互斥体(用于重启功能) 23 | /// 24 | public static void ReleaseSingleInstanceMutex() 25 | { 26 | try 27 | { 28 | SingleInstanceMutex.ReleaseMutex(); 29 | } 30 | catch (Exception) 31 | { 32 | // 忽略释放互斥体时的异常 33 | } 34 | } 35 | 36 | /// 37 | /// 检查是否有其他实例正在运行(备用方法) 38 | /// 39 | public static bool IsAnotherInstanceRunning() 40 | { 41 | try 42 | { 43 | var currentProcess = Process.GetCurrentProcess(); 44 | string currentProcessName = currentProcess.ProcessName; 45 | Process[] processes = Process.GetProcessesByName(currentProcessName); 46 | 47 | // 检查是否有其他进程具有相同的可执行文件路径 48 | string currentPath = currentProcess.MainModule.FileName; 49 | 50 | foreach (var process in processes) 51 | { 52 | if (process.Id != currentProcess.Id && 53 | !process.HasExited && 54 | process.MainModule.FileName.Equals(currentPath, StringComparison.OrdinalIgnoreCase)) 55 | { 56 | return true; 57 | } 58 | } 59 | 60 | return false; 61 | } 62 | catch (Exception) 63 | { 64 | // 如果检查失败,返回false(假设没有其他实例) 65 | return false; 66 | } 67 | } 68 | 69 | public static Mutex GetSingleInstanceMutex() 70 | { 71 | return SingleInstanceMutex; 72 | } 73 | 74 | public static string GetAppDataPath() 75 | { 76 | return AppDataPath; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Line_wpf/MonitoredAppsWindow.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 31 | 34 | 35 | 36 | 37 | 38 | 39 |