private static void CloseAndWaitForWindow() { // close the window Keyboard.Press(Key.Alt); Keyboard.Press(Key.F4); Keyboard.Release(Key.F4); Keyboard.Release(Key.Alt); int counter = 0; int max = 20; bool found = true; while (counter < max && found) { Thread.Sleep(1000); counter++; found = false; foreach (var process in Process.GetProcesses()) { if (process.ProcessName.ToLower() == ThemeProcessName) { IntPtr hWnd = WindowEnumerator.FindFirstWindowWithCaption(process, "personalization"); if (hWnd != IntPtr.Zero) { found = true; break; } } } } }
/// <remarks> /// For the case of OS versons 6.1 and above the process for setting /// the theme is as follows: /// /// 1. launch the .theme file (theme is automatically selected) /// 2. wait for explorer to launch the 'personalization' child window /// 3. close the 'personalization' window /// /// Unlike MonitorProcess, explorer.exe is already running and a subwindow is launched for /// this process. /// </remarks> private static void SetThemeThroughExplorer(string themeFilename) { // Get the active window since the window activation will be lost // by lauching the ControlPanel.Personalization window. IntPtr activehWnd = IntPtr.Zero; ManualResetEvent waitEvent = new ManualResetEvent(false); System.Timers.Timer timer = null; bool enterFlag = true; try { // initialize the wait event waitEvent.Reset(); activehWnd = NativeMethods.GetForegroundWindow(); // set the actual theme which launches the personalization window Process themeChangeProcess = new Process(); themeChangeProcess.StartInfo.FileName = themeFilename; themeChangeProcess.Start(); // wait for the window to activate timer = new System.Timers.Timer(1500); timer.Elapsed += (s, e) => { if (enterFlag) { enterFlag = false; foreach (var process in Process.GetProcesses()) { if (process.ProcessName.ToLower() == ThemeProcessName) { IntPtr hWnd = WindowEnumerator.FindFirstWindowWithCaption(process, "personalization"); if (hWnd != IntPtr.Zero) { // first make sure it's active int maxCounter = 20; int counter = 0; IntPtr foregroundHWnd = NativeMethods.GetForegroundWindow(); Console.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", foregourndHWnd: " + foregroundHWnd + ", hWnd: " + hWnd); while ((foregroundHWnd != hWnd || !NativeMethods.IsWindowVisible(hWnd)) && counter < maxCounter && timer != null) { Console.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId + ", restore the window. hWnd: " + hWnd + ", foregroundHWnd: " + foregroundHWnd); NativeMethods.ShowWindow(hWnd, NativeMethods.SW_RESTORE); Thread.Sleep(500); NativeMethods.BringWindowToTop(hWnd); Thread.Sleep(500); foregroundHWnd = NativeMethods.GetForegroundWindow(); counter++; } if (foregroundHWnd == hWnd) { timer.Stop(); CloseAndWaitForWindow(); waitEvent.Set(); } break; } } } enterFlag = true; } }; timer.Start(); waitEvent.WaitOne(60000, false); } finally { enterFlag = false; if (timer != null) { timer.Stop(); timer.Dispose(); timer = null; } // Restore the active window if (activehWnd != IntPtr.Zero) { NativeMethods.SetForegroundWindow(activehWnd); } } }
/// <remarks> /// For the case of OS versons below 6.1 the process for setting /// the theme is as follows: /// /// 1. launch the .theme file /// 2. wait for the new rundll32 to start. /// 3. press enter to select the theme and close the dialog /// </remarks> private static void MonitorProcess(string processName, string themeFilename) { // Get the active window since the window activation will be lost IntPtr activehWnd = IntPtr.Zero; ManualResetEvent waitEvent = new ManualResetEvent(false); System.Timers.Timer timer = null; bool enterFlag = true; try { // initialize the wait event waitEvent.Reset(); activehWnd = NativeMethods.GetForegroundWindow(); // set the actual theme which launches the run32.dll window Process themeChangeProcess = new Process(); themeChangeProcess.StartInfo.FileName = themeFilename; themeChangeProcess.Start(); bool themeSet = false; // wait for the window to activate timer = new System.Timers.Timer(1500); timer.Elapsed += (s, e) => { if (enterFlag) { enterFlag = false; // find the process to monitor Process process = FindProcessFromName(processName); if (process != null) { process.Refresh(); HwndInfo[] topLevelWindows = WindowEnumerator.GetTopLevelVisibleWindows(process); if (topLevelWindows.Length > 0) { // In case the dialog was opened previously NativeMethods.SetForegroundWindow(topLevelWindows[0].hWnd); Thread.Sleep(1000); // The process monitor calls back more than once, only do this action once. if (!themeSet) { themeSet = true; // press enter to confirm and set the theme Keyboard.Type(Key.Return); } } } else { // For good measure Thread.Sleep(1000); waitEvent.Set(); } enterFlag = true; } }; timer.Start(); waitEvent.WaitOne(60000, false); } finally { enterFlag = false; if (timer != null) { timer.Stop(); timer.Dispose(); timer = null; } // Restore the active window if (activehWnd != IntPtr.Zero) { NativeMethods.SetForegroundWindow(activehWnd); } } }