由於項目的的需要,系統中的各終端機時間必須與服務器保持一致,卻由於是內部服務器,不連接外網,所以沒辦法使用百度的地址作為時間地址標准,購買一個時間服務器又會增加成本,所以想着自己做一個簡易的程序來同步服務器上面的時間。
在最初的操作時確實很順利,百度了一下出來很多修改時間的辦法。在自己的本地環境中測試沒任何問題,在其他PC機上同步我的時間也正常,於是很高興的拿來用了,然而,實際生產環境中卻無法使用,提示“無法連接到遠程服務器”,在網上找了很多方法,包括開啟80端口服務;在調用.net的API修改時間方法SetLocalTime(&time)之前,先設置SYSTEMTIME time = systemtime;等多種辦法,還是沒能解決問題。最后終於在微軟社區中找到了一篇,在VS中設置程序自動以管理員權限運行的博客,配合之前的獲取數據庫的時間,然后進行本機時間修改的方法,解決了問題。
解決方法的連接:https://social.msdn.microsoft.com/Forums/zh-CN/fd806d68-a895-4df6-b7f2-3c158357952e/-win10-datetimenowtostring-0318-224209-?forum=2212
下面是代碼:
using System; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Data.SqlClient; using static 自動同步時間.Form1; namespace 自動同步時間 { public partial class Form1 : Form { SqlConnect con = new SqlConnect(); SqlDataReader dr; public Form1() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) { UpdateTime(); } /** * 系統時間的設置 * */ [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 wMiliseconds; } private void Form1_Load(object sender, EventArgs e) { this.Width = 0; this.Height = 0; UpdateTime(); timer1.Interval = 604800000; if (!CheckExistRegisterApp()) { SetRegistryApp(); } } private bool UpdateTime() { string dtSql = "select getdate()";//獲取數據庫時間,同步本機時間 string whStr = "Server=192.168.1.62;initial Catalog=WKDB;user id=sa;password=admin12345678;Connect Timeout=5;Max Pool Size=100;Min Pool Size=5";//數據庫連接字符串 SqlConnection whCon = new SqlConnection(whStr); whCon.Open(); try { SqlCommand cmd1 = new SqlCommand(dtSql, whCon); dr = cmd1.ExecuteReader(); DateTime da; dr = con.select(dtSql); if (dr.Read()) { da = dr.GetDateTime(0); string dt = da.ToString(); SystemTime sysTime = new SystemTime(); DateTime datetime = (Convert.ToDateTime(dt)); sysTime.wYear = (ushort)datetime.Year; sysTime.wMonth = (ushort)datetime.Month; sysTime.wDay = (ushort)datetime.Day; sysTime.wDayOfWeek = (ushort)datetime.DayOfWeek; sysTime.wHour = (ushort)datetime.Hour; sysTime.wMinute = (ushort)datetime.Minute; sysTime.wSecond = (ushort)datetime.Second; sysTime.wMiliseconds = (ushort)datetime.Millisecond; //SystemTime time = sysTime;//這里是解決問題過程中百度的方法,但是不起作用 return SetSystemDateTime.SetLocalTime(ref sysTime); } } catch (Exception ex) { Util.outlogtext("更新時間失敗");//簡單的日志輸出 Util.outlogtext(ex.ToString()); } finally { con.close(); } return false; } /// <summary> /// 檢查當前程序是否在啟動項中 /// </summary> /// <returns></returns> public static bool CheckExistRegisterApp() { string ShortFileName = Application.ProductName; //獲得應用程序名 bool bResult = false; try { Microsoft.Win32.RegistryKey Reg; Reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true); if (Reg == null) { Reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run"); } foreach (string s in Reg.GetValueNames()) { if (s.Equals(ShortFileName)) { bResult = true; break; } } } catch (Exception ex) { return false; } return bResult; } /// <summary> /// 注冊表操作,將程序添加到啟動項 /// </summary> public static void SetRegistryApp() { try { Microsoft.Win32.RegistryKey Reg; string ShortFileName = Application.ProductName; Reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true); if (Reg == null) { Reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run"); } Reg.SetValue(ShortFileName, Application.ExecutablePath); } catch (Exception ex) { } } } public class SetSystemDateTime { [DllImport("Kernel32.dll")] public static extern bool SetLocalTime(ref SystemTime sysTime); public static bool SetLocalTimeByStr(string timestr) { bool flag = false; SystemTime sysTime = new SystemTime(); DateTime dt = Convert.ToDateTime(timestr); sysTime.wYear = Convert.ToUInt16(dt.Year); sysTime.wMonth = Convert.ToUInt16(dt.Month); sysTime.wDay = Convert.ToUInt16(dt.Day); sysTime.wHour = Convert.ToUInt16(dt.Hour); sysTime.wMinute = Convert.ToUInt16(dt.Minute); sysTime.wSecond = Convert.ToUInt16(dt.Second); try { flag = SetSystemDateTime.SetLocalTime(ref sysTime); } catch (Exception e) { Console.WriteLine("SetSystemDateTime函數執行異常" + e.Message); } return flag; } } }
下面才是最關鍵的設置方法,接下來就是改權限的時候了
一: 在Visual Studio 中--解決方案資源管理器--右鍵項目名稱--屬性,找到“安全性”選項,
二:勾選“啟用ClickOnce安全設置”,
三:這時,在項目下面會多出一個“app.manifest”的文件,選中它,並找到代碼段<requestedExecutionLevel level="asInvoker" uiAccess="false" />,將其改為:<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />,
打開:
將上圖部分修改為:
四:改正后,不要急於重新編譯生成,再次打開“屬性--安全性”界面,
將“啟用ClickOnce安全設置”前面的勾去掉后再編譯運行。 不然程序會報錯無法運行。
五:最后,保存修改,重新編譯運行程序。
打開程序時,會提示“用戶賬戶控制”來獲取管理員權限運行,點擊“是”則獲取了管理員權限。
到此,整個操作工作完成,運行程序后,下次開機會自動啟動進行時間的更新。應該還有其他方法進行時間的獲取和更新,找到后我會持續更新。☺