0

I maintained a system which used the WPF Framework to wrote, which appeared a so weird scene, when screen-saver is running and a window used the ShowDialog to popup a window by timer object, this was popup window will not be appeared the any text, button and another control, its whole view is blank. but the popup window will be works if screen-saver doesn't run. enter image description here

I means that the popup window will have view issue when screen-saver is running. The popup will be works normally if screen-saver doesn't run. enter image description here

This issue which can't reproduce in my development environment locally. it is run for a specific PC(windows 8.1 embedded version)

I figured out a pathway directly to resolve, which is to interrupt screen-saver before ShowDialog window. These are ways included as below,

  • a. Move mouse(used the user32's mouse_event api)
  • b. Send keys(also used the user32's api)
  • c. Kill screen-saver process.
  • d. upgraded to Framework to 4.6.2

Above ways refer to above links, All of these ways can be work well in my locally(Windows 10) , but didn't work on that specific PC(windows 8.1 embedded version) indeed. https://www.codeproject.com/Articles/17067/Controlling-The-Screen-Saver-With-C

https://support.microsoft.com/en-us/help/140723/how-to-force-a-screen-saver-to-close-once-started-in-windows-nt,-windows-2000,-and-windows-server-2003

How to interrupt Screen-saver under windows 8

I have given up this interrupt screen-saver way, I hope look at another key point to resolve this issue, but I didn't know should to focus on which part of code. Have any suggestion for me? thanks in advance. I according to logic of this part of original project to wrote a demo as below,

Main window code

using OutdoorCentral.WPF.UI;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private static object inactivityLockObject = "InactivityLockObject";
        protected delegate void func();
        private static Timer checkActivityTimer;
        public MessageDialog msg = new MessageDialog();

        public enum MessageWindowType
        {
            OK,
            OKCancel,
            YesNo,
            YesNoCancel
        }

        public MainWindow()
        {
            InitializeComponent();
            this.Title = "test";
            AutoResetEvent autoResetEvent = new AutoResetEvent(false);
            checkActivityTimer = new Timer(CheckActivityCallback, autoResetEvent, new TimeSpan(0, 2, 0), new TimeSpan(0, 2, 0));
        }

        private void CheckActivityCallback(object stateInfo)
        {
            CheckActivity();
        }

        private void CheckActivity()
        {
            lock (inactivityLockObject)
            {
                InvokeOnUiThread(ForceLogout);
            }
        }

        protected void InvokeOnUiThread(func method)
        {
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, method);
        }

        private void ForceLogout()
        {
            checkActivityTimer.Dispose();
            msg.TitleLabel.Content = Title;
            msg.Topmost = true;
            msg.Message = "test focus on message missed";
            msg.MessageWindowType = MessageWindowType.OK;
            msg.ShowDialog();
        }
    }
}

There was pop-up window code as below

using System.Diagnostics;
using Microsoft.Win32;
using System.Windows;
using System;
using System.Threading;
using System.Runtime.InteropServices;
using WpfApplication1;
using static WpfApplication1.MainWindow;

namespace OutdoorCentral.WPF.UI
{
    /// <summary>
    /// Interaction logic for MessageDialog.xaml
    /// </summary>
    public partial class MessageDialog : Window
    {
        public MessageDialog()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MessageDialog_Loaded);
        }

        public bool? MessageResult { get; set; }

        void MessageDialog_Loaded(object sender, RoutedEventArgs e)
        {
            SetWindowType();
        }

        new string Title
        {
            get { return TitleLabel.Content.ToString(); }
            set { TitleLabel.Content = value; }
        }

        public string Message
        {
            get { return MessageText.Text; }
            set { MessageText.Text = value; }
        }

        private MessageWindowType messageWindowType;
        public MessageWindowType MessageWindowType
        {
            get { return messageWindowType; }
            set
            {
                messageWindowType = value;
                SetWindowType();
            }
        }

        private void SetWindowType()
        {
            switch (MessageWindowType)
            {
                case MessageWindowType.OKCancel:
                    CancelButton.Visibility = Visibility.Visible;
                    break;
                case MessageWindowType.YesNo:
                    OKButton.Content = "Yes";
                    NoButton.Visibility = Visibility.Visible;
                    break;
                case MessageWindowType.YesNoCancel:
                    OKButton.Content = "Yes";
                    CancelButton.Visibility = Visibility.Visible;
                    NoButton.Visibility = Visibility.Visible;
                    break;
            }
        }

        private void Done(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
            MessageResult = true;
        }

        private void NoSelection(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
            MessageResult = false;
        }

        public void Canceled(object sender, RoutedEventArgs e)
        {
            MessageResult = null;
            this.Close();
        }

        private void Window_LostFocus(object sender, RoutedEventArgs e)
        {
            this.Focus();
        }
    }
}

Actually, it's very simple code for below, please give me some suggestions. thanks in advance.

Jason.gao
  • 21
  • 2

2 Answers2

0

You can try to check if a screensaver is running by querying SystemParametersInfo() with SPI_GETSCREENSAVERRUNNING parameter (because as far as I know there is no any event like "screensaver on/off"). So, once you detect a screensaver active, you can postpone any popups until the screensaver is off.

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int fuWinIni);

const int SPI_GETSCREENSAVERRUNNING = 114;
int screenSaverRunning = -1;

// is the screen saver running?

int ok = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref screenSaverRunning, 0);

if (ok == 0)
{
    Console.WriteLine("Call to SystemParametersInfo failed.");
}

if (screenSaverRunning != 0)
{
    // screen saver is running
    ... do something ...
}
else
{
    // screen saver is NOT running
    ... do other thing ...
}

Original link: https://bytes.com/topic/c-sharp/answers/261540-detecting-screensaver-state

Yury Schkatula
  • 5,291
  • 2
  • 18
  • 42
0

I know this is a rather old question, but I've spent a lot of time trying to figure this out and am hoping to save anyone else some time if they happen to stumble upon it.

By default, WPF uses hardware acceleration to render the UI, if your system supports it. While the screen saver is active, it seems to hog the GPU which prevents WPF from rendering normally (totally speculating here, but the fix suggests this is true).

I was able to fix this in my application by disabling hardware acceleration, as it's not required for my relatively basic UI.

You can set your process's rendering mode to software-only at startup like this:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;

You can also disable hardware acceleration on a per-window basis.