共用方式為


處理螢幕保護程式

Microsoft Win32 API 支援 螢幕保護程式的特殊應用程式。 屏幕保護程式會在滑鼠和鍵盤閑置一段時間後啟動。 它們用於下列兩個原因:

  • 保護螢幕免受靜態圖像引起的磷燃燒。
  • 隱藏螢幕上留下的敏感性資訊。

本主題分為下列各節。

關於屏幕保護程式

Windows 控制面板中的桌面應用程式可讓使用者從螢幕儲存程式清單中選取、指定螢幕儲存程式開始之前應該經過多少時間、設定螢幕儲存程式,以及預覽螢幕儲存程式。 Windows 啟動時或使用者透過控制面板啟動螢幕保護程式時,螢幕儲存程式會自動載入。

選擇螢幕保護程序之後,Windows 會監視擊鍵和滑鼠移動,然後在一段閑置期間後啟動螢幕保護程式。 不過,如果下列任何一個條件存在,Windows 就不會啟動螢幕保護程式:

  • 使用中應用程式不是以 Windows 為基礎的應用程式。
  • 電腦輔助訓練 (CBT) 視窗已開啟。
  • 使用中應用程式會接收具有設定為 SC_SCREENSAVE 值的 wParam 參數的 WM_SYSCOMMAND 訊息,但不會將訊息傳遞至 DefWindowProc 函式。

螢幕保護程式的安全性內容

屏幕保護程式的安全性內容取決於使用者是否以互動方式登入。 如果使用者在互動式登入時叫用螢幕保護程式,螢幕保護程式會在互動式使用者的安全性上下文中執行。 如果未登入任何使用者,螢幕保護程式的安全性內容會相依於所使用的 Windows 版本。

  • Windows XP 和 Windows 2000 - 螢幕保護程式會在 LocalSystem 的內容中執行,且帳戶受到限制。
  • Windows 2003 - 螢幕保護程式會在 LocalService 的內容中執行,其中已移除所有許可權,且系統管理員群組已停用。
  • 不適用於 Windows NT4。

安全性環境會決定可從螢幕保護程式完成的特殊作業權限等級。

Windows Vista 和更新版本: 如果依政策啟用密碼保護功能,無論應用程式如何處理 SC_SCREENSAVE 通知,螢幕保護程式都會啟動。

屏幕保護程式包含特定的導出函式、資源定義和變數宣告。 螢幕保護程式函式庫包含 函式,以及螢幕保護程式所需的其他啟動程式碼。 當螢幕保護程式啟動時,螢幕儲存程式連結庫中的啟動程式代碼會建立全螢幕視窗。 這個視窗的視窗類別宣告如下:

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;

若要建立螢幕保護程式,大部分開發人員都會建立包含三個必要函式的原始程式碼模組,並將它們與螢幕保護連結庫連結。 屏幕保護模組只負責設定本身和提供視覺效果。

螢幕保護模組中三個必要函式之一是 screenSaverProc 。 此函式會處理特定訊息,並將任何未處理的訊息傳回螢幕保護連結庫。 以下是 ScreenSaverProc所處理的一些一般訊息。

訊息 意義
WM_CREATE 從 Regedit.ini 檔案擷取任何初始化數據。 設定螢幕保護視窗的視窗定時器。 執行任何其他必要的初始化。
WM_ERASEBKGND 清除螢幕保護程序視窗,並準備進行後續的繪圖作業。
WM_TIMER 執行繪圖作業。
WM_DESTROY 終結應用程式處理 WM_CREATE 訊息時所建立的定時器。 執行任何其他必要的清理。

 

ScreenSaverProc 藉由呼叫 DefScreenSaverProc 函式,將未處理的訊息傳遞至螢幕保護連結庫。 下表描述此函式如何處理各種訊息。

消息 行動
WM_SETCURSOR 將游標設定為空游標,並從畫面中移除它。
WM_PAINT 繪製螢幕背景。
WM_LBUTTONDOWN 終止螢幕保護程式。
WM_MBUTTONDOWN 終止螢幕保護程式。
WM_RBUTTONDOWN 終止螢幕保護程式。
WM_KEYDOWN 終止螢幕保護程式。
WM_MOUSEMOVE 終止螢幕保護程式。
WM_ACTIVATE 如果 wParam 參數設定為 FALSE,請終止螢幕保護程式。

 

螢幕保護模組中的第二個必要函式是 ScreenSaverConfigureDialog。 此函式會顯示對話框,讓用戶能夠設定螢幕保護程式(應用程式必須提供對應的對話框範本)。 當使用者在 [控制面板的螢幕儲存程式] 對話框中選取 [安裝程式] 按鈕時,Windows 會顯示組態對話框。

螢幕保護模組中的第三個必要函式是 RegisterDialogClasses。 所有螢幕保護應用程式都必須呼叫此函式。 不過,在組態對話框中不需要特殊視窗或自定義控件的應用程式,只需傳回 TRUE 。 需要特殊視窗或自定義控件的應用程式應該使用此函式來註冊對應的窗口類別。

除了建立支援剛才描述之三個函式的模組之外,屏幕保護程式也應該提供圖示。 只有當螢幕保護程式以獨立應用程式的形式執行時,才會顯示此圖示。 (若要由控制面板執行,螢幕保護程式必須具有 .scr 擴展名;若要以獨立應用程式的形式執行,它必須具有 .exe 擴展名。圖示必須由 scrnsave.h 頭檔中定義的常數ID_APP在螢幕儲存器的資源文件中識別。

最後一個需求是螢幕保護程式描述字串。 螢幕保護工具的資源檔案必須包含 [控制面板] 顯示為螢幕儲存程式名稱的字串。 描述字串必須是資源檔案字串數據表中的第一個字串(以序數值 1 識別)。 不過,如果螢幕保護程式有長檔名,控制面板就會忽略描述字串。 在這種情況下,檔名會當做描述字串使用。

使用螢幕保護功能

本節使用從螢幕保護程序應用程式擷取的範例程式代碼來說明下列工作:

建立屏幕保護程式

在介於 1 到 10 秒的間隔下,本範例中的應用程式會以四種色彩之一重繪螢幕:白色、淺灰色、深灰色和黑色。 應用程式會在每次收到 WM_TIMER 訊息時繪製畫面。 用戶可以選取應用程式的組態對話框並調整單一水準滾動條,來調整傳送此訊息的間隔。

螢幕保護程式庫

靜態螢幕保護函式包含在螢幕保護連結庫中。 有兩個版本的程式庫可用,Scrnsave.lib 和 Scrnsavw.lib。 您必須將項目連結至其中之一。 Scrnsave.lib 用於使用 ANSI 字元的螢幕保護程式,而 Scrnsavw.lib 則用於使用 Unicode 字元的螢幕儲存器。 與 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

您必須使用十進位值 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 會將未處理的訊息傳遞至 DefScreenSaverProc 函式,而不是將它們傳遞至 DefWindowProc 函式。 ScreenSaverProc 和一般視窗程式之間的另一個差異是,傳遞至 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); 
}

建立模組定義檔案

ScreenSaverProcScreenSaverConfigureDialog 函式必須在應用程式的模組定義檔案中匯出;不過,不應該導出 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 擴展名,並將其複製到正確的目錄。

將說明新增至螢幕保護程式設定對話框

螢幕保護程式的設定對話框通常包含 [說明] 按鈕。 屏幕保護程式應用程式可以檢查 [說明] 按鈕標識符,並呼叫 WinHelp 函式,就像其他 Windows 應用程式所提供的說明一樣。