327 lines
13 KiB
C#
327 lines
13 KiB
C#
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());
|
||
}
|
||
}
|
||
}
|
||
*/ |