專案建立與介面佈局
- 新建 Windows Forms App (.NET Framework) 專案,命名
FormCapture。
- 主表單
Form1 設定:Text = "螢幕截圖程式"。
- 工具箱拖曳控件:
PictureBox (name: pictureBox1):顯示截圖預覽,SizeMode = Zoom。
Button (name: btnCapture, Text = "螢幕截圖"):觸發截圖。
- 可選:
SaveFileDialog (name: saveFileDialog1, Filter = "JPEG|*.jpg|PNG|*.png") 儲存檔案。
完整截圖程式碼
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class Form1 : Form {
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
private const int SRCCOPY = 0x00CC0020;
public Form1() => InitializeComponent();
private void btnCapture_Click(object sender, EventArgs e) {
// 1. 取得螢幕尺寸 (或指定區域)
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
// 2. 建立目標 Bitmap
using (Bitmap bmp = new Bitmap(width, height)) {
// 3. 從 Bitmap 取得 Graphics 並獲取 DC
using (Graphics g = Graphics.FromImage(bmp)) {
IntPtr hdcDest = g.GetHdc();
try {
// 4. 取得螢幕 DC
IntPtr hdcSrc = GetDC(IntPtr.Zero);
try {
// 5. 執行 BitBlt 複製像素
bool success = BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);
if (!success) {
int error = Marshal.GetLastWin32Error();
MessageBox.Show($"BitBlt 失敗,錯誤碼: {error}");
return;
}
} finally {
ReleaseDC(IntPtr.Zero, hdcSrc);
}
} finally {
g.ReleaseHdc(hdcDest);
}
// 6. 顯示於 PictureBox
pictureBox1.Image?.Dispose();
pictureBox1.Image = (Bitmap)bmp.Clone();
}
}
}
private void btnSave_Click(object sender, EventArgs e) {
if (pictureBox1.Image == null) return;
if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
ImageFormat fmt = saveFileDialog1.FilterIndex == 1 ? ImageFormat.Jpeg : ImageFormat.Png;
pictureBox1.Image.Save(saveFileDialog1.FileName, fmt);
MessageBox.Show("儲存成功!");
}
}
}
關鍵實作細節
- using 區塊巢狀:確保
Bitmap、Graphics、DC 正確釋放順序 (先 ReleaseHdc 再 Dispose Graphics)。
- 錯誤處理:
BitBlt 回傳 false 時透過 Marshal.GetLastWin32Error() 取得 Win32 錯誤碼。
- PictureBox 影像更新:先
Dispose() 舊影像再指派新影像,避免記憶體洩漏。
- 多螢幕支援:可改用
Screen.AllScreens 計算虛擬螢幕總矩形,或讓使用者選擇特定螢幕。
進階擴充
- 區域截圖:滑鼠拖曳選取矩形,傳入
BitBlt 的 nXSrc/nYSrc/nWidth/nHeight。
- 熱鍵觸發:
RegisterHotKey 註冊全域熱鍵 (如 PrintScreen)。
- 直接存檔不預覽:省略
PictureBox,截圖後直接 bmp.Save(...)。
- 無框架透明表單覆蓋:實現類似 Snipping Tool 的選取介面。