Пример #1
0
 /// <summary>
 /// 异步登出客户端
 /// </summary>
 public void LogoutAsync()
 {
     Task.Factory.StartNew(() =>
     {
         if (baseRequest != null)
         {
             try
             {
                 string result = Logout();
                 asyncOperation.Post(
                     new SendOrPostCallback((obj) =>
                 {
                     LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                 }), user);
             }
             catch (Exception e)
             {
                 asyncOperation.Post(
                     new SendOrPostCallback((obj) =>
                 {
                     ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                 }), e);
                 throw e;
             }
         }
     });
 }
Пример #2
0
        /// <summary>
        /// 获取头像,因为请求的时候需要带Cookie等相关参数,所以直接用新的http请求不行,务必使用客户端API来获取
        /// </summary>
        /// <param name="url">头像地址,例如/cgi-bin/mmwebwx-bin/webwxgeticon?seq=0&username=filehelper&skey=@crypt_372b266_540d016177e861740ee84fec697a3b01 </param>
        /// <param name="action">委托Action</param>
        /// <returns></returns>
        public void GetIconAsync(string url, Action <byte[]> action)
        {
            string fullUrl = host + url;

            new Task(() =>
            {
                try
                {
                    var img = httpClient.GetImage(fullUrl);
                    asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                    {
                        action((byte[])obj);
                    }), img);
                }
                catch (Exception e)
                {
                    asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                    {
                        ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                    }), e);
                }
            }).Start();
        }
Пример #3
0
 /// <summary>
 /// 获取登陆二维码
 /// </summary>
 private void GetLoginQrCode()
 {
     try
     {
         string jsloginUrl = $"https://login.wx2.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx2.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={Utils.GetJavaTimeStamp()}";
         string result     = httpClient.GetString(jsloginUrl);
         Utils.Debug("GetLoginQrCode " + result);
         string qruuidStr = "window.QRLogin.uuid = \"";
         int    index     = result.IndexOf("window.QRLogin.uuid = \"");
         if (index == -1)
         {
             throw new Exception("获取登陆二维码失败,请稍后再试。");
         }
         else
         {
             uuid = result.Substring(index + qruuidStr.Length, result.Length - index - qruuidStr.Length - "\";".Length);
         }
         string qrcodeUrl = string.Format("https://login.weixin.qq.com/qrcode/{0}", uuid);
         var    img       = httpClient.GetImage(qrcodeUrl);
         asyncOperation.Post(
             new SendOrPostCallback((obj) =>
         {
             GetLoginQrCodeComplete?.Invoke(this, new TEventArgs <byte[]>((byte[])obj));
         }), img);
     }
     catch (Exception e)
     {
         asyncOperation.Post(
             new SendOrPostCallback((obj) =>
         {
             ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
         }), e);
         throw e;
     }
 }
Пример #4
0
        internal static void GetUIElementInToWorkAreaWithTabTipOpened(UIElement element)
        {
            try
            {
                FrameworkElement rootVisualForAnimation   = GetRootVisualForAnimation(element);
                Rectangle        workAreaWithTabTipOpened = GetWorkAreaWithTabTipOpened(element);

                Rectangle uiElementRectangle;
                Window    window = rootVisualForAnimation as Window;
                if (window != null && workAreaWithTabTipOpened.Height >= window.Height)
                {
                    uiElementRectangle = GetWindowRectangle(window);
                }
                else
                {
                    uiElementRectangle = GetUIElementRect(element);
                }

                MoveRootVisualBy(
                    rootVisual: rootVisualForAnimation,
                    moveBy: GetYOffsetToMoveUIElementInToWorkArea(
                        uiElementRectangle: uiElementRectangle,
                        workAreaRectangle: workAreaWithTabTipOpened));
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(ex);
            }
        }
Пример #5
0
 /// <summary>
 /// 主要用于提醒手机端,同步状态
 /// </summary>
 private void StatusNotify()
 {
     try
     {
         //反馈服务器
         string webwxstatusnotifyUrl             = host + "/cgi-bin/mmwebwx-bin/webwxstatusnotify";
         StatusNotifyRequest statusNotifyRequest = new StatusNotifyRequest();
         statusNotifyRequest.BaseRequest  = baseRequest;
         statusNotifyRequest.Code         = 3;
         statusNotifyRequest.FromUserName = user.UserName;
         statusNotifyRequest.ToUserName   = user.UserName;
         statusNotifyRequest.ClientMsgId  = Utils.GetJavaTimeStamp();
         //反馈结果可以不理
         httpClient.PostJson <StatusNotifyResponse>(webwxstatusnotifyUrl, statusNotifyRequest);
     }
     catch (Exception e)
     {
         asyncOperation.Post(
             new SendOrPostCallback((obj) =>
         {
             ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
         }), e);
         throw e;
     }
 }
Пример #6
0
        public async Task StartAsync()
        {
            if (IsRunning)
            {
                return;
            }

            IsRunning = true;
            Source    = new CancellationTokenSource();
            try
            {
                await DiscordConnection.RunAsync(Source.Token, DiscordSocketConfig);
            }
            catch (OperationCanceledException ocex)
            {
                if (!Source.IsCancellationRequested || ocex.CancellationToken != Source.Token)
                {
                    ExceptionCatched?.Invoke(this, ocex);
                }
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(this, ex);
            }
            finally
            {
                IsRunning = false;
            }
        }
Пример #7
0
 internal static void GetEverythingInToWorkAreaWithTabTipClosed()
 {
     try
     {
         foreach (KeyValuePair <FrameworkElement, Storyboard> moveRootVisualStoryboard in MoveRootVisualStoryboards)
         {
             Window window = moveRootVisualStoryboard.Key as Window;
             // if window exist also check if it has not been closed
             if (window != null && new WindowInteropHelper(window).Handle != IntPtr.Zero)
             {
                 MoveRootVisualBy(
                     rootVisual: window,
                     moveBy: GetYOffsetToMoveUIElementInToWorkArea(
                         uiElementRectangle: GetWindowRectangle(window),
                         workAreaRectangle: GetWorkAreaWithTabTipClosed(window)));
             }
             else
             {
                 MoveRootVisualTo(rootVisual: moveRootVisualStoryboard.Key, moveTo: 0);
             }
         }
     }
     catch (Exception ex)
     {
         ExceptionCatched?.Invoke(ex);
     }
 }
Пример #8
0
        /// <summary>
        /// 读取用户的联系人列表,其中只包含公众号,个人号,如果返回值seq不为0,那么用户列表还没获取完(因为可能会有几千人的号,不可能一次获取完),则附带上seq的值继续获取。
        /// </summary>
        private void GetContact()
        {
            try
            {
                //获取联系人列表
                finishGetContactList = false;
                string getContactUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxgetcontact?r={0}&seq={1}&skey={2}", Utils.GetJavaTimeStamp(), 0, baseRequest.Skey);
                while (!finishGetContactList)
                {
                    string contactResult = httpClient.GetStringOnce(getContactUrl);
                    GetContactResponse getContactResponse = JsonConvert.DeserializeObject<GetContactResponse>(contactResult);
                    asyncOperation.Post(
                    new SendOrPostCallback((list) =>
                    {
                        GetContactComplete?.Invoke(this, new TEventArgs<List<Contact>>((List<Contact>)list));
                    }), getContactResponse.MemberList);

                    if (getContactResponse.Seq == 0)
                    {
                        finishGetContactList = true;
                    }
                    else
                    {
                        getContactUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxgetcontact?r={0}&seq={1}&skey={2}", Utils.GetJavaTimeStamp(), getContactResponse.Seq, baseRequest.Skey);
                    }
                }

                //获取完联系人中的公众号,才能获得名称,这个时候再发送图文消息事件。
                asyncOperation.Post(
                new SendOrPostCallback((obj) =>
                {
                    MPSubscribeMsgListComplete?.Invoke(this, new TEventArgs<List<MPSubscribeMsg>>((List<MPSubscribeMsg>)obj));
                }), mpSubscribeMsgList);
            }
            catch (Exception e)
            {
                if (e is WebException)
                {

                    WebException we = e as WebException;
                    if (we.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)we.Response).StatusCode == HttpStatusCode.ServiceUnavailable)
                    {
                        //过千人账号有时候获取不到联系人列表,服务器返回503,官方测试结果也是反馈503导致获取不到,为了不影响正常使用,跳过获取联系人步骤
                        asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                        {
                            ExceptionCatched?.Invoke(this, new TEventArgs<Exception>((Exception)obj));
                        }), new GetContactException("无法获取好友列表"));
                    }
                }
                else
                {
                    asyncOperation.Post(
                    new SendOrPostCallback((obj) =>
                    {
                        ExceptionCatched?.Invoke(this, new TEventArgs<Exception>((Exception)obj));
                    }), e);
                }
            }
        }
Пример #9
0
        /// <summary>
        /// 获取联系人信息,例如初始化、群聊里面。
        /// </summary>
        /// <param name="statusNotifyUserName">需要获取的UserName列表,包括群,个人用户,用英文,分割</param>
        /// <param name="EncryChatRoomId">默认为空,如果是获取群内成员详细信息,则填写encryChatRoomId,也就是群的UserName</param>
        public void GetBatchGetContactAsync(string statusNotifyUserName, string encryChatRoomId = "")
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    //获取历史会话列表
                    string webwxbatchgetcontactUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r={0}", Utils.GetJavaTimeStamp());
                    string[] chatNameArr           = statusNotifyUserName.Split(',');
                    bool finishGetChatList         = false;
                    BatchGetContactRequest batchGetContactRequest = new BatchGetContactRequest();
                    batchGetContactRequest.BaseRequest            = baseRequest;
                    int count = chatNameArr.Length;
                    int index = 0;
                    //一批次最多获取50条,多出来分批获取
                    while (!finishGetChatList)
                    {
                        batchGetContactRequest.List = new List <ChatRoom>();
                        if (((index + 1) * 50) < count)
                        {
                            for (int i = index * 50; i < (index + 1) * 50; i++)
                            {
                                batchGetContactRequest.List.Add(new ChatRoom {
                                    UserName = chatNameArr[i], EncryChatRoomId = encryChatRoomId
                                });
                            }
                        }
                        else
                        {
                            for (int i = index * 50; i < count; i++)
                            {
                                batchGetContactRequest.List.Add(new ChatRoom {
                                    UserName = chatNameArr[i], EncryChatRoomId = encryChatRoomId
                                });
                            }
                            finishGetChatList = true;
                        }
                        BatchGetContactResponse batchGetContactMsg = httpClient.PostJson <BatchGetContactResponse>(webwxbatchgetcontactUrl, batchGetContactRequest);
                        asyncOperation.Post(
                            new SendOrPostCallback((list) =>
                        {
                            BatchGetContactComplete?.Invoke(this, new TEventArgs <List <Contact> >((List <Contact>)list));
                        }), batchGetContactMsg.ContactList);

                        index++;
                    }
                }
                catch (Exception e)
                {
                    asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                    {
                        ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                    }), e);
                }
            });
        }
Пример #10
0
        static TabTipAutomation()
        {
            if (EnvironmentEx.GetOSVersion() == OSVersion.Win7)
            {
                return;
            }

            TabTip.Closed += () => TabTipClosedSubject.OnNext(true);

            AutomateTabTipOpen(FocusSubject.AsObservable());
            AutomateTabTipClose(FocusSubject.AsObservable(), TabTipClosedSubject);

            AnimationHelper.ExceptionCatched += exception => ExceptionCatched?.Invoke(exception);
        }
Пример #11
0
 internal static void KillTapTibProcess()
 {
     try
     {
         foreach (Process tabTipProcess in Process.GetProcessesByName(TabTipProcessName))
         {
             tabTipProcess.Kill();
         }
     }
     catch (Exception ex)
     {
         ExceptionCatched?.Invoke(ex);
     }
 }
Пример #12
0
 private static bool TabTipClosed()
 {
     try
     {
         const int  GWL_STYLE           = -16; // Specifies we wish to retrieve window styles.
         const uint KeyboardClosedStyle = 2617245696;
         IntPtr     KeyboardWnd         = GetTabTipWindowHandle();
         return(KeyboardWnd.ToInt32() == 0 || GetWindowLong(KeyboardWnd, GWL_STYLE) == KeyboardClosedStyle);
     }
     catch (Exception ex)
     {
         ExceptionCatched?.Invoke(ex);
         return(false);
     }
 }
Пример #13
0
        /// <summary>
        /// Close TabTip
        /// </summary>
        public static void Close()
        {
            System.Diagnostics.Debug.WriteLine("TabTip.Close");
            const int WM_SYSCOMMAND = 274;
            const int SC_CLOSE      = 61536;

            try
            {
                SendMessage(GetTabTipWindowHandle().ToInt32(), WM_SYSCOMMAND, SC_CLOSE, 0);
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(ex);
            }
        }
Пример #14
0
        private static void EnableTabTipOpenInDesctopModeOnWin10()
        {
            try
            {
                const string TabTipAutoInvokeKey = "EnableDesktopModeAutoInvoke";

                int EnableDesktopModeAutoInvoke = (int)(Registry.GetValue(TabTipRegistryKeyName, TabTipAutoInvokeKey, -1) ?? -1);
                if (EnableDesktopModeAutoInvoke != 1)
                {
                    Registry.SetValue(TabTipRegistryKeyName, TabTipAutoInvokeKey, 1);
                }
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(ex);
            }
        }
Пример #15
0
 /// <summary>
 /// 异步发送文字消息
 /// </summary>
 /// <param name="msg">消息</param>
 /// <param name="toUserName">发送人UserName</param>
 public void SendMsgAsync(string msg, string toUserName)
 {
     Task.Factory.StartNew(() =>
     {
         try
         {
             SendMsg(msg, toUserName);
         }
         catch (Exception e)
         {
             asyncOperation.Post(
                 new SendOrPostCallback((obj) =>
             {
                 ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
             }), e);
         }
     });
 }
Пример #16
0
        /// <summary>
        /// 开始初始化所有关键内容
        /// </summary>
        private void Init()
        {
            try
            {
                string  webwxinitUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxinit?r={0}pass_ticket={1}", Utils.Get_r(), passTicket);
                JObject postjson     = JObject.FromObject(new
                {
                    BaseRequest = baseRequest
                });
                InitResponse initMsg = httpClient.PostJson <InitResponse>(webwxinitUrl, postjson);
                if (initMsg.BaseResponse.Ret != 0)
                {
                    throw new Exception("程序初始化失败");
                }
                //初始化2次,官网也是初始化2次,这样貌似比较稳定
                httpClient.PostJson <InitResponse>(webwxinitUrl, postjson);
                user = initMsg.User;
                mpSubscribeMsgList = initMsg.MPSubscribeMsgList;
                syncKey            = initMsg.SyncKey;

                //初始化的时候会返回一个最近联系人列表,但是主要还是以第一次sync获得的最近联系人为准。
                asyncOperation.Post(
                    new SendOrPostCallback((list) =>
                {
                    BatchGetContactComplete?.Invoke(this, new TEventArgs <List <Contact> >((List <Contact>)list));
                }), initMsg.ContactList);

                asyncOperation.Post(
                    new SendOrPostCallback((obj) =>
                {
                    LoginComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                }), user);
            }
            catch (Exception ex)
            {
                FileLog.Exception("Init", ex);
                asyncOperation.Post(
                    new SendOrPostCallback((obj) =>
                {
                    ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                }), ex);
                //throw ex;
            }
        }
Пример #17
0
        /// <summary>
        /// Open TabTip
        /// </summary>
        public static void Open()
        {
            if (EnvironmentEx.GetOSVersion() == OSVersion.Win10)
            {
                EnableTabTipOpenInDesctopModeOnWin10();
            }

            try
            {
                Process.Start(new ProcessStartInfo(TabTipExecPath)
                {
                    UseShellExecute = true
                });
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(ex);
            }
        }
Пример #18
0
        /// <summary>
        /// Open TabTip in undocked state
        /// </summary>
        public static void OpenUndocked()
        {
            const string TabTipDockedKey = "EdgeTargetDockedState";

            try
            {
                int docked = (int)(Registry.GetValue(TabTipRegistryKeyName, TabTipDockedKey, 1) ?? 1);
                if (docked == 1)
                {
                    Registry.SetValue(TabTipRegistryKeyName, TabTipDockedKey, 0);
                    KillTapTibProcess();
                }
            }
            catch (Exception ex)
            {
                ExceptionCatched?.Invoke(ex);
            }

            Open();
        }
Пример #19
0
        /// <summary>
        /// 检测手机是否扫码
        /// </summary>
        private void CheckSacnLogin()
        {
            try
            {
                byte[]    userAvatar = null;
                ScanState scanState  = ScanState.UnKnown;
                while (syncPolling && (scanState != ScanState.Login))
                {
                    string timespan = Utils.GetTimeStamp();
                    string loginUrl = string.Format("https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r={1}&_={2}", uuid, Utils.Get_r(), Utils.GetTimeStamp());
                    //采用长轮询的方式,25秒返内回一次检测数据。
                    string checkResult = httpClient.GetString(loginUrl);
                    Utils.Debug("CheckSacnLogin " + checkResult);
                    if (checkResult.IndexOf("window.code=408;") != -1)
                    {
                        scanState = ScanState.Timeout;
                    }
                    else if (checkResult.IndexOf("window.code=201;") != -1)
                    {
                        scanState = ScanState.Scan;
                        //有些号没有头像就跳过这个步骤
                        if (checkResult.IndexOf("window.userAvatar") != -1)
                        {
                            //扫码返回的头像是base64格式,需要转化
                            string subStr           = "window.code=201;window.userAvatar = 'data:img/jpg;base64,";
                            string base64UserAvatar = checkResult.Substring(subStr.Length, checkResult.Length - subStr.Length - 2);
                            byte[] arr = Convert.FromBase64String(base64UserAvatar);
                            userAvatar = arr;
                            asyncOperation.Post(
                                new SendOrPostCallback((obj) =>
                            {
                                CheckScanComplete?.Invoke(this, new TEventArgs <byte[]>((byte[])obj));
                            }), userAvatar);
                        }
                    }
                    else if (checkResult.IndexOf("window.code=200;") != -1)
                    {
                        scanState = ScanState.Login;
                        string subStr = "window.code=200;\nwindow.redirect_uri=\"";
                        cookieRedirectUri = checkResult.Substring(subStr.Length, checkResult.Length - subStr.Length - 2);
                        //跳转登录页获取cookie,并且获取关键参数,根据跳转地址,获相应提交地址
                        string cookieRedirectResult = httpClient.LoginString(cookieRedirectUri);
                        if (cookieRedirectUri.StartsWith("https://wx2.qq.com"))
                        {
                            host       = "https://wx2.qq.com";
                            pushHost   = "https://webpush.wx2.qq.com";
                            uploadHost = "https://file.wx2.qq.com";
                        }
                        else if (cookieRedirectUri.StartsWith("https://wx8.qq.com"))
                        {
                            host       = "https://wx8.qq.com";
                            pushHost   = "https://webpush.wx8.qq.com";
                            uploadHost = "https://file.wx8.qq.com";
                        }
                        else if (cookieRedirectUri.StartsWith("https://web2.wechat.com"))
                        {
                            host       = "https://web2.wechat.com";
                            pushHost   = "https://webpush.web2.wechat.com";
                            uploadHost = "https://file.web2.wechat.com";
                        }
                        else if (cookieRedirectUri.StartsWith("https://web.wechat.com"))
                        {
                            host       = "https://web.wechat.com";
                            pushHost   = "https://webpush.web.wechat.com";
                            uploadHost = "https://file.web.wechat.com";
                        }
                        else
                        {
                            host       = "https://wx.qq.com";
                            pushHost   = "https://webpush.wx.qq.com";
                            uploadHost = "https://file.wx.qq.com";
                        }

                        httpClient.Referer = host;
                        XmlDocument xmlDoc = new XmlDocument();
                        xmlDoc.LoadXml(cookieRedirectResult);
                        //如果返回异常,则可能被暂封,无法登陆网页版
                        if (xmlDoc["error"]["ret"].InnerText != "0")
                        {
                            throw new Exception(xmlDoc["error"]["message"].InnerText);
                        }
                        else
                        {
                            baseRequest.Sid  = xmlDoc["error"]["wxsid"].InnerText;
                            baseRequest.Uin  = Convert.ToInt64(xmlDoc["error"]["wxuin"].InnerText);
                            baseRequest.Skey = xmlDoc["error"]["skey"].InnerText;
                            passTicket       = xmlDoc["error"]["pass_ticket"].InnerText;
                        }
                    }
                    else if (checkResult.IndexOf("window.code=400;") != -1)
                    {
                        scanState = ScanState.Expires;
                        GetLoginQrCode();
                    }
                    else
                    {
                        scanState = ScanState.UnKnown;
                    }
                    Thread.Sleep(1000);
                }
            }
            catch (Exception ex)
            {
                FileLog.Exception("CheckSacnLogin", ex);
                asyncOperation.Post(
                    new SendOrPostCallback((obj) =>
                {
                    ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                }), ex);
                throw ex;
            }
        }
Пример #20
0
        /// <summary>
        /// 开始轮询检测是否有新消息
        /// </summary>
        private void Sync()
        {
            while (syncPolling)
            {
                try
                {
                    string syncCheckUrl    = string.Format(pushHost + "/cgi-bin/mmwebwx-bin/synccheck?r={0}&skey={1}&sid={2}&uin={3}&deviceid={4}&synckey={5}&_={6}", Utils.GetJavaTimeStamp(), baseRequest.Skey, baseRequest.Sid, baseRequest.Uin, baseRequest.DeviceID, syncKey.ToString(), syncKey.Step);
                    string syncCheckResult = httpClient.GetString(syncCheckUrl);
                    if (!syncPolling)
                    {
                        return;
                    }
                    MatchCollection matchCollection = Regex.Matches(syncCheckResult, @"\d+");
                    string          retcode         = matchCollection[0].Value;
                    string          selector        = matchCollection[1].Value;
                    Utils.Debug("retcode:" + retcode + " selector:" + selector);
                    switch (retcode)
                    {
                    case "0":
                        if (selector != "0")
                        {
                            //有新消息,拉取信息。
                            SyncRequest syncRequest = new SyncRequest();
                            syncRequest.BaseRequest = baseRequest;
                            syncRequest.SyncKey     = syncKey;
                            syncRequest.rr          = Utils.Get_r();
                            string       syncUrl      = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}", baseRequest.Sid, baseRequest.Skey, passTicket);
                            SyncResponse syncResponse = httpClient.PostJson <SyncResponse>(syncUrl, syncRequest);
                            if (!syncPolling)
                            {
                                return;
                            }
                            else
                            {
                                syncKey = syncResponse.SyncKey;
                                //只要不是0,就是有消息,有消息我们处理就行了,不管selector是几
                                if (syncResponse.AddMsgCount == 0 && syncResponse.DelContactCount == 0 && syncResponse.ModContactCount == 0 && syncResponse.ModChatRoomMemberCount == 0)
                                {
                                    //会有这么一种情况,selector=2,但是没有任何消息体,这样会导致持续快速的空交互
                                    //除非下次有新消息,或者主动点击手机触发消息
                                    //为了防止这种情况,做个5秒停顿。
                                    Thread.Sleep(5000);
                                }
                                else
                                {
                                    if (syncResponse.AddMsgList.Count > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            ReceiveMsg?.Invoke(this, new TEventArgs <List <AddMsg> >((List <AddMsg>)obj));
                                        }), syncResponse.AddMsgList);
                                    }

                                    if (syncResponse.ModContactCount > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            ModContactListComplete?.Invoke(this, new TEventArgs <List <ModContactItem> >((List <ModContactItem>)obj));
                                        }), syncResponse.ModContactList);
                                    }
                                    if (syncResponse.DelContactCount > 0)
                                    {
                                        asyncOperation.Post(
                                            new SendOrPostCallback((obj) =>
                                        {
                                            DelContactListComplete?.Invoke(this, new TEventArgs <List <DelContactItem> >((List <DelContactItem>)obj));
                                        }), syncResponse.DelContactList);
                                    }
                                    if (syncResponse.ModChatRoomMemberCount > 0)
                                    {
                                        //待分析,这个消息基本没有
                                    }
                                }
                            }
                        }
                        break;

                    case "1100":
                        //登出了微信,很可能是wx.qq.com和wx2.qq.com调用接口不一致导致的,注意登陆时候的跳转地址
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        break;

                    case "1101":
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        throw new Exception("1101可能其他地方登录/登出了 WEB 版微信,请检查手机端已登出WEB微信,然后稍后再试");
                        break;

                    case "1102":
                        Close();
                        asyncOperation.Post(
                            new SendOrPostCallback((obj) =>
                        {
                            LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj));
                        }), user);
                        throw new Exception("1102被强制登出(很可能cookie冲突),请检查手机端已登出WEB微信,然后稍后再试");
                        break;

                    default:
                        //有其他任何异常,取消轮询
                        throw new Exception("轮询结果异常,停止轮询:" + syncCheckResult);
                        break;
                    }
                    Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    FileLog.Exception("Init", ex);
                    asyncOperation.Post(
                        new SendOrPostCallback((obj) =>
                    {
                        ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj));
                    }), ex);
                }
            }
        }