winipc-ua-test/Program.cs
2026-01-08 21:34:38 +03:00

327 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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());
}
}
}
*/