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

1

8

In C# or else VB.Net, knowing the ubication of a visual theme .theme file, I would like to apply that visual theme in Windows, without depending on other applications such as RunDll32.exe, just P/Invoking, but avoiding weird/strange things such as opening the personalization window and then using FindWindow function to close it, the procedure should be automated from platform invoking not interacting with other windows.

This question about how to apply a theme was asked before in S.O by many people (Included by me, with a solution via registry modification plus service stoping/resuming that only works under Windows 7), I think its time for an expert to illustrate us with a WinAPI approach that does not involve RunDll32.exe neither opening the personalization window.

I wonder this could be done by setting some values on the registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ThemeManager and then posting/sending a message via SendMessage or PostMessage or other function, or maybe notifying about an environment change via SendMessageTimeOut function or SHChangeNotify or SystemParametersInfo or another function, because in the uxtheme.dll library seems there is nothing usefull for this task, the question is what function and with what parameters to apply a visual theme change, there are some commercial applications that can do this, which are the steps to do it then?, I tried all those functions without success.


This is the solution I did for Windows 7 in the past, I remember that is not perfect because for some themes the colors were not applied properlly and only has beeen solved with an user session re-logon to affect changes properlly after modifications:

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

In windows 8 I think because DWM composition changes just that code didn't worked anymore.

Homer answered 23/6, 2015 at 9:31 Comment(7)
seen this: https://mcmap.net/q/439402/-how-do-i-change-the-current-windows-theme-programmatically/1070452 ?Brunn
i've seen that question in the past, but there is nothing that could help me, it does not accomplish the requisites of my question (no rundll32, no personalization windows + fundwindow function), thankyou anyways.Homer
You can do it using UI automation (en.wikipedia.org/wiki/Microsoft_UI_Automation)Armistice
Thankyou anyways but I pretend to do it without Interaction with or automation on other windows (I imagine that you mean use UI Automation on the personalization Window). Really this issue can't be solved just P/Invoking the proper functions? somebody knows if exist the posibility?.Homer
As an example that I think it proofs its possible, I will say that after a Windows installation the O.S can set a default Theme (previouslly set on the automated XML installation file) and the OS does that without opening any personalization window.... so, if the OS can automate the task, I suppose Microsoft exposed the required functions in the WinAPI to accomplish that task vía sending messages or I don't know. But... where, and how to?.Homer
I think that you are looking for the SetSystemVisualStyle function? see: pinvoke.net/default.aspx/uxtheme.SetSystemVisualStyle Note that this function is undocumented. I just tested it and it works under Win 8.1.Madaih
@Madaih please feel free to publish an answer with that info to mark it as accepted and give the bounty reward. 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. Please add that valuable info if you answer, I'm sure that info is very unknown.Thanks.Homer
M
5

There is an undocumented function named "SetSystemVisualStyle" described on pinvoke.net that allows you to change the current "msstyles" file. As this function is undocumented it comes with the caveat: "use at your own risk".

The following function signatures are from the site referenced above.

C# signature

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

usage:

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

VB.Net signature

<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

The OP asked that the following information be added to this answer.

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.

Madaih answered 6/7, 2015 at 14:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.