2.10.8
This commit is contained in:
@@ -13,13 +13,13 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.10.7" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.10.7." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const VersionBaseName As String = "2.10.8" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.10.8." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
||||
#If BETA Then
|
||||
Public Const VersionCode As Integer = 367 'Release
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 368 'Snapshot
|
||||
Public Const VersionCode As Integer = 370 'Snapshot
|
||||
#End If
|
||||
'自动生成的版本信息
|
||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||
@@ -765,17 +765,6 @@ Public Module ModBase
|
||||
Return FilePath
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。
|
||||
''' </summary>
|
||||
Public Function GetFileNameWithoutExtentionFromPath(FilePath As String) As String
|
||||
Dim Name As String = GetFileNameFromPath(FilePath)
|
||||
If Name.Contains(".") Then
|
||||
Return Name.Substring(0, Name.LastIndexOfF("."))
|
||||
Else
|
||||
Return Name
|
||||
End If
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 从文件夹路径获取文件夹名。
|
||||
''' </summary>
|
||||
Public Function GetFolderNameFromPath(FolderPath As String) As String
|
||||
@@ -791,8 +780,8 @@ Public Module ModBase
|
||||
Public Sub CopyFile(FromPath As String, ToPath As String)
|
||||
Try
|
||||
'还原文件路径
|
||||
FromPath = ShortenPath(If(FromPath.Contains(":\"), FromPath, Path & FromPath))
|
||||
ToPath = ShortenPath(If(ToPath.Contains(":\"), ToPath, Path & ToPath))
|
||||
FromPath = If(FromPath.Contains(":\"), FromPath, Path & FromPath)
|
||||
ToPath = If(ToPath.Contains(":\"), ToPath, Path & ToPath)
|
||||
'如果复制同一个文件则跳过
|
||||
If FromPath = ToPath Then Return
|
||||
'确保目录存在
|
||||
@@ -861,7 +850,7 @@ Public Module ModBase
|
||||
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
|
||||
Public Sub WriteFile(FilePath As String, Text As String, Optional Append As Boolean = False, Optional Encoding As Encoding = Nothing)
|
||||
'处理相对路径
|
||||
FilePath = ShortenPath(If(FilePath.Contains(":\"), FilePath, Path & FilePath))
|
||||
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
|
||||
'确保目录存在
|
||||
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
|
||||
'写入文件
|
||||
@@ -886,7 +875,7 @@ Public Module ModBase
|
||||
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
|
||||
Public Sub WriteFile(FilePath As String, Content As Byte(), Optional Append As Boolean = False)
|
||||
'处理相对路径
|
||||
FilePath = ShortenPath(If(FilePath.Contains(":\"), FilePath, Path & FilePath))
|
||||
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
|
||||
'确保目录存在
|
||||
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
|
||||
'写入文件
|
||||
@@ -1294,11 +1283,11 @@ Re:
|
||||
''' </summary>
|
||||
Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing,
|
||||
Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
|
||||
Directory.CreateDirectory(ShortenPath(DestDirectory))
|
||||
Directory.CreateDirectory(DestDirectory)
|
||||
If CompressFilePath.EndsWithF(".gz", True) Then
|
||||
'以 gz 方式解压
|
||||
Dim stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.ReadWrite), CompressionMode.Decompress)
|
||||
Dim decompressedFile As New FileStream(ShortenPath(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", "")), FileMode.OpenOrCreate, FileAccess.Write)
|
||||
Dim decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), FileMode.OpenOrCreate, FileAccess.Write)
|
||||
Dim data As Integer = stream.ReadByte()
|
||||
While data <> -1
|
||||
decompressedFile.WriteByte(data)
|
||||
@@ -1312,13 +1301,10 @@ Re:
|
||||
Dim TotalCount As Long = Archive.Entries.Count
|
||||
For Each Entry As ZipArchiveEntry In Archive.Entries
|
||||
If ProgressIncrementHandler IsNot Nothing AndAlso TotalCount > 0 Then ProgressIncrementHandler(1 / TotalCount)
|
||||
Dim DestinationPath As String = ShortenPath(IO.Path.Combine(DestDirectory, Entry.FullName))
|
||||
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
|
||||
Continue For '不创建空文件夹
|
||||
Else
|
||||
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
|
||||
Entry.ExtractToFile(DestinationPath, True)
|
||||
End If
|
||||
Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
|
||||
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then Continue For '不创建空文件夹
|
||||
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
|
||||
Entry.ExtractToFile(DestinationPath, True)
|
||||
Next
|
||||
End Using
|
||||
End If
|
||||
@@ -1342,6 +1328,7 @@ Re:
|
||||
Try
|
||||
Files = Directory.GetFiles(Path)
|
||||
Catch ex As DirectoryNotFoundException '#4549
|
||||
If Not Directory.Exists(Path) Then Return 0 '可能已被其他线程删除
|
||||
Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer)
|
||||
Directory.Delete(Path)
|
||||
Return 0
|
||||
@@ -1406,7 +1393,7 @@ RetryDir:
|
||||
''' 遍历文件夹中的所有文件。
|
||||
''' </summary>
|
||||
Public Function EnumerateFiles(Directory As String) As IEnumerable(Of FileInfo)
|
||||
Dim Info As New DirectoryInfo(ShortenPath(Directory))
|
||||
Dim Info As New DirectoryInfo(Directory)
|
||||
If Not Info.Exists Then Return New List(Of FileInfo)
|
||||
Return Info.EnumerateFiles("*", SearchOption.AllDirectories)
|
||||
End Function
|
||||
@@ -1414,13 +1401,15 @@ RetryDir:
|
||||
''' <summary>
|
||||
''' 若路径长度大于指定值,则将长路径转换为短路径。
|
||||
''' </summary>
|
||||
Public Function ShortenPath(LongPath As String, Optional ShortenThreshold As Integer = 247) As String
|
||||
If LongPath.Length <= ShortenThreshold Then Return LongPath
|
||||
Public Function ShortenPath(LongPath As String) As String
|
||||
If LongPath.Length <= 200 OrElse LongPath.StartsWithF("http", True) Then Return LongPath
|
||||
If Not Directory.Exists(LongPath) AndAlso Not File.Exists(LongPath) Then Return LongPath
|
||||
Dim ShortPath As New StringBuilder(260)
|
||||
GetShortPathName(LongPath, ShortPath, 260)
|
||||
Return ShortPath.ToString
|
||||
ShortenPath = ShortPath.ToString
|
||||
If String.IsNullOrEmpty(ShortenPath) Then Return LongPath
|
||||
End Function
|
||||
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As Integer) As Integer
|
||||
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (lpszLongPath As String, lpszShortPath As StringBuilder, cchBuffer As Integer) As Integer
|
||||
|
||||
#End Region
|
||||
|
||||
@@ -1500,7 +1489,7 @@ RetryDir:
|
||||
If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then
|
||||
Return "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。"
|
||||
ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then
|
||||
Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行,或将目标从 C 盘或桌面挪到其他硬盘。"
|
||||
Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行。"
|
||||
ElseIf TypeOf InnerEx Is OutOfMemoryException Then
|
||||
Return "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。"
|
||||
ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then
|
||||
@@ -2027,8 +2016,8 @@ RetryDir:
|
||||
'构造函数
|
||||
Public Sub New()
|
||||
End Sub
|
||||
Public Sub New(data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
|
||||
For Each DataItem In data
|
||||
Public Sub New(Data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
|
||||
For Each DataItem In Data
|
||||
_Dictionary.Add(DataItem.Key, DataItem.Value)
|
||||
Next
|
||||
End Sub
|
||||
@@ -2184,7 +2173,7 @@ RetryDir:
|
||||
''' 返回程序的返回代码,如果运行失败将抛出异常。
|
||||
''' </summary>
|
||||
Public Function RunAsAdmin(Argument As String) As Integer
|
||||
Dim NewProcess = Process.Start(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
|
||||
Dim NewProcess = StartProcess(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
|
||||
NewProcess.WaitForExit()
|
||||
Return NewProcess.ExitCode
|
||||
End Function
|
||||
@@ -2343,46 +2332,21 @@ NextElement:
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' 前台运行文件。
|
||||
''' 启动进程并返回进程实例,若失败则抛出异常。
|
||||
''' 会自动进行长路径处理。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
|
||||
Try
|
||||
FileName = ShortenPath(FileName)
|
||||
Using Program As New Process
|
||||
Program.StartInfo.Arguments = Arguments
|
||||
Program.StartInfo.FileName = FileName
|
||||
Log("[System] 执行外部命令:" & FileName & " " & Arguments)
|
||||
Program.Start()
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Log(ex, "打开文件或程序失败:" & FileName, LogLevel.Msgbox)
|
||||
End Try
|
||||
End Sub
|
||||
Public Function StartProcess(FileName As String, Optional Arguments As String = "") As Process
|
||||
Return StartProcess(New ProcessStartInfo With {.FileName = FileName, .Arguments = Arguments})
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 前台运行文件并返回返回值。
|
||||
''' 启动进程并返回进程实例,若失败则抛出异常。
|
||||
''' 会自动进行长路径处理。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。</param>
|
||||
Public Function ShellAndGetExitCode(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000) As ProcessReturnValues
|
||||
Try
|
||||
Using Program As New Process
|
||||
Program.StartInfo.Arguments = Arguments
|
||||
Program.StartInfo.FileName = FileName
|
||||
Log("[System] 执行外部命令并等待返回码:" & FileName & " " & Arguments)
|
||||
Program.Start()
|
||||
If Program.WaitForExit(Timeout) Then
|
||||
Return Program.ExitCode
|
||||
Else
|
||||
Return ProcessReturnValues.Timeout
|
||||
End If
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行命令失败:" & FileName, LogLevel.Msgbox)
|
||||
Return ProcessReturnValues.Fail
|
||||
End Try
|
||||
Public Function StartProcess(StartInfo As ProcessStartInfo) As Process
|
||||
StartInfo.FileName = ShortenPath(StartInfo.FileName)
|
||||
If Not String.IsNullOrEmpty(StartInfo.WorkingDirectory) Then StartInfo.WorkingDirectory = ShortenPath(StartInfo.WorkingDirectory)
|
||||
Log("[System] 启动进程:" & StartInfo.FileName & " " & StartInfo.Arguments)
|
||||
Return Process.Start(StartInfo)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 静默运行文件并返回输出流字符串。执行失败会抛出异常。
|
||||
@@ -2390,10 +2354,11 @@ NextElement:
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会抛出错误。</param>
|
||||
Public Function ShellAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000, Optional WorkingDirectory As String = Nothing) As String
|
||||
Public Function StartProcessAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000,
|
||||
Optional WorkingDirectory As String = Nothing) As String
|
||||
Dim Info = New ProcessStartInfo With {
|
||||
.Arguments = Arguments,
|
||||
.FileName = FileName,
|
||||
.FileName = ShortenPath(FileName),
|
||||
.UseShellExecute = False,
|
||||
.CreateNoWindow = True,
|
||||
.RedirectStandardError = True,
|
||||
@@ -2408,7 +2373,7 @@ NextElement:
|
||||
End If
|
||||
End If
|
||||
Log("[System] 执行外部命令并等待返回结果:" & FileName & " " & Arguments)
|
||||
Using Program As New Process() With {.StartInfo = Info}
|
||||
Using Program As New Process With {.StartInfo = Info}
|
||||
Program.Start()
|
||||
Dim Result As String = Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd
|
||||
Program.WaitForExit(Timeout)
|
||||
@@ -2510,17 +2475,14 @@ NextElement:
|
||||
''' <summary>
|
||||
''' 尝试从字典中获取某项,如果该项不存在,则返回默认值。
|
||||
''' </summary>
|
||||
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As Dictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
|
||||
If Dict.ContainsKey(Key) Then
|
||||
Return Dict(Key)
|
||||
Else
|
||||
Return DefaultValue
|
||||
End If
|
||||
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As IDictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
|
||||
Dim Result As TValue
|
||||
Return If(Dict.TryGetValue(Key, Result), Result, DefaultValue)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 将某项添加到以列表作为值的字典中。
|
||||
''' </summary>
|
||||
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As Dictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
|
||||
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As IDictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
|
||||
If Dict.ContainsKey(Key) Then
|
||||
Dict(Key).Add(Value)
|
||||
Else
|
||||
@@ -2568,7 +2530,7 @@ NextElement:
|
||||
Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
|
||||
End If
|
||||
Log("[System] 正在打开网页:" & Url)
|
||||
Process.Start(Url)
|
||||
StartProcess(Url)
|
||||
Catch ex As Exception
|
||||
Log(ex, "无法打开网页(" & Url & ")")
|
||||
ClipboardSet(Url, False)
|
||||
@@ -2582,12 +2544,12 @@ NextElement:
|
||||
''' </summary>
|
||||
Public Sub OpenExplorer(Location As String)
|
||||
Try
|
||||
Location = ShortenPath(Location.Replace("/", "\").Trim(" "c, """"c))
|
||||
Location = Location.Replace("/", "\").Trim(" "c, """"c)
|
||||
Log("[System] 正在打开资源管理器:" & Location)
|
||||
If Location.EndsWith("\") Then
|
||||
ShellOnly(Location)
|
||||
StartProcess(Location)
|
||||
Else
|
||||
ShellOnly("explorer", $"/select,""{Location}""")
|
||||
StartProcess("explorer", $"/select,""{Location}""")
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogLevel.Msgbox)
|
||||
|
||||
Reference in New Issue
Block a user