Добрый день. У меня, на домашнем компе, в качестве обоев установлен черный цвет, и я к нему привык, мне удобно работать с таким фоном. На моем не домашнем компе, стоят обои, довольно светлые. При смене обоев на черный цвет, через некоторое время, обои возвращаются. Поменять обои на черный цвет не трудно: ПКМ->Персонализация->итд . Но я решил менять фон рабочего стола программно. Исходный текст на 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 _TEST switch (*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; } #else switch (*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"; #else filePath = 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 //Изменение фона через COM HRESULT hr = ChangeDesktopBackgroundColor(blackColor); if (SUCCEEDED(hr)) { SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDWININICHANGE); } #else //Изменение фона через WINAPI if (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 - шутка, но почему бы и нет ?!
Спасибо за внимание, буду рад, если мой труд был не напрасен и кому-то окажется полезным.
