Search code examples
winapiwndproclparam

How to read WM_SETTINGCHANGE LParam in C#?


In my WndProc I receive a WM_SETTINGCHANGE message, and I want to see what category the caller sent in the LParam field of the incoming message. Try as I might (and after searching everywhere), I cannot find anything that shows how to get the original string into C# where I can see it. The best I got was the code below, but it causes a system access violation attempting to read protected memory at the GetLParam call.

I get the feeling that the method for accessing LParam varies with every different WM_* message type.

    var mystr = new COPYDATASTRUCT();
    var mytype = mystr.GetType();
    mystr = (COPYDATASTRUCT) wMsg.GetLParam(mytype)!; // sys access violation here
    var textReceived = mystr.lpData;
    // System.AccessViolationException: 'Attempted to read or write protected memory

How can I dereference or copy the LParam so that I can see what category the WM_SETTINGCHANGE is referring to? Thank you.

UPDATE: Here is the solution that I was looking for, thanks to @Remy below.

 case WM_SETTINGCHANGE:
        // this arrives TWICE on a user dark mode change
        var text = Marshal.PtrToStringAuto(wMsg.LParam);
        var msg = @$"WM_SETTINGCHANGE received: W:{wMsg.WParam}" + $" - L: {text}";
        MessageBox.Show(msg);

Solution

  • I get the feeling that the method for accessing LParam varies with every different WM_* message type.

    Yes, it does. So, you have to read the documentation for each individual message. For instance:

    Per the WM_COPYDATA documentation:

    lParam

    A pointer to a COPYDATASTRUCT structure that contains the data to be passed.

    Per the WM_SETTINGCHANGE documentation:

    lParam is a pointer to a [C-style null-termimated] string that indicates the area containing the system parameter that was changed. This parameter does not usually indicate which specific system parameter changed. (Note that some applications send this message with lParam set to NULL.) In general, when you receive this message, you should check and reload any system parameter settings that are used by your application.

    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.