private static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate HandlerRoutine, bool Add);
private static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate handlerRoutine, bool add); // 由于不支持泛型,所以采用delegate
public static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate handlerRoutine, bool Add);
static void Main(string[] args) { // 先注入一个dll,Hook要绘制的窗体的WndProc函数,吃掉WM_PAINT消息,不然任务管理器会闪烁 var dllInjectionContext = DllInjection.Injection("Taskmgr", Path.Combine(Environment.CurrentDirectory, "HookWinProc.dll")); controlCtrlDelegate = type => { switch (type) { case 0: // CTRL_C_EVENT case 2: // CTRL_CLOSE_EVENT case 5: // CTRL_LOGOFF_EVENT case 6: // CTRL_SHUTDOWN_EVENT // 控制台关闭后清理掉注入的dll DllInjection.FreeLibrary(dllInjectionContext); break; } return(true); }; SetConsoleCtrlHandler(controlCtrlDelegate, true); // 获得CPU核心数,其实我之后的代码已经写死默认是4个核心的情况 var kernelCount = Environment.ProcessorCount; var hwnd = WinApi.FindWindow("TaskManagerWindow", "任务管理器"); var root = new Window(hwnd); if (root.Childs.Count == 1 && root.Childs[0].ClassName == "NativeHWNDHost") { root = root.Childs[0]; } else { throw new Exception("未找到窗体"); } if (root.Childs.Count == 1 && root.Childs[0].ClassName == "DirectUIHWND") { root = root.Childs[0]; } else { throw new Exception("未找到窗体"); } // 拿到4个子窗体,但是顺序还不确定 var drawWindows = root.Childs .Where(w => w.ClassName == "CtrlNotifySink" && w.Childs.Count == 1 && w.Childs[0].ClassName == "CvChartWindow") .Select(w => w.Childs[0]) .OrderByDescending(w => w.Rect.Width * w.Rect.Height) .Take(kernelCount) .ToArray(); // 以下是捕获声音有关的代码,使用的是WASAPI Loopback的方式 var screenWidth = WinApi.GetScreenWidth(); FixedQueueArray <float> leftWaveQueue = new FixedQueueArray <float>(screenWidth), rightWaveQueue = new FixedQueueArray <float>(screenWidth); IWaveIn loopbackCapture = new WasapiLoopbackCapture(); var observer = new StreamObserver <float>(FFTSize, FFTSize / 2, 2); float[] leftFixedWaveData = new float[FFTSize], rightFixedWaveData = new float[FFTSize]; // 捕获声音 // leftFixedWaveData 和 rightFixedWaveData 之后会交给绘制频谱的线程处理 observer.Completed += newData => { lock (fftLock) { for (int i = 0; i < leftFixedWaveData.Length; i++) { leftFixedWaveData[i] = newData[2 * i + 0]; rightFixedWaveData[i] = newData[2 * i + 1]; } } }; // 捕获声音 // leftWaveQueue 和 rightWaveQueue 之后会交给绘制声波的线程处理 loopbackCapture.DataAvailable += (_, e) => { var waveData = MemoryMarshal.Cast <byte, float>(new ReadOnlySpan <byte>(e.Buffer, 0, e.BytesRecorded)); int copyLength = Math.Min(waveData.Length / 2, screenWidth); if (copyLength == 0) { return; } Span <float> leftNextData = stackalloc float[copyLength], rightNextData = stackalloc float[copyLength]; for (int i = 0; i < copyLength; i++) { leftNextData[i] = waveData[2 * i + 0]; rightNextData[i] = waveData[2 * i + 1]; } leftWaveQueue.Write(leftNextData); rightWaveQueue.Write(rightNextData); observer.Write(waveData); }; loopbackCapture.StartRecording(); var sampleRate = loopbackCapture.WaveFormat.SampleRate; bool polylineStyle = false; // 找出对应位置的子窗体 var leftTopWin = drawWindows.OrderBy(w => w.Rect.X + w.Rect.Y).First(); var rightTopWin = drawWindows.OrderBy(w => - w.Rect.X + w.Rect.Y).First(); var leftBottomWin = drawWindows.OrderBy(w => w.Rect.X - w.Rect.Y).First(); var rightBottomWin = drawWindows.OrderBy(w => - w.Rect.X - w.Rect.Y).First(); void StartThread(Action action) { new Thread(new ThreadStart(action)) { Priority = ThreadPriority.Highest }.Start(); } // 启动线程开始捕获声音并绘制,每个窗体一个线程 StartThread(() => DrawWave(leftTopWin, leftWaveQueue, polylineStyle, 1)); StartThread(() => DrawWave(rightTopWin, rightWaveQueue, polylineStyle, 2)); StartThread(() => DrawSpectrum(leftBottomWin, leftFixedWaveData, sampleRate, polylineStyle, 3)); StartThread(() => DrawSpectrum(rightBottomWin, rightFixedWaveData, sampleRate, polylineStyle, 4)); Thread.Sleep(Timeout.Infinite); }
public void StartService(String args) { if (_StartMode != ConsoleStartMode.Default || TCPServer != null || UDPServer != null) { Console.WriteLine("Input Arguments Exception."); return; } Console.Title = Title; _StartMode = ConsoleStartMode.Service; //安全退出处理 ControlCtrl = new ControlCtrlDelegate(ConsoleExitHandler); ConsoleApplication.SetConsoleCtrlHandler(ControlCtrl, true); //服务模式启动后不可重复启动 bool createdNew; Mutex mutex = new Mutex(true, InputHeader + ".Service", out createdNew); if (!createdNew) { Console.WriteLine("Services Error 服务正在运行中 ..."); MessageBox.Show("服务正在运行中...", "Error", MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK); Console.WriteLine("Exiting ..."); Thread.Sleep(100); Environment.Exit(0); return; } if (!String.IsNullOrWhiteSpace(args) && ConsoleApplication.Uint_Regex.IsMatch(args)) { ServicePort = Convert.ToInt32(args); } //独立线程运行服务 Thread thread = new Thread(() => { Console.Title = String.Format("{0} Port:{1}", Title, ServicePort); Console.WriteLine("{0} Starting ... ", Title); TCPServer = new TCPServer(); if (TCPServer.Start(ServicePort)) { TCPServer.ServerDataReceived += Server_DataReceived; TCPServer.ServerStateChanged += Server_StateChanged; TCPServer.ClientStateChanged += Server_ClientStateChanged; Console.WriteLine("TCP Server 启功完成 Port:{0},等待客户端连接 ...", ServicePort); } else { TCPServer.Destroy(); TCPServer = null; Console.WriteLine("TCP Server 启动失败,检查端口 {0} 是否被占用", ServicePort); } UDPServer = new UDPServer(); if (UDPServer.Start(ServicePort)) { UDPServer.ServerDataReceived += Server_DataReceived; UDPServer.ServerStateChanged += Server_StateChanged; UDPServer.ClientStateChanged += Server_ClientStateChanged; Console.WriteLine("UDP Server 启功完成 Port:{0},等待客户端连接 ...", ServicePort); } else { UDPServer.Destroy(); UDPServer = null; Console.WriteLine("UDP Server 启动失败,检查端口 {0} 是否被占用", ServicePort); } Console.Write("{0}>", InputHeader); }); thread.Name = Title; thread.Start(); //可输入模式 while (_StartMode == ConsoleStartMode.Service) { Console.Write("{0}>", InputHeader); String input = Console.ReadLine(); if (String.IsNullOrWhiteSpace(input)) { continue; } String[] arguments = ConsoleApplication.ParserInput(input); if (arguments != null) { ConsoleApplication.Run(this, arguments); } } }
public static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate HandlerRoutine, bool Add);