tags:

views:

49

answers:

3

Hi,

I want to disable the screensaver and monitor power off. At this stage there's no windows form, which I could youse. Thus I wan't to use NativeWindow.

Here's my code

sealed class ObserverWindow : NativeWindow, IDisposable
{
    internal ObserverWindow()
    {
        this.CreateHandle(new CreateParams()
        {
            Parent= IntPtr.Zero
        });

    }

    public void Dispose()
    {
        DestroyHandle();
    }

    protected override void WndProc(ref Message msg)
    {
        if (msg.Msg == WM_SYSCOMMAND &&
            ((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
            ((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
        {
            msg.Msg = 0;
            msg.HWnd = IntPtr.Zero;
        }
        base.WndProc(ref msg);
    }
}

The Problem is, that the WndProc is not called with WM_SYSCOMMAND. Actualy the WndProc is called 4 times. At the last call there's msg.Msg == WM_CREATE.

I think I'm missing some create parameter. Does anyone have advise?

Regards Michael

UPDATE

I was running the code in a non STA thread. Thus the window did not reveive any messages exept the initial ones. Now I'm receiving WM_SYSCOMMAND messages. But when the screensaver is activated, there's no message.

I also tried to overwrite a Form's WndProc with the same result. But this used to work in Windows XP. Is there a change in Windows 7?

OS: Windows 7 64bit.

SOLUTION

As a comment in this Question states, only the foreground window can cancel the screensaver. Thus the above code can't work. The NativeWindow is great for receiving messages, but not for canceling a screensaver. For latter I recommend the answer to this question.

A: 

Disabling the screen saver is much easier, according to this KB article:

This can be done easily using:

SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,
                      FALSE,
                      0,
                      SPIF_SENDWININICHANGE
                    );

[...]

If you need the screen saver to start up again, you'll need to reinitialize the time-out period. Do this by [c]alling SystemParametersInfo (SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDWININICHANGE).

Thomas
This would probably do it, but my intension is to disable the screensaver temporarely. Your approach would overwrite any change done by the user. Anyway I missed to mention, that I wan't to disable power saving also.
Michael Stoll
A: 

You could try overriding DefWndProc instead.

public override void DefWndProc(ref Message msg)
{
    if (msg.Msg == WM_SYSCOMMAND &&
        ((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
        ((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
    {
        msg.Msg = 0;
        msg.HWnd = IntPtr.Zero;
    }
    base.DefWndProc(ref msg);
}

I'm not on a Windows box right now, so I cannot test this. Let me know if it works.

Thomas
I can't, it's not virtual.
Michael Stoll
+1  A: 

The proper way to do this is by telling Windows that your thread needs to have the display active. Commonly used by video players. P/Invoke the SetThreadExecutionState() API function, pass ES_DISPLAY_REQUIRED. And ES_SYSTEM_REQUIRED to keep the machine from shutting down automatically. Visit pinvoke.net for the required declarations.

Hans Passant
Great, this is exactly, what I was looking for.
Michael Stoll