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

Visual C# 開發多功能定時關機工具:API 調用、系統信息獲取與倒計時功能全實現

     編輯:關於C語言

項目概覽

開發一個集定時關機、倒計時關機、關機提醒、系統信息查看於一體的 Windows 工具,深度演示 C# 調用 Windows API(user32.dll、kernel32.dll、shell32.dll)的完整流程。

一、主窗體設計與 API 聲明

1.1 界面佈局

  • 分組框 1:當前系統時間(動態顯示)
  • 分組框 2:設置時間(DateTimePicker 日期+時間)
  • 複選框:自動關機 / 倒計時 / 定時報警
  • 操作按鈕:關機、重啟、注銷、取消、系統信息
  • Timer 組件:Interval=100ms 高頻刷新

1.2 核心 API 聲明

using System.Runtime.InteropServices;
using System.Text;

public partial class MainForm : Form
{
    // user32.dll - 窗口與關機
    [DllImport("user32.dll")]
    public static extern long ExitWindowsEx(long uFlags, long dwReserved);
    
    [DllImport("user32.dll")]
    public static extern long SetWindowPos(long hwnd, long hWndInsertAfter, 
        long x, long y, long cx, long cy, long wFlags);

    // shell32.dll - 系統關於信息
    [DllImport("shell32.dll")]
    public static extern long ShellAbout(long hWnd, string szApp, string szOtherStuff, long hIcon);

    // kernel32.dll - 系統信息獲取
    [DllImport("kernel32.dll")]
    public static extern void GetWindowsDirectory(StringBuilder lpBuffer, int nSize);
    
    [DllImport("kernel32.dll")]
    public static extern void GetSystemDirectory(StringBuilder lpBuffer, int nSize);
    
    [DllImport("kernel32.dll")]
    public static extern void GetSystemInfo(ref CPU_INFO lpSystemInfo);
    
    [DllImport("kernel32.dll")]
    public static extern void GlobalMemoryStatus(ref MEMORY_INFO lpBuffer);
    
    [DllImport("kernel32.dll")]
    public static extern void GetSystemTime(ref SYSTEMTIME_INFO lpSystemTime);
}

二、結構體定義(對應 API 參數)


[StructLayout(LayoutKind.Sequential)]
public struct CPU_INFO
{
    public uint dwOemId;
    public uint dwPageSize;
    public uint lpMinimumApplicationAddress;
    public uint lpMaximumApplicationAddress;
    public uint dwActiveProcessorMask;
    public uint dwNumberOfProcessors;
    public uint dwProcessorType;
    public uint dwAllocationGranularity;
    public uint dwProcessorLevel;
    public uint dwProcessorRevision;
}

[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_INFO
{
    public uint dwLength;
    public uint dwMemoryLoad;        // 內存使用率 %
    public uint dwTotalPhys;         // 總物理內存
    public uint dwAvailPhys;         // 可用物理內存
    public uint dwTotalPageFile;     // 總頁文件
    public uint dwAvailPageFile;     // 可用頁文件
    public uint dwTotalVirtual;      // 總虛擬內存
    public uint dwAvailVirtual;      // 可用虛擬內存
}

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME_INFO
{
    public ushort wYear;
    public ushort wMonth;
    public ushort wDayOfWeek;
    public ushort wDay;
    public ushort wHour;
    public ushort wMinute;
    public ushort wSecond;
    public ushort wMilliseconds;
}

三、關機核心邏輯實現


private const int SHUTDOWN = 1;
private const int REBOOT = 2;
private const int LOGOFF = 0;
private long dwReserved = 0;

private void ExecuteShutdown(int action)
{
    long result = action switch
    {
        SHUTDOWN => ExitWindowsEx(SHUTDOWN | 0x04, dwReserved), // EWX_FORCE
        REBOOT => ExitWindowsEx(REBOOT | 0x04, dwReserved),
        LOGOFF => ExitWindowsEx(LOGOFF | 0x04, dwReserved),
        _ => 0
    };
    
    if (result == 0)
    {
        int error = Marshal.GetLastWin32Error();
        MessageBox.Show($"操作失敗,錯誤碼: {error}");
    }
}

// 按鈕事件綁定
private void btnShutdown_Click(object sender, EventArgs e) => ExecuteShutdown(SHUTDOWN);
private void btnReboot_Click(object sender, EventArgs e) => ExecuteShutdown(REBOOT);
private void btnLogoff_Click(object sender, EventArgs e) => ExecuteShutdown(LOGOFF);

四、定時器邏輯(定時/倒計時雙模式)


private int _countdownSeconds = 0;

private void timer1_Tick(object sender, EventArgs e)
{
    // 1. 更新當前時間顯示
    lblCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    
    // 2. 定時關機檢查
    if (chkSchedule.Checked)
    {
        DateTime target = dtpDate.Value.Date + dtpTime.Value.TimeOfDay;
        if (DateTime.Now >= target)
        {
            ExecuteShutdown(SHUTDOWN);
            timer1.Stop();
        }
    }
    
    // 3. 倒計時關機
    if (chkCountdown.Checked)
    {
        if (_countdownSeconds > 0)
        {
            _countdownSeconds--;
            lblCountdown.Text = $"剩餘: {_countdownSeconds} 秒";
        }
        else
        {
            ExecuteShutdown(SHUTDOWN);
            timer1.Stop();
        }
    }
    
    // 4. 定時報警
    if (chkAlarm.Checked && DateTime.Now >= dtpAlarm.Value)
    {
        MessageBox.Show("定時提醒到達!");
        chkAlarm.Checked = false; // 單次觸發
    }
}

// 啟動倒計時
private void btnStartCountdown_Click(object sender, EventArgs e)
{
    _countdownSeconds = (int)numCountdown.Value; // NumericUpDown 設置秒數
    chkCountdown.Checked = true;
}

五、系統信息窗體實現


public partial class SysInfoForm : Form
{
    private void btnRefresh_Click(object sender, EventArgs e)
    {
        // 1. 系統路徑
        StringBuilder sb = new StringBuilder(256);
        GetWindowsDirectory(sb, sb.Capacity);
        txtWinDir.Text = sb.ToString();
        
        GetSystemDirectory(sb, sb.Capacity);
        txtSysDir.Text = sb.ToString();
        
        // 2. CPU 信息
        CPU_INFO cpu = new CPU_INFO();
        GetSystemInfo(ref cpu);
        txtCpuCount.Text = cpu.dwNumberOfProcessors.ToString();
        txtCpuType.Text = cpu.dwProcessorType.ToString();
        txtCpuLevel.Text = cpu.dwProcessorLevel.ToString();
        
        // 3. 內存信息
        MEMORY_INFO mem = new MEMORY_INFO { dwLength = (uint)Marshal.SizeOf() };
        GlobalMemoryStatus(ref mem);
        txtMemLoad.Text = $"{mem.dwMemoryLoad}%";
        txtTotalPhys.Text = FormatBytes(mem.dwTotalPhys);
        txtAvailPhys.Text = FormatBytes(mem.dwAvailPhys);
        
        // 4. 系統時間 (UTC)
        SYSTEMTIME_INFO st = new SYSTEMTIME_INFO();
        GetSystemTime(ref st);
        txtSysTime.Text = $"{st.wYear}-{st.wMonth:D2}-{st.wDay:D2} {st.wHour:D2}:{st.wMinute:D2}:{st.wSecond:D2} (UTC)";
    }
    
    private string FormatBytes(uint bytes)
    {
        double gb = bytes / 1024.0 / 1024 / 1024;
        return gb >= 1 ? $"{gb:F2} GB" : $"{bytes / 1024 / 1024} MB";
    }
}

六、關鍵技術難點總結

  1. 結構體內存佈局:[StructLayout(LayoutKind.Sequential)] 確保字段順序與 C++ 結構一致
  2. 字符串緩衝區:StringBuilder 配合容量參數防止緩衝區溢出
  3. 引用傳遞:結構體參數必須用 ref 關鍵字
  4. 錯誤處理:API 失敗時調用 Marshal.GetLastWin32Error() 獲取錯誤碼
  5. 權限提升:關機/重啟需管理員權限,建議清單文件配置 requireAdministrator

七、現代化改進建議

  • 使用 System.Management (WMI) 替代 kernel32 API 獲取硬件信息(托管代碼、跨平台)
  • 使用 PerformanceCounter 類獲取實時 CPU/內存使用率
  • 關機功能遷移至 Process.Start("shutdown.exe", "/s /t 0") 避免 P/Invoke 複雜度
  • UI 升級至 WPF/WinUI 3 支持高 DPI 與現代風格

本項目完整演示了 C# P/Invoke 技術棧的核心用法:API 聲明、結構體映射、字符串緩衝、錯誤處理、定時器調度,是學習 Windows 系統編程的優秀實戰案例。

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