using System.IO; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text.Json; using System.Threading.Tasks; using static System.Net.Mime.MediaTypeNames; //using WinIPC.Utils using Google.Protobuf; using System; using System.IO; using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; using WinIPC.Models; // Предполагается, что сгенерированные Protobuf-классы находятся здесь namespace IpcCliClient { class Program { private static readonly string _pipeName = "Global\\ProcessMonitoringService.UserAgent.Pipe"; private static uint _requestId = 0; static async Task Main(string[] args) { Console.WriteLine("Клиентское приложение для тестирования IPC."); Console.WriteLine("Введите команду (например, get_windows) или 'exit' для выхода."); Console.WriteLine("---------------------------------------------"); while (true) { Console.Write("> "); string command = Console.ReadLine()?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(command)) { continue; } if (command.Equals("exit", StringComparison.OrdinalIgnoreCase)) { break; } try { await ExecuteCommand(command); } catch (Exception ex) { Console.WriteLine($"Ошибка: {ex.Message}"); } } Console.WriteLine("Приложение завершено."); } /// /// Выполняет команду, введенную пользователем. /// private static async Task ExecuteCommand(string command) { Request request = new Request(); string responseMessage = string.Empty; bool handled = true; switch (command.ToLowerInvariant()) { case "get_windows": request.Id = ++_requestId; request.Type = CommandType.GetWindowsInfo; Console.WriteLine("Отправка запроса на получение списка окон..."); responseMessage = "Список окон:"; break; // TODO: Добавить другие команды (get_screenshot, get_pixel_color, input_action) // как только будут определены их структуры запросов/ответов. default: Console.WriteLine($"Неизвестная команда: '{command}'"); handled = false; break; } if (handled) { await SendAndReceive(request, responseMessage); } } /// /// Отправляет запрос и получает ответ от сервера. /// private static async Task SendAndReceive(Request request, string successMessage) { try { using (var pipeClient = new NamedPipeClientStream(".", _pipeName, PipeDirection.InOut)) { Console.WriteLine("Подключение к IPC серверу..."); await pipeClient.ConnectAsync(5000); // Таймаут 5 секунд Console.WriteLine("Подключено."); // Сериализация и отправка запроса byte[] requestBytes = request.ToByteArray(); await WriteMessageAsync(pipeClient, requestBytes, CancellationToken.None); // Чтение ответа byte[] responseBytes = await ReadMessageAsync(pipeClient, CancellationToken.None); var response = Response.Parser.ParseFrom(responseBytes); // Обработка ответа if (response.Success) { Console.WriteLine($"Успешно: {successMessage}"); if (response.Type == CommandType.GetWindowsInfo && response.Payload != null) { var windowsResponse = WindowsResponse.Parser.ParseFrom(response.Payload); Console.WriteLine($"Найдено {windowsResponse.Data.Count} окон:"); foreach (var window in windowsResponse.Data) { Console.WriteLine($" - HWND: {window.Hwnd}, PID: {window.Pid}, Title: '{window.Title}'"); } } else { Console.WriteLine($"Получен успешный ответ. Сообщение: {response.Message}"); } } else { Console.WriteLine($"Ошибка ответа: {response.Message}"); } } } catch (TimeoutException) { Console.WriteLine("Ошибка: Таймаут подключения к серверу."); } catch (Exception ex) { Console.WriteLine($"Ошибка при взаимодействии с сервером: {ex.Message}"); } } /// /// Читает сообщение из pipe. /// private static async Task ReadMessageAsync(PipeStream pipe, CancellationToken cTok) { // Чтение префикса длины (4 байта) byte[] lengthBytes = new byte[4]; int bytesRead = await pipe.ReadAsync(lengthBytes, 0, 4, cTok); if (bytesRead < 4) { throw new EndOfStreamException("Поток закрыт или достигнут конец потока при чтении длины сообщения."); } int messageLength = BitConverter.ToInt32(lengthBytes, 0); if (messageLength <= 0) { throw new InvalidDataException($"Получена некорректная длина сообщения: {messageLength}."); } // Чтение самого сообщения byte[] messageBytes = new byte[messageLength]; bytesRead = 0; while (bytesRead < messageLength) { int read = await pipe.ReadAsync(messageBytes, bytesRead, messageLength - bytesRead, cTok); if (read == 0) { throw new EndOfStreamException($"Поток закрыт или достигнут конец потока при чтении полезной нагрузки. Ожидалось {messageLength} байт, прочитано {bytesRead}."); } bytesRead += read; } return messageBytes; } /// /// Записывает сообщение в pipe. /// private static async Task WriteMessageAsync(PipeStream pipe, byte[] messageBytes, CancellationToken cTok) { byte[] lengthPrefix = BitConverter.GetBytes(messageBytes.Length); await pipe.WriteAsync(lengthPrefix, 0, lengthPrefix.Length, cTok); await pipe.WriteAsync(messageBytes, 0, messageBytes.Length, cTok); await pipe.FlushAsync(cTok); } } } /* public class Datagram { public IPCWindowInfo Info; public string Title { get; set; } = String.Empty; public int Hwnd { get => Info.Hwnd; } public uint Pid { get => Info.Pid; } public uint ThreadId { get => Info.ThreadId; } public bool IsActive { get => Info.IsActive; } public int CursorX { get => Info.CursorX; } public int CursorY { get => Info.CursorY; } public int ContentWidth { get => Info.ContentWidth; } public int ContentHeight { get => Info.ContentHeight; } public int WindowX { get => Info.WindowX; } public int WindowY { get => Info.WindowY; } public int WindowWidth { get => Info.WindowWidth; } public int WindowHeight { get => Info.WindowHeight; } } public class Program { public static async Task Main(string[] args) { Console.WriteLine("IPC Client started. Press any key to send a 'GetWindows' request..."); Console.ReadKey(); await SendGetWindowsRequest(); Console.WriteLine("\nPress any key to exit."); Console.ReadKey(); } private static async Task SendGetWindowsRequest() { try { using (var pipe = new NamedPipeClientStream( ".", // Сервер находится на локальной машине IPC.PipeName, PipeDirection.InOut, PipeOptions.Asynchronous, TokenImpersonationLevel.None, HandleInheritability.None)) { Console.WriteLine($"Connecting to pipe: {IPC.PipeName}..."); await pipe.ConnectAsync(5000); // Таймаут 5 секунд Console.WriteLine("Connected to pipe!"); IPCPayload payload; #if WINDOWS if (IPC.SerializeIPC(new IPCHeader { Type = IPCType.ListWindows }, 0, out var data) > 0) { Console.WriteLine($"Writing to pipe..."); if (await IPC.WriteMessageAsync(pipe, data, CancellationToken.None)) { Console.WriteLine($"Writing successful"); Console.WriteLine($"Reading from pipe..."); if ((payload = await IPC.ReadMessageAsync(pipe, CancellationToken.None)).Header.Type == (IPCType.Response | IPCType.ListWindows)) { Console.WriteLine($"Reading successful"); var s = (IEnumerable?)payload.Data; var d = new List(); if (s != null) { foreach (var p in s) { d.Add(new Datagram { Info = p.Info, Title = p.Title }); } } Console.WriteLine($"Received response: {JsonSerializer.Serialize(d)}"); } else { Console.WriteLine($"Not received! ID: {payload.Header.ID}, Code: {payload.Header.Code}, Type: {payload.Header.Type}"); } } } #endif #if IMAGE if (IPC.SerializeIPC(new IPCHeader { Type = IPCType.GetScreenshot }, 0, out var d1) > 0 && IPC.SerializeIPC(new IPCScreenshotRequest { Hwnd = 66982 }, 0, out var d2) > 0) { byte[] data = new byte[d1.Length + d2.Length]; Buffer.BlockCopy(d1, 0, data, 0, d1.Length); Buffer.BlockCopy(d2, 0, data, d1.Length, d2.Length); Console.WriteLine($"Writing to pipe..."); if (await IPC.WriteMessageAsync(pipe, data, CancellationToken.None)) { Console.WriteLine($"Writing successful"); Console.WriteLine($"Reading from pipe..."); if ((payload = await IPC.ReadMessageAsync(pipe, CancellationToken.None)).Header.Type == (IPCType.Response | IPCType.GetScreenshot)) { Console.WriteLine($"Reading successful"); var s = (IPCScreenshotPayload?)payload.Data; var d = new List(); if (s != null) { using (FileStream fs = new FileStream("C:\\Users\\lirent\\test.png", FileMode.Create, FileAccess.Write, FileShare.None)) { await fs.WriteAsync(s.Value.Image, 0, s.Value.Image.Length); } Console.WriteLine("See C:\\Users\\lirent\\test.png"); } } else { Console.WriteLine($"Not received! ID: {payload.Header.ID}, Code: {payload.Header.Code}, Type: {payload.Header.Type}"); } } } #endif } } catch (TimeoutException) { Console.WriteLine("Connection to pipe timed out. Ensure UserSessionAgent is running."); } catch (Exception ex) { Console.WriteLine($"An error occurred: {ex.Message}"); Console.WriteLine(ex.ToString()); } } } */