Apply changes made in registry regarding window metrics
I want to set specific values for:
Computer\HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics
Is there a way to apply registry changes without the need of logging off and on? Perhaps some service needs restarting? I've tried to restart explorer.exe and dwm.exe, but with no success.
Disclaimer:
I know about winapi function SystemParametersInfo, however this function does not follow specifications, so I am looking for a workaround.
Thank you for your time.
Windows API - Win32
-
David Lowndes 2,535 Reputation points • MVP
2024-04-23T13:14:38.1366667+00:00 What specifically doesn't work for you with the SystemParametersInfo API?
-
RLWA32 45,326 Reputation points
2024-04-23T15:04:05.1133333+00:00 Have you tried broadcasting the WM_SETTINGCHANGE message?
-
Ivan 0 Reputation points
2024-04-24T11:16:57.1666667+00:00 Hi, I am working with Lukas. We had following code to change values in "NONCLIENTMETRICS". The code was working for about a year:
private void SetWindowParameters() { Logger.Info("Setting NONCLIENTMETRICS back", "MyForm"); if (!SystemParametersInfo(SPI_SETNONCLIENTMETRICS, Marshal.SizeOf(typeof(NONCLIENTMETRICS)), ref myMetrics, 0)) { Logger.Error("Failed to set NONCLIENTMETRICS at exit, error code: " + Marshal.GetLastWin32Error(), "MyForm"); return; } Logger.Info("Sending WM_SETTINGCHANGE", "MyForm"); if (!SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0)) { Logger.Error("Failed to broadcast after reloading metrics, error code: " + Marshal.GetLastWin32Error(), "MyForm"); } }
The last parameter of SystemParametersInfo is intentionally set to 0. But now we are facing "freezing" of our application at this method. The Task Manger show us that Microsoft.SharePoint.exe is blocking us, but do not know why. If the Microsoft.SharePoint.exe is terminated, our app is working as expected. With some beta versions of OneDrive the issue disappeared.
Stack from *.DMP file:
STACK_TEXT:
: win32u!NtUserSystemParametersInfo+0x14
: user32!RealSystemParametersInfoW+0x72
: uxtheme!ClassicSystemParametersInfoW+0x4b
: uxtheme!ThemeSystemParametersInfoW+0xb8
: user32!SystemParametersInfoW+0xb2
-
David Lowndes 2,535 Reputation points • MVP
2024-04-24T12:32:48.8366667+00:00 Ivan,
Can you reproduce this hang problem with a stand-alone project (ideally a simple console project)? -
RLWA32 45,326 Reputation points
2024-04-24T12:46:55.0433333+00:00 The docs for WM_SETTINGCHANGE message wParam say "When an application sends this message, this parameter must be NULL." Have you tried this?
-
Castorix31 84,546 Reputation points
2024-04-24T13:44:59.56+00:00 Did you try with SPIF_UPDATEINIFILE | SPIF_SENDCHANGE and without SendNotifyMessage ?
-
Ivan 0 Reputation points
2024-04-24T13:55:28.45+00:00 @David Lowndes Yes, I can .
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace MyConsoleApplication { class Program { static void Main(string[] args) { Console.Write("Hi, press Enter to change borders"); Console.ReadKey(); Helper helper = new Helper(); helper.SetExpectedWindowParameters(); Console.Write("Press Enter to change borders back"); Console.ReadKey(); helper.ReloadWindowParameters(); Console.Write("Press Enter to end"); Console.ReadKey(); } } class Helper { private const int LF_FACESIZE = 32; // A "logical font" used by old-school windows [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct LOGFONT { public int lfHeight; public int lfWidth; public int lfEscapement; public int lfOrientation; public int lfWeight; public byte lfItalic; public byte lfUnderline; public byte lfStrikeOut; public byte lfCharSet; public byte lfOutPrecision; public byte lfClipPrecision; public byte lfQuality; public byte lfPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = LF_FACESIZE)] public string lfFaceName; // to shut it up about the warnings public LOGFONT(string lfFaceName) { this.lfFaceName = lfFaceName; lfHeight = lfWidth = lfEscapement = lfOrientation = lfWeight = 0; lfItalic = lfUnderline = lfStrikeOut = lfCharSet = lfOutPrecision = lfClipPrecision = lfQuality = lfPitchAndFamily = 0; } } private struct NONCLIENTMETRICS { public int cbSize; public int iBorderWidth; public int iScrollWidth; public int iScrollHeight; public int iCaptionWidth; public int iCaptionHeight; public LOGFONT lfCaptionFont; public int iSMCaptionWidth; public int iSMCaptionHeight; public LOGFONT lfSMCaptionFont; public int iMenuWidth; public int iMenuHeight; public LOGFONT lfMenuFont; public LOGFONT lfStatusFont; public LOGFONT lfMessageFont; public int iPaddedBorderWidth; } private const int SPIF_SENDCHANGE = 0x02; private const int SPI_GETNONCLIENTMETRICS = 0x29; private const int SPI_SETNONCLIENTMETRICS = 0x2A; private NONCLIENTMETRICS metrics; private NONCLIENTMETRICS backupMetrics; private IntPtr setMetricsThread; private uint setMetricsThreadID = 0; private bool gotMetrics = true; private int HWND_BROADCAST = 0xFFFF; private uint WM_SETTINGCHANGE = 0x1A; // NONCLIENTMETRICS IMPORTS [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SystemParametersInfo(int Action, int Param, ref NONCLIENTMETRICS lpParam, int WinIni); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); public void SetExpectedWindowParameters() { metrics = new NONCLIENTMETRICS(); backupMetrics = new NONCLIENTMETRICS(); metrics.cbSize = Marshal.SizeOf(metrics); backupMetrics.cbSize = Marshal.SizeOf(backupMetrics); Console.Write("Getting NONCLIENTMETRICS"); if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, ref metrics, 0) || !SystemParametersInfo(SPI_GETNONCLIENTMETRICS, backupMetrics.cbSize, ref backupMetrics, 0)) { gotMetrics = false; Console.Write("Failed to get NONCLIENTMETRICS, error code: " + Marshal.GetLastWin32Error()); return; } metrics.iPaddedBorderWidth = 0x11; metrics.iBorderWidth = 0x21; Console.Write("Setting NONCLIENTMETRICS"); if (!SystemParametersInfo(SPI_SETNONCLIENTMETRICS, metrics.cbSize, ref metrics, 0)) { Console.Write("Failed to set NONCLIENTMETRICS at startup, error code: " + Marshal.GetLastWin32Error()); return; } Console.Write("Sending WM_SETTINGCHANGE"); if (!SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0)) { Console.Write("Failed to broadcast after setting metrics, error code: " + Marshal.GetLastWin32Error()); } } public void ReloadWindowParameters() { if (!gotMetrics) return; Console.Write("Setting NONCLIENTMETRICS back"); if (!SystemParametersInfo(SPI_SETNONCLIENTMETRICS, Marshal.SizeOf(typeof(NONCLIENTMETRICS)), ref backupMetrics, 0)) { Console.Write("Failed to set NONCLIENTMETRICS at exit, error code: " + Marshal.GetLastWin32Error()); return; } Console.Write("Sending WM_SETTINGCHANGE"); if (!SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0)) { Console.Write("Failed to broadcast after reloading metrics, error code: " + Marshal.GetLastWin32Error()); } } } }
-
-
Ivan 0 Reputation points
2024-04-24T14:40:24.9566667+00:00 @Castorix31 The issue is happening in SystemParametersInfo() method. The code do not proceed to the SendNotifyMessage() method. That is the strange part...
-
RLWA32 45,326 Reputation points
2024-04-24T16:16:54.1466667+00:00 The issue is earlier - in the method SystemParametersInfo(), the code do not proceed to the SendNotifyMessage() method. That is the strange part...
I could understand a SystemParametersInfo hang if it was broadcasting WM_SETTINGCHANGE. But like you say, this does seems strange. Have you considered calling SystemParametersInfo from a worker thread so that the entire application doesn't hang if the function doesn't return?
-
David Lowndes 2,535 Reputation points • MVP
2024-04-24T17:12:43.4266667+00:00 Is your pinvoke definition of NONCLIENTMETRICS OK? I notice it doesn't have the StructLayout attribute like your LOGFONT definition has - but I'm not that familiar with pinvoking. It might be simpler to write the example as a C/C++ console program when you won't have such things to worry about.
Also, what happens if you just get/set the setting (i.e. don't change any settings)? -
Ivan 0 Reputation points
2024-04-25T12:39:24.2133333+00:00 The code in C++ has same issue.
// MetricsTest.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include <iostream> int _tmain(int argc, _TCHAR* argv[]) { NONCLIENTMETRICS metrics = {0}; metrics.cbSize = sizeof(metrics); std::cout << "Getting NONCLIENTMETRICS" << std::endl; if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, 0)) { std::cout << "Failed to set NONCLIENTMETRICS at startup" << std::endl; return 1; } metrics.iPaddedBorderWidth = 0x00; metrics.iBorderWidth = 0x01; metrics.cbSize = sizeof(metrics); std::cout << "Setting NONCLIENTMETRICS" << std::endl; if (!SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, 0)) { std::cout << "Failed to set NONCLIENTMETRICS at startup" << std::endl; return 1; } std::cout << "Sending WM_SETTINGCHANGE" << std::endl; if (!SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0)) { std::cout << "Failed to broadcast after setting metrics" << std::endl; return 1; } return 0; }
-
-
David Lowndes 2,535 Reputation points • MVP
2024-04-25T12:48:40.04+00:00 And what if you don't alter the metrics values between Get/Set ?
-
Ivan 0 Reputation points
2024-04-26T13:41:01.9+00:00 The issue is still there.
-
RLWA32 45,326 Reputation points
2024-04-26T13:55:36.6666667+00:00 The docs for SPI_SETNONCLIENTMETRICS say "Also, the lfHeight member of the LOGFONT structure must be a negative value." I don't know if implementing this change will make a difference but it's worth a try.
-
David Lowndes 2,535 Reputation points • MVP
2024-04-26T13:55:52.2433333+00:00 OK, so are you aware of this happening in conjunction with any other application besides SharePoint, and have you tried different versions of SharePoint too (just in case the latest version doesn't exhibit the problem)?
I suspect the only course of action now is to raise it with paid MS support. -
Bikram Sandhu 5 Reputation points
2024-05-28T14:58:20.6466667+00:00 Did you guys find any fix? I am not a developer or a programmer, I am a sysadmin, we have an old application (i think developed in C, but not sure) that start causing the same issue from 3-4 weeks. it freezes and the wait chain shows waiting on Microsoft.SharePoint.exe. If we end the Microsoft.SharePoint.exe, application works fine.
Any help any insights much appreciated.
-
Lukas 15 Reputation points
2024-07-16T13:17:40.32+00:00 Hi, we contacted support paid MS support and its an ongoing issue that can be resolved by adding new registry entry:
[HKLM\SOFTWARE\Policies\Microsoft\OneDrive] "DisableNucleusSync" = "dword:1"
Sharepoint.exe simply stops running on startup and cannot be started manually after restart. The downside are in this article: https://learn.microsoft.com/en-us/SharePoint/lists-sync-policies
We have tested this and the feature that we are disabling by this registry does not even work most of the time.
Hope this helps, sucks that its a workaround and not an actual fix.
-
-
Bikram Sandhu 5 Reputation points
2024-07-16T13:40:15.0866667+00:00 Thanks for sharing Lukas. I am going to try the reg edit.
-
Bikram Sandhu 5 Reputation points
2024-08-07T15:52:58.1266667+00:00 I added that registry entry for around 10 users so far, one user contact back today for the application freeing issue. When I analyze the wait chain it was Outlook.exe this time :-(
Sign in to comment