Application.xaml.vb 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. Imports System.Net
  2. Imports System.Reflection
  3. Imports System.Windows.Threading
  4. Public Class Application
  5. #If DEBUG Then
  6. ''' <summary>
  7. ''' 用于开始程序时的一些测试。
  8. ''' </summary>
  9. Private Sub Test()
  10. Try
  11. ModDevelop.Start()
  12. Catch ex As Exception
  13. Log(ex, "开发者模式测试出错", LogLevel.Msgbox)
  14. End Try
  15. End Sub
  16. #End If
  17. '开始
  18. Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
  19. Try
  20. SecretOnApplicationStart()
  21. '检查参数调用
  22. If e.Args.Length > 0 Then
  23. If e.Args(0) = "--update" Then
  24. '自动更新
  25. UpdateReplace(e.Args(1), e.Args(2).Trim(""""), e.Args(3).Trim(""""), e.Args(4))
  26. Environment.Exit(Result.Cancel)
  27. ElseIf e.Args(0).StartsWithF("--memory") Then
  28. '内存优化
  29. Dim Ram = My.Computer.Info.AvailablePhysicalMemory
  30. Try
  31. PageOtherTest.MemoryOptimizeInternal()
  32. Catch ex As Exception
  33. MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败")
  34. Environment.Exit(-1)
  35. End Try
  36. If My.Computer.Info.AvailablePhysicalMemory < Ram Then '避免 ULong 相减出现负数
  37. Environment.Exit(0)
  38. Else
  39. Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
  40. End If
  41. #If DEBUG Then
  42. '制作更新包
  43. ElseIf e.Args(0) = "--edit1" Then
  44. ExeEdit(e.Args(1), True)
  45. Environment.Exit(Result.Cancel)
  46. ElseIf e.Args(0) = "--edit2" Then
  47. ExeEdit(e.Args(1), False)
  48. Environment.Exit(Result.Cancel)
  49. #End If
  50. End If
  51. End If
  52. '初始化文件结构
  53. Directory.CreateDirectory(Path & "PCL\Pictures")
  54. Directory.CreateDirectory(Path & "PCL\Musics")
  55. Try
  56. Directory.CreateDirectory(PathTemp)
  57. If Not CheckPermission(PathTemp) Then Throw New Exception("PCL 没有对 " & PathTemp & " 的访问权限")
  58. Catch ex As Exception
  59. If PathTemp = IO.Path.GetTempPath() & "PCL\" Then
  60. MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
  61. Else
  62. MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
  63. Setup.Set("SystemSystemCache", "")
  64. PathTemp = IO.Path.GetTempPath() & "PCL\"
  65. End If
  66. End Try
  67. Directory.CreateDirectory(PathTemp & "Cache")
  68. Directory.CreateDirectory(PathTemp & "Download")
  69. Directory.CreateDirectory(PathAppdata)
  70. '检测单例
  71. #If Not DEBUG Then
  72. Dim ShouldWaitForExit As Boolean = e.Args.Length > 0 AndAlso e.Args(0) = "--wait" '要求等待已有的 PCL 退出
  73. Dim WaitRetryCount As Integer = 0
  74. WaitRetry:
  75. Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
  76. If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ")
  77. If WindowHwnd <> IntPtr.Zero Then
  78. If ShouldWaitForExit AndAlso WaitRetryCount < 20 Then '至多等待 10 秒
  79. WaitRetryCount += 1
  80. Thread.Sleep(500)
  81. GoTo WaitRetry
  82. End If
  83. '将已有的 PCL 窗口拖出来
  84. ShowWindowToTop(WindowHwnd)
  85. '播放提示音并退出
  86. Beep()
  87. Environment.[Exit](Result.Cancel)
  88. End If
  89. #End If
  90. '设置 ToolTipService 默认值
  91. ToolTipService.InitialShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(300))
  92. ToolTipService.BetweenShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(400))
  93. ToolTipService.ShowDurationProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(9999999))
  94. ToolTipService.PlacementProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(Primitives.PlacementMode.Bottom))
  95. ToolTipService.HorizontalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(8.0))
  96. ToolTipService.VerticalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(4.0))
  97. '设置初始窗口
  98. If Setup.Get("UiLauncherLogo") Then
  99. FrmStart = New SplashScreen("Images\icon.ico")
  100. FrmStart.Show(False, True)
  101. End If
  102. '动态 DLL 调用
  103. AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
  104. '日志初始化
  105. LogStart()
  106. '添加日志
  107. Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})")
  108. Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
  109. Log($"[Start] 程序路径:{PathWithName}")
  110. Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
  111. Log($"[Start] 管理员权限:{IsAdmin()}")
  112. '检测异常环境
  113. If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
  114. MyMsgBox("请将 PCL 从压缩文件中解压,或是更换文件夹后再继续使用!" & vbCrLf & "程序目前在临时文件夹中运行,设置、游戏存档等可能无法保存,且部分功能将无法使用。", "环境警告", "我知道了", IsWarn:=True)
  115. End If
  116. If Is32BitSystem Then
  117. MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True)
  118. End If
  119. '设置初始化
  120. Setup.Load("SystemDebugMode")
  121. Setup.Load("SystemDebugAnim")
  122. Setup.Load("ToolDownloadThread")
  123. Setup.Load("ToolDownloadCert")
  124. '网络配置初始化
  125. ServicePointManager.Expect100Continue = True
  126. ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
  127. ServicePointManager.DefaultConnectionLimit = 1024
  128. '计时
  129. Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
  130. ApplicationStartTick = GetTimeTick()
  131. '执行测试
  132. #If DEBUG Then
  133. Test()
  134. #End If
  135. AniControlEnabled += 1
  136. Catch ex As Exception
  137. Dim FilePath As String = Nothing
  138. Try
  139. FilePath = PathWithName
  140. Catch
  141. End Try
  142. MsgBox(GetExceptionDetail(ex, True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误")
  143. FormMain.EndProgramForce(Result.Exception)
  144. End Try
  145. End Sub
  146. '结束
  147. Private Sub Application_SessionEnding(sender As Object, e As SessionEndingCancelEventArgs) Handles Me.SessionEnding
  148. FrmMain.EndProgram(False)
  149. End Sub
  150. '异常
  151. Private IsCritErrored As Boolean = False
  152. Private Sub Application_DispatcherUnhandledException(sender As Object, e As DispatcherUnhandledExceptionEventArgs) Handles Me.DispatcherUnhandledException
  153. On Error Resume Next
  154. e.Handled = True
  155. If IsProgramEnded Then Exit Sub
  156. If IsCritErrored Then
  157. '在汇报错误后继续引发错误,知道这次压不住了
  158. FormMain.EndProgramForce(Result.Exception)
  159. Exit Sub
  160. End If
  161. IsCritErrored = True
  162. Dim ExceptionString As String = GetExceptionDetail(e.Exception, True)
  163. If ExceptionString.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse
  164. ExceptionString.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse
  165. ExceptionString.Contains(".NET Framework") OrElse ' “自动错误判断” 的结果分析
  166. ExceptionString.Contains("未能加载文件或程序集") Then
  167. OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer")
  168. MsgBox("你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.6.2!", MsgBoxStyle.Information, "运行环境错误")
  169. FormMain.EndProgramForce(Result.Cancel)
  170. Else
  171. FeedbackInfo()
  172. Log(e.Exception, "程序出现未知错误", LogLevel.Assert, "锟斤拷烫烫烫")
  173. End If
  174. End Sub
  175. '动态 DLL 调用
  176. Private Shared AssemblyNAudio As Assembly
  177. Private Shared AssemblyJson As Assembly
  178. Private Shared AssemblyDialog As Assembly
  179. Private Shared AssemblyImazenWebp As Assembly
  180. Private Shared ReadOnly AssemblyNAudioLock As New Object
  181. Private Shared ReadOnly AssemblyJsonLock As New Object
  182. Private Shared ReadOnly AssemblyDialogLock As New Object
  183. Private Shared ReadOnly AssemblyImazenWebpLock As New Object
  184. Private Declare Function SetDllDirectory Lib "kernel32" Alias "SetDllDirectoryA" (lpPathName As String) As Boolean
  185. Public Shared Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
  186. If args.Name.StartsWithF("NAudio") Then
  187. SyncLock AssemblyNAudioLock
  188. If AssemblyNAudio Is Nothing Then
  189. Log("[Start] 加载 DLL:NAudio")
  190. AssemblyNAudio = Assembly.Load(GetResources("NAudio"))
  191. End If
  192. Return AssemblyNAudio
  193. End SyncLock
  194. ElseIf args.Name.StartsWithF("Newtonsoft.Json") Then
  195. SyncLock AssemblyJsonLock
  196. If AssemblyJson Is Nothing Then
  197. Log("[Start] 加载 DLL:Json")
  198. AssemblyJson = Assembly.Load(GetResources("Json"))
  199. End If
  200. Return AssemblyJson
  201. End SyncLock
  202. ElseIf args.Name.StartsWithF("Ookii.Dialogs.Wpf") Then
  203. SyncLock AssemblyDialogLock
  204. If AssemblyDialog Is Nothing Then
  205. Log("[Start] 加载 DLL:Dialogs")
  206. AssemblyDialog = Assembly.Load(GetResources("Dialogs"))
  207. End If
  208. Return AssemblyDialog
  209. End SyncLock
  210. ElseIf args.Name.StartsWithF("Imazen.WebP") Then
  211. SyncLock AssemblyImazenWebpLock
  212. If AssemblyImazenWebp Is Nothing Then
  213. Log("[Start] 加载 DLL:Imazen.WebP")
  214. AssemblyImazenWebp = Assembly.Load(GetResources("Imazen_WebP"))
  215. SetDllDirectory(PathPure.TrimEnd("\"))
  216. WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
  217. End If
  218. Return AssemblyImazenWebp
  219. End SyncLock
  220. Else
  221. Return Nothing
  222. End If
  223. End Function
  224. '切换窗口
  225. '控件模板事件
  226. Private Sub MyIconButton_Click(sender As Object, e As EventArgs)
  227. Select Case Setup.Get("LoginType")
  228. Case McLoginType.Ms
  229. '微软
  230. Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson"))
  231. MsJson.Remove(sender.Tag)
  232. Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None))
  233. If FrmLoginMs.ComboAccounts.SelectedItem Is sender.Parent Then FrmLoginMs.ComboAccounts.SelectedIndex = 0
  234. FrmLoginMs.ComboAccounts.Items.Remove(sender.Parent)
  235. Case McLoginType.Legacy
  236. '离线
  237. Dim Names As New List(Of String)
  238. Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
  239. Names.Remove(sender.Tag)
  240. Setup.Set("LoginLegacyName", Join(Names, "¨"))
  241. FrmLoginLegacy.ComboName.ItemsSource = Names
  242. FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "")
  243. Case Else
  244. '第三方
  245. Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
  246. Dim Dict As New Dictionary(Of String, String)
  247. Dim Names As New List(Of String)
  248. Dim Passs As New List(Of String)
  249. If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨"))
  250. If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨"))
  251. For i = 0 To Names.Count - 1
  252. Dict.Add(Names(i), Passs(i))
  253. Next
  254. Dict.Remove(sender.Tag)
  255. Setup.Set("Login" & Token & "Email", Join(Dict.Keys, "¨"))
  256. Setup.Set("Login" & Token & "Pass", Join(Dict.Values, "¨"))
  257. Select Case Token
  258. Case "Nide"
  259. FrmLoginNide.ComboName.ItemsSource = Dict.Keys
  260. FrmLoginNide.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
  261. FrmLoginNide.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
  262. Case "Auth"
  263. FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
  264. FrmLoginAuth.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
  265. FrmLoginAuth.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
  266. End Select
  267. End Select
  268. End Sub
  269. Public Shared ShowingTooltips As New List(Of Border)
  270. Private Sub TooltipLoaded(sender As Border, e As EventArgs)
  271. ShowingTooltips.Add(sender)
  272. End Sub
  273. Private Sub TooltipUnloaded(sender As Border, e As RoutedEventArgs)
  274. ShowingTooltips.Remove(sender)
  275. End Sub
  276. End Class