[VC2005] スクリーンセーバーを作る方法

◆概要

この資料は、Microsoft(R) Visual C# 2010で スクリーンセーバーを作る方法について記述しています。

 スクリーンセーバーとは、標準的なexe拡張子の代わりにscrの拡張子をもつ標準的なWidnowsの実行可能ファイルです。つまり、Formアプリケーションを作成後、拡張子をexeからscrへ変更したものです。

 Windowsはスクリーンセーバーを実行するとき、特定の引数を渡すことになります。その引数とは、"/s"(スクリーンセーバーを表示する)、"/P"(画面のプロパティダイアログボックスのスクリーンセーバータブに表示される小さなモニターの中に表示されるプレビュー)、"/c"(スクリーンセーバーのオプション表示したり構成する)です。WindowsはスクリーンセーバーのMainメソッドでこれらの引数を読み取り、それに応じてスクリーンセーバーを表示したり、オプション画面を表示したりします。

スクリーンセーバーは通常、全画面で実行されます。従って、キーが押されたか、マウスが移動したかでスクリーンセーバーを終了させることが必要です。

また、スクリーンセーバーは、他のすべてのウィンドウの上で表示され、かつ、マウスカーソルは非表示にする必要があります。


▼ページトップへ

引数を読み取る

C#アプリケーションに引数を読み込むことができる唯一の場所は、自動的に作成される Main()メソッドです。
ソリューションエクスプローラーで、"Program.cs"と表示されているコードファイルがあるはずです。コードエディタで開くと、次のようになっていると思います。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace MyscreenSaver
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

既定ではMainメソッドは、引数がありません。それを編集して引数"string[] args"を受け取るようにします。そうすることで、アプリケーションに渡される引数を読み込むことができるようになります

static void Main(string[] args)
{
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(new Form1());
}

argsパラメータはアプリケーションに渡されるすべての引数を保持します。さて、それらの引数を解釈して引数を一つだけ、スクリーンセーバーに渡されるようにする必要があります。次のようにすると単純なifステートメントで容易に引数を読み取ることができます。

if (args[0].ToLower().Trim().Substring(0, 2) == "/s") //show
{
   // スクリーンセーバーを表示
}
else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") //preview
{
   // プレビュー画面を表示
}
else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") //configure
{
   // スクリーンセーバーのオプション表示
}

しかし、引数なしがスクリーンセーバーに渡される可能性があります。したがって、他のif文を追加します。

if (args.Length > 0)
{
   if (args[0].ToLower().Trim().Substring(0, 2) == "/s") //show
   {
       // スクリーンセーバーを表示
    }
   else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") //preview
   {
       // プレビュー画面を表示
    }
    else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") //configure
    {
       // スクリーンセーバーのオプション表示
     }
}
else
{
   // 引数なしの場合。これはユーザーがファイルを右クリックして
   //「構成」を選んだときに発生します。通常はオプションフォームを表示します。
}
この段階で、Mainメソッドは次のようになっていると思います。
static void Main(string[] args)
{
   if (args.Length > 0)
   {
      if (args[0].ToLower().Trim().Substring(0, 2) == "/s") //show
      {
          // スクリーンセーバーを表示
       }
      else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") //preview
      {
         // プレビュー画面を表示
       }
      else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") //configure
      {
         // スクリーンセーバーのオプション表示
        }
   }
   else
   {
      // 引数なしの場合。これはユーザーがファイルを右クリックして
      //「構成」を選んだときに発生します。通常はオプションフォームを表示します。
    }
}

▼ページトップへ

二重起動を防止する

 一般にプログラムの二重起動を防止するには、Mutexクラスを利用します。Mainメソッドに次のコードを追加します。

        static void Main(string[] args)
        {
            //Mutexクラスの作成
            System.Threading.Mutex mutex 
                = new System.Threading.Mutex(false, Application.ProductName);

            //ミューテックスの所有権を要求する
            if (mutex.WaitOne(0, false) == false)
            {
                //すでに起動していると判断して終了
                return;
            }
            // GC.KeepAlive メソッドが呼び出されるまで、ガベージ コレクション対象から除外される
            GC.KeepAlive(mutex);
            // Mutex を閉じる
            mutex.Close();

▼ページトップへ

スクリーンセーバーを設定する

 ここで、アプリーションを実行するとコンソールアプリケーションを実行したような状態になります。MainメソッドでApplication.Runを呼び出していないからです。
さて、複数のモニタをサポートするために使用する構造を説明します。 複数のモニタをサポートするためには、すべての画面上の別のメインフォームが表示されますので、代わりに、単に、メインフォームを作り、すべての画面を埋めるために、それを伸ばし、スクリーンセーバーを作成します。 これを行うには、System.Windows.Forms.Screenクラスが便利です。このコードを見てみましょう

foreach (Screen screen in Screen.AllScreens)
{
   MainForm screensaver = new MainForm(screen.Bounds);
   screensaver.Show();
}

foreachループでは、現在のコンピュータ上のすべての画面(モニタ)をループして参照しています。しかし、引数をメインフォームに渡すコンストラクタメソッドがないため、うまく動作しません。メインフォームにコンストラクタを追加します。

public MainForm(Rectangle Bounds)
{
   InitializeComponent();
   this.Bounds = Bounds;
   Cursor.Hide();
}

見てわかるように、それは、(境界とは何かということ)System.Drawing.Rectangleの引数を取るコンストラクタでは、コンストラクタに渡されたいずれかのフォームの境界を設定します。また、スクリーンセーバーでカーソルを隠すには、Curor.Hide()を使います。

なので、スクリーンセーバーを実行するには、次のようにメソッドを作成することができます

static void ShowScreenSaver()
{
   foreach (Screen screen in Screen.AllScreens)
   {
       MainForm screensaver = new MainForm(screen.Bounds);
       screensaver.Show();
   }
}

これは通常、スクリーンセーバーを表示するためのメソッドなので(Program)に記述します。Programのクラスは、次のようになります。

using System;
using System.Windows.Forms;

namespace MyscreenSaver
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //Mutexクラスの作成
            System.Threading.Mutex mutex 
                = new System.Threading.Mutex(false, Application.ProductName);

            //ミューテックスの所有権を要求する
            if (mutex.WaitOne(0, false) == false)
            {
                //すでに起動していると判断して終了
                return;
            }
            // GC.KeepAlive メソッドが呼び出されるまで、ガベージ コレクション対象から除外される
            GC.KeepAlive(mutex);
            // Mutex を閉じる
            mutex.Close();
            if (args.Length > 0)
            {
                if (args[0].ToLower().Trim().Substring(0, 2) == "/s") // 表示
                {
                    // スクリーンセーバーを実行
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver(); //
                    Application.Run();
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") // プレビュー
                {
                    // プレビュー画面を表示                                    }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") // 設定
                {
                    // スクリーンセーバーのオプション表示                    
                }                            }
            else// 引数なしの場合
            {
                // 渡される引数がない場合、これはユーザーがファイルを右クリックして
                //「構成」を選んだときに発生します。通常はオプションフォームを表示します。                            }
        }

        // スクリーンセーバーを表示
        static void ShowScreenSaver()
        {
            // コンピューター上のすべてのスクリーン(モニター)をループ
            foreach (Screen screen in Screen.AllScreens)
            {
                MainForm screensaver = new MainForm(screen.Bounds);
                screensaver.Show();
            }
        }
    }
}

注意:Programクラスの中に ShowScreenSaver() メソッドを記載するときは、staticクラスにする必要があります。

 さて、アプリケーションが、/ sを渡された場合、または何も渡されなかった場合、実際にそのメソッドを使用するようにMain()メソッドを変更してみましょう。

            if (args.Length > 0)
            {
                if (args[0].ToLower().Trim().Substring(0, 2) == "/s") //表示
                {
                    // スクリーンセーバーを表示
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver(); //
                    Application.Run();
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") //プレビュー
                {
                    // プレビュー画面を表示
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") //設定                {
                    // スクリーンセーバーのオプション表示
                }
            }
            else
            {
                // 引数なしの場合。これはユーザーがファイルを右クリックして
                //「構成」を選んだときに発生します。通常はオプションフォームを表示します。
                // ここでは、スクリーンセーバーを表示しています。
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                ShowScreenSaver(); //
                Application.Run();
            }

一応、スクリーンセーバーができましたが完全ではありません。Main()メソッドに /p と /cのためのコードを作成する必要があります。さて/c(設定)引数のための設定ですが、ユーザーに設定オプションを選択できるようにしたいですか?その場合は、単に設定のためのフォームを作成し、それを表示するようにします。そのフォームでiniファイルかレジストリに設定を保存するようにします。次の例は、プロジェクトに新しいフォーム「ConfigureForm」を追加してから記述します。

else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") // 設定
{
    // スクリーンセーバーのオプション表示
     Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new ConfigureForm()); //
}

一方、ユーザーが設定することができる任意のオプションを持っていないなら、次のようにメッセージを表示するようにします。

else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") // 設定
{
    // スクリーンセーバーのオプション表示
     MessageBox.Show("オプションなし"
           + "\nこのスクリーンセーバーには、設定できるオプションはありません。",
           "My Screen Saver",
           MessageBoxButtons.OK,
           MessageBoxIcon.Information);
}

上記のコードでは、スクリーンセーバーは設定可能なオプションを持っていないとユーザーに示すメッセージが表示されます。そこでアプリケーションは終了します。

さて、/ p(プレビュー)の引数を処理しましょう。プレビューは、Windowsスクリーンセーバーのダイアログに表示される小さなモニターの中にスクリーンセーバーを表示したい場合の処理です。プレビューを必要としない場合は、プレビューを処理するセクションに任意のコードを必要としません。
プレビューをするようにするにはどうするのか?その方法を説明します。

▼ページトップへ

プレビューの設定

これは少しトリッキーです。これにはいくつかのAPIを使用します。Windowsが自動的にプレビューウィンドウで表示してくれないので、アプリケーションの中にコードを記述する必要があります。Windowsは、/ pコマンドを受け取ると、それはまた別の引数を渡します。 スクリーンセーバー]ダイアログボックス上のプレビューウィンドウへのハンドルを返します。プレビューウィンドウをスクリーンセーバーのメインフォームの親とするためにいくつかのAPIを使用します。これを実現するためには次のようにします。

  1. 最初の引数/pを見て、2番目の引数はプレビューウィンドウへのハンドルを感知します。
  2. Application.Run()を使用してメインフォームとしてのMainFormを使用してアプリケーションを実行します。また、プレビューウィンドウへのハンドルをメインフォームに渡します。
  3. メインフォームは、プレビューウィンドウ内に表示されます。

では、その実装を開始しましょう。まず、メインルーチンのセクションを更新します。

else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") // プレビュー
{
    // プレビュー画面を表示
}

 次のように編集します。

else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") // プレビュー
{
    // プレビュー画面を表示
     Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    //args[1] はプレビューウィンドウのハンドル
    Application.Run(new MainForm(new IntPtr(long.Parse(args[1]))));
}

 次の行に注目してください。

Application.Run(new MainForm(new IntPtr(long.Parse(args[1]))));

IntPtrの形式でプレビューウィンドウへのハンドルをMainFormに渡しています。しかし、IntPtrを受け入れることをフォームのコンストラクタを持っていないので、次のコードを使用します。

//このコンストラクタはスクリーンセーバーの設定ダイアログボックスのハンドル
//プレビューモード (/p)で使用される
public MainForm(IntPtr PreviewHandle)
{
   InitializeComponent();
   //このウィンドウの親ウィンドウを設定する
   SetParent(this.Handle, PreviewHandle);

   //この子ウィンドウを作成する
   //スクリーンセーバーの設定ダイアログボックスが閉じられると終了する
   SetWindowLong(this.Handle, -16,
        new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));

   //親ウィンドウのサイズに設定する
   Rectangle ParentRect;
   GetClientRect(PreviewHandle, out ParentRect);
   this.Size = ParentRect.Size;

   //ロケーションを設定
   this.Location = new Point(0, 0);

   IsPreviewMode = true;
}

この段階ではエラーが表示されると思います。4つのAPIを記述する必要があります。
まず、APIを使用するためusingディレクティブに次のコードを追加します。

using System.Runtime.InteropServices;

次にAPIを追加します。

#region Preview API's

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

#endregion

コンストラクタ内の変数は、IsPreviewModeです。アプリケーションが実行されているときに、それがプレビューモードかどうかをアプリケーションに知らせます。スクリーンセーバーを作成するときには、IsPreviewModeと呼ぶBoolearn型のグローバル変数を作成します。プレビューモードになっているときに、マウスイベントやキーイベントを無効にするためにそのような変数が必要になります。アプリケーション内にそれを終了させるキーダウンイベントコードを持っているときには、アプリケーションがプレビューモードではないことを確認するために、ifステートメントを入れてください。 なぜって?「スクリーンセーバーの設定」ダイアログボックス上のプレビューウィンドウでプレビューしている際、プレビューウィンドウの上にマウスを移動させキーを押すか、クリックするしたとき、別のプレビューを選択したときにその前のプレビューの予防策を講じない場合は、前のスクリーンセーバーのプレビューが表示されることがあるからです。
また、特定のコードは、プレビューモードで実行されないようにIsPreviewMode変数を使用することができます。そして、特定のコードは表示ユンモードでは実行されず、プレビューモードで実行されます。それは非常に便利です。

すべてをまとめる

Program.csファイルは、この時点で次のようになります。

using System;
using System.Windows.Forms;

namespace MyscreenSaver
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //Mutexクラスの作成
            System.Threading.Mutex mutex 
                = new System.Threading.Mutex(false, Application.ProductName);

            //ミューテックスの所有権を要求する
            if (mutex.WaitOne(0, false) == false)
            {
                //すでに起動していると判断して終了
                return;
            }
            // GC.KeepAlive メソッドが呼び出されるまで、ガベージ コレクション対象から除外される
            GC.KeepAlive(mutex);
            // Mutex を閉じる
            mutex.Close();
            if (args.Length > 0)
            {
                if (args[0].ToLower().Trim().Substring(0, 2) == "/s") // 表示
                {
                    // スクリーンセーバーを実行
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver(); //
                    Application.Run();
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") // プレビュー
                {
                    // プレビュー画面を表示
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    //args[1] はプレビューウィンドウのハンドル
                    Application.Run(new MainForm(new IntPtr(long.Parse(args[1]))));
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") // 設定
                {
                    // スクリーンセーバーのオプション表示
                    MessageBox.Show("オプションなし"
                        + "\nこのスクリーンセーバーには、設定できるオプションはありません。",
                        "My Screen Saver",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                }
                else
                // 引数が渡されたが、それが /s, /p,/c 
                // でなかった場合
                {
                    // 常にスクリーンセーバーを表示
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver();
                    Application.Run();
                }
            }
            else// 引数なしの場合
            {
                // 渡される引数がない場合、これはユーザーがファイルを右クリックして
                //「構成」を選んだときに発生します。通常はオプションフォームを表示します。
                // このプロジェクトでは設定フォームを準備していないため、
                // スクリーンセーバーを実行しています。
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                ShowScreenSaver(); //
                Application.Run();
            }
        }

        // スクリーンセーバーを表示
        static void ShowScreenSaver()
        {
            // コンピューター上のすべてのスクリーン(モニター)をループ
            foreach (Screen screen in Screen.AllScreens)
            {
                MainForm screensaver = new MainForm(screen.Bounds);
                screensaver.Show();
            }
        }
    }
}

MainFormの中に2つの新しいコンストラクタを追加します(これはプレビューを選択しなかった場合にのみ一番上になります)。

bool IsPreviewMode = false;

#region Constructors

public MainForm()
{
   InitializeComponent();
}

// このコンストラクタは、フォームを全画面で表示する
// ノーマルモードで使用される
public MainForm(Rectangle Bounds)
{
   InitializeComponent();
   //フォームのバックカラーを黒に設定
   this.BackColor = Color.Black;
   //コントロールボックスを表示しないように
   //FormBorderStyleをNoneに設定
   this.FormBorderStyle = FormBorderStyle.None;
   this.Bounds = Bounds;
   //フォームを最前面に設定
   TopMost = true;
   // マウスカーソルを非表示にする
   Cursor.Hide();

}

// このコンストラクタは、スクリーンセーバーの選択ダイアログボックスの小窓で使用される。
// プレビューモードで使用される (/p)
public MainForm(IntPtr PreviewHandle)
{
   InitializeComponent();
   // このウィンドの親ウィンドウにプレビューウィンドを設定
   SetParent(this.Handle, PreviewHandle);
   // この子ウィンドウをスクリーンセーバーの選択ダイアログボックスが閉じられたとき
   SetWindowLong(this.Handle, -16, new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));

   //ウィンドウサイズを親ウィンドウのサイズに設定する
   Rectangle ParentRect;
   GetClientRect(PreviewHandle, out ParentRect);
   this.Size = ParentRect.Size;

   // ロケーションを(0, 0)に設定
   this.Location = new Point(0, 0);

   IsPreviewMode = true;
}

#endregion

さて、もう一つしなければならないことがあります。キーが押されたときやマウスが動いたときにスクリーンセーバーを終了させるFimctionを実装します。次のようなります。MainFormに記述してください。

        #region User Input

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            //** プレビューを実行していないとき
            if (!IsPreviewMode) // プレビュー画面用に無効にする
            {
                System.Environment.Exit(0);
            }
        }

        private void MainForm_Click(object sender, EventArgs e)
        {
            //** レビューを実行していないとき
            if (!IsPreviewMode) // プレビュー画面用に無効にする
            {
                System.Environment.Exit(0);
            }
        }

        // XとY int.MaxValueのとOriginalLoctionを始める
        // カーソルがその位置にすることは不可能なので。
        // この変数がまだ設定されている場合
        Point OriginalLocation = new Point(int.MaxValue, int.MaxValue);

        private void MainForm_MouseMove(object sender, MouseEventArgs e)
        {
            //** プレビューを行っていない場合は、このif文を取り出す
            if (!IsPreviewMode) // プレビューのとき終了関数を無効にする
            {
                //originallocationが設定されているかどうかを確認
                if (OriginalLocation.X == int.MaxValue &
                    OriginalLocation.Y == int.MaxValue)
                {
                    OriginalLocation = e.Location;
                }
                // マウスが20 pixels 以上動いたかどうかを監視
                // 動いた場合はアプリケーションを終了
                if (Math.Abs(e.X - OriginalLocation.X) > 20 |
                    Math.Abs(e.Y - OriginalLocation.Y) > 20)
                {
                    System.Environment.Exit(0);
                }
            }
        }
        #endregion

this.close()を使わずに、System.Environment.Exit(0)を使用していることに注意してください。 MainFormを閉じてもアプリケーションはまだ実行されているからです。それを解決するためには、System.Environment.Exit(0)を使用する必要があります。なお、System.Environment.Exit(0)の代わりにApplication.Exit() でもOKですが、System.Environment.Exit(0)がおススメです。

 最後に残っているのは、アプリケションの拡張子をexeからscrにして、スクリーンセーバーとして利用するときには、Widnowsのsystem32フォルダにコピーしてください。


▼ページトップへ

コード全文

これで完成ですので、コードの全文を掲載しておきます。スクリーンセーバーのひな形として利用できます。
MainFormのClikイベントハンドラはMainForm_Clickに、KeyDownイベントハンドラはMainForm_KeyDown、MouseDownとMouseMoveはOnMouseMoveに割り当ててください。
なお、不要なusingディレクティブは削除してあります。

Program.cs
using System;
using System.Windows.Forms;

namespace MyscreenSaver
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //Mutexクラスの作成
            System.Threading.Mutex mutex 
                = new System.Threading.Mutex(false, Application.ProductName);

            //ミューテックスの所有権を要求する
            if (mutex.WaitOne(0, false) == false)
            {
                //すでに起動していると判断して終了
                return;
            }
            // GC.KeepAlive メソッドが呼び出されるまで、ガベージ コレクション対象から除外される
            GC.KeepAlive(mutex);
            // Mutex を閉じる
            mutex.Close();
            if (args.Length > 0)
            {
                if (args[0].ToLower().Trim().Substring(0, 2) == "/s") // 表示
                {
                    // スクリーンセーバーを実行
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver(); //
                    Application.Run();
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/p") // プレビュー
                {
                    // プレビュー画面を表示
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    //args[1] はプレビューウィンドウのハンドル
                    Application.Run(new MainForm(new IntPtr(long.Parse(args[1]))));
                }
                else if (args[0].ToLower().Trim().Substring(0, 2) == "/c") // 設定
                {
                    // スクリーンセーバーのオプション表示
                    MessageBox.Show("オプションなし"
                        + "\nこのスクリーンセーバーには、設定できるオプションはありません。",
                        "My Screen Saver",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                }
                else
                // 引数が渡されたが、それが /s, /p,/c 
                // でなかった場合
                {
                    // 常にスクリーンセーバーを表示
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    ShowScreenSaver();
                    Application.Run();
                }
            }
            else// 引数なしの場合
            {
                // 渡される引数がない場合、これはユーザーがファイルを右クリックして
                //「構成」を選んだときに発生します。通常はオプションフォームを表示します。
                // このプロジェクトでは設定フォームを準備していないため、
                // スクリーンセーバーを実行しています。
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                ShowScreenSaver(); //
                Application.Run();
            }
        }

        // スクリーンセーバーを表示
        static void ShowScreenSaver()
        {
            // コンピューター上のすべてのスクリーン(モニター)をループ
            foreach (Screen screen in Screen.AllScreens)
            {
                MainForm screensaver = new MainForm(screen.Bounds);
                screensaver.Show();
            }
        }
    }
}
MainForm.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MyscreenSaver
{
    public partial class MainForm : Form
    {
        #region Preview API's

        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

        #endregion

        bool IsPreviewMode = false;

        #region Constructors

        public MainForm()
        {
            InitializeComponent();
        }

        // このコンストラクタは、フォームを全画面で表示する
        // ノーマルモードで使用される
        public MainForm(Rectangle Bounds)
        {
            InitializeComponent();
            //フォームのバックカラーを黒に設定
            this.BackColor = Color.Black;
            //コントロールボックスを表示しないように
            //FormBorderStyleをNoneに設定
            this.FormBorderStyle = FormBorderStyle.None;
            this.Bounds = Bounds;
            //フォームを最前面に設定
            TopMost = true;
            // マウスカーソルを非表示にする
            Cursor.Hide();
        }

        // このコンストラクタは、スクリーンセーバーの選択ダイアログボックスの小窓で使用される。
        // プレビューモードで使用される (/p)
        public MainForm(IntPtr PreviewHandle)
        {
            InitializeComponent();

            // このウィンドの親ウィンドウにプレビューウィンドを設定
            SetParent(this.Handle, PreviewHandle);

            // この子ウィンドウをスクリーンセーバーの選択ダイアログボックスが閉じられたとき
            SetWindowLong(this.Handle, -16, new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));

            //ウィンドウサイズを親ウィンドウのサイズに設定する
            Rectangle ParentRect;
            GetClientRect(PreviewHandle, out ParentRect);
            this.Size = ParentRect.Size;

            // ロケーションを(0, 0)に設定
            this.Location = new Point(0, 0);

            IsPreviewMode = true;
        }

        #endregion

        #region User Input

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            System.Environment.Exit(0);

        }

        private void MainForm_Click(object sender, EventArgs e)
        {
            //** レビューを実行していないとき
            if (!IsPreviewMode) // プレビュー画面用に無効にする
            {
                System.Environment.Exit(0);
            }
        }

        // XとY int.MaxValueのとOriginalLoctionを始める
        // カーソルがその位置にすることは不可能なので。
        // この変数がまだ設定されている場合
        Point OriginalLocation = new Point(int.MaxValue, int.MaxValue);

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            //** プレビューを行っていない場合は、このif文を取り出す
            if (!IsPreviewMode) // プレビューのとき終了関数を無効にする
            {
                //originallocationが設定されているかどうかを確認
                if (OriginalLocation.X == int.MaxValue &
                    OriginalLocation.Y == int.MaxValue)
                {
                    OriginalLocation = e.Location;
                }
                // マウスが20 pixels 以上動いたかどうかを監視
                // 動いた場合はアプリケーションを終了
                if (Math.Abs(e.X - OriginalLocation.X) > 20 |
                    Math.Abs(e.Y - OriginalLocation.Y) > 20)
                {
                    System.Environment.Exit(0);
                }
            }
        }
        #endregion
    }
}
動作確認:WindowsXp Professional/Windows 7 64bit
必要なもの:.NET Framework 3.5

◆ダウンロード
ダウンロードmyscreensaver.zip(48KB)

画面のプロパティでは次のように表示されます。
ここでは、プレビュー画面がきちんと表示されることを示すために、Formのプロパティをあえて設定していません。
実際にスクリーンセーバーを作成するときには、最初にFormのプロパティでBackColorを黒、FormBorderStyleをNoneに設定します。
その場合は、public MainForm(Rectangle Bounds)にある次の行を削除します。

//フォームのバックカラーを黒に設定
this.BackColor = Color.Black;
//コントロールボックスを表示しないように
//FormBorderStyleをNoneに設定
this.FormBorderStyle = FormBorderStyle.None;

◆スクリーンセーバーのテストを行う方法

  1. [プロジェクト]メニューの[MyScreenSaverのプロパティ]をクリックします。
  2. [MyScreenSaverのプロパティ]ダイアログボックスで、[デバッグ]タブをクリックし、開始オプション-コマンドライン引数(N)に/sと入力し、F5キーを押します。
設定オプションをテストする場合は、上記の2で/cと入力し、F5キーを押します。
▼ページトップへ