Windows服务调用Quartz.net 实现消息调度
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等
以上介绍是从博客园张善友(http://www.cnblogs.com/shanyou/archive/2007/08/25/quartznettutorial.html)的博客摘录,可登录他博客具体了解quartz.net。
我在这里只讲具体在项目中的实现:
通过Windows服务调用Quartz.net,然后Quartz.net 调用WinForm消息窗口,实现计划任务消息推送。
【Windows服务】-->【Quartz.net】 --> 【Winform .exe】 --> 【程序打包】
项目解决方案,如图所示:
一、创建Windows服务
1、打开vs2010--新建项目--选择"Windows服务",我这里命名为"QuartzService". 创建好后首先映入我们眼帘的是QuartzService.cs[设计]视图,右键点设计视图选择"添加安装程序",如下图:
注释:(创建一个Windows服务,仅用InstallUtil程序去安装这个服务是不够的。你必须还要把一个服务安装程序添加到你的Windows服务当中,这样便于InstallUtil或是任何别的安装程序知道应用你服务的是怎样的配置设置)
2、切换到刚被添加的ProjectInstaller的设计视图, 设置serviceInstaller1组件的属性: StartType = Automatic;ServiceName = QuartzService;
设置serviceProcessInstaller1组件的属性 Account = LocalSystem; 如下图:
3、QuartzService中添加Quartz.dll ,log4net.dll引用,在QuartzService.cs文件中引用命名空间 Quartz;Quartz.Impl; log4net;
右键点击QuartzService项目,属性-目标框架 ,选择.net Framwork 4,如下图:
4、添加app.config配置文件,具体配置如下:
1 <?xml version="1.0"?> 2 <configuration> 3 <configSections> 4 <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> 6 <sectionGroup name="common"> 7 <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/> 8 </sectionGroup> 9 </configSections> 10 <common> 11 <logging> 12 <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net"> 13 <arg key="configType" value="INLINE"/> 14 </factoryAdapter> 15 </logging> 16 </common> 17 <log4net> 18 <appender name="InfoFileAppender" type="log4net.Appender.RollingFileAppender"> 19 <file value="log/" /> 20 <appendToFile value="true" /> 21 <param name="DatePattern" value="yyyyMMdd".txt"" /> 22 <rollingStyle value="Date" /> 23 <maxSizeRollBackups value="100" /> 24 <maximumFileSize value="1024KB" /> 25 <staticLogFileName value="false" /> 26 <Encoding value="UTF-8" /> 27 <filter type="log4net.Filter.LevelRangeFilter"> 28 <param name="LevelMin" value="INFO" /> 29 <param name="LevelMax" value="INFO" /> 30 </filter> 31 <layout type="log4net.Layout.PatternLayout"> 32 <conversionPattern value="%date %-5level %logger - %message%newline" /> 33 </layout> 34 </appender> 35 <appender name="ErrorFileAppender" type="log4net.Appender.RollingFileAppender"> 36 <file value="log/error.txt" /> 37 <appendToFile value="true" /> 38 <rollingStyle value="Size" /> 39 <maxSizeRollBackups value="100" /> 40 <maximumFileSize value="10240KB" /> 41 <staticLogFileName value="true" /> 42 <Encoding value="UTF-8" /> 43 <filter type="log4net.Filter.LevelRangeFilter"> 44 <param name="LevelMin" value="WARN" /> 45 <param name="LevelMax" value="FATAL" /> 46 </filter> 47 <layout type="log4net.Layout.PatternLayout"> 48 <conversionPattern value="%date %-5level %logger - %message%newline" /> 49 </layout> 50 </appender> 51 <root> 52 <level value="INFO" /> 53 <appender-ref ref="InfoFileAppender" /> 54 <appender-ref ref="ErrorFileAppender" /> 55 </root> 56 </log4net> 57 58 <!-- 59 We use quartz.config for this server, you can always use configuration section if you want to. 60 Configuration section has precedence here. 61 --> 62 <appSettings> 63 <!-- YYC.WebService URL地址 --> 64 <add key="URL" value="http://localhost:43093/WebService.asmx" /> 65 </appSettings> 66 <!-- 67 <quartz > 68 </quartz> 69 --> 70 <startup> 71 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 72 </startup> 73 </configuration>
View Code
二、创建Quartz.Net.JobLibrary并配置Job
1、在解决方案中添加新项-选择"类库",我这里命名为Quartz.Net.JobLibrary,Quartz.Net.JobLibrary用来实现多个"作业"类。Quartz.Net.JobLibrary类库中添加Quartz.dll ,log4net.dll引用。
Quartz.Net.JobLibrary类库中添加一个类Interop.cs,这个类是为了解决在Win7中出现【交互式检测】弹窗,博客园李敬然(http://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html)的博客详细谈到 穿透Session 0 隔离,具体代码如下:
1 using System; 2 using System.Runtime.InteropServices; 3 4 namespace Quartz.Net.JobLibrary 5 { 6 public class Interop 7 { 8 public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; 9 public static void ShowMessageBox(string message, string title) 10 { 11 int resp = 0; 12 WTSSendMessage( 13 WTS_CURRENT_SERVER_HANDLE, 14 WTSGetActiveConsoleSessionId(), 15 title, title.Length, 16 message, message.Length, 17 0, 0, out resp, false); 18 } 19 [DllImport("kernel32.dll", SetLastError = true)] 20 public static extern int WTSGetActiveConsoleSessionId(); 21 [DllImport("wtsapi32.dll", SetLastError = true)] 22 public static extern bool WTSSendMessage( 23 IntPtr hServer, 24 int SessionId, 25 String pTitle, 26 int TitleLength, 27 String pMessage, 28 int MessageLength, 29 int Style, 30 int Timeout, 31 out int pResponse, 32 bool bWait); 33 34 public static void CreateProcess(string app, string path) 35 { 36 IntPtr hToken; 37 IntPtr hDupedToken = IntPtr.Zero; 38 39 PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 40 SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); 41 sa.Length = Marshal.SizeOf(sa); 42 43 STARTUPINFO si = new STARTUPINFO(); 44 si.cb = Marshal.SizeOf(si); 45 46 int dwSessionID = WTSGetActiveConsoleSessionId(); 47 bool result = WTSQueryUserToken(dwSessionID, out hToken); 48 49 if (!result) 50 { 51 ShowMessageBox("WTSQueryUserToken failed", "AlertService Message"); 52 } 53 54 result = DuplicateTokenEx( 55 hToken, 56 GENERIC_ALL_ACCESS, 57 ref sa, 58 (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, 59 (int)TOKEN_TYPE.TokenPrimary, 60 ref hDupedToken 61 ); 62 63 if (!result) 64 { 65 ShowMessageBox("DuplicateTokenEx failed", "AlertService Message"); 66 } 67 68 IntPtr lpEnvironment; 69 result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false); 70 71 if (!result) 72 { 73 ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message"); 74 } 75 76 result = CreateProcessAsUser( 77 hDupedToken, 78 path + app, 79 String.Empty, 80 ref sa, ref sa, 81 false, 0, IntPtr.Zero, 82 path, ref si, ref pi); 83 84 if (!result) 85 { 86 int error = Marshal.GetLastWin32Error(); 87 string message = String.Format("CreateProcessAsUser Error: {0}", error); 88 ShowMessageBox(message, "AlertService Message"); 89 } 90 91 if (pi.hProcess != IntPtr.Zero) 92 CloseHandle(pi.hProcess); 93 if (pi.hThread != IntPtr.Zero) 94 CloseHandle(pi.hThread); 95 if (hDupedToken != IntPtr.Zero) 96 CloseHandle(hDupedToken); 97 } 98 99 [StructLayout(LayoutKind.Sequential)] 100 public struct STARTUPINFO 101 { 102 public Int32 cb; 103 public string lpReserved; 104 public string lpDesktop; 105 public string lpTitle; 106 public Int32 dwX; 107 public Int32 dwY; 108 public Int32 dwXSize; 109 public Int32 dwXCountChars; 110 public Int32 dwYCountChars; 111 public Int32 dwFillAttribute; 112 public Int32 dwFlags; 113 public Int16 wShowWindow; 114 public Int16 cbReserved2; 115 public IntPtr lpReserved2; 116 public IntPtr hStdInput; 117 public IntPtr hStdOutput; 118 public IntPtr hStdError; 119 } 120 121 [StructLayout(LayoutKind.Sequential)] 122 public struct PROCESS_INFORMATION 123 { 124 public IntPtr hProcess; 125 public IntPtr hThread; 126 public Int32 dwProcessID; 127 public Int32 dwThreadID; 128 } 129 130 [StructLayout(LayoutKind.Sequential)] 131 public struct SECURITY_ATTRIBUTES 132 { 133 public Int32 Length; 134 public IntPtr lpSecurityDescriptor; 135 public bool bInheritHandle; 136 } 137 138 public enum SECURITY_IMPERSONATION_LEVEL 139 { 140 SecurityAnonymous, 141 SecurityIdentification, 142 SecurityImpersonation, 143 SecurityDelegation 144 } 145 146 public enum TOKEN_TYPE 147 { 148 TokenPrimary = 1, 149 TokenImpersonation 150 } 151 152 public const int GENERIC_ALL_ACCESS = 0x10000000; 153 154 [DllImport("kernel32.dll", SetLastError = true, 155 CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 156 public static extern bool CloseHandle(IntPtr handle); 157 158 [DllImport("advapi32.dll", SetLastError = true, 159 CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 160 public static extern bool CreateProcessAsUser( 161 IntPtr hToken, 162 string lpApplicationName, 163 string lpCommandLine, 164 ref SECURITY_ATTRIBUTES lpProcessAttributes, 165 ref SECURITY_ATTRIBUTES lpThreadAttributes, 166 bool bInheritHandle, 167 Int32 dwCreationFlags, 168 IntPtr lpEnvrionment, 169 string lpCurrentDirectory, 170 ref STARTUPINFO lpStartupInfo, 171 ref PROCESS_INFORMATION lpProcessInformation); 172 173 [DllImport("advapi32.dll", SetLastError = true)] 174 public static extern bool DuplicateTokenEx( 175 IntPtr hExistingToken, 176 Int32 dwDesiredAccess, 177 ref SECURITY_ATTRIBUTES lpThreadAttributes, 178 Int32 ImpersonationLevel, 179 Int32 dwTokenType, 180 ref IntPtr phNewToken); 181 182 [DllImport("wtsapi32.dll", SetLastError = true)] 183 public static extern bool WTSQueryUserToken( 184 Int32 sessionId, 185 out IntPtr Token); 186 187 [DllImport("userenv.dll", SetLastError = true)] 188 static extern bool CreateEnvironmentBlock( 189 out IntPtr lpEnvironment, 190 IntPtr hToken, 191 bool bInherit); 192 } 193 }
View Code
Quartz.Net.JobLibrary类库中再分别添加两个"作业"类JobTest1.cs,JobTest2.cs:
代码如下
JobTest1.cs
1 using System; 2 using System.Configuration; 3 using System.Reflection; 4 using Common.Logging; 5 6 namespace Quartz.Net.JobLibrary 7 { 8 public class JobTest1 : IJob 9 { 10 //使用Common.Logging.dll日志接口实现日志记录 11 private static readonly ILog logger = 12 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 13 14 private static string URL = ConfigurationManager.AppSettings["URL"]; 15 16 #region IJob 成员 17 18 public void Execute(IJobExecutionContext context) 19 { 20 try 21 { 22 logger.Info("JobTest1 任务开始运行"); 23 //ShowMsgBox msgBox = new ShowMsgBox(); 24 //msgBox.ShowMsg(100, "AAAA", "计划任务提醒"); 25 //WebServiceSoapClient client = new WebServiceSoapClient(new BasicHttpBinding(), new EndpointAddress(URL)); 26 //client.Shake(); 27 //ShowMsg(100, "AAAA", "计划任务提醒"); 28 //Interop.ShowMessageBox("This a message from AlertService.", 29 // "AlertService Message"); 30 string path = System.Windows.Forms.Application.StartupPath; 31 Interop.CreateProcess("Quartz.Net.WinForm.exe", path + "\\"); 32 logger.Info("JobTest1 任务运行结束"); 33 } 34 catch (Exception ex) 35 { 36 logger.Error("JobTest1 运行异常", ex); 37 } 38 } 39 40 #endregion 41 42 } 43 }
View Code
2、在Quartz.Net.JobLibrary中,添加配置文件quartz_jobs.xml,配置信息如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <!-- This file contains job definitions in schema version 2.0 format --> 4 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"> 5 <processing-directives> 6 <overwrite-existing-data>true</overwrite-existing-data> 7 </processing-directives> 8 9 <schedule> 10 <!--定义JobTest1--> 11 <job> 12 <name>JobTest1</name> 13 <group>JobGroup</group> 14 <description>测试任务1</description> 15 <job-type>Quartz.Net.JobLibrary.JobTest1,Quartz.Net.JobLibrary</job-type> 16 <durable>true</durable> 17 <recover>false</recover> 18 </job> 19 20 <!--定义示JobTest2--> 21 <job> 22 <name>JobTest2</name> 23 <group>JobGroup</group> 24 <description>测试任务2</description> 25 <job-type>Quartz.Net.JobLibrary.JobTest2,Quartz.Net.JobLibrary</job-type> 26 <durable>true</durable> 27 <recover>false</recover> 28 </job> 29 30 <!--定义JobTest1 触发器 每30秒执行一次任务--> 31 <trigger> 32 <cron> 33 <name>JobTestTrigger1</name> 34 <group>TriggerGroup</group> 35 <job-name>JobTest1</job-name> 36 <job-group>JobGroup</job-group> 37 <cron-expression>0/30 * * * * ?</cron-expression> 38 </cron> 39 </trigger> 40 41 <!--定义JobTest2 触发器 每分钟执行一次任务--> 42 <trigger> 43 <cron> 44 <name>JobTestTrigger2</name> 45 <group>TriggerGroup</group> 46 <job-name>JobTest2</job-name> 47 <job-group>JobGroup</job-group> 48 <cron-expression>0 * * * * ?</cron-expression> 49 </cron> 50 </trigger> 51 52 <!--定义JobTest2 触发器 每天凌晨01:00执行一次任务--> 53 <trigger> 54 <cron> 55 <name>JobTestTrigger3</name> 56 <group>TriggerGroup</group> 57 <job-name>JobTest2</job-name> 58 <job-group>JobGroup</job-group> 59 <cron-expression>0 0 1 * * ?</cron-expression> 60 </cron> 61 </trigger> 62 </schedule> 63 64 <!-- Cron Expressions——Cron 表达式 65 Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示: 66 1. Seconds 秒 67 2. Minutes 分钟 68 3. Hours 小时 69 4. Day-of-Month 月中的天 70 5. Month 月 71 6. Day-of-Week 周中的天 72 7. Year (optional field) 年(可选的域) 73 一个cron表达式的例子字符串为"0 0 12 ? * WED",这表示“每周三的中午12:00”。 74 单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"。 75 通配符('*')可以被用来表示域中“每个”可能的值。因此在"Month"域中的*表示每个月,而在Day-Of-Week域中的*则表示“周中的每一天”。 76 所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值得合法凡范围是0到31, 77 但是需要注意不同的月份中的天数不同。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。 78 Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示. 79 '/'字符用来表示值的增量,例如, 如果分钟域中放入'0/15',它表示“每隔15分钟,从0开始”,如果在份中域中使用'3/20',则表示“小时中每隔20分钟, 80 从第3分钟开始”或者另外相同的形式就是'3,23,43'。 81 '?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。 82 'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天, 83 即,一月的31日,非闰年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面, 84 则表示"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。 85 'W' 字符用来指定距离给定日最接近的周几(在day-of-week域中指定)。例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”。 86 '#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。 87 下面是一些表达式以及它们的含义。 88 Example Cron Expressions ——Cron表达式的例子 89 CronTrigger 90 例1 – 一个简单的每隔5分钟触发一次的表达式 91 "0 0/5 * * * ?" CronTrigger 92 例2 – 在每分钟的10秒后每隔5分钟触发一次的表达式(例如. 10:00:10 am, 10:05:10等.)。 93 "10 0/5 * * * ?" CronTrigger 94 例3 – 在每个周三和周五的10:30,11:30,12:30触发的表达式。 95 "0 30 10-13 ? * WED,FRI" CronTrigger 96 例4 – 在每个月的5号,20号的8点和10点之间每隔半个小时触发一次且不包括10点,只是8:30,9:00和9:30的表达式。 97 "0 0/30 8-9 5,20 * ?" 注意,对于单独触发器来说,有些日程需求可能过于复杂而不能用表达式表述,例如:9:00到10:00之间每隔5分钟触发一次, 98 下午1:00到10点每隔20分钟触发一次。这个解决方案就是创建两个触发器,两个触发器都运行相同的任务。 99 --> 100 </job-scheduling-data>
View Code
三、创建Quartz.Net.WinForm消息窗口
1、在解决方案中添加新项-选择"windows 应用程序",我这里命名为Quartz.Net.WinForm,具体实现从右下角逐渐显示气泡式窗口如图所示:
点击【确定】从右下角逐渐消失
通过JobTest1调用消息窗口,
string path = System.Windows.Forms.Application.StartupPath;
Interop.CreateProcess("Quartz.Net.WinForm.exe", path + "\\");
实现例如每一个小时检测是否有计划任务,一旦有任务,消息窗口弹出提醒!
四、注册Windows服务
1、cmd打开命令行工具:如果你系统是C盘,一般命令应该如下:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe "你的windows服务路径"
反注册如下:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u "你的windows服务路径"
当然也可以用sc命令
sc create windows服务名称 binPath= "你的windows服务路径"
删除服务
sc delete windows服务名称
这样注册就完了。
2、打开服务:
运行 下输入services.msc打开服务管理。如图:
刷新,可以查看到QuartzService.如下图:
3、 启动QuartzService,回到windows服务 应用程序所在目录
以上四部分大体实现了类似一些新闻消息推送,下一篇讲讲具体程序打包、安装等实现过程。希望大家多多推荐一下
转载于:https://www.cnblogs.com/Raymond-YYC/p/3975378.html
Windows服务调用Quartz.net 实现消息调度相关推荐
- windows服务调用Owin写一个http API 报错 调用的目标发生了异常。
在使用owin开发windows服务的时候,在部署的时候报如下错误: 2016-07-02 11:39:48: 读取配置信息失败:调用的目标发生了异常. 在 System.RuntimeMeth ...
- Windows服务调用Office时,未将对象引用的实例
Windows键+R键 回车 输入:comexp.msc -32 回车 点击控制台根节点--组件服务--计算机--我的电脑- ...
- Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度 Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quar
Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度 Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quartz ...
- Windows服务使用log4net记录日志
该文章是系列文章 基于.NetCore和ABP框架如何让Windows服务执行Quartz定时作业 的其中一篇. 比较流行的日志组件有以下四种,Topshelf都有相应的组件提供 log4net NL ...
- C# 定时任务 调度框架 WebWork (Quartz.NET) Web版的Windows服务
说起这个,还是觉得很自豪的(另外这里还要特别感谢Nick同学),至少目前我没有见到有这样现成框架,这个东西主要是用来调度任务的,就是根据时间定时执行一个任务,而这个任务你可以用C# 写成一个一个的dl ...
- windows 服务实现定时任务调度(Quartz.Net)
我们通常在一些情况下需要软件具有一个自动执行某些任务的功能,但是又不希望直接启动软件,或者每次都要手动的来启动软件,这时我们可可以考虑到windows服务了. 首先创建一个windows服务项目(详细 ...
- SpringCloud微服务-服务注册发现-负载均衡-服务调用-服务降级-服务网关-配置中心-消息总线-消息驱动-链路追踪-alibaba-nacos-sentinel-seata理论原理分析
SpringCloud理论技术 概述 Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总 ...
- Quartz+TopShelf实现Windows服务作业调度 (转载)
Quartz:首先我贴出来了两段代码(下方),可以看出,首先会根据配置文件(quartz.config),包装出一个Quartz.Core.QuartzScheduler instance,这是一个调 ...
- 服务端Skynet(二)——消息调度机制
服务端Skynet(二)--消息调度机制 文章目录 服务端Skynet(二)--消息调度机制 1.提前了解知识 1.1.互斥锁(mutex lock : **mut**ual **ex**clusio ...
最新文章
- 不要以为用了云,就不要运维
- Apache 2.2 虚拟主机配置(本人推荐的)
- Android NFC 开发实例
- 【数据分析】年轻人逃离大城市之后的下一站选哪儿?用数据来为你揭晓
- C++中的继承(三)
- vivo应用商店电脑版_VIVO应用商店代理商江湖的那些关系
- 二、uniapp项目(分段器的使用、scroll-view、视频下载、转发)
- amr文件格式分析【转http://blog.csdn.net/dinggo/article/details/1966444】
- qt读oracle时间戳,QT利用QDateTime获取当前时间戳的方法toTime_t
- phpcms调用后台上传的img图片 - 代码篇
- python做大型网站_django可以开发大型网站吗
- vue 动态scss变量,包含16进制转rgba,rgba转16进制
- 较完整的 bean生命周期
- 载波频率成分法——理论公式
- 移动鼠标计算鼠标偏移量
- 《极客与团队》一HRT实战
- Java日期时间主要API:java.time.Duration类和java.time.Period类
- mybatis的大于小于号转义符号
- 嵌入式系统与普适计算
- win10 任务栏打开直接显示【此电脑】的设置方法
热门文章
- 水位传感器c语言程序,基于STC89C51单片机的水位传感器控制系统设计.doc
- 云厂商下一块必争之地就是它了!
- HNOI2016D1T3 树 题解
- Openshift概念
- paypal余额限制_如何将您的PayPal余额转换成可以在任何地方消费的借记卡
- 领英辅助工具—领探,可突破领英的好友人脉限制
- Python中随机数的使用
- 读书发现一个勘误,提交了,这里是地址
- 曝各城市娶妻成本:深圳208万 程序员成为“妻奴”?
- linux网络编程 华清,网络编程(华清远见内部培训资料).ppt