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

C++ Builder 使用 IActiveDesktop 介面設定桌面壁紙:支援 JPG/PNG/HTML 完整範例

     編輯:關於C++

前言:SystemParametersInfo 的限制與 IActiveDesktop 的優勢

傳統 SystemParametersInfo(SPI_SETDESKWALLPAPER, ...) 僅支援 BMP 格式,需自行轉檔。Windows 98/2000 引入 Active Desktop 技術,提供 IActiveDesktop COM 介面,原生支援 **JPG、PNG、GIF、HTML** 等格式直接設為壁紙,並可啟用/停用 Active Desktop、設定壁紙樣式 (置中、平鋪、拉伸)。本文提供完整 C++ Builder 實作。

必要環境與標頭檔

  • C++ Builder 5/6/2007/10.x+
  • #define NO_WIN32_LEAN_AND_MEAN (在專案最早 include 前,避免 windows.h 衝突)
  • #include (包含 IActiveDesktop, CLSID_ActiveDesktop, IID_IActiveDesktop 定義)
  • 連結 oleaut32.lib, uuid.lib (BCB 專案通常自動處理)

完整設定壁紙函式


#include 
#include  // _bstr_t, _com_error
#include  // OleCheck

// 設定桌面壁紙 (支援 JPG, PNG, GIF, BMP, HTML)
// wallpaperPath: 完整檔案路徑 (本機或 UNC 網路路徑)
// style: WPSTYLE_CENTER (0), WPSTYLE_TILE (1), WPSTYLE_STRETCH (2), WPSTYLE_FIT (3), WPSTYLE_FILL (4) - Vista+
// 回傳: true 成功, false 失敗 (可用 GetLastError 或 _com_error 取得細節)
bool SetWallpaperEx(const wchar_t* wallpaperPath, DWORD style = WPSTYLE_STRETCH) {
  // 1. 初始化 COM 單元執行緒 (STA)
  HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  if (FAILED(hr)) return false; // 已初始化則傳回 S_FALSE 視為成功

  IActiveDesktop* pActiveDesktop = NULL;
  bool success = false;

  try {
    // 2. 建立 Active Desktop 物件
    hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
                          IID_IActiveDesktop, (void**)&pActiveDesktop);
    if (FAILED(hr)) throw _com_error(hr);

    // 3. 設定壁紙路徑 (需 BSTR / WideString)
    _bstr_t bstrPath(wallpaperPath); // 自動管理 BSTR 生命週期
    hr = pActiveDesktop->SetWallpaper(bstrPath, 0); // 0 = 保留未來旗標
    if (FAILED(hr)) throw _com_error(hr);

    // 4. 設定壁紙樣式 (選用,需先取得選項再修改)
    WALLPAPEROPT wpo = { sizeof(WALLPAPEROPT) };
    hr = pActiveDesktop->GetWallpaperOptions(&wpo, 0);
    if (SUCCEEDED(hr)) {
      wpo.dwStyle = style; // WPSTYLE_*
      hr = pActiveDesktop->SetWallpaperOptions(&wpo, 0);
      if (FAILED(hr)) throw _com_error(hr);
    }

    // 5. 套用變更 (關鍵步驟!)
    hr = pActiveDesktop->ApplyChanges(AD_APPLY_ALL); // AD_APPLY_SAVE | AD_APPLY_HTMLGEN | AD_APPLY_REFRESH | AD_APPLY_ALL
    if (FAILED(hr)) throw _com_error(hr);

    success = true;
  }
  catch (const _com_error& e) {
    // 可記錄 e.Error(), e.ErrorMessage(), e.Description()
    success = false;
  }

  // 6. 釋放介面與反初始化 COM
  if (pActiveDesktop) pActiveDesktop->Release();
  CoUninitialize();

  return success;
}

C++ Builder VCL 專案整合範例


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

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

void __fastcall TForm1::BtnSetWallpaperClick(TObject *Sender) {
  // 開啟檔案對話框選擇圖片
  TOpenDialog* dlg = new TOpenDialog(this);
  dlg->Filter = "圖片檔案 (*.jpg;*.jpeg;*.png;*.bmp;*.gif)|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有檔案 (*.*)|*.*";
  dlg->Options << ofFileMustExist << ofPathMustExist;
  if (!dlg->Execute()) { delete dlg; return; }

  AnsiString file = dlg->FileName;
  delete dlg;

  // 對應 ComboBox 選擇的樣式
  DWORD style = WPSTYLE_STRETCH; // 預設拉伸
  switch (ComboBoxStyle->ItemIndex) {
    case 0: style = WPSTYLE_CENTER; break;   // 置中
    case 1: style = WPSTYLE_TILE; break;     // 平鋪
    case 2: style = WPSTYLE_STRETCH; break;  // 拉伸
    case 3: style = WPSTYLE_FIT; break;      // 適應 (Vista+)
    case 4: style = WPSTYLE_FILL; break;     // 填滿 (Vista+)
  }

  Screen->Cursor = crHourGlass;
  try {
    if (SetWallpaperEx(file.c_str(), style))
      ShowMessage("壁紙設定成功!");
    else
      ShowMessage("壁紙設定失敗,請確認檔案存在且具備權限。");
  }
  __finally {
    Screen->Cursor = crDefault;
  }
}

壁紙樣式常數對照 (WALLPAPEROPT.dwStyle)

常數值說明支援版本
WPSTYLE_CENTER0置中,保持原始尺寸All
WPSTYLE_TILE1平鋪重複All
WPSTYLE_STRETCH2拉伸填滿螢幕 (可能變形)All
WPSTYLE_FIT3等比縮放至完全顯示 (可能有邊框)Vista+
WPSTYLE_FILL4等比縮放至填滿螢幕 (可能裁切)Vista+
WPSTYLE_SPAN5跨多螢幕延展 (Win8+)Win8+

常見問題與解決方案

問題原因解決
CoCreateInstance 回傳 0x80040154 (CLASS_E_CLASSNOTAVAILABLE)Active Desktop 元件未註冊/損毀 (WinXP SP2+ 預設停用 Active Desktop)執行 regsvr32 shdocvw.dll、regsvr32 browseui.dll;或改用 IActiveDesktop 替代方案 (見下)
ApplyChanges 失敗 / 壁紙不更新權限不足、群組原則禁用 Active Desktop、桌面視窗未就緒檢查 HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\ActiveDesktop;嘗試 SystemParametersInfo(SPI_SETDESKWALLPAPER) 備援
HTML 壁紙不顯示/腳本錯誤Active Desktop 使用 MSHTML (IE 引擎),現代網頁標準不支援**不建議**使用 HTML 壁紙,僅用於相容舊系統
64 位元專案編譯錯誤shlobj.h 定義衝突、COM 介面指標大小確認 _WIN32_DCOM 定義、使用 IActiveDesktop* 而非 IActiveDesktopPtr (智慧指標需正確匯入型別庫)

現代替代方案 (Vista / Win7 / 8 / 10 / 11)

Active Desktop 在 Vista 後被 **Desktop Window Manager (DWM)** 取代,IActiveDesktop 仍相容但屬舊技術。現代建議:

方案一:IDesktopWallpaper (Win7+,正式 API)


#include  // IDesktopWallpaper, CLSID_DesktopWallpaper

bool SetWallpaperModern(const wchar_t* path, DESKTOP_WALLPAPER_POSITION pos = DWPOS_FILL) {
  IDesktopWallpaper* pWallpaper = NULL;
  HRESULT hr = CoCreateInstance(CLSID_DesktopWallpaper, NULL, CLSCTX_INPROC_SERVER,
                                IID_IDesktopWallpaper, (void**)&pWallpaper);
  if (SUCCEEDED(hr)) {
    hr = pWallpaper->SetWallpaper(NULL, path); // NULL = 所有顯示器
    if (SUCCEEDED(hr)) hr = pWallpaper->SetPosition(pos);
    pWallpaper->Release();
  }
  return SUCCEEDED(hr);
}

優點:原生支援多顯示器獨立壁紙、高 DPI、動態換圖 (SlideShow)、無 Active Desktop 相依。

方案二:SystemParametersInfo + 臨時 BMP 轉檔 (最相容)


bool SetWallpaperCompat(const wchar_t* path) {
  // 1. 使用 GDI+/WIC 將 JPG/PNG 載入並儲存為暫存 BMP
  // 2. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)bmpPath, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  // 3. 刪除暫存 BMP
  // 適合不想引入 COM 相依、需支援極舊系統 (Win95/NT4) 的專案
}

結語

IActiveDesktop 曾是 Windows 98/2000/XP 時代設定非 BMP 壁紙的標準方式。雖然現代系統已轉向 IDesktopWallpaper,但理解 IActiveDesktop 的 COM 介面操作流程 (建立物件、設定屬性、ApplyChanges 套用) 仍具教學價值。實際專案建議**優先使用 IDesktopWallpaper (Win7+)**,舊系統相容才回退至 IActiveDesktop 或 SystemParametersInfo + 圖片轉檔方案。

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