护卫盾网络验证系统
简介及特点
新手视频教程
1.开通授权并安装服务端
常见问题
服务器域名简介
开通授权及安装服务端
如何更新服务端
如何迁移服务端
显示未授权的故常排除
关于域名备案问题
核心库与WebAPI的区别
快速验证与常规验证的区别
Windows服务器无法显示验证码
什么是软件自定义常量
什么是用户自定义常量
开发文档
返回状态码
核心库函数说明
快速验证-初始化
快速验证-取软件自定义常量
快速验证-取软件自定义常量节点值
常规验证-字节流加载皮肤
常规验证-本地文件加载皮肤
常规验证-初始化
常规验证-取软件数据
常规验证-取软件版本数据
常规验证-取软件自定义常量节点值
常规验证-取验证码-字节流
常规验证-获取验证码-本地文件
常规验证-获取机器码
常规验证-注册通行证
常规验证-发送改密验证邮件
常规验证-修改密码
常规验证-账户充值
常规验证-加入黑名单
常规验证-用户登录
常规验证-获取用户数据
常规验证-取用户自定义常量节点值
常规验证-扣点
常规验证-扣时
常规验证-扣余额
常规验证-绑定用户数据
常规验证-绑定机器码
常规验证-调用远程PHP函数
常规验证-进程通信-取资料
常规验证-心跳
常规验证-退出登录
常规验证-载入内置窗口
常规验证-取云端独立自定义常量
其它函数-保存配置/读取配置
其它函数-获取核心库版本号
其它函数-获取出错信息
其它函数-计算机蓝屏
其它函数-获取MD5值
其它函数-取程序目录/取模块目录
其它函数-过滤HTML标签
WebAPI开发手册
WebAPI-组包规则
WebAPI-解包规则
WebAPI-数据校验
WebAPI-快速验证
WebAPI-常规验证-初始化
WebAPI-常规验证-取验证码
WebAPI-常规验证-用户登录
WebAPI-常规验证-心跳通信
WebAPI-常规验证-绑定用户数据
WebAPI-常规验证-绑定机器码
WebAPI-常规验证-注册通行证
WebAPI-常规验证-发送改密验证邮件
WebAPI-常规验证-修改密码
WebAPI-常规验证-账户充值
WebAPI-常规验证-扣点
WebAPI-常规验证-扣时
WebAPI-常规验证-扣余额
WebAPI-常规验证-调用远程PHP函数
WebAPI-常规验证-添加黑名单
WebAPI-常规验证-退出登录
WebAPI-常规验证-取云端独立自定义常量
如何调用自动更新程序
远程自定义函数
全局变量
数据库操作函数
新增记录
查询记录-多条记录
查询记录-单条记录
查询记录-多条记录(SQL)
查询记录-单条记录(SQL)
执行SQL语句
更新记录
删除记录
统计数量
其它函数
常用自定义函数分享
获取充值卡详情
获取某软件在线人数
批量生成测试通行证
获取用户扣点记录
制作示例程序免费领取授权
EUE文档 - 私有云文档管理系统
-
+
首页
制作示例程序免费领取授权
<style> .linenums {max-height:200px;} </style> ## 活动概要 单丝不成线,孤木不成林,护卫盾支持接入几乎99%编程语言,由于涉及语言过多,作者无法为每个语言制作一份demo程序,故发动群众的力量,收集各个语言的demo程序,同时为付出汗水的作者准备了与付出价值相匹配的奖励。注:本活动仅针对`webAPI`接入方式。 ## 活动奖励 * `永久授权`一份。 ## 报名方式 联系客服QQ,说明使用的`编程语言`。客服记录下来后即可开始编写。编写完毕后提供`注册账号(领取奖励)`、`例程源码`、`编译成品`提供给客服即可。 ## 其它说明 目前仅支持编译型语言,解释性语言实际应用范围不大,故不在活动范围内(移动APP除外,例如UniAPP等)。 --- ## 例程要求 #### 什么是WebAPI? WebAPI是HTTP协议接口,支持几乎所有编程语言,制作WebAPI例程需要做一些准备,`POST库`、`Json解析库`、`AES-256-CBC加解密库`。 #### 例程要求 1. 备注尽量清晰,例程主要针对新手同学,清晰的备注有助于新手快速掌握。 2. 将`WebAPI`所有函数封装成一个类或库,可以参考护卫盾官方例程中,你能理解的其它语言例程,下方以C#为例。 ``` using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using System.Windows.Forms; using System.Security.Cryptography; using System.Drawing; using System.IO; using System.Net; using System.Threading; using System.Web; using System.Diagnostics; using System.Text.RegularExpressions; namespace 护卫盾网络验证_CSharp { class hwd { public struct g_softPara { public static string url; public static string sid; public static string key; public static string webkey; public static string clientRule; public static string serverRule; public static string moduleMD5; public static string clientId; public static bool autoHeartBeat; }; public struct g_soft { public static string name;//软件名称 public static string login;//0 账号密码登录,1 充值卡登录 public static string captcha;//captcha_login 用户登录,captcha_recharge 用户充值,captcha_bind 转绑 public static string version;//软件版本管理器全文,json格式,由旧到新顺序排列 public static string notice; //公告html源码,可使用 hwd_messageBox() 命令弹出提示,也可自行处理. public static string para; //软件内置自定义数据,只有登录成功才会返回. public static string qq;//客服QQ public static string deduct;//转绑扣除,计时模式为分钟,计点模式为点数. public static string type;//0 计时模式,1 计点模式 public static string loginimg;//登录图片 public static string website;//官网地址 public static string heartbeatTime;//自定义心跳时间 public static string clientIp;//客户端IP public static string state;//软件状态,0正常,1维护 public static string stateInfo;//维护说明. }; public struct g_fast { public static string para;//快验软件自定义常量 public static string clientIp;//客户端IP public static bool heartBeat; }; public struct g_user { public static string username;//用户名 public static string password;//密码 public static string endtime;//到期时间 public static int point;//点数余额 public static string para;//用户自定义常量 public static string loginToken;//登录Token public static string loginAuth;//登录令牌 public static string bind;//用户绑定资料 public static double balance;//通行证余额 public static string machineCode;//用户机器码 }; public struct g_errorMsg { public static string errorMsg; public static int errorCode; }; private static CookieContainer sendCookie = new CookieContainer(); //全局cookies,在取验证码时会自动更新. /// <summary> /// 初始化软件参数,必须最先执行(快验无需初始化). /// </summary> /// <param name="url">webAPI地址,后台添加软件后返回软件列表查看.</param> /// <param name="webkey">护卫盾官网-用户中心-我的授权 中获得</param> /// <param name="sid">软件ID,网页后台添加软件后获取</param> /// <param name="key">通讯秘钥, 网页后台添加软件后获取</param> /// <param name="clientRule">客户端sign算法,由后台添加软件时填写.</param> /// <param name="serverRule">服务端sign算法,由后台添加软件时填写.</param> /// <param name="moduleMD5">模块MD5值, 购买授权时获得.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_init(string url, string webkey, string sid, string key, string clientRule, string serverRule, string moduleMD5) { g_softPara.url = url; g_softPara.webkey = webkey; g_softPara.sid = sid; g_softPara.key = key; g_softPara.clientRule = clientRule; g_softPara.serverRule = serverRule; g_softPara.moduleMD5 = moduleMD5; g_softPara.clientId = getUUID(); g_user.machineCode = hwd_getMachineCode(); string data = "action=init"; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_soft.name = resJson["result"]["name"].ToString(); g_soft.login = resJson["result"]["login"].ToString(); g_soft.captcha = resJson["result"]["captcha"].ToString(); g_soft.version = resJson["result"]["version"].ToString(); g_soft.notice = resJson["result"]["notice"].ToString(); g_soft.para = resJson["result"]["para"].ToString();//软件自定义常量初始化为空,只有登录成功才会返回. g_soft.qq = resJson["result"]["qq"].ToString(); g_soft.deduct = resJson["result"]["deduct"].ToString(); g_soft.type = resJson["result"]["type"].ToString(); g_soft.loginimg = resJson["result"]["loginimg"].ToString(); g_soft.website = resJson["result"]["website"].ToString(); g_soft.heartbeatTime = resJson["result"]["heartbeatTime"].ToString(); g_soft.clientIp = resJson["result"]["clientip"].ToString(); g_soft.state = resJson["result"]["state"].ToString(); g_soft.stateInfo = resJson["result"]["stateinfo"].ToString(); return true; } return false; } /// <summary> /// 根据提交参数名,返回网页端设置的软件数据管理器中对应的版本信息,例如更新包地址、更新后版本号等 /// </summary> /// <param name="version">当前客户端版本号,如对应版本不存在,则返回最新版本对应参数.</param> /// <param name="name">updateUrl=更新包地址,newVer=更新后版本号,completeUrl=完整包下载地址,forceUpdate=是否强制更新(yes/no),visible=前台是否可见(yes/no),command=更新前后执行命令</param> /// <returns>string</returns> public static string hwd_getSoftVersionInfo(string version, string name) { JToken tmp = JToken.Parse(g_soft.version); JToken result = JToken.Parse("{}"); foreach (JToken temp in tmp) { if (temp["oldVer"].ToString() == version) { if(temp[name] == null) { return ""; } return temp[name].ToString(); } result = JToken.Parse(temp.ToString()); } if (result[name] == null) { return ""; } return result[name].ToString(); } /// <summary> /// 根据提交参数名,返回网页端设置的软件数据,例如软件名、客户端公告等 /// </summary> /// <param name="name">name=软件名,versioninfo=版本管理器中所有数据(json格式由旧到新排列),version=服务端最新版本号,heartbeattime=心跳时间,notice=客户端公告,qq=客服qq,website=官网地址,loginimg=登录页面图片,clientip=客户端IP地址,deduct=转绑扣除数量,login=登录方式(0:账号密码登录,1:充值卡登录),type=计费模式(0:计时,1:计点),para=软件自定义常量(注意,只有登录成功才能取到此值.),captcha=需要验证码的位置(如此值包含 captcha_login 需要登录验证码,包含 captcha_recharge 充值验证码,包含 captcha_reg 注册验证码,包含 captcha_repwd 改密验证码[同时包含发送邮件和修改密码]))</param> /// <returns>string</returns> public static string hwd_getSoftInfo(string name) { //这里多此一举了,你完全可以使用全局变量 g_soft.x获取软件资料,为了与文档匹配,以及如果使用核心库的话,参数获取习惯的熟练度,故加此获取方式。 string tmp = name; if (tmp == "name") { return g_soft.name; } else if (tmp == "versioninfo") { return g_soft.version; } else if (tmp == "version") { //获取服务端最新版本号,通过传入一个不存在的版本号获取最新版资料。 return hwd_getSoftVersionInfo("<!!!!>", "newVer"); } else if (tmp == "heartbeattime") { return g_soft.heartbeatTime; } else if (tmp == "notice") { return g_soft.notice; } else if (tmp == "qq") { return g_soft.qq; } else if (tmp == "website") { return g_soft.website; } else if (tmp == "loginimg") { return g_soft.loginimg; } else if (tmp == "clientip") { return g_soft.clientIp; } else if (tmp == "para") { return g_soft.para; } else if (tmp == "captcha") { return g_soft.captcha; } else if (tmp == "deduct") { return g_soft.deduct; } else if (tmp == "type") { return g_soft.type; } else if (tmp == "login") { return g_soft.login; } return ""; } /// <summary> /// 根据提交参数,返回软件自定义常量中指定节点的值,只有用户正常登陆,才会返回此值,如果用户到期,且"允许到期登陆",那么也会返回此值(也属于正常登陆).注意,如使用此命令,必须保证软件自定义常量为标准JSON格式 /// </summary> /// <param name="name">例 : 软件自定义常量为 {"提交地址":"xxx.com","version":"1.0"},则 : hwd_getSoftPara("提交地址"); 返回:xxx.com</param> /// <returns>string</returns> public static string hwd_getSoftPara(string name) { JToken tmp = JToken.Parse(g_soft.para); if (tmp[name] == null) { return ""; } return tmp[name].ToString(); } /// <summary> /// 获取验证码,登录、注册、充值、改密 都可通过此函数获取 /// </summary> /// <returns>Image</returns> public static Image hwd_getCaptchaImg() { string url = g_softPara.url.Substring(0, g_softPara.url.IndexOf("ac.php")) + "include/captcha_api.php" ; HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.CookieContainer = sendCookie; request.Method = "GET"; request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"; HttpWebResponse response = request.GetResponse() as HttpWebResponse; sendCookie.Add(response.Cookies); Stream responseStream = response.GetResponseStream(); MemoryStream memoryStream = new MemoryStream(); byte[] bArr = new byte[1024]; int size = responseStream.Read(bArr, 0, (int)bArr.Length); while (size > 0) { memoryStream.Write(bArr, 0, size); size = responseStream.Read(bArr, 0, (int)bArr.Length); Thread.Sleep(1); } Image outputImg = Image.FromStream(memoryStream); return outputImg; } /// <summary> /// 获取机器码,你可以自由发挥,此方式可区分物理机、VM虚拟机、以及virtualbox,同时适用32位与64位程序 /// </summary> /// <returns></returns> public static string hwd_getMachineCode() { //此方式不足之处是使用管理员模式运行和非管理员模式可能会取出不同结果,是否采用,自己衡量 string biosID = GetCmdInfo("wmic csproduct get uuid"); string baseID = GetCmdInfo("wmic baseboard get SerialNumber"); string memID = GetCmdInfo("wmic memphysical list brief"); string cpuID = GetCmdInfo("wmic cpu get processorid"); string tmp = biosID + baseID + memID + cpuID; tmp = tmp.Replace("\n", ""); tmp = tmp.Replace("\r", ""); tmp = tmp.Replace(" ", ""); tmp = getMD5(tmp); string ret = tmp.Substring(0, 8) + "-" + tmp.Substring(8, 4) + "-" + tmp.Substring(12, 4) + "-" + tmp.Substring(16, 4) + "-" + tmp.Substring(20); return ret; } /// <summary> /// 注册通行证. /// </summary> /// <param name="username">注册用户名</param> /// <param name="password">注册密码</param> /// <param name="email">绑定邮箱,取回密码唯一途径</param> /// <param name="referrer">推荐人账号,可空</param> /// <param name="code">如果 g_soft.captcha 中包含 "captcha_reg" , 则需要填写验证码,否则可留空.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_reg(string username, string password, string email, string referrer, string code) { string data = "action=user&fun=reg&username=" + username + "&password=" + password + "&mail=" + email + "&referrer=" + referrer + "&code=" + code; string result = httpPost(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 发送密码重置邮件. /// </summary> /// <param name="username">用户名</param> /// <param name="email">绑定邮箱</param> /// <param name="code">如果 g_soft.captcha 中包含 "captcha_repwd" , 则需要填写验证码,否则可留空.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_sendMail(string username, string email, string code) { string data = "action=user&fun=sendMail&username=" + username + "&mail=" + email + "&code=" + code; string result = httpPost(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 修改密码. /// </summary> /// <param name="username">用户名</param> /// <param name="password">新密码</param> /// <param name="mailcode">邮件验证码</param> /// <param name="code">如果 g_soft.captcha 中包含 "captcha_repwd" , 则需要填写验证码,否则可留空.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_resetPwd(string username, string password, string mailcode, string code) { string data = "action=user&fun=resetPwd&username=" + username + "&password=" + password + "&mailcode=" + mailcode + "&code=" + code; string result = httpPost(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 用户充值. /// </summary> /// <param name="username">欲充值的用户名</param> /// <param name="cardnum">充值卡号</param> /// <param name="code">如果 g_soft.captcha 中包含 "captcha_recharge" , 则需要填写验证码,否则可留空</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_recharge(string username, string cardnum, string code) { string data = "action=recharge&user=" + username + "&card=" + cardnum + "&code=" + code; string result = httpPost(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 添加黑名单. /// </summary> /// <param name="code">黑名单号码,可以是IP地址或机器码,IP地址:禁止一切访问(包括网站),机器码:禁止客户端访问(不包括网站,因为网站获取不到机器码,无法判断.)</param> /// <param name="remark">添加黑名单理由</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_addBlackList(string code, string remark) { string data = "action=addBlacklist&code=" + code + "&remark=" + remark; string result = httpPost(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 用户登录. /// </summary> /// <param name="username">账号密码模式为登录账号,充值卡登录为卡号.</param> /// <param name="password">账号密码模式为登录密码,充值卡登录无需填写.</param> /// <param name="code">如果 g_soft.captcha 中包含 "captcha_login" , 则需要填写验证码,否则可留空.</param> /// <param name="client_version">客户端版本号,传入此值可在后台“在线用户”中显示再用用户客户端版本号.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_login(string username, string password, string code,string client_version) { string data = "action=login&user=" + username + "&pwd=" + password + "&code=" + code + "&client_version=" + client_version; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_user.endtime = resJson["result"]["endtime"].ToString(); g_user.point = int.Parse(resJson["result"]["point"].ToString()); g_user.para = resJson["result"]["para"].ToString(); g_user.loginToken = resJson["result"]["loginToken"].ToString(); g_user.loginAuth = resJson["result"]["loginAuth"].ToString(); g_user.bind = resJson["result"]["bind"].ToString(); g_user.balance = double.Parse(resJson["result"]["balance"].ToString()); g_soft.para = resJson["result"]["softpara"].ToString(); return true; } else { return false; } } /// <summary> /// 获取登录用户信息,根据提交参数名,返回指定用户数据. /// </summary> /// <param name="name">username=用户名,password=密码,token=登录token(用于校验登录状态),auth=登录令牌,endtime=到期时间,point=点数余额,balance=账户余额,para=用户自定义数据,bind=用户绑定信息</param> /// <returns>string</returns> public static string hwd_getUserInfo(string name) { //这里多此一举了,你完全可以使用全局变量 g_user.x获取用户资料,为了与文档匹配,以及如果使用核心库的话,参数获取习惯的熟练度,故加此获取方式。 string tmp = name; if (tmp == "username") { return g_user.username; } else if (tmp == "password") { return g_user.password; } else if (tmp == "token") { return g_user.loginToken; } else if (tmp == "auth") { return g_user.loginAuth; } else if (tmp == "endtime") { return g_user.endtime; } else if (tmp == "point") { return g_user.point.ToString(); } else if (tmp == "balance") { return g_user.balance.ToString(); } else if (tmp == "para") { return g_user.para; } else if (tmp == "bind") { return g_user.bind; } return ""; } /// <summary> /// 根据提交参数,返回用户自定义常量中指定节点的值,只有用户正常登陆且未到期/有点数,才会返回此值.注意,如使用此命令,必须保证用户自定义常量为标准JSON格式 /// </summary> /// <param name="name">例 : 用户自定义常量为 {"版本":"普通版","高级功能":"ON"},则 : hwd_getUserPara("版本"); 返回:普通版</param> /// <returns>string</returns> public static string hwd_getUserPara(string name) { if(g_user.para == "") { return ""; } JToken tmp = JToken.Parse(g_user.para); if (tmp[name] == null) { return ""; } return tmp[name].ToString(); } /// <summary> /// 扣除点数,只有相同的point和remarks才会过滤,例如:hwd_deductPoint(1,"日费用",86400) 和 hwd_deductPoint(30,"月费用",2592000);这两个并不冲突,因为扣点数量和扣点备注均不同. /// </summary> /// <param name="point">扣除数量,最小为1点</param> /// <param name="remarks">扣点备注,管理可在后台查看,用户可在个人中心查看(请在"软件编辑"中开启"记录扣点日志")</param> /// <param name="interval">扣点间隔(单位:秒),0为不限,即每次都扣点.大于零代表指定间隔内不重复扣点,例如1天只扣一次点,那么间隔就是86400秒,需在软件后台开启:记录扣点日志().</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_deductPoint(int point, string remarks, int interval) { string data = "action=deductpoint&user=" + g_user.username + "&num=" + point.ToString() + "&msg=" + remarks + "&interval=" + interval.ToString(); string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_user.point = int.Parse(resJson["result"]["point"].ToString()); return true; } else { return false; } } /// <summary> /// 扣除时间,只有相同的minute和remarks才会过滤,例如:hwd_deductTime(1,"日费用",86400) 和 hwd_deductTime(30,"月费用",2592000);这两个并不冲突,因为扣时数量和扣时备注均不同. /// </summary> /// <param name="minute">扣除时间,单位:分钟,最小为1分钟</param> /// <param name="remarks">扣时备注,管理可在后台查看,用户可在个人中心查看(请在"软件编辑"中开启"记录扣点日志")</param> /// <param name="interval">扣时间隔(单位:秒),0为不限,即每次都扣时.大于零代表指定间隔内不重复扣时,例如1天只扣一次时,那么间隔就是86400秒,需在软件后台开启:记录扣点日志().</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_deductTime(int minute, string remarks, int interval) { string data = "action=deducttime&user=" + g_user.username + "&num=" + minute.ToString() + "&msg=" + remarks + "&interval=" + interval.ToString(); string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_user.endtime = resJson["result"]["endtime"].ToString(); return true; } else { return false; } } /// <summary> /// 扣余额,充值卡登录模式无效,只有相同的money和remarks才会过滤,例如:hwd_deductBalance(1,"日费用",86400) 和 hwd_deductBalance(33,"月费用",2592000);这两个并不冲突,因为扣除数量和扣除备注均不同. /// </summary> /// <param name="money">扣除金额,单位:元,最小为0.01元</param> /// <param name="remarks">扣除备注,管理可在后台查看,用户可在个人中心查看(请在"软件编辑"中开启"记录扣点日志")</param> /// <param name="interval">扣除间隔(单位:秒),0为不限,即每次都扣除.大于零代表指定间隔内不重复扣除,例如1天只扣一次余额,那么间隔就是86400秒,需在软件后台开启:记录扣点日志().</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_deductBalance(double money, string remarks, int interval) { string data = "action=deductbalance&user=" + g_user.username + "&num=" + money.ToString() + "&msg=" + remarks + "&interval=" + interval.ToString(); string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_user.balance = double.Parse(resJson["result"]["balance"].ToString()); return true; } else { return false; } } /// <summary> /// 绑定用户资料,例如配置云备份,绑定游戏号等.用户登录成功状态下,可使用hwd_getUserInfo("bind")获取此绑定资料. /// </summary> /// <param name="str">欲写入的数据,理论无长度限制,由于数据加密传输,数据越长加密时间越慢,因此不建议数据太大.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_setUserbind(string str) { string data = "action=bindstr&user=" + g_user.username + "&pwd=" + g_user.password + "&str=" + str; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_user.bind = str; return true; } else { return false; } } /// <summary> /// 绑定机器码,自动将指定账户绑定本机,无需传入机器码,自动获取,如已达到绑定上限,则删除最先绑定的机器码.转绑扣时扣点自动完成,无需独立扣除. /// </summary> /// <param name="username">欲绑定的用户名,无需传入机器码,机器码自动获取.</param> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_bindMachineCode(string username) { string data = "action=bind&user=" + username; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 退出登录,程序退出前可调用此命令,服务端立即更新用户状态,否则需要等待无心跳通讯后,才能判定用户退出 /// </summary> /// <returns>成功返回true , 失败返回false</returns> public static bool hwd_logout() { string data = "action=logout&user=" + g_user.username; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return true; } else { return false; } } /// <summary> /// 动态调用自定义函数(PHP语法) /// </summary> /// <param name="name">函数名,例如:function test($a,$b){return $a + $b},函数名为:test</param> /// <param name="para">参数值,例如:function test($a,$b){return $a + $b},参数值为:3,4 参数分隔符为英文半角逗号(,)</param> /// <returns></returns> public static string hwd_callPHP(string name, string para) { //分割参数 string[] tmp = para.Split(','); JArray jarray = new JArray(); //构造参数json数据 foreach (string val in tmp) { jarray.Add(val); } UTF8Encoding utf8 = new UTF8Encoding(); string param = jarray.ToString().Replace("\r\n", "").Replace(" ", ""); string urlEncode = UrlEncode(param); string data = "action=callPHP&fun=" + name + "¶=" + urlEncode + "&user=" + g_user.username; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { return resJson["result"]["result"].ToString(); } else { return ""; } } /// <summary> /// 心跳包,保持与服务器通讯.请注意,此命令有两种功能,1.单次心跳,2.循环心跳,具体请看参数<1>说明. /// </summary> /// <param name="time">心跳周期,单位:秒,为0则单次心跳,若大于0,则最小120秒,最大不限,只要调用过1次循环心跳,则程序退出前均有效,若自动心跳,则此处心跳时间必须与后台软件设置中的"心跳时间"相同.即使使用自动心跳,也可单独调用hwd_heartbeat(0)进行单次心跳.</param> /// <param name="loginAuth">登录令牌,主进程可留空,使用此令牌可在其它进程免登录心跳.</param> /// <returns></returns> public static bool hwd_heartbeat(int time,string loginAuth) { if (time > 0 && time < 120) time = 120; if (time > 0 && !g_softPara.autoHeartBeat) { g_softPara.autoHeartBeat = true; System.Timers.Timer t = new System.Timers.Timer(int.Parse(g_soft.heartbeatTime)*1000); t.Elapsed += new System.Timers.ElapsedEventHandler(heartBeatTimer); t.AutoReset = true; t.Enabled = true; } string data = "action=heartbeat&user=" + g_user.username; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { if (loginAuth != "") { g_user.username = resJson["result"]["user"].ToString(); g_user.password = resJson["result"]["password"].ToString(); g_user.loginToken = resJson["result"]["loginToken"].ToString(); g_softPara.clientId = resJson["result"]["clientId"].ToString(); } g_soft.para = resJson["result"]["softpara"].ToString(); g_user.para = resJson["result"]["para"].ToString(); g_user.bind = resJson["result"]["bind"].ToString(); g_user.endtime = resJson["result"]["endtime"].ToString(); g_user.point = int.Parse(resJson["result"]["point"].ToString()); g_user.balance = double.Parse(resJson["result"]["balance"].ToString()); return true; } else { g_soft.para = ""; g_user.para = ""; g_user.bind = ""; g_user.endtime = ""; g_user.point = 0; g_user.balance = 0; AutoClosingMessageBox.Show(g_errorMsg.errorMsg, "账户已离线", 10000); Process.GetCurrentProcess().Kill(); return false; } } /// <summary> /// 过滤掉字符串中的html标签,例如公告中的html标签. /// </summary> /// <param name="htmlStr">待过滤的html原字符串</param> /// <returns></returns> public static string hwd_htmlFilter(string htmlStr) { Regex math = new Regex(@"<[^>]*>|<\/[^>]*>"); string str = math.Replace(htmlStr,""); return str; } /// <summary> /// 快速验证,作者临时接单,一条命令快速接入验证,数据安全的前提下,防止被骗软件.此命令只需运行一次,程序结束前每隔几分钟自动校验一次. /// </summary> /// <param name="url">webAPI地址,后台添加软件后返回软件列表查看.</param> /// <param name="webkey">护卫盾官网-用户中心-我的授权 中获得</param> /// <param name="sid">软件ID,网页后台添加软件后获取</param> /// <param name="key">通讯秘钥,网页后台添加软件后获取</param> /// <param name="clientRule">客户端sign算法,由后台添加软件时填写.</param> /// <param name="serverRule">服务端sign算法,由后台添加软件时填写.</param> /// <param name="moduleMD5">模块MD5值,购买授权时获得.</param> /// <param name="fastPara">软件自定义常量,只要用户未付款,此处一定留空,将会联网验证.付款后将常量传入,将不再联网验证,也可在软件调试时使用.</param> /// <returns></returns> public static bool hwd_fastCheck(string url, string webkey, string sid, string key, string clientRule, string serverRule, string moduleMD5, string fastPara) { g_fast.para = fastPara; if (g_fast.para == "") { g_softPara.url = url; g_softPara.webkey = webkey; g_softPara.sid = sid; g_softPara.key = key; g_softPara.clientRule = clientRule; g_softPara.serverRule = serverRule; g_softPara.moduleMD5 = moduleMD5; g_softPara.clientId = getUUID(); g_user.machineCode = hwd_getMachineCode(); string data = "action=fast"; string result = hwd_post(data); JToken resJson = JToken.Parse(result); if (resJson["code"].ToString() == "200") { g_fast.para = resJson["result"]["para"].ToString(); g_fast.clientIp = resJson["result"]["clientIp"].ToString(); if (!g_fast.heartBeat) { g_fast.heartBeat = true; Random rd = new Random(); System.Timers.Timer t = new System.Timers.Timer(rd.Next(290, 310) * 1000); t.Elapsed += new System.Timers.ElapsedEventHandler(autoFastCheckTimer); t.AutoReset = true; t.Enabled = true; } return true; } else { if (resJson["code"].ToString() == "205") { Clipboard.SetDataObject(g_user.machineCode); AutoClosingMessageBox.Show(resJson["msg"].ToString(), "提示", 10000); } else { g_fast.para = ""; AutoClosingMessageBox.Show(resJson["msg"].ToString(), "提示", 10000); } Process.GetCurrentProcess().Kill(); return false; } } else { g_fast.para = fastPara; return true; } } /// <summary> /// 根据提交参数名,返回网页端设置的软件数据,例如快验软件自定义常量,客户端IP /// </summary> /// <param name="name">para=软件自定义常量,clientip=客户端IP</param> /// <returns></returns> public static string hwd_getFastInfo(string name) { string tmp = name; if (tmp == "para") { return g_fast.para; } else if (tmp == "clientip") { return g_fast.clientIp; } return ""; } /// <summary> /// 快速验证通过后,根据提交参数,返回快验自定义常量中指定节点的值,注意,如使用此命令,必须保证快验自定义常量为标准JSON格式,否则请使用hwd_getFastInfo(); 获取数据后自行处理. /// </summary> /// <param name="name">例 : 软件自定义常量为 {"提交地址":"xxx.com","version":"1.0"},则 : hwd_getFastPara("提交地址"); 返回:xxx.com</param> /// <returns></returns> public static string hwd_getFastPara(string name) { JToken tmp = JToken.Parse(g_fast.para); if(tmp[name] != null) { return tmp[name].ToString(); } return ""; } /// <summary> /// 获取文件MD5值 /// </summary> /// <param name="filename">获取MD5值完整文件路径</param> /// <returns></returns> public static string hwd_getFileMD5(string filename) { string filePath = filename; StringBuilder builder = new StringBuilder(); using (var md5 = new MD5CryptoServiceProvider()) { File.Copy(filePath, filePath + "e");//复制一份,防止占用 using (FileStream fs = new FileStream(filePath + "e", FileMode.Open)) { byte[] bt = md5.ComputeHash(fs); for (int i = 0; i < bt.Length; i++) { builder.Append(bt[i].ToString("x2")); } } File.Delete(filePath + "e");//删除复制的文件,这里没处理异常等.... } return builder.ToString(); } /// <summary> /// 获取字符串MD5值 /// </summary> /// <param name="str">获取MD5值的字符串</param> /// <returns></returns> public static string hwd_getStrMD5(string str) { return getMD5(str); } /// <summary> /// 自动心跳timmer /// </summary> /// <param name="source"></param> /// <param name="e"></param> protected static void heartBeatTimer(object source, System.Timers.ElapsedEventArgs e) { hwd_heartbeat(0,""); } /// <summary> /// 快验timmer /// </summary> /// <param name="source"></param> /// <param name="e"></param> protected static void autoFastCheckTimer(object source, System.Timers.ElapsedEventArgs e) { hwd_fastCheck(g_softPara.url, g_softPara.webkey, g_softPara.sid, g_softPara.key, g_softPara.clientRule, g_softPara.serverRule, g_softPara.moduleMD5, ""); } /// <summary> /// aesEncrypt /// </summary> /// <param name="encryptStr"></param> /// <returns></returns> protected static string aesEncrypt(string encryptStr) { var _aes = new AesCryptoServiceProvider(); _aes.BlockSize = 128; _aes.KeySize = 256; _aes.Key = Encoding.UTF8.GetBytes(g_softPara.key); _aes.IV = Encoding.UTF8.GetBytes(g_softPara.key.Substring(0,16)); _aes.Padding = PaddingMode.PKCS7; _aes.Mode = CipherMode.CBC; var _crypto = _aes.CreateEncryptor(_aes.Key, _aes.IV); byte[] encrypted = _crypto.TransformFinalBlock(Encoding.UTF8.GetBytes(encryptStr), 0, Encoding.UTF8.GetBytes(encryptStr).Length); _crypto.Dispose(); return BitConverter.ToString(encrypted, 0).Replace("-", string.Empty).ToLower(); } /// <summary> /// aesDecrypt /// </summary> /// <param name="decryptStr"></param> /// <returns></returns> protected static string aesDecrypt(string decryptStr) { var _aes = new AesCryptoServiceProvider(); _aes.BlockSize = 128; _aes.KeySize = 256; _aes.Key = Encoding.UTF8.GetBytes(g_softPara.key); _aes.IV = Encoding.UTF8.GetBytes(g_softPara.key.Substring(0,16)); _aes.Padding = PaddingMode.None; _aes.Mode = CipherMode.CBC; if ((decryptStr.Length % 2) != 0) decryptStr += " "; byte[] returnBytes = new byte[decryptStr.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) { returnBytes[i] = Convert.ToByte(decryptStr.Substring(i * 2, 2), 16); } var _crypto = _aes.CreateDecryptor(_aes.Key, _aes.IV); byte[] decrypted = _crypto.TransformFinalBlock(returnBytes, 0, returnBytes.Length); _crypto.Dispose(); return Encoding.UTF8.GetString(decrypted); } /// <summary> /// 发包函数 /// </summary> /// <param name="param"></param> /// <returns></returns> private static string hwd_post(string param) { int reConnectTime = 0; TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); string t = Convert.ToInt64(ts.TotalSeconds).ToString(); string token = getMD5(g_softPara.sid + g_softPara.key + t); string uuid = getUUID(); param += "&sid=" + g_softPara.sid + "&uuid=" + uuid + "&t=" + t + "&m1=" + token + "&m2=" + getMd5ByMyself() + "&m3=" + g_softPara.moduleMD5 + "&mcode=" + g_user.machineCode + "&webkey=" + g_softPara.webkey + "&clientid=" + g_softPara.clientId; string[] arr = param.Split('&'); string tmp = "", sign = "", data = ""; JToken json = JToken.Parse("{}"); //将提交参数转为JSON格式. foreach (string s in arr) { json[strLeft(s, "=")] = strRight(s, "="); } // 由于护卫盾兼容多重语言,不同语言支持不同的padding方式,故我们将数据块补齐,不让他padding。 string jsonStr = json.ToString(); while(jsonStr.Length % 16 != 0) { jsonStr += " ";//如果数据块不是16的整数倍,就补充一个空格,直到是为止。 } tmp = aesEncrypt(json.ToString()); string clientRule = g_softPara.clientRule; clientRule = clientRule.Replace("[data]", tmp); clientRule = clientRule.Replace("[key]", g_softPara.key); sign = getMD5(clientRule); data = "data=" + tmp + "&sign=" + sign; string tmp1; do { //发送请求,尝试三次机会,如都失败,代表网络连接失败 tmp1 = httpPost(data); if (tmp1 == "") { Thread.Sleep(150000); } reConnectTime++; } while (reConnectTime <= 3 && tmp1 == ""); if (tmp1 == "") { MessageBox.Show("网络连接失败,请稍后再试。", "连接失败"); Process.GetCurrentProcess().Kill(); } if (tmp1 == "Sign Error") { MessageBox.Show("数据签名校验失败,请检查。", "Sign Error"); Process.GetCurrentProcess().Kill(); } //获取返回密文并解析json JToken res = JToken.Parse(tmp1); string resData = res["data"].ToString(); string resSign = res["sign"].ToString(); string serverRule = g_softPara.serverRule; serverRule = serverRule.Replace("[data]", resData); serverRule = serverRule.Replace("[key]", g_softPara.key); if(getMD5(serverRule) != resSign) { MessageBox.Show("封包签名校验失败,请检查。", "Sign Error"); Process.GetCurrentProcess().Kill(); } //解密数据 resData = aesDecrypt(resData); JToken resJson = JToken.Parse(resData); g_errorMsg.errorCode = int.Parse(resJson["code"].ToString()); g_errorMsg.errorMsg = resJson["msg"].ToString(); //校验UUID,如果不同,则表示封包中途被篡改. if (uuid != resJson["uuid"].ToString()) { return ""; } //校验token,如果不同,则表示封包中途被篡改. token = getMD5(token + resJson["t"].ToString()); if (token != resJson["token"].ToString()) { return ""; } JToken result = JToken.Parse("{}"); if (string.IsNullOrEmpty(resJson["result"].ToString()) == false) { //计算数据返回完整内容token, result = JToken.Parse(resJson["result"].ToString()); string temp2 = ""; foreach (JToken temp in result) { var temp1 = temp as JProperty; if (temp1 != null) { temp2 += temp1.Name + "" + temp1.Value; } } string result_token = getMD5(temp2 + g_softPara.key); if (result_token != resJson["result_token"].ToString()) { return ""; } } return resJson.ToString(); } /// <summary> /// 取UUID /// </summary> /// <returns></returns> private static string getUUID() { string uuid = System.Guid.NewGuid().ToString(); return uuid; } /// <summary> /// 取字符串MD5 /// </summary> /// <param name="str"></param> /// <returns></returns> private static string getMD5(string str) { string result = ""; MD5 md5 = MD5.Create(); byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); for (int i = 0; i < s.Length; i++) { result = result + s[i].ToString("x2"); } return result; } /// <summary> /// POST请求 /// </summary> /// <param name="data"></param> /// <returns></returns> private static string httpPost(string data) { byte[] bArr = ASCIIEncoding.UTF8.GetBytes(data); HttpWebRequest request = WebRequest.Create(g_softPara.url) as HttpWebRequest; request.CookieContainer = sendCookie; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = bArr.Length; request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"; Stream postStream = request.GetRequestStream(); postStream.Write(bArr, 0, bArr.Length); postStream.Close(); //发送请求并获取相应回应数据 HttpWebResponse response = request.GetResponse() as HttpWebResponse; sendCookie.Add(response.Cookies); //直到request.GetResponse()程序才开始向目标网页发送Post请求 Stream responseStream = response.GetResponseStream(); //返回结果网页(html)代码 MemoryStream memoryStream = new MemoryStream(); bArr = new byte[1024]; int size = responseStream.Read(bArr, 0, (int)bArr.Length); while (size > 0) { memoryStream.Write(bArr, 0, size); size = responseStream.Read(bArr, 0, (int)bArr.Length); Thread.Sleep(1); } string content = Encoding.UTF8.GetString(memoryStream.ToArray()); return content; } /// <summary> /// 取自身MD5值 /// </summary> /// <returns></returns> private static string getMd5ByMyself() { string filePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; StringBuilder builder = new StringBuilder(); using (var md5 = new MD5CryptoServiceProvider()) { File.Copy(filePath, filePath + "e");//复制一份,防止占用 using (FileStream fs = new FileStream(filePath + "e", FileMode.Open)) { byte[] bt = md5.ComputeHash(fs); for (int i = 0; i < bt.Length; i++) { builder.Append(bt[i].ToString("x2")); } } File.Delete(filePath + "e");//删除复制的文件,这里没处理异常等.... } return builder.ToString(); } /// <summary> /// URL编码 /// </summary> /// <param name="url"></param> /// <returns></returns> private static string UrlEncode(string url) { var result = HttpUtility.UrlEncode(url); return result; } /// <summary> /// URL解码 /// </summary> /// <param name="url"></param> /// <returns></returns> private static string UrlDecode(string url) { var result = HttpUtility.UrlDecode(url); return result; } /// <summary> /// 取字符串左边 /// </summary> /// <param name="str"></param> /// <param name="left"></param> /// <returns></returns> private static string strLeft(string str, string left) { int length = str.IndexOf(left); string result = str.Substring(0, length); return result; } /// <summary> /// 取字符串右边 /// </summary> /// <param name="str"></param> /// <param name="right"></param> /// <returns></returns> private static string strRight(string str, string right) { int start = str.IndexOf(right) + 1; string result = str.Substring(start, str.Length - start); return result; } /// <summary> /// 取CMD返回值,用于获取机器码,如果你自己写机器码,此函数可以删除。 /// </summary> /// <param name="str"></param> /// <returns></returns> static string GetCmdInfo(string str) { Process pro = null; string ll = string.Empty; try { pro = new Process(); pro.StartInfo.FileName ="cmd.exe"; //cmd pro.StartInfo.UseShellExecute = false; //不显示shell pro.StartInfo.CreateNoWindow = true; //不创建窗口 pro.StartInfo.RedirectStandardInput = true; //打开流输入 pro.StartInfo.RedirectStandardOutput = true; //打开流输出 pro.StartInfo.RedirectStandardError = true; //打开错误流 pro.Start();//执行 pro.StandardInput.WriteLine(str + "&exit"); //&exit运行完立即退出 pro.StandardInput.AutoFlush = true; //清缓存 ll = pro.StandardOutput.ReadToEnd(); //读取输出 pro.WaitForExit(); //等待程序执行完退出进程 pro.Close();//结束 return ll; } catch (Exception ex) { Console.WriteLine("ExceptionOccurred:{ 0},{ 1}", ex.Message, ex.StackTrace.ToString()); return null; } } /// <summary> /// 定时关闭提示框 /// </summary> public class AutoClosingMessageBox { System.Threading.Timer _timeoutTimer; string _caption; AutoClosingMessageBox(string text, string caption, int timeout) { _caption = caption; _timeoutTimer = new System.Threading.Timer(OnTimerElapsed, null, timeout, System.Threading.Timeout.Infinite); MessageBox.Show(text, caption); } public static void Show(string text, string caption, int timeout) { new AutoClosingMessageBox(text, caption, timeout); } void OnTimerElapsed(object state) { IntPtr mbWnd = FindWindow(null, _caption); if (mbWnd != IntPtr.Zero) SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); _timeoutTimer.Dispose(); } const int WM_CLOSE = 0x0010; [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); } } } ``` 4. 简易登录窗口,如图  5. 初始化 ``` private void Form1_Load(object sender, EventArgs e) { bool state = hwd.hwd_init( "http://test.huweidun.cn/ac.php?s=52e4f9c09c609ac2578c285fcf2d1029", "943e508419c4cd486ab894d3f7dbee50", "c1162b61-fa71-4214-b66b-014ae6b0a99a", "GorgBdTnRDYxQGxKC9pYB42O933Pzxx4", "[data]123[key]abc", "[data]cba[key]321", "a0368bba05140b66e8172247da2650ab" ); if (!state) { MessageBox.Show(hwd.g_errorMsg.errorMsg.ToString(), "初始化失败"); return; } //校验版本号与调用自动更新程序 string clientVersion = "1.3"; string serverVersion = hwd.hwd_getSoftVersionInfo("<!!!>", "newVer"); if (serverVersion != clientVersion) { string updateFile = "./update.exe"; if (!File.Exists(updateFile)) { if (MessageBox.Show("发现新版本,自动更新程序不存在,是否打开浏览器下载新版本?", "发现新版本", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { string completeUrl = hwd.hwd_getSoftVersionInfo(clientVersion, "completeUrl"); System.Diagnostics.Process.Start(completeUrl); Process.GetCurrentProcess().Kill(); } } else { if (MessageBox.Show("发现新版本,是否启动自动更新程序?", "发现新版本", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { JToken json = JToken.Parse("{}"); json["path"] = Application.StartupPath; json["updateUrl"] = hwd.hwd_getSoftVersionInfo(clientVersion, "updateUrl"); json["completeUrl"] = hwd.hwd_getSoftVersionInfo(clientVersion, "completeUrl"); json["command"] = hwd.hwd_getSoftVersionInfo(clientVersion, "command"); StreamWriter sw = new StreamWriter("./update.tmp"); sw.Write(json.ToString()); sw.Close(); ShellExecute(IntPtr.Zero,"open", json["path"].ToString()+@"\update.exe", "update",null,1); Process.GetCurrentProcess().Kill(); } } //如果强制更新,到这里代表没有更新,直接退出。 if(hwd.hwd_getSoftVersionInfo(clientVersion, "forceUpdate") == "yes") { Process.GetCurrentProcess().Kill(); } } //如果需要登录验证码,则读取。 if(hwd.g_soft.captcha.IndexOf("captcha_login") > -1) { pictureBox1.Image = hwd.hwd_getCaptchaImg(); } } ``` 5. 登录 ``` private void button1_Click(object sender, EventArgs e) { if(hwd.hwd_login(username.Text, password.Text, code.Text)) { hwd.g_user.username = username.Text; hwd.g_user.password = password.Text; //登录成功,校验一下登录token string userToken = hwd.hwd_getStrMD5(hwd.g_user.username + hwd.g_user.password + hwd.g_softPara.key); if (userToken != hwd.hwd_getUserInfo("token")) { //登录成功,但校验失败,一定有问题,执行你的惩罚代码。 Process.GetCurrentProcess().Kill(); } this.Hide(); Form2 from2 = new Form2(); from2.ShowDialog(); this.Close(); } else { //如果登录失败且开启了绑定机器码,则需要对失败原因进行处理,209:已绑定满,需要转绑,扣除时间后台设置。261:未绑定满,免费绑定 string type = hwd.g_soft.type == "0" ? "分钟" : "点"; DialogResult cState = DialogResult.Cancel; if (hwd.g_errorMsg.errorCode == 209) { string msgStr = "是否将账号绑定至本机?\n\n转绑将扣除:" + hwd.g_soft.deduct + type + "\n\n如您已绑定多台机器,将自动解绑最先绑定的机器。\n\n点击 '是' 键自动绑定至本机。"; cState = MessageBox.Show(msgStr, "绑定提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); } else if (hwd.g_errorMsg.errorCode == 261) { string msgStr = "是否将账号绑定至本机?\n\n由于未达到满额绑定,本次绑定免费。\n\n点击 '是' 键自动绑定至本机。"; cState = MessageBox.Show(msgStr, "绑定提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); } if (cState == DialogResult.OK) { if (hwd.hwd_bindMachineCode(hwd.g_user.username) == true) { MessageBox.Show("绑定成功,请重新登录。", "绑定提示"); return; } else { MessageBox.Show(hwd.g_errorMsg.errorMsg, "绑定提示"); return; } } //如果不是209或261错误,则直接提示用户。 MessageBox.Show(hwd.g_errorMsg.errorMsg, "登录失败"); //如果服务端开启登录验证码,则刷新验证码 if (hwd.g_soft.captcha.IndexOf("captcha_login") > -1) { pictureBox1.Image = hwd.hwd_getCaptchaImg() ; } } } ``` 6. 载入主窗口,窗口功能为: 
管理员
Feb. 24, 2022, 11:53 a.m.
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
冀ICP备19021017号-14
冀公网安备 13108202000785号
Markdown文件
PDF文档
PDF文档(打印)
分享
链接
类型
密码
更新密码