Application.xaml.vb 15 KB

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