瀏覽代碼

1.解密内存优化
2.记录分页支持
3.模版选择初步支持

Suxue 1 年之前
父節點
當前提交
f16e0b020b
共有 7 個文件被更改,包括 300 次插入165 次删除
  1. 89 19
      Helpers/DecryptionHelper.cs
  2. 2 0
      Model/WXModel.cs
  3. 40 0
      Pages/MsgTemplateSelector .cs
  4. 4 4
      Pages/Workspace.xaml
  5. 68 70
      Pages/Workspace.xaml.cs
  6. 3 0
      ViewModel/WorkspaceViewModel.cs
  7. 94 72
      WXUserReader.cs

+ 89 - 19
Helpers/DecryptionHelper.cs

@@ -143,15 +143,19 @@ namespace WechatBakTool.Helpers
             return null;
         }
 
-        public static byte[] DecryptDB(byte[] db_file_bytes, byte[] password_bytes)
+        public static void DecryptDB(string file, string to_file, byte[] password_bytes)
         {
             //数据库头16字节是盐值
-            var salt = db_file_bytes.Take(16).ToArray();
+            byte[] salt_key = new byte[16];
+
+            FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
+            fileStream.Read(salt_key, 0, 16);
+
             //HMAC验证时用的盐值需要亦或0x3a
             byte[] hmac_salt = new byte[16];
-            for (int i = 0; i < salt.Length; i++)
+            for (int i = 0; i < salt_key.Length; i++)
             {
-                hmac_salt[i] = (byte)(salt[i] ^ 0x3a);
+                hmac_salt[i] = (byte)(salt_key[i] ^ 0x3a);
             }
             //计算保留段长度
             int reserved = IV_SIZE;
@@ -161,7 +165,7 @@ namespace WechatBakTool.Helpers
             //密钥扩展,分别对应AES解密密钥和HMAC验证密钥
             byte[] key = new byte[KEY_SIZE];
             byte[] hmac_key = new byte[KEY_SIZE];
-            OpenSSLInterop.PKCS5_PBKDF2_HMAC_SHA1(password_bytes, password_bytes.Length, salt, salt.Length, DEFAULT_ITER, key.Length, key);
+            OpenSSLInterop.PKCS5_PBKDF2_HMAC_SHA1(password_bytes, password_bytes.Length, salt_key, salt_key.Length, DEFAULT_ITER, key.Length, key);
             OpenSSLInterop.PKCS5_PBKDF2_HMAC_SHA1(key, key.Length, hmac_salt, hmac_salt.Length, 2, hmac_key.Length, hmac_key);
 
             int page_no = 0;
@@ -169,8 +173,82 @@ namespace WechatBakTool.Helpers
             Console.WriteLine("开始解密...");
             var hmac_sha1 = HMAC.Create("HMACSHA1");
             hmac_sha1!.Key = hmac_key;
+
             List<byte> decrypted_file_bytes = new List<byte>();
-            while (page_no < db_file_bytes.Length / DEFAULT_PAGESIZE)
+            FileStream tofileStream = new FileStream(to_file, FileMode.OpenOrCreate, FileAccess.Write);
+
+            using (fileStream)
+            {
+                try
+                {
+                    // 当前分页小于计算分页数
+                    while (page_no < fileStream.Length / DEFAULT_PAGESIZE)
+                    {
+                        // 读内容
+                        byte[] decryped_page_bytes = new byte[DEFAULT_PAGESIZE];
+                        byte[] going_to_hashed = new byte[DEFAULT_PAGESIZE - reserved - offset + IV_SIZE + 4];
+                        fileStream.Seek((page_no * DEFAULT_PAGESIZE) + offset, SeekOrigin.Current);
+                        fileStream.Read(going_to_hashed, 0, DEFAULT_PAGESIZE - reserved - offset + IV_SIZE);
+
+                        // 分页标志
+                        var page_bytes = BitConverter.GetBytes(page_no + 1);
+                        page_bytes.CopyTo(going_to_hashed, DEFAULT_PAGESIZE - reserved - offset + IV_SIZE);
+                        var hash_mac_compute = hmac_sha1.ComputeHash(going_to_hashed, 0, going_to_hashed.Length);
+
+                        // 取分页hash
+                        byte[] hash_mac_cached = new byte[hash_mac_compute.Length];
+                        fileStream.Seek((page_no * DEFAULT_PAGESIZE) + DEFAULT_PAGESIZE - reserved + IV_SIZE, SeekOrigin.Current);
+                        fileStream.Read(hash_mac_cached, 0, hash_mac_compute.Length);
+
+                        if (!hash_mac_compute.SequenceEqual(hash_mac_cached) && page_no == 0)
+                        {
+                            Console.WriteLine("Hash错误...");
+                            return;
+                        }
+                        else
+                        {
+                            if (page_no == 0)
+                            {
+                                var header_bytes = Encoding.ASCII.GetBytes(SQLITE_HEADER);
+                                header_bytes.CopyTo(decryped_page_bytes, 0);
+                            }
+
+                            // 加密内容
+                            byte[] page_content = new byte[DEFAULT_PAGESIZE - reserved - offset];
+                            fileStream.Seek((page_no * DEFAULT_PAGESIZE) + offset, SeekOrigin.Current);
+                            fileStream.Read(page_content, 0, DEFAULT_PAGESIZE - reserved - offset);
+
+                            // iv
+                            byte[] iv = new byte[16];
+                            fileStream.Seek((page_no * DEFAULT_PAGESIZE) + (DEFAULT_PAGESIZE - reserved), SeekOrigin.Current);
+                            fileStream.Read(iv, 0, 16);
+
+                            var decrypted_content = AESDecrypt(page_content, key, iv);
+                            decrypted_content.CopyTo(decryped_page_bytes, offset);
+
+                            // 保留
+                            byte[] reserved_byte = new byte[reserved];
+                            fileStream.Seek((page_no * DEFAULT_PAGESIZE) + DEFAULT_PAGESIZE - reserved, SeekOrigin.Current);
+                            fileStream.Read(reserved_byte, 0, reserved);
+                            reserved_byte.CopyTo(decryped_page_bytes, DEFAULT_PAGESIZE - reserved);
+
+                            tofileStream.Write(decryped_page_bytes, 0, decryped_page_bytes.Length);
+
+                        }
+                        page_no++;
+                        offset = 0;
+                    }
+                }catch(Exception ex)
+                {
+                    File.AppendAllText("err.log", "page=>" + page_no.ToString() + "\r\n");
+                    File.AppendAllText("err.log", "size=>" + fileStream.Length.ToString() + "\r\n");
+                    File.AppendAllText("err.log", "postion=>" + ((page_no * DEFAULT_PAGESIZE) + offset).ToString() + "\r\n");
+                    File.AppendAllText("err.log", ex.ToString() + "\r\n");
+                }
+            }
+            /*
+             * 旧版解密
+            while (page_no < fileStream.Length / DEFAULT_PAGESIZE)
             {
                 byte[] decryped_page_bytes = new byte[DEFAULT_PAGESIZE];
                 byte[] going_to_hashed = new byte[DEFAULT_PAGESIZE - reserved - offset + IV_SIZE + 4];
@@ -179,7 +257,6 @@ namespace WechatBakTool.Helpers
                 page_bytes.CopyTo(going_to_hashed, DEFAULT_PAGESIZE - reserved - offset + IV_SIZE);
                 //计算分页的Hash
                 var hash_mac_compute = hmac_sha1.ComputeHash(going_to_hashed, 0, going_to_hashed.Length);
-                //取出分页中存储的Hash
                 var hash_mac_cached = db_file_bytes.Skip((page_no * DEFAULT_PAGESIZE) + DEFAULT_PAGESIZE - reserved + IV_SIZE).Take(hash_mac_compute.Length).ToArray();
                 //对比两个Hash
                 if (!hash_mac_compute.SequenceEqual(hash_mac_cached))
@@ -208,8 +285,9 @@ namespace WechatBakTool.Helpers
                 {
                     decrypted_file_bytes.Add(item);
                 }
-            }
-            return decrypted_file_bytes.ToArray();
+            }*/
+            tofileStream.Close();
+            tofileStream.Dispose();
         }
         public static byte[] AESDecrypt(byte[] content, byte[] key, byte[] iv)
         {
@@ -297,16 +375,8 @@ namespace WechatBakTool.Helpers
             {
                 FileInfo info = new FileInfo(file);
                 viewModel.LabelStatus = "正在解密" + info.Name;
-                var db_bytes = File.ReadAllBytes(file);
-                var decrypted_file_bytes = DecryptDB(db_bytes, key);
-                if (decrypted_file_bytes == null || decrypted_file_bytes.Length == 0)
-                {
-                    Console.WriteLine("解密后的数组为空");
-                }
-                else
-                {
-                    File.WriteAllBytes(Path.Combine(decPath, info.Name), decrypted_file_bytes);
-                }
+                string to_file = Path.Combine(decPath, info.Name);
+                DecryptDB(file,to_file, key);
             }
         }
     }

+ 2 - 0
Model/WXModel.cs

@@ -114,6 +114,8 @@ namespace WechatBakTool.Model
     {
         [Column("localId")]
         public int LocalId { get; set; }
+        [Column("MsgSequence")]
+        public int MsgSequence { get; set; }
         [Column("Type")]
         public int Type { get; set; }
         [Column("SubType")]

+ 40 - 0
Pages/MsgTemplateSelector .cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using WechatBakTool.Model;
+
+namespace WechatBakTool.Pages
+{
+    public class MsgTemplateSelector : DataTemplateSelector
+    {
+
+        public override DataTemplate? SelectTemplate(object item, DependencyObject container)
+        {
+            FrameworkElement? element = container as FrameworkElement;
+
+            if (element != null && item != null && item is WXMsg)
+            {
+                WXMsg? wxmsg = item as WXMsg;
+
+                if (wxmsg == null)
+                    return null;
+
+                if (wxmsg.Type == 1)
+                    return
+                        element.FindResource("MsgText") as DataTemplate;
+                else if (wxmsg.Type == 3)
+                    return
+                        element.FindResource("MsgImage") as DataTemplate;
+                else
+                    return
+                        element.FindResource("MsgText") as DataTemplate;
+            }
+            return null;
+        }
+
+    }
+}

+ 4 - 4
Pages/Workspace.xaml

@@ -3,11 +3,12 @@
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-      xmlns:local="clr-namespace:WechatBakTool.Pages"
+      xmlns:local="clr-namespace:WechatBakTool.Pages" 
       mc:Ignorable="d" 
       d:DesignHeight="450" d:DesignWidth="720"
       Title="Workspace" Background="White">
     <Page.Resources>
+        <local:MsgTemplateSelector x:Key="MsgTemplateSelector"/>
         <Style TargetType="ToggleButton" x:Key="ComboxStyleBtn">
             <Setter Property="Template">
                 <Setter.Value>
@@ -164,9 +165,8 @@
         </DataTemplate>
         <DataTemplate x:Key="MsgImage">
             <Grid Margin="0">
-                <Image Width="40" Height="40" Margin="10" VerticalAlignment="Top" HorizontalAlignment="Left" Source="{Binding Avatar}"  />
                 <Label Margin="60,8,0,0" FontWeight="Bold" VerticalAlignment="Top" HorizontalAlignment="Left" Content="{Binding NickName}" Width="130"/>
-                <Label Margin="60,25,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="140" Content="{Binding LastMsg}"/>
+                <Label Margin="60,25,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="140" Content="1111"/>
             </Grid>
         </DataTemplate>
         <DataTemplate x:Key="MsgAudio">
@@ -214,7 +214,7 @@
             </ListView.Resources>
         </ListView>
         <Label Content="{Binding WXContact.NickName}" HorizontalAlignment="Left" Margin="258,21,0,0" VerticalAlignment="Top"/>
-        <ListView x:Name="list_msg" Margin="230,60,0,60" Background="Transparent" BorderThickness="0,1,0,1" BorderBrush="#BB2775b6" ItemTemplate="{DynamicResource MsgText}">
+        <ListView x:Name="list_msg" Margin="230,60,0,60" Background="Transparent" BorderThickness="0,1,0,1" BorderBrush="#BB2775b6" ItemTemplateSelector="{StaticResource MsgTemplateSelector}" ItemsSource="{Binding WXMsgs}" ScrollViewer.ScrollChanged="list_msg_ScrollChanged" >
 
         </ListView>
         <ComboBox Name="cb_export" Width="120" Height="30" Style="{StaticResource ComboBoxStyle}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="30,15" ItemsSource="{Binding ExportItems}" SelectedItem="{Binding SelectExportItem}" DisplayMemberPath="Name" SelectedValuePath="Value" IsEnabled="{Binding SelectContact}" Background="#2775b6" />

+ 68 - 70
Pages/Workspace.xaml.cs

@@ -27,6 +27,8 @@ using System.Windows.Controls;
 using System.Text.RegularExpressions;
 using Newtonsoft.Json;
 using System.Drawing.Imaging;
+using System.Threading;
+using System.Runtime.CompilerServices;
 
 namespace WechatBakTool.Pages
 {
@@ -37,6 +39,9 @@ namespace WechatBakTool.Pages
     {
         public WXUserReader? UserReader;
         private WorkspaceViewModel ViewModel = new WorkspaceViewModel();
+        private int PageSize = 100;
+        private int Postion = 0;
+        private bool Loading = false;
         public Workspace()
         {
             ViewModel.ExportItems = new System.Collections.ObjectModel.ObservableCollection<ExportItem> {
@@ -56,7 +61,11 @@ namespace WechatBakTool.Pages
                 UserReader = new WXUserReader(config);
                 if (config.Decrypt)
                 {
-                    ViewModel.Contacts = UserReader.GetWXContacts();
+                    ViewModel.Contacts = null;
+                    Task.Run(() => {
+                        ViewModel.Contacts = UserReader.GetWXContacts();
+                    });
+                    
                 }
             }
         }
@@ -72,14 +81,43 @@ namespace WechatBakTool.Pages
 
         private void list_users_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
+
+            ViewModel.WXMsgs.Clear();
+            Postion = 0;
             ViewModel.ExportCount = "";
+            
+            loadMsg();
+            if (ViewModel.WXMsgs.Count == 0)
+                return;
+            
+        }
+
+        private void loadMsg()
+        {
+            Loading = true;
             ViewModel.WXContact = list_users.SelectedItem as WXContact;
-            if(ViewModel.WXContact == null || UserReader == null)
-            {
+            if (ViewModel.WXContact == null || UserReader == null)
+                return;
+
+            List<WXMsg>? list = UserReader.GetWXMsgs(ViewModel.WXContact.UserName, Postion, PageSize);
+            // Trace.WriteLine(string.Format("{0}->{1}", PageSize, Postion));
+            if (list == null)
                 return;
+            if (list.Count == 0)
+                return;
+            
+            
+            foreach (WXMsg w in list)
+            {
+                ViewModel.WXMsgs.Add(w);
             }
-            List<WXMsg>? msgs = UserReader.GetWXMsgs(ViewModel.WXContact.UserName);
-            list_msg.ItemsSource = msgs;
+
+            Postion = int.Parse(list.Max(x => x.CreateTime).ToString());
+            list_msg.ScrollIntoView(list[0]);
+            Task.Run(() => {
+                Thread.Sleep(500);
+                Loading = false;
+            });
         }
 
         private void txt_find_user_TextChanged(object sender, TextChangedEventArgs e)
@@ -91,22 +129,25 @@ namespace WechatBakTool.Pages
             if (txt_find_user.Text == "搜索...")
                 findName = "";
 
-            ViewModel.Contacts = UserReader.GetWXContacts(findName);
-            // 保底回落搜索已删除人员
-            if(ViewModel.Contacts.Count == 0)
+            Task.Run(() =>
             {
-                var i = UserReader.GetWXMsgs(txt_find_user.Text);
-                if (i != null)
+                ViewModel.Contacts = UserReader.GetWXContacts(findName);
+                // 保底回落搜索已删除人员
+                if (ViewModel.Contacts.Count == 0)
                 {
-                    var g = i.GroupBy(x => x.StrTalker);
-                    ViewModel.Contacts = new System.Collections.ObjectModel.ObservableCollection<WXContact>();
-                    foreach (var x in g)
+                    var i = UserReader.GetWXMsgs(txt_find_user.Text);
+                    if (i != null)
                     {
-                        string name = x.Key;
-                        ViewModel.Contacts.Add(new WXContact() { UserName = name, NickName = name });
+                        var g = i.GroupBy(x => x.StrTalker);
+                        ViewModel.Contacts = new System.Collections.ObjectModel.ObservableCollection<WXContact>();
+                        foreach (var x in g)
+                        {
+                            string name = x.Key;
+                            ViewModel.Contacts.Add(new WXContact() { UserName = name, NickName = name });
+                        }
                     }
                 }
-            }
+            });
         }
 
         private void txt_find_user_GotFocus(object sender, RoutedEventArgs e)
@@ -132,9 +173,9 @@ namespace WechatBakTool.Pages
                 export.SetMsg(UserReader, ViewModel.WXContact, ViewModel);
                 export.SetEnd();
                 export.Save(path);
-            }catch(Exception ex)
+            }
+            catch (Exception ex)
             {
-                File.AppendAllText("1.log", ex.Message);
                 MessageBox.Show(ex.Message);
             }
             
@@ -287,61 +328,18 @@ namespace WechatBakTool.Pages
                     MessageBox.Show("用户所有表情预下载完毕");
                 });
             }
-            /*
-            if (UserReader != null && ViewModel.WXContact != null)
-            {
-                Task.Run(() =>
-                {
-                    List<WXMsg> msgs = UserReader.GetWXMsgs(ViewModel.WXContact.UserName).ToList();
-                    List<WXContactHT> users = new List<WXContactHT>();
-                    if (File.Exists("WXContact.json"))
-                    {
-                        string text = File.ReadAllText("WXContact.json");
-                        text = text.Substring(8, text.Length - 8);
-                        users = JsonConvert.DeserializeObject<List<WXContactHT>>(text);
-                    }
-
-                    int i = 1; int all = 1;
-                    List<WXMsg> tmp = new List<WXMsg>();
-                    foreach (WXMsg m in msgs)
-                    {
-                        m.BytesExtra = null;
-                        tmp.Add(m);
-                        if (all % 10000 == 0)
-                        {
-                            File.WriteAllText(ViewModel.WXContact.UserName + "-" + i.ToString() + ".json", string.Format("showMsg({0})", JsonConvert.SerializeObject(tmp)));
-                            tmp.Clear();
-                            i++;
-                        }
-                        all++;
-                    }
+        }
 
-                    if (users!.Find(x => x.UserName == ViewModel.WXContact.UserName) == null)
-                    {
-                        WXContactHT html = new WXContactHT();
-                        html.NickName = ViewModel.WXContact.NickName;
-                        html.UserName = ViewModel.WXContact.UserName;
-                        html.LastMsg = ViewModel.WXContact.LastMsg;
-                        if (ViewModel.WXContact.Avatar != null)
-                        {
-                            using (var ms = new MemoryStream())
-                            {
-                                ViewModel.WXContact.Avatar.StreamSource.CopyTo(ms);
-                                byte[] bytes = new byte[ms.Length];
-                                ms.Write(bytes, 0, bytes.Length);
-                                html.AvatarString = Convert.ToBase64String(bytes);
-                            }
-                        }
-                        html.FileCount = i;
-                        users.Add(html);
-                    }
+        private void list_msg_ScrollChanged(object sender, ScrollChangedEventArgs e)
+        {
+            if (ViewModel.WXMsgs.Count == 0)
+                return;
 
-                    File.WriteAllText(ViewModel.WXContact.UserName + "-" + i.ToString() + ".json", string.Format("showMsg({0})", JsonConvert.SerializeObject(tmp)));
-                    File.WriteAllText("WXContact.json", string.Format("getUser({0})", JsonConvert.SerializeObject(users)));
-                    MessageBox.Show("json已导出");
-                });
+            if (e.VerticalOffset + e.ViewportHeight == e.ExtentHeight && !Loading)
+            {
+                // 滚动条到达底部的处理逻辑
+                loadMsg();
             }
-            */
         }
     }
 }

+ 3 - 0
ViewModel/WorkspaceViewModel.cs

@@ -16,6 +16,9 @@ namespace WechatBakTool.ViewModel
         [NotifyPropertyChangedFor(nameof(LabelStatus))]
         private WXContact? wXContact = null;
 
+        [ObservableProperty]
+        private ObservableCollection<WXMsg> wXMsgs = new ObservableCollection<WXMsg>();
+
         [ObservableProperty]
         [NotifyPropertyChangedFor(nameof(LabelStatus))]
         private string exportCount = "";

+ 94 - 72
WXUserReader.cs

@@ -330,6 +330,25 @@ namespace WechatBakTool
             }
             return tmp;
         }
+
+        public List<WXMsg>? GetWXMsgs(string uid,int time,int page)
+        {
+            List<WXMsg> tmp = new List<WXMsg>();
+            for (int i = 0; i <= 99; i++)
+            {
+                SQLiteConnection? con = getCon("MSG" + i.ToString());
+                if (con == null)
+                    return tmp;
+
+                List<WXMsg>? wXMsgs = null;
+                string query = "select * from MSG where StrTalker=? and CreateTime>? Limit ?";
+                wXMsgs = con.Query<WXMsg>(query, uid, time, page);
+                if (wXMsgs.Count != 0) {
+                    return ProcessMsg(wXMsgs, uid);
+                }
+            }
+            return tmp;
+        }
         public List<WXMsg>? GetWXMsgs(string uid,string msg = "")
         {
             List<WXMsg> tmp = new List<WXMsg>();
@@ -356,104 +375,107 @@ namespace WechatBakTool
                     wXMsgs = con.Query<WXMsg>(query, uid, string.Format("%{0}%", msg));
                 }
 
-                foreach (WXMsg w in wXMsgs)
+                tmp.AddRange(ProcessMsg(wXMsgs, uid));
+            }
+            return tmp;
+        }
+        private List<WXMsg> ProcessMsg(List<WXMsg> msgs,string uid)
+        {
+            foreach (WXMsg w in msgs)
+            {
+                if (UserNameCache.ContainsKey(w.StrTalker))
                 {
-                    if (UserNameCache.ContainsKey(w.StrTalker))
+                    WXContact? contact = UserNameCache[w.StrTalker] as WXContact;
+                    if (contact != null)
                     {
-                        WXContact? contact = UserNameCache[w.StrTalker] as WXContact;
-                        if (contact != null)
-                        {
-                            if (contact.Remark != "")
-                                w.NickName = contact.Remark;
-                            else
-                                w.NickName = contact.NickName;
+                        if (contact.Remark != "")
+                            w.NickName = contact.Remark;
+                        else
+                            w.NickName = contact.NickName;
 
-                            w.StrTalker = contact.UserName;
-                        }
+                        w.StrTalker = contact.UserName;
                     }
-                    else
+                }
+                else
+                {
+                    w.NickName = uid;
+                }
+
+                // 群聊处理
+                if (uid.Contains("@chatroom"))
+                {
+                    string userId = "";
+
+                    if (w.BytesExtra == null)
+                        continue;
+
+                    string sl = BitConverter.ToString(w.BytesExtra).Replace("-", "");
+
+                    ProtoMsg protoMsg;
+                    using (MemoryStream stream = new MemoryStream(w.BytesExtra))
                     {
-                        w.NickName = uid;
+                        protoMsg = ProtoBuf.Serializer.Deserialize<ProtoMsg>(stream);
                     }
 
-                    // 群聊处理
-                    if (uid.Contains("@chatroom"))
+                    if (protoMsg.TVMsg != null)
                     {
-                        string userId = "";
-
-                        if (w.BytesExtra == null)
-                            continue;
+                        foreach (TVType _tmp in protoMsg.TVMsg)
+                        {
+                            if (_tmp.Type == 1)
+                                userId = _tmp.TypeValue;
+                        }
+                    }
 
-                        string sl = BitConverter.ToString(w.BytesExtra).Replace("-", "");
 
-                        ProtoMsg protoMsg;
-                        using (MemoryStream stream = new MemoryStream(w.BytesExtra))
+                    if (!w.IsSender)
+                    {
+                        if (UserNameCache.ContainsKey(userId))
                         {
-                            protoMsg = ProtoBuf.Serializer.Deserialize<ProtoMsg>(stream);
+                            WXContact? contact = UserNameCache[userId] as WXContact;
+                            if (contact != null)
+                                w.NickName = contact.Remark == "" ? contact.NickName : contact.Remark;
                         }
-
-                        if (protoMsg.TVMsg != null)
+                        else
                         {
-                            foreach (TVType _tmp in protoMsg.TVMsg)
-                            {
-                                if (_tmp.Type == 1)
-                                    userId = _tmp.TypeValue;
-                            }
+                            w.NickName = userId;
                         }
+                    }
+                }
 
 
-                        if (!w.IsSender)
-                        {
-                            if (UserNameCache.ContainsKey(userId))
-                            {
-                                WXContact? contact = UserNameCache[userId] as WXContact;
-                                if (contact != null)
-                                    w.NickName = contact.Remark == "" ? contact.NickName : contact.Remark;
-                            }
-                            else
-                            {
-                                w.NickName = userId;
-                            }
-                        }
+                // 发送人名字处理
+                if (w.IsSender)
+                    w.NickName = "我";
+
+                w.DisplayContent = w.StrContent;
+                // 额外格式处理
+                if (w.Type != 1)
+                {
+                    if (w.Type == 10000)
+                    {
+                        w.Type = 1;
+                        w.NickName = "系统消息";
+                        w.DisplayContent = w.StrContent.Replace("<revokemsg>", "").Replace("</revokemsg>", "");
                     }
-                    
-                    
-                    // 发送人名字处理
-                    if (w.IsSender)
-                        w.NickName = "我";
-
-                    w.DisplayContent = w.StrContent;
-                    // 额外格式处理
-                    if (w.Type != 1)
+                    else if (w.Type == 49 && (w.SubType == 6 || w.SubType == 19 || w.SubType == 40))
                     {
-                        if (w.Type == 10000)
+                        WXSessionAttachInfo? attachInfos = GetWXMsgAtc(w);
+                        if (attachInfos == null)
                         {
-                            w.Type = 1;
-                            w.NickName = "系统消息";
-                            w.DisplayContent = w.StrContent.Replace("<revokemsg>", "").Replace("</revokemsg>", "");
-                        }
-                        else if (w.Type == 49 && (w.SubType == 6 || w.SubType == 19 || w.SubType == 40))
-                        {
-                            WXSessionAttachInfo? attachInfos = GetWXMsgAtc(w);
-                            if (attachInfos == null)
-                            {
-                                w.DisplayContent = "附件不存在";
-                            }
-                            else
-                            {
-                                w.DisplayContent = Path.Combine(UserBakConfig!.UserResPath, attachInfos.attachPath);
-                            }
+                            w.DisplayContent = "附件不存在";
                         }
                         else
                         {
-                            w.DisplayContent = "[界面未支持格式]Type=" + w.Type;
+                            w.DisplayContent = Path.Combine(UserBakConfig!.UserResPath, attachInfos.attachPath);
                         }
                     }
-                    tmp.Add(w);
-
+                    else
+                    {
+                        w.DisplayContent = "[界面未支持格式]Type=" + w.Type;
+                    }
                 }
             }
-            return tmp;
+            return msgs;
         }
         public List<WXSessionAttachInfo>? GetWXMsgAtc()
         {