Skip to content

Instantly share code, notes, and snippets.

@z16
Created May 20, 2026 21:47
Show Gist options
  • Select an option

  • Save z16/2d022186f54b553a5444785742a4ef2d to your computer and use it in GitHub Desktop.

Select an option

Save z16/2d022186f54b553a5444785742a4ef2d to your computer and use it in GitHub Desktop.
public unsafe class Ipc {
public Ipc(String addon) {
AddonBytes = Encoding.UTF8.GetBytes(addon);
if (AddonBytes.Length >= AddonSize) {
throw new InvalidDataException("Maximum length for addon name is 31 bytes in UTF-8.");
}
}
public void Send(String message, String character) =>
Send(message, GetPid(character));
public void Send(String message, Int32? pid = null) {
var messageBytes = Encoding.UTF8.GetBytes(message);
if (messageBytes.Length >= TextSize) {
throw new InvalidDataException("Maximum length for the message is 2015 bytes in UTF-8.");
}
Send(messageBytes, pid);
}
public void Send(Byte[] messageBytes, String character) =>
Send(messageBytes, GetPid(character));
public void Send(Byte[] messageBytes, Int32? pid = null) {
if (messageBytes.Length >= TextSize) {
throw new InvalidDataException("Maximum length for the message is 2015 bytes.");
}
Mutex.WaitOne();
try {
using var instancesFile = MemoryMappedFile.CreateOrOpen(@"Local\Windower MMF IPC Instances", sizeof(Instance) * InstanceCount, MemoryMappedFileAccess.ReadWrite);
using var instancesView = instancesFile.CreateViewAccessor();
for (var i = 0; i < InstanceCount; ++i) {
instancesView.Read<Instance>(i * sizeof(Instance), out var instance);
if (instance.Id == 0 || pid.HasValue && instance.Id != pid.Value) {
continue;
}
var name = new String(instance.Name, 0, NameSize);
using var instanceFile = MemoryMappedFile.OpenExisting(@"Local\Windower MMF " + name, MemoryMappedFileRights.Write);
using var instanceView = instanceFile.CreateViewAccessor();
var offset = instance.Index * sizeof(Message);
instanceView.WriteArray(offset, AddonBytes, 0, AddonBytes.Length);
instanceView.WriteArray(offset + AddonBytes.Length, Zeroes, 0, AddonSize - AddonBytes.Length);
instanceView.WriteArray(offset + AddonSize, messageBytes, 0, messageBytes.Length);
instanceView.WriteArray(offset + AddonSize + messageBytes.Length, Zeroes, 0, TextSize - messageBytes.Length);
instancesView.Write(IndexOffset, (instance.Index + 1) % MessageCount);
using var instanceEvent = EventWaitHandle.OpenExisting(@"Local\Windower Event " + name);
instanceEvent.Set();
break;
}
} finally {
Mutex.ReleaseMutex();
}
}
private readonly Byte[] AddonBytes;
private static readonly Mutex Mutex = new(@"Local\Windower Mutex IPC", new() {
CurrentUserOnly = false,
});
private struct Instance {
public UInt32 Id;
public UInt32 Index;
public fixed Char Name[NameSize];
}
private struct Message {
public fixed Byte Addon[AddonSize];
public fixed Byte Text[TextSize];
}
private static readonly IntPtr IndexOffset = Marshal.OffsetOf<Instance>(nameof(Instance.Index));
private const Int32 InstanceCount = 100;
private const Int32 MessageCount = 0x10;
private const Int32 NameSize = 0x10;
private const Int32 AddonSize = 0x20;
private const Int32 TextSize = 0x7E0;
private static readonly Byte[] Zeroes = [.. Enumerable.Range(0, TextSize).Select(_ => (Byte)0)];
private static Int32 GetPid(String character) =>
Process.GetProcesses().Single(process => process.MainWindowTitle == character).Id;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment