public class initWeChatLogin
{
static string uuid = "";
static string successUrl = "";//登陸成功後返回的路徑
static string skey = "";
static string wxsid = "";
static string wxuin = "";
static string pass_ticket = "";
static string isgrayscale = "";
static string DeviceID = "";
public static JObject BaseResponse;//聯繫人字符串
static string MsgID = "";
public static string webwx_data_ticket = "";
public initWeChatLogin()
{
uuid = "";
successUrl = "";
skey = "";
wxsid = "";
wxuin = "";
pass_ticket = "";
isgrayscale = "";
DeviceID = "";
BaseResponse = null;
MsgID = "";
webwx_data_ticket = "";
}
/// <summary>
/// 獲取登陸二維碼
/// </summary>
/// <returns></returns>
public static Bitmap GetLoginQrcode()
{
Bitmap loginQrcode = null;
try
{
long Timestamps = Common.ConvertDateTimeToInt(DateTime.Now);
//獲得uuid
string LoginJson_1 = Common.doGet("https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=" + Timestamps);
uuid = LoginJson_1.Substring(LoginJson_1.IndexOf("window.QRLogin.uuid =") + "window.QRLogin.uuid =".Length);
uuid = uuid.Replace("\"", "");
uuid = uuid.Replace(";", "").Trim();
//獲得登陸的二維碼
loginQrcode = (Bitmap)Image.FromStream(WebRequest.Create(("https://login.weixin.qq.com/qrcode/" + uuid).Trim()).GetResponse().GetResponseStream());
}
catch (Exception ex)
{
Common.ErrorLog(ex, "GetLoginQrcode");
}
return loginQrcode;
}
/// <summary>
/// 獲取登陸成功後的路徑
/// </summary>
/// <returns></returns>
public static string GetLoginSuccessUrl()
{
string url = "";
int random = new Random().Next(100000000, 999999999);
long Timestamps = Common.ConvertDateTimeToInt(DateTime.Now);
string json = Common.doGet("https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=" + uuid + "&tip=0&r=" + random + "&_=" + Timestamps);
if (string.IsNullOrEmpty(json))
{
json = Common.doGet("https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=" + uuid + "&tip=0&r=" + random + "&_=" + Timestamps);
}
var code = json.Substring(json.IndexOf("window.code=") + "window.code=".Length, 3);
if (code.Trim() == "200")
{
if (json.IndexOf("https") != -1)
{
url = json.Substring(json.IndexOf("redirect_uri=") + "redirect_uri=".Length);
url = url.Replace("\"", "");
url = url.Replace(";", "").Trim();
successUrl = url;
}
}
return url;
}
/// <summary>
/// 獲取微信用戶信息
/// </summary>
public static void GetWeChatUserInfo()
{
string json = Common.HttpPostGetCookie(successUrl + "&fun=new&version=v2","");
if (Common.GetXmlConfig("ret", json) == "0")
{
skey = Common.GetXmlConfig("skey", json);
wxsid = Common.GetXmlConfig("wxsid", json);
wxuin = Common.GetXmlConfig("wxuin", json);
pass_ticket = Common.GetXmlConfig("pass_ticket", json);
isgrayscale = Common.GetXmlConfig("isgrayscale", json);
}
else
{
MessageBox.Show(Common.GetXmlConfig("message", json));
}
}
/// <summary>
/// 初始化微信獲取聯繫人信息
/// </summary>
/// <returns></returns>
public static string webwxinit()
{
int random = new Random().Next(100000000, 999999999);web
string parment = "";json
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);數組
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("BaseRequest", BaseRequest);微信
parment = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
string json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=" + random + "&pass_ticket=" + pass_ticket, parment);cookie
BaseResponse = JObject.Parse(json);
if (BaseResponse["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=" + random + "&pass_ticket=" + pass_ticket, parment);
BaseResponse = JObject.Parse(json);
}
return json;
}
/// <summary>
/// 開啓消息通知狀態
/// </summary>
/// <returns></returns>
public static void webwxstatusnotify()
{
int random = new Random().Next(100000000, 999999999);
string parment = "";app
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);dom
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("BaseRequest", BaseRequest);
dic.Add("ClientMsgId", Common.ConvertDateTimeToInt(DateTime.Now));
dic.Add("Code", 3);
dic.Add("FromUserName", BaseResponse["User"]["UserName"].ToString());
dic.Add("ToUserName", BaseResponse["User"]["UserName"].ToString());
parment = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
string json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=" + pass_ticket, parment);async
JObject obj = JObject.Parse(json);
if (obj["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=" + pass_ticket, parment);
obj = JObject.Parse(json);
}
MsgID = obj["MsgID"].ToString();
}
///// <summary>
///// 請求羣組列表
///// </summary>
//public static void webwxbatchgetcontact()
//{
// int random = new Random().Next(100000000, 999999999);
// string parment = "";
// Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
// BaseRequest.Add("Uin", wxuin);
// BaseRequest.Add("Sid", wxsid);
// BaseRequest.Add("Skey", skey);
// DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
// BaseRequest.Add("DeviceID", DeviceID);ide
// Dictionary<string, object> dic = new Dictionary<string, object>();
// dic.Add("BaseRequest", BaseRequest);工具
// string json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=" + random + "&lang=zh_CN&pass_ticket="+pass_ticket, parment);
//}
static string webwxsyncparment = "";
public static JObject webwxsyncsObj;
/// <summary>
/// 獲取消息
/// </summary>
public static webwxsync webwxsyncs()
{
//if (string.IsNullOrEmpty(webwxsyncparment))
//{
int random = new Random().Next(100000000, 999999999);
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("BaseRequest", BaseRequest);
dic.Add("SyncKey", BaseResponse["SyncKey"]);
webwxsyncparment = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
// }
string json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=" + wxsid + "&skey=" + skey + "&lang=zh_CN&pass_ticket=" + pass_ticket, webwxsyncparment);
webwxsyncsObj = JObject.Parse(json);
if (webwxsyncsObj["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=" + wxsid + "&skey=" + skey + "&lang=zh_CN&pass_ticket=" + pass_ticket, webwxsyncparment);
webwxsyncsObj = JObject.Parse(json);
}
return JsonConvert.DeserializeObject<webwxsync>(json);
}
/// <summary>
/// 發消息
/// </summary>
/// <param name="ToUserName"></param>
/// <param name="Msg"></param>
/// <param name="Types">消息類型</param>
public static void webwxsendmsg(string ToUserName, string Msg)
{
try
{
bool fig = false;
string parment = "";
int random = new Random().Next(100000000, 999999999);
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("BaseRequest", BaseRequest);
var msgId = Common.ConvertDateTimeToInt(DateTime.Now).ToString() + (new Random().Next(1000, 9999).ToString());
Dictionary<string, object> dicMsg = new Dictionary<string, object>();
dicMsg.Add("ClientMsgId", msgId);
dicMsg.Add("Content", Msg);
dicMsg.Add("FromUserName", BaseResponse["User"]["UserName"].ToString());
dicMsg.Add("LocalID", msgId);
dicMsg.Add("ToUserName", ToUserName);
dicMsg.Add("Type", 1);
dic.Add("Msg", dicMsg);
dic.Add("Scene", 0);
parment = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
string json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=" + pass_ticket, parment);
var obj = JObject.Parse(json);
if (obj["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=" + pass_ticket, parment);
obj = JObject.Parse(json);
fig = true;
}
else
{
fig = true;
}
}
catch (Exception ex)
{
if (ex.Message.IndexOf("操做超時") != -1)
{
webwxsendmsg(ToUserName, Msg);
}
}
}
/// <summary>
/// 發送圖片
/// </summary>
/// <param name="ToUserName">接收人</param>
/// <param name="MediaId">圖片ID</param>
/// <returns></returns>
public static bool webwxsendemoticon(string ToUserName, string MediaId)
{
bool fig = false;
string parment = "";
int random = new Random().Next(100000000, 999999999);
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);
var msgId = Common.ConvertDateTimeToInt(DateTime.Now).ToString() + (new Random().Next(10000, 99999).ToString());
Dictionary<string, object> dicMsg = new Dictionary<string, object>();
dicMsg.Add("ClientMsgId", msgId);
dicMsg.Add("Content", "");
dicMsg.Add("FromUserName", BaseResponse["User"]["UserName"].ToString());
dicMsg.Add("LocalID", msgId);
dicMsg.Add("MediaId", MediaId);
dicMsg.Add("ToUserName", ToUserName);
dicMsg.Add("Type", 3);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("BaseRequest", BaseRequest);
dic.Add("Msg", dicMsg);
dic.Add("Scene", 0);
parment = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
string json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket=" + pass_ticket, parment);
var obj = JObject.Parse(json);
if (obj["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket=" + pass_ticket, parment);
obj = JObject.Parse(json);
fig = true;
}
else
{
fig = true;
}
return fig;
}
/// <summary>
/// 檢查微信狀態
/// </summary>
public static JObject synccheck()
{
int random = new Random().Next(100000000, 999999999);
DeviceID = "e" + (random.ToString() + (new Random().Next(100000, 999999).ToString()));
StringBuilder sb = new StringBuilder();
for (var i = 0; i < BaseResponse["SyncKey"]["List"].Count(); i++)
{
var item = BaseResponse["SyncKey"]["List"][i];
sb.Append(item["Key"].ToString() + "_" + item["Val"] + "|");
}
string syncKey = (sb.ToString().Substring(0, sb.ToString().Length - 1));
StringBuilder parment = new StringBuilder();
parment.Append("?r=" + Common.ConvertDateTimeToInt(DateTime.Now));
parment.Append("&skey=" + HttpUtility.UrlEncode(skey));
parment.Append("&sid=" + wxsid);
parment.Append("&uin=" + wxuin);
parment.Append("&deviceid=" + DeviceID);
parment.Append("&synckey=" + HttpUtility.UrlEncode(syncKey).ToUpper());
parment.Append("&_=" + Common.ConvertDateTimeToInt(DateTime.Now));
string json = Common.doGet("https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck" + parment.ToString());
json = json.Replace("window.synccheck", "");
json = json.Replace("=", "");
return JObject.Parse(json);
}
public static JObject contactObj;
/// <summary>
/// 返回羣信息
/// </summary>
/// <param name="ToUserName">羣ID</param>
/// <returns></returns>
public static void webwxbatchgetcontact(string ToUserName, string AddUserName = "")
{
if (!string.IsNullOrEmpty(ToUserName))
{
Dictionary<string, object> dicParment = new Dictionary<string, object>();
int random = new Random().Next(100000000, 999999999);
Dictionary<string, object> BaseRequest = new Dictionary<string, object>();
BaseRequest.Add("Uin", wxuin);
BaseRequest.Add("Sid", wxsid);
BaseRequest.Add("Skey", skey);
DeviceID = "e" + (random.ToString() + (new Random().Next(10000, 99999).ToString()));
BaseRequest.Add("DeviceID", DeviceID);
List<object> list = new List<object>();
//根據羣找尋對應的羣成員信息
for (var i = 0; i < BaseResponse["ContactList"].Count(); i++)
{
var item = BaseResponse["ContactList"][i];
if (item["UserName"].ToString().IndexOf(ToUserName) != -1)
{
if(!string.IsNullOrEmpty(AddUserName))
{
JObject obj = JObject.Parse("{\"Uin\":0,\"UserName\":\""+AddUserName+"\",\"NickName\":\"\",\"AttrStatus\":0,\"PYInitial\":\"\",\"PYQuanPin\":\"\",\"RemarkPYInitial\":\"\",\"RemarkPYQuanPin\":\"\",\"MemberStatus\":0,\"DisplayName\":\"\",\"KeyWord\":\"\"}");
item["MemberList"].Last.AddAfterSelf(obj);
}
for (var j = 0; j < item["MemberList"].Count(); j++)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("EncryChatRoomId", ToUserName);
dic.Add("UserName", item["MemberList"][j]["UserName"].ToString());
list.Add(dic);
}
break;
}
}
dicParment.Add("BaseRequest", BaseRequest);
dicParment.Add("Count", list.Count);
dicParment.Add("List", list);
string parment = Newtonsoft.Json.JsonConvert.SerializeObject(dicParment);
string json = Common.PostMoths("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=" + Common.ConvertDateTimeToInt(DateTime.Now) + "&pass_ticket=" + pass_ticket, parment);
contactObj = JObject.Parse(json);
if (contactObj["BaseResponse"]["Ret"].ToString() != "0")
{
json = Common.PostMoths("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=" + Common.ConvertDateTimeToInt(DateTime.Now) + "&pass_ticket=" + pass_ticket, parment);
contactObj = JObject.Parse(json);
}
}
else
{
contactObj = null;
}
}
/// <summary>
/// 圖片上傳類
/// </summary>
/// <param name="fileUrl"></param>
/// <param name="from"></param>
/// <returns></returns>
public static string WxUploadImage(string fileUrl, string from)
{
byte[] img = Common.GetFileData(fileUrl);
try
{
var ClientMediaId = Common.ConvertDateTimeToInt(DateTime.Now).ToString() + (new Random().Next(1000, 9999).ToString());
#region 變量
string BoundStr = "-----------------------------143021075525875";//根據抓包生成
StringBuilder UploadBuf = new StringBuilder();
#endregion
#region 頭部數據
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"id\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("WU_FILE_0\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"name\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("untitled1.jpg\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"type\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("image/jpeg\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"lastModifiedDate\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("Sat Apr 22 2017 15:59:04 GMT+0800 (中國標準時間)\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"size\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append(img.Length + "\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"mediatype\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("pic\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"uploadmediarequest\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append("{\"UploadType\":2,\"BaseRequest\":{\"Uin\":" + wxuin + ",\"Sid\":\"" + wxsid + "\",\"Skey\":\"" +skey + "\"");
UploadBuf.Append(",\"DeviceID\":\"e995465833539115\"},\"ClientMediaId\":" + ClientMediaId + ",\"TotalLen\":" + img.Length + ",\"StartPos\":0,\"DataLen\"");
UploadBuf.Append(":" + img.Length + ",\"MediaType\":4,\"FromUserName\":\"" + BaseResponse["User"]["UserName"].ToString() + "\",\"ToUserName\":\"" + from + "\",\"FileMd5\"");
UploadBuf.Append(":\"" + GetMD5Hash(img) + "\"}\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"webwx_data_ticket\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append(webwx_data_ticket + "\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"pass_ticket\"\r\n");
UploadBuf.Append("\r\n");
UploadBuf.Append(pass_ticket + "\r\n");
UploadBuf.Append(BoundStr + "\r\n");
UploadBuf.Append("Content-Disposition: form-data; name=\"filename\"; filename=\"untitled1.jpg\"\r\n");
UploadBuf.Append("Content-Type: image/jpeg\r\n");
UploadBuf.Append("\r\n");
byte[] HeadBytes = Encoding.ASCII.GetBytes(UploadBuf.ToString());
#endregion
#region 圖片數據
byte[] PicBytes = img;
#endregion
#region 尾部數據
UploadBuf.Clear();
UploadBuf.Append("\r\n" + BoundStr + "--");
UploadBuf.Append("\r\n");
byte[] TailBytes = Encoding.ASCII.GetBytes(UploadBuf.ToString());
#endregion
#region 數組拼接
byte[] UploadBuffers = null;
UploadBuffers = ComposeArrays(HeadBytes, PicBytes);
UploadBuffers = ComposeArrays(UploadBuffers, TailBytes);
#endregion
Console.WriteLine("------------------------------------調試cookie");
Console.WriteLine("");
#region 上傳
HttpHelper Http = new HttpHelper();
HttpItem item = null;
HttpResult result = null;
item = new HttpItem()
{
URL = "https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json",
Method = "POST",
Accept = "/",
Referer = " https://wx.qq.com/",
ContentType = " multipart/form-data; boundary=" + BoundStr.Substring(2),
PostDataType = PostDataType.Byte,
PostEncoding = Encoding.UTF8,
PostdataByte = UploadBuffers
};
item.Header.Add("Origin", " https://wx.qq.com");
result = Http.GetHtml(item);
#endregion
JObject json = JObject.Parse(result.Html);
if (json["BaseResponse"]["Ret"].ToString() == "0")
{
return json["MediaId"].ToString();
}
else
{
item = new HttpItem()
{
URL = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json",
Method = "POST",
Accept = "/",
Referer = " https://wx.qq.com/",
ContentType = " multipart/form-data; boundary=" + BoundStr.Substring(2),
PostDataType = PostDataType.Byte,
PostEncoding = Encoding.UTF8,
PostdataByte = UploadBuffers
};
item.Header.Add("Origin", " https://wx.qq.com");
result = Http.GetHtml(item);
json = JObject.Parse(result.Html);
if (json["BaseResponse"]["Ret"].ToString() == "0")
{
return json["MediaId"].ToString();
}
else
{
return "";
}
}
}
catch
{
return null;
}
}
#region 數組組合
public static byte[] ComposeArrays(byte[] Array1, byte[] Array2)
{
byte[] Temp = new byte[Array1.Length + Array2.Length];
Array1.CopyTo(Temp, 0);
Array2.CopyTo(Temp, Array1.Length);
return Temp;
}
#endregion
/// <summary>
/// 計算字符串MD5
/// </summary>
/// <param name="bytedata"></param>
/// <returns></returns>
public static string GetMD5Hash(byte[] bytedata)
{
try
{
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(bytedata);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("GetMD5Hash() fail,error:" + ex.Message);
}
}
}
HttpHelper 和HttpResult爲http幫助類可見我另一篇文章
https://blog.csdn.net/weixin_39349390/article/details/90041280
若有問題也能夠加QQ羣討論:
技術羣 710217654