web-dev-qa-db-fra.com

Comment changer le thème Windows actuel par programme?

Je souhaite autoriser mes utilisateurs à basculer le thème de l'utilisateur actuel entre Aero et Windows Classic (1). Y a-t-il un moyen de le faire par programme?

Je ne veux pas faire apparaître les "propriétés d'affichage", et je doute que l'on veuille simplement changer le registre. (Cela nécessite une déconnexion et une reconnexion pour que les modifications prennent effet).

L'application de skinning (à l'aide de Codejock libraries) ne fonctionne pas non plus.

Y-a-t'il une façon de le faire?

L'application est hébergée/exécutée sur un Windows Server 2008 sur _RDP .

(1) L’application en question est une "application distante" hébergée, et je souhaite que les utilisateurs puissent modifier l’apparence de l’application affichée en fonction de leur bureau.

26
seanyboy

Vous pouvez le définir en utilisant la commande suivante:

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

La mise en garde est que cela affichera la boîte de dialogue de sélection de thème. Vous pouvez tuer ce dialogue tout de suite après.

62
Campbell

Il y a certainement de bonnes raisons de vouloir changer le thème actuel par programmation. Par exemple. un outil de test automatisé peut avoir besoin de basculer entre différents thèmes pour s'assurer que l'application fonctionne correctement avec chacun d'entre eux.

En tant qu'utilisateur, vous pouvez modifier le thème en double-cliquant sur un fichier .theme dans Windwos Explorer, puis en fermant l'applet du panneau de configuration qui s'affiche. Vous pouvez facilement faire la même chose à partir du code. Les étapes ci-dessous fonctionnent parfaitement pour moi. Je n'ai testé que sur Windows 7.

  1. Utilisez SHGetKnownFolderPath() pour obtenir le dossier "Local AppData" de l'utilisateur. Les fichiers de thème sont stockés dans le sous-dossier Microsoft\Windows\Themes. Les fichiers de thème qui y sont stockés sont appliqués directement, tandis que les fichiers de thème stockés ailleurs sont dupliqués lorsque vous les exécutez. Il est donc préférable d’utiliser les fichiers de ce dossier uniquement.
  2. Utilisez ShellExecute() pour exécuter le fichier .theme que vous avez trouvé à l’étape 1.
  3. Attendez que le thème soit appliqué. Je laisse simplement mon application dormir pendant 2 secondes.
  4. Appelez FindWindow('CabinetWClass', 'Personalization') pour obtenir le descripteur de la fenêtre du Panneau de configuration qui s'est affichée lors de l'application du thème. La légende "Personnalisation" sera probablement différente des versions de Windows autres que l'anglais des États-Unis.
  5. Appelez PostMessage(HWND, WM_CLOSE, 0, 0) pour fermer la fenêtre du Panneau de configuration.

Ce n'est pas une solution très élégante, mais elle fait le travail.

19
Jan Goyvaerts

Je crois que le mieux que vous puissiez faire est d'ouvrir votre fichier .msstyles cible (dans c:\windows\resources\themes), ce qui affichera la boîte de propriétés d'affichage. À ce stade, vous pouvez utiliser le sous-classement de fenêtre pour cliquer par programme sur les boutons de droite.

2
Factor Mystic

En plus du post de "Jan Goyvaerts": J'utilise SendMessage au lieu de PostMessage. La différence est que SendMessage attend que la commande soit prise en compte par la fenêtre. Cela signifie que dans les retours de SendMessages, vous savez que la boîte de dialogue du thème est fermée.

Donc, si vous le démarrez avec la méthode monstrueuse (mais géniale) rundll32.exe suggérée par "Campbell". Vous devez attendre une seconde avant d’envoyer WM_CLOSE. Sinon, le thème ne sera pas défini et l'application se ferme immédiatement.

L'extrait de code ci-dessous extrait un fichier de la ressource (une réserve thématique). Ensuite, exécute desk.cpl avec rundll32.exe, attend 3 secondes, puis envoie WM_CLOSE (0x0010), attend que la commande soit traitée (le temps nécessaire pour définir le thème).

    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

La commande pour les versions plus récentes de Windows (Windows 8 et 8.1, ne l’a pas encore essayée sur W10) est la suivante:

rundll32.exe themecpl.dll,OpenThemeAction %1

ou avec des chemins complets:

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

Il s’agit en gros de la commande Personalization CPL "open" pour les extensions .theme & .themepack extraites du registre ...

Vous finirez toujours par avoir la fenêtre Personnalisation ouverte après avoir utilisé cette commande. Pour la fermer par programme, vous devrez utiliser l'une des méthodes suggérées ci-dessus ...

0
Cube

Bon alors voici mon point de vue sur ceci - un script VB . C'est un peu méchant mais le meilleur que je pourrais trouver (malheureusement).

Pour un utilisateur qui se connecte, nous exécutons simplement ChangeTheme.vbs lorsqu’il se connecte (par exemple, autorun). Le script démarre desk.cpl et lui transmet les paramètres requis, ainsi que le nom du thème sélectionné.

On peut exécuter le script avec ou sans paramètres:

> ChangeTheme.vbs
> ChangeTheme.vbs AnyThemeName

Le scénario:

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

J'espère que cela pourra aider.

0
displayname

Cela fonctionne sur Windows 10.

c'est mon script. Cela change le thème et ferme la fenêtre. Je l'enregistre dans un fichier de commandes et exécute ce fichier de correctif à partir de 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

Je viens de me rendre compte que vous pouvez double-cliquer sur le thème et le changer automatiquement - beaucoup plus simple, il suffit donc d'exécuter le thème, ex:

:: 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