缘起

最近需要以编程方式调用windows api实现windows10专注模式的切换,但是Google一圈,没有现成代码。找到的相关帖子要么是cpp的要么是rust的,而且是undocument的Windows api。

Csharp调用

以下是完整代码

public static class FocusAssistToogle
{
    private const string NtdllDlDll = "ntdll.dll";
    private const uint DataBufferSize = 4;
    private static readonly byte[] DisableDataBuf = { 0x00, 0x00, 0x00, 0x00 };
    // 01仅优先通知 02 仅限闹钟 
    private static readonly byte[] EnableDataBuf = { 0x02, 0x00, 0x00, 0x00 };

    [DllImport(NtdllDlDll, SetLastError = true)]
    private static extern int ZwUpdateWnfStateData(
        ref WnfSWnfStateName sWnfStateName,
        byte[] buffer,
        uint bufferSize,
        IntPtr previousStateData,
        IntPtr currentStateData,
        uint previousStateDataSize,
        uint currentStateDataSize);

    [StructLayout(LayoutKind.Sequential)]
    private struct WnfSWnfStateName
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public uint[] Data;
    }

    private static WnfSWnfStateName _wnfSWnfShelQuietMomentShellModeChanged = new WnfSWnfStateName
    {
        Data = new uint[] { 0xa3bf5075, 0xd83063e }
    };


    public static bool EnableFocusMode()
    {
        int result = ZwUpdateWnfStateData(ref 			_wnfSWnfShelQuietMomentShellModeChanged,
            EnableDataBuf,
            DataBufferSize,
            IntPtr.Zero,
            IntPtr.Zero,
            0,
            0);
        return result == 0;
    }

    public static bool DisableFocusMode()
    {
        int result = ZwUpdateWnfStateData(ref _wnfSWnfShelQuietMomentShellModeChanged,
            DisableDataBuf,
            DataBufferSize,
            IntPtr.Zero,
            IntPtr.Zero,
            0,
            0);
        return result == 0;
    }
}

调用时,最好先调用DisableFoucusMode方法,再调用EnableFocusMode,参考StackOverflow上的说明

if one attempts to use this to enable focus mode, I recommend first disabling focus mode (pass new byte[] {0x00, 0x00, 0x00, 0x00} instead). Then, after a few milliseconds, one can safely enable focus mode.

ps:如果需要禁用Windows通知中心,不显示通知,可以考虑使用下面这种写入注册表的方式。

void Main()
{
    // 调用
	EnableAllNotifications();
}

private static void SetValue(RegistryHive hive, string keyPath, string valueName, object value)
{
	try
	{
		RegistryKey key;
		if (hive == RegistryHive.CurrentUser)
		{
			key = Registry.CurrentUser.OpenSubKey(keyPath, true);
			if (key == null)
			{
				key = Registry.CurrentUser.CreateSubKey(keyPath);
			}
		}
		else if (hive == RegistryHive.LocalMachine)
		{
			key = Registry.LocalMachine.OpenSubKey(keyPath, true);
			if (key == null)
			{
				key = Registry.LocalMachine.CreateSubKey(keyPath);
			}
		}
		else
		{
			throw new ArgumentException("Invalid registry hive specified.");
		}
		key.SetValue(valueName, value);
		key.Close();
	}
	catch (Exception ex)
	{
		Console.WriteLine($"Failed to set value in registry: {ex.Message}");
	}
}
private static void DeleteValue(RegistryHive hive, string keyPath, string valueName)
{
	try
	{
		RegistryKey key;
		if (hive == RegistryHive.CurrentUser)
		{
			key = Registry.CurrentUser.OpenSubKey(keyPath, true);
		}
		else if (hive == RegistryHive.LocalMachine)
		{
			key = Registry.LocalMachine.OpenSubKey(keyPath, true);
		}
		else
		{
			throw new ArgumentException("Invalid registry hive specified.");
		}
		if (key != null)
		{
			key.DeleteValue(valueName, false);
			key.Close();
		}
	}
	catch (Exception ex)
	{
		Console.WriteLine($"Failed to delete value from registry: {ex.Message}");
	}
}
public static void EnableAllNotifications()
{
	SetValue(RegistryHive.CurrentUser, @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "TaskbarNoNotification", 0);
	SetValue(RegistryHive.CurrentUser, @"Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications", "NoToastApplicationNotification", 0);
	SetValue(RegistryHive.CurrentUser, @"Software\Policies\Microsoft\Windows\Explorer", "DisableNotificationCenter", 0);
	SetValue(RegistryHive.LocalMachine, @"Software\Microsoft\WcmSvc\wifinetworkmanager", "WiFiSenseCredShared",1);
	SetValue(RegistryHive.LocalMachine, @"Software\Microsoft\WcmSvc\wifinetworkmanager", "WiFiSenseOpen", 1);
	SetValue(RegistryHive.CurrentUser, @"Software\Microsoft\Windows\CurrentVersion\Notifications\Settings", "NOC_GLOBAL_SETTING_TOASTS_ENABLED", 1);
}
public static void DisableAllNotifications()
{
    DeleteValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer", "TaskbarNoNotification");
    DeleteValue(RegistryHive.CurrentUser, @"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", "EnableBalloonTips");
    DeleteValue(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", "EnableBalloonTips");
    SetValue(RegistryHive.CurrentUser, @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "TaskbarNoNotification", 1);
    SetValue(RegistryHive.CurrentUser, @"Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications", "NoToastApplicationNotification", 1);
    SetValue(RegistryHive.CurrentUser, @"Software\Policies\Microsoft\Windows\Explorer", "DisableNotificationCenter", 1);
    SetValue(RegistryHive.LocalMachine, @"Software\Microsoft\WcmSvc\wifinetworkmanager", "WiFiSenseCredShared", 0);
    SetValue(RegistryHive.LocalMachine, @"Software\Microsoft\WcmSvc\wifinetworkmanager", "WiFiSenseOpen", 0);
    SetValue(RegistryHive.CurrentUser, @"Software\Microsoft\Windows\CurrentVersion\Notifications\Settings", "NOC_GLOBAL_SETTING_TOASTS_ENABLED", 0);

}

参考链接