共用方式為


處理螢幕儲存程式

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

  • 若要保護螢幕不受靜態影像所造成之靜止的消耗。
  • 隱藏螢幕上留下的敏感性資訊。

本主題分為下列各節。

關於螢幕儲存程式

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

選擇螢幕保護裝置後,Windows 會監視按鍵和滑鼠移動,然後在閒置期間後啟動畫面保護程式。 不過,如果下列任一條件存在,Windows 就不會啟動畫面保護程式:

  • 使用中應用程式不是以 Windows 為基礎的應用程式。
  • CBT) 視窗存在以電腦為基礎的訓練 (。
  • 使用中應用程式會接收WM_SYSCOMMAND訊息,並將wParam參數設定為SC_SCREENSAVE值,但不會將訊息傳遞至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 將游標設定為 Null 資料指標,並將其從畫面中移除。
WM_PAINT 繪製螢幕背景。
WM_LBUTTONDOWN 終止螢幕保護裝置程式。
WM_MBUTTONDOWN 終止螢幕保護裝置程式。
WM_RBUTTONDOWN 終止螢幕保護裝置程式。
WM_KEYDOWN 終止螢幕保護裝置程式。
WM_MOUSEMOVE 終止螢幕保護裝置程式。
WM_ACTI加值稅E 如果 wParam 參數設定為 FALSE,請終止螢幕保護裝置程式。

 

螢幕儲存模組中的第二個必要函式是 ScreenSaverConfigureDialog。 此函式會顯示一個對話方塊,可讓使用者在應用程式 (設定螢幕保護裝置程式,必須提供對應的對話方塊範本) 。 當使用者在主控台的 [螢幕儲存器] 對話方塊中選取 [設定] 按鈕時,Windows 會顯示組態對話方塊。

螢幕儲存模組中的第三個必要函式是 RegisterDialogClasses。 所有螢幕保護裝置應用程式都必須呼叫此函式。 不過,在組態對話方塊中不需要特殊視窗或自訂控制項的應用程式,只要傳回 TRUE即可。 需要特殊視窗或自訂控制項的應用程式應該使用此函式來註冊對應的視窗類別。

除了建立支援剛才描述之三個函式的模組之外,螢幕保護裝置程式也應該提供圖示。 只有當螢幕保護裝置程式以獨立應用程式的形式執行時,才會顯示此圖示。 (若要由主控台執行,螢幕保護裝置程式必須具有 .scr 副檔名;若要以獨立應用程式身分執行,它必須具有.exe副檔名。) 此圖示必須由常數ID_APP在螢幕儲存程式的資源檔中識別,此檔案定義于 Scrnsave.h 標頭檔中。

最後一個需求是螢幕保護裝置程式描述字串。 螢幕儲存程式的資源檔必須包含主控台顯示為螢幕保護裝置程式名稱的字串。 描述字串必須是資源檔字串資料表中的第一個字串, (以序數值 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 副檔名,並將其複製到正確的目錄。

將說明新增至螢幕保護裝置組態對話方塊

螢幕保護裝置程式的組態對話方塊通常包含 [ 說明 ] 按鈕。 螢幕保護裝置應用程式可以檢查 [說明] 按鈕識別碼,並以其他 Windows 型應用程式中提供的 [說明] 相同方式呼叫 WinHelp 函式。