| 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 Overloads) Sub New |
| 47 | ' |
| 48 | ' Function: __cli, __completeCLI, __getTEMP, __getTEMPhash, __isMicrosoftPlatform |
| 49 | ' __listFiles, __sysTEMP, (+2 Overloads) Argument, BugsFormatter, CLICode |
| 50 | ' ElapsedMilliseconds, Exit, FormatTime, GenerateTemp, (+2 Overloads) GetAppLocalData |
| 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 String, String) = App _ |
| 469 | .CommandLine _ |
| 470 | .EnvironmentVariables |
| 471 | |
| 472 | Call App.JoinVariables( |
| 473 | envir _ |
| 474 | .SafeQuery _ |
| 475 | .Select(Function(x) |
| 476 | Return New NamedValue(Of String) With { |
| 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$ = Nothing) As 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 String) With { |
| 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 String) In vars |
| 517 | __joinedVariables(v.Name) = v |
| 518 | Next |
| 519 | End Sub |
| 520 | |
| 521 | Public Sub JoinVariables(vars As Dictionary(Of String, String)) |
| 522 | Call App.JoinVariables(vars.Select( |
| 523 | Function(x) |
| 524 | Return New NamedValue(Of String) With { |
| 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$ = Nothing) As String |
| 543 | If __joinedVariables.ContainsKey(name) Then |
| 544 | Return __joinedVariables(name).Value |
| 545 | Else |
| 546 | For Each v As NamedValue(Of String) In __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 String) With { |
| 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 Integer) As 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%/<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 String) As 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$ = Nothing) As 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$ = Nothing) As Integer |
| 1050 | Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, Nothing, Nothing, Nothing) |
| 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$ = Nothing) As Integer |
| 1063 | Return Interpreter.RunCLIInternal(args, caller, Nothing, Nothing, Nothing) |
| 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$ = Nothing) As Integer |
| 1078 | Return Interpreter.RunCLIInternal(args, caller, executeEmpty, Nothing, Nothing) |
| 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$ = Nothing) As Integer |
| 1092 | Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, executeEmpty, Nothing, Nothing) |
| 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$ = Nothing) As 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$ = Nothing) As 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$ = Nothing) As Integer |
| 1173 | Return Interpreter.RunCLIInternal(CLITools.TryParse(args), caller, Nothing, Nothing, 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$ = Nothing) As Integer |
| 1190 | Return Interpreter.RunCLIInternal(args, caller, Nothing, Nothing, 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$ = Nothing) As 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$ = Nothing) As 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 Boolean, Optional 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 String) As 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 = False) As 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 Integer) As 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 String) As 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 |