winipc-ua-test/Program.cs

327 lines
13 KiB
C#
Raw Normal View History

2026-01-08 21:34:38 +03:00
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("Приложение завершено.");
}
/// <summary>
/// Выполняет команду, введенную пользователем.
/// </summary>
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);
}
}
/// <summary>
/// Отправляет запрос и получает ответ от сервера.
/// </summary>
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}");
}
}
/// <summary>
/// Читает сообщение из pipe.
/// </summary>
private static async Task<byte[]> 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;
}
/// <summary>
/// Записывает сообщение в pipe.
/// </summary>
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<IPCWindowInfoPayload>?)payload.Data;
var d = new List<Datagram>();
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<Datagram>();
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());
}
}
}
*/