using System; using System.IO; using System.IO.MemoryMappedFiles; using System.Runtime.InteropServices; using System.Threading; using GpuFanControl.MsiAfterburnerWrap.ShareMemoryStructs; namespace GpuFanControl.MsiAfterburnerWrap { internal class MsiAfterBurnControlWrap : IDisposable { //const private const string ShareMemoryName = "MACMSharedMemory"; private const string MutexName = "Global\\Access_MACMSharedMemory"; private const uint HeaderSignature = ('M' << 24 | ('A' << 16) | ('C' << 8) | ('M')); private MemoryMappedFile _hMapFile; private MemoryMappedViewStream _pMapAddr; private byte[] _bufSnap; public void Connect() { //connect , failure throws FileNotFoundException _hMapFile = MemoryMappedFile.OpenExisting(ShareMemoryName, MemoryMappedFileRights.FullControl); _pMapAddr = _hMapFile.CreateViewStream(); } public void Disconnect() { _pMapAddr?.Close(); _hMapFile?.Dispose(); } public void Refresh() { using (var m = new Mutex(false, MutexName)) { m.WaitOne(); var lenHeader = Marshal.SizeOf(typeof(MACM_SHARED_MEMORY_HEADER)); var bufHeader = new byte[lenHeader]; _pMapAddr.Seek(0, SeekOrigin.Begin); _pMapAddr.Read(bufHeader, 0, lenHeader); var stHeader = ByteArrayToStruct(bufHeader); if (stHeader.Signature == HeaderSignature) { var lenSnap = stHeader.HeaderSize + stHeader.GpuEntryCount * stHeader.GpuEntrySize; var bufSnap = new byte[lenSnap]; _pMapAddr.Seek(0, SeekOrigin.Begin); _pMapAddr.Read(bufSnap, 0, (int)lenSnap); _bufSnap = bufSnap; } m.ReleaseMutex(); } } public void Commit() { using (var m = new Mutex(false, MutexName)) { m.WaitOne(); _pMapAddr.Seek(0, SeekOrigin.Begin); _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length); _pMapAddr.Flush(); _pMapAddr.Seek(0, SeekOrigin.Begin); var header = ByteArrayToStruct(_bufSnap); header.Command = MACM_SHARED_MEMORY_COMMAND.FLUSH; StructToByteArray(header, _bufSnap); _pMapAddr.Seek(0, SeekOrigin.Begin); _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length); _pMapAddr.Flush(); m.ReleaseMutex(); } Refresh(); } public int GetNumberOfGpu() { var st = ByteArrayToStruct(_bufSnap); return (int)st.GpuEntryCount; } public MACM_SHARED_MEMORY_GPU_ENTRY? GetGpuEntry(int index, out string error) { var header = ByteArrayToStruct(_bufSnap); if (index > header.GpuEntryCount || index < 0) { error = "index out of range"; return null; } var entry = ByteArrayToStruct(_bufSnap, (int)header.HeaderSize + index * (int)header.GpuEntrySize); error = null; return entry; } public string SetGpuEntry(MACM_SHARED_MEMORY_GPU_ENTRY entry, int index, bool flush = false) { var header = ByteArrayToStruct(_bufSnap); if (index > header.GpuEntryCount || index < 0) return "index out of range"; StructToByteArray(entry, _bufSnap, (int)(header.HeaderSize + index * header.GpuEntrySize)); if (flush) Commit(); return null; } private T ByteArrayToStruct(byte[] bytes, int offset = 0) { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); T stuff; try { stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + offset, typeof(T)); } finally { handle.Free(); } return stuff; } private static void StructToByteArray(T str, byte[] snap, int offset = 0) { var h = default(GCHandle); try { h = GCHandle.Alloc(snap, GCHandleType.Pinned); Marshal.StructureToPtr(str, h.AddrOfPinnedObject() + offset, false); } finally { if (h.IsAllocated) { h.Free(); } } } public void Dispose() { Disconnect(); } } }