Добрый день. У меня, на домашнем компе, в качестве обоев установлен черный цвет, и я к нему привык, мне удобно работать с таким фоном. На моем не домашнем компе, стоят обои, довольно светлые. При смене обоев на черный цвет, через некоторое время, обои возвращаются. Поменять обои на черный цвет не трудно: ПКМ->Персонализация->итд . Но я решил менять фон рабочего стола программно. Исходный текст на GitHub’е (https://github.com/bvr63/ChangeDesktopColor). Написана на C++, в VS2026. Программа циклически меняет фон рабочего стола: Файл ->Solid Color->Файл ->Solid Color->…
Ниже опишу некоторые моменты.
Программа консольная, для windows.При запуске программы я не хочу видеть окно консоли => окно консоли надо скрыть. В программе есть 2 варианта скрыть окно.
-
HWND hWnd = GetConsoleWindow();ShowWindow(hWnd, SW_HIDE);
Получить хендл окна, затем скрыть окно. При этом варианте окно создается, потом скрывается, есть эффект мелькания. -
Использовать директивы для линкера
#pragma comment(linker, "/subsystem:windows")#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
Первая директива предписывает линкеру собрать приложение как Windows GUI и искать точку входа WinMain(). Вторая директива — скрывает консоль и предписывает линкеру искать main(). При таком решении окно консоли вообще не создается, и как следствие, нет мелькания. Эти директивы применяются для всех конфигураций, кроме Debug.
#ifndef _DEBUG//скрыть консольное окно: либо программно скрыть его сразу после запуска //ShowWindow(hWnd, SW_HIDE), либо настроить проект так, чтобы оно вообще не создавалось // /subsystem:windows#pragma comment(linker, "/subsystem:windows")#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")#endif // _DEBUG
Менять фон рабочего стола можно через COM или WINAPI. В программе определена #define MyCOM для выбора используемой технологии.
//Если определена MyCOM, то обновление фона через СОМ, иначе через WINAPI
//#define MyCOM
Мне WINAPI больше нравится, я использовал его. COM оставил для информации.
В программе определено 3 конфигурации: Debug, Release, TEST. Конфигурация TEST наследована от Release. Для конфигурации TEST в свойствах проекта в разделе C/C++ -> Препроцессор -> Определения препроцессора добавлена _TEST .
Опишу TEST. Release отличается от TEST тем, что файлы обоев могут располагаться на разных дисках, в разных папках. При конфигурации TEST, файлы обоев должны располагаться в папке с программой и должны быть 0.jpg, 1.jpg, 2.jpg, 3.jpg, 4.jpg.
Если раскомментировать #define _TEST, то можно отлаживать фактически конфигурацию TEST в конфигурации Debug.
#ifdef _TESTswitch (*argv[1]) {case '0':filePath = dir.wstring() + L"\\0.jpg";fileName = L"0.jpg";break;case '1':filePath = dir.wstring() + L"\\1.jpg";fileName = L"1.jpg";break;..................................................... default:filePath = dir.wstring() + L"\\4.jpg";fileName = L"4.jpg";break;}#elseswitch (*argv[1]) {case '0':filePath = L"C:\\folder\\subfolder\\subfolder\\filename0.jpg";fileName = L"filename0.jpg";break;case '1':filePath = L"C:\\folder\\subfolder\\subfolder\\filename1.jpg";fileName = L"filename1.jpg";break;..................................................... default:filePath = L"C:\\folder\\subfolder\\subfolder\\filename4.jpg";fileName = L"filename4.jpg";break;}#endif //_TEST
При запуске программы, определяем папку расположения программы. При запуске из командной строки argv[0]=»», поэтому используем GetModuleFileName. Для конфигурации Release нет необходимости определять папку запуска программы, так как файлы обоев содержат полные пути к файлам. Присваиваем filePath и fileName значения, которые будут использоваться по умолчанию.
#ifdef _TEST//Получаем путь расположения программыwchar_t pathTmp[MAX_PATH] = { L'\0' };GetModuleFileName(NULL, pathTmp, MAX_PATH);//std::filesystem::path dir = ((std::filesystem::path)argv[0]).parent_path();//из командной строки не работаетstd::filesystem::path dir = ((std::filesystem::path)pathTmp).parent_path();filePath = dir.wstring() + L"\\0.jpg";fileName = L"0.jpg";#elsefilePath = L"C:\\folder\\subfolder\\subfolder\\filename0.jpg";fileName = L"filename0.jpg";#endif // _TEST
Так как программа для личного использования, расположение файлов обоев прописаны в самом тексте
filePath = dir.wstring() + L»\\0.jpg»; //для конфигурации TEST
fileName = L»0.jpg»; //для конфигурации TEST
filePath = L»C:\\folder\\subfolder\\subfolder\\filename0.jpg»; //для конфигурации Release
fileName = L»filename0.jpg»; //для конфигурации Release
Проверяем, что сейчас установлено в качестве обоев
wchar_t wallFile[MAX_PATH] = { L'\0' };SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallFile, 0);wchar_t* ptr = wcsstr(wallFile, fileName.c_str());
Если в качестве обоев используется файл, то в wallFile будет имя файла, если используется сплошной цвет, то wallFile=»». В 3 строчке ищем вхождение fileName в wallFile. Если вхождение не найдено (используется сплошной цвет или другой файл), указатель ptr будет нулевым.
Кстати, строчки 1, 2 можно использовать для определения какой файл используется для обоев.
В зависимости от ptr и существует ли файл filePath устанавливаем либо файл в качестве обоев, либо сплошной цвет. И рассылаем сообщения всем окнам SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDWININICHANGE);
if (!ptr && std::filesystem::exists(filePath)) {BOOL result = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (void*)filePath.c_str(), SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);}else {//При этом варианте окно создается, потом скрывается, есть эффект мелькания// HWND hWnd = GetConsoleWindow();// ShowWindow(hWnd, SW_HIDE);//Задаем цветCOLORREF blackColor = RGB(0, 0, 0);#ifdef MyCOM//Изменение фона через COMHRESULT hr = ChangeDesktopBackgroundColor(blackColor);if (SUCCEEDED(hr)) {SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDWININICHANGE);}#else//Изменение фона через WINAPIif (SetDesktopSolidColor(blackColor)) {SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDWININICHANGE);}#endif // MyCOM }
На этом собственно все о программе, ниже несколько слов о запуске и использовании шпаргалок в качестве обоев.
При компиляции в конфигурации TEST, файлы фона рабочего стола должны иметь названия 0.jpg, 1.jpg, 2.jpg, 3.jpg, 4.jpg и располагаться в папке программы. Запуск программы: ChangeDesktopColor.exe Х, где Х от 0 до … .
|
Примеры запуска |
Файл для обоев |
|
ChangeDesktopColor.exe |
0.jpg |
|
ChangeDesktopColor.exe 0 |
0.jpg |
|
ChangeDesktopColor.exe 1 |
1.jpg |
|
ChangeDesktopColor.exe 2 |
2.jpg |
|
ChangeDesktopColor.exe 3 |
3.jpg |
|
ChangeDesktopColor.exe 4 |
4.jpg |
|
…………………………. |
…………………………. |
|
ChangeDesktopColor.exe 999 |
4.jpg |
|
ChangeDesktopColor.exe 1 2 |
0.jpg |
Исполняемый файл ChangeDesktopColor.exe скомпилированный в конфигурации TEST с образцами файлов обоев доступен по ссылке. Проверить целостность файла можно алгоритмом SHA256 (в PowerShell перейти в папку с программой и выполнить Get-FileHash ChangeDesktopColor.exe -Algorithm SHA256). Хэш файла ChangeDesktopColor.exe в таблице ниже.
|
Algorithm |
Hash |
|
SHA256 |
659323F608340C48DF42089E50D1561377A5E744A4FE7528F6F34018A57FEE54 |
Немножко про файл 0.jpg. Сейчас много мышек с большим количеством дополнительных кнопок. Используя фирменный софт, на дополнительные кнопки можно повесить комбинации клавиш, макросы, и тд и тп. Эти установки можно сохранять в разные файлы как разные профили и во время работы с разными программами/играми загружать необходимый профиль.
Я использую мышку Razer NAGA X. У нее 12 боковых кнопок + кнопка модификатор, которая еще добавляет 12 кнопок (аналог Shift на клавиатуре). Что бы они всегда были перед глазами, я сделал такой файл-шпаргалку и использую его как фон рабочего стола.
Можно наделать таких шпаргалок, и загружать их при необходимости. И еще раз про шпаргалки — файл 4.jpg — шутка, но почему бы и нет ?!
Спасибо за внимание, буду рад, если мой труд был не напрасен и кому-то окажется полезным.
ссылка на оригинал статьи https://habr.com/ru/articles/1022508/