using EasyPipes; using SoraV2Tools; using System; using System.IO; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; namespace SoraV2Utils_Service { // Interface for mouse data interaction public interface IMouseData { byte[] GetDeviceStatus(); double GetBatteryRuntime(); void Exit(); } public class ServiceIPC { // Creates pipe security for system IO private PipeSecurity CreateSystemIOPipeSecurity() { PipeSecurity pipeSecurity = new PipeSecurity(); // Assign authenticated user read-write access var authenticatedUserSid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null); pipeSecurity.SetAccessRule(new PipeAccessRule(authenticatedUserSid, PipeAccessRights.ReadWrite, AccessControlType.Allow)); return pipeSecurity; } // Opens a custom named pipe with the specified name and buffer size private NamedPipeServerStream OpenCustomPipe(string pipeName, int bufferSize) { try { var pipeSecurity = CreateSystemIOPipeSecurity(); var pipeStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, bufferSize, 0x400, pipeSecurity, HandleInheritability.Inheritable); Console.WriteLine($"Named Pipe '{pipeName}' successfully opened."); return pipeStream; } catch (Exception ex) { Console.Error.WriteLine($"Error opening pipe {pipeName}: {ex.Message}"); throw; } } // Constructor for initializing the IPC service and server public ServiceIPC() { try { var server = new Server("SoraV2UtilsDeviceData", OpenCustomPipe); server.RegisterService(new ServiceIPCHandler()); server.Start(); Console.WriteLine("IPC Service started successfully."); } catch (Exception ex) { Console.Error.WriteLine($"Failed to start IPC Service: {ex.Message}"); } } } // Handler class to implement the IMouseData interface public class ServiceIPCHandler : IMouseData { public byte[] GetDeviceStatus() { var status = DeviceTracker.Instance._DeviceStatus; try { int size = Marshal.SizeOf(status); byte[] arr = new byte[size]; IntPtr ptr = IntPtr.Zero; try { ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(status, ptr, true); Marshal.Copy(ptr, arr, 0, size); } finally { Marshal.FreeHGlobal(ptr); } return arr; } catch (Exception ex) { Console.Error.WriteLine($"Error retrieving battery level: {ex.Message}"); return null; } } public double GetBatteryRuntime() { try { return DeviceTracker.Instance?.EstimateRemainingRuntime() ?? 0.0; } catch (Exception ex) { Console.Error.WriteLine($"Error estimating battery runtime: {ex.Message}"); return 0.0; } } public void Exit() { try { // Exit the application with code 1 Console.WriteLine("Exiting application..."); Environment.Exit(1); } catch (Exception ex) { Console.Error.WriteLine($"Error during exit: {ex.Message}"); } } } }