次の方法で共有


スクリーン セーバーの処理

Microsoft Win32 API では、 スクリーン セーバーと呼ばれる特別なアプリケーションがサポートされています。 スクリーン セーバーは、指定した期間マウスとキーボードがアイドル状態になったときに起動します。 これらは、次の 2 つの理由で使用されます。

  • 静的なイメージによって引き起こされる蛍光体の火傷からスクリーンを保護するため。
  • 画面上に残された機密情報を隠すために。

このトピックは次のセクションに分割されます。

スクリーン セーバーについて

Windows コントロール パネル のデスクトップ アプリケーションを使用すると、ユーザーはスクリーン セーバーの一覧から選択し、スクリーン セーバーが開始されるまでの経過時間を指定したり、スクリーン セーバーを構成したり、スクリーン セーバーをプレビューしたりできます。 スクリーン セーバーは、Windows の起動時、またはユーザーがコントロール パネルを介してスクリーン セーバーをアクティブ化したときに自動的に読み込まれます。

スクリーン セーバーを選択すると、Windows はキーストロークとマウスの動きを監視し、一定の非アクティブ状態の後にスクリーン セーバーを開始します。 ただし、次のいずれかの条件が存在する場合、Windows はスクリーン セーバーを起動しません。

  • アクティブなアプリケーションは Windows ベースのアプリケーションではありません。
  • コンピューター ベースのトレーニング (CBT) ウィンドウが存在します。
  • アクティブなアプリケーションは、wParam パラメーターが SC_SCREENSAVE 値に設定されたWM_SYSCOMMAND メッセージを受信しますが、DefWindowProc 関数にメッセージを渡しません。

スクリーン セーバーのセキュリティ コンテキスト

スクリーン セーバーのセキュリティ コンテキストは、ユーザーが対話形式でログオンしているかどうかによって異なります。 スクリーン セーバーが呼び出されたときにユーザーが対話的にログオンした場合、スクリーン セーバーは対話型ユーザーのセキュリティ コンテキストで実行されます。 ログオンしているユーザーがいない場合、スクリーン セーバーのセキュリティ コンテキストは、使用されている Windows のバージョンによって異なります。

  • Windows XP と Windows 2000 - アカウントが制限された LocalSystem のコンテキストでスクリーン セーバーが実行されます。
  • Windows 2003 - スクリーン セーバーは LocalService のコンテキストで実行され、すべての特権が削除され、管理者グループが無効になります。
  • Windows NT4 には適用されません。

セキュリティ コンテキストは、スクリーン セーバーから実行できる特権操作のレベルを決定します。

Windows Vista 以降: ポリシーによってパスワード保護が有効になっている場合、アプリケーションがSC_SCREENSAVE通知で何を行うかに関係なく、スクリーン セーバーが開始されます。

スクリーン セーバーには、エクスポートされた特定の関数、リソース定義、および変数宣言が含まれます。 スクリーン セーバー ライブラリには、スクリーン セーバーに必要なメイン関数とその他のスタートアップ コードが含まれています。 スクリーン セーバーが起動すると、スクリーン セーバー ライブラリのスタートアップ コードによって全画面表示ウィンドウが作成されます。 このウィンドウの window クラスは、次のように宣言されます。

WNDCLASS cls; 
cls.hCursor        = NULL; 
cls.hIcon          = LoadIcon(hInst, MAKEINTATOM(ID_APP)); 
cls.lpszMenuName   = NULL; 
cls.lpszClassName  = "WindowsScreenSaverClass"; 
cls.hbrBackground  = GetStockObject(BLACK_BRUSH); 
cls.hInstance      = hInst; 
cls.style          = CS_VREDRAW  | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS; 
cls.lpfnWndProc    = (WNDPROC) ScreenSaverProc; 
cls.cbWndExtra     = 0; 
cls.cbClsExtra     = 0;

スクリーン セーバーを作成するために、ほとんどの開発者は、必要な 3 つの関数を含むソース コード モジュールを作成し、スクリーン セーバー ライブラリにリンクします。 スクリーン セーバー モジュールは、それ自体の構成と視覚効果の提供のみを担当します。

スクリーン セーバー モジュールで必要な 3 つの関数の 1 つは 、ScreenSaverProc です。 この関数は、特定のメッセージを処理し、未処理のメッセージをスクリーン セーバー ライブラリに戻します。 ScreenSaverProc によって処理される一般的なメッセージの一部を次に示します。

メッセージ 意味
Wm_create Regedit.ini ファイルから初期化データを取得します。 スクリーン セーバー ウィンドウのウィンドウ タイマーを設定します。 その他の必要な初期化を実行します。
WM_ERASEBKGND スクリーン セーバー ウィンドウを消去し、後続の描画操作に備えます。
Wm_timer 描画操作を実行します。
WM_DESTROY アプリケーションが WM_CREATE メッセージを処理したときに作成されたタイマーを破棄します。 追加の必要なクリーンアップを実行します。

 

ScreenSaverProc、DefScreenSaverProc 関数を呼び出して、未処理のメッセージをスクリーン セーバー ライブラリに渡します。 次の表では、この関数がさまざまなメッセージを処理する方法について説明します。

メッセージ アクション
WM_SETCURSOR カーソルを null カーソルに設定し、画面から削除します。
Wm_paint 画面の背景を塗りつぶします。
WM_LBUTTONDOWN スクリーン セーバーを終了します。
WM_MBUTTONDOWN スクリーン セーバーを終了します。
WM_RBUTTONDOWN スクリーン セーバーを終了します。
Wm_keydown スクリーン セーバーを終了します。
Wm_mousemove スクリーン セーバーを終了します。
WM_ACTIVATE wParam パラメーターが FALSE に設定されている場合は、スクリーン セーバーを終了します

 

スクリーン セーバー モジュールで 2 番目に必要な関数は 、ScreenSaverConfigureDialog です。 この関数は、ユーザーがスクリーン セーバーを構成できるようにするダイアログ ボックスを表示します (アプリケーションは、対応するダイアログ ボックス テンプレートを提供する必要があります)。 Windows では、ユーザーがコントロール パネルの [スクリーン セーバー] ダイアログ ボックスで [セットアップ] ボタンを選択すると、構成ダイアログ ボックスが表示されます。

スクリーン セーバー モジュールで 3 番目に必要な関数は RegisterDialogClasses です。 この関数は、すべてのスクリーン セーバー アプリケーションによって呼び出される必要があります。 ただし、構成ダイアログ ボックスで特別なウィンドウやカスタム コントロールを必要としないアプリケーションは、 単に TRUE を返すことができます。 特別なウィンドウまたはカスタム コントロールを必要とするアプリケーションでは、この関数を使用して、対応するウィンドウ クラスを登録する必要があります。

前述の 3 つの関数をサポートするモジュールを作成するだけでなく、スクリーン セーバーにはアイコンを指定する必要があります。 このアイコンは、スクリーン セーバーがスタンドアロン アプリケーションとして実行されている場合にのみ表示されます。 (コントロール パネルで実行するには、スクリーン セーバーに .scr ファイル名拡張子が必要です。スタンドアロン アプリケーションとして実行するには、.exeファイル名拡張子が必要です)。アイコンは、スクリーン セーバーのリソース ファイルで、Scrnsave.h ヘッダー ファイルで定義されている定数ID_APPで識別する必要があります。

最終的な要件の 1 つは、スクリーン セーバーの説明文字列です。 スクリーン セーバーのリソース ファイルには、コントロール パネルがスクリーン セーバー名として表示する文字列を含める必要があります。 説明文字列は、リソース ファイルの文字列テーブルの最初の文字列である必要があります (序数値 1 で識別されます)。 ただし、スクリーン セーバーに長いファイル名がある場合、説明文字列はコントロール パネルによって無視されます。 このような場合は、ファイル名が説明文字列として使用されます。

スクリーン セーバー関数の使用

このセクションでは、スクリーン セーバー アプリケーションから取得したコード例を使用して、次のタスクを示します。

スクリーン セーバーの作成

この例のアプリケーションでは、1 から 10 秒の間隔で、白、薄い灰色、濃い灰色、黒の 4 色のいずれかで画面を再描画します。 アプリケーションは、 WM_TIMER メッセージを受信するたびに画面を描画します。 ユーザーは、アプリケーションの構成ダイアログ ボックスを選択し、1 つの水平スクロール バーを調整することで、このメッセージの送信間隔を調整できます。

スクリーン セーバー ライブラリ

静的スクリーン セーバー関数は、スクリーン セーバー ライブラリに含まれています。 使用可能なライブラリには、Scrnsave.lib と Scrnsavw.lib の 2 つのバージョンがあります。 プロジェクトを次のいずれかにリンクする必要があります。 Scrnsave.lib は ANSI 文字を使用するスクリーン セーバーに使用され、Unicode 文字を使用するスクリーン セーバーには Scrnsavw.lib が使用されます。 Scrnsavw.lib にリンクされているスクリーン セーバーは、Unicode をサポートする Windows プラットフォームでのみ実行され、Scrnsave.lib にリンクされたスクリーン セーバーは任意の Windows プラットフォームで実行されます。

構成ダイアログ ボックスのサポート

ほとんどのスクリーン セーバーには、一意の色、描画速度、線の太さ、フォントなどのカスタマイズ データをユーザーが指定するための構成ダイアログ ボックスが用意されています。 構成ダイアログ ボックスをサポートするには、アプリケーションでダイアログ ボックス テンプレートを提供し、 ScreenSaverConfigureDialog 関数もサポートする必要があります。 サンプル アプリケーションのダイアログ ボックス テンプレートを次に示します。

DLG_SCRNSAVECONFIGURE DIALOG 6, 18, 160, 63
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Sample Screen-Saver Setup"
FONT 8, "MS Shell Dlg"
BEGIN
    GROUPBOX      "Redraw Speed", 101, 0, 6, 98, 40
    SCROLLBAR     ID_SPEED, 5, 31, 89, 10
    LTEXT         "Fast", 103, 6, 21, 20, 8
    LTEXT         "Slow", 104, 75, 21, 20, 8
    PUSHBUTTON    "OK", ID_OK, 117, 10, 40, 14
    PUSHBUTTON    "Cancel", ID_CANCEL, 117, 32, 40, 14
END

次の例のように、10 進値 2003 を使用してダイアログ ボックス テンプレートを識別するために使用する定数を定義する必要があります。

#define  DLG_SCRNSAVECONFIGURE 2003

次の例は、サンプル アプリケーションで 見つかった ScreenSaverConfigureDialog 関数を示しています。

#define MINVEL  1                 // minimum redraw speed value     
#define MAXVEL  10                // maximum redraw speed value    
#define DEFVEL  5                 // default redraw speed value    
 
LONG    lSpeed = DEFVEL;          // redraw speed variable         
  
extern HINSTANCE hMainInstance;   // screen saver instance handle  
 
CHAR   szAppName[80];             // .ini section name             
CHAR   szTemp[20];                // temporary array of characters  
CHAR   szRedrawSpeed[ ] = "Redraw Speed";   // .ini speed entry 
CHAR   szIniFile[MAXFILELEN];     // .ini or registry file name  
 
BOOL WINAPI ScreenSaverConfigureDialog(hDlg, message, wParam, lParam) 
HWND     hDlg; 
UINT     message; 
DWORD    wParam; 
LONG     lParam; 
HRESULT  hr;
{ 
    static HWND hSpeed;   // handle to speed scroll bar 
    static HWND hOK;      // handle to OK push button  
 
    switch(message) 
    { 
        case WM_INITDIALOG: 
 
            // Retrieve the application name from the .rc file.  
            LoadString(hMainInstance, idsAppName, szAppName, 
                       80 * sizeof(TCHAR)); 
 
            // Retrieve the .ini (or registry) file name. 
            LoadString(hMainInstance, idsIniFile, szIniFile, 
                       MAXFILELEN * sizeof(TCHAR)); 
 
            // TODO: Add error checking to verify LoadString success
            //       for both calls.
            
            // Retrieve any redraw speed data from the registry. 
            lSpeed = GetPrivateProfileInt(szAppName, szRedrawSpeed, 
                                          DEFVEL, szIniFile); 
 
            // If the initialization file does not contain an entry 
            // for this screen saver, use the default value. 
            if(lSpeed > MAXVEL || lSpeed < MINVEL) 
                lSpeed = DEFVEL; 
 
            // Initialize the redraw speed scroll bar control.
            hSpeed = GetDlgItem(hDlg, ID_SPEED); 
            SetScrollRange(hSpeed, SB_CTL, MINVEL, MAXVEL, FALSE); 
            SetScrollPos(hSpeed, SB_CTL, lSpeed, TRUE); 
 
            // Retrieve a handle to the OK push button control.  
            hOK = GetDlgItem(hDlg, ID_OK); 
 
            return TRUE; 
 
        case WM_HSCROLL: 

            // Process scroll bar input, adjusting the lSpeed 
            // value as appropriate. 
            switch (LOWORD(wParam)) 
                { 
                    case SB_PAGEUP: 
                        --lSpeed; 
                    break; 
 
                    case SB_LINEUP: 
                        --lSpeed; 
                    break; 
 
                    case SB_PAGEDOWN: 
                        ++lSpeed; 
                    break; 
 
                    case SB_LINEDOWN: 
                        ++lSpeed; 
                    break; 
 
                    case SB_THUMBPOSITION: 
                        lSpeed = HIWORD(wParam); 
                    break; 
 
                    case SB_BOTTOM: 
                        lSpeed = MINVEL; 
                    break; 
 
                    case SB_TOP: 
                        lSpeed = MAXVEL; 
                    break; 
 
                    case SB_THUMBTRACK: 
                    case SB_ENDSCROLL: 
                        return TRUE; 
                    break; 
                } 

                if ((int) lSpeed <= MINVEL) 
                    lSpeed = MINVEL; 
                if ((int) lSpeed >= MAXVEL) 
                    lSpeed = MAXVEL; 
 
                SetScrollPos((HWND) lParam, SB_CTL, lSpeed, TRUE); 
            break; 
 
        case WM_COMMAND: 
            switch(LOWORD(wParam)) 
            { 
                case ID_OK: 
 
                    // Write the current redraw speed variable to
                    // the .ini file. 
                    hr = StringCchPrintf(szTemp, 20, "%ld", lSpeed);
                    if (SUCCEEDED(hr))
                        WritePrivateProfileString(szAppName, szRedrawSpeed, 
                                                  szTemp, szIniFile); 
 
                case ID_CANCEL: 
                    EndDialog(hDlg, LOWORD(wParam) == ID_OK); 

                return TRUE; 
            } 
    } 
    return FALSE; 
}

ダイアログ ボックス テンプレートを提供し、 ScreenSaverConfigureDialog 関数をサポートするだけでなく、アプリケーションで RegisterDialogClasses 関数もサポートする必要があります。 この関数は、スクリーン セーバーに必要な標準以外のウィンドウ クラスを登録します。 サンプル アプリケーションではダイアログ ボックス プロシージャで標準ウィンドウ クラスのみが使用されているため、次の例のように、この関数は 単に TRUE を返します。

BOOL WINAPI RegisterDialogClasses(hInst) 
HANDLE  hInst; 
{ 
    return TRUE; 
}

スクリーン セーバー ウィンドウの手順のサポート

各スクリーン セーバーは 、ScreenSaverProc という名前のウィンドウ プロシージャをサポートする必要があります。 ほとんどのウィンドウ プロシージャと同様に、 ScreenSaverProc は 特定のメッセージのセットを処理し、未処理のメッセージを既定のプロシージャに渡します。 ただし、ScreenSaverProcDefWindowProc 関数に渡す代わりに、未処理のメッセージを DefScreenSaverProc 関数に渡します。 ScreenSaverProc と通常のウィンドウ プロシージャのもう 1 つの違いは、ScreenSaverProc に渡されるハンドルによって、クライアント ウィンドウではなくデスクトップ全体が識別される点です。 次の例は、サンプルスクリーンセーバーの ScreenSaverProc ウィンドウ プロシージャを示しています。

LONG WINAPI ScreenSaverProc(hwnd, message, wParam, lParam) 
HWND  hwnd; 
UINT  message; 
DWORD wParam; 
LONG  lParam; 
{ 
    static HDC          hdc;      // device-context handle  
    static RECT         rc;       // RECT structure  
    static UINT         uTimer;   // timer identifier  
 
    switch(message) 
    { 
        case WM_CREATE: 
 
            // Retrieve the application name from the .rc file. 
            LoadString(hMainInstance, idsAppName, szAppName, 80 * sizeof(TCHAR)); 
 
            // Retrieve the .ini (or registry) file name. 
            LoadString(hMainInstance, idsIniFile, szIniFile, MAXFILELEN * sizeof(TCHAR)); 
 
            // TODO: Add error checking to verify LoadString success
            //       for both calls.
            
            // Retrieve any redraw speed data from the registry.  
            lSpeed = GetPrivateProfileInt(szAppName, szRedrawSpeed, 
                                          DEFVEL, szIniFile); 
 
            // Set a timer for the screen saver window using the 
            // redraw rate stored in Regedit.ini. 
            uTimer = SetTimer(hwnd, 1, lSpeed * 1000, NULL); 
            break; 
 
        case WM_ERASEBKGND: 
 
            // The WM_ERASEBKGND message is issued before the 
            // WM_TIMER message, allowing the screen saver to 
            // paint the background as appropriate. 

            hdc = GetDC(hwnd); 
            GetClientRect (hwnd, &rc); 
            FillRect (hdc, &rc, GetStockObject(BLACK_BRUSH)); 
            ReleaseDC(hwnd,hdc); 
            break; 
 
        case WM_TIMER: 
 
            // The WM_TIMER message is issued at (lSpeed * 1000) 
            // intervals, where lSpeed == .001 seconds. This 
            // code repaints the entire desktop with a white, 
            // light gray, dark gray, or black brush each 
            // time a WM_TIMER message is issued. 

            hdc = GetDC(hwnd); 
            GetClientRect(hwnd, &rc); 
            if (i++ <= 4) 
                FillRect(hdc, &rc, GetStockObject(i)); 
            else 
                (i = 0); 
            ReleaseDC(hwnd,hdc); 
            break; 
 
        case WM_DESTROY: 
 
            // When the WM_DESTROY message is issued, the screen saver 
            // must destroy any of the timers that were set at WM_CREATE 
            // time. 

            if (uTimer) 
                KillTimer(hwnd, uTimer); 
            break; 
    } 
 
    // DefScreenSaverProc processes any messages ignored by ScreenSaverProc. 
    return DefScreenSaverProc(hwnd, message, wParam, lParam); 
}

モジュール定義ファイルの作成

ScreenSaverProc 関数と ScreenSaverConfigureDialog 関数は、アプリケーションのモジュール定義ファイルにエクスポートする必要があります。ただし、RegisterDialogClasses はエクスポートしないでください。 次の例は、サンプル アプリケーションのモジュール定義ファイルを示しています。

NAME    SSTEST.SCR 

DESCRIPTION 'SCRNSAVE : Test' 
 
STUB    'WINSTUB.EXE' 
EXETYPE WINDOWS 
 
CODE    MOVEABLE 
DATA    MOVEABLE MULTIPLE 
 
HEAPSIZE  1024 
STACKSIZE 4096 
 
EXPORTS 
        ScreenSaverProc 
        ScreenSaverConfigureDialog

新しいスクリーン セーバーのインストール

使用可能なスクリーン セーバーの一覧をコンパイルすると、コントロール パネルは Windows スタートアップ ディレクトリで .scr 拡張子を持つファイルを検索します。 スクリーン セーバーは、.exe拡張子を持つ標準の Windows 実行可能ファイルであるため、拡張子が .scr になるように名前を変更し、正しいディレクトリにコピーする必要があります。

[スクリーン セーバーの構成] ダイアログ ボックスへのヘルプの追加

スクリーン セーバーの構成ダイアログ ボックスには、通常、[ ヘルプ ] ボタンが含まれます。 スクリーン セーバー アプリケーションでは、ヘルプ ボタン識別子をチェックし、他の Windows ベースのアプリケーションでヘルプが提供されるのと同じ方法で WinHelp 関数を呼び出すことができます。