Merge branch 'net6' into net462
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user