2026-06-09

[powershell] 用Gemini自製scrnsave.scr

繼上篇  [cmd]利用保護螢幕裝置關螢幕不關喇叭(關螢幕聽歌)
已知 .scr 是透過 C# 編寫而成
現今已經是 AI 撰寫程式的時代,就算我們不懂 C#,也沒有 VSCode,一樣也可以自己做螢幕保護程式
畢竟有個現成的在那邊可以抄,所以我們只要對AI下達想要的指令
用什麼程式語言撰寫、希望的功能是什麼,最主要的這兩個方向訂下後,步步邁向目標

一開始,我希望他用powershell實現,雖然可以成功,但只成功一半,他會卡死在迴圈之中
透過第一個方式,我們知道保護螢幕裝置,實際上就是開啟一個全螢幕的程式把畫面擋住,並將鼠標消除,透過迴圈偵測滑鼠是否移動,來退出迴圈。

大方向對了,那我們就繼續

卡死迴圈的bug一直無法解決,於是他又推薦我改用edge實現
雖然畫面黑了,卻一直無法正確全螢幕,他用的全螢幕方案太複雜,我就叫他換另一個方案
他認為是針對edge視窗控制比較困難,所以想換成IE來控制
但我說 NO!,IE很多漏洞我可不想

於是乎轉了一圈,還是回歸C#
我才知道不用VSCode,微軟本身就有C#的編譯器(我不知道哪來的)
直接透過powershell編譯一個exe,改個附檔名變成scr就成了
這次BUG就問題不大,慢慢和AI一來一回修改就搞定了

經過多次修改,就成下面的程式碼

Add-Type -AssemblyName System.Windows.Forms

# 1. 定義 C# 原始碼(完美雙螢幕、純黑、防震動退出、隱藏游標)
$csharpCode = @"
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;

namespace PureBlackScreenSaver
{
    public class BlackForm : Form
    {
        private Point mouseLocation = Point.Empty;

        public BlackForm(Screen targetScreen)
        {
            this.BackColor = Color.Black;
            this.FormBorderStyle = FormBorderStyle.None;
            this.StartPosition = FormStartPosition.Manual;
            this.TopMost = true;
            this.Bounds = targetScreen.Bounds;
            this.DoubleBuffered = true;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            Cursor.Hide(); 
        }

        private void ExitAction()
        {
            Cursor.Show();
            Application.Exit();
        }

        protected override void OnKeyDown(KeyEventArgs e) { ExitAction(); }
        protected override void OnMouseDown(MouseEventArgs e) { ExitAction(); }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (mouseLocation.IsEmpty)
            {
                mouseLocation = e.Location;
                return;
            }

            if (Math.Abs(e.X - mouseLocation.X) > 15 || Math.Abs(e.Y - mouseLocation.Y) > 15)
            {
                ExitAction();
            }
        }
    }


    static class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
    
            string rawCommandLine = Environment.CommandLine.ToLower();

            // ─── 情況一:完全沒有參數 (args.Length == 0) ───
            // 根據你的測試,只有在 Win11 右鍵點擊「設定」時,才會是空參數
            if (args.Length == 0)
            {
                MessageBox.Show("這個純黑螢幕保護程式不需要任何設定功能喔!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return; // 精準攔截 Win11 右鍵設定,直接結束
            }

            // ─── 情況二:有帶參數 ───
            if (args.Length > 0)
            {
                // 1. 傳統螢幕保護程式面板點擊「設定」(/c)
                if (rawCommandLine.Contains("/c"))
                {
                    MessageBox.Show("這個純黑螢幕保護程式不需要任何設定功能喔!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return; // 精準攔截傳統面板設定,直接結束
                }
    
                // 2. 傳統螢幕保護程式面板的小螢幕預覽(/p)
                if (rawCommandLine.Contains("/p"))
                {
                    return; // 直接結束,防止背景亂跑
                }

                // 3. 剩下的狀況(包含 /s 或 /S):不論是雙擊開啟、右鍵 Test、還是系統閒置,通通放行塗黑!
            }
    
            // ─── 真正執行全螢幕純黑的邏輯 ───
            foreach (Screen screen in Screen.AllScreens)
            {
                BlackForm form = new BlackForm(screen);
                form.Show();
            }
            Application.Run();
        }
    }
}
"@

# 💡【核心修正】將輸出路徑強制設定在當前使用者的「桌面」,避開 System32 權限問題
$desktopPath = [Environment]::GetFolderPath("Desktop")
$sourceFile = Join-Path $desktopPath "BlackScreen.cs"
$outputFile = Join-Path $desktopPath "PureBlackSaver.exe"
$scrFile = Join-Path $desktopPath "PureBlackSaver.scr"

Set-Content -Path $sourceFile -Value $csharpCode -Encoding UTF8

# 2. 自動尋找 Windows 內建的 .NET C# 編譯器 (csc.exe)
$cscPath = Join-Path $env:windir "Microsoft.NET\Framework64\v4.0.30319\csc.exe"
if (-not (Test-Path $cscPath)) {
    $cscPath = Join-Path $env:windir "Microsoft.NET\Framework\v4.0.30319\csc.exe"
}

if (Test-Path $cscPath) {
    Write-Host "正在透過 Windows 內建編譯器打包成 C# 原生程式..." -ForegroundColor Green
    
    # 呼叫編譯器
    & $cscPath /target:winexe /out:$outputFile $sourceFile
    
    if (Test-Path $outputFile) {
      
        # 自動複製一份並改名為 .scr 螢幕保護程式格式
        Copy-Item $outputFile $scrFile
        Write-Host "【成功】已在 $scrFile 產生" -ForegroundColor Cyan
        
        # 刪除過渡期的臨時 .cs 原始碼檔案
        Remove-Item $sourceFile
        Remove-Item $outputFile
    } else {
        Write-Error "編譯失敗,請檢查代碼。"
    }
} else {
    Write-Error "找不到 Windows 內建的 .NET 編譯器環境!"
}