首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ Builder 開發 Windows 螢幕保護程式完整實戰教學

     編輯:關於C++

Windows 螢幕保護程式本質是基於命令列參數的應用程式,副檔名為 .scr。系統依不同情境以特定參數啟動:/p(預覽)、/s(正常運行)、/c(設定對話框)、/a(密碼設定,NT 無效)。本文通過完整專案示範開發全功能螢幕保護程式,包含註冊表儲存設定、密碼驗證、預覽模式支援。

核心 API 函數速查

函數用途
GetWindowLong / SetWindowLong獲取/設定視窗長整數屬性(風格、擴展風格等)
SetParent變更視窗父子關係(預覽模式嵌入)
GetClientRect取得視窗客戶區矩形
SetWindowPos調整視窗大小、位置、Z-order
SystemParametersInfo查詢/設定系統參數(螢保運行狀態、動畫等)
ShowCursor顯示/隱藏滑鼠游標
GetVersion取得作業系統版本資訊

專案架構與表單設計

  • MainForm:全螢幕運行主視窗,BorderStyle=bsNone,黑色背景,含 TImage + TTimer。
  • FrmConfig:設定對話框(/c),含 TTrackBar 設定切圖頻率、SelectDirectory 選擇圖片資料夾,設定寫入註冊表 HKEY_CURRENT_USER\Software\CODEHUNTER。
  • FrmControl:預覽視窗(/p),固定 160×130,TImage.Stretch=true。

WinMain 入口點:命令列分發邏輯

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR p, int) {
    String StartType;
    AnsiString Command = p, temp;
    HWND CPWindow = NULL;

    if (Command == "") StartType = "/c"; // 無參數預設開啟設定
    else StartType = Command.SubString(1, 2);

    try {
        Application->Initialize();
        if (StartType == "/c") {
            Application->CreateForm(__classid(TFrmConfig), &FrmConfig);
        } else if (StartType == "/s") {
            Application->CreateForm(__classid(TFrmmain), &Frmmain);
        } else if (StartType == "/p") { // 預覽模式
            Application->CreateForm(__classid(TFrmControl), &FrmControl);
            temp = Command.SubString(3, Command.Length() - 2);
            CPWindow = (HWND)temp.ToInt(); // 取得預覽視窗 HWND

            // 將 FrmControl 設為子視窗並嵌入預覽區
            LONG style = GetWindowLong(Application->MainForm->Handle, GWL_STYLE);
            SetWindowLong(Application->MainForm->Handle, GWL_STYLE, style | WS_CHILD);
            SetParent(Application->MainForm->Handle, CPWindow);

            RECT lookrect;
            GetClientRect(CPWindow, &lookrect);
            SetWindowPos(Application->MainForm->Handle, HWND_TOP, 0, 0,
                         lookrect.right, lookrect.bottom,
                         SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
        } else if (StartType == "/a") { // 密碼設定
            temp = Command.SubString(3, Command.Length() - 2);
            CPWindow = (HWND)temp.ToInt();
            // 動態載入 mpr.dll 呼叫 PwdChangePasswordA
            typedef UINT (CALLBACK *FUN)(LPSTR, HWND, UINT, UINT);
            HINSTANCE hDll = LoadLibrary("mpr.DLL");
            if (hDll) {
                FUN myfun = (FUN)GetProcAddress(hDll, "PwdChangePasswordA");
                if (myfun) myfun("SCRSAVE", CPWindow, 0, 0);
                FreeLibrary(hDll);
            }
        }
        Application->Run();
    } catch (Exception &e) {
        Application->ShowException(&e);
    }
    return 0;
}

MainForm 關鍵實作

FormCreate:初始化與註冊表讀取

void __fastcall TFrmmain::FormCreate(TObject *Sender) {
    // 置頂、全螢幕覆蓋
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    Width = Screen->Width; Height = Screen->Height; Top = 0; Left = 0;

    Version = GetVersion();
    TRegistry *Reg = new TRegistry;
    try {
        if (Version > 0x80000000) { // Win9x
            Reg->RootKey = HKEY_CURRENT_USER;
            Reg->OpenKey("\\Control Panel\\Desktop", false);
            PWProtect = Reg->ReadInteger("ScreenSaveUsePassword");
            Reg->CloseKey();
        }
        Reg->RootKey = HKEY_CURRENT_USER;
        Reg->OpenKey("\\Software\\CODEHUNTER", true);
        picdir = Reg->ReadString("PicDir"); // 圖片目錄
        frequence = Reg->ReadInteger("frequence"); // 切換頻率(秒)
        if (picdir == "") picdir = "no";
        if (frequence < 0 || frequence > 6) frequence = 2;
        Timer1->Interval = 1000 * frequence;
    } __finally { delete Reg; picdir = "no"; }

    // 非 NT 且啟用密碼保護時,設定螢保運行狀態並隱藏游標
    if (Version != 0 && PWProtect && Version > 0x80000000)
        SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, 0, 0);
    while (!ShowCursor(false) < -5); // 徹底隱藏游標
}

事件處理:任意鍵盤/滑鼠動作結束螢保

void __fastcall TFrmmain::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { Close(); }
void __fastcall TFrmmain::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Close(); }
void __fastcall TFrmmain::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) {
    static int MouseMoves = 0;
    if (++MouseMoves > 4) { Close(); MouseMoves = 0; }
}

FormCloseQuery:密碼驗證

void __fastcall TFrmmain::FormCloseQuery(TObject *Sender, bool &CanClose) {
    if (PWProtect && Version > 0x80000000) {
        while (!ShowCursor(true) > 5); // 顯示游標
        typedef UINT (CALLBACK *FUN)(HWND);
        HINSTANCE hDll = LoadLibrary("password.cpl");
        bool PassChck = false;
        if (hDll) {
            FUN myfun = (FUN)GetProcAddress(hDll, "VerifyScreenSavePwd");
            if (myfun) PassChck = myfun(Handle);
            FreeLibrary(hDll);
        }
        if (!PassChck) {
            while (!ShowCursor(false) < -5); CanClose = false;
        }
    }
}

Timer 事件:隨機移動圖片

void __fastcall TFrmmain::Timer1Timer(TObject *Sender) {
    if (picdir == "no") {
        randomize();
        int i = (rand() % 2) ? 1 : -1;
        Image1->Top = i * (rand() % Height);
        Image1->Left = i * (rand() % Width);
    }
    // TODO: picdir != "no" 時讀取目錄下圖片輪播(留作練習)
}

建置與測試步驟

  1. 新建專案,加入三個表單並命名。
  2. 依上述設計配置元件與事件。
  3. 編譯產生 .exe,重命名為 .scr。
  4. 複製至 Windows 目錄(或 System32)。
  5. 在桌面右鍵 → 內容 → 螢幕保護程式中選擇測試。

留待讀者實作的擴充功能

程式碼中已實作 SelectDirectory 選擇圖片資料夾並寫入註冊表 PicDir。請自行完成:當 picdir != "no" 時,從該目錄讀取圖片檔(.bmp/.jpg),於 Timer 事件中輪流顯示,實現真正的相簿式螢幕保護程式。

本範例展示了螢幕保護程式的完整生命週期處理、預覽模式嵌入、密碼驗證、系統參數互動等核心技術,為開發專業級 .scr 程式奠定堅實基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved