module aimpremote; import core.sys.windows.windows; import std.typecons : Nullable; private const wstring AIMPRemoteAccessClass = "AIMP2_RemoteInfo"; private const int AIMPRemoteAccessMapFileSize = 2048; align(1) private struct AIMPRemoteFileInfo { DWORD deprecated1; BOOL active; DWORD bitRate; DWORD channels; DWORD duration; align(4) INT64 fileSize; DWORD fileMark; DWORD sampleRate; DWORD trackNumber; DWORD albumLength; DWORD artistLength; DWORD dateLength; DWORD fileNameLength; DWORD genreLength; DWORD titleLength; DWORD[6] deprecated2; }; private const int WM_AIMP_COMMAND = WM_USER + 0x75; private const int WM_AIMP_NOTIFY = WM_USER + 0x76; private const int WM_AIMP_PROPERTY = WM_USER + 0x77; private const int AIMP_RA_PROPVALUE_GET = 0; private const int AIMP_RA_PROPVALUE_SET = 1; private const int AIMP_RA_PROPERTY_MASK = 0xFFFFFFF0; private const int AIMP_RA_PROPERTY_PLAYER_STATE = 0x40; private const int AIMP_RA_PROPERTY_VOLUME = 0x50; private const int AIMP_RA_CMD_BASE = 10; private const int AIMP_RA_CMD_NEXT = AIMP_RA_CMD_BASE + 7; private const int AIMP_RA_CMD_PREV = AIMP_RA_CMD_BASE + 8; private enum TagItem { Album, Artist, Date, FileName, Genre, Title } public struct TrackInfo { wstring artist; wstring title; wstring genre; }; public enum PlayerState { Off, Stopped, Paused, Playing } public static PlayerState getPlayerState() { auto hwnd = findPlayerWindow(); if (hwnd == null) { return PlayerState.Off; } const auto state = SendMessage(hwnd, WM_AIMP_PROPERTY, AIMP_RA_PROPERTY_PLAYER_STATE | AIMP_RA_PROPVALUE_GET, 0); switch (state) { default: return PlayerState.Stopped; case 1: return PlayerState.Paused; case 2: return PlayerState.Playing; } } public static void setVolume(ubyte volume) { auto hwnd = findPlayerWindow(); if (hwnd != null) { SendMessage(hwnd, WM_AIMP_PROPERTY, AIMP_RA_PROPERTY_VOLUME | AIMP_RA_PROPVALUE_SET, volume); } } public static void nextTrack() { auto hwnd = findPlayerWindow(); if (hwnd != null) { SendMessage(hwnd, WM_AIMP_COMMAND, AIMP_RA_CMD_NEXT, 0); } } public static Nullable!TrackInfo getInfo() { import std.conv : to; import std.traits : EnumMembers; Nullable!TrackInfo result = Nullable!TrackInfo.init; auto haimp = OpenFileMapping(FILE_MAP_READ, 0, AIMPRemoteAccessClass.ptr); if (haimp == null) { result.nullify(); return result; } const auto hfilemap = MapViewOfFile(haimp, FILE_MAP_READ, 0, 0, AIMPRemoteAccessMapFileSize); if (hfilemap == null) { result.nullify(); return result; } AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; auto bytes = (cast(ubyte*) hfilemap)[0 .. AIMPRemoteAccessMapFileSize]; const wcharsize = wchar.sizeof; auto pbuff = AIMPRemoteFileInfo.sizeof; DWORD[TagItem] lengthInfo; wstring[TagItem] trackInfo; lengthInfo[TagItem.Album] = info.albumLength; lengthInfo[TagItem.Artist] = info.artistLength; lengthInfo[TagItem.Date] = info.dateLength; lengthInfo[TagItem.FileName] = info.fileNameLength; lengthInfo[TagItem.Genre] = info.genreLength; lengthInfo[TagItem.Title] = info.titleLength; foreach (index, immutable item; [EnumMembers!TagItem]) { auto key = to!TagItem(index); auto length = lengthInfo[key]; trackInfo[key] = cast(wstring)(bytes[pbuff .. (pbuff + length * wcharsize)]); pbuff += length * wcharsize; } TrackInfo r = { artist: trackInfo[TagItem.Artist], title: trackInfo[TagItem.Title], genre: trackInfo[TagItem.Genre] }; result = Nullable!TrackInfo(r); return result; } private static HWND findPlayerWindow() { return FindWindow(AIMPRemoteAccessClass.ptr, null); } /*void main() { import std.stdio : writeln, write; auto haimp = OpenFileMapping(FILE_MAP_READ, 0, AIMPRemoteAccessClass.ptr); auto hfilemap = MapViewOfFile(haimp, FILE_MAP_READ, 0, 0, AIMPRemoteAccessMapFileSize); AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; write("Bitrate: "); writeln(info.bitRate); write("Samlerate: "); writeln(info.sampleRate); write("fileSize: "); writeln(info.fileSize); auto bytes = (cast(ubyte*) hfilemap)[0 .. AIMPRemoteAccessMapFileSize]; writeln(bytes); const wcharsize = wchar.sizeof; auto pbuff = AIMPRemoteFileInfo.sizeof; DWORD[TagItem] lengthInfo; wstring[TagItem] trackInfo; lengthInfo[TagItem.Album] = info.albumLength; lengthInfo[TagItem.Artist] = info.artistLength; lengthInfo[TagItem.Date] = info.dateLength; lengthInfo[TagItem.FileName] = info.fileNameLength; lengthInfo[TagItem.Genre] = info.genreLength; lengthInfo[TagItem.Title] = info.titleLength; foreach (key; TagItem.min .. TagItem.max) { auto length = lengthInfo[key]; trackInfo[key] = cast(wstring)(bytes[pbuff .. (pbuff + length * wcharsize)]); pbuff += length * wcharsize; } foreach (key, value; trackInfo) { writeln(value); } }*/