Settings.vb 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. Imports System.Security.Cryptography
  2. Public Class Settings
  3. Public Shared ReadOnly Entries As Dictionary(Of String, Setting) = (New List(Of Setting) From {
  4. New Setting("Identify", "", Source:=Sources.Registry),
  5. New Setting("WindowHeight", 550),
  6. New Setting("WindowWidth", 900),
  7. New Setting("AprilYear", 0, Source:=Sources.Registry, Encrypted:=True),
  8. New Setting("Potatoes", "", Source:=Sources.Registry, Encrypted:=True),
  9. New Setting("HintDownloadThread", False, Source:=Sources.Registry),
  10. New Setting("HintNotice", 0, Source:=Sources.Registry),
  11. New Setting("HintDownload", 0, Source:=Sources.Registry),
  12. New Setting("HintHide", False, Source:=Sources.Registry),
  13. New Setting("HintHandInstall", False, Source:=Sources.Registry),
  14. New Setting("HintBuy", False, Source:=Sources.Registry),
  15. New Setting("HintClearRubbish", 0, Source:=Sources.Registry),
  16. New Setting("HintUpdateMod", False, Source:=Sources.Registry),
  17. New Setting("HintCustomCommand", False, Source:=Sources.Registry),
  18. New Setting("HintCustomWarn", False, Source:=Sources.Registry),
  19. New Setting("HintMoreAdvancedSetup", False, Source:=Sources.Registry),
  20. New Setting("HintIndieSetup", False, Source:=Sources.Registry),
  21. New Setting("HintExportConfig", False, Source:=Sources.Registry),
  22. New Setting("HintSnapshot", False, Source:=Sources.Registry),
  23. New Setting("SystemEulaVersion", 0, Source:=Sources.Registry),
  24. New Setting("SystemCount", 0, Source:=Sources.Registry, Encrypted:=True),
  25. New Setting("SystemLaunchCount", 0, Source:=Sources.Registry, Encrypted:=True),
  26. New Setting("SystemLastVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
  27. New Setting("SystemHighestSavedBetaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
  28. New Setting("SystemHighestBetaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
  29. New Setting("SystemHighestAlphaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
  30. New Setting("SystemHelpVersion", 0, Source:=Sources.Registry),
  31. New Setting("SystemDebugMode", False, Source:=Sources.Registry, OnChanged:=Sub() Logger.Instance.MinLevel = If(ModeDebug, LogLevel.Trace, LogLevel.Info)),
  32. New Setting("SystemDebugAnim", 9, Source:=Sources.Registry),
  33. New Setting("SystemDebugDelay", False, Source:=Sources.Registry),
  34. New Setting("SystemDebugSkipCopy", False, Source:=Sources.Registry),
  35. New Setting("SystemSystemCache", "", Source:=Sources.Registry),
  36. New Setting("SystemSystemUpdate", 0),
  37. New Setting("SystemSystemActivity", 0),
  38. New Setting("SystemSystemTelemetry", True, Source:=Sources.Registry),
  39. New Setting("CacheDrops", "", Source:=Sources.Registry),
  40. New Setting("CacheConfig", 0, Source:=Sources.Registry),
  41. New Setting("CacheExportConfig", "", Source:=Sources.Registry),
  42. New Setting("CacheSavedPageUrl", "", Source:=Sources.Registry),
  43. New Setting("CacheSavedPageVersion", "", Source:=Sources.Registry),
  44. New Setting("CacheMsOAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True),
  45. New Setting("CacheMsAccess", "", Source:=Sources.Registry, Encrypted:=True),
  46. New Setting("CacheMsProfileJson", "", Source:=Sources.Registry, Encrypted:=True),
  47. New Setting("CacheMsUuid", "", Source:=Sources.Registry, Encrypted:=True),
  48. New Setting("CacheMsName", "", Source:=Sources.Registry, Encrypted:=True),
  49. New Setting("CacheMsV2Migrated", False, Source:=Sources.Registry),
  50. New Setting("CacheMsV2OAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True),
  51. New Setting("CacheMsV2Access", "", Source:=Sources.Registry, Encrypted:=True),
  52. New Setting("CacheMsV2ProfileJson", "", Source:=Sources.Registry, Encrypted:=True),
  53. New Setting("CacheMsV2Uuid", "", Source:=Sources.Registry, Encrypted:=True),
  54. New Setting("CacheMsV2Name", "", Source:=Sources.Registry, Encrypted:=True),
  55. New Setting("CacheMsV2Expires", 0L, Source:=Sources.Registry, Encrypted:=True),
  56. New Setting("CacheNideAccess", "", Source:=Sources.Registry, Encrypted:=True),
  57. New Setting("CacheNideClient", "", Source:=Sources.Registry, Encrypted:=True),
  58. New Setting("CacheNideUuid", "", Source:=Sources.Registry, Encrypted:=True),
  59. New Setting("CacheNideName", "", Source:=Sources.Registry, Encrypted:=True),
  60. New Setting("CacheNideUsername", "", Source:=Sources.Registry, Encrypted:=True),
  61. New Setting("CacheNidePass", "", Source:=Sources.Registry, Encrypted:=True),
  62. New Setting("CacheNideServer", "", Source:=Sources.Registry, Encrypted:=True),
  63. New Setting("CacheAuthAccess", "", Source:=Sources.Registry, Encrypted:=True),
  64. New Setting("CacheAuthClient", "", Source:=Sources.Registry, Encrypted:=True),
  65. New Setting("CacheAuthUuid", "", Source:=Sources.Registry, Encrypted:=True),
  66. New Setting("CacheAuthName", "", Source:=Sources.Registry, Encrypted:=True),
  67. New Setting("CacheAuthUsername", "", Source:=Sources.Registry, Encrypted:=True),
  68. New Setting("CacheAuthPass", "", Source:=Sources.Registry, Encrypted:=True),
  69. New Setting("CacheAuthServerServer", "", Source:=Sources.Registry, Encrypted:=True),
  70. New Setting("CacheAuthServerName", "", Source:=Sources.Registry, Encrypted:=True),
  71. New Setting("CacheAuthServerRegister", "", Source:=Sources.Registry, Encrypted:=True),
  72. New Setting("CacheDownloadFolder", "", Source:=Sources.Registry),
  73. New Setting("CacheJavaListVersion", 0, Source:=Sources.Registry),
  74. New Setting("LoginRemember", True, Source:=Sources.Registry, Encrypted:=True),
  75. New Setting("LoginLegacyName", "", Source:=Sources.Registry, Encrypted:=True),
  76. New Setting("LoginMsJson", "{}", Source:=Sources.Registry, Encrypted:=True), '{UserName: OAuthToken, ...}
  77. New Setting("LoginNideEmail", "", Source:=Sources.Registry, Encrypted:=True),
  78. New Setting("LoginNidePass", "", Source:=Sources.Registry, Encrypted:=True),
  79. New Setting("LoginAuthEmail", "", Source:=Sources.Registry, Encrypted:=True),
  80. New Setting("LoginAuthPass", "", Source:=Sources.Registry, Encrypted:=True),
  81. New Setting("LoginType", McLoginType.Legacy, Source:=Sources.Registry),
  82. New Setting("LoginPageType", 0),
  83. New Setting("LaunchSkinID", "", Source:=Sources.Registry, OnChanged:=Sub() PageLaunchLeft.SkinLegacy.Start()),
  84. New Setting("LaunchSkinType", 0, Source:=Sources.Registry, OnChanged:=AddressOf PageSetupLaunch.UpdateSkinType),
  85. New Setting("LaunchSkinSlim", False, Source:=Sources.Registry),
  86. New Setting("LaunchFolderSelect", ""),
  87. New Setting("LaunchFolders", "", Source:=Sources.Registry),
  88. New Setting("LaunchArgumentTitle", ""),
  89. New Setting("LaunchArgumentInfo", "PCL"),
  90. New Setting("LaunchArgumentJavaSelect", "", Source:=Sources.Registry),
  91. New Setting("LaunchArgumentJavaAll", "[]", Source:=Sources.Registry),
  92. New Setting("LaunchArgumentIndie", 0),
  93. New Setting("LaunchArgumentIndieV2", 4),
  94. New Setting("LaunchArgumentVisible", 5, Source:=Sources.Registry),
  95. New Setting("LaunchArgumentPriority", 1, Source:=Sources.Registry),
  96. New Setting("LaunchArgumentWindowWidth", 854),
  97. New Setting("LaunchArgumentWindowHeight", 480),
  98. New Setting("LaunchArgumentWindowType", 1),
  99. New Setting("LaunchArgumentRam", False, Source:=Sources.Registry),
  100. New Setting("LaunchAdvanceJvm", "-XX:-OmitStackTraceInFastThrow -Djdk.lang.Process.allowAmbiguousCommands=True -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True"),
  101. New Setting("LaunchAdvanceGame", ""),
  102. New Setting("LaunchAdvanceRun", ""),
  103. New Setting("LaunchAdvanceRunWait", True),
  104. New Setting("LaunchAdvanceDisableJLW", False),
  105. New Setting("LaunchAdvanceDisableLUA", False),
  106. New Setting("LaunchAdvanceGraphicCard", True, Source:=Sources.Registry),
  107. New Setting("LaunchAdvanceGC", 4),
  108. New Setting("LaunchRamType", 0, OnChanged:=AddressOf PageSetupLaunch.UpdateRamType),
  109. New Setting("LaunchRamCustom", 15),
  110. New Setting("LinkLastAutoJoinInviteCode", "", Source:=Sources.Registry),
  111. New Setting("LinkLatencyMode", 0, Source:=Sources.Registry),
  112. New Setting("LinkCustomPeer", ""),
  113. New Setting("LinkEasyTierVersion", -1, Source:=Sources.Registry),
  114. New Setting("ToolHelpChinese", True, Source:=Sources.Registry),
  115. New Setting("ToolDownloadThread", 63, Source:=Sources.Registry),
  116. New Setting("ToolDownloadSpeed", 42, Source:=Sources.Registry, OnChanged:=AddressOf ModNet.UpdateNetTaskSpeedLimitHigh),
  117. New Setting("ToolDownloadSource", 1, Source:=Sources.Registry),
  118. New Setting("ToolDownloadVersion", 1, Source:=Sources.Registry),
  119. New Setting("ToolDownloadTranslate", 0, Source:=Sources.Registry),
  120. New Setting("ToolDownloadTranslateV2", 1, Source:=Sources.Registry),
  121. New Setting("ToolDownloadCert", False, Source:=Sources.Registry, OnChanged:=AddressOf ModNet.ShouldValidateSslCertificateOnLogin),
  122. New Setting("ToolDownloadMod", 2, Source:=Sources.Registry),
  123. New Setting("ToolModLocalNameStyle", 0, Source:=Sources.Registry),
  124. New Setting("ToolUpdateRelease", False, Source:=Sources.Registry),
  125. New Setting("ToolUpdateSnapshot", False, Source:=Sources.Registry),
  126. New Setting("ToolUpdateReleaseLast", "", Source:=Sources.Registry),
  127. New Setting("ToolUpdateSnapshotLast", "", Source:=Sources.Registry),
  128. New Setting("UiLauncherTransparent", 600, OnChanged:=Sub(Value As Integer) If FrmMain IsNot Nothing Then FrmMain.Opacity = Value / 1000 + 0.4), '避免与 PCL1 设置冲突(UiLauncherOpacity)
  129. New Setting("UiLauncherHue", 180),
  130. New Setting("UiLauncherSat", 80),
  131. New Setting("UiLauncherDelta", 90),
  132. New Setting("UiLauncherLight", 20),
  133. New Setting("UiLauncherTheme", 0, OnChanged:=AddressOf ThemeRefresh),
  134. New Setting("UiLauncherThemeHide", "0|1|2|3|4", Source:=Sources.Registry, Encrypted:=True),
  135. New Setting("UiLauncherThemeHide2", "0|1|2|3|4", Source:=Sources.Registry, Encrypted:=True),
  136. New Setting("UiLauncherLogo", True),
  137. New Setting("UiLauncherEmail", False),
  138. New Setting("UiBackgroundColorful", True, OnChanged:=Sub() ThemeRefresh()), '不传入参数
  139. New Setting("UiBackgroundOpacity", 1000, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  140. New Setting("UiBackgroundBlur", 0, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  141. New Setting("UiBackgroundSuit", 0, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  142. New Setting("UiCustomType", 0, OnChanged:=AddressOf PageSetupUI.OnMainPageTypeChanged),
  143. New Setting("UiCustomPreset", 0),
  144. New Setting("UiCustomNet", ""),
  145. New Setting("UiLogoType", 1, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  146. New Setting("UiLogoText", "", OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  147. New Setting("UiLogoLeft", False, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
  148. New Setting("UiMusicVolume", 500),
  149. New Setting("UiMusicStop", False),
  150. New Setting("UiMusicStart", False),
  151. New Setting("UiMusicRandom", True),
  152. New Setting("UiMusicAuto", True),
  153. New Setting("UiHiddenPageDownload", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  154. New Setting("UiHiddenPageLink", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  155. New Setting("UiHiddenPageSetup", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  156. New Setting("UiHiddenPageOther", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  157. New Setting("UiHiddenFunctionSelect", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  158. New Setting("UiHiddenFunctionModUpdate", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  159. New Setting("UiHiddenFunctionInstanceModify", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  160. New Setting("UiHiddenFunctionHidden", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  161. New Setting("UiHiddenSetupLaunch", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  162. New Setting("UiHiddenSetupUi", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  163. New Setting("UiHiddenSetupLink", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  164. New Setting("UiHiddenSetupSystem", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  165. New Setting("UiHiddenOtherHelp", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  166. New Setting("UiHiddenOtherFeedback", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  167. New Setting("UiHiddenOtherVote", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  168. New Setting("UiHiddenOtherAbout", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  169. New Setting("UiHiddenOtherTest", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
  170. New Setting("VersionAdvanceJvm", "", Source:=Sources.Instance),
  171. New Setting("VersionAdvanceGame", "", Source:=Sources.Instance),
  172. New Setting("VersionAdvanceAssets", 0, Source:=Sources.Instance),
  173. New Setting("VersionAdvanceAssetsV2", False, Source:=Sources.Instance),
  174. New Setting("VersionAdvanceRun", "", Source:=Sources.Instance),
  175. New Setting("VersionAdvanceRunWait", True, Source:=Sources.Instance),
  176. New Setting("VersionAdvanceDisableJLW", False, Source:=Sources.Instance),
  177. New Setting("VersionAdvanceDisableLUA", False, Source:=Sources.Instance),
  178. New Setting("VersionAdvanceDisableModUpdate", False, Source:=Sources.Instance),
  179. New Setting("VersionAdvanceGC", 0, Source:=Sources.Instance),
  180. New Setting("VersionRamType", 2, Source:=Sources.Instance, OnChanged:=AddressOf PageInstanceSetup.OnVersionRamTypeChanged),
  181. New Setting("VersionRamCustom", 15, Source:=Sources.Instance),
  182. New Setting("VersionRamOptimize", 0, Source:=Sources.Instance),
  183. New Setting("VersionArgumentTitle", "", Source:=Sources.Instance),
  184. New Setting("VersionArgumentInfo", "", Source:=Sources.Instance),
  185. New Setting("VersionArgumentIndie", -1, Source:=Sources.Instance),
  186. New Setting("VersionArgumentIndieV2", False, Source:=Sources.Instance),
  187. New Setting("VersionArgumentJavaSelect", "使用全局设置", Source:=Sources.Instance),
  188. New Setting("VersionArgumentJavaV2", 0, Source:=Sources.Instance),
  189. New Setting("VersionArgumentJavaRange", "", Source:=Sources.Instance),
  190. New Setting("VersionServerEnter", "", Source:=Sources.Instance),
  191. New Setting("VersionServerLogin", 0, Source:=Sources.Instance, OnChanged:=AddressOf PageInstanceSetup.OnVersionServerLoginChanged),
  192. New Setting("VersionServerNide", "", Source:=Sources.Instance),
  193. New Setting("VersionServerAuthRegister", "", Source:=Sources.Instance),
  194. New Setting("VersionServerAuthName", "", Source:=Sources.Instance),
  195. New Setting("VersionServerAuthServer", "", Source:=Sources.Instance)
  196. }).ToDictionary(Function(e) e.Key)
  197. Public Enum Sources
  198. Normal
  199. Registry
  200. Instance
  201. End Enum
  202. Public Class Setting
  203. Public Key As String
  204. Public Encrypted As Boolean
  205. Public DefaultValue As Object
  206. Public Source As Sources
  207. ''' <summary>
  208. ''' 当设置项的值实际被改变时触发,参数为新值。
  209. ''' </summary>
  210. Public OnChanged As Action(Of Object)
  211. ''' <summary>
  212. ''' 该设置的值的实际类型。
  213. ''' </summary>
  214. Public Type As Type
  215. Public Sub New(Key As String, Value As Object, Optional Source As Sources = Sources.Normal, Optional Encrypted As Boolean = False, Optional OnChanged As Action(Of Object) = Nothing)
  216. Try
  217. Me.Key = Key
  218. Me.DefaultValue = Value
  219. Me.Encrypted = Encrypted
  220. Me.Source = Source
  221. Me.Type = If(Value, "").GetType
  222. Me.OnChanged = OnChanged
  223. Catch ex As Exception
  224. Logger.Error(ex, "初始化设置项失败") '#5095 的 fallback
  225. End Try
  226. End Sub
  227. ''' <summary>
  228. ''' 读取过的设置的缓存,若从未读取过则为 Nothing。
  229. ''' 若为版本独立设置,键为版本路径;否则,键为空字符串。
  230. ''' </summary>
  231. Public ValueCache As New ConcurrentDictionary(Of String, Object)
  232. Public Function GetCache(Instance As McInstance)
  233. Dim Key As String = If(Source = Sources.Instance, Instance.PathVersion, "")
  234. Dim Result = Nothing
  235. Return If(ValueCache.TryGetValue(Key, Result), Result, Nothing)
  236. End Function
  237. Public Sub [Set](Value As Object, Instance As McInstance)
  238. Dim Key As String = If(Source = Sources.Instance, Instance.PathVersion, "")
  239. ValueCache(Key) = Value
  240. End Sub
  241. ''' <summary>
  242. ''' 立即将当前的 Value 写入对应的注册表或文件。
  243. ''' </summary>
  244. Public Sub Save(Optional Instance As McInstance = Nothing)
  245. Dim Value As String = GetCache(Instance)
  246. Logger.Trace($"保存设置:{Key} {If(Encrypted, "", "= " & Value)}{If(Instance Is Nothing, "", $"(实例:{Instance?.PathVersion})")}")
  247. If Encrypted Then
  248. Try
  249. If Value Is Nothing Then Value = ""
  250. Value = DesEncrypt(Value, "PCL" & Identify)
  251. Catch ex As Exception
  252. Logger.Warn(ex, $"加密设置失败:{Key}")
  253. End Try
  254. End If
  255. Select Case Source
  256. Case Sources.Normal
  257. WriteIni("Setup", Key, Value)
  258. Case Sources.Registry
  259. Try
  260. RegistryUtils.Write($"HKEY_CURRENT_USER\Software\{RegFolder}", Key, Value)
  261. Catch ex As Exception
  262. Logger.Warn(ex, $"写入注册表失败({Key} → {Value})", LogBehavior.Toast)
  263. End Try
  264. Case Sources.Instance
  265. If Instance Is Nothing Then Throw New Exception($"保存版本独立设置 {Key} 时未提供目标版本")
  266. WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value)
  267. End Select
  268. End Sub
  269. End Class
  270. ''' <summary>
  271. ''' 改变某个设置项的值。
  272. ''' </summary>
  273. Public Shared Sub [Set](Key As String, Value As Object, Optional Instance As McInstance = Nothing)
  274. Dim Entry As Setting = Nothing
  275. If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
  276. Try
  277. '判断是否一致
  278. Value = CTypeDynamic(Value, Entry.Type)
  279. If Entry.GetCache(Instance) Is Nothing Then [Get](Key, Instance)
  280. If Entry.GetCache(Instance) = Value Then Return
  281. '设置新值
  282. Entry.Set(Value, Instance)
  283. Entry.Save(Instance)
  284. '触发改变事件(必须在保存之后,以保证 VersionServerLogin 之类的在事件中读取到的是最新的值)
  285. If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Value)
  286. Catch ex As Exception
  287. Logger.Error(ex, $"设置设置项时出错({Key}, {Value})")
  288. End Try
  289. End Sub
  290. ''' <summary>
  291. ''' 写入某个未经加密的设置项。
  292. ''' 若该设置项经过了加密,则会抛出异常。
  293. ''' </summary>
  294. Public Shared Sub SetSafe(Key As String, Value As Object, Optional Instance As McInstance = Nothing)
  295. Dim Entry As Setting = Nothing
  296. If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
  297. If Entry.Encrypted Then Throw New InvalidOperationException("禁止写入加密设置项:" & Key)
  298. [Set](Key, Value, Instance)
  299. End Sub
  300. ''' <summary>
  301. ''' 获取某个设置项的值。
  302. ''' </summary>
  303. Public Shared Function [Get](Key As String, Optional Instance As McInstance = Nothing)
  304. Dim Entry As Setting = Nothing
  305. If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
  306. Dim Value = Entry.GetCache(Instance)
  307. If Value IsNot Nothing Then Return Value
  308. '对部分设置强制赋值
  309. Static ForcedSettings As New Dictionary(Of String, Object) From {
  310. {"UiHiddenPageLink", True},
  311. {"UiHiddenSetupLink", True}
  312. }
  313. Dim ForcedSetting As Object = Nothing
  314. If ForcedSettings.TryGetValue(Key, ForcedSetting) Then
  315. Entry.Set(ForcedSetting, Instance)
  316. Return ForcedSetting
  317. End If
  318. '正常读取
  319. Try
  320. Dim GotValue As String = Nothing '先用 String 储存,避免类型转换
  321. Dim DefaultValue As String = If(Entry.Encrypted, DesEncrypt(Entry.DefaultValue, "PCL" & Identify), Entry.DefaultValue)
  322. Select Case Entry.Source
  323. Case Sources.Normal
  324. GotValue = ReadIni("Setup", Key, DefaultValue)
  325. Case Sources.Registry
  326. GotValue = RegistryUtils.TryRead($"HKEY_CURRENT_USER\Software\{RegFolder}", Key, DefaultValue)
  327. Case Sources.Instance
  328. If Instance Is Nothing Then
  329. Throw New Exception($"读取版本设置 {Key} 时未提供目标版本")
  330. Else
  331. GotValue = ReadIni(Instance.PathVersion & "PCL\Setup.ini", Key, DefaultValue)
  332. End If
  333. End Select
  334. If Entry.Encrypted Then
  335. If GotValue = DefaultValue Then
  336. GotValue = Entry.DefaultValue
  337. Else
  338. Try
  339. GotValue = DesDecrypt(GotValue, "PCL" & Identify)
  340. Catch ex As Exception
  341. Logger.Warn(ex, $"解密设置失败:{Key}")
  342. GotValue = Entry.DefaultValue
  343. Entry.Set(Entry.DefaultValue, Instance)
  344. Entry.Save(Instance)
  345. End Try
  346. End If
  347. End If
  348. Entry.Set(CTypeDynamic(GotValue, Entry.Type), Instance)
  349. Catch ex As Exception
  350. Logger.Error(ex, $"读取设置失败:{Key}", LogBehavior.Toast)
  351. Entry.Set(CTypeDynamic(Entry.DefaultValue, Entry.Type), Instance)
  352. End Try
  353. Return Entry.GetCache(Instance)
  354. End Function
  355. Public Shared Function [Get](Of T)(Key As String, Optional Instance As McInstance = Nothing) As T
  356. Return [Get](Key, Instance)
  357. End Function
  358. ''' <summary>
  359. ''' 获取某个未经加密的设置项的值。
  360. ''' 若该设置项经过了加密,则会抛出异常。
  361. ''' </summary>
  362. Public Shared Function GetSafe(Key As String, Optional Instance As McInstance = Nothing)
  363. Dim Entry As Setting = Nothing
  364. If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
  365. If Entry.Encrypted Then Throw New InvalidOperationException("禁止读取加密设置项:" & Key)
  366. Return [Get](Key, Instance)
  367. End Function
  368. ''' <summary>
  369. ''' 初始化某个设置项的值。
  370. ''' </summary>
  371. Public Shared Sub Reset(Key As String, Optional Instance As McInstance = Nothing)
  372. Dim Entry As Setting = Nothing
  373. If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
  374. Try
  375. '判断是否一致
  376. If Entry.GetCache(Instance) Is Nothing Then [Get](Key, Instance)
  377. If Entry.GetCache(Instance) = Entry.DefaultValue Then Return
  378. '设置新值
  379. Entry.Set(Entry.DefaultValue, Instance)
  380. Select Case Entry.Source
  381. Case Sources.Normal
  382. DeleteIniKey("Setup", Key)
  383. Case Sources.Registry
  384. Try
  385. RegistryUtils.Delete($"HKEY_CURRENT_USER\Software\{RegFolder}", Key)
  386. Catch ex As Exception
  387. Logger.Warn(ex, $"删除注册表失败({Key})", LogBehavior.Toast)
  388. End Try
  389. Case Sources.Instance
  390. If Instance Is Nothing Then Throw New Exception($"重置版本设置 {Key} 时未提供目标版本")
  391. DeleteIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
  392. End Select
  393. '触发改变事件
  394. If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Entry.DefaultValue)
  395. Catch ex As Exception
  396. Logger.Error(ex, $"重置设置项时出错({Key})")
  397. End Try
  398. End Sub
  399. ''' <summary>
  400. ''' 获取某个设置项的默认值。
  401. ''' </summary>
  402. Public Shared Function GetDefault(Key As String) As String
  403. Return Entries(Key).DefaultValue
  404. End Function
  405. ''' <summary>
  406. ''' 对应的注册表或文件是否已经储存了某个设置项。
  407. ''' 若改成了和默认值一样的,在 2.12.3- 会储存更改,在 2.12.4+ 不会储存更改。
  408. ''' </summary>
  409. Public Shared Function HasSaved(Key As String, Optional Instance As McInstance = Nothing) As Boolean
  410. Select Case Entries(Key).Source
  411. Case Sources.Normal
  412. Return HasIniKey("Setup", Key)
  413. Case Sources.Registry
  414. Try
  415. Return RegistryUtils.Has($"HKEY_CURRENT_USER\Software\{RegFolder}", Key)
  416. Catch ex As Exception
  417. Logger.Warn(ex, $"判断注册表 {Key} 是否存在时出错")
  418. Return False
  419. End Try
  420. Case Else 'Source.Instance
  421. If Instance Is Nothing Then Throw New Exception($"判断版本设置 {Key} 是否存在时未提供目标版本")
  422. Return HasIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
  423. End Select
  424. End Function
  425. #Region "DES 加密"
  426. Private Shared ReadOnly desInitialVector As Byte() = Encoding.UTF8.GetBytes("95168702")
  427. ''' <summary>
  428. ''' 使用 DES 对称加密算法加密字符串。
  429. ''' </summary>
  430. Private Shared Function DesEncrypt(sourceString As String, Optional key As String = Nothing) As String
  431. key = If(key Is Nothing, "@;$ Abv2", key.GetStableHashCode().ToString().EnsureLength("X"c, 8).Substring(0, 8))
  432. Dim btKey As Byte() = Encoding.UTF8.GetBytes(key)
  433. Using des As New DESCryptoServiceProvider()
  434. Using ms As New MemoryStream()
  435. Using cs As New CryptoStream(ms, des.CreateEncryptor(btKey, desInitialVector), CryptoStreamMode.Write)
  436. Dim inData As Byte() = Encoding.UTF8.GetBytes(sourceString)
  437. cs.Write(inData, 0, inData.Length)
  438. cs.FlushFinalBlock()
  439. Return Convert.ToBase64String(ms.ToArray())
  440. End Using
  441. End Using
  442. End Using
  443. End Function
  444. ''' <summary>
  445. ''' 使用 DES 对称加密算法解密字符串。
  446. ''' </summary>
  447. Private Shared Function DesDecrypt(encryptedString As String, Optional key As String = Nothing) As String
  448. key = If(key Is Nothing, "@;$ Abv2", key.GetStableHashCode().ToString().EnsureLength("X"c, 8).Substring(0, 8))
  449. Dim btKey As Byte() = Encoding.UTF8.GetBytes(key)
  450. Using des As New DESCryptoServiceProvider()
  451. Using ms As New MemoryStream()
  452. Using cs As New CryptoStream(ms, des.CreateDecryptor(btKey, desInitialVector), CryptoStreamMode.Write)
  453. Dim inData As Byte() = Convert.FromBase64String(encryptedString)
  454. cs.Write(inData, 0, inData.Length)
  455. cs.FlushFinalBlock()
  456. Return Encoding.UTF8.GetString(ms.ToArray())
  457. End Using
  458. End Using
  459. End Using
  460. End Function
  461. #End Region
  462. End Class