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