スクリーンセーバー起動の回避

(1878d) 更新

公開メモ

スクリーンセーバー起動の回避

長時間ユーザーの入力なしに画面表示を行うことを目的としたアプリケーション、 例えばスライドショーソフト、ビデオ再生ソフト、ゲームパッドのみを用いる ゲームソフト、計器の状態を表示し続ける測定ソフトなどでは、その動作中に スクリーンセーバーが起動してしまうと不都合な場合がある。

これを回避するための方法をインターネット上で探すと
http://d.hatena.ne.jp/NyaRuRu/20080925/p1

  • SetThreadExecutionState を使う
  • WM_SYSCOMMAND メッセージを補足する(フォアグランドアプリケーションのみ可能)
  • SetCursorPos でカーソル位置を移動させる
  • ・・・

などなどいろいろ記述が見つかるが、

  • Windows Vista
  • 再開時にパスワードが必要

の条件が重なるとなかなかうまく行かない。

解決法

探し回ったあげく、ここにあった方法はそれなりの効果があった。

http://groups.google.com/group/microsoft.public.win32.programmer.kernel/browse_thread/thread/976caa9de9a5e359

以下の関数を定期的に(1分以下の間隔で)呼んでやることで スクリーンセーバーは起動しない。

ただ、マウスカーソルが始終プルプル動くので、 フルスクリーンでマウスカーソルを消して実行しているような、 スライドショーやビデオ再生ソフトくらいでしか使えない?

LANG:C#(linenumber)
void PreventScreenSaverFromStarting()
{
    Point pos = Cursor.Position;
    Cursor.Position = new Point(pos.X + 1, pos.Y + 1);
    if ( Cursor.Position == pos )
        Cursor.Position = new Point(0, 0);

    INPUT input = new INPUT();
    input.type = INPUT_MOUSE;
    input.mi = new MOUSEINPUT();

    input.mi.dwExtraInfo = IntPtr.Zero;
    // mouse co-ords: top left is (0,0), bottom right is (65535, 65535)
    // convert screen co-ord to mouse co-ords...
    Random ran = new Random();
    input.mi.dx = ran.Next(0, 2000);
    input.mi.dy = ran.Next(0, 3000);
    input.mi.time = 0;
    input.mi.mouseData = 0;
    input.mi.dwFlags = 0x0001 | 0x8000; // MOVE | ABSOLUTE

    int cbSize = Marshal.SizeOf(typeof(INPUT));
    uint r = SendInput(1, ref input, cbSize);
}

#region Win32 API
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
    public int dx;
    public int dy;
    public uint mouseData;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}
const int INPUT_MOUSE = 0;

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
    ushort wVk;
    ushort wScan;
    uint dwFlags;
    uint time;
    IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
    uint uMsg;
    ushort wParamL;
    ushort wParamH;
}

[StructLayout(LayoutKind.Explicit)]
struct INPUT
{
    [FieldOffset(0)]
    public int type;
    [FieldOffset(4)] //*
    public MOUSEINPUT mi;
    [FieldOffset(4)] //*
    public KEYBDINPUT ki;
    [FieldOffset(4)] //*
    public HARDWAREINPUT hi;
}

[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

[FlagsAttribute]
public enum EXECUTION_STATE: uint
{
    ES_SYSTEM_REQUIRED = 0x00000001,
    ES_DISPLAY_REQUIRED = 0x00000002,
    // Legacy flag, should not be used.
    // ES_USER_PRESENT   = 0x00000004,
    ES_CONTINUOUS = 0x80000000,
}

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
#endregion

改善案

手元で試した限り、マウスカーソルを動かさなくても ダミーのインプット(実際にはカーソルを動かさない) を送り続けている限りスクリーンセーバーの起動は 阻止できるみたいだった。

これならカーソルが勝手に動くこともないので使いやすそう。

LANG:C#(linenumber)
void PreventScreenSaverFromStarting()
{
    INPUT input = new INPUT();
    input.type = INPUT_MOUSE;
    input.mi = new MOUSEINPUT();

    input.mi.dwExtraInfo = IntPtr.Zero;
    input.mi.dx = 0;
    input.mi.dy = 0;
    input.mi.time = 0;
    input.mi.mouseData = 0;
    input.mi.dwFlags = 0x0001; // MOVE (RELATIVE)
    int cbSize = Marshal.SizeOf(typeof(INPUT));
    uint r = SendInput(1, ref input, cbSize);
}

コメント





Counter: 11840 (from 2010/06/03), today: 3, yesterday: 0