public static void CreateProcessAsync(IMineContext mineContext) { Task.Factory.StartNew(() => { lock (_locker) { try { #if DEBUG Write.Stopwatch.Start(); #endif // 清理除当前外的Temp/Kernel Cleaner.Instance.Clear(); #if DEBUG var elapsedMilliseconds = Write.Stopwatch.Stop(); if (elapsedMilliseconds.ElapsedMilliseconds > NTStopwatch.ElapsedMilliseconds) { Write.DevTimeSpan($"耗时{elapsedMilliseconds} {nameof(MinerProcess)}.{nameof(CreateProcessAsync)}[{nameof(Cleaner)}.{nameof(Cleaner.Clear)}]"); } #endif Write.UserOk("场地打扫完毕"); // 应用超频 if (Instance.GpuProfileSet.IsOverClockEnabled(mineContext.MainCoin.GetId())) { Write.UserWarn("应用超频,如果CPU性能较差耗时可能超过1分钟,请耐心等待"); var cmd = new CoinOverClockCommand(mineContext.MainCoin.GetId()); VirtualRoot.BuildOnecePath <CoinOverClockDoneEvent>("超频完成后继续流程", LogEnum.DevConsole, message => { if (mineContext == Instance.LockedMineContext) { ContinueCreateProcess(mineContext); } }, pathId: cmd.Id); // 超频是在另一个线程执行的,因为N卡超频当cpu性能非常差时较耗时 VirtualRoot.Execute(cmd); } else { ContinueCreateProcess(mineContext); } } catch (Exception e) { Logger.ErrorDebugLine(e); Write.UserFail("挖矿内核启动失败,请联系开发人员解决"); } } }); }
public static void BuildOnecePath <TMessage>(this Window window, string description, LogEnum logType, Guid pathId, Type location, PathPriority priority, Action <TMessage> path) where TMessage : IMessage { if (WpfUtil.IsInDesignMode) { return; } if (window.Resources == null) { window.Resources = new ResourceDictionary(); } List <IMessagePathId> messagePathIds = (List <IMessagePathId>)window.Resources[messagePathIdsResourceKey]; if (messagePathIds == null) { messagePathIds = new List <IMessagePathId>(); window.Resources.Add(messagePathIdsResourceKey, messagePathIds); window.Closed += UiElement_Closed;; } var messagePathId = VirtualRoot.BuildOnecePath(description, logType, pathId, location, priority, path); messagePathIds.Add(messagePathId); }
protected override void OnStartup(StartupEventArgs e) { // 之所以提前到这里是因为升级之前可能需要下载升级器,下载升级器时需要下载器 VirtualRoot.BuildCmdPath <ShowFileDownloaderCommand>(path: message => { FileDownloader.ShowWindow(message.DownloadFileUrl, message.FileTitle, message.DownloadComplete); }, location: this.GetType()); VirtualRoot.BuildCmdPath <UpgradeCommand>(path: message => { AppRoot.Upgrade(NTMinerAppType.MinerStudio, message.FileName, message.Callback); }, location: this.GetType()); if (AppUtil.GetMutex(NTKeyword.MinerStudioAppMutex)) { this.ShutdownMode = ShutdownMode.OnExplicitShutdown; // 因为登录窗口会用到VirtualRoot.Out,而Out的延迟自动关闭消息会用到倒计时 VirtualRoot.StartTimer(new WpfTimingEventProducer()); NotiCenterWindow.ShowWindow(); AppRoot.RemoteDesktop = MsRdpRemoteDesktop.OpenRemoteDesktop; MinerStudioRoot.Login(() => { MinerStudioRoot.Init(new MinerStudioWsClient()); _ = MinerStudioService.Instance;// 访问一下从而提前拉取本地服务数据 NTMinerContext.Instance.Init(() => { _appViewFactory.BuildPaths(); UIThread.Execute(() => { MinerStudioRoot.MinerClientsWindowVm.OnPropertyChanged(nameof(MinerStudioRoot.MinerClientsWindowVm.NetTypeText)); if (RpcRoot.IsOuterNet) { MinerStudioRoot.MinerClientsWindowVm.QueryMinerClients(); } else { VirtualRoot.BuildOnecePath <ClientSetInitedEvent>("矿工集合初始化完成后刷新矿机列表界面", LogEnum.DevConsole, path: message => { MinerStudioRoot.MinerClientsWindowVm.QueryMinerClients(); }, pathId: PathId.Empty, this.GetType()); } AppRoot.NotifyIcon = ExtendedNotifyIcon.Create("群控客户端", isMinerStudio: true); VirtualRoot.Execute(new ShowMinerClientsWindowCommand(isToggle: false)); }); }); }, btnCloseClick: () => { Shutdown(); }); #region 处理显示主界面命令 VirtualRoot.BuildCmdPath <ShowMainWindowCommand>(path: message => { VirtualRoot.Execute(new ShowMinerClientsWindowCommand(isToggle: message.IsToggle)); }, location: this.GetType()); #endregion HttpServer.Start($"http://{NTKeyword.Localhost}:{NTKeyword.MinerStudioPort.ToString()}"); } else { try { _appViewFactory.ShowMainWindow(this, NTMinerAppType.MinerStudio); } catch (Exception) { DialogWindow.ShowSoftDialog(new DialogWindowViewModel( message: "另一个群控客户端正在运行但唤醒失败,请重试。", title: "错误", icon: "Icon_Error")); Process currentProcess = Process.GetCurrentProcess(); NTMiner.Windows.TaskKill.KillOtherProcess(currentProcess); } } base.OnStartup(e); }
// 创建管道,将输出通过管道转送到日志文件,然后读取日志文件内容打印到控制台 private static void CreatePipProcess(IMineContext mineContext, string kernelExeFileFullName, string arguments) { SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES { bInheritHandle = true, lpSecurityDescriptor = IntPtr.Zero, length = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)) }; //set the bInheritHandle flag so pipe handles are inherited saAttr.lpSecurityDescriptor = IntPtr.Zero; //get handle to current stdOut IntPtr mypointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STARTUPINFO))); Marshal.StructureToPtr(saAttr, mypointer, true); var bret = CreatePipe(out var hReadOut, out var hWriteOut, mypointer, 0); const uint STARTF_USESHOWWINDOW = 0x00000001; const uint STARTF_USESTDHANDLES = 0x00000100; const uint NORMAL_PRIORITY_CLASS = 0x00000020; //const short SW_SHOW = 5; const short SW_HIDE = 0; const int HANDLE_FLAG_INHERIT = 1; //ensure the read handle to pipe for stdout is not inherited SetHandleInformation(hReadOut, HANDLE_FLAG_INHERIT, 0); ////Create pipe for the child process's STDIN STARTUPINFO lpStartupInfo = new STARTUPINFO { cb = (uint)Marshal.SizeOf(typeof(STARTUPINFO)), dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW, wShowWindow = SW_HIDE, // SW_HIDE; //SW_SHOW hStdOutput = hWriteOut, hStdError = hWriteOut, hStdInput = IntPtr.Zero }; StringBuilder lpEnvironment = new StringBuilder(); // 复制父进程的环境变量 IDictionary dic = Environment.GetEnvironmentVariables(); // 追加环境变量 foreach (var item in mineContext.CoinKernel.EnvironmentVariables) { dic.Add(item.Key, item.Value); } foreach (var key in dic.Keys) { if (key == null || key.ToString().Contains("\0")) { continue; } var value = dic[key]; if (value == null || value.ToString().Contains("\0")) { continue; } lpEnvironment.Append($"{key.ToString()}={value.ToString()}\0"); } if (CreateProcess( lpApplicationName: null, lpCommandLine: new StringBuilder($"\"{kernelExeFileFullName}\" {arguments}"), lpProcessAttributes: IntPtr.Zero, lpThreadAttributes: IntPtr.Zero, bInheritHandles: true, dwCreationFlags: NORMAL_PRIORITY_CLASS, lpEnvironment: lpEnvironment, lpCurrentDirectory: Path.GetDirectoryName(kernelExeFileFullName), lpStartupInfo: ref lpStartupInfo, lpProcessInformation: out _)) { if (bret == false) { int lasterr = Marshal.GetLastWin32Error(); VirtualRoot.RaiseEvent(new StartingMineFailedEvent($"管道型进程创建失败 lasterr:{lasterr.ToString()}")); } else { IMessagePathId closeHandle = null; bool isHWriteOutHasClosed = false; KernelProcessDaemon(mineContext, () => { if (!isHWriteOutHasClosed) { CloseHandle(hWriteOut); isHWriteOutHasClosed = true; } VirtualRoot.DeletePath(closeHandle); }); closeHandle = VirtualRoot.BuildOnecePath <MineStopedEvent>("挖矿停止后关闭非托管的日志句柄", LogEnum.DevConsole, action: message => { // 挖矿停止后摘除挖矿内核进程守护器 if (_kernelProcessDaemon != null) { VirtualRoot.DeletePath(_kernelProcessDaemon); _kernelProcessDaemon = null; } if (!isHWriteOutHasClosed) { CloseHandle(hWriteOut); isHWriteOutHasClosed = true; } }, pathId: Guid.Empty); Task.Factory.StartNew(() => { using (FileStream fs = new FileStream(mineContext.LogFileFullName, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { const byte r = (byte)'\r'; byte[] buffer = new byte[1024]; int ret; // Read会阻塞,直到读取到字符或者hWriteOut被关闭 while ((ret = Read(buffer, 0, buffer.Length, hReadOut)) > 0) { byte[] data = new byte[ret]; int n = 0; for (int i = 0; i < ret; i++) { if (buffer[i] != r) { data[n] = buffer[i]; n++; } } fs.Write(data, 0, n); fs.Flush(); } } CloseHandle(hReadOut); }, TaskCreationOptions.LongRunning); ReadPrintLoopLogFileAsync(mineContext, isWriteToConsole: true); } } else { VirtualRoot.RaiseEvent(new StartingMineFailedEvent($"内核启动失败,请重试")); } }