microsoft - windows 10 themes anime
¿Cómo cambio el tema actual de Windows programáticamente? (5)
Creo que lo mejor que puede hacer es abrir su archivo .msstyles de destino (en c:/windows/resources/themes
), que abrirá el cuadro de propiedades de visualización. En este punto, puede usar la subclase de ventana para hacer clic en los botones de la derecha.
Quiero permitir a mis usuarios alternar el tema del usuario actual entre Aero y Windows Classic (1). ¿Hay alguna manera de que pueda hacer esto programáticamente?
No quiero que aparezcan las "Propiedades de pantalla", y tengo dudas acerca de simplemente cambiar el registro. (Esto requiere cerrar sesión y volver a iniciar sesión para que los cambios surtan efecto).
El skinning de aplicación (usando las bibliotecas Codejock ) tampoco funciona.
¿Hay alguna forma de hacer esto?
La aplicación se aloja / ejecuta en un Windows Server 2008 a través de RDP .
(1) La aplicación en cuestión es una "Aplicación Remota" alojada, y quiero que los usuarios puedan cambiar el aspecto de la aplicación mostrada para que coincida con su escritorio.
Puedes configurarlo usando el siguiente comando:
rundll32.exe %SystemRoot%/system32/shell32.dll,Control_RunDLL %SystemRoot%/system32/desk.cpl desk,@Themes /Action:OpenTheme /file:"C:/Windows/Resources/Themes/aero.theme"
La advertencia es que esto mostrará el cuadro de diálogo del selector de tema. Podrías matar ese diálogo enseguida.
Sin duda hay buenas razones para querer cambiar el tema actual programáticamente. Por ejemplo, una herramienta de prueba automatizada puede necesitar cambiar entre varios temas para asegurarse de que la aplicación funcione correctamente con todos ellos.
Como usuario, puede cambiar el tema haciendo doble clic en un archivo .theme en Windwos Explorer y luego cerrando el applet del Panel de control que aparece. Puedes hacer lo mismo fácilmente desde el código. Los pasos a continuación funcionan bien para mí. Solo he probado en Windows 7.
- Use
SHGetKnownFolderPath()
para obtener la carpeta "Local AppData" para el usuario. Los archivos de tema se almacenan en la subcarpetaMicrosoft/Windows/Themes
. Los archivos de temas almacenados allí se aplican directamente, mientras que los archivos de temas almacenados en otro lugar se duplican cuando los ejecuta. Entonces, lo mejor es usar archivos de esa carpeta solamente. - Use
ShellExecute()
para ejecutar el archivo.theme
que ubicó en el paso 1. - Espere a que se aplique el tema. Simplemente dejo que mi aplicación duerma durante 2 segundos.
- Llame a
FindWindow(''CabinetWClass'', ''Personalization'')
para obtener el control de la ventana del Panel de control que apareció cuando se aplicó el tema. El título de "Personalización" probablemente será diferente en las versiones de Windows que no sean de inglés estadounidense. - Llame a
PostMessage(HWND, WM_CLOSE, 0, 0)
para cerrar la ventana del Panel de control.
Esta no es una solución muy elegante, pero cumple su función.
Además de la publicación de "Jan Goyvaerts": utilizo SendMessage en lugar de PostMessage. La diferencia es que SendMessage espera que el comando sea captado por la ventana. Lo que significa que en los retornos SendMessages, sabes que el diálogo del tema está cerrado.
Entonces, si comienzas con el método monstruoso (pero genial) rundll32.exe sugerido por "Campbell". Debes esperar un segundo antes de enviar WM_CLOSE. De lo contrario, el tema no se establecerá y la aplicación se cerrará de inmediato.
El fragmento de código a continuación extrae un archivo del recurso (un paquete de temas). A continuación, ejecuta desk.cpl con rundll32.exe, espera 3 segundos, luego envía WM_CLOSE (0x0010), espera a que se procese el comando (el tiempo que tarda el tema en configurarse).
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;
}
Sé que es una entrada vieja, pero alguien me preguntó cómo hacer esto hoy. Así que comenzando desde la publicación de Mike anterior, limpié las cosas, agregué comentarios y publicaré el código de la aplicación de la consola C # completa:
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
}
}