Merge branch 'net6' into net462

This commit is contained in:
doudou0720
2026-05-02 10:16:15 +08:00
37 changed files with 1933 additions and 603 deletions
+4 -1
View File
@@ -7,7 +7,10 @@ namespace Ink_Canvas.Helpers
{
internal class AnimationsHelper
{
private static UIElement ResolveAnimationTarget(UIElement element) => element;
private static UIElement ResolveAnimationTarget(UIElement element)
{
return element;
}
public static void ShowWithFadeIn(UIElement element, double duration = 0.15)
{
+12 -22
View File
@@ -1509,32 +1509,22 @@ namespace Ink_Canvas.Helpers
int.TryParse(remoteParts[2], out int remoteBuild) &&
int.TryParse(remoteParts[3], out int remoteRevision))
{
// 计算代数差异:主版本号差异 * 1000 + 次版本号差异 * 100 + 构建号差异 * 10 + 修订号差异
int majorDiff = remoteMajor - localMajor;
int minorDiff = remoteMinor - localMinor;
int buildDiff = remoteBuild - localBuild;
int revisionDiff = remoteRevision - localRevision;
var localSemver = new Version(localMajor, localMinor, localBuild, localRevision);
var remoteSemver = new Version(remoteMajor, remoteMinor, remoteBuild, remoteRevision);
int direction = remoteSemver.CompareTo(localSemver);
if (direction == 0) return 0;
int sign = direction > 0 ? 1 : -1;
// 如果主版本号不同,则代数差异很大
if (majorDiff != 0)
{
return majorDiff * 1000 + minorDiff * 100 + buildDiff * 10 + revisionDiff;
}
int majorDiff = Math.Abs(remoteMajor - localMajor);
if (majorDiff != 0) return sign * (majorDiff * 1000);
// 如果次版本号不同,则代数差异中等
if (minorDiff != 0)
{
return minorDiff * 100 + buildDiff * 10 + revisionDiff;
}
int minorDiff = Math.Abs(remoteMinor - localMinor);
if (minorDiff != 0) return sign * (minorDiff * 100);
// 如果构建号不同,则代数差异较小
if (buildDiff != 0)
{
return buildDiff * 10 + revisionDiff;
}
int buildDiff = Math.Abs(remoteBuild - localBuild);
if (buildDiff != 0) return sign * (buildDiff * 10);
// 只有修订号不同,代数差异最小
return revisionDiff;
return sign * Math.Abs(remoteRevision - localRevision);
}
return 0;
+1 -1
View File
@@ -32,7 +32,7 @@ namespace Ink_Canvas.Helpers
private bool _available;
private static string HelperExePath =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "InkCanvasForClass.IACoreHelper.exe");
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "InkCanvas.IACoreHelper.exe");
private string PipeName =>
string.Format("ICC_IACoreHelper_{0}", Process.GetCurrentProcess().Id);
+15 -13
View File
@@ -718,7 +718,7 @@ namespace Ink_Canvas.Helpers
try
{
if (!IsConnected || !IsInSlideShow || PPTApplication == null)
if (!IsConnected || PPTApplication == null)
return;
if (!Marshal.IsComObject(PPTApplication))
@@ -733,7 +733,7 @@ namespace Ink_Canvas.Helpers
if (slideShowWindow == null)
return;
SlideShowBegin?.Invoke(slideShowWindow);
OnSlideShowBegin(slideShowWindow);
}
catch (COMException comEx)
{
@@ -818,17 +818,10 @@ namespace Ink_Canvas.Helpers
{
UnbindEvents();
if (activePresentation != null)
{
try
{
PresentationClose?.Invoke(activePresentation);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"触发PresentationClose事件失败: {ex.Message}", LogHelper.LogType.Warning);
}
}
// 注意:PresentationClose 只应在真正的关闭(OnPresentationBeforeClose)中抛出。
// DisconnectFromPPT 会被重绑、热重载、瞬时 COM 失效恢复等内部路径调用,
// 此时演示文稿仍处于打开状态,抛 PresentationClose 会让上层错误地清空缓存,
// 而后续重连到同一个演示文稿也不会补发 PresentationOpen。
SafeReleaseComObject(slideShowWindow, "_pptSlideShowWindow");
SafeReleaseComObject(activePresentation, "_pptActivePresentation");
@@ -1217,6 +1210,15 @@ namespace Ink_Canvas.Helpers
{
try
{
try
{
PresentationClose?.Invoke(pres ?? _pptActivePresentation);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"触发PresentationClose事件失败: {ex.Message}", LogHelper.LogType.Warning);
}
if (_bindingEvents && PPTApplication != null)
{
try
+23 -1
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
@@ -12,6 +13,14 @@ namespace Ink_Canvas.Helpers
{
private const string DefaultDateTime = "yyyy-MM-dd HH-mm-ss-fff";
// Windows 保留设备名(不区分大小写)。这些名称无论是否带扩展名,CreateFile 都会失败。
private static readonly HashSet<string> ReservedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
};
public static string Render(string template, SaveFileNameContext ctx)
{
if (ctx == null) ctx = new SaveFileNameContext();
@@ -51,7 +60,20 @@ namespace Ink_Canvas.Helpers
{
name = name.Replace(c, '_');
}
return name.Trim();
// Windows 禁止文件名以点号或空格结尾(会被静默截断甚至创建失败)。
name = name.Trim().TrimEnd('.', ' ');
if (string.IsNullOrEmpty(name)) return name;
// 保留设备名:比较时忽略扩展名,命中则加下划线前缀以规避。
var stem = Path.GetFileNameWithoutExtension(name);
if (!string.IsNullOrEmpty(stem) && ReservedNames.Contains(stem))
{
name = "_" + name;
}
return name;
}
}
+43 -5
View File
@@ -294,7 +294,13 @@ namespace Ink_Canvas.Helpers
{
try
{
if (!GetUserPrimaryToken(out IntPtr userToken))
if (!GetCurrentProcessSessionId(out uint sessionId))
{
LogHelper.WriteLogToFile($"UIAccess | 获取当前会话 ID 失败 (LastError={Marshal.GetLastWin32Error()})", LogHelper.LogType.Error);
return false;
}
if (!GetUserPrimaryToken(sessionId, out IntPtr userToken))
{
LogHelper.WriteLogToFile($"UIAccess | 获取用户令牌失败 (LastError={Marshal.GetLastWin32Error()})", LogHelper.LogType.Error);
return false;
@@ -506,11 +512,31 @@ namespace Ink_Canvas.Helpers
finally { CloseHandle(hProc); }
}
private static bool GetCurrentProcessSessionId(out uint sessionId)
{
sessionId = 0;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out IntPtr hSelfQuery))
return false;
try
{
IntPtr sesBuf = Marshal.AllocHGlobal(sizeof(uint));
try
{
if (!GetTokenInformation(hSelfQuery, TokenSessionId, sesBuf, sizeof(uint), out _))
return false;
sessionId = (uint)Marshal.ReadInt32(sesBuf);
return true;
}
finally { Marshal.FreeHGlobal(sesBuf); }
}
finally { CloseHandle(hSelfQuery); }
}
/// <summary>
/// 从 explorer.exe / ctfmon.exe 取得普通用户(非提升)令牌的主令牌副本,用于降权启动。
/// 仅当当前进程为管理员时才能成功。
/// </summary>
private static bool GetUserPrimaryToken(out IntPtr userToken)
private static bool GetUserPrimaryToken(uint sessionId, out IntPtr userToken)
{
userToken = IntPtr.Zero;
@@ -528,9 +554,9 @@ namespace Ink_Canvas.Helpers
{
if (string.Equals(pe.szExeFile, name, StringComparison.OrdinalIgnoreCase))
{
if (TryDuplicateUserPrimaryToken(pe.th32ProcessID, out userToken))
if (TryDuplicateUserPrimaryToken(pe.th32ProcessID, sessionId, out userToken))
{
LogHelper.WriteLogToFile($"UIAccess | 已从 {name} (PID={pe.th32ProcessID}) 取得用户令牌");
LogHelper.WriteLogToFile($"UIAccess | 已从 {name} (PID={pe.th32ProcessID}, Session={sessionId}) 取得用户令牌");
return true;
}
}
@@ -543,7 +569,7 @@ namespace Ink_Canvas.Helpers
return false;
}
private static bool TryDuplicateUserPrimaryToken(uint pid, out IntPtr dupToken)
private static bool TryDuplicateUserPrimaryToken(uint pid, uint sessionId, out IntPtr dupToken)
{
dupToken = IntPtr.Zero;
@@ -557,6 +583,18 @@ namespace Ink_Canvas.Helpers
try
{
// 会话隔离:拒绝来自其他登录会话(RDP / 终端服务 / 快速用户切换)的令牌,
// 否则降权后进程会落到错误用户的桌面上下文中。
IntPtr sesBuf = Marshal.AllocHGlobal(sizeof(uint));
try
{
if (!GetTokenInformation(hToken, TokenSessionId, sesBuf, sizeof(uint), out _))
return false;
if ((uint)Marshal.ReadInt32(sesBuf) != sessionId)
return false;
}
finally { Marshal.FreeHGlobal(sesBuf); }
// 仅接受非提升令牌(否则降权失败)
IntPtr elevBuf = Marshal.AllocHGlobal(sizeof(int));
try