-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathModBase.vb
More file actions
3063 lines (2902 loc) · 153 KB
/
ModBase.vb
File metadata and controls
3063 lines (2902 loc) · 153 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Imports System.Globalization
Imports System.IO.Compression
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Xaml
Imports System.Threading.Tasks
Imports Microsoft.Win32
Imports Newtonsoft.Json
Imports PCL.Core.App
Imports PCL.Core.Logging
Imports PCL.Core.Utils
Imports System.Windows
Imports PCL.Core.Utils.Codecs
Imports PCL.Core.Utils.OS
Imports PCL.Core.IO
Public Module ModBase
#Region "声明"
'下列版本信息由更新器自动修改
Public ReadOnly VersionBaseName As String = Basics.VersionName
Public ReadOnly VersionStandardCode As String = Basics.Metadata.Version.StandardVersion
Public ReadOnly UpstreamVersion As String = Basics.Metadata.Version.UpstreamVersion
Public ReadOnly CommitHash As String = Basics.Metadata.Version.Commit
Public ReadOnly CommitHashShort As String = Basics.Metadata.Version.CommitDigest
Public ReadOnly VersionCode As Integer = Basics.VersionCode
'自动生成的版本信息
#If DEBUG Then
Public Const VersionBranchName As String = "Debug"
Public Const VersionBranchCode As String = "100"
#ElseIf DEBUGCI Then
Public Const VersionBranchName As String = "CI"
Public Const VersionBranchCode As String = "50"
#Else
Public Const VersionBranchName As String = "Publish"
Public Const VersionBranchCode As String = "0"
#End If
''' <summary>
''' 主窗口句柄。
''' </summary>
Public FrmHandle As IntPtr
'龙猫味石山小记: 用最不靠谱的实现写出能跑的代码 (AppDomain.CurrentDomain.SetupInformation.ApplicationBase 获取到的是当前工作目录而不是可执行文件所在目录)
''' <summary>
''' 程序可执行文件所在目录,以“\”结尾。
''' </summary>
Public ReadOnly ExePath As String = If(Basics.ExecutableDirectory.EndsWith("\"), Basics.ExecutableDirectory, Basics.ExecutableDirectory & "\")
''' <summary>
''' 程序可执行文件完整路径。
''' </summary>
Public ReadOnly ExePathWithName As String = Basics.ExecutablePath
''' <summary>
''' 程序内嵌图片文件夹路径,以“/”结尾。
''' </summary>
Public ReadOnly PathImage As String = "pack://application:,,,/Plain Craft Launcher 2;component/Images/"
''' <summary>
''' 当前程序的语言。
''' </summary>
Public Lang As String = "zh_CN"
''' <summary>
''' 设置对象。
''' </summary>
Public Setup As New ModSetup()
''' <summary>
''' 程序的打开计时。
''' </summary>
Public ApplicationStartTick As Long = TimeUtils.GetTimeTick()
''' <summary>
''' 程序打开时的时间。
''' </summary>
Public ApplicationOpenTime As Date = Date.Now
''' <summary>
''' 识别码。
''' </summary>
Public UniqueAddress As String = SecretGetUniqueAddress()
''' <summary>
''' 程序是否已结束。
''' </summary>
Public IsProgramEnded As Boolean = False
''' <summary>
''' 是否为 32 位系统。
''' </summary>
Public Is32BitSystem As Boolean = Not Environment.Is64BitOperatingSystem
''' <summary>
''' 是否为 ARM64 架构。
''' </summary>
Public IsArm64System As Boolean = RuntimeInformation.OSArchitecture = Architecture.Arm64
''' <summary>
''' 是否使用 GBK 编码。
''' </summary>
Public IsGBKEncoding As Boolean = Encoding.Default.CodePage = 936
''' <summary>
''' 系统盘盘符,以 \ 结尾。例如 “C:\”。
''' </summary>
Public OsDrive As String = Environment.GetLogicalDrives().Where(Function(p) Directory.Exists(p)).First.ToUpper.First & ":\" '#3799
''' <summary>
''' 程序的缓存文件夹路径,以 \ 结尾。
''' </summary>
Public PathTemp As String = Paths.Temp & "\"
''' <summary>
''' AppData 中的 PCL 文件夹路径,以 \ 结尾。
''' </summary>
Public PathAppdata As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\PCL\"
''' <summary>
''' AppData 中的 PCLCE 配置文件夹路径,以 \ 结尾。
''' </summary>
Public PathAppdataConfig As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & If(VersionBranchName = "Debug", "\.pclcedebug\", "\.pclce\")
Public PathHelpFolder As String = PathTemp & "CE\Help\"
#End Region
#Region "矢量图标"
Public Class Logo
''' <summary>
''' 图标按钮,心(空心),1.1x
''' </summary>
Public Const IconButtonLikeLine As String = "M512 896a42.666667 42.666667 0 0 1-30.293333-12.373333l-331.52-331.946667a224.426667 224.426667 0 0 1 0-315.733333 223.573333 223.573333 0 0 1 315.733333 0L512 282.026667l46.08-46.08a223.573333 223.573333 0 0 1 315.733333 0 224.426667 224.426667 0 0 1 0 315.733333l-331.52 331.946667A42.666667 42.666667 0 0 1 512 896zM308.053333 256a136.533333 136.533333 0 0 0-97.28 40.106667 138.24 138.24 0 0 0 0 194.986666L512 792.746667l301.226667-301.653334a138.24 138.24 0 0 0 0-194.986666 141.653333 141.653333 0 0 0-194.56 0l-76.373334 76.8a42.666667 42.666667 0 0 1-60.586666 0L405.333333 296.106667A136.533333 136.533333 0 0 0 308.053333 256z"
''' <summary>
''' 图标按钮,心(实心),1.1x
''' </summary>
Public Const IconButtonLikeFill As String = "M700.856 155.543c-74.769 0-144.295 72.696-190.046 127.26-45.737-54.576-115.247-127.26-190.056-127.26-134.79 0-244.443 105.78-244.443 235.799 0 77.57 39.278 131.988 70.845 175.713C238.908 694.053 469.62 852.094 479.39 858.757c9.41 6.414 20.424 9.629 31.401 9.629 11.006 0 21.998-3.215 31.398-9.63 9.782-6.662 240.514-164.703 332.238-291.701 31.587-43.724 70.874-98.143 70.874-175.713-0.001-130.02-109.656-235.8-244.445-235.8z m0 0"
''' <summary>
''' 图标按钮,垃圾桶,1.1x
''' </summary>
Public Const IconButtonDelete As String = "M520.192 0C408.43 0 317.44 82.87 313.563 186.734H52.736c-29.038 0-52.663 21.943-52.663 49.079s23.625 49.152 52.663 49.152h58.075v550.473c0 103.35 75.118 187.757 167.717 187.757h472.43c92.599 0 167.716-83.894 167.716-187.757V285.477h52.59c29.038 0 52.59-21.943 52.663-49.08-0.073-27.135-23.625-49.151-52.663-49.151H726.235C723.237 83.017 631.955 0 520.192 0zM404.846 177.957c3.803-50.03 50.176-89.015 107.447-89.015 57.197 0 103.57 38.985 106.788 89.015H404.92zM284.379 933.669c-33.353 0-69.997-39.351-69.997-95.525v-549.01H833.39v549.522c0 56.247-36.645 95.525-69.998 95.525H284.379v-0.512z M357.23 800.695a48.274 48.274 0 0 0 47.616-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.69 49.006V751.69c0 27.282 20.846 49.006 47.617 49.006z m166.62 0a48.274 48.274 0 0 0 47.688-49.006V471.7a48.274 48.274 0 0 0-47.689-49.08 48.274 48.274 0 0 0-47.543 49.006V751.69c0 27.282 21.431 49.006 47.543 49.006z m142.92 0a48.274 48.274 0 0 0 47.543-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.616 49.006V751.69c0 27.282 20.773 49.006 47.543 49.006z"
''' <summary>
''' 图标按钮,禁止,1x
''' </summary>
Public Const IconButtonStop As String = "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z"
''' <summary>
''' 图标按钮,勾选,1x
''' </summary>
Public Const IconButtonCheck As String = "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"
''' <summary>
''' 图标按钮,笔,1x
''' </summary>
Public Const IconButtonEdit As String = "M732.64 64.32C688.576 21.216 613.696 21.216 569.6 64.32L120.128 499.52c-17.6 12.896-26.432 30.144-30.848 51.68L32 870.048c0 25.856 8.8 56 26.432 73.248 17.632 17.216 17.632 48.704 88.64 48.704h13.248l326.08-56c22.016-4.32 39.68-12.928 52.864-30.176l449.472-435.2c22.048-21.536 35.264-47.36 35.264-77.536 0-30.176-13.216-56-35.264-77.568l-256.096-251.2zM139.712 903.776l56-326.912 311.04-295.136 267.104 269.44-310.976 295.168-323.168 57.44zM844.576 467.84l-273.984-260.672 61.856-59.84c8.832-8.512 26.528-8.512 39.776 0l234.24 226.496c4.384 4.288 8.832 12.8 8.832 17.088s-4.416 8.544-8.864 12.8l-61.856 64.128z"
''' <summary>
''' 图标按钮,齿轮,1.1x
''' </summary>
Public Const IconButtonSetup As String = "M651.946667 1001.813333c-22.186667 0-42.666667-10.24-61.44-27.306666-23.893333-23.893333-49.493333-35.84-75.093334-35.84-29.013333 0-56.32 11.946667-73.386666 30.72v3.413333c-17.066667 17.066667-42.666667 27.306667-66.56 27.306667h-6.826667c-6.826667 0-11.946667-1.706667-15.36-1.706667l-6.826667-1.706667c-64.853333-20.48-121.173333-54.613333-168.96-98.986666-29.013333-23.893333-37.546667-63.146667-25.6-95.573334 8.533333-23.893333 5.12-51.2-10.24-75.093333-15.36-27.306667-34.133333-40.96-59.733333-47.786667h-1.706667l-5.12-1.706666c-35.84-8.533333-61.44-34.133333-66.56-69.973334C1.706667 575.146667 0 537.6 0 512c0-32.426667 3.413333-63.146667 8.533333-93.866667v-6.826666l3.413334-8.533334c10.24-23.893333 23.893333-40.96 44.373333-51.2 5.12-3.413333 11.946667-6.826667 20.48-8.533333 27.306667-8.533333 51.2-25.6 63.146667-44.373333 13.653333-23.893333 17.066667-52.906667 10.24-81.92-11.946667-34.133333 0-71.68 30.72-93.866667 44.373333-37.546667 97.28-68.266667 158.72-93.866667l3.413333-1.706666c44.373333-13.653333 75.093333 3.413333 92.16 20.48 23.893333 23.893333 49.493333 35.84 75.093333 35.84 30.72 0 56.32-10.24 71.68-30.72l3.413334-3.413334c27.306667-27.306667 63.146667-35.84 93.866666-22.186666 63.146667 22.186667 117.76 54.613333 165.546667 97.28 29.013333 23.893333 37.546667 63.146667 25.6 95.573333-8.533333 23.893333-5.12 51.2 10.24 75.093333 15.36 27.306667 34.133333 40.96 59.733333 47.786667h1.706667l5.12 1.706667c35.84 8.533333 61.44 34.133333 66.56 71.68 6.826667 30.72 10.24 63.146667 11.946667 93.866666v3.413334c0 32.426667-3.413333 63.146667-8.533334 93.866666v6.826667l-3.413333 8.533333c-10.24 23.893333-23.893333 40.96-44.373333 51.2-5.12 3.413333-11.946667 6.826667-20.48 8.533334-27.306667 8.533333-51.2 25.6-63.146667 46.08-13.653333 23.893333-17.066667 52.906667-10.24 81.92 11.946667 35.84-1.706667 75.093333-30.72 95.573333-44.373333 35.84-95.573333 66.56-157.013333 92.16-15.36 3.413333-27.306667 3.413333-35.84 3.413333z m3.413333-83.626666z m1.706667 0zM517.12 853.333333c47.786667 0 93.866667 20.48 134.826667 59.733334 1.706667 1.706667 3.413333 1.706667 3.413333 3.413333 52.906667-22.186667 97.28-49.493333 136.533333-80.213333l1.706667-1.706667v-3.413333c-13.653333-52.906667-8.533333-104.106667 17.066667-148.48 23.893333-39.253333 64.853333-69.973333 114.346666-85.333334 1.706667 0 3.413333-1.706667 6.826667-6.826666 5.12-25.6 8.533333-51.2 8.533333-78.506667-1.706667-29.013333-3.413333-56.32-10.24-81.92v-5.12h-1.706666c-51.2-11.946667-90.453333-39.253333-119.466667-87.04-27.306667-44.373333-34.133333-100.693333-17.066667-148.48l-1.706666-1.706667h-3.413334c-39.253333-35.84-85.333333-63.146667-136.533333-80.213333H648.533333s-1.706667 1.706667-3.413333 1.706667c-32.426667 39.253333-80.213333 59.733333-136.533333 59.733333-47.786667 0-93.866667-20.48-134.826667-59.733333l-1.706667-1.706667h-1.706666c-54.613333 22.186667-98.986667 49.493333-136.533334 80.213333l-1.706666 1.706667v3.413333c13.653333 52.906667 8.533333 104.106667-17.066667 148.48-23.893333 39.253333-64.853333 69.973333-114.346667 85.333334-1.706667 0-3.413333 1.706667-6.826666 6.826666-6.826667 25.6-8.533333 51.2-8.533334 78.506667 0 30.72 3.413333 58.026667 6.826667 76.8l1.706667 5.12h1.706666c51.2 11.946667 90.453333 39.253333 119.466667 87.04 27.306667 44.373333 34.133333 100.693333 17.066667 148.48l1.706666 1.706667 1.706667 1.706666c37.546667 35.84 83.626667 63.146667 134.826667 80.213334 1.706667 0 3.413333 0 3.413333 1.706666h1.706667s1.706667 0 5.12-1.706666c34.133333-37.546667 81.92-59.733333 136.533333-59.733334z m-6.826667-146.773333c-110.933333 0-199.68-85.333333-199.68-196.266667 0-109.226667 87.04-196.266667 199.68-196.266666s199.68 85.333333 199.68 196.266666c-1.706667 109.226667-88.746667 196.266667-199.68 196.266667z m0-307.2c-63.146667 0-114.346667 49.493333-114.346666 110.933333 0 63.146667 49.493333 110.933333 114.346666 110.933334 30.72 0 59.733333-11.946667 80.213334-32.426667 20.48-20.48 32.426667-49.493333 32.426666-78.506667 0-63.146667-49.493333-110.933333-112.64-110.933333z"
''' <summary>
''' 图标按钮,重置,0.9x
''' </summary>
Public Const IconButtonReset As String = "M667.6817627 313.65283203l-45.28564454 55.76660156L858.06933594 391.27124023 787.61950684 165.93066406l-56.01379395 69.01611328A354.47387695 354.47387695 0 0 0 520.89892578 165.93066406C324.87536621 165.93066406 165.93066406 324.43041992 165.93066406 519.91015625c0 195.52917481 158.94470215 353.97949219 354.96826172 353.97949219a355.06713867 355.06713867 0 0 0 331.73217774-227.66418458 50.52612305 50.52612305 0 0 0-29.21813966-65.25878905 50.77331543 50.77331543 0 0 0-65.50598144 29.16870117A253.61938477 253.61938477 0 0 1 520.94836426 772.78796387c-140.05920411 0-253.61938477-113.21411133-253.61938477-252.87780762 0-139.61425781 113.56018067-252.82836914 253.61938477-252.82836914 53.59130859 0 104.46350098 16.61132813 146.73339843 46.57104492"
''' <summary>
''' 图标按钮,刷新,0.85x
''' </summary>
Public Const IconButtonRefresh As String = "M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z"
''' <summary>
''' 图标按钮,软盘,1x
''' </summary>
Public Const IconButtonSave As String = "M819.392 0L1024 202.752v652.16a168.96 168.96 0 0 1-168.832 168.768h-104.192a47.296 47.296 0 0 1-10.752 0H283.776a47.232 47.232 0 0 1-10.752 0H168.832A168.96 168.96 0 0 1 0 854.912V168.768A168.96 168.96 0 0 1 168.832 0h650.56z m110.208 854.912V242.112l-149.12-147.776H168.896c-41.088 0-74.432 33.408-74.432 74.432v686.144c0 41.024 33.344 74.432 74.432 74.432h62.4v-190.528c0-33.408 27.136-60.544 60.544-60.544h440.448c33.408 0 60.544 27.136 60.544 60.544v190.528h62.4c41.088 0 74.432-33.408 74.432-74.432z m-604.032 74.432h372.864v-156.736H325.568v156.736z m403.52-596.48a47.168 47.168 0 1 1 0 94.336H287.872a47.168 47.168 0 1 1 0-94.336h441.216z m0-153.728a47.168 47.168 0 1 1 0 94.4H287.872a47.168 47.168 0 1 1 0-94.4h441.216z"
''' <summary>
''' 图标按钮,信息,1.05x
''' </summary>
Public Const IconButtonInfo As String = "M512 917.333333c223.861333 0 405.333333-181.472 405.333333-405.333333S735.861333 106.666667 512 106.666667 106.666667 288.138667 106.666667 512s181.472 405.333333 405.333333 405.333333z m0 106.666667C229.226667 1024 0 794.773333 0 512S229.226667 0 512 0s512 229.226667 512 512-229.226667 512-512 512z m-32-597.333333h64a21.333333 21.333333 0 0 1 21.333333 21.333333v320a21.333333 21.333333 0 0 1-21.333333 21.333333h-64a21.333333 21.333333 0 0 1-21.333333-21.333333V448a21.333333 21.333333 0 0 1 21.333333-21.333333z m0-192h64a21.333333 21.333333 0 0 1 21.333333 21.333333v64a21.333333 21.333333 0 0 1-21.333333 21.333333h-64a21.333333 21.333333 0 0 1-21.333333-21.333333v-64a21.333333 21.333333 0 0 1 21.333333-21.333333z"
''' <summary>
''' 图标按钮,列表,1x
''' </summary>
Public Const IconButtonList As String = "M384 128h640v128H384zM160 192m-96 0a96 96 0 1 0 192 0 96 96 0 1 0-192 0ZM384 448h640v128H384zM160 512m-96 0a96 96 0 1 0 192 0 96 96 0 1 0-192 0ZM384 768h640v128H384zM160 832m-96 0a96 96 0 1 0 192 0 96 96 0 1 0-192 0Z"
''' <summary>
''' 图标按钮,文件夹,1.15x
''' </summary>
Public Const IconButtonOpen As String = "M889.018182 418.909091H884.363636V316.509091a93.090909 93.090909 0 0 0-99.607272-89.832727h-302.545455l-93.090909-76.334546A46.545455 46.545455 0 0 0 358.865455 139.636364H146.152727A93.090909 93.090909 0 0 0 46.545455 229.469091V837.818182a46.545455 46.545455 0 0 0 46.545454 46.545454 46.545455 46.545455 0 0 0 16.756364-3.258181 109.381818 109.381818 0 0 0 25.134545 3.258181h586.472727a85.178182 85.178182 0 0 0 87.04-63.301818l163.374546-302.545454a46.545455 46.545455 0 0 0 5.585454-21.876364A82.385455 82.385455 0 0 0 889.018182 418.909091z m-744.727273-186.181818h198.283636l93.09091 76.334545a46.545455 46.545455 0 0 0 29.323636 10.705455h319.301818a12.101818 12.101818 0 0 1 6.516364 0V418.909091H302.545455a85.178182 85.178182 0 0 0-87.04 63.301818L139.636364 622.778182V232.727273a19.549091 19.549091 0 0 1 6.516363 0z m578.094546 552.029091a27.461818 27.461818 0 0 0-2.792728 6.516363H154.530909l147.083636-272.290909a27.461818 27.461818 0 0 0 2.792728-6.981818h565.061818z"
''' <summary>
''' 图标按钮,名片,1.1x
''' </summary>
Public Const IconButtonCard As String = "M834.5 684.1c-31.2-70.4-98.9-120.9-179.1-127.3 63.5-8.5 112.6-63 112.6-128.8 0-71.8-58.2-130-130-130s-130 58.2-130 130c0 65.9 49 120.3 112.6 128.8-80.2 6.4-148 57-179.1 127.3-8.7 19.7 6 42 27.6 42 12.1 0 22.7-7.5 27.7-18.5 24.3-53.9 78.5-91.5 141.3-91.5s117 37.6 141.3 91.5c5 11.1 15.6 18.5 27.7 18.5 21.4 0 36.1-22.3 27.4-42zM567.9 427.9c0-38.6 31.4-70 70-70s70 31.4 70 70-31.4 70-70 70-70-31.4-70-70zM460.3 347.9H216.9c-16.6 0-30 13.4-30 30s13.4 30 30 30h243.3c16.6 0 30-13.4 30-30 0.1-16.5-13.4-30-29.9-30zM367.4 459.6H216.9c-16.6 0-30 13.4-30 30s13.4 30 30 30h150.4c16.6 0 30-13.4 30-30 0.1-16.6-13.4-30-29.9-30zM297.4 571.2H217c-16.6 0-30 13.4-30 30s13.4 30 30 30h80.4c16.6 0 30-13.4 30-30 0-16.5-13.5-30-30-30zM900 236v552H124V236h776m0-60H124c-33.1 0-60 26.9-60 60v552c0 33.1 26.9 60 60 60h776c33.1 0 60-26.9 60-60V236c0-33.1-26.9-60-60-60z"
''' <summary>
''' 图标按钮,×,0.85x
''' </summary>
Public Const IconButtonCross As String = "F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z"
''' <summary>
''' 图标按钮,验证,1.1x
''' </summary>
Public Const IconButtonAuth As String = "M511.488256 95.184408c35.310345 22.516742 95.184408 55.78011 167.34033 84.437781 75.738131 29.681159 148.405797 40.93953 191.392304 45.033483v353.615193c0 73.691154-50.662669 164.781609-136.123938 244.101949C649.65917 901.181409 558.568716 942.12094 512 942.12094c-46.568716 0-137.65917-40.93953-222.096952-119.748126C204.441779 742.54073 153.77911 651.450275 153.77911 577.247376v-353.103448c42.474763-4.093953 116.165917-15.352324 191.904048-45.545227 75.226387-30.192904 133.565217-63.456272 165.805098-83.414293M512 0c-4.093953 0-8.187906 1.535232-11.258371 3.582209l-14.84058 10.234882c-1.023488 0.511744-67.550225 47.592204-170.410794 88.531735-100.813593 39.916042-198.556722 41.963018-199.58021 41.963018l-25.075462 0.511744c-10.746627 0.511744-18.934533 8.187906-18.934533 18.422789v414.000999c0 216.97951 286.064968 446.24088 440.09995 446.24088s440.09995-229.261369 440.09995-445.729136V163.758121c0-10.234883-8.69965-18.422789-18.934533-18.422789l-24.563718-0.511744c-1.023488 0-98.766617-2.046977-199.58021-41.963018-103.372314-40.93953-170.410795-88.01999-170.922538-88.531734L523.258371 3.582209c-3.070465-2.558721-7.164418-3.582209-11.258371-3.582209z M743.308346 410.930535l-260.477761 260.477761c-15.864068 15.864068-41.963018 15.864068-57.827087 0l-144.823588-144.823588c-15.864068-15.864068-15.864068-41.963018 0-57.827087 8.187906-8.187906 18.422789-11.770115 29.169415-11.770115 10.234883 0 20.981509 4.093953 29.169416 11.770115l115.654173 115.654173L685.993003 352.591704c15.864068-15.864068 41.963018-15.864068 57.827087 0 15.352324 16.375812 15.352324 42.474763-0.511744 58.338831z"
''' <summary>
''' 图标按钮,第三方
''' </summary>
Public Const IconButtonThirdparty As String = "M865.004 167.069c-10.794-9.687-24.91-15.085-39.579-15.085-1.383 0-2.629 0-4.013 0.139-0.831 0.139-10.102 0.692-24.771 0.692-24.218 0-71.408-1.522-116.107-12.178-57.708-13.7-124.411-77.083-143.785-89.675-9.687-6.227-21.034-9.41-32.244-9.41-11.21 0-22.42 3.182-32.244 9.41-2.353 1.522-72.1 73.484-140.324 89.675-44.699 10.655-92.72 12.178-116.938 12.178-14.53 0-23.941-0.554-24.771-0.692-1.246-0.139-2.629-0.139-3.875-0.139-14.67 0-28.924 5.396-39.717 15.085-11.763 10.655-18.405 25.325-18.405 40.825v140.048c0 517.846 351.089 584.411 366.034 587.040 3.46 0.554 6.782 0.831 10.241 0.831 3.46 0 6.918-0.276 10.241-0.831 14.946-2.629 368.663-69.33 368.663-587.040v-139.911c0.139-15.5-6.642-30.446-18.405-40.962v0zM825.425 348.080c0 476.883-320.783 531.961-320.783 531.961s-318.291-55.078-318.291-531.961v-140.048c0 0 10.933 0.831 28.785 0.831 30.446 0 81.648-2.214 130.777-13.839 80.403-19.098 158.731-97.564 158.731-97.564s81.787 78.466 162.19 97.564c49.129 11.625 99.501 13.839 129.946 13.839 17.714 0 28.785-0.831 28.785-0.831l-0.139 140.048zM463.405 491.173z M349.925 603.958l66.841-15.085c10.102 54.663 40.962 81.925 92.72 81.925 57.43-1.383 87.045-29.476 88.429-84.14 0-50.373-35.289-75.421-105.728-75.421-17.299 0-30.998 0-40.962 0v-51.757c10.102 0 20.757 0 32.382 0 66.149 0 99.916-25.187 101.3-75.421-1.383-45.945-26.571-69.747-75.421-71.132-48.85 0-77.635 26.571-86.215 79.85l-64.766-15.085c18.683-76.252 70.438-114.308 155.27-114.308 87.738 2.906 134.373 40.962 140.187 114.308-1.383 53.279-30.998 87.738-88.429 103.514 63.244 13.008 97.009 49.542 101.3 110.019-4.29 81.925-56.878 124.411-157.486 127.316-87.461 1.246-140.739-36.811-159.422-114.585z"
''' <summary>
''' 图标按钮,用户,0.95x
''' </summary>
Public Const IconButtonUser As String = "M660.338 528.065c63.61-46.825 105.131-121.964 105.131-206.83 0-141.7-115.29-256.987-256.997-256.987-141.706 0-256.998 115.288-256.998 256.987 0 85.901 42.52 161.887 107.456 208.562-152.1 59.92-260.185 207.961-260.185 381.077 0 21.276 17.253 38.53 38.53 38.53 21.278 0 38.53-17.254 38.53-38.53 0-183.426 149.232-332.671 332.667-332.671 1.589 0 3.113-0.207 4.694-0.244 0.8 0.056 1.553 0.244 2.362 0.244 183.434 0 332.664 149.245 332.664 332.671 0 21.276 17.255 38.53 38.533 38.53 21.277 0 38.53-17.254 38.53-38.53 0-174.885-110.354-324.13-264.917-382.809z m-331.803-206.83c0-99.22 80.72-179.927 179.935-179.927s179.937 80.708 179.937 179.927c0 99.203-80.721 179.91-179.937 179.91s-179.935-80.708-179.935-179.91z"
''' <summary>
''' 图标按钮,盾牌,1x
''' </summary>
Public Const IconButtonShield As String = "M511.488256 95.184408c35.310345 22.516742 95.184408 55.78011 167.34033 84.437781 75.738131 29.681159 148.405797 40.93953 191.392304 45.033483v353.615193c0 73.691154-50.662669 164.781609-136.123938 244.101949C649.65917 901.181409 558.568716 942.12094 512 942.12094c-46.568716 0-137.65917-40.93953-222.096952-119.748126C204.441779 742.54073 153.77911 651.450275 153.77911 577.247376v-353.103448c42.474763-4.093953 116.165917-15.352324 191.904048-45.545227 75.226387-30.192904 133.565217-63.456272 165.805098-83.414293M512 0c-4.093953 0-8.187906 1.535232-11.258371 3.582209l-14.84058 10.234882c-1.023488 0.511744-67.550225 47.592204-170.410794 88.531735-100.813593 39.916042-198.556722 41.963018-199.58021 41.963018l-25.075462 0.511744c-10.746627 0.511744-18.934533 8.187906-18.934533 18.422789v414.000999c0 216.97951 286.064968 446.24088 440.09995 446.24088s440.09995-229.261369 440.09995-445.729136V163.758121c0-10.234883-8.69965-18.422789-18.934533-18.422789l-24.563718-0.511744c-1.023488 0-98.766617-2.046977-199.58021-41.963018-103.372314-40.93953-170.410795-88.01999-170.922538-88.531734L523.258371 3.582209c-3.070465-2.558721-7.164418-3.582209-11.258371-3.582209z M743.308346 410.930535l-260.477761 260.477761c-15.864068 15.864068-41.963018 15.864068-57.827087 0l-144.823588-144.823588c-15.864068-15.864068-15.864068-41.963018 0-57.827087 8.187906-8.187906 18.422789-11.770115 29.169415-11.770115 10.234883 0 20.981509 4.093953 29.169416 11.770115l115.654173 115.654173L685.993003 352.591704c15.864068-15.864068 41.963018-15.864068 57.827087 0 15.352324 16.375812 15.352324 42.474763-0.511744 58.338831z"
''' <summary>
''' 图标按钮,离线,0.85x
''' </summary>
Public Const IconButtonOffline As String = "M533.293176 788.841412a60.235294 60.235294 0 1 1 85.202824 85.202823l-42.616471 42.586353c-129.355294 129.385412-339.124706 129.385412-468.510117 0-129.385412-129.385412-129.385412-339.124706 0-468.510117l42.586353-42.616471a60.235294 60.235294 0 1 1 85.202823 85.202824l-42.61647 42.586352a210.823529 210.823529 0 1 0 298.164706 298.164706l42.586352-42.61647z m255.548236-255.548236l42.61647-42.586352a210.823529 210.823529 0 1 0-298.164706-298.164706l-42.586352 42.61647a60.235294 60.235294 0 1 1-85.202824-85.202823l42.616471-42.586353c129.355294-129.385412 339.124706-129.385412 468.510117 0 129.385412 129.385412 129.385412 339.124706 0 468.510117l-42.586353 42.616471a60.235294 60.235294 0 1 1-85.202823-85.202824zM192.542118 192.542118a60.235294 60.235294 0 0 1 85.202823 0l553.712941 553.712941a60.235294 60.235294 0 0 1-85.202823 85.202823L192.542118 277.744941a60.235294 60.235294 0 0 1 0-85.202823z"
''' <summary>
''' 图标,服务端,1x
''' </summary>
Public Const IconButtonServer As String = "M224 160a64 64 0 0 0-64 64v576a64 64 0 0 0 64 64h576a64 64 0 0 0 64-64V224a64 64 0 0 0-64-64H224z m0 384h576v256H224v-256z m192 96v64h320v-64H416z m-128 0v64h64v-64H288zM224 224h576v256H224V224z m192 96v64h320v-64H416z m-128 0v64h64v-64H288z"
''' <summary>
''' 图标按钮,复制
''' </summary>
Public Const IconButtonCopy As String = "M394.666667 106.666667h448a74.666667 74.666667 0 0 1 74.666666 74.666666v448a74.666667 74.666667 0 0 1-74.666666 74.666667H394.666667a74.666667 74.666667 0 0 1-74.666667-74.666667V181.333333a74.666667 74.666667 0 0 1 74.666667-74.666666z m0 64a10.666667 10.666667 0 0 0-10.666667 10.666666v448a10.666667 10.666667 0 0 0 10.666667 10.666667h448a10.666667 10.666667 0 0 0 10.666666-10.666667V181.333333a10.666667 10.666667 0 0 0-10.666666-10.666666H394.666667z m245.333333 597.333333a32 32 0 0 1 64 0v74.666667a74.666667 74.666667 0 0 1-74.666667 74.666666H181.333333a74.666667 74.666667 0 0 1-74.666666-74.666666V394.666667a74.666667 74.666667 0 0 1 74.666666-74.666667h74.666667a32 32 0 0 1 0 64h-74.666667a10.666667 10.666667 0 0 0-10.666666 10.666667v448a10.666667 10.666667 0 0 0 10.666666 10.666666h448a10.666667 10.666667 0 0 0 10.666667-10.666666v-74.666667z"
''' <summary>
''' 图标按钮,外链
''' </summary>
Public Const IconButtonlink As String = "M433.230769 74.830769a43.323077 43.323077 0 0 1 0 86.646154l-236.307692 0.157539a35.446154 35.446154 0 0 0-35.446154 35.446153v630.153847a35.446154 35.446154 0 0 0 35.446154 35.446153h630.153846a35.446154 35.446154 0 0 0 35.446154-35.446153V590.769231a43.323077 43.323077 0 1 1 86.646154 0v236.425846a122.092308 122.092308 0 0 1-122.092308 122.092308H196.923077a122.092308 122.092308 0 0 1-122.092308-122.092308v-630.153846a122.092308 122.092308 0 0 1 122.092308-122.092308z m452.923077 0a63.015385 63.015385 0 0 1 63.015385 63.015385V354.461538a43.323077 43.323077 0 0 1-43.323077 43.323077l-4.726154-0.236307A43.323077 43.323077 0 0 1 862.523077 354.461538l-0.039385-131.702153-287.074461 287.15323-90.072616 90.072616a43.323077 43.323077 0 1 1-61.243077-61.243077l90.033231-90.072616 287.113846-287.192615H669.538462a43.323077 43.323077 0 0 1-43.08677-38.596923L626.215385 118.153846A43.323077 43.323077 0 0 1 669.538462 74.830769z"
''' <summary>
''' 图标,音符,1x
''' </summary>
Public Const IconMusic As String = "M348.293565 716.53287V254.797913c0-41.672348 28.004174-78.358261 68.919652-90.37913L815.994435 40.826435c62.775652-18.610087 125.907478 26.579478 125.907478 89.933913v539.158261c8.013913 42.25113-8.94887 89.177043-47.014956 127.109565a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c21.014261 1.024 40.514783 5.164522 57.878261 12.065391V233.338435c0-12.109913-10.551652-20.034783-20.569044-20.034783a24.620522 24.620522 0 0 0-5.787826 0.934957L439.785739 338.18713a19.545043 19.545043 0 0 0-14.825739 19.144348v438.984348H423.846957c11.53113 43.987478-5.164522 94.208-45.412174 134.322087a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c20.791652 1.024 40.069565 5.075478 57.299478 11.842783z"
''' <summary>
''' 图标,播放,0.8x
''' </summary>
Public Const IconPlay As String = "M803.904 463.936a55.168 55.168 0 0 1 0 96.128l-463.616 264.448C302.848 845.888 256 819.136 256 776.448V247.616c0-42.752 46.848-69.44 84.288-48.064l463.616 264.384z"
''' <summary>
''' 图标,创建,0.9x
''' </summary>
Public Const IconButtonCreate As String = "F1 M 4 2 C 2.35499 2 1 3.35499 1 5 v 13 c 0 1.64501 1.35499 3 3 3 h 16 c 1.64501 0 3 -1.35499 3 -3 V 8 C 23 6.35499 21.645 5 20 5 h -7.90039 a 1.0001 1.0001 0 0 0 -0.0098 0 C 11.7487 5.00334 11.4337 4.83568 11.2461 4.55078 a 1.0001 1.0001 0 0 0 -0.0078 -0.00977 L 10.4355 3.34961 C 9.88132 2.50803 8.93736 2.00017 7.92969 2 Z m 0 2 h 3.92969 c 0.337496 5.56e-05 0.650315 0.167354 0.835938 0.449219 a 1.0001 1.0001 0 0 0 0.00586 0.00977 l 0.802734 1.19141 c 0.000794 0.00121 0.00311 0.0007486 0.00391 0.00195 C 10.1385 6.50064 11.0926 7.00997 12.1094 7 H 20 c 0.564129 0 1 0.435871 1 1 v 10 c 0 0.564129 -0.435871 1 -1 1 H 4 C 3.43587 19 3 18.5641 3 18 V 5 C 3 4.43587 3.43587 4 4 4 Z m 5 8 a 1 1 0 0 0 -1 1 a 1 1 0 0 0 1 1 h 6 a 1 1 0 0 0 1 -1 a 1 1 0 0 0 -1 -1 z m 3 -3 a 1 1 0 0 0 -1 1 v 6 a 1 1 0 0 0 1 1 a 1 1 0 0 0 1 -1 V 10 A 1 1 0 0 0 12 9 Z"
''' <summary>
''' 图标,分享,1x
''' </summary>
Public Const IconButtonShare As String = "F1 M 14.9062 5.64648 L 8.08594 9.62695 A 1 1 0 0 0 7.72656 10.9941 A 1 1 0 0 0 9.09375 11.3535 L 15.9141 7.37305 A 1 1 0 0 0 16.2734 6.00586 A 1 1 0 0 0 14.9062 5.64648 Z m -5.8125 7 a 1 1 0 0 0 -1.36719 0.359375 a 1 1 0 0 0 0.359375 1.36719 l 6.83008 3.98047 a 1 1 0 0 0 1.36719 -0.359375 a 1 1 0 0 0 -0.359375 -1.36719 z M 18 15 c -2.19729 0 -4 1.80271 -4 4 c 0 2.19729 1.80271 4 4 4 c 2.19729 0 4 -1.80271 4 -4 c 0 -2.19729 -1.80271 -4 -4 -4 z m 0 2 c 1.11641 0 2 0.883586 2 2 c 0 1.11641 -0.883586 2 -2 2 c -1.11641 0 -2 -0.883586 -2 -2 c 0 -1.11641 0.883586 -2 2 -2 z M 6 8 c -2.19729 0 -4 1.80271 -4 4 c 0 2.19729 1.80271 4 4 4 c 2.19729 0 4 -1.80271 4 -4 C 10 9.80271 8.19729 8 6 8 Z m 0 2 c 1.11641 0 2 0.883586 2 2 c 0 1.11641 -0.883586 2 -2 2 C 4.88359 14 4 13.1164 4 12 C 4 10.8836 4.88359 10 6 10 Z M 18 1 c -2.19729 0 -4 1.80271 -4 4 c 0 2.19729 1.80271 4 4 4 c 2.19729 0 4 -1.80271 4 -4 c 0 -2.19729 -1.80271 -4 -4 -4 z m 0 2 c 1.11641 0 2 0.883586 2 2 c 0 1.11641 -0.883586 2 -2 2 c -1.11641 0 -2 -0.883586 -2 -2 c 0 -1.11641 0.883586 -2 2 -2 z"
''' <summary>
''' 图标,添加,1x
''' </summary>
Public Const IconButtonAdd As String = "F1 m 12 7 a 1 1 0 0 0 -1 1 v 8 a 1 1 0 0 0 1 1 a 1 1 0 0 0 1 -1 V 8 A 1 1 0 0 0 12 7 Z m -4 4 a 1 1 0 0 0 -1 1 a 1 1 0 0 0 1 1 h 8 a 1 1 0 0 0 1 -1 a 1 1 0 0 0 -1 -1 z M 12 1 C 5.93671 1 1 5.93671 1 12 C 1 18.0633 5.93671 23 12 23 C 18.0633 23 23 18.0633 23 12 C 23 5.93671 18.0633 1 12 1 Z m 0 2 c 4.98241 0 9 4.01759 9 9 c 0 4.98241 -4.01759 9 -9 9 C 7.01759 21 3 16.9824 3 12 C 3 7.01759 7.01759 3 12 3 Z"
''' <summary>
''' 图标,开始游戏,1x
''' </summary>
Public Const IconPlayGame As String = "M213.333333 65.386667a85.333333 85.333333 0 0 1 43.904 12.16L859.370667 438.826667a85.333333 85.333333 0 0 1 0 146.346666L257.237333 946.453333A85.333333 85.333333 0 0 1 128 873.28V150.72a85.333333 85.333333 0 0 1 85.333333-85.333333z m0 64a21.333333 21.333333 0 0 0-21.184 18.837333L192 150.72v722.56a21.333333 21.333333 0 0 0 30.101333 19.456l2.197334-1.152L826.453333 530.282667a21.333333 21.333333 0 0 0 2.048-35.178667l-2.048-1.386667L224.298667 132.416A21.333333 21.333333 0 0 0 213.333333 129.386667z"
Public Const IconButtonEnable As String = "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"
Public Const IconButtonDisable As String = "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z"
End Class
#End Region
#Region "自定义类"
''' <summary>
''' 支持小数与常见类型隐式转换的颜色。
''' </summary>
Public Class MyColor
Public A As Double = 255
Public R As Double = 0
Public G As Double = 0
Public B As Double = 0
'类型转换
Public Shared Widening Operator CType(str As String) As MyColor
Return New MyColor(str)
End Operator
Public Shared Widening Operator CType(col As Color) As MyColor
Return New MyColor(col)
End Operator
Public Shared Widening Operator CType(conv As MyColor) As Color
Return Color.FromArgb(MathByte(conv.A), MathByte(conv.R), MathByte(conv.G), MathByte(conv.B))
End Operator
Public Shared Widening Operator CType(conv As MyColor) As System.Drawing.Color
Return System.Drawing.Color.FromArgb(MathByte(conv.A), MathByte(conv.R), MathByte(conv.G), MathByte(conv.B))
End Operator
Public Shared Widening Operator CType(bru As SolidColorBrush) As MyColor
Return New MyColor(bru.Color)
End Operator
Public Shared Widening Operator CType(conv As MyColor) As SolidColorBrush
Return New SolidColorBrush(Color.FromArgb(MathByte(conv.A), MathByte(conv.R), MathByte(conv.G), MathByte(conv.B)))
End Operator
Public Shared Widening Operator CType(bru As Brush) As MyColor
Return New MyColor(bru)
End Operator
Public Shared Widening Operator CType(conv As MyColor) As Brush
Return New SolidColorBrush(Color.FromArgb(MathByte(conv.A), MathByte(conv.R), MathByte(conv.G), MathByte(conv.B)))
End Operator
'颜色运算
Public Shared Operator +(a As MyColor, b As MyColor) As MyColor
Return New MyColor With {.A = a.A + b.A, .B = a.B + b.B, .G = a.G + b.G, .R = a.R + b.R}
End Operator
Public Shared Operator -(a As MyColor, b As MyColor) As MyColor
Return New MyColor With {.A = a.A - b.A, .B = a.B - b.B, .G = a.G - b.G, .R = a.R - b.R}
End Operator
Public Shared Operator *(a As MyColor, b As Double) As MyColor
Return New MyColor With {.A = a.A * b, .B = a.B * b, .G = a.G * b, .R = a.R * b}
End Operator
Public Shared Operator /(a As MyColor, b As Double) As MyColor
Return New MyColor With {.A = a.A / b, .B = a.B / b, .G = a.G / b, .R = a.R / b}
End Operator
Public Shared Operator =(a As MyColor, b As MyColor) As Boolean
If IsNothing(a) AndAlso IsNothing(b) Then Return True
If IsNothing(a) OrElse IsNothing(b) Then Return False
Return a.A = b.A AndAlso a.R = b.R AndAlso a.G = b.G AndAlso a.B = b.B
End Operator
Public Shared Operator <>(a As MyColor, b As MyColor) As Boolean
If IsNothing(a) AndAlso IsNothing(b) Then Return False
If IsNothing(a) OrElse IsNothing(b) Then Return True
Return Not (a.A = b.A AndAlso a.R = b.R AndAlso a.G = b.G AndAlso a.B = b.B)
End Operator
'构造函数
Public Sub New()
End Sub
Public Sub New(col As Color)
Me.A = col.A
Me.R = col.R
Me.G = col.G
Me.B = col.B
End Sub
Public Sub New(HexString As String)
Dim StringColor As Media.Color = ColorConverter.ConvertFromString(HexString)
A = StringColor.A
R = StringColor.R
G = StringColor.G
B = StringColor.B
End Sub
Public Sub New(newA As Double, col As MyColor)
Me.A = newA
Me.R = col.R
Me.G = col.G
Me.B = col.B
End Sub
Public Sub New(newR As Double, newG As Double, newB As Double)
Me.A = 255
Me.R = newR
Me.G = newG
Me.B = newB
End Sub
Public Sub New(newA As Double, newR As Double, newG As Double, newB As Double)
Me.A = newA
Me.R = newR
Me.G = newG
Me.B = newB
End Sub
Public Sub New(brush As Brush)
Dim Color As Color = CType(brush, SolidColorBrush).Color
A = Color.A
R = Color.R
G = Color.G
B = Color.B
End Sub
Public Sub New(brush As SolidColorBrush)
Dim Color As Color = brush.Color
A = Color.A
R = Color.R
G = Color.G
B = Color.B
End Sub
Public Sub New(obj As Object)
If obj Is Nothing Then
A = 255 : R = 255 : G = 255 : B = 255
Else
If TypeOf obj Is SolidColorBrush Then
'避免反复获取 Color 对象造成性能下降
Dim Color As Color = CType(obj, SolidColorBrush).Color
A = Color.A
R = Color.R
G = Color.G
B = Color.B
Else
A = obj.A
R = obj.R
G = obj.G
B = obj.B
End If
End If
End Sub
'HSL
Public Function Hue(v1 As Double, v2 As Double, vH As Double) As Double
If vH < 0 Then vH += 1
If vH > 1 Then vH -= 1
If vH < 0.16667 Then Return v1 + (v2 - v1) * 6 * vH
If vH < 0.5 Then Return v2
If vH < 0.66667 Then Return v1 + (v2 - v1) * (4 - vH * 6)
Return v1
End Function
Public Function FromHSL(sH As Double, sS As Double, sL As Double) As MyColor
If sS = 0 Then
R = sL * 2.55
G = R
B = R
Else
Dim H = sH / 360
Dim S = sS / 100
Dim L = sL / 100
S = If(L < 0.5, S * L + L, S * (1.0 - L) + L)
L = 2 * L - S
R = 255 * Hue(L, S, H + 1 / 3)
G = 255 * Hue(L, S, H)
B = 255 * Hue(L, S, H - 1 / 3)
End If
A = 255
Return Me
End Function
Public Function FromHSL2(sH As Double, sS As Double, sL As Double) As MyColor
If sS = 0 Then
R = sL * 2.55 : G = R : B = R
Else
'初始化
sH = (sH + 3600000) Mod 360
Dim cent As Double() = {
+0.1, -0.06, -0.3, '0, 30, 60
-0.19, -0.15, -0.24, '90, 120, 150
-0.32, -0.09, +0.18, '180, 210, 240
+0.05, -0.12, -0.02, '270, 300, 330
+0.1, -0.06} '最后两位与前两位一致,加是变亮,减是变暗
'计算色调对应的亮度片区
Dim center As Double = sH / 30.0
Dim intCenter As Integer = Math.Floor(center) '亮度片区编号
center = 50 - (
(1 - center + intCenter) * cent(intCenter) + (center - intCenter) * cent(intCenter + 1)
) * sS
'center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS
sL = If(sL < center, sL / center, 1 + (sL - center) / (100 - center)) * 50
FromHSL(sH, sS, sL)
End If
A = 255
Return Me
End Function
Public Function Alpha(sA As Double) As MyColor
A = sA
Return Me
End Function
Public Overrides Function ToString() As String
Return "(" & A & "," & R & "," & G & "," & B & ")"
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return Me = obj
End Function
End Class
''' <summary>
''' 支持负数与浮点数的矩形。
''' </summary>
Public Class MyRect
'属性
Public Property Width As Double = 0
Public Property Height As Double = 0
Public Property Left As Double = 0
Public Property Top As Double = 0
'构造函数
Public Sub New()
End Sub
Public Sub New(left As Double, top As Double, width As Double, height As Double)
Me.Left = left
Me.Top = top
Me.Width = width
Me.Height = height
End Sub
End Class
''' <summary>
''' 模块加载状态枚举。
''' </summary>
Public Enum LoadState
Waiting
Loading
Finished
Failed
Aborted
End Enum
''' <summary>
''' 执行返回值。
''' </summary>
Public Enum ProcessReturnValues
''' <summary>
''' 执行成功,或进程被中断。
''' </summary>
Aborted = -1
''' <summary>
''' 执行成功。
''' </summary>
Success = 0
''' <summary>
''' 执行失败。
''' </summary>
Fail = 1
''' <summary>
''' 执行时出现未经处理的异常。
''' </summary>
Exception = 2
''' <summary>
''' 执行超时。
''' </summary>
Timeout = 3
''' <summary>
''' 取消执行。可能是由于不满足执行的前置条件。
''' </summary>
Cancel = 4
''' <summary>
''' 任务成功完成。
''' </summary>
TaskDone = 5
End Enum
''' <summary>
''' 可以使用 Equals 和等号的 List。
''' </summary>
Public Class EqualableList(Of T)
Inherits List(Of T)
Public Overrides Function Equals(obj As Object) As Boolean
If TryCast(obj, List(Of T)) Is Nothing Then
'类型不同
Return False
Else
'类型相同
Dim objList As List(Of T) = obj
If objList.Count <> Count Then Return False
For i = 0 To objList.Count - 1
If Not objList(i).Equals(Me(i)) Then Return False
Next
Return True
End If
End Function
Public Shared Operator =(left As EqualableList(Of T), right As EqualableList(Of T)) As Boolean
Return EqualityComparer(Of EqualableList(Of T)).Default.Equals(left, right)
End Operator
Public Shared Operator <>(left As EqualableList(Of T), right As EqualableList(Of T)) As Boolean
Return Not left = right
End Operator
End Class
#End Region
#Region "数学"
''' <summary>
''' 2~65 进制的转换。
''' </summary>
Public Function RadixConvert(Input As String, FromRadix As Integer, ToRadix As Integer) As String
Const Digits As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="
'零与负数的处理
If String.IsNullOrEmpty(Input) Then Return "0"
Dim IsNegative As Boolean = Input.StartsWithF("-")
If IsNegative Then Input = Input.TrimStart("-")
'转换为十进制
Dim RealNum As Long = 0, Scale As Long = 1
For Each Digit In Input.Reverse.Select(Function(l) Digits.IndexOfF(l))
RealNum += Digit * Scale
Scale *= FromRadix
Next
'转换为指定进制
Dim Result = ""
While RealNum > 0
Dim NewNum As Integer = RealNum Mod ToRadix
RealNum = (RealNum - NewNum) / ToRadix
Result = Digits(NewNum) & Result
End While
'负数的结束处理与返回
Return If(IsNegative, "-", "") & Result
End Function
''' <summary>
''' 计算二阶贝塞尔曲线。
''' </summary>
Public Function MathBezier(x As Double, x1 As Double, y1 As Double, x2 As Double, y2 As Double, Optional acc As Double = 0.01) As Double
If x <= 0 OrElse Double.IsNaN(x) Then Return 0
If x >= 1 Then Return 1
Dim a, b
a = x
Do
b = 3 * a * ((0.33333333 + x1 - x2) * a * a + (x2 - 2 * x1) * a + x1)
a += (x - b) * 0.5
Loop Until Math.Abs(b - x) < acc '精度
Return 3 * a * ((0.33333333 + y1 - y2) * a * a + (y2 - 2 * y1) * a + y1)
End Function
''' <summary>
''' 将一个数字限制为 0~255 的 Byte 值。
''' </summary>
Public Function MathByte(d As Double) As Byte
If d < 0 Then d = 0
If d > 255 Then d = 255
Return Math.Round(d)
End Function
''' <summary>
''' 提供 MyColor 类型支持的 Math.Round。
''' </summary>
Public Function MathRound(col As MyColor, Optional w As Integer = 0) As MyColor
Return New MyColor With {.A = Math.Round(col.A, w), .R = Math.Round(col.R, w), .G = Math.Round(col.G, w), .B = Math.Round(col.B, w)}
End Function
''' <summary>
''' 获取两数间的百分比。小数点精确到 6 位。
''' </summary>
''' <returns></returns>
Public Function MathPercent(ValueA As Double, ValueB As Double, Percent As Double) As Double
Return Math.Round(ValueA * (1 - Percent) + ValueB * Percent, 6) '解决 Double 计算错误
End Function
''' <summary>
''' 获取两颜色间的百分比,根据 RGB 计算。小数点精确到 6 位。
''' </summary>
Public Function MathPercent(ValueA As MyColor, ValueB As MyColor, Percent As Double) As MyColor
Return MathRound(ValueA * (1 - Percent) + ValueB * Percent, 6) '解决Double计算错误
End Function
''' <summary>
''' 将数值限定在某个范围内。
''' </summary>
Public Function MathClamp(value As Double, min As Double, max As Double) As Double
Return Math.Max(min, Math.Min(max, value))
End Function
''' <summary>
''' 符号函数。
''' </summary>
Public Function MathSgn(Value As Double) As Integer
If Value = 0 Then
Return 0
ElseIf Value > 0 Then
Return 1
Else
Return -1
End If
End Function
#End Region
#Region "文件"
'=============================
' 注册表
'=============================
''' <summary>
''' 重命名一个注册表子键。不可用于包含子键的子键。
''' </summary>
Public Sub RenameReg(parentKey As Microsoft.Win32.RegistryKey, subKeyName As String, newSubKeyName As String)
If parentKey.GetSubKeyNames().Contains(newSubKeyName) Then parentKey.DeleteSubKeyTree(newSubKeyName, False)
Dim SourceKey As Microsoft.Win32.RegistryKey = parentKey.OpenSubKey(subKeyName)
If IsNothing(SourceKey) Then Exit Sub '没有目标项
Dim NewKey As Microsoft.Win32.RegistryKey = parentKey.CreateSubKey(newSubKeyName)
If SourceKey.GetSubKeyNames().Length > 0 Then Throw New NotSupportedException("不支持对包含子键的子键进行重命名:" & SourceKey.GetSubKeyNames()(0) & "。")
For Each valueName As String In SourceKey.GetValueNames()
Dim objValue As Object = SourceKey.GetValue(valueName)
Dim valKind As Microsoft.Win32.RegistryValueKind = SourceKey.GetValueKind(valueName)
NewKey.SetValue(valueName, objValue, valKind)
Next
parentKey.DeleteSubKeyTree(subKeyName, False)
End Sub
''' <summary>
''' 读取注册表,默认为程序所属。
''' </summary>
Public Function ReadReg(Key As String, Optional DefaultValue As String = "", Optional Path As String = "") As String
Try
Dim parentKey As RegistryKey, softKey As RegistryKey
parentKey = Registry.CurrentUser
softKey = parentKey.OpenSubKey("Software\" & If(Path = "", RegFolder, Path), True)
If softKey Is Nothing Then
ReadReg = DefaultValue '不存在则返回默认值
Else
Dim readValue As New Text.StringBuilder
readValue.AppendLine(softKey.GetValue(Key))
Dim value = readValue.ToString.Replace(vbCrLf, "") '去除莫名的回车
Return If(value = "", DefaultValue, value) '错误则返回默认值
End If
Catch ex As Exception
Log(ex, "读取注册表出错:" & Key, LogLevel.Hint)
Return DefaultValue
End Try
End Function
''' <summary>
''' 写入注册表,默认为程序所属。
''' </summary>
Public Sub WriteReg(Key As String, Value As String, Optional ShowException As Boolean = False, Optional Path As String = "", Optional ThrowException As Boolean = False)
Try
Dim parentKey As RegistryKey, softKey As RegistryKey
parentKey = Registry.CurrentUser
softKey = parentKey.OpenSubKey("Software\" & If(Path = "", RegFolder, Path), True)
If softKey Is Nothing Then softKey = parentKey.CreateSubKey("Software\" & If(Path = "", RegFolder, Path)) '如果不存在就创建
softKey.SetValue(Key, Value)
Catch ex As Exception
Log(ex, "写入注册表出错:" & Key, If(ThrowException, LogLevel.Hint, LogLevel.Developer))
If ThrowException Then Throw
End Try
End Sub
''' <summary>
''' 是否存在某个注册表键。
''' </summary>
Public Function HasReg(Key As String) As Boolean
Return ReadReg(Key, Nothing) IsNot Nothing
End Function
''' <summary>
''' 删除注册表键。
''' </summary>
Public Sub DeleteReg(Key As String, Optional ThrowException As Boolean = False)
Try
Dim SubKey As Microsoft.Win32.RegistryKey = Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, True)
SubKey?.DeleteValue(Key)
Catch ex As Exception
Log(ex, "删除注册表出错:" & Key, If(ThrowException, LogLevel.Hint, LogLevel.Developer))
If ThrowException Then Throw
End Try
End Sub
'=============================
' ini
'=============================
Private ReadOnly IniCache As New SafeDictionary(Of String, SafeDictionary(Of String, String))
''' <summary>
''' 清除某 ini 文件的运行时缓存。
''' </summary>
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
Public Sub IniClearCache(FileName As String)
If Not FileName.Contains(":\") Then FileName = $"{ExePath}PCL\{FileName}.ini"
If IniCache.ContainsKey(FileName) Then IniCache.Remove(FileName)
End Sub
''' <summary>
''' 获取 ini 文件缓存。如果没有,则新读取 ini 文件内容。
''' 在文件不存在或读取失败时返回 Nothing。
''' </summary>
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
Private Function IniGetContent(FileName As String) As SafeDictionary(Of String, String)
Try
'还原文件路径
If Not FileName.Contains(":\") Then FileName = $"{ExePath}PCL\{FileName}.ini"
'检索缓存
If IniCache.ContainsKey(FileName) Then Return IniCache(FileName)
'读取文件
If Not File.Exists(FileName) Then Return Nothing
Dim Ini As New SafeDictionary(Of String, String)
For Each Line In ReadFile(FileName).Split(vbCrLf.ToArray(), StringSplitOptions.RemoveEmptyEntries)
Dim Index As Integer = Line.IndexOfF(":")
If Index > 0 Then Ini(Line.Substring(0, Index)) = Line.Substring(Index + 1) '可能会有重复键,见 #3616
Next
IniCache(FileName) = Ini
Return Ini
Catch ex As Exception
Log(ex, $"生成 ini 文件缓存失败({FileName})", LogLevel.Hint)
Return Nothing
End Try
End Function
''' <summary>
''' 读取 ini 文件。这可能会使用到缓存。
''' </summary>
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
''' <param name="Key">键。</param>
''' <param name="DefaultValue">没有找到键时返回的默认值。</param>
Public Function ReadIni(FileName As String, Key As String, Optional DefaultValue As String = "") As String
Dim Content = IniGetContent(FileName)
If Content Is Nothing OrElse Not Content.ContainsKey(Key) Then Return DefaultValue
Return Content(Key)
End Function
''' <summary>
''' 判断 ini 文件中是否包含某个键。这可能会使用到缓存。
''' </summary>
Public Function HasIniKey(FileName As String, Key As String) As Boolean
Dim Content = IniGetContent(FileName)
Return Content IsNot Nothing AndAlso Content.ContainsKey(Key)
End Function
''' <summary>
''' 从 ini 文件中移除某个键。这会更新缓存。
''' </summary>
Public Sub DeleteIniKey(FileName As String, Key As String)
WriteIni(FileName, Key, Nothing)
End Sub
''' <summary>
''' 写入 ini 文件,这会更新缓存。
''' 若 Value 为 Nothing,则删除该键。
''' </summary>
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
''' <param name="Key">键。</param>
''' <param name="Value">值。</param>
''' <remarks></remarks>
Public Sub WriteIni(FileName As String, Key As String, Value As String)
Try
'预处理
If Key.Contains(":") Then Throw New Exception($"尝试写入 ini 文件 {FileName} 的键名中包含了冒号:{Key}")
Key = Key.Replace(vbCr, "").Replace(vbLf, "")
Value = Value?.Replace(vbCr, "").Replace(vbLf, "")
'防止争用
SyncLock WriteIniLock
'获取目前文件
Dim Content As SafeDictionary(Of String, String) = IniGetContent(FileName)
If Content Is Nothing Then Content = New SafeDictionary(Of String, String)
'更新值
If Value Is Nothing Then
If Not Content.ContainsKey(Key) Then Return '无需处理
Content.Remove(Key)
Else
If Content.ContainsKey(Key) AndAlso Content(Key) = Value Then Return '无需处理
Content(Key) = Value
End If
'写入文件
Dim FileContent As New StringBuilder
For Each Pair In Content
FileContent.Append(Pair.Key)
FileContent.Append(":")
FileContent.Append(Pair.Value)
FileContent.Append(vbCrLf)
Next
If Not FileName.Contains(":\") Then FileName = $"{ExePath}PCL\{FileName}.ini"
WriteFile(FileName, FileContent.ToString)
End SyncLock
Catch ex As Exception
Log(ex, $"写入文件失败({FileName} → {Key}:{Value})", LogLevel.Hint)
End Try
End Sub
Private WriteIniLock As New Object
'路径处理
''' <summary>
''' 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。
''' 取决于原路径格式,路径以 / 或 \ 结尾。
''' 不包含路径将会抛出异常。
''' </summary>
Public Function GetPathFromFullPath(FilePath As String) As String
If Not (FilePath.Contains("\") OrElse FilePath.Contains("/")) Then Throw New Exception("不包含路径:" & FilePath)
If FilePath.EndsWithF("\") OrElse FilePath.EndsWithF("/") Then
'是文件夹路径
Dim IsRight As Boolean = FilePath.EndsWithF("\")
FilePath = Left(FilePath, Len(FilePath) - 1)
GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"})) & If(IsRight, "\", "/")
Else
'是文件路径
GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"}) + 1)
If GetPathFromFullPath = "" Then Throw New Exception("不包含路径:" & FilePath)
End If
End Function
''' <summary>
''' 从文件路径或者 Url 获取不包含路径的文件名。不包含文件名将会抛出异常。
''' </summary>
Public Function GetFileNameFromPath(FilePath As String) As String
FilePath = FilePath.Replace("/", "\")
If FilePath.EndsWithF("\") Then Throw New Exception("不包含文件名:" & FilePath)
If FilePath.Contains("?") Then FilePath = FilePath.Substring(0, FilePath.IndexOfF("?")) '去掉网络参数后的 ?
If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1)
Dim length As Integer = FilePath.Length
If length = 0 Then Throw New Exception("不包含文件名:" & FilePath)
If length > 250 Then Throw New PathTooLongException("文件名过长:" & FilePath)
Return FilePath
End Function
''' <summary>
''' 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。
''' </summary>
Public Function GetFileNameWithoutExtentionFromPath(FilePath As String) As String
Return IO.Path.GetFileNameWithoutExtension(FilePath)
End Function
''' <summary>
''' 从文件夹路径获取文件夹名。
''' </summary>
Public Function GetFolderNameFromPath(FolderPath As String) As String
If FolderPath.EndsWithF(":\") OrElse FolderPath.EndsWithF(":\\") Then Return FolderPath.Substring(0, 1)
If FolderPath.EndsWithF("\") OrElse FolderPath.EndsWithF("/") Then FolderPath = Left(FolderPath, FolderPath.Length - 1)
Return GetFileNameFromPath(FolderPath)
End Function
'读取、写入、复制文件
''' <summary>
''' 复制文件。会自动创建文件夹、会覆盖已有的文件。
''' </summary>
Public Sub CopyFile(FromPath As String, ToPath As String)
Try
'还原文件路径
If Not FromPath.Contains(":\") Then FromPath = ExePath & FromPath
If Not ToPath.Contains(":\") Then ToPath = ExePath & ToPath
'如果复制同一个文件则跳过
If FromPath = ToPath Then Return
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(ToPath))
'复制文件
File.Copy(FromPath, ToPath, True)
Catch ex As Exception
Throw New Exception("复制文件出错:" & FromPath & " → " & ToPath, ex)
End Try
End Sub
''' <summary>
''' 读取文件,如果失败则返回空数组。
''' </summary>
Public Function ReadFileBytes(FilePath As String, Optional Encoding As Encoding = Nothing) As Byte()
Try
'还原文件路径
If Not FilePath.Contains(":\") Then FilePath = ExePath & FilePath
If File.Exists(FilePath) Then
Using ReadStream As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) '支持读取使用中的文件
Using ms As New MemoryStream
ReadStream.CopyTo(ms)
Return ms.ToArray()
End Using
End Using
Else
Log("[System] 欲读取的文件不存在,已返回空内容:" & FilePath)
Return {}
End If
Catch ex As Exception
Log(ex, "读取文件出错:" & FilePath)
Return {}
End Try
End Function
''' <summary>
''' 读取文件,如果失败则返回空字符串。
''' </summary>
''' <param name="FilePath">文件完整或相对路径。</param>
Public Function ReadFile(FilePath As String, Optional Encoding As Encoding = Nothing) As String
Dim FileBytes = ReadFileBytes(FilePath)
ReadFile = If(Encoding Is Nothing, DecodeBytes(FileBytes), Encoding.GetString(FileBytes))
End Function
''' <summary>
''' 读取流中的所有文本。
''' </summary>
Public Function ReadFile(Stream As Stream, Optional Encoding As Encoding = Nothing) As String
Try
Dim readedContent As New MemoryStream()
Stream.CopyTo(readedContent)
Dim Bts = readedContent.ToArray()
Return If(Encoding, EncodingDetector.DetectEncoding(Bts)).GetString(Bts)
Catch ex As Exception
Log(ex, "读取流出错")
Return ""
End Try
End Function
''' <summary>
''' 写入文件。
''' </summary>
''' <param name="FilePath">文件完整或相对路径。</param>
''' <param name="Text">文件内容。</param>
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
Public Sub WriteFile(FilePath As String, Text As String, Optional Append As Boolean = False, Optional Encoding As Encoding = Nothing)
'处理相对路径
If Not FilePath.Contains(":\") Then FilePath = ExePath & FilePath
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
'写入文件
If Append Then
'追加目前文件
Using writer As New StreamWriter(FilePath, True, If(Encoding, EncodingDetector.DetectEncoding(ReadFileBytes(FilePath))))
writer.Write(Text)
End Using
Else
'直接写入字节
File.WriteAllBytes(FilePath, If(Encoding Is Nothing, New UTF8Encoding(False).GetBytes(Text), Encoding.GetBytes(Text)))
End If
End Sub
''' <summary>
''' 写入文件。
''' 如果 CanThrow 设置为 False,返回是否写入成功。
''' </summary>
''' <param name="FilePath">文件完整或相对路径。</param>
''' <param name="Content">文件内容。</param>
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
Public Sub WriteFile(FilePath As String, Content As Byte(), Optional Append As Boolean = False)
'处理相对路径
If Not FilePath.Contains(":\") Then FilePath = ExePath & FilePath
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
'写入文件
File.WriteAllBytes(FilePath, Content)
End Sub
''' <summary>
''' 将流写入文件。
''' </summary>
''' <param name="FilePath">文件完整或相对路径。</param>
Public Function WriteFile(FilePath As String, Stream As Stream) As Boolean
Try
'还原文件路径
If Not FilePath.Contains(":\") Then FilePath = ExePath & FilePath
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
'读取流
Using fs As New FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.Read)
fs.SetLength(0)
Stream.CopyTo(fs)
End Using
Return True
Catch ex As Exception
Log(ex, "保存流出错")
Return False
End Try
End Function
''' <summary>
''' 解码 Bytes。
''' </summary>
Public Function DecodeBytes(Bytes As Byte()) As String
Dim Length As Integer = Bytes.Length
If Length < 3 Then Return Encoding.UTF8.GetString(Bytes)
'根据 BOM 判断编码
If Bytes(0) >= &HEF Then
'有 BOM 类型
If Bytes(0) = &HEF AndAlso Bytes(1) = &HBB Then
Return Encoding.UTF8.GetString(Bytes, 3, Length - 3)
ElseIf Bytes(0) = &HFE AndAlso Bytes(1) = &HFF Then
Return Encoding.BigEndianUnicode.GetString(Bytes, 3, Length - 3)
ElseIf Bytes(0) = &HFF AndAlso Bytes(1) = &HFE Then
Return Encoding.Unicode.GetString(Bytes, 3, Length - 3)
Else
Return Encoding.GetEncoding("GB18030").GetString(Bytes, 3, Length - 3)
End If
End If