-2

I am catching the WM_SETTINGSCHANGE in WndProc so that I can update my app for dark/light mode changes. I run the app and catch the messages when I change my user preference in Personalization / Colors / Choose Your Mode (light, dark, custom) on Windows 11.

I notice that changing my preference generates TWO of the WM_SETTINGSCHANGE messages in WndProc. They do have different numbers in the LParam, but I can't figure out how to print the LParam string in C# (if that makes a difference).

The values of the two messages are as follows, where 0=user policy change. I don't know what the values of the lparams are - the doc says they are the addresses of strings (possibly to null strings?) provided by the sender of the messages:

wparam=0, lparam=800528915624
wparam=0, lparam=800528912280

Does this mean I have to update all my app settings twice whenever I get a message? (The Microsoft doc for WM_SETTINGSCHANGE recommends updating all app system settings each time.) Does anyone know why my single preference change triggers TWO settings change messages? Thank you.

Kevin
  • 1,548
  • 2
  • 19
  • 34
  • What are the `wParam` values of the two messages? You may find `WM_SYSCOLORCHANGE` is a better message to look for. – Jonathan Potter May 03 '23 at 22:42
  • I added the values of wparm and lparam to the question. I will go look up syscolorchange; I got the WM_SETTINGSCHANGE from one of the other SO posts that I read. – Kevin May 04 '23 at 01:32
  • Also, my app does not receive WM_SYSCOLORCHANGE when I change the user preferences to dark mode, so that is not an option. – Kevin May 04 '23 at 01:38
  • 3
    The `lParam`, if not `NULL`, is a pointer to a string that represents the category that was changed. On my system (Windows 10) I get more than two `WM_SETTINGSCHANGE` messages, all of which have a value of `"ImmersiveColorSet"` passed as the `lParam`. I guess this is because multiple colors do change (such as a custom accent color). – IInspectable May 04 '23 at 06:59
  • @IInspectable, thank you for making the point that multiple colors might have changed, maybe in different windows, client areas, etc. That would explain why multiple messages are being sent out. My color code is minor and fast, so it's no big harm if I do things twice or N times. Do you suppose it would be workable to wait a bit for all the messages to arrive and then do my changes only once? – Kevin May 04 '23 at 16:24
  • 1
    From observation, it appears as though the Settings app broadcasts `WM_SETTINGSCHANGE` messages using [`SendMessageTimeoutW`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagetimeoutw), which sends messages to all top-level windows, in order, and doesn't move on to the next window until the previous one has handled the message (or timed out). Whatever you are doing in response to this message thus *adds* to the overall time it takes for the change notification to propagate to all windows in the system (there's no parallelism here, I believe). – IInspectable May 04 '23 at 19:38
  • 1
    Keeping the response time low is a good idea to keep the perceived system responsiveness up. Whether it is worth the extra complexity of setting up and resetting a timer on each notification depends no how expensive the operations you are performing really are (`InvalidateRect()`, for example, may be relatively cheap, while `RedrawWindow()` might not). Though, that would probably make for a good Q&A in itself. – IInspectable May 04 '23 at 19:44
  • I went through some mental calculations like the ones you described and concluded that I just have to bite the bullet and do my color changes each time. I'm just walking menus and setting colors in controls, so it is a non-zero time but cheap. Setting up timers or queues etc. is going to take just as long, and waiting for the second message will also take time. You know the old rule, "Never spend time optimizing anything unless you have measured it and know that it causes an issue." :-) – Kevin May 05 '23 at 21:24

1 Answers1

2

As I mentioned in my answer to your other question:

In C#, you can use PtrToStringAnsi(), PtrToStringUni(), or PtrToStringAuto() function (depending on how you are creating your window) to access the string value from the lParam of WM_SETTINGCHANGE.

But, as @IInspectable noted, you are likely to get multiple messages with the same string value. So yes, you will have to reload your app settings each time. To avoid doing that unnecessarily if you receive multiple messages in a short period of time, you can throttle the reload by (re)starting a short timer whenever a new setting-changing message is received, and then reload your app settings only when that timer has elapsed.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • once again, you are _exactly_ on target. "Throttling" or avoiding doing the settings reload multiple times unnecessarily is _exactly_ why I wanted to dereference the C string - so that I could see what was going on and why Windows would be sending me two messages instead of just one. I saw a sequence in another SO post that said Windows would 1) save some parameters, 2) pump out a message, 3) set the new values, and 4) pump out another message. I don't know if that applies to my case. I am impressed by your accuracy at knowing what I was trying to do. Thank you again. – Kevin May 04 '23 at 16:21