У каждого из нас есть свои маленькие радости, даже на фоне серой рутины. Для меня, как для обычного смертного, это был стандартный фон рабочего стола в Windows. Но, как это бывает, однажды моя жизнь пошла по новому пути, и я столкнулся с чудеснейшей картинкой, которая словно проникла в мою душу. Она стала моим вдохновением, моим маленьким островком радуги в море повседневной скуки. И, конечно же, это была картинка... ну, довольно вызывающего характера.
Сразу же в моей голове появилась идея: "Почему бы не поставить эту картинку на фон рабочего стола?". Ведь у нас есть горячие клавиши, правда? Но вот беда – ожидается общественное негодование и взгляды укоризны. Сквозь страхи и сомнения родилась невероятная идея: я напишу код, который будет мгновенно менять фон рабочего стола по нажатию горячих клавиш! Да, именно так, уважаемые читатели, я решил смело потрясти мир своим выбором обоев.
И вот, внезапно, на сцене появляется наш герой – P/Invoke! Если вы, как и я, не были в ладах с C/C++, не отчаивайтесь – P/Invoke стоит на страже ваших инноваций. Дело в том, что у меня не было ни малейшего понятия о C/C++, но это не остановило меня. Сила P/Invoke заключается в том, что он позволяет вам вызывать функции из низкоуровневых библиотек так, будто они были написаны на чистом C#. Вот как это работает:
Регистрация горячих клавиш
Мы нацелились на две магические комбинации клавиш: одну для эротического фона (да-да, я так и назвал) и другую для обычного. Итак, RegisterHotKey из "user32.dll" становится нашим верным спутником:
[DllImport("user32.dll")] public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); // Настройки для магических клавиш. public const int MOD_ALT = 0x0001; public const int MOD_CONTROL = 0x0002; public const int MOD_SHIFT = 0x0004; // Заклинания в виде клавиш. ��а этот раз мы выбрали "B" и "C". public const int VK_B = 0x42; public const int VK_C = 0x43; // Ритуальные команды для вызова заклинаний. Наши числа имеют особое значение. public const int WallpaperErroticCommand = 11; // Пора призвать эротику! public const int WallpaperNormalCommand = 12; // А здесь - обычные обои. if (RegisterHotKey(IntPtr.Zero, WallpaperErroticCommand, MOD_ALT | MOD_CONTROL, VK_B) && RegisterHotKey(IntPtr.Zero, WallpaperNormalCommand, MOD_SHIFT, VK_C)) { Console.WriteLine("Горячие клавиши успешно зарегистрированы. Время для волшебства!"); Console.WriteLine("Нажмите Ctrl+Alt+B, чтобы погрузиться в мир эротики. Это наш секрет!"); Console.WriteLine("Нажмите Shift+C, чтобы вернуться к обычным обоям. Магия тоже может быть невидимой."); } else { Console.WriteLine("Не удалось зарегистрировать горячие клавиши. Магия чуть подвела нас."); }
Получение сообщений
И вот он, грядущий момент! Наш код ждет, когда кто-то нажмет горячие клавиши. GetMessage, снова из "user32.dll", оказывается в роли почтового голубя, который приносит нам эти важные сообщения:
[DllImport("user32.dll")] public static extern bool GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); public const int WM_HOTKEY = 0x0312; MSG msg; while (GetMessage(out msg, IntPtr.Zero, 0, 0)) { // Дело в том, что когда наступает момент и горячая клавиша нажимается, // код ощущает, что что-то важное произошло. Все благодаря таинственному WM_HOTKEY, // сообщению, которое как будто шепчет: "Друг мой, нажата горячая клавиша!". if (msg.message != WM_HOTKEY) continue; // ... }
Однако перед тем, как зажечь огонь фонов рабочего стола, я вынужден был призвать на помощь двух верных спутников – MSG и POINT.
// Структура MSG – это настоящий посланник между мирами. // Она приносит с собой множество важных данных и оставляет на них свой отпечаток. [StructLayout(LayoutKind.Sequential)] public struct MSG { public IntPtr hwnd; // Окно, через которое проникают тайные сообщения. public uint message; // Секретный код сообщения, как магическая формула. public IntPtr wParam; // Внутренний атрибут для заклинаний. public IntPtr lParam; // Еще одна загадочная составляющая. public uint time; // Время, в которое произошла магия. public POINT pt; // Точка, из которой мы начинаем свое магическое путешествие. public uint lPrivate; // Загадочное личное свойство, которое всегда вызывает вопросы. // Магическая формула, раскрывающая суть MSG. public readonly override string ToString() => $"hwnd: {hwnd}, message: {message}, wParam: {wParam}, lParam: {lParam}, time: {time}, pt: {pt}, lPrivate: {lPrivate}"; } // А вот и наш друг POINT, тоже со своими тайнами. // Он умеет указывать на самые глубокие секреты координат. [StructLayout(LayoutKind.Sequential)] public struct POINT { public int x; // Секретная координата X, на которой начинается магия. public int y; // И Y, естественно, не менее загадочный. // Интригующая загадка, которую POINT оставляет нам в наследство. public readonly override string ToString() => $"x: {x}, y: {y}"; }
Установка обоев
Да-да, самая волнительная часть! Определяем, какой фон стоит поставить, и SystemParametersInfo возвращает нам победу или патовую ситуацию:
[DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); // Готовимся к великому замаху - выбору обоев! var imagePath = msg.wParam switch { WallpaperErroticCommand => WallpaperErroticPath, WallpaperNormalCommand => WallpaperNormalPath, _ => throw new InvalidOperationException($"Недопустимое значение команды {nameof(msg.wParam)}:{msg.wParam}") }; // Поднимаем путеводный факел - адрес изображения! var imagePtr = Marshal.StringToHGlobalUni(imagePath); // Открываем ворота в мир фантазий - установка обоев! if (!SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, imagePtr, 0)) { Console.WriteLine("Не удалось установить фон рабочего стола. Жизнь не по детски сложна, верно?"); } else { Console.WriteLine("Фон успешно установлен. Помните, обои – это ваше зеркало в мир!"); } // Освобождаем место для других идей - освобождение памяти! Marshal.FreeHGlobal(imagePtr);
Результат
И вот, наконец, наступило время раскрыть завесу и рассказать о результатах магических воздействий!
До нажатия Ctrl+Alt+B:

После нажатие Ctrl+Alt+B

И так, подготовьтесь к следующей главе моей истории. Нажимаю Shift+C:

Представьте, как ��удто мир вокруг меняется с каждым нажатием клавиши, как будто прикосновение волшебной палочки!
Заключение
Итак, что у нас получается? Не волнуйтесь, если мир C/C++ вам кажется далеким и непонятным, это совсем не повод опускать руки! P/Invoke – это наш надежный союзник в этом мире низкоуровневых библиотек. Так что даже если вы совсем не связаны с этими технологиями, не унывайте! Не бойтесь претворять ваши идеи в жизнь, даже если они затрагивают такой обыденный момент, как выбор обоев рабочего стола. Помните, одним маленьким шагом в коде вы можете придать жизнь всему окружающему миру!