Windows 系統參數資訊函式 SystemParametersInfo 可讀寫多種系統級設定,其中 SPI_SETDESKWALLPAPER (0x0014) 可程式化更換桌面壁紙。本文完整示範 C# P/Invoke 宣告、圖片格式轉換 (僅支援 BMP)、檔案選擇 UI、預覽與套用流程。
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
string pvParam,
uint fWinIni);
// 常數
public const uint SPI_SETDESKWALLPAPER = 0x0014;
public const uint SPIF_UPDATEINIFILE = 0x01; // 寫入 user profile
public const uint SPIF_SENDCHANGE = 0x02; // 廣播 WM_SETTINGCHANGE 通知其他程式
CharSet.Auto:自動依專案 Unicode/ANSI 封送字串路徑。SetLastError=true:失敗時可呼叫 Marshal.GetLastWin32Error() 取得錯誤碼。fWinIni 組合 SPIF_UPDATEINIFILE | SPIF_SENDCHANGE 確保即時生效並持久化。public partial class WallpaperForm : Form
{
private string _selectedBmpPath;
public WallpaperForm()
{
InitializeComponent();
// UI: btnSelect, btnApply, txtPath, picPreview, openFileDialog1
}
private void btnSelect_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "圖片檔案|*.bmp;*.jpg;*.jpeg;*.png;*.gif|所有檔案|*.*";
openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string srcPath = openFileDialog1.FileName;
txtPath.Text = srcPath;
try
{
using (var img = Image.FromFile(srcPath))
{
picPreview.Image = new Bitmap(img); // 複製避免檔案鎖定
// 必須轉為 BMP 才能設定壁紙
string ext = Path.GetExtension(srcPath).ToLowerInvariant();
if (ext != ".bmp")
{
_selectedBmpPath = Path.ChangeExtension(Path.GetTempFileName(), ".bmp");
img.Save(_selectedBmpPath, ImageFormat.Bmp);
}
else
{
_selectedBmpPath = srcPath;
}
}
}
catch (Exception ex)
{
MessageBox.Show($"圖片載入失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void btnApply_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(_selectedBmpPath) || !File.Exists(_selectedBmpPath))
{
MessageBox.Show("請先選擇有效圖片", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
bool result = SystemParametersInfo(
SPI_SETDESKWALLPAPER,
0,
_selectedBmpPath,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
if (result)
{
MessageBox.Show("桌面壁紙已更新", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
int err = Marshal.GetLastWin32Error();
MessageBox.Show($"更新失敗 (錯誤碼: {err})", "失敗", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
// 清理暫存 BMP
if (!string.IsNullOrEmpty(_selectedBmpPath) &&
_selectedBmpPath != txtPath.Text && // 非原始 BMP
File.Exists(_selectedBmpPath))
{
try { File.Delete(_selectedBmpPath); } catch { /* 忽略 */ }
}
base.OnFormClosing(e);
}
}
SystemParametersInfo(SPI_SETDESKWALLPAPER) 僅接受 BMP 格式路徑。JPG/PNG 直接傳遞會失敗 (錯誤碼 87 - 參數錯誤) 或顯示黑畫面。故需先轉檔。
// 使用 Image.Save 直接轉 BMP (無損但檔案較大)
image.Save(bmpPath, ImageFormat.Bmp);
// 若需壓縮可先縮放至螢幕解析度再存 BMP
var screenSize = Screen.PrimaryScreen.Bounds.Size;
using var resized = new Bitmap(image, screenSize);
resized.Save(bmpPath, ImageFormat.Bmp);
單一壁紙會延伸至所有螢幕。若需各螢幕不同壁紙,需呼叫 IDesktopWallpaper (Windows 8+ COM 介面) 或使用 SystemParametersInfo(SPI_SETDESKWALLPAPER) 搭配登錄機碼 HKCU\Control Panel\Desktop\Wallpaper 手動拼貼大圖。
DpiAwareness,Screen.Bounds 回傳實體像素,轉檔時可直接使用。// Program.cs - 適合排程/捷徑呼叫
class Program
{
static int Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("用法: SetWallpaper.exe <圖片完整路徑>");
return 1;
}
string path = args[0];
if (!File.Exists(path)) { Console.Error.WriteLine("找不到檔案"); return 2; }
string bmpPath = path;
string ext = Path.GetExtension(path).ToLowerInvariant();
if (ext != ".bmp")
{
try
{
using var img = Image.FromFile(path);
bmpPath = Path.ChangeExtension(Path.GetTempFileName(), ".bmp");
img.Save(bmpPath, ImageFormat.Bmp);
}
catch (Exception ex) { Console.Error.WriteLine($"轉檔失敗: {ex.Message}"); return 3; }
}
bool ok = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, bmpPath, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
if (!ok) Console.Error.WriteLine($"API 失敗: {Marshal.GetLastWin32Error()}");
// 清理暫存
if (bmpPath != path && File.Exists(bmpPath)) File.Delete(bmpPath);
return ok ? 0 : 4;
}
// ... P/Invoke 宣告同上
}
| 錯誤碼 | 常數 | 說明 |
|---|---|---|
| 87 | ERROR_INVALID_PARAMETER | 路徑非 BMP、檔案不存在、路徑過長 (MAX_PATH 260) |
| 5 | ERROR_ACCESS_DENIED | 權限不足 (受限桌面、系統帳號) |
| 2 | ERROR_FILE_NOT_FOUND | 檔案路徑錯誤 |
| 1460 | ERROR_TIMEOUT | 廣播 WM_SETTINGCHANGE 逾時 (其他視窗未回應) |
| 方法 | 優點 | 缺點 |
|---|---|---|
| SystemParametersInfo (本文) | 無相依、支援 XP+、程式碼簡單 | 僅 BMP、單一壁紙、無轉換/縮放選項 |
| IDesktopWallpaper (COM) | 多螢幕獨立壁紙、支援 JPG/PNG、位置模式 (填滿/置中/平鋪) | 需 Windows 8+、COM Interop 較複雜 |
| 登錄機碼 + WM_SETTINGCHANGE | 可控制 WallpaperStyle/TileWallpaper | 非官方支援、需手動廣播、相容性風險 |
| PowerShell / cmd | 無需編譯、腳本化 | 啟動較慢、依賴外部程式 |