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

C++ Builder 應用程式禁止 Windows 螢幕保護程式啟動

     編輯:C++ 入門

前言

長時間運算、批次列印、影片播放、簡報模式等場景下,應用程式需**暫時阻止螢幕保護程式啟動**,避免系統進入閒置狀態導致畫面鎖定、網路中斷、硬碟休眠影響任務連續性。Windows 在啟動螢幕保護程式前,會向前景視窗所屬執行緒發送 WM_SYSCOMMAND、wParam = SC_SCREENSAVE 訊息。攔截此訊息並標記已處理,即可取消啟動。本文以 C++ Builder (VCL) 為例,示範透過 TApplication::OnMessage 事件攔截系統命令的完整實作。

一、核心原理

  • Windows 檢測到系統閒置超過螢幕保護等待時間。
  • 向當前作用中視窗的執行緒佇列發送 WM_SYSCOMMAND,wParam = SC_SCREENSAVE。
  • 視窗程式若在 OnMessage (或 WndProc) 中處理此訊息並將 Handled = true,系統**取消**螢幕保護啟動並重置閒置計時器。
  • 若未處理 (Handled = false),系統繼續預設流程啟動螢幕保護程式。

二、C++ Builder 完整實作

1. 表單標頭檔 (Unit1.h)


#ifndef Unit1H
#define Unit1H
#include 
#include 
#include 
#include 

class TForm1 : public TForm
{
__published:    // IDE 管理元件
private:        // 使用者宣告
    void __fastcall AppMessageHandler(tagMSG &Msg, bool &Handled);
public:         // 使用者宣告
    __fastcall TForm1(TComponent* Owner);
};
extern PACKAGE TForm1 *Form1;
#endif

2. 表單實作檔 (Unit1.cpp)


#include 
#pragma hdrstop
#include "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}

void __fastcall TForm1::AppMessageHandler(tagMSG &Msg, bool &Handled)
{
    // 攔截系統命令:螢幕保護啟動
    if (Msg.message == WM_SYSCOMMAND && Msg.wParam == SC_SCREENSAVE) {
        Handled = true;  // 標記已處理,取消螢幕保護啟動
        // 可選:記錄日誌、重置業務閒置計時器
    }
    else {
        Handled = false; // 交由預設訊息處理流程
    }
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    // 註冊應用程式層級訊息攔截器
    Application->OnMessage = AppMessageHandler;
}

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    // 釋放時解除註冊 (良好習慣)
    Application->OnMessage = nullptr;
}

三、關鍵結構體定義 (VCL 內部)


// tagMSG 對應 Windows MSG 結構
typedef struct tagMSG {
    HWND   hwnd;      // 視窗控制代碼
    UINT   message;   // 訊息代碼 (WM_SYSCOMMAND = 0x0112)
    WPARAM wParam;    // 參數 (SC_SCREENSAVE = 0xF140)
    LPARAM lParam;    // 參數
    DWORD  time;      // 訊息時間
    POINT  pt;        // 滑鼠座標
} MSG, *PMSG, *LPMSG;

// TMessageEvent 委派型別
typedef void __fastcall (__closure *TMessageEvent)(tagMSG &Msg, bool &Handled);
__property TMessageEvent OnMessage = {read=FOnMessage, write=FOnMessage};

四、替代方案對比

方法適用範圍優點缺點
Application->OnMessage 攔截 SC_SCREENSAVEVCL 應用程式全域集中管理、不需修改每個視窗、可動態啟用/停用僅對當前執行緒訊息佇列有效、需視窗焦點
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED)執行緒級、無視窗也有效現代 API、不依賴訊息迴圈、支援睡眠/顯示器分別控制需 Vista+/Win7+、需記得呼叫 SetThreadExecutionState(ES_CONTINUOUS) 還原
視窗 WndProc 處理 WM_SYSCOMMAND單一視窗精確控制特定視窗多視窗需重複、易遺漏
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, ...)全系統 (影響所有使用者)徹底關閉需管理員權限、影響範圍過大、不建議應用程式使用

現代化推薦:SetThreadExecutionState


#include 

// 啟動長時間任務前
void DisableSleepAndScreenSaver() {
    // ES_CONTINUOUS: 通知系統此狀態持續有效,直到明確撤銷
    // ES_DISPLAY_REQUIRED: 強制顯示器保持開啟
    // ES_SYSTEM_REQUIRED: 強制系統保持運作 (防止睡眠)
    SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED);
}

// 任務結束後
void RestorePowerPolicy() {
    SetThreadExecutionState(ES_CONTINUOUS); // 撤銷先前設定,還原系統電源管理
}

優勢: 不需視窗焦點、主控台應用程式/服務亦可用、官方推薦 API、細粒度控制 (僅阻擋睡眠/或僅阻擋螢幕關閉)。

五、測試驗證步驟

  1. 將 Windows 螢幕保護程式等待時間設為 **1 分鐘** (控制台 → 個人化 → 螢幕保護程式)。
  2. 編譯執行應用程式,保持視窗焦點。
  3. 等待超過 1 分鐘,**螢幕保護程式不應啟動**。
  4. 關閉應用程式,再等待 1 分鐘,**螢幕保護程式應正常啟動**。
  5. 若使用 SetThreadExecutionState,測試無視窗主控台程式同樣有效。

六、常見問題與除錯

現象可能原因解決
螢幕保護仍啟動訊息未送達前景執行緒、應用程式非前景、Handled 未設 true確認 Application->OnMessage 已註冊、視窗有焦點、Msg.wParam == SC_SCREENSAVE 比對正確
系統進入睡眠僅阻擋螢幕保護,未阻擋睡眠改用 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)
多執行緒應用程式失效OnMessage 僅攔截主執行緒訊息佇列改用 SetThreadExecutionState (執行緒級) 或各執行緒各自攔截
關閉程式後螢幕保護異常未還原 SetThreadExecutionState確保 FormDestroy 或 atexit 呼叫還原函式

結語

阻止螢幕保護程式啟動是長時間任務應用程式的基本禮貌。C++ Builder 透過 TApplication::OnMessage 攔截 WM_SYSCOMMAND/SC_SCREENSAVE 為經典 VCL 做法;現代開發**強烈建議改用 SetThreadExecutionState**,跨平台 (Win32/Win64)、無視窗依賴、官方維護、粒度更細。兩種方案皆需注意**成對啟用/還原**,避免永久干擾系統電源管理。選擇適合專案架構的方案,並納入自動化測試驗證,確保使用者體驗不受干擾。

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