本文主要是介绍macad3d解析macad—application,commands,utils,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.macad-properties
设置类型可见,以及语言
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]//设置此程序集中的类型对COM组件不可见//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
[assembly: NeutralResourcesLanguage("en", UltimateResourceFallbackLocation.MainAssembly)]
//语言设置[assembly: ThemeInfo(ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located//(used if a resource is not found in the page, // or application resource dictionaries)ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located//(used if a resource is not found in the page, // app, or any theme specific resource dictionaries)
)]
1.macad-application-appcontext
using System;
using System.IO;
using System.Text;
using System.Windows.Input;
using Macad.Core; // 引入Macad核心命名空间
using Macad.Common.Serialization; // 引入Macad通用序列化命名空间
using Macad.Interaction; // 引入Macad交互命名空间
using Macad.Common; // 引入Macad通用命名空间
using Macad.Exchange; // 引入Macad交换命名空间namespace Macad.Window
{// 定义应用程序上下文类,继承自交互上下文类public class AppContext : InteractiveContext{#region Properties// 获取当前应用程序上下文的静态属性public new static AppContext Current { get; private set; }//--------------------------------------------------------------------------------------------------// 是否在沙盒模式中的静态属性public static bool IsInSandbox{get { return CommandLine.EnableSandbox; }}//--------------------------------------------------------------------------------------------------// 命令行对象的静态属性public static CommandLine CommandLine { get; private set; }#endregion#region Initialization// 构造函数,初始化应用程序上下文AppContext(){LoadShortcuts(); // 加载快捷键}//--------------------------------------------------------------------------------------------------// 初始化应用程序上下文internal static void Initialize(CommandLine cmdLine){CommandLine = cmdLine; // 设置命令行对象if (IsInSandbox) // 如果处于沙盒模式{DebugPipeServer.Open(); // 开启调试管道服务器}Current = new AppContext(); // 创建当前应用程序上下文对象ExchangeModule.Initialize(); // 初始化交换模块}//--------------------------------------------------------------------------------------------------// 加载快捷键void LoadShortcuts(){ShortcutHandler.AddShortcut(ShortcutScope.Application, new(Key.F1, ApplicationCommands.Help)); // 添加帮助命令的快捷键ShortcutHandler.AddShortcut(ShortcutScope.Application, new(Key.S, ModifierKeys.Control, DocumentCommands.SaveAll)); // 添加保存所有文档命令的快捷键}//--------------------------------------------------------------------------------------------------#endregion#region Local App Data// 本地应用数据目录public readonly string LocalAppDataDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create), "Macad");//--------------------------------------------------------------------------------------------------// 保存本地设置public override void SaveLocalSettings(string name, object obj){if (IsInSandbox) // 如果处于沙盒模式,则返回return;try{var data = Serializer.Serialize(obj, new SerializationContext(SerializationScope.Storage)); // 序列化对象if (data.IsNullOrEmpty()) // 如果数据为空,则返回return;var dir = Path.Combine(LocalAppDataDirectory, "Settings"); // 设置保存目录Directory.CreateDirectory(dir); // 创建目录var path = Path.Combine(dir, name); // 设置保存路径File.WriteAllText(path, Serializer.Format(data), Encoding.UTF8); // 写入文件}catch (Exception e){Messages.Exception("Exception while saving local settings for " + name, e); // 异常处理}}//--------------------------------------------------------------------------------------------------// 加载本地设置public override T LoadLocalSettings<T>(string name) {if (IsInSandbox) // 如果处于沙盒模式,则返回nullreturn null;try{var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create), "Macad", "Settings", name); // 设置加载路径if (!File.Exists(path)) // 如果文件不存在,则返回nullreturn null;var data = File.ReadAllText(path, Encoding.UTF8); // 读取文件内容if (data.IsNullOrEmpty()) // 如果数据为空,则返回nullreturn null;return Serializer.Deserialize<T>(data, new SerializationContext(SerializationScope.Storage)); // 反序列化对象}catch (Exception e){Messages.Exception("Exception while saving local settings for " + name, e); // 异常处理return null;}}//--------------------------------------------------------------------------------------------------#endregion}
}
这段代码是一个C#应用程序的主要入口点,定义了一个名为AppContext
的类,用于管理应用程序的上下文环境。主要功能包括:
-
定义了
AppContext
类,继承自InteractiveContext
,用于管理应用程序的交互环境。 -
提供了静态属性
Current
,用于获取当前应用程序上下文的实例。 -
提供了静态属性
IsInSandbox
,用于判断应用程序是否处于沙盒模式。 -
提供了静态属性
CommandLine
,用于获取命令行对象。 -
提供了静态方法
Initialize
,用于初始化应用程序上下文。 -
在构造函数中加载了快捷键。
-
提供了方法
SaveLocalSettings
和LoadLocalSettings
,用于保存和加载本地设置。
总的来说,这段代码的作用是初始化应用程序的上下文环境,包括加载快捷键和管理本地设置等功能。
1.macad-application-crashhandler
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using Macad.Common.Interop;
using Macad.Core.Topology;
using Macad.Presentation;namespace Macad.Window
{public static class CrashHandler{// 初始化崩溃处理器public static void Init(string crashDumpDirectory){// 设置崩溃转储目录_CrashDumpDirectory = crashDumpDirectory;// 注册未捕获异常事件处理程序AppDomain.CurrentDomain.UnhandledException += _CurrentDomain_UnhandledException;Application.Current.DispatcherUnhandledException += _Current_DispatcherUnhandledException;// 删除之前的崩溃转储文件foreach (var dumpFile in Directory.EnumerateFiles(_CrashDumpDirectory, "Macad_*.dmp")){try{File.Delete(dumpFile);}catch (Exception){}}}//--------------------------------------------------------------------------------------------------static string _CrashDumpDirectory;static bool _InCrashState;//--------------------------------------------------------------------------------------------------// 处理调度程序未捕获的异常static void _Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs args){if (_UnhandledException()){if (args != null)args.Handled = true;Application.Current?.Shutdown();}}//--------------------------------------------------------------------------------------------------// 处理应用程序域未捕获的异常static void _CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs args){_UnhandledException();Application.Current?.Shutdown();}//--------------------------------------------------------------------------------------------------// 处理未捕获的异常static bool _UnhandledException(){if (_InCrashState || Debugger.IsAttached)return false;_InCrashState = true;MessageBoxResult mbres = MessageBoxResult.OK;Task.Run(() =>{mbres = MessageBox.Show("An unhandled exception occurred, and the application is terminating.\n\n"+ "If you click OK, it is tried to save a copy of the open documents.\n"+ "Also two crashdump files will be saved to the application directory. "+ "These can be used by the developer to trace the crash.\n\n"+ "The crashdump files will be deleted on the next start of the application.","Ooops...", MessageBoxButton.OKCancel, MessageBoxImage.Error);}).Wait();if(mbres != MessageBoxResult.OK)return false;using (new WaitCursor()){_Dump(false);_Dump(true);_SaveDocuments();}return true;}//--------------------------------------------------------------------------------------------------// 保存文档static void _SaveDocuments(){try{string fileName = AppContext.Current?.Document?.FilePath;if (!string.IsNullOrEmpty(fileName)){string dirName = Path.GetDirectoryName(fileName) ?? _CrashDumpDirectory;fileName = Path.Combine(dirName, $"{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now:yyyy-MM-yy_HHmmss}.{Model.FileExtension}");AppContext.Current.Document.SaveToFile(fileName);}}catch (Exception){}}//--------------------------------------------------------------------------------------------------// 生成转储文件static void _Dump(bool full){var fileName = Path.Combine(_CrashDumpDirectory, $"Macad_{ (full ? "Full" : "Small")}_{DateTime.Now:yyyy-MM-yy_HHmmss}.dmp");var fileStream = File.Create(fileName);if (fileStream.SafeFileHandle == null)return;var info = new Win32Api.MINIDUMP_EXCEPTION_INFORMATION{ClientPointers = 1,ExceptionPointers = Marshal.GetExceptionPointers(),ThreadId = Win32Api.GetCurrentThreadId()};Win32Api.MiniDumpWriteDump(Win32Api.GetCurrentProcess(), Win32Api.GetCurrentProcessId(),fileStream.SafeFileHandle.DangerousGetHandle(), full ? Win32Api.MINIDUMP_TYPE.MiniDumpWithFullMemory : Win32Api.MINIDUMP_TYPE.MiniDumpNormal,ref info, IntPtr.Zero, IntPtr.Zero);fileStream.Close();}//--------------------------------------------------------------------------------------------------}
}
整段代码的作用是实现了一个崩溃处理器,用于捕获应用程序中的未处理异常,并进行相应的处理:
-
初始化方法
Init
用于设置崩溃转储目录,并注册应用程序域和调度程序未捕获异常的处理事件。 -
处理未捕获异常的方法
_CurrentDomain_UnhandledException
和_Current_DispatcherUnhandledException
。 -
_UnhandledException
方法用于处理未捕获的异常,当发生未捕获的异常时,弹出提示框询问用户是否希望保存当前打开的文档,并生成两个崩溃转储文件。 -
_SaveDocuments
方法用于保存当前打开文档。 -
_Dump
方法用于生成崩溃转储文件。
1.macad-application-windowscliboard
using System.IO;
using Macad.Core;namespace Macad.Window
{// WindowsClipboard 类继承自 Clipboard 抽象类,用于处理 Windows 平台的剪贴板操作public sealed class WindowsClipboard : Clipboard{// 构造函数WindowsClipboard(){}//--------------------------------------------------------------------------------------------------// 检查剪贴板中是否包含指定格式的数据public override bool ContainsData(in string format){return System.Windows.Clipboard.ContainsData(format);}//--------------------------------------------------------------------------------------------------// 从剪贴板中获取指定格式的数据流public override MemoryStream GetDataStream(in string format){return System.Windows.Clipboard.GetData(format) as MemoryStream;}//--------------------------------------------------------------------------------------------------// 将数据设置到剪贴板中指定的格式public override void SetData(in string format, in MemoryStream data){System.Windows.Clipboard.SetData(format, data);}//--------------------------------------------------------------------------------------------------// 初始化 WindowsClipboard 实例public static void Init(){if(Current == null)Current = new WindowsClipboard();}//--------------------------------------------------------------------------------------------------}
}
1.macad-command-appcommands
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Threading;
using Macad.Common;
using Macad.Common.Interop;
using Macad.Core;
using Macad.Core.Topology;
using Macad.Interaction;
using Macad.Interaction.Dialogs;
using Macad.Presentation;namespace Macad.Window
{// 定义了一组应用程序命令public static class AppCommands{// 退出应用程序命令,关闭主窗口public static ActionCommand ExitApplication { get; } = new(() =>{Application.Current.MainWindow.Close();}){Header = () => "Exit Program" // 设置菜单显示文本};//--------------------------------------------------------------------------------------------------// 初始化应用程序,包括显示欢迎信息、创建新模型、检查更新等操作internal static RelayCommand InitApplication { get; } = new(() =>{Messages.Info("Welcome to Macad|3D."); // 显示欢迎信息DocumentCommands.CreateNewModel.Execute(); // 创建新模型// 检查更新if (!AppContext.IsInSandbox && VersionCheck.IsAutoCheckEnabled){Dispatcher.CurrentDispatcher.BeginInvoke(VersionCheck.BeginCheckForUpdate, DispatcherPriority.ApplicationIdle);}});//--------------------------------------------------------------------------------------------------// 运行启动命令,包括打开文件、运行脚本等操作internal static RelayCommand RunStartupCommands { get; } = new(() =>{var cmdArgs = AppContext.CommandLine;// 检查命令行选项以加载项目if (cmdArgs.HasPathToOpen && DocumentCommands.OpenFile.CanExecute(cmdArgs.PathToOpen)&& PathUtils.GetExtensionWithoutPoint(cmdArgs.PathToOpen).Equals(Model.FileExtension)){DocumentCommands.OpenFile.Execute(cmdArgs.PathToOpen);}// 如果没有加载文档,则创建一个新文档if (AppContext.Current.Document == null){DocumentCommands.CreateNewModel.Execute();}// 加载除模型以外的其他文件if (cmdArgs.HasPathToOpen && DocumentCommands.OpenFile.CanExecute(cmdArgs.PathToOpen)&& !PathUtils.GetExtensionWithoutPoint(cmdArgs.PathToOpen).Equals(Model.FileExtension)){Dispatcher.CurrentDispatcher.InvokeAsync(() => DocumentCommands.OpenFile.Execute(cmdArgs.PathToOpen), DispatcherPriority.Loaded);}// 检查命令行选项以运行脚本if (cmdArgs.HasScriptToRun){ToolboxCommands.RunScriptCommand.Execute(cmdArgs.ScriptToRun);}});//--------------------------------------------------------------------------------------------------// 准备关闭窗口,包括提示保存修改等操作public static RelayCommand<CancelEventArgs> PrepareWindowClose { get; } = new((e) =>{if (DocumentCommands.SaveAll.CanExecute()){var result = Dialogs.AskForSavingChanges(); // 提示用户保存修改switch (result){case TaskDialogResults.Cancel:e.Cancel = true;return;case TaskDialogResults.Yes:DocumentCommands.SaveAll.Execute(); // 执行保存操作e.Cancel = DocumentCommands.SaveAll.CanExecute();break;case TaskDialogResults.No:break;}}});//--------------------------------------------------------------------------------------------------// 显示关于对话框public static ActionCommand ShowAboutDialog { get; } = new(() =>{new AboutDialog{Owner = MainWindow.Current}.ShowDialog(); // 显示关于对话框}){Header = () => "About Macad|3D...", // 设置菜单显示文本Description = () => "Shows version and license information.", // 设置菜单项描述};//--------------------------------------------------------------------------------------------------// 显示图层编辑器public static ActionCommand ShowLayerEditor { get; } = new(() => MainWindow.Current?.Docking.ActivateToolAnchorable("Layers") ) // 激活图层编辑器{Header = () => "Layer Editor", // 设置菜单显示文本Description = () => "Opens the layer editor.", // 设置菜单项描述Icon = () => "Layer-Editor" // 设置菜单项图标};//--------------------------------------------------------------------------------------------------// 显示形状检查器public static ActionCommand ShowShapeInspector { get; } = new(() =>{MainWindow.Current?.Docking.ActivateToolAnchorable("ShapeInspector");}) // 激活形状检查器{Header = () => "Shape Inspector", // 设置菜单显示文本Description = () => "Opens the shape inspector.", // 设置菜单项描述Icon = () => "Tool-ShapeInspect" // 设置菜单项图标};//--------------------------------------------------------------------------------------------------// 重置窗口布局public static ActionCommand ResetWindowLayout { get; } = new(() =>{MainWindow.Current?.Docking.LoadWindowLayout("Default");}) // 加载默认窗口布局{Header = () => "Reset Window Layout", // 设置菜单显示文本Description = () => "Resets the window layout to the default layout.", // 设置菜单项描述Icon = () => "App-RestoreLayout" // 设置菜单项图标};//--------------------------------------------------------------------------------------------------// 显示帮助主题public static ActionCommand<string> ShowHelpTopic { get; } = new((topicId) =>{var version = Assembly.GetExecutingAssembly().GetName().Version;var url = $"https://macad3d.net/userguide/go/?version={version.Major}.{version.Minor}&guid={topicId}";Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });}) // 打开帮助主题链接{Header = (topicId) => "Show User Guide", // 设置菜单显示文本Description = (topicId) => "Open and browse the Macad|3D User Guide.", // 设置菜单项描述Icon = (topicId) => "App-UserGuide" // 设置菜单项图标};//--------------------------------------------------------------------------------------------------}
}
这段代码定义了一系列应用程序命令,用于处理用户界面中的各种操作,例如退出程序、打开文件、显示帮助等
1.macad-utils-commandline
using System;
using System.Reflection;
using Macad.Common;namespace Macad.Window
{// 命令行参数处理类public class CommandLine{// 要打开的文件路径public string PathToOpen { get; }// 是否存在要打开的文件路径public bool HasPathToOpen => !PathToOpen.IsNullOrEmpty();// 是否启用沙箱模式public bool EnableSandbox { get; }// 是否禁用欢迎对话框public bool NoWelcomeDialog { get; }// 要运行的脚本路径public string ScriptToRun { get; }// 是否存在要运行的脚本路径public bool HasScriptToRun => !ScriptToRun.IsNullOrEmpty();//--------------------------------------------------------------------------------------------------// 构造函数,解析命令行参数public CommandLine(string[] cmdArgs){foreach (var cmdarg in cmdArgs){if (cmdarg.StartsWith("-") | cmdarg.StartsWith("/")){string option, parameter;int splitPos = Math.Min(cmdarg.IndexOf('='), cmdarg.IndexOf(':'));if (splitPos > 1){option = cmdarg.Substring(1, splitPos-1).ToLower(); // 提取参数名称parameter = cmdarg.Substring(splitPos + 1); // 提取参数值}else{option = cmdarg.Substring(1).ToLower(); // 提取参数名称parameter = null; // 参数值为空}// 根据参数名称进行处理switch (option){case "sandbox":EnableSandbox = true; // 启用沙箱模式break;case "nowelcome":NoWelcomeDialog = true; // 禁用欢迎对话框break;case "runscript":ScriptToRun = parameter; // 设置要运行的脚本路径break;}}else{PathToOpen = cmdarg; // 设置要打开的文件路径}}}//--------------------------------------------------------------------------------------------------}
}
这段代码定义了一个命令行参数处理类 CommandLine
,用于解析传递给应用程序的命令行参数。它包含了处理命令行参数的方法,并提供了访问这些参数的属性
1.macad-utils-debugpipeserver
using System;
using System.Globalization;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using Macad.Common;
using Macad.Common.Interop;
using Macad.Common.Serialization;
using Macad.Core;
using Macad.Interaction.Editors.Shapes;
using Macad.Presentation;namespace Macad.Window
{// 调试管道服务器类,用于与外部调试器进行通信internal static class DebugPipeServer{#region Pipe Handlingstatic Thread _Thread;//--------------------------------------------------------------------------------------------------// 打开调试管道服务器internal static void Open(){if (_Thread != null)return;_Thread = new Thread(_ThreadProc);_Thread.Start();// 订阅应用程序退出事件App.Current.Exit += (sender, args) => _Close();}//--------------------------------------------------------------------------------------------------// 关闭调试管道服务器static void _Close(){if (_Thread == null)return;_Thread.Interrupt();_Thread = null;}//--------------------------------------------------------------------------------------------------// 线程处理函数static void _ThreadProc(object data){try{// 创建命名管道服务器using (var pipeServer = new NamedPipeServerStream("MacadDebug", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous)){pipeServer.WaitForConnection();var buffer = new byte[64];var sb = new StringBuilder();while(true){var readBytes = pipeServer.Read(buffer, 0, 64);if (readBytes == 0)break;// 读取并处理消息sb.Append(Encoding.UTF8.GetString(buffer, 0, readBytes));if (pipeServer.IsMessageComplete){var answer = _OnMessageReceived(sb.ToString());if(answer != null)pipeServer.Write(answer, 0, answer.Length);sb.Clear();}};}}catch (ThreadInterruptedException){// 优雅地关闭线程}catch (Exception e){// 在UI线程中显示异常信息Application.Current.Dispatcher.Invoke(() => Messages.Exception("An exception occured in the debug pipe stream thread.", e));}}//--------------------------------------------------------------------------------------------------// 处理接收到的消息static byte[] _OnMessageReceived(string message){var code = message.Substring(0, 4);switch (code){case "GETV":var signature = message.Substring(4, 8);string value = Application.Current.Dispatcher.Invoke(() => _GetValue(message.Substring(12), out var obj ) ? Serializer.Serialize(obj) : "INVALID");return $"VALU{signature}{value}".ToUtf8Bytes();case "KEYD":var keyd = int.Parse(message.Substring(4), NumberStyles.HexNumber);return (_SendKeyEvent(keyd, false) ? $"DYEK{message.Substring(4)}" : "DYEK$Failed").ToUtf8Bytes();case "KEYU":var keyu = int.Parse(message.Substring(4), NumberStyles.HexNumber);return (_SendKeyEvent(keyu, true) ? $"UYEK{message.Substring(4)}" : "UYEK$Failed").ToUtf8Bytes();}return null;}//--------------------------------------------------------------------------------------------------#endregion#region Value Query// 获取对象的值static bool _GetValue(string path, out object obj){// 根据路径查找对象的值obj = null;string[] parts;// 是否为方法调用?var firstPar = path.IndexOf('(');if (firstPar > 0){parts = path.Substring(0, firstPar).Split('.');parts[^1] = parts[^1] + path.Substring(firstPar);}else{parts = path.Split('.');if (parts.Length == 0)return false;}if (!_FindRootObject(ref obj, parts[0]))return false;foreach (var part in parts.Skip(1)){if (!_FindValue(ref obj, part))return false;}return true;}//--------------------------------------------------------------------------------------------------// 查找根对象static bool _FindRootObject(ref object obj, string memberName){if (memberName.StartsWith("!")){if (!Guid.TryParse(memberName.Substring(1), out var guid))return false;obj = AppContext.Current?.Document?.FindInstance(guid);return true;}switch (memberName){case "$Context":obj = AppContext.Current;return true;case "$Selected":obj = AppContext.Current?.WorkspaceController?.Selection?.SelectedEntities?.FirstOrDefault();return true;case "$Tool":obj = AppContext.Current?.WorkspaceController?.CurrentTool;return true;case "$Sketch":obj = (AppContext.Current?.WorkspaceController?.CurrentTool as SketchEditorTool)?.Sketch;return true;}return false;}//--------------------------------------------------------------------------------------------------// 查找对象的属性值或方法返回值static bool _FindValue(ref object obj, string memberName){if (obj == null)return false;if (memberName.StartsWith('[') && memberName.EndsWith(']')){return _FindIndexedPropertyValue(ref obj, memberName);}if (memberName.EndsWith(')')){return _FindMethodValue(ref obj, memberName);}// 获取属性值var propInfo = obj.GetType().GetProperty(memberName);if (propInfo == null)return false;obj = propInfo.GetValue(obj);return true;}//--------------------------------------------------------------------------------------------------// 查找方法的返回值static bool _FindMethodValue(ref object obj, string memberName){int first = memberName.IndexOf('(');string paramStr = memberName.Substring(first + 1, memberName.Length - first - 2).Trim();int paramCount = paramStr.Length > 0 ? 1 : 0;string methodName = memberName.Substring(0, first);var methodInfo = obj.GetType().GetMethods().FirstOrDefault(mi => mi.Name == methodName && mi.GetParameters().Length == paramCount);if (methodInfo == null)return false;object param1 = null;if (paramCount == 1 && !_GetValue(paramStr, out param1))return false;obj = methodInfo.Invoke(obj, new[] {param1});return true;}//--------------------------------------------------------------------------------------------------// 查找对象的索引器属性值static bool _FindIndexedPropertyValue(ref object obj, string memberName){var indexerPropInfo = obj.GetType().GetProperties().FirstOrDefault(pi => pi.GetIndexParameters().Length > 0);if (indexerPropInfo == null)return false;var indexStr = memberName.Substring(1, memberName.Length - 2);obj = int.TryParse(indexStr, out var index)? indexerPropInfo.GetValue(obj, new object[] {index}): indexerPropInfo.GetValue(obj, new object[] {indexStr});return true;}//--------------------------------------------------------------------------------------------------#endregion#region Keyboard Input// 发送键盘事件static bool _SendKeyEvent(int key, bool isUp){bool success = false;int vkey = key & 0xff;Application.Current.Dispatcher.Invoke(() =>{var sourceElement = Keyboard.PrimaryDevice.ActiveSource;var focusElement = Keyboard.PrimaryDevice.FocusedElement;if (focusElement == null || sourceElement == null)return;ModifierKeys modifiers = ModifierKeys.None;if ((key & 0x0100) > 0) modifiers = modifiers.Added(ModifierKeys.Shift);if ((key & 0x0200) > 0) modifiers = modifiers.Added(ModifierKeys.Control);if ((key & 0x0400) > 0) modifiers = modifiers.Added(ModifierKeys.Alt);InputHelper.SimulatedModifiers = modifiers;var tunnelArgs = new KeyEventArgs(Keyboard.PrimaryDevice, sourceElement, 0, KeyInterop.KeyFromVirtualKey(vkey));tunnelArgs.RoutedEvent = isUp ? Keyboard.PreviewKeyUpEvent : Keyboard.PreviewKeyDownEvent;focusElement.RaiseEvent(tunnelArgs);if (!tunnelArgs.Handled){var bubbleArgs = new KeyEventArgs(Keyboard.PrimaryDevice, sourceElement, 0, KeyInterop.KeyFromVirtualKey(vkey));bubbleArgs.RoutedEvent = isUp ? Keyboard.KeyUpEvent : Keyboard.KeyDownEvent;focusElement.RaiseEvent(bubbleArgs);if (!bubbleArgs.Handled && !isUp){var sb = new StringBuilder();byte[] bKeyState = new byte[255];if ((key & 0x0100) > 0) bKeyState[0x10] = 0x80;if ((key & 0x0200) > 0) bKeyState[0x11] = 0x80;if ((key & 0x0400) > 0) bKeyState[0x12] = 0x80;uint lScanCode = Win32Api.MapVirtualKey((uint)(vkey), Win32Api.MapVirtualKeyMapTypes.MAPVK_VK_TO_VSC);Win32Api.ToUnicode((uint)(vkey), lScanCode, bKeyState, sb, 5, 0);TextCompositionManager.StartComposition(new TextComposition(InputManager.Current, Keyboard.FocusedElement, sb.ToString()));}}InputHelper.SimulatedModifiers = ModifierKeys.None;success = true;});return success;}//--------------------------------------------------------------------------------------------------#endregion}
}
这段代码实现了调试管道服务器,用于与外部调试器进行通信。它包括了以下功能:
- 打开和关闭调试管道服务器。
- 处理接收到的消息,包括获取对象的值和发送键盘事件。
- 在UI线程中处理消息,以便与WPF元素交互。
- 处理不同类型的消息,如获取值和发送键盘事件。
- 在异常情况下,通过UI线程显示异常信息
1.macad-utils-vertioncheck
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Windows;
using Macad.Common;
using Macad.Common.Serialization;
using Macad.Core;namespace Macad.Window
{#region Model// 存储版本检查信息的类[SerializeType]internal class VersionCheckInfo{[SerializeMember]public DateTime OnlineCheck { get; set; } = DateTime.MinValue;[SerializeMember]public string LocalVersion { get; set; } = "0.0.0.0";[SerializeMember]public bool UpdateAvailable { get; set; } = false;[SerializeMember]public string UpdateVersion { get; set; } = "0.0.0.0";[SerializeMember]public string UpdateUrl { get; set; } = "";}//--------------------------------------------------------------------------------------------------// 版本检查参数设置类public sealed class VersionCheckParameterSet : OverridableParameterSet{public bool CheckForUpdate { get => GetValue<bool>(); set => SetValue(value); }public uint CheckIntervalDays { get => GetValue<uint>(); set => SetValue(value); }//--------------------------------------------------------------------------------------------------// 构造函数,设置默认值public VersionCheckParameterSet(){SetDefaultValue(nameof(CheckForUpdate), true);SetDefaultValue(nameof(CheckIntervalDays), (uint)7);}}//--------------------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------------------#endregion#region VersionCheckRequest// 版本检查请求接口internal interface IVersionCheckRequest{void BeginRequest(Action<Dictionary<string, string>> callback);}//--------------------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------------------// 版本检查Web请求类internal class VersionCheckWebRequest : IVersionCheckRequest{readonly string _Url;readonly Version _UserAgentVersion;Action<Dictionary<string, string>> _Callback;//--------------------------------------------------------------------------------------------------// 构造函数public VersionCheckWebRequest(string url, Version userAgentVersion){_Url = url;_UserAgentVersion = userAgentVersion;}//--------------------------------------------------------------------------------------------------// 开始请求public void BeginRequest(Action<Dictionary<string, string>> callback){_Callback = callback;// 在后台线程中执行请求Thread t = new Thread(_ThreadEntry){IsBackground = true,};t.Start();}//--------------------------------------------------------------------------------------------------// 线程入口函数void _ThreadEntry(object obj){using HttpClient httpClient = new();httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd($"Macad3D/{_UserAgentVersion.Major}.{_UserAgentVersion.Minor}");try{var task = httpClient.GetStringAsync(_Url);if (!task.Wait(new TimeSpan(0, 0, 30))){Debug.Print("--- Version check failed: Timeout on server connection.");}string responseText = task.Result;if (responseText.Length >= 1){var serializer = Serializer.GetSerializer(typeof(Dictionary<string, string>));var reader = new Reader(responseText);if (serializer.Read(reader, null, null) is Dictionary<string, string> dict){_Callback.Invoke(dict);}}}catch (Exception){Debug.Print("--- Version check failed: Retrieving version information from server failed.");}}}//--------------------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------------------#endregion#region VersionCheck// 版本检查类internal class VersionCheck{public const string GetVersionUrl = "https://macad3d.net/versioninfo";//--------------------------------------------------------------------------------------------------// 获取是否启用自动检查更新public static bool IsAutoCheckEnabled{get{var parameterSet = CoreContext.Current.Parameters.Get<VersionCheckParameterSet>();return parameterSet.CheckForUpdate;}set{var parameterSet = CoreContext.Current.Parameters.Get<VersionCheckParameterSet>();parameterSet.CheckForUpdate = value;}}//--------------------------------------------------------------------------------------------------// 开始检查更新public static void BeginCheckForUpdate(){var vc = new VersionCheck();if (vc._Info.UpdateAvailable){Application.Current.Dispatcher.Invoke(() =>{vc.RaiseUpdateAvailable();});return;}vc.BeginCheckForUpdate(false, new VersionCheckWebRequest(GetVersionUrl, vc._LocalVersion));}//--------------------------------------------------------------------------------------------------// 重置更新状态public static void ResetAvailability(){var info = CoreContext.Current.LoadLocalSettings<VersionCheckInfo>("LastVersionCheck") ?? new VersionCheckInfo();info.UpdateAvailable = false;CoreContext.Current.SaveLocalSettings("LastVersionCheck", info);}//--------------------------------------------------------------------------------------------------// 更新可用事件public static event EventHandler<VersionCheckInfo> UpdateAvailable;void RaiseUpdateAvailable(){UpdateAvailable?.Invoke(this, _Info);}//--------------------------------------------------------------------------------------------------VersionCheckInfo _Info;readonly Version _LocalVersion;//--------------------------------------------------------------------------------------------------// 构造函数public VersionCheck(){_LocalVersion = Assembly.GetExecutingAssembly().GetName().Version;_Info = CoreContext.Current.LoadLocalSettings<VersionCheckInfo>("LastVersionCheck") ?? new VersionCheckInfo();}//--------------------------------------------------------------------------------------------------// 开始检查更新public bool BeginCheckForUpdate(bool force, IVersionCheckRequest request){if (!force && !_IsUpdateCheckNeeded()){return false;}_Info.OnlineCheck = DateTime.Now;_Info.LocalVersion = _LocalVersion.ToString();CoreContext.Current.SaveLocalSettings("LastVersionCheck", _Info);request?.BeginRequest(_OnRequested);return true;}//--------------------------------------------------------------------------------------------------// 处理请求后的回调void _OnRequested(Dictionary<string, string> dictionary){if (dictionary.TryGetValue("Version", out string version)&& dictionary.TryGetValue("Url", out string url)){// 检查是否已经发布新版本if (_Compare(new Version(version), new Version(_Info.UpdateVersion)) != 0){_Info.UpdateAvailable = _Compare(new Version(version), new Version(_Info.LocalVersion)) == 1;_Info.UpdateVersion = version;_Info.UpdateUrl = url;CoreContext.Current.SaveLocalSettings("LastVersionCheck", _Info);}// 通知用户更新可用if (_Info.UpdateAvailable){Application.Current?.Dispatcher.Invoke(() =>{RaiseUpdateAvailable();});}}}//--------------------------------------------------------------------------------------------------// 检查是否需要进行更新检查bool _IsUpdateCheckNeeded(){// 如果有新版本,强制进行一次更新var lastLocalVersion = new Version(_Info.LocalVersion);if (_Compare(lastLocalVersion, _LocalVersion) != 0){return true;}var parameterSet = CoreContext.Current.Parameters.Get<VersionCheckParameterSet>();// 如果距离上次检查超过 n 天,则需要更新检查TimeSpan span = DateTime.Now - _Info.OnlineCheck;if (span.Days > (int)parameterSet.CheckIntervalDays){return true;}return false;}//--------------------------------------------------------------------------------------------------// 版本比较函数int _Compare(Version v1, Version v2){if (v1.Major != v2.Major)if (v1.Major > v2.Major)return 1;elsereturn -1;if (v1.Minor != v2.Minor)if (v1.Minor > v2.Minor)return 1;elsereturn -1;if (v1.Build != v2.Build)if (v1.Build > v2.Build)return 1;elsereturn -1;if (v1.Revision != v2.Revision)if (v1.Revision < v2.Revision)return 1;elsereturn -1;return 0; }}#endregion
}
该段代码主要实现了版本检查功能,包括以下几个部分:
-
Model:定义了用于存储版本检查信息的类
VersionCheckInfo
和版本检查参数设置的类VersionCheckParameterSet
。 -
VersionCheckRequest:定义了版本检查请求的接口
IVersionCheckRequest
,以及基于 Web 请求的版本检查类VersionCheckWebRequest
。这些类用于发起与服务器的通信,获取最新版本信息。 -
VersionCheck:实现了版本检查的主要逻辑。它包括了检查是否启用自动检查更新、开始检查更新、重置更新状态以及比较版本号的功能。
1.macad-utils-windowplacement
using System.Runtime.InteropServices;
using System.Windows.Interop;
using Macad.Common.Interop;
using Macad.Common.Serialization;namespace Macad.Window
{// 窗口位置信息类,实现了 ISerializeValue 接口[SerializeType]public sealed class WindowPlacement : ISerializeValue{// 窗口位置信息结构体[SerializeMember]Win32Api.WINDOWPLACEMENT Placement{get { return _Placement; }set { _Placement = value; }}Win32Api.WINDOWPLACEMENT _Placement;//--------------------------------------------------------------------------------------------------// 获取窗口位置信息bool _GetPlacement(System.Windows.Window window){return Win32Api.GetWindowPlacement(new HandleRef(this, new WindowInteropHelper(window).Handle), out _Placement);}//--------------------------------------------------------------------------------------------------// 设置窗口位置信息bool _SetPlacement(System.Windows.Window window){_Placement.showCmd = _Placement.showCmd == Win32Api.SW_SHOWMINIMIZED ? Win32Api.SW_SHOWNORMAL : _Placement.showCmd;_Placement.flags = 0;return Win32Api.SetWindowPlacement(new HandleRef(this, new WindowInteropHelper(window).Handle), ref _Placement);}//--------------------------------------------------------------------------------------------------// 保存窗口位置信息到本地设置public static void SaveWindowPlacement(System.Windows.Window window, string name){var placement = new WindowPlacement();if (placement._GetPlacement(window))AppContext.Current.SaveLocalSettings(name, placement);}//--------------------------------------------------------------------------------------------------// 从本地设置加载窗口位置信息public static void LoadWindowPlacement(System.Windows.Window window, string name){var placement = AppContext.Current.LoadLocalSettings<WindowPlacement>(name);placement?._SetPlacement(window);}//--------------------------------------------------------------------------------------------------// 静态成员,用于序列化窗口位置信息static readonly ISerializer _PlacementSerializer;// 静态构造函数,初始化窗口位置信息序列化器static WindowPlacement(){_PlacementSerializer = Serializer.GetSerializer(typeof(Win32Api.WINDOWPLACEMENT)); }// 实现 ISerializeValue 接口的 Write 方法,将窗口位置信息序列化public bool Write(Writer writer, SerializationContext context){return _PlacementSerializer.Write(writer, _Placement, context);}// 实现 ISerializeValue 接口的 Read 方法,从序列化数据中读取窗口位置信息public bool Read(Reader reader, SerializationContext context){var obj = _PlacementSerializer.Read(reader, null, context);if (obj == null)return false;_Placement = (Win32Api.WINDOWPLACEMENT) obj;return true;}//--------------------------------------------------------------------------------------------------}
}
该段代码定义了用于保存和加载窗口位置信息的 WindowPlacement
类。其主要功能包括:
-
定义窗口位置信息结构体:包含了窗口的状态、位置和显示方式等信息。
-
获取和设置窗口位置信息:通过调用 Win32 API 实现了获取和设置窗口位置信息的功能。
-
保存和加载窗口位置信息:提供了静态方法
SaveWindowPlacement
和LoadWindowPlacement
,用于将窗口位置信息保存到本地设置和从本地设置加载窗口位置信息。 -
实现序列化接口:实现了
ISerializeValue
接口,使得WindowPlacement
类的对象可以被序列化和反序列化,以便保存和加载窗口位置信息。
这篇关于macad3d解析macad—application,commands,utils的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!