スクリーン セーバーの処理
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 は 特定のメッセージのセットを処理し、未処理のメッセージを既定のプロシージャに渡します。 ただし、ScreenSaverProc は DefWindowProc 関数に渡す代わりに、未処理のメッセージを 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 関数を呼び出すことができます。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示