it-swarm.com.ru

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

Я хочу, чтобы мои пользователи могли переключать текущую пользовательскую тему между Aero и Windows Classic (1). Есть ли способ, которым я могу сделать это программно?

Я не хочу выскакивать «Свойства дисплея», и я сомневаюсь в том, чтобы просто изменить реестр. (Это требует выхода из системы и повторного входа, чтобы изменения вступили в силу).

Скины приложений (с использованием библиотек Codejock ) также не работают.

Есть ли способ сделать это?

Приложение размещено/запущено на Windows Server 2008 over RDP .

(1) Данное приложение является размещенным «Удаленным приложением», и я хочу, чтобы пользователи могли изменять внешний вид отображаемого приложения в соответствии со своим рабочим столом.

26
seanyboy

Вы можете установить его с помощью следующей команды:

rundll32.exe %SystemRoot%\system32\Shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:"C:\Windows\Resources\Themes\aero.theme"

Предостережение в том, что это покажет диалог выбора темы. Вы можете убить этот диалог сразу после.

62
Campbell

Есть, конечно, веские причины для того, чтобы захотеть изменить текущую тему программно. Например. инструмент автоматического тестирования может потребоваться переключаться между различными темами, чтобы убедиться, что приложение работает со всеми из них правильно.

Как пользователь, вы можете изменить тему, дважды щелкнув файл .theme в Windwos Explorer, а затем закрыв всплывающее окно панели управления. Вы можете легко сделать то же самое из кода. Следующие шаги работают нормально для меня. Я тестировал только на Windows 7.

  1. Используйте SHGetKnownFolderPath(), чтобы получить папку «Local AppData» для пользователя. Файлы тем хранятся в подпапке Microsoft\Windows\Themes. Файлы тем, хранящиеся там, применяются напрямую, тогда как файлы тем, хранящиеся в другом месте, дублируются при их выполнении. Поэтому лучше использовать файлы только из этой папки.
  2. Используйте ShellExecute() для выполнения файла .theme, который вы нашли в шаге 1.
  3. Подождите, пока тема будет применена. Я просто позволяю своему приложению спать в течение 2 секунд.
  4. Вызовите FindWindow('CabinetWClass', 'Personalization'), чтобы получить дескриптор окна панели управления, которое всплывало при применении темы. Надпись «Персонализация», скорее всего, будет отличаться в англоязычных версиях Windows.
  5. Вызовите PostMessage(HWND, WM_CLOSE, 0, 0), чтобы закрыть окно панели управления.

Это не очень элегантное решение, но оно делает свою работу.

19
Jan Goyvaerts

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

2
Factor Mystic

В дополнение к посту "Ян Гойваэртс": Я использую SendMessage вместо PostMessage. Разница в том, что SendMessage ожидает, пока окно не примет команду. Это означает, что в SendMessages возвращается, вы знаете, что диалог темы закрыт.

Так что, если вы начнете его с чудовищного (но гениального) метода rundll32.exe, предложенного "Campbell". Вам следует подождать секунду перед отправкой WM_CLOSE. В противном случае тема не будет установлена, и приложение сразу закроется.

Приведенный ниже фрагмент кода извлекает файл из ресурса (тематический пакет). Затем исполняет файл desk.cpl с помощью rundll32.exe, ожидает 3 сценария, затем отправляет WM_CLOSE (0x0010), ожидает обработки команды (время, необходимое для установки темы).

    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;
    }
2
Mike de Klerk

Команда для более новых версий Windows (Windows 8 и 8.1, еще не пробовала ее на W10):

rundll32.exe themecpl.dll,OpenThemeAction %1

или с полными путями:

C:\WINDOWS\system32\rundll32.exe C:\WINDOWS\system32\themecpl.dll,OpenThemeAction %LocalAppData%\Microsoft\Windows\Themes\yourtheme.theme

По сути, это Personalization CPL "open" команда для расширений .theme & .themepack, взятых из реестра ...

После использования этой команды вы по-прежнему будете открывать окно «Персонализация», поэтому чтобы закрыть его программно, вам придется использовать один из предложенных методов, упомянутых выше ... (лично я предпочитаю сценарий Powershell)

0
Cube

Хорошо, вот мое мнение об этом - VB сценарий . Это немного неприятно, но лучшее, что я могу придумать (к сожалению).

Для пользователя, который входит в систему, мы просто запускаем ChangeTheme.vbs, когда пользователь входит в систему (например, автозапуск). Сценарий запускает desk.cpl и передает ему необходимые параметры, а также имя выбранной темы.

Можно запустить скрипт с параметрами или без параметров:

> ChangeTheme.vbs
> ChangeTheme.vbs AnyThemeName

Сценарий:

' ////////////////////////////////////////////////////////////////////
'
' 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}" 

Надеюсь, это поможет.

0
displayname

Работает на Windows 10.

это мой сценарий Это меняет тему и закрывает окно. Я сохраняю его в командный файл и запускаю этот файл патча из TaskScheduler:

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
0
user1390106

Я только что понял, что вы можете дважды щелкнуть по теме, и она автоматически переключится - намного проще, так что просто выполнение темы работает, ex batch file:

:: 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"
0
Daniel Sokolowski