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

C# 呼叫 Windows API 設定系統時間完整教學

     編輯:關於C語言

前言

在 C# 中直接修改系統時間需要呼叫 Windows 底層 API,因為 .NET Framework 沒有直接提供設定系統時間的 managed 方法。本文完整示範如何使用 P/Invoke 呼叫 kernel32.dll 的 SetSystemTime 函數,並處理時區轉換(系統時間為 UTC)的關鍵細節。

核心結構與 API 宣告

SYSTEMTIME 結構對應 Windows API 的時間格式,必須使用 StructLayout(LayoutKind.Sequential) 確保記憶體配置正確:

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

public static class Win32Api
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetSystemTime(ref SYSTEMTIME st);

    [DllImport("kernel32.dll")]
    public static extern void GetSystemTime(ref SYSTEMTIME st);
}

關鍵點:本地時間轉 UTC

SetSystemTime 接收的是 UTC 時間,若直接傳入 DateTime.Now 會導致時間偏移。必須手動轉換:

DateTime localNow = DateTime.Now;
DateTime utcNow = localNow.ToUniversalTime(); // 正確轉換

SYSTEMTIME st = new SYSTEMTIME
{
    wYear = (ushort)utcNow.Year,
    wMonth = (ushort)utcNow.Month,
    wDay = (ushort)utcNow.Day,
    wDayOfWeek = (ushort)utcNow.DayOfWeek,
    wHour = (ushort)utcNow.Hour,
    wMinute = (ushort)utcNow.Minute,
    wSecond = (ushort)utcNow.Second,
    wMilliseconds = (ushort)utcNow.Millisecond
};

bool success = Win32Api.SetSystemTime(ref st);
if (!success)
{
    int error = Marshal.GetLastWin32Error();
    throw new System.ComponentModel.Win32Exception(error);
}

完整 WinForms 範例程式

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class TimeSyncForm : Form
{
    private Button btnSync;
    private TextBox txtCurrentTime;
    private TextBox txtNewTime;

    public TimeSyncForm()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        this.btnSync = new Button { Text = "同步系統時間", Location = new Point(20, 50), Width = 150 };
        this.txtCurrentTime = new TextBox { Location = new Point(20, 20), Width = 300, ReadOnly = true };
        this.txtNewTime = new TextBox { Location = new Point(20, 90), Width = 300, ReadOnly = true };
        
        this.btnSync.Click += BtnSync_Click;
        this.Controls.AddRange(new Control[] { btnSync, txtCurrentTime, txtNewTime });
        this.Text = "系統時間設定工具";
        this.Size = new Size(360, 180);
    }

    private void BtnSync_Click(object sender, EventArgs e)
    {
        try
        {
            txtCurrentTime.Text = $"目前系統時間: {DateTime.Now:yyyy/MM/dd HH:mm:ss.fff}";
            
            // 取得網路時間或指定時間(此處示範用目前時間)
            DateTime targetTime = DateTime.Now; // 實務上應從 NTP 伺服器取得
            DateTime utcTime = targetTime.ToUniversalTime();

            SYSTEMTIME st = new SYSTEMTIME
            {
                wYear = (ushort)utcTime.Year,
                wMonth = (ushort)utcTime.Month,
                wDay = (ushort)utcTime.Day,
                wDayOfWeek = (ushort)utcTime.DayOfWeek,
                wHour = (ushort)utcTime.Hour,
                wMinute = (ushort)utcTime.Minute,
                wSecond = (ushort)utcTime.Second,
                wMilliseconds = (ushort)utcTime.Millisecond
            };

            if (Win32Api.SetSystemTime(ref st))
            {
                txtNewTime.Text = $"設定成功,新時間: {DateTime.Now:yyyy/MM/dd HH:mm:ss.fff}";
                MessageBox.Show("系統時間已更新", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"設定失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new TimeSyncForm());
    }
}

權限需求與實務建議

  • 管理員權限:設定系統時間需要「變更系統時間」權限,程式需以管理員身分執行
  • 應用程式清單:在 `app.manifest` 中設定 ``
  • 時間同步來源:生產環境建議從 NTP 伺服器(如 `time.windows.com`)取得標準時間
  • 日誌記錄:記錄時間變更前後的數值,供稽核追蹤

常見錯誤排查

錯誤碼原因解決方式
1314 (ERROR_PRIVILEGE_NOT_HELD)權限不足以管理員身分執行、檢查群組原則
87 (ERROR_INVALID_PARAMETER)參數錯誤檢查 SYSTEMTIME 結構欄位是否在有效範圍
時間偏移 8 小時未轉 UTC使用 ToUniversalTime() 轉換

總結

透過 P/Invoke 呼叫 `SetSystemTime` 是 C# 修改系統時間的標準做法。核心關鍵在於:正確定義 `SYSTEMTIME` 結構、將本地時間轉為 UTC、以管理員權限執行。實務應用中建議整合 NTP 客戶端功能,打造完整的時間同步解決方案。

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