Change Windows Appearance programmatically - c#

I need to change Windows Accent Color using C#. I need to change only these 3 settings (accent color, show accent color in start, taskbar, action center and title bars and window borders.)
If possible, I would like to take these effects immediately.
I tried this:
Color newColor = Color.FromArgb(255, 0, 0); // red color
RegistryKey key = Registry.CurrentUser.CreateSubKey(#"Control Panel\Personalization");
key.SetValue("AccentColor", ColorTranslator.ToWin32(newColor));
key.Close();
const uint SPI_SETDESKWALLPAPER = 20;
const uint SPIF_UPDATEINIFILE = 0x1;
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, SPIF_UPDATEINIFILE);
I tried it with and without administrator rights, I tried restarting PC but nothing changed. I use Windows 10 Home.
I also asked ChatGPT, but all solutions ChatGPT provided was not working as expected.
So is there a way to change these settings programmatically? Changing registry? Any help will be useful, thanks.

Related

Why SetWindowsPos function return false in Windows 10 and windows 11 last update?

I'm creating an AppBar in .net MAUI, and I want my app to sit at the top of the screen and reduce the working area. The area used by the AppBar shouldn't be covered by any other window.
I'm using the setWindowPos function(from user32.dll) to resize the working area, but it seems to work only on Windows 11 version 21H2. I also checked in Windows 10 versions 21H2, 22H2, and windows 11 version 22H2(+Patched) but setWindowPos returns false in all of them.
What might be the reason for this behavior? and what can I adjust in my code to make it work on other versions as well?
p.s: GetDesktopWindow and SystemParametersInfo are also from user32.dll
IntPtr desktopWindow = GetDesktopWindow();
var setPos = SetWindowPos(desktopWindow, IntPtr.Zero, 0, _APPBARHEIGHT, 0, 0, (uint) (SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOZORDER));//in windows 11 v21H2 return true
RECT rect = new RECT();
rect.Left = 0;
rect.Top = _APPBARHEIGHT;
rect.Right = _ScreenWidth;
rect.Bottom = _ScreenHeight - _APPBARHEIGHT;
var sysparam = SystemParametersInfo(0x002F, 0, ref rect, 0x0002);//return true
Thanks!
I expected the desktop working area would resize and any maximized window would not run over the AppBar
something like this. It
works as I expected in Windows 11 v21H2.

How to make WinForm use the system dark mode theme?

Can WinForm use system dark mode theme like explorer or StartAllBack?
I've tried these things:
int trueValue = 0x01, falseValue = 0x00;
SetWindowTheme(this.Handle, "DarkMode_Explorer", null);
DwmSetWindowAttribute(this.Handle, DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE, ref trueValue, Marshal.SizeOf(typeof(int)));
DwmSetWindowAttribute(this.Handle, DwmWindowAttribute.DWMWA_MICA_EFFECT, ref trueValue, Marshal.SizeOf(typeof(int)));
But these only make the titlebar and scrollbar in dark, no difference for other controls.
How to make all controls to system dark style, like this:
Dark mode theme Explorer

How to keep a window on top of a specific window only?

My application is a Winforms transparent overlay attached to another application.
Since there can be multiple overlays running at one time for different apps, I need my overlay to be always on top, but only over its target application.
What I tried was to bring the form to the foreground with
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
When target app gains focus through my WindowHook eventType == NativeMethods.SWEH_Events.EVENT_OBJECT_FOCUS.
The problem is that the overlay gains focus after going on top, not allowing me to interact with the app underneath. Like if I try to drag the target app it will block me at first, and if I try to click anywhere nothing happens despite being clickthrough (works when I set Winforms TopMost = true;).
I would consider setting the form topmost when target app gains focus, but there is no event to check for loss of focus to undo the topmost, and even then it would be less than an elegant solution, to say the least.
There must be a simpler way to keep my overlay on top of its target app process. Or the very least, a way to bring the form on top without gaining focus / disrupting my mouse events.
So EVENT_SYSTEM_CAPTUREEND = 0x0009 gets called after any interaction with the target process window. This means I can set my form topmost
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
and undo it with
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); on EVENT_SYSTEM_CAPTUREEND.
I'm not a fan of this solution but works and it's seamless.

Replace Windows Shell or Restrict application window size

I'm working on an application for home based users. And this application involves completely replacing windows explorer for a custom application.
I would like to mimic the behavior of the taskbar. For example, when you click the maximize button in Notepad, it does not overlap the taskbar.
I already tried to use the api to AppBar however, AppBar api does not work when windows explorer is not running and other windows overlap my taskbar.
Any idea how I can do this? If I can restrict the size of maximized windows when ever helps me. The problem is that other applications are not always written by me.
I found an example using an win32 api SystemParametersInfo.
This way I can define an area where the other applications will fit and leave an space to my form even if other applications is maximized.
Link on github
public static void MakeNewDesktopArea()
{
// Save current Working Area size
m_rcOldDesktopRect.left = SystemInformation.WorkingArea.Left;
m_rcOldDesktopRect.top = SystemInformation.WorkingArea.Top;
m_rcOldDesktopRect.right = SystemInformation.WorkingArea.Right;
m_rcOldDesktopRect.bottom = SystemInformation.WorkingArea.Bottom;
// Make a new Workspace
WinAPI.RECT rc;
rc.left = SystemInformation.VirtualScreen.Left + 150;
rc.top = SystemInformation.VirtualScreen.Top; // We reserve the 24 pixels on top for our taskbar
rc.right = SystemInformation.VirtualScreen.Right;
rc.bottom = SystemInformation.VirtualScreen.Bottom - 101;
WinAPI.SystemParametersInfo((int)WinAPI.SPI.SPI_SETWORKAREA, 0, ref rc, 0);
}

What is the best way to capture an application window in C#?

I've developed a simple windows forms application to capture the windows of a video chat application (inbound, aka Remote, and outbound, aka Local).
I use unmanaged Windows API code for this. Here is the Capture code:
// Set Local Window
localHandle = FindWindow(null, "local");
// Backup parent window for local
prevLocalHandle = GetParent(localHandle);
SetParent(localHandle, this.pBoxLocal.Handle);
SetWindowLong(localHandle, GWL_STYLE, WS_VISIBLE + (WS_MAXIMIZE | WS_BORDER | WS_DISABLED));
MoveWindow(localHandle, 0, -TOP_BAR_HEIGHT, this.pBoxLocal.Width, this.pBoxLocal.Height + LOWER_BAR_HEIGHT, true);
// Set Remote Window
remoteHandle = FindWindow(null, "remote");
// Backup parent window for remote
prevRemoteHandle = GetParent(remoteHandle);
SetParent(remoteHandle, this.pBoxRemote.Handle);
SetWindowLong(remoteHandle, GWL_STYLE, WS_VISIBLE + (WS_MAXIMIZE | WS_BORDER | WS_DISABLED));
MoveWindow(remoteHandle, 0, -TOP_BAR_HEIGHT, this.pBoxRemote.Width, this.pBoxRemote.Height + LOWER_BAR_HEIGHT, true);
Here is the Return code:
// Return Windows
SetParent(localHandle, prevLocalHandle);
SetWindowLong(localHandle, GWL_STYLE, (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
MoveWindow(localHandle, 0, 0, NORMAL_WIDTH, NORMAL_HEIGHT, true);
SetParent(remoteHandle, prevRemoteHandle);
SetWindowLong(remoteHandle, GWL_STYLE, (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
MoveWindow(remoteHandle, 0, 0, NORMAL_WIDTH, NORMAL_HEIGHT, true);
The goal is to go from this:
To this:
And then back again! :)
There are currently two issues with my way of doing things:
first of all, when I return the windows to the video chat application, ocasionally a black rectangle is left on my top-left corner of the screen. It disappears when I refresh the area.
second and most important of all, there are times that when I capture the window of the application, I also capture its toolbars (although the measurements I supply are just the ones regarding the video area of the window).
Is there a better way of doing this? Even if its just better functions! Remember: I want to obtain the windows of the video chat application and return them afterwards.
Thanks in advance for any tips!
Ok well the first issue you stated is an easy one to fix. You can just call Refresh() when you return the windows. However if you meant there is a black rectangle on your main desktop not a window then you can use http://msdn.microsoft.com/en-us/library/bb776346(VS.85).aspx which will allow you to force the whole desktop to refresh.
As for the second issue you are having since you are already messing with the Window Long method why not just remove all borders, I believe what might be happening is the border may have a "ThickFrame" which you specify in your return methods but not capture methods so that may be why you are getting toolbars and borders. You can check this by calling GetWindowLong storing that value and seeing what is there, this way you can know exactly what to remove.
Although I am not sure as to what the use of this application is. I believe what you are doing may be the only way to do it, since you are manipulating external screens.

Categories