明天的明天 永远的永远 未知的一切 我与你一起承担 ??

是非成败转头空 青山依旧在 几度夕阳红 。。。
  博客园  :: 首页  :: 管理
由于项目的的需要,系统中的各终端机时间必须与服务器保持一致,却由于是内部服务器,不连接外网,所以没办法使用百度的地址作为时间地址标准,购买一个时间服务器又会增加成本,所以想着自己做一个简易的程序来同步服务器上面的时间。

  在最初的操作时确实很顺利,百度了一下出来很多修改时间的办法。在自己的本地环境中测试没任何问题,在其他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安全设置”前面的勾去掉后再编译运行。 不然程序会报错无法运行。

 

五:最后,保存修改,重新编译运行程序。

打开程序时,会提示“用户账户控制”来获取管理员权限运行,点击“是”则获取了管理员权限。

 

到此,整个操作工作完成,运行程序后,下次开机会自动启动进行时间的更新。