1 #Region "Microsoft.VisualBasic::af1e1ba26dabe65b712e256f682c1155, Microsoft.VisualBasic.Core\ApplicationServices\App.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     Module App
35     
36     '     Properties: AppSystemTemp, AssemblyName, BufferSize, Command, CommandLine
37     '                 CPUCoreNumbers, CurrentDirectory, CurrentProcessTemp, Desktop, ExceptionLogFile
38     '                 ExecutablePath, Github, HOME, Info, InputFile
39     '                 IsConsoleApp, IsMicrosoftPlatform, LocalData, LocalDataTemp, LogErrDIR
40     '                 NanoTime, NextTempName, OutFile, PID, Platform
41     '                 PreviousDirectory, Process, ProductName, ProductProgramData, ProductSharedDIR
42     '                 ProductSharedTemp, References, Running, RunTimeDirectory, StartTime
43     '                 StartupDirectory, StdErr, StdOut, SysTemp, UserHOME
44     '                 Version
45     
46     '     Constructor: (+1 OverloadsSub New
47     
48     '     Function: __CLI, __completeCLI, __getTEMP, __getTEMPhash, __isMicrosoftPlatform
49     '               __listFiles, __sysTEMP, (+2 Overloads) Argument, BugsFormatter, CLICode
50     '               ElapsedMilliseconds, Exit, formatTime, GenerateTemp, (+2 OverloadsGetAppLocalData
51     '               GetAppSysTempFile, GetAppVariables, GetFile, GetProductSharedDIR, GetProductSharedTemp
52     '               GetTempFile, GetVariable, (+3 Overloads) LogException, NullDevice, (+10 Overloads) RunCLI
53     '               RunCLIInternal, SelfFolk, SelfFolks, Shell, TraceBugs
54     
55     '     Sub: __GCThreadInvoke, __removesTEMP, AddExitCleanHook, FlushMemory, Free
56     '          JoinVariable, (+2 Overloads) JoinVariables, Pause, (+2 Overloads) println, RunAsAdmin
57     '          SetBufferSize, StartGC, StopGC
58     
59     ' /********************************************************************************/
60
61 #End Region
62
63 Imports System.IO
64 Imports System.Reflection
65 Imports System.Runtime.CompilerServices
66 Imports System.Runtime.InteropServices
67 Imports System.Security
68 Imports System.Text
69 Imports Microsoft.VisualBasic.ApplicationServices
70 Imports Microsoft.VisualBasic.ApplicationServices.Debugging
71 Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Logging
72 Imports Microsoft.VisualBasic.ApplicationServices.Development
73 Imports Microsoft.VisualBasic.ApplicationServices.Windows.Forms.VistaSecurity
74 Imports Microsoft.VisualBasic.CommandLine
75 Imports Microsoft.VisualBasic.CommandLine.Reflection
76 Imports Microsoft.VisualBasic.ComponentModel
77 Imports Microsoft.VisualBasic.ComponentModel.Collection
78 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
79 Imports Microsoft.VisualBasic.ComponentModel.Settings
80 Imports Microsoft.VisualBasic.Emit.CodeDOM_VBC
81 Imports Microsoft.VisualBasic.Language
82 Imports Microsoft.VisualBasic.Language.C
83 Imports Microsoft.VisualBasic.Language.Default
84 Imports Microsoft.VisualBasic.Language.UnixBash
85 Imports Microsoft.VisualBasic.Language.UnixBash.FileSystem
86 Imports Microsoft.VisualBasic.Linq
87 Imports Microsoft.VisualBasic.Parallel.Linq
88 Imports Microsoft.VisualBasic.Parallel.Tasks
89 Imports Microsoft.VisualBasic.Parallel.Threads
90 Imports Microsoft.VisualBasic.Scripting.MetaData
91 Imports Microsoft.VisualBasic.Terminal
92 Imports Microsoft.VisualBasic.Text
93 Imports CLI = Microsoft.VisualBasic.CommandLine.CommandLine
94 Imports DevAssmInfo = Microsoft.VisualBasic.ApplicationServices.Development.AssemblyInfo
95
96 '                   _ooOoo_
97 '                  o8888888o
98 '                  88" . "88
99 '                  (| -_- |)
100 '                  O\  =  /O
101 '               ____/`---'\____
102 '             .'  \\|     |//  `.
103 '            /  \\|||  :  |||//  \
104 '           /  _||||| -:- |||||-  \
105 '           |   | \\\  -  /// |   |
106 '           | \_|  ''\---/''  |   |
107 '           \  .-\__  `-`  ___/-. /
108 '         ___`. .'  /--.--\  `. . __
109 '      ."" '<  `.___\_<|>_/___.'  >'"".
110 '     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
111 '     \  \ `-.   \_ __\ /__ _/   .-` /  /
112 '======`-.____`-.___\_____/___.-`____.-'======
113 '                   `=---='
114 '^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
115 '           佛祖保佑       永无BUG
116 '           心外无法       法外无心
117
118 ''' <summary>
119 ''' Provides information about, and means to manipulate, the current environment Application information collection.
120 ''' (More easily runtime environment information provider on <see cref="PlatformID.Unix"/>/LINUX server platform for VisualBasic program.)
121 ''' (从命令行之中使用``/@set``参数赋值环境变量的时候,每一个变量之间使用分号进行分隔)
122 ''' </summary>
123 '''
124 <Package("App", Description:="More easily runtime environment information provider on LINUX platform for VisualBasic program.",
125                   Publisher:="amethyst.asuka@gcmodeller.org",
126                   Url:="http://SourceForge.net/projects/shoal")>
127 Public Module App
128
129     ''' <summary>
130     ''' 运行时环境所安装的文件夹的位置
131     ''' </summary>
132     ''' <returns></returns>
133     Public ReadOnly Property RunTimeDirectory As String
134
135     ''' <summary>
136     ''' Gets the number of ticks that represent the date and time of this instance.
137     ''' 
138     ''' The number of ticks that represent the date and time of this instance. The value
139     ''' is between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks.
140     ''' </summary>
141     ''' <returns></returns>
142     Public ReadOnly Property NanoTime As Long
143         <MethodImpl(MethodImplOptions.AggressiveInlining)>
144         Get
145             Return Now.Ticks
146         End Get
147     End Property
148
149     ''' <summary>
150     ''' Numbers of the CPU kernels on the current machine.
151     ''' (获取当前的系统主机的CPU核心数)
152     ''' </summary>
153     ''' <returns></returns>
154     Public ReadOnly Property CPUCoreNumbers As Integer = LQuerySchedule.CPU_NUMBER
155     ''' <summary>
156     ''' 判断当前运行的程序是否为Console类型的应用和程序,由于在执行初始化的时候,
157     ''' 最先被初始化的是这个模块,所以没有任何代码能够先执行<see cref="Console.IsErrorRedirected"/>了,
158     ''' 在这里使用<see cref="Console.IsErrorRedirected"/>这个来进行判断是可靠的
159     ''' </summary>
160     ''' <returns></returns>
161     Public ReadOnly Property IsConsoleApp As Boolean = Not Console.IsErrorRedirected
162     ''' <summary>
163     ''' Get the referenced dll list of current running ``*.exe`` program.
164     ''' (获取得到当前的这个所运行的应用程序所引用的dll文件列表)
165     ''' </summary>
166     ''' <returns></returns>
167     Public ReadOnly Property References As New Lazy(Of String())(Function() ReferenceSolver.ExecutingReferences)
168     ''' <summary>
169     ''' Gets a path name pointing to the Desktop directory.
170     ''' </summary>
171     ''' <returns>The path to the Desktop directory.</returns>
172     Public ReadOnly Property Desktop As String
173     Public ReadOnly Property StdErr As New StreamWriter(Console.OpenStandardError)
174
175     ''' <summary>
176     ''' <see cref="Console.OpenStandardOutput()"/> as default text output device.
177     ''' </summary>
178     ''' <returns></returns>
179     Public ReadOnly Property StdOut As DefaultValue(Of TextWriter) = Console.OpenStandardOutput.OpenTextWriter
180
181     ''' <summary>
182     ''' Get the <see cref="System.Diagnostics.Process"/> id(PID) of the current program process.
183     ''' </summary>
184     Public ReadOnly Property PID As Integer = Process.GetCurrentProcess.Id
185     ''' <summary>
186     ''' Gets a new <see cref="System.Diagnostics.Process"/> component and associates it with the currently active process.
187     ''' </summary>
188     ''' <returns></returns>
189     Public ReadOnly Property Process As Process = Process.GetCurrentProcess
190
191     ''' <summary>
192     ''' Gets the command-line arguments for this <see cref="Process"/>.
193     ''' </summary>
194     ''' <returns>Gets the command-line arguments for this process.</returns>
195     Public ReadOnly Property CommandLine As CommandLine.CommandLine = __CLI()
196
197     ''' <summary>
198     ''' Get argument value from <see cref="CommandLine"/>.
199     ''' </summary>
200     ''' <typeparam name="T"></typeparam>
201     ''' <param name="name$"></param>
202     ''' <returns></returns>
203     Public Function Argument(Of T)(name$) As T
204         With CommandLine(name).DefaultValue
205             If .StringEmpty Then
206                 Return Nothing
207             Else
208                 Return Scripting.CTypeDynamic(Of T)(.ByRef)
209             End If
210         End With
211     End Function
212
213     ''' <summary>
214     ''' Get argument value string from <see cref="CommandLine"/>.
215     ''' </summary>
216     ''' <param name="name$"></param>
217     ''' <returns></returns>
218     ''' 
219     <MethodImpl(MethodImplOptions.AggressiveInlining)>
220     Public Function Argument(name$) As String
221         Return CommandLine(name)
222     End Function
223
224     Const gitBash As String = "C:/Program Files/Git"
225
226     ''' <summary>
227     ''' Makes compatibility with git bash: <see cref="gitBash"/> = ``C:/Program Files/Git``
228     ''' </summary>
229     ''' <returns></returns>
230     Private Function __CLI() As CommandLine.CommandLine
231         Dim tokens$() = ' 第一个参数为应用程序的文件路径,不需要
232             Environment.GetCommandLineArgs _
233             .Skip(1) _
234             .ToArray
235         Dim CLI$ = tokens _
236             .Select(Function(s) s.CLIToken) _
237             .JoinBy(" ") _
238             .Replace(gitBash, "")
239
240         Return CLITools.TryParse(CLI)
241     End Function
242
243     Public ReadOnly Property Github As String = LICENSE.githubURL
244
245     ''' <summary>
246     ''' Returns the argument portion of the <see cref="Microsoft.VisualBasic.CommandLine.CommandLine"/> used to start Visual Basic or
247     ''' an executable program developed with Visual Basic. The My feature provides greater
248     ''' productivity and performance than the <see cref="microsoft.VisualBasic.Interaction.Command"/> function. For more information,
249     ''' see <see cref="ConsoleApplicationBase.CommandLineArgs"/>.
250     ''' </summary>
251     ''' <returns>Gets the command-line arguments for this process.</returns>
252     Public ReadOnly Property Command As String = CLITools.Join(App.CommandLine.Tokens)
253
254     ''' <summary>
255     ''' The file path of the current running program executable file.(本应用程序的可执行文件的文件路径)
256     ''' </summary>
257     ''' <returns></returns>
258     Public ReadOnly Property ExecutablePath As String
259     ''' <summary>
260     ''' Get assembly info of current running ``*.exe`` program.
261     ''' </summary>
262     ''' <returns></returns>
263     Public ReadOnly Property Info As DevAssmInfo
264
265     ''' <summary>
266     ''' Gets the name, without the extension, of the assembly file for the application.
267     ''' </summary>
268     ''' <returns></returns>
269     Public ReadOnly Property AssemblyName As String
270     Public ReadOnly Property ProductName As String
271
272     ''' <summary>
273     ''' The program directory of the current running program.
274     ''' </summary>
275     ''' <returns></returns>
276     Public ReadOnly Property HOME As String
277     ''' <summary>
278     ''' Getting the path of the home directory
279     ''' </summary>
280     ''' <returns></returns>
281     Public ReadOnly Property UserHOME As String
282
283     ''' <summary>
284     ''' Gets the ``/in`` commandline value as the input file path.
285     ''' </summary>
286     ''' <returns></returns>
287     Public Property InputFile As String
288         <MethodImpl(MethodImplOptions.AggressiveInlining)>
289         Get
290             Return App.CommandLine("/in")
291         End Get
292         Friend Set(value As String)
293             App.CommandLine.Add("/in", value)
294         End Set
295     End Property
296
297     Dim _out$
298
299     ''' <summary>
300     ''' Gets the ``/out`` commandline value as the output file path.
301     ''' </summary>
302     ''' <returns></returns>
303     Public Property OutFile As String
304         <MethodImpl(MethodImplOptions.AggressiveInlining)>
305         Get
306             If _out.StringEmpty Then
307                 _out = App.CommandLine("/out")
308             End If
309
310             Return _out
311         End Get
312         Set(value As String)
313             _out = value
314         End Set
315     End Property
316
317     ''' <summary>
318     ''' Found the file path based on the current application context.
319     ''' 
320     ''' 1. 直接查找(这个查找已经包含了在当前的文件夹之中查找)
321     ''' 2. 从<see cref="App.InputFile"/>所在的文件夹之中查找
322     ''' 3. 从<see cref="App.OutFile"/>所在的文件夹之中查找
323     ''' 4. 从<see cref="App.Home"/>文件夹之中查找
324     ''' 5. 从<see cref="App.UserHOME"/>文件夹之中查找
325     ''' 6. 从<see cref="App.ProductProgramData"/>文件夹之中查找
326     ''' </summary>
327     ''' <param name="fileName$"></param>
328     ''' <returns></returns>
329     Public Function GetFile(fileName$) As String
330         If fileName.FileExists Then
331             Return fileName.GetFullPath
332         End If
333
334         Dim path As New Value(Of String)
335
336         On Error Resume Next
337
338         If Not App.InputFile.StringEmpty AndAlso
339             (path = App.InputFile.ParentPath & "/" & fileName).FileExists Then
340
341             Return path
342         End If
343         If Not App.OutFile.StringEmpty AndAlso
344             (path = App.OutFile.ParentPath & "/" & fileName).FileExists Then
345
346             Return path
347         End If
348
349         For Each DIR As String In {
350             App.HOME,
351             App.UserHOME,
352             App.ProductProgramData,
353             App.ProductSharedDIR
354         }
355             If (path = DIR & "/" & fileName).FileExists Then
356                 Return path
357             End If
358         Next
359
360         Return App.CurrentDirectory & "/" & fileName
361     End Function
362
363     ''' <summary>
364     ''' The currrent working directory of this application.(应用程序的当前的工作目录)
365     ''' </summary>
366     ''' <returns></returns>
367     Public Property CurrentDirectory As String
368         <MethodImpl(MethodImplOptions.AggressiveInlining)>
369         Get
370             ' 由于会因为切换目录而发生变化,所以这里不适用简写形式了
371             Return FileIO.FileSystem.CurrentDirectory
372         End Get
373         Set(value As String)
374             If String.Equals(value, "-"Then  ' 切换到前一个工作目录
375                 value = PreviousDirectory
376             Else
377                 _PreviousDirectory = FileIO.FileSystem.CurrentDirectory
378             End If
379
380             FileIO.FileSystem.CreateDirectory(value)
381             FileIO.FileSystem.CurrentDirectory = value
382         End Set
383     End Property
384
385     ''' <summary>
386     ''' -
387     ''' Linux里面的前一个文件夹
388     ''' </summary>
389     ''' <remarks>
390     ''' 假设你之前好不容易进入了一个很深的目录,然后不小心敲了个 ``cd /``,是不是快气晕了啊,不用着急,通过下面的指令可以轻松的回到前一个指令:
391     '''
392     ''' ```bash
393     ''' cd -
394     ''' ```
395     ''' </remarks>
396     Public ReadOnly Property PreviousDirectory As String
397
398     ''' <summary>
399     ''' Gets the path for the executable file that started the application, not including the executable name.
400     ''' </summary>
401     ''' <returns></returns>
402     Public ReadOnly Property StartupDirectory As String
403         <MethodImpl(MethodImplOptions.AggressiveInlining)>
404         Get
405             Return Application.StartupPath
406         End Get
407     End Property
408
409     ''' <summary>
410     ''' The repository root of the product application program data.
411     ''' </summary>
412     ''' <returns></returns>
413     Public ReadOnly Property ProductProgramData As String
414
415     ''' <summary>
416     ''' The shared program data directory for a group of app which have the same product series name.
417     ''' (同一產品程序集所共享的數據文件夾)
418     ''' </summary>
419     ''' <returns></returns>
420     Public ReadOnly Property ProductSharedDIR As String
421
422     Sub New()
423         On Error Resume Next ' 在Linux服务器上面不起作用???
424
425         Call FileIO.FileSystem.CreateDirectory(AppSystemTemp)
426         Call FileIO.FileSystem.CreateDirectory(App.HOME & "/Resources/")
427
428         PreviousDirectory = App.StartupDirectory
429
430 #Region "公共模块内的所有的文件路径初始化"
431         ' 因为vb的基础运行时环境在Linux平台上面对文件系统的支持还不是太完善,所以不能够放在属性的位置直接赋值,否则比较难处理异常
432         ' 现在放在这个构造函数之中,强制忽略掉错误继续执行,提升一些稳定性,防止出现程序无法启动的情况出现。
433
434         ' 请注意,这里的变量都是有先后的初始化顺序的
435         Try
436             App.RunTimeDirectory = FileIO.FileSystem _
437                 .GetDirectoryInfo(RuntimeEnvironment.GetRuntimeDirectory) _
438                 .FullName _
439                 .Replace("/""\")
440             App.Desktop = My.Computer.FileSystem.SpecialDirectories.Desktop
441             App.ExecutablePath = FileIO.FileSystem.GetFileInfo(Application.ExecutablePath).FullName    ' (Process.GetCurrentProcess.StartInfo.FileName).FullName
442             App.Info = ApplicationInfoUtils.CurrentExe()
443             App.AssemblyName = BaseName(App.ExecutablePath)
444             App.ProductName = Application.ProductName Or AssemblyName.AsDefault(Function(s) String.IsNullOrEmpty(s))
445             App.HOME = FileIO.FileSystem.GetParentPath(App.ExecutablePath)
446             App.UserHOME = PathMapper.HOME.GetDirectoryFullPath("App.New(.cctor)")
447             App.ProductProgramData = $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/{ProductName}".GetDirectoryFullPath("App.New(.cctor)")
448             App.ProductSharedDIR = $"{ProductProgramData}/.shared".GetDirectoryFullPath
449             App.LocalData = App.GetAppLocalData(ProductName, AssemblyName, "App.New(.cctor)")
450             App.CurrentProcessTemp = GenerateTemp(App.SysTemp & "/tmp.io", App.PID).GetDirectoryFullPath("App.New(.cctor)")
451             App.ProductSharedTemp = App.ProductSharedDIR & "/tmp/"
452             App.LogErrDIR = App.LocalData & $"/.logs/err/"
453         Catch ex As Exception
454
455         End Try
456 #End Region
457     End Sub
458
459     <MethodImpl(MethodImplOptions.AggressiveInlining)>
460     Public Function GetAppLocalData(app$, assemblyName$, <CallerMemberName> Optional track$ = NothingAs String
461         Return $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/{app}/{assemblyName}".GetDirectoryFullPath(track)
462     End Function
463
464     Public Function GetAppLocalData(exe$) As String
465         Dim app As DevAssmInfo = Assembly.LoadFile(path:=IO.Path.GetFullPath(exe)).FromAssembly
466         Return GetAppLocalData(app:=app.AssemblyProduct, assemblyName:=exe.BaseName)
467     End Function
468
469 #Region "这里的环境变量方法主要是操作从命令行之中所传递进来的额外的参数的"
470
471     Dim __joinedVariables As New Dictionary(Of NamedValue(Of String))
472
473     ''' <summary>
474     ''' 添加参数到应用程序的环境变量之中
475     ''' </summary>
476     ''' <param name="name$"></param>
477     ''' <param name="value$"></param>
478     Public Sub JoinVariable(name$, value$)
479         __joinedVariables(name) =
480             New NamedValue(Of StringWith {
481                 .Name = name,
482                 .Value = value
483         }
484     End Sub
485
486     ''' <summary>
487     ''' 添加参数集合到应用程序的环境变量之中
488     ''' </summary>
489     ''' <param name="vars"></param>
490     Public Sub JoinVariables(ParamArray vars As NamedValue(Of String)())
491         For Each v As NamedValue(Of StringIn vars
492             __joinedVariables(v.Name) = v
493         Next
494     End Sub
495
496     Public Sub JoinVariables(vars As Dictionary(Of StringString))
497         Call App.JoinVariables(vars.Select(
498             Function(x)
499                 Return New NamedValue(Of StringWith {
500                     .Name = x.Key,
501                     .Value = x.Value
502                 }
503             End Function).ToArray)
504     End Sub
505
506     ''' <summary>
507     ''' If the parameter <paramref name="name"/> is ignored, then the value from <see cref="CallerMemberNameAttribute"/> 
508     ''' will be used as variable name.
509     ''' (这个函数只是会从设置的变量之中查找,本模块之中的变量请直接从属性进行引用,对于查找失败的变量,这个函数会返回空值
510     ''' 假若忽略掉<paramref name="name"/>参数的话,则这个函数会使用<see cref="CallerMemberNameAttribute"/>来获取变量
511     ''' 的名称)
512     ''' </summary>
513     ''' <param name="name$">
514     ''' 因为由于是从命令行之中输入进来的,所以可能有些时候大小写会影响直接字典查找,在这里需要用字符串手工查找
515     ''' </param>
516     ''' <returns>当没有查找到相对应的环境变量的时候会返回空值</returns>
517     Public Function GetVariable(<CallerMemberName> Optional name$ = NothingAs String
518         If __joinedVariables.ContainsKey(name) Then
519             Return __joinedVariables(name).Value
520         Else
521             For Each v As NamedValue(Of StringIn __joinedVariables.Values
522                 If v.Name.TextEquals(name) Then
523                     Return v.Value
524                 End If
525             Next
526         End If
527
528         Return Nothing
529     End Function
530
531     ''' <summary>
532     ''' 获取<see cref="App"/>的可读属性值来作为环境变量
533     ''' </summary>
534     ''' <returns></returns>
535     Public Function GetAppVariables() As NamedValue(Of String)()
536         Dim type As Type = GetType(App)
537         Dim pros = type.Schema(PropertyAccess.Readable, BindingFlags.Public Or BindingFlags.Static)
538         Dim out As New List(Of NamedValue(Of String))(__joinedVariables.Values)
539         Dim value$
540         Dim o
541
542         For Each prop As PropertyInfo
543             In pros.Values _
544                 .Where(Function(p)
545                            Return p.PropertyType.Equals(GetType(String)) AndAlso
546                                   p.GetIndexParameters _
547                                    .IsNullOrEmpty
548                        End Function)
549
550             o = prop.GetValue(Nothing, Nothing)
551             value = Scripting.ToString(o)
552             out += New NamedValue(Of StringWith {
553                 .Name = prop.Name,
554                 .Value = value
555             }
556         Next
557
558         Return out.ToArray
559     End Function
560
561 #End Region
562
563     ''' <summary>
564     ''' 其他的模块可能也会依赖于这个初始化参数
565     ''' </summary>
566     ''' <returns></returns>
567     Public ReadOnly Property BufferSize As Integer = 4 * 1024 * 1024
568
569     ''' <summary>
570     ''' Set value of <see cref="BufferSize"/>
571     ''' </summary>
572     ''' <param name="size"></param>
573     Public Sub SetBufferSize(size As Integer)
574         _BufferSize = size
575     End Sub
576
577     ''' <summary>
578     ''' 假若有些时候函数的参数要求有一个输出流,但是并不想输出任何数据的话,则可以使用这个进行输出
579     ''' </summary>
580     ''' <returns></returns>
581     Public Function NullDevice(Optional encoding As Encodings = Encodings.ASCII) As StreamWriter
582         Dim ms As New MemoryStream(capacity:=BufferSize)
583         Dim codePage As Encoding = encoding.CodePage
584         Return New StreamWriter(ms, encoding:=codePage)
585     End Function
586
587     ''' <summary>
588     ''' java <see cref="printf"/> + <see cref="Console.WriteLine(String)"/>
589     ''' </summary>
590     ''' <param name="s$"></param>
591     ''' <param name="args"></param>
592     Public Sub println(s$, ParamArray args As Object())
593         If Not args.IsNullOrEmpty Then
594             s = sprintf(s, args)
595         Else
596             s = CLangStringFormatProvider.ReplaceMetaChars(s)
597         End If
598
599         Call InnerQueue.AddToQueue(
600             Sub()
601                 Call Console.WriteLine(s)
602             End Sub)
603     End Sub
604
605     <MethodImpl(MethodImplOptions.AggressiveInlining)>
606     Public Sub println()
607         Call InnerQueue.AddToQueue(AddressOf Console.WriteLine)
608     End Sub
609
610     Public Declare Function SetProcessWorkingSetSize Lib "kernel32.dll" (process As IntPtr, minimumWorkingSetSize As Integer, maximumWorkingSetSize As IntegerAs Integer
611
612     ''' <summary>
613     ''' Rabbish collection to free the junk memory.(垃圾回收)
614     ''' </summary>
615     ''' <remarks></remarks>
616     '''
617     <ExportAPI("FlushMemory"Info:="Rabbish collection To free the junk memory.")>
618     Public Sub FlushMemory()
619         Call GC.Collect()
620         Call GC.WaitForPendingFinalizers()
621
622         If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
623             Call SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1)
624         End If
625     End Sub
626
627     ''' <summary>
628     ''' Free this variable pointer in the memory.(销毁本对象类型在内存之中的指针)
629     ''' </summary>
630     ''' <typeparam name="T">假若该对象类型实现了<see cref="System.IDisposable"></see>接口,则函数还会在销毁前调用该接口的销毁函数</typeparam>
631     ''' <param name="obj"></param>
632     ''' <remarks></remarks>
633     <Extension> Public Sub Free(Of T As Class)(ByRef obj As T)
634         If Not obj Is Nothing Then
635             Dim TypeInfo As Type = obj.GetType
636             If Array.IndexOf(TypeInfo.GetInterfaces, GetType(IDisposable)) > -1 Then
637                 Try
638                     Call DirectCast(obj, IDisposable).Dispose()
639                 Catch ex As Exception
640
641                 End Try
642             End If
643         End If
644
645         obj = Nothing
646
647         ' Will not working on Linux platform
648         If App.IsMicrosoftPlatform Then
649             Call FlushMemory()
650         End If
651     End Sub
652
653     ''' <summary>
654     ''' Pause the console program.
655     ''' </summary>
656     ''' <param name="Prompted"></param>
657     ''' <remarks></remarks>
658     '''
659     <ExportAPI("Pause"Info:="Pause the console program.")>
660     Public Sub Pause(Optional prompted$ = "Press any key to continute...")
661         Call InnerQueue.WaitQueue()
662         Call Console.WriteLine(prompted)
663
664         ' 2018-6-26 如果不是命令行程序的话,可能会因为没有地方进行输入而导致程序在这里停止运行
665         ' 所以会需要进行一些判断,只在命令行模式下才会要求输入
666         If App.IsConsoleApp Then
667             Call Console.Read()
668         End If
669     End Sub
670
671     ''' <summary>
672     ''' 使用<see cref="ProductSharedDIR"/>的位置会变化的,则使用本函数则会使用获取当前的模块的文件夹,即使其不是exe程序而是一个dll文件
673     ''' </summary>
674     ''' <param name="type"></param>
675     ''' <returns></returns>
676     Public Function GetProductSharedDIR(type As Type) As String
677         Dim assm As Assembly = type.Assembly
678         Dim productName As String = ApplicationInfoUtils.GetProductName(assm)
679
680         If String.IsNullOrEmpty(productName) Then
681             productName = BaseName(assm.Location)
682         End If
683
684         Return $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/{productName}"
685     End Function
686
687     ''' <summary>
688     ''' The time tag of the application started.(应用程序的启动的时间)
689     ''' </summary>
690     ''' <returns></returns>
691     Public ReadOnly Property StartTime As Long = Now.ToBinary
692
693     ''' <summary>
694     ''' The distance of time that this application running from start and to current time.
695     ''' (当前距离应用程序启动所逝去的时间)
696     ''' </summary>
697     ''' <returns></returns>
698     '''
699     <ExportAPI("Elapsed.Milliseconds")>
700     Public Function ElapsedMilliseconds() As Long
701         Dim nowLng As Long = Now.ToBinary
702         Dim d As Long = nowLng - StartTime
703         Return d
704     End Function
705
706     ''' <summary>
707     ''' The local data dir of the application in the %user%/&lt;CurrentUser>/Local/Product/App
708     ''' </summary>
709     ''' <returns></returns>
710     Public ReadOnly Property LocalData As String
711
712     ''' <summary>
713     ''' The temp directory in the application local data.
714     ''' </summary>
715     ''' <returns></returns>
716     Public ReadOnly Property LocalDataTemp As String
717         <MethodImpl(MethodImplOptions.AggressiveInlining)>
718         Get
719             Return App.LocalData & "/Temp/"
720         End Get
721     End Property
722
723     ''' <summary>
724     ''' The directory path of the system temp data.
725     ''' </summary>
726     ''' <returns></returns>
727     Public ReadOnly Property SysTemp As String = App.__sysTEMP
728
729     ''' <summary>
730     ''' <see cref="FileIO.FileSystem.GetParentPath"/>(<see cref="FileIO.FileSystem.GetTempFileName"/>)
731     ''' 当临时文件夹被删除掉了的时候,会出现崩溃。。。。所以弃用改用读取环境变量
732     ''' </summary>
733     ''' <returns></returns>
734     Private Function __sysTEMP() As String
735         Dim DIR As String = Environment.GetEnvironmentVariable("TMP"' Linux系统可能没有这个东西
736
737         If String.IsNullOrEmpty(DIR) Then
738             DIR = IO.Path.GetTempPath
739         End If
740
741         Try
742             Call FileIO.FileSystem.CreateDirectory(DIR)
743         Catch ex As Exception
744             ' 不知道应该怎样处理,但是由于只是得到一个路径,所以在这里干脆忽略掉这个错误就可以了
745             Call New Exception(DIR, ex).PrintException
746         End Try
747
748         Return DIR
749     End Function
750
751     ''' <summary>
752     ''' Application temp data directory in the system temp root: %<see cref="App.SysTemp"/>%/<see cref="App.AssemblyName"/>
753     ''' </summary>
754     ''' <returns></returns>
755     Public ReadOnly Property AppSystemTemp As String
756         <MethodImpl(MethodImplOptions.AggressiveInlining)>
757         Get
758             Return SysTemp & "/" & App.AssemblyName
759         End Get
760     End Property
761
762     ''' <summary>
763     ''' Gets the product version associated with this application.
764     ''' </summary>
765     ''' <returns></returns>
766     Public ReadOnly Property Version As String
767         <MethodImpl(MethodImplOptions.AggressiveInlining)>
768         Get
769             Return Trim(Application.ProductVersion)
770         End Get
771     End Property
772
773     ''' <summary>
774     ''' Simply log application exception data into a log file which saves at location: %<see cref="App.LocalData"/>%/.logs/err/.
775     ''' (简单日志记录,函数返回空值)
776     ''' </summary>
777     ''' <param name="ex"></param>
778     ''' <param name="trace">调用函数的位置,这个参数一般为空,编译器会自动生成Trace位点参数</param>
779     ''' <returns>这个函数总是返回空值的</returns>
780     <ExportAPI("LogException")>
781     Public Function LogException(ex As Exception, <CallerMemberName> Optional ByRef trace$ = ""As Object
782         Try
783             trace = App.TraceBugs(ex, trace)
784         Catch ex2 As Exception
785             ' 错误日志文件的存放位置不可用或者被占用了不可写,则可能会出错,
786             ' 在这里将原来的错误打印在终端上面就行了, 扔弃掉这个错误日志
787             Call ex.PrintException
788         End Try
789
790         Return Nothing
791     End Function
792
793     ''' <summary>
794     ''' Function returns the file path of the application log file.
795     ''' (函数返回的是日志文件的文件路径)
796     ''' </summary>
797     ''' <returns></returns>
798     '''
799     <ExportAPI("TraceBugs")>
800     Public Function TraceBugs(ex As Exception, <CallerMemberName> Optional trace$ = ""As String
801         Dim entry$ = $"{Now.formatTime}_{App.__getTEMPhash}"
802         Dim log$ = $"{App.LogErrDIR}/{entry}.log"
803         Call App.LogException(ex, trace:=trace, fileName:=log)
804         Return log
805     End Function
806
807     <Extension>
808     Private Function formatTime(time As DateTime) As String
809         Dim yy = time.Year
810         Dim mm = time.Month
811         Dim dd = time.Day
812         Dim hh = time.Hour
813         Dim mi = time.Minute
814         Dim ss = time.Second
815
816         Return $"{yy}-{mm}-{dd}, {Format(hh, "00")}-{Format(mi, "00")}-{Format(ss, "00")}"
817     End Function
818
819     ''' <summary>
820     ''' Is this application running on a Microsoft OS platform.(是否是运行于微软的操作系统平台?)
821     ''' </summary>
822     ''' <returns></returns>
823     Public ReadOnly Property IsMicrosoftPlatform As Boolean = App.__isMicrosoftPlatform
824
825     ''' <summary>
826     ''' 这个主要是判断一个和具体的操作系统平台相关的Win32 API是否能够正常的工作?
827     ''' </summary>
828     ''' <returns></returns>
829     Private Function __isMicrosoftPlatform() As Boolean
830 #If UNIX Then
831         Return False
832 #Else
833         Dim pt As PlatformID = Platform
834
835         ' 枚举值在.NET和Mono之间可能会不一样??
836         If pt.ToString = NameOf(PlatformID.Unix) Then
837             Return False
838         ElseIf pt.ToString = NameOf(PlatformID.MacOSX) Then
839             Return False
840         End If
841
842         Return pt = PlatformID.Win32NT OrElse
843             pt = PlatformID.Win32S OrElse
844             pt = PlatformID.Win32Windows OrElse
845             pt = PlatformID.WinCE OrElse
846             pt = PlatformID.Xbox
847 #End If
848     End Function
849
850     ''' <summary>
851     ''' Example: ``tmp2A10.tmp``
852     ''' </summary>
853     Dim _tmpHash As New Uid(Not IsMicrosoftPlatform)
854
855     <MethodImpl(MethodImplOptions.AggressiveInlining)>
856     Private Function __getTEMPhash() As String
857         SyncLock _tmpHash
858             Return FormatZero(++_tmpHash, "00000")
859         End SyncLock
860     End Function
861
862     ''' <summary>
863     ''' 由于可能会运行多个使用本模块的进程,单独考哈希来作为表示会产生冲突,所以这里使用应用程序的启动时间戳以及当前的哈希值来生成唯一标示
864     ''' </summary>
865     ''' <returns></returns>
866     <MethodImpl(MethodImplOptions.AggressiveInlining)>
867     Private Function __getTEMP() As String
868         Return $"tmp{App.__getTEMPhash}"
869     End Function
870
871     ''' <summary>
872     ''' 是名称,不是文件路径
873     ''' </summary>
874     ''' <returns></returns>
875     Public ReadOnly Property NextTempName As String
876         <MethodImpl(MethodImplOptions.AggressiveInlining)>
877         Get
878             Return __getTEMP()
879         End Get
880     End Property
881
882     ''' <summary>
883     ''' Error default log fie location from function <see cref="App.LogException(Exception, ByRef String)"/>.(存放自动存储的错误日志的文件夹)
884     ''' </summary>
885     ''' <returns></returns>
886     Public ReadOnly Property LogErrDIR As String
887
888     ''' <summary>
889     ''' Simply log application exception data into a log file which saves at a user defined location parameter: <paramref name="FileName"/>.
890     ''' (简单日志记录)
891     ''' </summary>
892     ''' <param name="ex"></param>
893     ''' <param name="Trace"></param>
894     ''' <param name="FileName"></param>
895     ''' <returns></returns>
896     '''
897     <ExportAPI("LogException")>
898     Public Function LogException(ex As Exception, fileName$, <CallerMemberName> Optional trace$ = NothingAs Object
899         Call BugsFormatter(ex, trace).SaveTo(fileName)
900         Return Nothing
901     End Function
902
903     ''' <summary>
904     ''' Generates the formatted error log file content.(生成简单的日志板块的内容)
905     ''' </summary>
906     ''' <param name="ex"></param>
907     ''' <param name="trace"></param>
908     ''' <returns></returns>
909     '''
910     <ExportAPI("Bugs.Formatter")>
911     Public Function BugsFormatter(ex As Exception, <CallerMemberName> Optional trace$ = ""As String
912         Dim logs = ex.ToString.LineTokens
913         Dim stackTrace = logs _
914             .Where(Function(s)
915                        Return InStr(s, "   在 ") = 1 OrElse InStr(s, "   at ") = 1
916                    End Function) _
917             .AsList
918         Dim message = logs _
919             .Where(Function(s)
920                        Return Not s.IsPattern("\s+[-]{3}.+?[-]{3}\s*"AndAlso stackTrace.IndexOf(s) = -1
921                    End Function) _
922             .JoinBy(ASCII.LF) _
923             .Trim _
924             .StringSplit("\s[-]{3}>\s")
925
926         Return New StringBuilder() _
927             .AppendLine("TIME:  " & Now.ToString) _
928             .AppendLine("TRACE: " & trace) _
929             .AppendLine(New String("=", 120)) _
930             .Append(LogFile.SystemInfo) _
931             .AppendLine(New String("=", 120)) _
932             .AppendLine() _
933             .AppendLine($"Environment Variables from {GetType(App).FullName}:") _
934             .AppendLine(ConfigEngine.Prints(App.GetAppVariables)) _
935             .AppendLine(New String("=", 120)) _
936             .AppendLine() _
937             .AppendLine(ex.GetType.FullName & ":") _
938             .AppendLine() _
939             .AppendLine(message _
940                 .Select(Function(s) "    ---> " & s) _
941                 .JoinBy(ASCII.LF)) _
942             .AppendLine() _
943             .AppendLine(stackTrace _
944                 .Select(Function(s)
945                             If InStr(s, "   在 ") = 1 Then
946                                 Return Mid(s, 6).Trim
947                             ElseIf InStr(s, "   at ") = 1 Then
948                                 Return Mid(s, 7).Trim
949                             Else
950                                 Return s
951                             End If
952                         End Function) _
953                 .Select(Function(s) "   at " & s) _
954                 .JoinBy(ASCII.LF)) _
955             .ToString()
956     End Function
957
958     ''' <summary>
959     ''' This is the custom message of the exception, not extract from the function <see cref="Exception.ToString()"/>
960     ''' </summary>
961     ''' <param name="exMsg">This is the custom message of the exception, not extract from the function <see cref="Exception.ToString()"/></param>
962     ''' <param name="Trace"></param>
963     ''' <returns></returns>
964     <ExportAPI("Exception.Log")>
965     <MethodImpl(MethodImplOptions.AggressiveInlining)>
966     Public Function LogException(exMsg$, <CallerMemberName> Optional Trace$ = ""As Object
967         Return App.LogException(New Exception(exMsg), Trace)
968     End Function
969
970     ''' <summary>
971     ''' <see cref="App.LocalData"/>/error.log
972     ''' </summary>
973     ''' <returns></returns>
974     Public ReadOnly Property ExceptionLogFile As String
975         <MethodImpl(MethodImplOptions.AggressiveInlining)>
976         Get
977             Return App.LocalData & "/error.log"
978         End Get
979     End Property
980
981 #Region "CLI interpreter"
982
983     Public ReadOnly Property Running As Boolean = True
984
985     ''' <summary>
986     '''  Terminates this <see cref="System.Diagnostics.Process"/> and gives the underlying operating system the specified exit code.
987     '''  (这个方法还会终止本应用程序里面的自动GC线程)
988     ''' </summary>
989     ''' <param name="state">Exit code to be given to the operating system. Use 0 (zero) to indicate that the process completed successfully.</param>
990     '''
991     <SecuritySafeCritical> Public Function Exit%(Optional state% = 0)
992         App._Running = False
993
994         Call InnerQueue.WaitQueue()
995         Call App.StopGC()
996         Call __GCThread.Dispose()
997         Call Environment.Exit(state)
998
999         Return state
1000     End Function
1001
1002 #If FRAMEWORD_CORE Then
1003
1004     ''' <summary>
1005     ''' Running the <see cref="String"/> as cli command line and the specific type define as a <see cref="CommandLine.Interpreter"/>.
1006     ''' (请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1007     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1008     ''' </summary>
1009     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1010     ''' <returns>Returns the function execute result to the operating system.</returns>
1011     '''
1012     <ExportAPI("RunCLI"Info:="Running the string as cli command line and the specific type define as a interpreter.")>
1013     <Extension>
1014     Public Function RunCLI(Interpreter As Type, args$, <CallerMemberName> Optional caller$ = NothingAs Integer
1015         Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, NothingNothingNothing)
1016     End Function
1017
1018     ''' <summary>
1019     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1020     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1021     ''' </summary>
1022     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1023     ''' <returns>Returns the function execute result to the operating system.</returns>
1024     '''
1025     <ExportAPI("RunCLI",
1026              Info:="Running the string as cli command line and the specific type define as a interpreter.")>
1027     <Extension> Public Function RunCLI(Interpreter As Type, args As CLI, <CallerMemberName> Optional caller$ = NothingAs Integer
1028         Return Interpreter.RunCLIInternal(args, caller, NothingNothingNothing)
1029     End Function
1030
1031     ''' <summary>
1032     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1033     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1034     ''' </summary>
1035     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1036     ''' <returns>Returns the function execute result to the operating system.</returns>
1037     '''
1038     <ExportAPI("RunCLI",
1039              Info:="Running the string as cli command line and the specific type define as a interpreter.")>
1040     <Extension> Public Function RunCLI(Interpreter As Type, args As CLI, executeEmpty As ExecuteEmptyCLI,
1041                                        <CallerMemberName>
1042                                        Optional caller$ = NothingAs Integer
1043         Return Interpreter.RunCLIInternal(args, caller, executeEmpty, NothingNothing)
1044     End Function
1045
1046     ''' <summary>
1047     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1048     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1049     ''' </summary>
1050     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1051     ''' <returns>Returns the function execute result to the operating system.</returns>
1052     '''
1053     <ExportAPI("RunCLI")>
1054     <Extension> Public Function RunCLI(Interpreter As Type, args$, executeEmpty As ExecuteEmptyCLI,
1055                                        <CallerMemberName>
1056                                        Optional caller$ = NothingAs Integer
1057         Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, executeEmpty, NothingNothing)
1058     End Function
1059
1060     ''' <summary>
1061     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1062     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1063     ''' </summary>
1064     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1065     ''' <returns>Returns the function execute result to the operating system.</returns>
1066     '''
1067     <ExportAPI("RunCLI")>
1068     <Extension> Public Function RunCLI(Interpreter As Type, args$, executeEmpty As ExecuteEmptyCLI, executeNotFound As ExecuteNotFound,
1069                                        <CallerMemberName>
1070                                        Optional caller$ = NothingAs Integer
1071         Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, executeEmpty, executeNotFound, Nothing)
1072     End Function
1073
1074     ''' <summary>
1075     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1076     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1077     ''' </summary>
1078     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1079     ''' <returns>Returns the function execute result to the operating system.</returns>
1080     '''
1081     <ExportAPI("RunCLI")>
1082     <Extension> Public Function RunCLI(Interpreter As Type, args As CLI, executeEmpty As ExecuteEmptyCLI, executeNotFound As ExecuteNotFound,
1083                                        <CallerMemberName>
1084                                        Optional caller$ = NothingAs Integer
1085         Return Interpreter.RunCLIInternal(args, caller, executeEmpty, executeNotFound, Nothing)
1086     End Function
1087
1088     <Extension>
1089     Private Function RunCLIInternal(App As Type, args As CLI, caller$,
1090                                     executeEmpty As ExecuteEmptyCLI,
1091                                     executeNotFound As ExecuteNotFound,
1092                                     executeFile As ExecuteFile) As Integer
1093 #If DEBUG Then
1094         Call args.__DEBUG_ECHO
1095 #End If
1096         Call args.InitDebuggerEnvir(caller)
1097
1098         If args.Name.TextEquals("/i"Then
1099             ' 交互式终端模式
1100             Dim console As New InteractiveConsole(App)
1101             Return __completeCLI(console.RunApp)
1102         Else
1103             Dim program As New Interpreter(App, caller:=caller) With {
1104                 .ExecuteEmptyCli = executeEmpty,
1105                 .ExecuteNotFound = executeNotFound,
1106                 .ExecuteFile = executeFile
1107             }
1108
1109             Return __completeCLI(program.Execute(args))
1110         End If
1111     End Function
1112
1113     ''' <summary>
1114     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1115     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1116     ''' </summary>
1117     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1118     ''' <returns>Returns the function execute result to the operating system.</returns>
1119     '''
1120     <ExportAPI("RunCLI")>
1121     <Extension> Public Function RunCLI(Interpreter As Type, args$, executeFile As ExecuteFile, <CallerMemberName> Optional caller$ = NothingAs Integer
1122         Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, NothingNothing, executeFile)
1123     End Function
1124
1125     ''' <summary>
1126     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1127     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1128     ''' </summary>
1129     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1130     ''' <returns>Returns the function execute result to the operating system.</returns>
1131     ''' <param name="executeFile">
1132     ''' 函数指针:
1133     ''' ```vbnet
1134     ''' Function ExecuteFile(path As <see cref="String"/>, args As <see cref="CommandLine"/>) As <see cref="Integer"/>
1135     ''' ```
1136     ''' </param>
1137     <ExportAPI("RunCLI")>
1138     <Extension> Public Function RunCLI(Interpreter As Type, args As CLI, executeFile As ExecuteFile, <CallerMemberName> Optional caller$ = NothingAs Integer
1139         Return Interpreter.RunCLIInternal(args, caller, NothingNothing, executeFile)
1140     End Function
1141
1142     ''' <summary>
1143     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1144     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1145     ''' </summary>
1146     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1147     ''' <returns>Returns the function execute result to the operating system.</returns>
1148     '''
1149     <ExportAPI("RunCLI")>
1150     <Extension> Public Function RunCLI(Interpreter As Type, args$, executeFile As ExecuteFile, executeEmpty As ExecuteEmptyCLI,
1151                                        <CallerMemberName>
1152                                        Optional caller$ = NothingAs Integer
1153         Return Interpreter.RunCLI(TryParse(args), executeFile, executeEmpty, caller)
1154     End Function
1155
1156     ''' <summary>
1157     ''' Running the string as a cli command line.(请注意,在调试模式之下,命令行解释器会在运行完命令之后暂停,而Release模式之下则不会。
1158     ''' 假若在调试模式之下发现程序有很长一段时间处于cpu占用为零的静止状态,则很有可能已经运行完命令并且等待回车退出)
1159     ''' </summary>
1160     ''' <param name="args">The command line arguments value, which its value can be gets from the <see cref="Command()"/> function.</param>
1161     ''' <returns>Returns the function execute result to the operating system.</returns>
1162     '''
1163     <ExportAPI("RunCLI")>
1164     <Extension> Public Function RunCLI(Interpreter As Type, args As CLI, executeFile As ExecuteFile, executeEmpty As ExecuteEmptyCLI,
1165                                        <CallerMemberName>
1166                                        Optional caller$ = NothingAs Integer
1167         Return Interpreter.RunCLIInternal(args, caller, executeEmpty, Nothing, executeFile)
1168     End Function
1169 #End If
1170
1171     ''' <summary>
1172     ''' IF the flag is True, that means cli API execute successfully, function returns ZERO, or a negative integer(Default -100) for failures.
1173     ''' </summary>
1174     ''' <param name="b"></param>
1175     ''' <param name="Failed"></param>
1176     ''' <returns></returns>
1177     <MethodImpl(MethodImplOptions.AggressiveInlining)>
1178     <Extension> Public Function CLICode(b As BooleanOptional Failed As Integer = -100) As Integer
1179         Return If(b, 0, Failed)
1180     End Function
1181
1182 #End Region
1183
1184     ''' <summary>
1185     ''' Creates a uniquely named zero-byte temporary file on disk and returns the full
1186     ''' path of that file.
1187     ''' </summary>
1188     ''' <returns></returns>
1189     '''
1190     <ExportAPI("GetTempFile")>
1191     Public Function GetTempFile() As String
1192         Dim Temp As String = FileIO.FileSystem.GetTempFileName
1193         Return GenerateTemp(Temp, "")
1194     End Function
1195
1196     ''' <summary>
1197     ''' Get temp file name in app system temp directory.
1198     ''' </summary>
1199     ''' <param name="ext"></param>
1200     ''' <param name="sessionID"></param>
1201     ''' <returns></returns>
1202     '''
1203     <ExportAPI("GetTempFile.AppSys")>
1204     Public Function GetAppSysTempFile(Optional ext$ = ".tmp"Optional sessionID$ = ""As String
1205         Dim tmp As String = App.SysTemp & "/" & __getTEMP() & ext  '  FileIO.FileSystem.GetTempFileName.Replace(".tmp", ext)
1206         tmp = GenerateTemp(tmp, sessionID)
1207         Call FileIO.FileSystem.CreateDirectory(FileIO.FileSystem.GetParentPath(tmp))
1208         tmp = FileIO.FileSystem.GetFileInfo(tmp).FullName.Replace("\""/")
1209         Return tmp
1210     End Function
1211
1212     Public ReadOnly Property CurrentProcessTemp As String
1213
1214     ''' <summary>
1215     '''
1216     ''' </summary>
1217     ''' <param name="sysTemp">临时文件路径</param>
1218     ''' <returns></returns>
1219     '''
1220     <ExportAPI("CreateTempFile")>
1221     Public Function GenerateTemp(sysTemp$, SessionID$) As String
1222         Dim Dir As String = FileIO.FileSystem.GetParentPath(sysTemp)
1223         Dim Name As String = FileIO.FileSystem.GetFileInfo(sysTemp).Name
1224         sysTemp = $"{Dir}/{App.AssemblyName}/{SessionID}/{Name}"
1225         Return sysTemp
1226     End Function
1227
1228     ''' <summary>
1229     ''' Gets a temp file name which is located at directory <see cref="App.ProductSharedDIR"/>.
1230     ''' (获取位于共享文件夹<see cref="App.ProductSharedDIR"/>里面的临时文件)
1231     ''' </summary>
1232     ''' <returns></returns>
1233     '''
1234     <ExportAPI("Shared.TempFile")>
1235     Public Function GetProductSharedTemp() As String
1236         'Dim Temp As String = FileIO.FileSystem.GetTempFileName
1237         Dim Name As String = App.__getTEMPhash  'FileIO.FileSystem.GetFileInfo(Temp).Name
1238         'Name = Name.ToUpper.Replace("TMP""")
1239         Dim Temp = $"{App.ProductSharedTemp}/{App.AssemblyName}-{Name}.tmp"
1240         Return Temp
1241     End Function
1242
1243     Public ReadOnly Property ProductSharedTemp As String
1244
1245     ''' <summary>
1246     ''' Gets a <see cref="System.PlatformID"/> enumeration value that identifies the operating system
1247     ''' platform.
1248     ''' </summary>
1249     ''' <remarks>One of the System.PlatformID values.</remarks>
1250     Public ReadOnly Property Platform As PlatformID = Environment.OSVersion.Platform
1251
1252     ''' <summary>
1253     ''' Self call this program itself for batch parallel task calculation.
1254     ''' (调用自身程序,这个通常是应用于批量的数据的计算任务的实现)
1255     ''' </summary>
1256     ''' <param name="CLI"></param>
1257     ''' <returns></returns>
1258     <MethodImpl(MethodImplOptions.AggressiveInlining)>
1259     <ExportAPI("Folk.Self")>
1260     Public Function SelfFolk(CLI As StringAs IIORedirectAbstract
1261         Return Shell(App.ExecutablePath, CLI, CLR:=True)
1262     End Function
1263
1264     ''' <summary>
1265     ''' Folk helper for running the other .NET application.
1266     ''' (请注意,这个函数只能够运行.NET程序, 假若是在Linux系统之上,还需要安装mono运行时环境)
1267     ''' </summary>
1268     ''' <param name="app">External application file full path</param>
1269     ''' <param name="CLI">Commandline string that running the application <paramref name="app$"/></param>
1270     ''' <param name="CLR">Is the calling external application is a .NET application?
1271     ''' (是否为.NET程序?)
1272     ''' </param>
1273     ''' <returns></returns>
1274     ''' <remarks><see cref="IORedirectFile"/>这个建议在进行外部调用的时候才使用</remarks>
1275     Public Function Shell(app$, CLI$,
1276                           Optional CLR As Boolean = False,
1277                           Optional stdin$ = NothingAs IIORedirectAbstract
1278
1279         If Not IsMicrosoftPlatform Then
1280             If CLR Then
1281                 Dim process As New ProcessEx With {
1282                     .Bin = "mono",
1283                     .CLIArguments = app.CLIPath & " " & CLI
1284                 }
1285                 Return process
1286             Else
1287                 Dim process As New IORedirectFile(app, CLI, stdin:=stdin)
1288                 Return process
1289             End If
1290         Else
1291             If CLR Then
1292                 Return New IORedirect(app, CLI) ' 由于是重新调用自己,所以这个重定向是没有多大问题的
1293             Else
1294                 Dim process As New IORedirectFile(app, CLI, stdin:=stdin)
1295                 Return process
1296             End If
1297         End If
1298     End Function
1299
1300     ''' <summary>
1301     ''' Folk this program itself for the large amount data batch processing.
1302     ''' </summary>
1303     ''' <param name="CLI">Self folk processing commandline collection.</param>
1304     ''' <param name="parallel">If this parameter value less than 1, then will be a single 
1305     ''' thread task. Any positive value that greater than 1 will be parallel task.
1306     ''' (小于等于零表示非并行化,单线程任务)
1307     ''' </param>
1308     ''' <param name="smart">Smart mode CPU load threshold, if the <paramref name="parallel"/> 
1309     ''' parameter value is less than or equals to 1, then this parameter will be disabled.
1310     ''' </param>
1311     ''' <returns>
1312     ''' Returns the total executation time for running this task collection.
1313     ''' (返回任务的执行的总时长)
1314     ''' </returns>
1315     <ExportAPI("Folk.Self")>
1316     Public Function SelfFolks&(CLI As IEnumerable(Of String),
1317                                Optional parallel% = 0,
1318                                Optional smart# = 0)
1319
1320         Dim sw As Stopwatch = Stopwatch.StartNew
1321
1322         If parallel <= 0 Then
1323             For Each args As String In CLI
1324                 Call App.SelfFolk(args).Run()
1325             Next
1326         Else
1327             Dim Tasks As Func(Of Integer)() = LinqAPI.Exec(Of Func(Of Integer)) <=
1328  _
1329                 From args As String
1330                 In CLI
1331                 Let io As IIORedirectAbstract = App.SelfFolk(args)
1332                 Let task As Func(Of Integer) = AddressOf io.Run
1333                 Select task
1334
1335             Call BatchTask(Of Integer)(Tasks, parallel, TimeInterval:=200)
1336         End If
1337
1338         Return sw.ElapsedMilliseconds
1339     End Function
1340
1341 #Region "Auto Garbage Cleaner"
1342
1343     ''' <summary>
1344     ''' 自动垃圾回收线程
1345     ''' </summary>
1346     ReadOnly __GCThread As New UpdateThread(10 * 60 * 1000, AddressOf App.__GCThreadInvoke)
1347
1348     Dim _CLIAutoClean As Boolean = False
1349     Dim __exitHooks As New List(Of Action)
1350
1351     ''' <summary>
1352     ''' 这里添加在应用程序退出执行的时候所需要完成的任务
1353     ''' </summary>
1354     ''' <param name="hook"></param>
1355     ''' 
1356     <MethodImpl(MethodImplOptions.AggressiveInlining)>
1357     Public Sub AddExitCleanHook(hook As Action)
1358         SyncLock __exitHooks
1359             With __exitHooks
1360                 Call .Add(hook)
1361             End With
1362         End SyncLock
1363     End Sub
1364
1365     ''' <summary>
1366     ''' 自动停止GC当前程序的线程
1367     ''' </summary>
1368     ''' <param name="state"></param>
1369     ''' <returns></returns>
1370     Private Function __completeCLI(state As IntegerAs Integer
1371         App._Running = False
1372
1373         If _CLIAutoClean Then
1374             Call StopGC()
1375         End If
1376
1377         ' 在这里等待终端的内部线程输出工作完毕,防止信息的输出错位
1378
1379         Call Terminal.WaitQueue()
1380         Call Console.WriteLine()
1381
1382         For Each hook As Action In __exitHooks
1383             Call hook()
1384         Next
1385
1386         Call Terminal.WaitQueue()
1387         Call Console.WriteLine()
1388
1389 #If DEBUG Then
1390         ' this option enable you disable the pause in debug mode 
1391         ' when the program is going to end.
1392         If Not App.GetVariable("pause.disable").ParseBoolean = True Then
1393             ' 应用程序在 debug 模式下会自动停止在这里
1394             Call Pause()
1395         End If
1396 #End If
1397         Return state
1398     End Function
1399
1400     ''' <summary>
1401     ''' Start the automatic garbage collection threads.
1402     ''' (这条线程只会自动清理*.tmp临时文件,因为假若不清理临时文件的话,有时候临时文件比较多的时候,会严重影响性能,甚至无法运行应用程序框架里面的IO重定向操作)
1403     ''' </summary>
1404     Public Sub StartGC(autoClose As Boolean)
1405         ' 因为有一部分程序假若在执行一个很长的任务的话,是会将一些中间文件存放在临时文件夹的
1406         ' 使用这个自动清理功能的函数,可能会将这些有用的中间文件给删除掉
1407         ' 所以在这里给出一条警告信息,方便在调试的时候了解这个自动垃圾回收线程是否被启动了
1408         Call App.__GCThread.Start()
1409         Call "Garbage auto collection thread started!".Warning
1410
1411         App._CLIAutoClean = autoClose
1412     End Sub
1413
1414     ''' <summary>
1415     ''' 自动垃圾回收线程
1416     ''' </summary>
1417     Private Sub __GCThreadInvoke()
1418
1419         Call App.__removesTEMP(App.SysTemp)
1420         Call App.__removesTEMP(App.AppSystemTemp)
1421         Call App.__removesTEMP(App.ProductSharedTemp)
1422         Call App.__removesTEMP(App.LocalDataTemp)
1423
1424         Call FlushMemory()
1425     End Sub
1426
1427     <Extension>
1428     Private Function __listFiles(DIR As StringAs IEnumerable(Of String)
1429         Try
1430             Return ls - l - r - {"*.tmp""*.temp"} <= DIR
1431         Catch ex As Exception
1432             Call App.LogException(ex)
1433             Return {}
1434         End Try
1435     End Function
1436
1437     ''' <summary>
1438     ''' The Windows file system have a limit of the numbers in a folder, so the long time running application 
1439     ''' required a thread to make the temp directory cleanup, or the application will no able to create temp 
1440     ''' file when the temp folder reach its file number upbound(This may caused the application crashed).
1441     ''' </summary>
1442     ''' <param name="TEMP"></param>
1443     Private Sub __removesTEMP(TEMP As String)
1444         For Each file As String In TEMP.__listFiles
1445             Try
1446                 Call FileIO.FileSystem.DeleteFile(file)
1447             Finally
1448                 ' DO Nothing
1449             End Try
1450         Next
1451     End Sub
1452
1453     ''' <summary>
1454     ''' Stop the automatic garbage collection threads.
1455     ''' </summary>
1456     Public Sub StopGC()
1457         Call App.__GCThread.Stop()
1458     End Sub
1459 #End Region
1460
1461     ''' <summary>
1462     ''' Restart the current process with administrator credentials.(以管理员的身份重启本应用程序)
1463     ''' </summary>
1464     <MethodImpl(MethodImplOptions.AggressiveInlining)>
1465     Public Sub RunAsAdmin(Optional args$ = "")
1466         Call RestartElevated(args)
1467     End Sub
1468 End Module