背景:
个人电脑 安装的 VS2015 Community 社区版。
一直用得挺好,都忘了要登录。
直到近来,30天试用期过 —— VS弹窗:要登录用户名、密码 才能继续使用。
但是,输入了无数次 邮箱,到下一步时,都弹出一个 白屏窗口 —— 死活没法登录成功。
登录不成功,日子还得过。
尊重著作权、版权 —— 破解VS这种事,还是不做的好(虽然能力可及)。
另辟蹊径:
试着通过 Win32 发送消息:关闭 弹出窗体。
但是 弹出窗体接收到 关闭消息后,整个VS 依然全部关掉了。
再尝试了一下:
如果先 修改系统时间,让修改后的系统时间 就是 试用期范围 —— 再关闭弹窗,VS 主窗体 没关闭。
思路明确:
> 监控系统所有窗体。
> 如果有窗体标题是 “Microsoft Visual Studio 帐户设置” 则开始 如下操作
> 修改系统时间 到 试用期范围。
> 发送 WM_CLOSE 消息,关闭 弹出窗体。
> 将系统时间 修改回来。
相关源码 150行:
1 class Program 2 { 3 /// <summary> 4 /// Visual Studio 2015 可以正常启用的 试用期 时间 5 /// </summary> 6 public static DateTime VisualStudioDate 7 { 8 get { return Convert.ToDateTime(ConfigurationManager.AppSettings["VisualStudioDate"] ?? "2018-05-01"); } 9 } 10 11 12 13 static void Main(string[] args) 14 { 15 while(true) 16 { 17 List<Win32API.WindowInfo> list = Win32API.EnumWindows(); 18 List<Win32API.WindowInfo> list2 = list.FindAll(x => x.szWindowName == "Microsoft Visual Studio 帐户设置"); 19 20 if (list2.Count >= 1) 21 { 22 //将系统时间设置为 可试用期 23 DateTime nowTime = DateTime.Now; 24 DateTime vsTime = VisualStudioDate; 25 double timeSpanMS = (nowTime - vsTime).TotalMilliseconds; 26 Win32API.SetSystemTime(vsTime); 27 28 foreach (Win32API.WindowInfo item in list2) 29 { 30 try 31 { 32 Console.WriteLine(string.Format("即将关闭 "{0}" 0x{1}", item.szWindowName, item.hWnd.ToString("X8"))); 33 Win32API.SendMessage(item.hWnd, Win32API.WM_CLOSE, 0, 0); 34 } 35 catch { } 36 } 37 38 Thread.Sleep(2000); 39 40 //将系统时间还原为 实际日期 41 DateTime nowTime2 = DateTime.Now; 42 double timeSpanMS2 = (nowTime2 - vsTime).TotalMilliseconds; 43 DateTime realTime = vsTime.AddMilliseconds(timeSpanMS + timeSpanMS2); 44 Win32API.SetSystemTime(realTime); 45 } 46 47 //死循环, 休眠5秒 48 Thread.Sleep(5000); 49 } 50 } 51 52 53 54 55 } 56 57 public class Win32API 58 { 59 public const int WM_CLOSE = 0x0010; 60 private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam); 61 62 [DllImport("User32.dll", EntryPoint = "SendMessage")] 63 public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 64 65 66 #region 获取所有窗体句柄 67 68 //Copyright © http://www.cnblogs.com/oraclejava/articles/1549025.html 69 70 [DllImport("user32.dll")] 71 private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam); 72 [DllImport("user32.dll")] 73 private static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount); 74 [DllImport("user32.dll")] 75 private static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount); 76 public struct WindowInfo 77 { 78 public IntPtr hWnd; 79 public string szWindowName; 80 public string szClassName; 81 82 public override string ToString() 83 { 84 return "0x" + hWnd.ToString("X8") + " '" + szWindowName + "' '" + szClassName + "'"; 85 } 86 } 87 88 public static List<WindowInfo> EnumWindows() 89 { 90 List<WindowInfo> wndList = new List<WindowInfo>(); 91 92 EnumWindows(delegate(IntPtr hWnd, int lParam) 93 { 94 WindowInfo wnd = new WindowInfo(); 95 StringBuilder sb = new StringBuilder(256); 96 wnd.hWnd = hWnd; 97 GetWindowTextW(hWnd, sb, sb.Capacity); 98 wnd.szWindowName = sb.ToString(); 99 GetClassNameW(hWnd, sb, sb.Capacity); 100 wnd.szClassName = sb.ToString(); 101 wndList.Add(wnd); 102 return true; 103 }, 0); 104 105 return wndList; 106 } 107 108 #endregion 109 110 111 #region 操作系统 时间修改 112 113 public static bool SetSystemTime(DateTime newDateTime) 114 { 115 SystemTime sysTime = new SystemTime(); 116 sysTime.wYear = Convert.ToUInt16(newDateTime.Year); 117 sysTime.wMonth = Convert.ToUInt16(newDateTime.Month); 118 sysTime.wDay = Convert.ToUInt16(newDateTime.Day); 119 sysTime.wHour = Convert.ToUInt16(newDateTime.Hour); 120 sysTime.wMinute = Convert.ToUInt16(newDateTime.Minute); 121 sysTime.wSecond = Convert.ToUInt16(newDateTime.Second); 122 sysTime.wMiliseconds = (ushort)newDateTime.Millisecond; 123 return SystemDateTime.SetLocalTime(ref sysTime); 124 } 125 126 private class SystemDateTime 127 { 128 [DllImport("Kernel32.dll")] 129 public static extern bool SetLocalTime(ref SystemTime sysTime); 130 131 [DllImport("Kernel32.dll")] 132 public static extern void GetLocalTime(ref SystemTime sysTime); 133 } 134 135 [StructLayout(LayoutKind.Sequential)] 136 private struct SystemTime 137 { 138 public ushort wYear; 139 public ushort wMonth; 140 public ushort wDayOfWeek; 141 public ushort wDay; 142 public ushort wHour; 143 public ushort wMinute; 144 public ushort wSecond; 145 public ushort wMiliseconds; 146 } 147 148 #endregion 149 150 }
项目编译:
新建一个 WinForm 程序。
将上面的代码 复制替换。
编译之后,将 exe 创建一个 快捷方式,放到 “启动” 菜单中,开机就启动,让exe在后台运行即可。
操作争议:
作者非常尊重 软件著作权、版权 —— 无意伤害微软利益。
用这种方式 延长试用,似乎有两个争议:修改系统时间、发送 WM_CLOSE 消息。
> 修改系统时间 是一种 普通操作,任何人都可以进行。【不具备争议性】
> 发送 WM_CLOSE 消息,一个程序给另一个程序发送消息,改变另外的程序的行为【有点外挂的味道】。 —— 但仔细一想:电脑关机时,系统会给每一个程序 都发送 WM_CLOSE 消息。这样一想,就突然不觉得侵权了。
尊重知识产权:
作者非常尊重 软件著作权、版权 —— 如果本文的操作 损害了 微软的利益,请及时联系作者,删除、修改 此文。