我想讓我的用戶切換Aero和Windows Classic(1)之間的當前用戶主題。有沒有一種方法可以通過編程來實現?如何以編程方式更改當前的Windows主題?
我不想彈出「顯示屬性」,我只是在改變註冊表。 (這需要註銷並重新登錄才能使更改生效)。使用Codejock庫也不起作用。
有沒有辦法做到這一點?
該應用程序託管/運行於Windows Server 2008超過RDP。 (1)有問題的應用程序是託管的「遠程應用程序」,我希望用戶能夠更改顯示的應用程序的外觀以匹配其桌面。
我想讓我的用戶切換Aero和Windows Classic(1)之間的當前用戶主題。有沒有一種方法可以通過編程來實現?如何以編程方式更改當前的Windows主題?
我不想彈出「顯示屬性」,我只是在改變註冊表。 (這需要註銷並重新登錄才能使更改生效)。使用Codejock庫也不起作用。
有沒有辦法做到這一點?
該應用程序託管/運行於Windows Server 2008超過RDP。 (1)有問題的應用程序是託管的「遠程應用程序」,我希望用戶能夠更改顯示的應用程序的外觀以匹配其桌面。
您可以使用以下命令進行設置:
rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:"C:\Windows\Resources\Themes\aero.theme"
需要注意的是,這將展會主題選擇對話框。你可以直接殺掉那個對話框。
我相信你可以做的最好的是打開你的目標.msstyles文件(在c:\windows\resources\themes
),這將彈出顯示屬性框。在這一點上,您可以使用窗口子類編程方式單擊正確的按鈕。
想要以編程方式更改當前主題肯定有很好的理由。例如。自動化測試工具可能需要在各種主題之間切換,以確保應用程序與所有主題正常工作。
作爲用戶,您可以通過雙擊Windwos Explorer中的.theme
文件更改主題,然後關閉彈出的控制面板小程序。您可以輕鬆地從代碼執行相同的操作。下面的步驟對我來說工作得很好。我只在Windows 7上測試過。
SHGetKnownFolderPath()
可以獲取用戶的「本地應用程序數據」文件夾。主題文件存儲在Microsoft\Windows\Themes
子文件夾中。存儲在那裏的主題文件直接應用,而在其他地方存儲的主題文件在執行時會被複制。所以最好只使用該文件夾中的文件。ShellExecute()
執行您在步驟1中找到的.theme
文件。FindWindow('CabinetWClass', 'Personalization')
可以獲得應用主題時彈出的控制面板窗口的句柄。在非美國英語版本的Windows上,「個性化」標題可能會有所不同。PostMessage(HWND, WM_CLOSE, 0, 0)
關閉控制面板窗口。這不是一個非常優雅的解決方案,但它的工作。
除了「Jan Goyvaerts」的帖子外: 我使用SendMessage而不是PostMessage。不同之處在於SendMessage等待命令被窗口占用。這意味着在SendMessages返回時,您知道主題對話框已關閉。
因此,如果你用「Campbell」建議的可怕的(但是很有意思的)rundll32.exe方法啓動它。在發送WM_CLOSE之前,您應該等待一秒。否則,主題將不會被設置,並且應用程序立即關閉。
下面的代碼片段從資源(一個themepack)中提取一個文件。然後用rundll32.exe執行desk.cpl,等待3個sceonds,然後發送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;
}
我知道這是一張舊票,但有人問我今天該怎麼做。因此,從麥克的帖子開始上面我清理東西,添加註釋,將發佈完整的C#控制檯應用程序代碼:
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
}
}
較新版本的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
基本上它是個性化CPL從註冊表中取。主題& .themepack的擴展名「打開」命令
你仍然結束了個性化窗口使用此命令後beeing開放,使來關閉它編程,你將不得不使用上面提到的建議方法之一...(我個人比較喜歡Powershell腳本)
生病了..你怎麼知道的? – Claudiu 2011-04-08 18:53:39
imma給這個賞金,因爲它是實際的答案 – Claudiu 2011-04-08 21:24:27
我猜測它是在手動更改主題時使用ProcessMonitor制定的。 – 2015-02-26 05:15:56