как программно изменить текущую тему windows?

<p>я хочу, чтобы мои пользователи могли переключать текущую пользовательскую тему между <a href="https://en.wikipedia.org/wiki/windows\_aero">aero</a> и windows classic (1). есть ли способ, которым я могу сделать это программно?</p><p>я не хочу выскакивать «свойства дисплея», и я сомневаюсь в том, чтобы просто изменить реестр. (это требует выхода из системы и повторного входа, чтобы изменения вступили в силу).</p><p>скины приложений (с использованием библиотек <a href="https://en.wikipedia.org/wiki/codejock\_software">codejock</a> ) также не работают.</p><p>есть ли способ сделать это?</p><p>приложение размещено/запущено на <a href="https://en.wikipedia.org/wiki/windows\_server\_2008">windows server 2008</a> over <a href="https://en.wikipedia.org/wiki/remote\_desktop\_protocol">rdp</a> .</p><p>(1) данное приложение является размещенным «удаленным приложением», и я хочу, чтобы пользователи могли изменять внешний вид отображаемого приложения в соответствии со своим рабочим столом.</p>

<p>вы можете установить его с помощью следующей команды:</p><pre><code>rundll32.exe %systemroot%\system32\shell32.dll,control\_rundll %systemroot%\system32\desk.cpl desk,@themes /action:opentheme /file:"c:\windows\resources\themes\aero.theme" </code></pre><p>предостережение в том, что это покажет диалог выбора темы. вы можете убить этот диалог сразу после.</p>

<p>есть, конечно, веские причины для того, чтобы захотеть изменить текущую тему программно. например. инструмент автоматического тестирования может потребоваться переключаться между различными темами, чтобы убедиться, что приложение работает со всеми из них правильно.</p><p>как пользователь, вы можете изменить тему, дважды щелкнув файл <code>.theme</code> в windwos explorer, а затем закрыв всплывающее окно панели управления. вы можете легко сделать то же самое из кода. следующие шаги работают нормально для меня. я тестировал только на windows 7.</p><ol> <li>используйте <code>shgetknownfolderpath()</code>, чтобы получить папку «local appdata» для пользователя. файлы тем хранятся в подпапке <code>microsoft\windows\themes</code>. файлы тем, хранящиеся там, применяются напрямую, тогда как файлы тем, хранящиеся в другом месте, дублируются при их выполнении. поэтому лучше использовать файлы только из этой папки.</li> <li>используйте <code>shellexecute()</code> для выполнения файла <code>.theme</code>, который вы нашли в шаге 1.</li> <li>подождите, пока тема будет применена. я просто позволяю своему приложению спать в течение 2 секунд.</li> <li>вызовите <code>findwindow('cabinetwclass', 'personalization')</code>, чтобы получить дескриптор окна панели управления, которое всплывало при применении темы. надпись «персонализация», скорее всего, будет отличаться в англоязычных версиях windows.</li> <li>вызовите <code>postmessage(hwnd, wm\_close, 0, 0)</code>, чтобы закрыть окно панели управления.</li> </ol><p>это не очень элегантное решение, но оно делает свою работу.</p>

<p>я считаю, что лучшее, что вы можете сделать, - это открыть целевой файл .msstyles (в <code>c:\windows\resources\themes</code>), который откроет окно свойств дисплея. на этом этапе вы можете использовать подклассы окна, чтобы программно нажимать правые кнопки.</p>

<p>в дополнение к посту "ян гойваэртс": я использую sendmessage вместо postmessage. разница в том, что sendmessage ожидает, пока окно не примет команду. это означает, что в sendmessages возвращается, вы знаете, что диалог темы закрыт.</p><p>так что, если вы начнете его с чудовищного (но гениального) метода rundll32.exe, предложенного "campbell". вам следует подождать секунду перед отправкой wm\_close. в противном случае тема не будет установлена, и приложение сразу закроется.</p><p>приведенный ниже фрагмент кода извлекает файл из ресурса (тематический пакет). затем исполняет файл desk.cpl с помощью rundll32.exe, ожидает 3 сценария, затем отправляет wm\_close (0x0010), ожидает обработки команды (время, необходимое для установки темы).</p><pre><code> private boolean switchtoclassictheme() { //first unpack the theme try { //extract the theme from the resource string themepath = system.environment.getfolderpath(environment.specialfolder.windows) + @"\resources\themes\classictheme.themepack"; //writefiletocurrentdirectory("classictheme.theme", tabletconfigurator.resources.classictheme); if(file.exists(themepath)) { file.delete(themepath); } if(file.exists(themepath)) { throw new exception("the file '" + themepath + "' exists and can not be deleted. you can try to delete it manually."); } using (binarywriter sw = new binarywriter(new filestream(themepath, filemode.openorcreate))) { sw.write(tabletconfigurator.resources.classictheme); sw.flush(); sw.close(); } if(!file.exists(themepath)) { throw new exception("the resource theme file could not be extracted"); } //set the theme file as like a user would have clicked it boolean btimedout = false; string themeoutput = startprocessandwait("rundll32.exe", system.environment.getfolderpath(environment.specialfolder.system) + @"\shell32.dll,control\_rundll " + system.environment.getfolderpath(environment.specialfolder.system) + "\\desk.cpl desk,@themes /action:opentheme /file:\"" + themepath + "\"", ref btimedout); system.threading.thread.sleep(3000); //wait for the theme to be set intptr hwndtheming = findwindow("cabinetwclass", null); sendmessage(hwndtheming, (uint)wm\_close, 0, 0); //using (bitmap bm = capturescreenshot()) //{ // boolean pixelisgray = true; // while (pixelisgray) // { // system.drawing.color pixel = bm.getpixel(0, 0) // } //} } catch(exception ex) { showerror("an exception occured while setting the theme: " + ex.message); return false; } return true; } </code></pre>

<p>команда для более новых версий windows (windows 8 и 8.1, еще не пробовала ее на w10):</p><pre><code>rundll32.exe themecpl.dll,openthemeaction %1 </code></pre><p>или с полными путями:</p><pre><code>c:\windows\system32\rundll32.exe c:\windows\system32\themecpl.dll,openthemeaction %localappdata%\microsoft\windows\themes\yourtheme.theme </code></pre><p>по сути, это<em> personalization cpl </em>"open" команда для расширений .theme & .themepack, взятых из реестра ...</p><p>после использования этой команды вы по-прежнему будете открывать окно «персонализация», поэтому чтобы закрыть его программно, вам придется использовать один из предложенных методов, упомянутых выше ... (лично я предпочитаю сценарий powershell)</p>

<p>хорошо, вот мое мнение об этом - <a href="https://en.wikipedia.org/wiki/vbscript">vb сценарий</a> . это немного неприятно, но лучшее, что я могу придумать (к сожалению).</p><p>для пользователя, который входит в систему, мы просто запускаем <code>changetheme.vbs</code>, когда пользователь входит в систему (например, автозапуск). сценарий запускает <code>desk.cpl</code> и передает ему необходимые параметры, а также имя выбранной темы.</p><p>можно запустить скрипт с параметрами или без параметров:</p><pre><code>> changetheme.vbs > changetheme.vbs anythemename </code></pre><p>сценарий:</p><pre class="lang-vb prettyprint-override"><code>' //////////////////////////////////////////////////////////////////// ' ' changes the theme. ' ' name: ' changetheme.vbs ' parameter 1: ' theme name e.g. aero or anything ' located in in c:\windows\resources\themes. ' if not present, a default theme will be used. ' ' example: ' inside a command line run ' > changetheme.vbs thethemename ' ' //////////////////////////////////////////////////////////////////// if(wscript.arguments.count <= 0) then ' if no parameter was given we set the following theme as default selectedtheme = "aero" else ' get theme via the first argument selectedtheme = wscript.arguments(0) end if ' create wscript shell object set wshshell = wscript.createobject("wscript.shell") ' run the command to open the "theme application" (or whatever) set process = wshshell.exec("rundll32.exe %systemroot%\system32\shell32.dll,control\_rundll %systemroot%\system32\desk.cpl desk,@themes /action:opentheme /file:""c:\windows\resources\themes\" & selectedtheme & ".theme""") ' wait for the application to start wscript.sleep 250 success = false maxtries = 20 trycount = 0 do until success = true wscript.sleep 1000 ' set focus to our application ' if this fails, or the application loses focus, it won't work! success = wshshell.appactivate(process.processid) trycount = trycount + 1 if (trycount >= maxtries) then ' if it does not work after maxtries we give up .. msgbox("cannot change theme - max tries exceeded ..") exit do end if loop ' the crucial part: send keys alt + b for applying the theme wshshell.sendkeys "%(b)" ' send key "escape" to close the window wshshell.sendkeys "{escape}" </code></pre><p>надеюсь, это поможет.</p>

<p>работает на windows 10.</p><p>это мой сценарий это меняет тему и закрывает окно. я сохраняю его в командный файл и запускаю этот файл патча из taskscheduler:</p><pre><code>c:\windows\system32\rundll32.exe c:\windows\system32\themecpl.dll,openthemeaction c:\users\xxx\misc\_computer\_stuff\themes\my\_fav\_gr.theme timeout 1 & rem waits 1 seconds before executing the next command taskkill /f /im systemsettings.exe & close window exit </code></pre>

<p>я только что понял, что вы можете дважды щелкнуть по теме, и она автоматически переключится - намного проще, так что просто выполнение темы работает, ex batch file:</p><pre><code>:: reactivate my theme after an remote desktop session :: we must select another theme first before we can select ours again and hence re-activate aero, please wait..." @echo off "c:\windows\resources\themes\aero.theme" ::echo "simulating a pause while" ping 127.0.0.1 -n 10 > null && "d:\users\danielsokolowski\windows 7 aero themes\`danielsokolowski` theme (without glass).theme" ::or ping 127.0.0.1 -n 3 > null && "%userprofile%\appdata\local\microsoft\windows\themes\`danielsokolowski` theme (without glass).theme" </code></pre>