it-swarm.com.de

Wie kann ich das aktuelle Windows-Design programmgesteuert ändern?

Ich möchte meinen Benutzern erlauben, das aktuelle Benutzerdesign zwischen Aero und Windows Classic (1) umzuschalten. Gibt es eine Möglichkeit, dass ich dies programmgesteuert tun kann?

Ich möchte die "Anzeigeeigenschaften" nicht öffnen, und ich bin dubios, nur die Registrierung zu ändern. (Dies erfordert eine Abmeldung und eine erneute Anmeldung, damit die Änderungen wirksam werden.).

Das Anwendungs-Skinning (mithilfe der Codejock -Bibliotheken) funktioniert ebenfalls nicht.

Gibt es eine Möglichkeit, dies zu tun?

Die Anwendung wird auf einem Windows Server 2008 über RDP gehostet/ausgeführt.

(1) Bei der fraglichen Anwendung handelt es sich um eine gehostete "Remote App", und ich möchte, dass Benutzer das Aussehen der angezeigten Anwendung an ihren Desktop anpassen können.

26
seanyboy

Sie können es mit dem folgenden Befehl einstellen:

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

Der Nachteil ist, dass dies den Dialog zur Motivauswahl anzeigt. Sie könnten diesen Dialog gleich danach beenden.

62
Campbell

Es gibt sicherlich gute Gründe, das aktuelle Thema programmatisch ändern zu wollen. Z.B. Ein automatisiertes Testwerkzeug muss möglicherweise zwischen verschiedenen Themen wechseln, um sicherzustellen, dass die Anwendung mit allen von ihnen ordnungsgemäß funktioniert.

Als Benutzer können Sie das Design ändern, indem Sie in Windwos Explorer auf eine .theme-Datei doppelklicken und das daraufhin geöffnete Steuerungsfenster schließen. Sie können das Gleiche leicht vom Code aus tun. Die folgenden Schritte funktionieren für mich gut. Ich habe nur unter Windows 7 getestet.

  1. Verwenden Sie SHGetKnownFolderPath(), um den Ordner "Local AppData" für den Benutzer abzurufen. Designdateien werden im Unterordner Microsoft\Windows\Themes gespeichert. Darin gespeicherte Themendateien werden direkt angewendet, wohingegen an anderer Stelle gespeicherte Themendateien beim Ausführen dupliziert werden. Daher sollten Sie nur Dateien aus diesem Ordner verwenden.
  2. Verwenden Sie ShellExecute(), um die .theme-Datei auszuführen, die Sie in Schritt 1 gefunden haben.
  3. Warten Sie, bis das Design angewendet wird. Ich lasse meine App einfach für 2 Sekunden schlafen.
  4. Rufen Sie FindWindow('CabinetWClass', 'Personalization') auf, um das Handle des Control Panel-Fensters abzurufen, das beim Anwenden des Designs angezeigt wurde. Die Beschriftung "Personalization" wird sich wahrscheinlich bei nicht US-englischen Versionen von Windows unterscheiden.
  5. Rufen Sie PostMessage(HWND, WM_CLOSE, 0, 0) auf, um das Fenster der Systemsteuerung zu schließen.

Dies ist keine sehr elegante Lösung, macht aber die Arbeit.

19
Jan Goyvaerts

Ich weiß, dass dies ein altes Ticket ist, aber jemand hat mich gefragt, wie ich das heute machen soll. Ausgehend von Mikes obigem Beitrag habe ich die Dinge aufgeräumt, Kommentare hinzugefügt und den vollständigen C # -Konsolen-App-Code veröffentlicht:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Win32;

namespace Windows7Basic
{
    class Theming
    {
        /// Handles to Win 32 API
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string sClassName, string sAppName);
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        /// Windows Constants
        private const uint WM_CLOSE = 0x10;

        private String StartProcessAndWait(string filename, string arguments, int seconds, ref Boolean bExited)
        {
            String msg = String.Empty;
            Process p = new Process();
            p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            p.StartInfo.FileName = filename;
            p.StartInfo.Arguments = arguments;
            p.Start();

            bExited = false;
            int counter = 0;
            /// give it "seconds" seconds to run
            while (!bExited && counter < seconds)
            {
                bExited = p.HasExited;
                counter++;
                System.Threading.Thread.Sleep(1000);
            }//while
            if (counter == seconds)
            {
                msg = "Program did not close in expected time.";
            }//if

            return msg;
        }

        public Boolean SwitchTheme(string themePath)
        {
            try
            {    
                //String themePath = System.Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\Resources\Ease of Access Themes\basic.theme";
                /// Set the theme
                Boolean bExited = false;
                /// essentially runs the command line:  rundll32.exe %SystemRoot%\system32\Shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:"%WINDIR%\Resources\Ease of Access Themes\classic.theme"
                String ThemeOutput = this.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 + "\"", 30, ref bExited);

                Console.WriteLine(ThemeOutput);

                /// Wait for the theme to be set
                System.Threading.Thread.Sleep(1000);

                /// Close the Theme UI Window
                IntPtr hWndTheming = FindWindow("CabinetWClass", null);
                SendMessage(hWndTheming, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            }//try
            catch (Exception ex)
            {
                Console.WriteLine("An exception occured while setting the theme: " + ex.Message);

                return false;
            }//catch
            return true;
        }

        public Boolean SwitchToClassicTheme()
        {
            return SwitchTheme(System.Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\Resources\Ease of Access Themes\basic.theme");
        }

        public Boolean SwitchToAeroTheme()
        {
            return SwitchTheme(System.Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\Resources\Themes\aero.theme");
        }

        public string GetTheme()
        {
            string RegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes";
            string theme;
            theme = (string)Registry.GetValue(RegistryKey, "CurrentTheme", string.Empty);
            theme = theme.Split('\\').Last().Split('.').First().ToString();
            return theme;
        }

        // end of object Theming
    }

    //---------------------------------------------------------------------------------------------------------------

    class Program
    {
        [DllImport("dwmapi.dll")]
        public static extern IntPtr DwmIsCompositionEnabled(out bool pfEnabled);

        /// ;RunProgram("%USERPROFILE%\AppData\Local\Microsoft\Windows\Themes\themeName.theme")      ;For User Themes
        /// RunProgram("%WINDIR%\Resources\Ease of Access Themes\classic.theme")                     ;For Basic Themes
        /// ;RunProgram("%WINDIR%\Resources\Themes\aero.theme")                                      ;For Aero Themes

        static void Main(string[] args)
        {
            bool aeroEnabled = false;
            Theming thm = new Theming();
            Console.WriteLine("The current theme is " + thm.GetTheme());

            /// The only real difference between Aero and Basic theme is Composition=0 in the [VisualStyles] in Basic (line omitted in Aero)
            /// So test if Composition is enabled
            DwmIsCompositionEnabled(out aeroEnabled);

            if (args.Length == 0 || (args.Length > 0 && args[0].ToLower(CultureInfo.InvariantCulture).Equals("basic")))
            {
                if (aeroEnabled)
                {
                    Console.WriteLine("Setting to basic...");
                    thm.SwitchToClassicTheme();
                }//if
            }//if
            else if (args.Length > 0 || args[0].ToLower(CultureInfo.InvariantCulture).Equals("aero"))
            {
                if (!aeroEnabled)
                {
                    Console.WriteLine("Setting to aero...");
                    thm.SwitchToAeroTheme();
                }//if
            }//else if
        }

        // end of object Program
    }
}
</ code>
10
isopropanol

Ich glaube, das Beste, was Sie tun können, ist die .msstyles-Zieldatei (in c:\windows\resources\themes) zu öffnen, die das Anzeigeeigenschaften-Fenster öffnet. An dieser Stelle könnten Sie die Fensterklasse verwenden, um programmgesteuert auf die rechten Schaltflächen zu klicken.

2
Factor Mystic

Zusätzlich zum Post von "Jan Goyvaerts": Ich verwende SendMessage anstelle von PostMessage. Der Unterschied ist, dass SendMessage darauf wartet, dass der Befehl vom Fenster übernommen wird. Das bedeutet, dass Sie in den SendMessages zurückkehren, dass das Designdialogfeld geschlossen ist.

Wenn Sie es also mit der monströsen (aber genialen) rundll32.exe-Methode starten, die von "Campbell" vorgeschlagen wird. Sie sollten eine Sekunde warten, bevor Sie WM_CLOSE senden. Andernfalls wird das Design nicht festgelegt und die Anwendung wird sofort geschlossen.

Das folgende Code-Snippet extrahiert eine Datei aus der Ressource (ein Themenpaket). Führt dann die Datei desk.cpl mit rundll32.exe aus, wartet 3 Sekunden, sendet dann WM_CLOSE (0x0010) und wartet auf die Verarbeitung des Befehls (die Zeit, die das Einrichten des Designs benötigt).

    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

Ich bin nicht sicher, ob dies eine neue Sache ist, aber Sie können einfach auf die .theme-Datei doppelklicken, und Windows 10 wendet das Design an. Daher können Sie dies mit PowerShell problemlos tun:

$Windows10Theme = "C:\Windows\Resources\Themes\aero.theme"
Invoke-Expression $Windows10Theme
0
joon

Der Befehl für neuere Windows-Versionen (Windows 8 und 8.1, auf W10 noch nicht ausprobiert) lautet:

rundll32.exe themecpl.dll,OpenThemeAction %1

oder mit vollen Pfaden:

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

Grundsätzlich handelt es sich um den Befehl Personalization CPL "open" für die Erweiterungen .theme & .themepack aus der Registrierung ...

Am Ende bleibt das Fenster für die Personalisierung geöffnet, nachdem Sie diesen Befehl verwendet haben. Um das Programm programmatisch zu schließen, müssen Sie eine der oben genannten Methoden verwenden ...

0
Cube

Okay, hier ist meine Einstellung zu diesem - einem VB - Skript . Es ist ein bisschen unangenehm, aber das Beste, mit dem ich (leider) aufwarten könnte.

Für einen Benutzer, der sich anmeldet, führen wir einfach ChangeTheme.vbs aus, wenn sich der Benutzer anmeldet (z. B. Autorun). Das Skript startet desk.cpl und übergibt ihm die erforderlichen Parameter sowie den Namen des ausgewählten Designs.

Man kann das Skript mit oder ohne Parameter ausführen:

> ChangeTheme.vbs
> ChangeTheme.vbs AnyThemeName

Das Skript:

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

Hoffentlich hilft das.

0
displayname

Es funktioniert unter Windows 10.

das ist mein Skript. Es ändert das Design und schließt das Fenster. Ich speichere es in einer Batch-Datei und starte diese Patch-Datei von TaskScheduler aus:

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

Ich habe gerade realisiert, dass Sie auf das Thema doppelklicken können, und es wechselt es automatisch - es ist viel einfacher, wenn Sie das Design ausführen, funktioniert die Batch-Datei:

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