如何通过 P/Invoking 在 Windows 8/8.1 中以编程方式更改视觉主题?

How do I change a visual theme programatically in Windows 8/8.1 by P/Invoking?

C#VB.Net中,了解视觉主题.theme 文件,我想在 Windows 中应用该视觉主题, 没有 取决于其他应用程序,例如 RunDll32.exe,只是P/Invoking,但避免weird/strange打开个性化window然后使用FindWindow功能关闭它,该过程应该从平台调用自动化不与其他人互动 windows.

这个关于如何应用主题的问题之前在 S.O 中被很多人问过(包括我在内,通过注册表修改加上服务 stoping/resuming 的解决方案只能在 Windows 7),我认为是时候让专家用不涉及 RunDll32.exe 既不打开个性化 window.[= 的 WinAPI 方法来说明我们了21=]

我想知道这可以通过在注册表项 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ThemeManager 上设置一些值然后通过 SendMessagePostMessage 或其他功能 posting/sending 一条消息来完成,或者可能通过 SendMessageTimeOut 函数或 SHChangeNotifySystemParametersInfo 或其他函数通知环境变化,因为在 uxtheme.dll 库中似乎没有任何有用的任务,问题是应用视觉主题更改的功能和参数是什么,有一些商业应用程序可以做到这一点,那么执行这些操作的步骤是什么?,我尝试了所有这些功能都没有成功。


这是我过去为 Windows 7 所做的解决方案,我记得这并不完美,因为对于某些主题,颜色应用不正确,只有通过用户会话重新登录才能解决修改后正确影响更改:

Private Sub SetAeroTheme(ByVal themeFile As String,
                         Optional ByVal colorName As String = "NormalColor",
                         Optional ByVal sizeName As String = "NormalSize")

    Dim regKeyPath As String = "Software\Microsoft\Windows\CurrentVersion\ThemeManager"

    Using themeService As New ServiceController("Themes")

        If themeService.Status = ServiceControllerStatus.Running Then
            themeService.Stop()
            themeService.WaitForStatus(ServiceControllerStatus.Stopped)
        End If

        Using regKey As RegistryKey = Registry.CurrentUser.OpenSubKey(regKeyPath, writable:=True)

            regKey.SetValue("LoadedBefore", "0", RegistryValueKind.String)
            regKey.SetValue("DllName", themeFile, RegistryValueKind.String)
            regKey.SetValue("ColorName", colorName, RegistryValueKind.String)
            regKey.SetValue("SizeName", sizeName, RegistryValueKind.String)

        End Using

        If themeService.Status = ServiceControllerStatus.Stopped Then
            themeService.Start()
            themeService.WaitForStatus(ServiceControllerStatus.Running)
        End If

    End Using

End Sub

在 windows 8 中,我认为是因为 DWM 组合发生了变化,所以代码不再有效。

有一个名为 "SetSystemVisualStyle" described on pinvoke.net 的未记录函数允许您更改当前 "msstyles" 文件。由于此函数未记录,因此附带警告:"use at your own risk"。

以下函数签名来自上述站点。

C# 签名

[DllImport("UxTheme.Dll", EntryPoint = "#65", CharSet = CharSet.Unicode)]
public static extern int SetSystemVisualStyle(string pszFilename, string pszColor, string pszSize, int dwReserved);

用法:

// This will set your Visual Style to Luna
SetSystemVisualStyle(@"C:\WINDOWS\resources\Themes\Luna\Luna.msstyles", "Metallic", "NormalSize", 0);

VB.Net签名

<DllImport("UxTheme.DLL", BestFitMapping:=False, CallingConvention:=CallingConvention.Winapi, CharSet:=CharSet.Unicode, EntryPoint:="#65")> _
Shared Function SetSystemVisualStyle(ByVal pszFilename As String, ByVal pszColor As String, ByVal pszSize As String, ByVal dwReserved As Integer) As Integer
End Function

OP 要求将以下信息添加到此答案中。

The function itself does not properlly change some dialog colors and some control styles when a 3rd party theme is applied with a custom msstyles, but doing an experiment by testing all the possible values from 0 to Int32.Max to pass it to the reserved parameter of the SetSystemVisualTheme function, by the moment I discovered that a value of 65 fixes this colorization and styles issue.