(山寨版QQ)源代码
仿QQ聊天软件MyQQ源代码教学(北大青鸟完整版)
需求分析——功能分析
主要功能:
注册与登录 好友管理 消息管理 个人设置
需求分析——界面分析
需要的界面:
注册界面 登录界面 登录后的主界面 查找/添加好友界面 聊天界面 系统消息界面 个人设置界面
头像列表界面
需求分析——辅助类分析
需要添加的辅助类:
DBHelper类 UserHelper 类
小组分工
4
4 4 4 4
软件开发流程
比尔盖子是一名建筑工人 起初只干一些比较简单的 建筑工作 凭个人技术和经验,不需要特 别设计,可以顺利完成
如同编写早期比较小的程序
软件开发流程
新任务:建造一间非常美 丽而完整的房间 工作变得复杂许多
像不断发展的软件,功能 越来越多,越来越复杂
软件开发流程
软件复杂性
图形用户界面 客户/服务器结构 分布式应用 数据通信 超大型关系型数据库
// 判断 ListView 中是否有选中的项 if (lvFaces.SelectedItems.Count == 0) { // … } // 获得选中的头像的索引 int faceId = lvFaces.SelectedItems[0].ImageIndex;
第四次集中编码:A任务
个人信息修改功能
第一次集中编码:难点分析
好友列表——第三方控件 SideBar
SbGroup 类型 Items 属性 Groups 属性 SbItem 类型
第一次集中编码:难点分析
SideBar
// 命名空间 using Aptech.UI; // 添加组 sbFriends.AddGroup("我的好友"); sbFriends.AddGroup("陌生人"); 显示的文字 // 添加项 SbItem item = new SbItem((string)dataReader["NickName"], (int)dataReader["FaceId"]); sbFriends.Groups[0].Items.Add(item); 显示的图像索引
51Aspx源码必读
║ 5) 商业源码请在源码授权范围内进行使用! ║
║ ║
2.数据库:有很多朋友问数据库怎么弄,实际上截至GG的目前版本,还没有用到数据库,所有的信息都只是在内存中,所以,目前版本的GG做了一些假设:
(1)用户登录帐号随意,但必须为数字组;密码可随意输入。
(2)所有的在线用户都是好友。
3.麦克风、摄像头以及扬声器的选择可在配置文件中指定相应的Index。
GG叽叽(QQ高仿)源码
源码描述:
GG是QQ的高仿版,包括客户端和服务端,可在广域网部署使用
GG的前面几个版本开发了一些比较高级的功能,像视频聊天、远程桌面、文件传送、远程磁盘等,但是,有一些基础且必需的功能一直未实现,比如注册、添加好友、加入群、群聊天等等。经常有朋友留言问这些功能要怎么做,GG3.0终于可以给出一个答案了。
║ ║
║51Aspx声明: ║
║ 1) 本站不保证所提供软件或程序的完整性和安全性。 ║
║ 51Aspx —— .Net源码服务专家 ║
║ 联系方式 : support@ ║
║ ╭──────────────────────╮ ║
╭══════┤ ├══════╮
║ ║ 论坛: ║ ║
║ ╰═══════════════╯ ║
4.语音视频:也有很多朋友问语音视频设备的工作怎么不正常,或者语音视频不流畅,这个可以直接参考OMCS官方文档:摄像头、麦克风、扬声器、设备测试 、带宽要求。
5.GG使用了最新版本的SkinForm,如果有关于SkinForm的问题,可以直接联系我的好友 威廉乔克斯_汀。
6.特别说明一下:GG项目中,只要是我写的代码,全部都放出来了。拜托喜欢每一个dll都有源码的朋友不要再问我要其它的源码了:)
qq源代码
UserHelper..cs类代码using System;using System.Collections.Generic;using System.Text;namespace MyQQ{//记录登录的用户Idclass UserHelper{public static int loginId; //登录的用户Id}}using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///聊天窗体///</summary>public partial class ChatForm : Form{public int friendId; // 当前聊天的好友号码public string nickName; // 当前聊天的好友昵称public int faceId; // 当前聊天的好友头像Idpublic ChatForm(){InitializeComponent();}// 窗体加载时的动作private void ChatForm_Load(object sender, EventArgs e){// 设置窗体标题this.Text = string.Format("与{0}聊天中",nickName);// 设置窗体顶部显示的好友信息picFace.Image = ilFaces.Images[faceId];lblFriend.Text = string.Format("{0}({1})",nickName,friendId);// 读取所有的未读消息,显示在窗体中ShowMessage();}// 关闭窗体private void btnClose_Click(object sender, EventArgs e){this.Close();}// 发送消息private void btnSend_Click(object sender, EventArgs e){if (txtChat.Text.Trim() == "") // 不能发送空消息{MessageBox.Show("不能发送空消息!", "提示", MessageBoxButtons.OK, rmation);return;}else if (txtChat.Text.Trim().Length > 50){MessageBox.Show("消息内容过长,请分为几条发送!", "提示", MessageBoxButtons.OK, rmation);return;}else// 发送消息,写入数据库{// MessageTypeId:1-表示聊天消息,为简化操作没有读取数据表,到S2可以用常量或者枚举实现// MessageState:0-表示消息状态是未读int result = -1; // 表示操作数据库的结果string sql = string.Format("INSERT INTO Messages (FromUserId, ToUserId, Message, MessageTypeId,MessageState) VALUES ({0},{1},'{2}',{3},{4})",UserHelper.loginId, friendId, txtChat.Text.Trim(), 1, 0);try{// 执行命令SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result != 1){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}txtChat.Text = ""; // 输入消息清空this.Close();}}///<summary>///读取所有的未读消息,显示在窗体中///</summary>private void ShowMessage(){string messageIdsString = ""; // 消息的Id组成的字符串string message; // 消息内容string messageTime; // 消息发出的时间// 读取消息的SQL语句string sql = string.Format("SELECT Id, Message,MessageTime From Messages WHERE FromUserId={0} AND ToUserId={1} AND MessageTypeId=1 AND MessageState=0",friendId,UserHelper.loginId);try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader reader = command.ExecuteReader();// 循环将消息添加到窗体上while (reader.Read()){messageIdsString += Convert.ToString(reader["Id"]) + "_";message = Convert.ToString(reader["Message"]);messageTime = Convert.ToDateTime(reader["MessageTime"]).ToString(); // 转换为日期类型,告诉学员lblMessages.Text += string.Format("\n{0} {1}\n{2}",nickName,messageTime,message);}reader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 把显示出的消息置为已读if (messageIdsString.Length > 1){messageIdsString.Remove(messageIdsString.Length - 1);SetMessageRead(messageIdsString, '_');}}///<summary>///把显示出的消息置为已读///</summary>private void SetMessageRead(string messageIdsString, char separator){string[] messageIds = messageIdsString.Split(separator); // 分割出每个消息Idstring sql = "Update Messages SET MessageState=1 WHERE Id="; // 更新状态的SQL语句的固定部分string updateSql; // 执行的SQL语句try{SqlCommand command = new SqlCommand(); // 创建Command对象command.Connection = DBHelper.connection; // 指定数据库连接DBHelper.connection.Open(); // 打开数据库连接foreach (string id in messageIds){if (id != ""){updateSql = sql + id; // 补充完整的SQL语句 mandText = updateSql; // 指定要执行的SQL语句int result = command.ExecuteNonQuery(); // 执行命令}}}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}}ChatForm.cs代码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///聊天窗体///</summary>public partial class ChatForm : Form{public int friendId; // 当前聊天的好友号码public string nickName; // 当前聊天的好友昵称public int faceId; // 当前聊天的好友头像Idpublic ChatForm(){InitializeComponent();}// 窗体加载时的动作private void ChatForm_Load(object sender, EventArgs e){// 设置窗体标题this.Text = string.Format("与{0}聊天中",nickName);// 设置窗体顶部显示的好友信息picFace.Image = ilFaces.Images[faceId];lblFriend.Text = string.Format("{0}({1})",nickName,friendId);// 读取所有的未读消息,显示在窗体中ShowMessage();}// 关闭窗体private void btnClose_Click(object sender, EventArgs e){this.Close();}// 发送消息private void btnSend_Click(object sender, EventArgs e){if (txtChat.Text.Trim() == "") // 不能发送空消息{MessageBox.Show("不能发送空消息!", "提示", MessageBoxButtons.OK, rmation);return;}else if (txtChat.Text.Trim().Length > 50){MessageBox.Show("消息内容过长,请分为几条发送!", "提示", MessageBoxButtons.OK, rmation);return;}else// 发送消息,写入数据库{// MessageTypeId:1-表示聊天消息,为简化操作没有读取数据表,到S2可以用常量或者枚举实现// MessageState:0-表示消息状态是未读int result = -1; // 表示操作数据库的结果string sql = string.Format("INSERT INTO Messages (FromUserId, ToUserId, Message, MessageTypeId, MessageState) VALUES ({0},{1},'{2}',{3},{4})",UserHelper.loginId, friendId, txtChat.Text.Trim(), 1, 0);try{// 执行命令SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result != 1){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}txtChat.Text = ""; // 输入消息清空this.Close();}}///<summary>///读取所有的未读消息,显示在窗体中///</summary>private void ShowMessage(){string messageIdsString = ""; // 消息的Id组成的字符串string message; // 消息内容string messageTime; // 消息发出的时间// 读取消息的SQL语句string sql = string.Format("SELECT Id, Message,MessageTime From Messages WHERE FromUserId={0} AND ToUserId={1} AND MessageTypeId=1 AND MessageState=0",friendId,UserHelper.loginId);try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader reader = command.ExecuteReader();// 循环将消息添加到窗体上while (reader.Read()){messageIdsString += Convert.ToString(reader["Id"]) + "_";message = Convert.ToString(reader["Message"]);messageTime = Convert.ToDateTime(reader["MessageTime"]).ToString(); // 转换为日期类型,告诉学员lblMessages.Text += string.Format("\n{0} {1}\n{2}",nickName,messageTime,message);}reader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 把显示出的消息置为已读if (messageIdsString.Length > 1){messageIdsString.Remove(messageIdsString.Length - 1);SetMessageRead(messageIdsString, '_');}}///<summary>///把显示出的消息置为已读///</summary>private void SetMessageRead(string messageIdsString, char separator){string[] messageIds = messageIdsString.Split(separator); // 分割出每个消息Idstring sql = "Update Messages SET MessageState=1 WHERE Id="; // 更新状态的SQL语句的固定部分string updateSql; // 执行的SQL语句try{SqlCommand command = new SqlCommand(); // 创建Command对象command.Connection = DBHelper.connection; // 指定数据库连接DBHelper.connection.Open(); // 打开数据库连接foreach (string id in messageIds){if (id != ""){updateSql = sql + id; // 补充完整的SQL语句 mandText = updateSql; // 指定要执行的SQL语句int result = command.ExecuteNonQuery(); // 执行命令}}}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}}private void lblMessages_Click(object sender, EventArgs e){}}}DBHelper.cs类代码using System;using System.Collections.Generic;using System.Text;using System.Data.SqlClient;namespace MyQQ{// 数据库帮助类,维护数据库连接字符串和数据库连接对象class DBHelper{private static string connString = "Data Source=.;database=MyQQ;integrated security=sspi";public static SqlConnection connection = new SqlConnection(connString);}}using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;namespace MyQQ{///<summary>///头像选择窗体///</summary>public partial class FacesForm : Form{public PersonalInfoForm personalInfoForm; // 个人信息窗体public FacesForm(){InitializeComponent();}1.FacesForm.cs代码private void FacesForm_Load(object sender, EventArgs e){for (int i = 0; i < ilFaces.Images.Count; i++){lvFaces.Items.Add(i.ToString());lvFaces.Items[i].ImageIndex = i;}}// 确定选择头像private void btnOK_Click(object sender, EventArgs e){if (lvFaces.SelectedItems.Count == 0){MessageBox.Show("请选择一个头像!", "提示", MessageBoxButtons.OK, rmation);}else{int faceId = lvFaces.SelectedItems[0].ImageIndex; // 获得当前选中的头像的索引personalInfoForm.ShowFace(faceId); // 设置个人信息窗体中显示的头像this.Close();}}// 双击时选择头像private void lvIcons_MouseDoubleClick(object sender, MouseEventArgs e){int faceId = lvFaces.SelectedItems[0].ImageIndex; // 获得当前选中的头像的索引 personalInfoForm.ShowFace(faceId); // 设置个人信息窗体中显示的头像this.Close();}// 关闭窗体private void btnCancel_Click(object sender, EventArgs e){this.Close();}}}LoginForm.csusing System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///登录窗体///</summary>public partial class LoginForm : Form{public LoginForm(){InitializeComponent();}// 取消按钮的事件处理private void btnCancel_Click(object sender, EventArgs e){Application.Exit();}// 打开申请号码界面private void llbl_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {RegisterForm registerForm = new RegisterForm();registerForm.Show();}// 登录按钮事件处理private void btnLogin_Click(object sender, EventArgs e){bool error = false; // 标志在执行数据库操作的过程中是否出错// 如果输入验证成功,就验证身份,并转到相应的窗体if (ValidateInput()){int num = 0; // 数据库操作结果try{// 查询用的sql语句string sql = string.Format("SELECT COUNT(*) FROM Users WHERE Id={0} AND LoginPwd = '{1}'",int.Parse(txtLoginId.Text.Trim()), txtLoginPwd.Text.Trim());// 创建Command 对象SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open(); // 打开数据库连接num = Convert.ToInt32(command.ExecuteScalar());}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close(); // 关闭数据库连接}if (!error && (num == 1)) // 验证通过{// 设置登录的用户号码UserHelper.loginId = int.Parse(txtLoginId.Text.Trim());// 创建主窗体MainForm mainForm = new MainForm();mainForm.Show(); // 显示窗体this.Visible = false; // 当前窗体不可见}else{MessageBox.Show("输入的用户名或密码有误!", "登录提示", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}// 忘记密码标签private void llblFogetPwd_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {MessageBox.Show("该功能尚未开通!","提示",MessageBoxButtons.OK,rmation);}// 用户输入验证private bool ValidateInput(){// 验证用户输入if (txtLoginId.Text.Trim() == ""){MessageBox.Show("请输入登录的号码", "登录提示", MessageBoxButtons.OK, rmation);txtLoginId.Focus();return false;}else if (txtLoginPwd.Text.Trim() == ""){MessageBox.Show("请输入密码", "登录提示", MessageBoxButtons.OK, rmation);txtLoginPwd.Focus();return false;}return true;}}}MainForm.csusing System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using Aptech.UI;using System.Data.SqlClient;using System.Media;namespace MyQQ{///<summary>///登录后的主窗体///</summary>public partial class MainForm : Form{int fromUserId; // 消息的发起者int friendFaceId; // 发消息的好友的头像Idint messageImageIndex = 0; // 工具栏中的消息图标的索引public MainForm(){InitializeComponent();}// 窗体加载时发生private void MainForm_Load(object sender, EventArgs e) {// 工具栏的消息图标tsbtnMessageReading.Image = ilMessage.Images[0];// 显示个人的信息ShowSelfInfo();// 添加SideBar 的两个组sbFriends.AddGroup("我的好友");sbFriends.AddGroup("陌生人");// 向我的好友组中添加我的好友列表ShowFriendList();}// 窗体关闭后,退出应用程序private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {Application.Exit();}// 显示个人信息窗体private void tsbtnPersonalInfo_Click(object sender, EventArgs e){PersonalInfoForm personalInfoForm = new PersonalInfoForm();personalInfoForm.mainForm = this; // 将当前窗体本身传给个人信息窗体 personalInfoForm.Show();}// 显示查找好友窗体private void tsbtnSearchFriend_Click(object sender, EventArgs e){SearchFriendForm searchFriendForm = new SearchFriendForm();searchFriendForm.Show();}// 双击一项,弹出聊天窗体private void sbFriends_ItemDoubleClick(SbItemEventArgs e){// 消息timer停止运行if (tmrChatRequest.Enabled == true){tmrChatRequest.Stop();e.Item.ImageIndex = this.friendFaceId;}// 显示聊天窗体ChatForm chatForm = new ChatForm();chatForm.friendId = Convert.ToInt32(e.Item.Tag); // 号码chatForm.nickName = e.Item.Text; // 昵称chatForm.faceId = e.Item.ImageIndex; // 头像chatForm.Show();}// 点击刷新好友列表private void tsbtnUpdateFriendList_Click(object sender, EventArgs e){ShowFriendList();}// 定时扫描数据库,找到未读消息private void tmrMessage_Tick(object sender, EventArgs e){ShowFriendList(); // 刷新好友列表int messageTypeId = 1; // 消息类型int messageState = 1; // 消息状态// 找出未读消息对应的好友Idstring sql = string.Format("SELECT Top 1 FromUserId, MessageTypeId, MessageState FROM Messages WHERE ToUserId={0} AND MessageState=0", UserHelper.loginId);SqlCommand command;// 消息有两种类型:聊天消息、添加好友消息try{command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();// 循环读出一个未读消息if (dataReader.Read()){this.fromUserId = (int)dataReader["FromUserId"];messageTypeId = (int)dataReader["MessageTypeId"];messageState = (int)dataReader["MessageState"];}dataReader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 判断消息类型,如果是添加好友消息,就启动喇叭timer,让小喇叭闪烁if (messageTypeId == 2 && messageState == 0){SoundPlayer player = new SoundPlayer("system.wav");player.Play();tmrAddFriend.Start();}// 如果是聊天消息,就启动聊天timer,让好友头像闪烁else if (messageTypeId == 1 && messageState == 0){// 获得发消息的人的头像Idsql = "SELECT FaceId FROM Users WHERE Id=" + this.fromUserId;try{command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();this.friendFaceId = Convert.ToInt32(command.ExecuteScalar()); // 设置发消息的好友的头像索引}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 如果发消息的人没有在列表中就添加到陌生人列表中if (!HasShowUser(fromUserId)){UpdateStranger(fromUserId);}SoundPlayer player = new SoundPlayer("msg.wav");player.Play();tmrChatRequest.Start(); // 启动闪烁头像定时器}}// 控制喇叭闪烁private void tmrAddFriend_Tick(object sender, EventArgs e){// 反复修改它的图像messageImageIndex = messageImageIndex == 0 ? 1:0;tsbtnMessageReading.Image = ilMessage.Images[messageImageIndex];}// 单击时显示请求好友消息窗体private void tsbtnMessageReading_Click(object sender, EventArgs e){tmrAddFriend.Stop(); // 消息timer停止运行// 图片恢复正常messageImageIndex = 0;tsbtnMessageReading.Image = ilMessage.Images[messageImageIndex];// 显示系统消息窗体RequestForm requestForm = new RequestForm();requestForm.Show();}// 让相应的好友头像闪烁private void tmrChatRequest_Tick(object sender, EventArgs e){// 循环好友列表两个组中的每个item,找到发消息的好友,让他的头像闪烁for (int i = 0; i < 2; i++){for (int j = 0; j < sbFriends.Groups[i].Items.Count; j++){if(Convert.ToInt32(sbFriends.Groups[i].Items[j].Tag) == this.fromUserId) {if (sbFriends.Groups[i].Items[j].ImageIndex < 100){sbFriends.Groups[i].Items[j].ImageIndex = 100;// 索引为的图片是一个空白图片}else{sbFriends.Groups[i].Items[j].ImageIndex = this.friendFaceId;}sbFriends.Invalidate(); // 重新绘制,只要告诉学生需要这句话才能正常闪烁头像就行}}}}// 显示右键菜单时,控制哪些菜单不可见private void cmsFriendList_Opening(object sender, CancelEventArgs e){// 如果没有选中的项if (sbFriends.SeletedItem == null){tsmiDelete.Visible = false;}else{tsmiDelete.Visible = true;}// 如果选中的是陌生人,显示加为好友菜单if (sbFriends.SeletedItem != null && sbFriends.SeletedItem.Parent == sbFriends.Groups[1]){tsmiAddFriend.Visible = true;}else{tsmiAddFriend.Visible = false;}}// 显示大、小头像视图切换private void tsmiView_Click(object sender, EventArgs e){if (sbFriends.View == rgeIcon){sbFriends.View = SbView.SmallIcon;tsmiView.Text = "显示大头像";}else if (sbFriends.View == SbView.SmallIcon){sbFriends.View = rgeIcon;tsmiView.Text = "显示小头像";}}// 删除好友private void tsmiDelete_Click(object sender, EventArgs e){DialogResult result; // 对话框结果int deleteResult = 0; // 操作结果if (sbFriends.SeletedItem != null){result = MessageBox.Show("确实要删除该好友吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes) // 确认删除{if (sbFriends.VisibleGroup == sbFriends.Groups[0]){string sql = string.Format("DELETE FROM Friends WHERE HostId={0} AND FriendId={1}",UserHelper.loginId, Convert.ToInt32(sbFriends.SeletedItem.Tag));try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();deleteResult = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (deleteResult == 1){MessageBox.Show("好友已删除", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);}}else{MessageBox.Show("好友已删除", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);}}}}// 将选中的人加为好友private void tsmiAddFriend_Click(object sender, EventArgs e){int result = 0; // 操作结果string sql = string.Format("INSERT INTO Friends (HostId, FriendId) VALUES({0},{1})",UserHelper.loginId, Convert.ToInt32(sbFriends.SeletedItem.Tag));try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result == 1){MessageBox.Show("添加成功!", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);ShowFriendList(); // 更新好友列表}else{MessageBox.Show("添加失败,请稍候再试!", "提示", MessageBoxButtons.OK, rmation);}}// 退出private void tsbtnExit_Click(object sender, EventArgs e){DialogResult result = MessageBox.Show("确实要退出吗?", "操作确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes){Application.Exit();}}// 可见组发生变化时,发出声音private void sbFriends_VisibleGroupChanged(SbGroupEventArgs e){SoundPlayer player = new SoundPlayer("folder.wav");player.Play();}///<summary>///登录后显示个人的信息///</summary>public void ShowSelfInfo(){string nickName = ""; // 昵称int faceId = 0; // 头像索引bool error = false; // 标识是否出现错误// 取得当前用户的昵称、头像string sql = string.Format("SELECT NickName, FaceId FROM Users WHERE Id={0}",UserHelper.loginId);try{// 查询SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();if (dataReader.Read()){if (!(dataReader["NickName"] is DBNull)) // 判断数据库类型是否为空 {nickName = Convert.ToString(dataReader["NickName"]);}faceId = Convert.ToInt32(dataReader["FaceId"]);}dataReader.Close();}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 根据操作数据库结果进行不同的操作if (error){MessageBox.Show("服务器请求失败!请重新登录!", "意外错误", MessageBoxButtons.OK, MessageBoxIcon.Error);Application.Exit();}else{// 在窗体标题显示登录的昵称、号码this.Text = UserHelper.loginId.ToString();this.picFace.Image = ilFaces.Images[faceId];this.lblLoginId.Text = string.Format("{0}({1})", nickName,UserHelper.loginId.ToString());}}///<summary>///向我的好友组中添加我的好友列表///</summary>private void ShowFriendList(){// 清空原来的列表sbFriends.Groups[0].Items.Clear();bool error = false; // 标识数据库是否出错// 查找有哪些好友string sql = string.Format("SELECT FriendId,NickName,FaceId FROM Users,Friends WHERE Friends.HostId={0} AND Users.Id=Friends.FriendId",UserHelper.loginId);try{// 执行查询SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();// 循环添加好友列表while (dataReader.Read()){// 创建一个SideBar项SbItem item = new SbItem((string)dataReader["NickName"], (int)dataReader["FaceId"]);item.Tag = (int)dataReader["FriendId"]; // 将号码放在Tag属性中// SideBar中的组可以通过数组的方式访问,按照添加的顺序索引从开始// Groups[0]表示SideBar中的第一个组,也就是“我的好友”组sbFriends.Groups[0].Items.Add(item); // 向SideBar的“我的好友”组中添加项 }dataReader.Close();}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 出错了if (error){MessageBox.Show("服务器发生意外错误!请尝试重新登录", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);Application.Exit();}}///<summary>///判断发消息的人是否在列表中///</summary>private bool HasShowUser(int loginId){bool find = false; // 表示是否在当前显示出的用户列表中找到了该用户// 循环SideBar 中的个组,寻找发消息的人是否在列表中for (int i = 0; i < 2; i++){for (int j = 0; j < sbFriends.Groups[i].Items.Count; j++){if (Convert.ToInt32(sbFriends.Groups[i].Items[j].Tag) == loginId){find = true;}}}return find;}///<summary>///更新陌生人列表///</summary>private void UpdateStranger(int loginId){// 选出这个人的基本信息string sql = "SELECT NickName, FaceId FROM Users WHERE Id=" + loginId;bool error = false; // 用来标识是否出现错误try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader(); // 查询if (dataReader.Read()){SbItem item = new SbItem((string)dataReader["NickName"],(int)dataReader["FaceId"]);item.Tag = this.fromUserId; // 将Id记录在Tag属性中sbFriends.Groups[1].Items.Add(item); // 向陌生人组中添加项}sbFriends.VisibleGroup = sbFriends.Groups[1]; // 设定陌生人组为可见组 }catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 出错了if (error){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}}(资料素材和资料部分来自网络,供参考。
qq木马源代码 (2)
/************************************************************************/
/* 其它直接用IoCallDriver把IRP传到下一层驱动中 */
/************************************************************************/
0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09, //normal
0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x0D, 0x00, 0x61, 0x73,
ULONG s_UpChar=0;
typedef struct _FILTER_DEVICE_EXTEN
{
PDEVICE_OBJECT pFilterDeviceObject;//过滤设备
PDEVICE_OBJECT pTagerDeviceObject;//绑定的设备对象
KSPIN_LOCK Lockspin;//调用时的保护锁
0x32, 0x33, 0x30, 0x2E,
0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09, //shift
0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0x0D, 0x00, 0x41, 0x53,
高仿QQ截图程序C#源码
高仿QQ截图程序C#源码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;namespace _SCREEN_CAPTURE{public partial class FrmCapture : Form{public FrmCapture() {InitializeComponent();this.FormBorderStyle = FormBorderStyle.None;this.Location = new Point(0, 0);this.Size = new Size(Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height);this.TopMost = true;this.ShowInTaskbar = false;m_MHook = new MouseHook();this.FormClosing += (s, e) => { m_MHook.UnLoadHook(); this.DelResource(); };imageProcessBox1.MouseLeave += (s, e) => this.Cursor = Cursors.Default;//后期一些操作历史记录图层m_layer = new List<Bitmap>();}private void DelResource() {if (m_bmpLayerCurrent != null) m_bmpLayerCurrent.Dispose();if (m_bmpLayerShow != null) m_bmpLayerShow.Dispose();m_layer.Clear();imageProcessBox1.DeleResource();GC.Collect();}#region Propertiesprivate bool isCaptureCursor;/// <summary>/// 获取或设置是否捕获鼠标/// </summary>public bool IsCaptureCursor {get { return isCaptureCursor; }set { isCaptureCursor = value; }}/// <summary>/// 获取或设置是否显示图像信息/// </summary>public bool ImgProcessBoxIsShowInfo {get { return imageProcessBox1.IsShowInfo; }set { imageProcessBox1.IsShowInfo = value; }}/// <summary>/// 获取或设置操作框点的颜色/// </summary>public Color ImgProcessBoxDotColor {get { return imageProcessBox1.DotColor; }set { imageProcessBox1.DotColor = value; }}/// <summary>/// 获取或设置操作框边框颜色/// </summary>public Color ImgProcessBoxLineColor {get { return imageProcessBox1.LineColor; }set { imageProcessBox1.LineColor = value; }}/// <summary>/// 获取或设置放大图形的原始尺寸/// </summary>public Size ImgProcessBoxMagnifySize {get { return imageProcessBox1.MagnifySize; }set { imageProcessBox1.MagnifySize = value; }}/// <summary>/// 获取或设置放大图像的倍数/// </summary>public int ImgProcessBoxMagnifyTimes {get { return imageProcessBox1.MagnifyTimes; }set { imageProcessBox1.MagnifyTimes = value; }}#endregion//初始化参数private void InitMember() {panel1.Visible = false;panel2.Visible = false;panel1.BackColor = Color.White;panel2.BackColor = Color.White;panel1.Height = tBtn_Finish.Bottom + 3;panel1.Width = tBtn_Finish.Right + 3;panel2.Height = colorBox1.Height;panel1.Paint += (s, e) => e.Graphics.DrawRectangle(Pens.SteelBlue, 0, 0, panel1.Width - 1, panel1.Height - 1);panel2.Paint += (s, e) => e.Graphics.DrawRectangle(Pens.SteelBlue, 0, 0, panel2.Width - 1, panel2.Height - 1);tBtn_Rect.Click += new EventHandler(selectToolButton_Click);tBtn_Ellipse.Click += new EventHandler(selectToolButton_Click);tBtn_Arrow.Click += new EventHandler(selectToolButton_Click);tBtn_Brush.Click += new EventHandler(selectToolButton_Click);tBtn_Text.Click += new EventHandler(selectToolButton_Click);tBtn_Close.Click += (s, e) => this.Close();textBox1.BorderStyle = BorderStyle.None;textBox1.Visible = false;textBox1.ForeColor = Color.Red;colorBox1.ColorChanged += (s, e) => textBox1.ForeColor = e.Color;}private MouseHook m_MHook;private List<Bitmap> m_layer; //记录历史图层private bool m_isStartDraw;private Point m_ptOriginal;private Point m_ptCurrent;private Bitmap m_bmpLayerCurrent;private Bitmap m_bmpLayerShow;private void FrmCapture_Load(object sender, EventArgs e) {this.InitMember();imageProcessBox1.BaseImage = this.GetScreen();m_MHook.SetHook();m_MHook.MHookEvent += new MouseHook.MHookEventHandler(m_MHook_MHookEvent);imageProcessBox1.IsDrawOperationDot = false;this.BeginInvoke(new MethodInvoker(() => this.Enabled = false));timer1.Interval = 500;timer1.Enabled = true;}private void m_MHook_MHookEvent(object sender, MHookEventArgs e) {//如果窗体禁用调用控件的方法设置信息显示位置if (!this.Enabled) //貌似Hook不能精确坐标(Hook最先执行执执行完后的坐标可能与执行时传入的坐标发生了变化猜测是这样) 所以放置了一个timer检测imageProcessBox1.SetInfoPoint(MousePosition.X, MousePosition.Y);//鼠标点下恢复窗体禁用if (e.MButton == ButtonStatus.LeftDown || e.MButton == ButtonStatus.RightDown) {this.Enabled = true;imageProcessBox1.IsDrawOperationDot = true;}#region 在imageProcessBox_MouseUp中完成了//if (e.MButton == ButtonStatus.LeftUp) {// //if (imageProcessBox1.SelectedRectangle.Width < 5// // || imageProcessBox1.SelectedRectangle.Height < 5) {// // //如果选取区域不符要求向控件模拟鼠标抬起然后禁用窗体// // //(Hook事件先于控件事件禁用控件时模拟一个鼠标抬起)// // Win32.SendMessage(imageProcessBox1.Handle, Win32.WM_LBUTTONUP,// // IntPtr.Zero, (IntPtr)(MousePosition.Y << 16 | MousePosition.X));// // this.Enabled = false;// // imageProcessBox1.IsDrawOperationDot = false;// //} else// // this.SetToolBarLocation(); //重置工具条位置//}#endregion#region 右键抬起if (e.MButton == ButtonStatus.RightUp) {if (!imageProcessBox1.IsDrawed) //没有绘制那么退出(直接this.Close右键将传递到下面)this.BeginInvoke(new MethodInvoker(() => this.Close()));//有绘制的情况情况继续禁用窗体this.Enabled = false;imageProcessBox1.ClearDraw();imageProcessBox1.CanReset = true;imageProcessBox1.IsDrawOperationDot = false;m_layer.Clear(); //清空历史记录m_bmpLayerCurrent = null;m_bmpLayerShow = null;ClearToolBarBtnSelected();panel1.Visible = false;panel2.Visible = false;}#endregion#region 找寻窗体if (!this.Enabled) {this.FoundAndDrawWindowRect();}#endregion}//工具条前五个按钮绑定的公共事件private void selectToolButton_Click(object sender, EventArgs e) {panel2.Visible = ((ToolButton)sender).IsSelected;if (panel2.Visible) imageProcessBox1.CanReset = false;else { imageProcessBox1.CanReset = m_layer.Count == 0; }this.SetToolBarLocation();}#region 截图后的一些后期绘制private void imageProcessBox1_MouseDown(object sender, MouseEventArgs e) { if (imageProcessBox1.Cursor != Cursors.SizeAll &&imageProcessBox1.Cursor != Cursors.Default)panel1.Visible = false; //表示改变选取大小隐藏工具条//若果在选取类点击并且有选择工具if (e.Button == MouseButtons.Left && imageProcessBox1.IsDrawed && HaveSelectedToolButton()) {if (imageProcessBox1.SelectedRectangle.Contains(e.Location)) {if (tBtn_Text.IsSelected) { //如果选择的是绘制文本弹出文本框textBox1.Location = e.Location;textBox1.Visible = true;textBox1.Focus();return;}m_isStartDraw = true;Cursor.Clip = imageProcessBox1.SelectedRectangle;}}m_ptOriginal = e.Location;}private void imageProcessBox1_MouseMove(object sender, MouseEventArgs e) { m_ptCurrent = e.Location;//根据是否选择有工具决定鼠标指针样式if (imageProcessBox1.SelectedRectangle.Contains(e.Location) && HaveSelectedToolButton() && imageProcessBox1.IsDrawed)this.Cursor = Cursors.Cross;else if (!imageProcessBox1.SelectedRectangle.Contains(e.Location))this.Cursor = Cursors.Default;if (imageProcessBox1.IsStartDraw && panel1.Visible) //在重置选取的时候重置工具条位置(成立于移动选取的时候)this.SetToolBarLocation();if (m_isStartDraw && m_bmpLayerShow != null) { //如果在区域内点下那么绘制相应图形using (Graphics g = Graphics.FromImage(m_bmpLayerShow)) {int tempWidth = 1;if (toolButton2.IsSelected) tempWidth = 3;if (toolButton3.IsSelected) tempWidth = 5;Pen p = new Pen(colorBox1.SelectedColor, tempWidth);#region 绘制矩形if (tBtn_Rect.IsSelected) {int tempX = e.X - m_ptOriginal.X > 0 ? m_ptOriginal.X : e.X;int tempY = e.Y - m_ptOriginal.Y > 0 ? m_ptOriginal.Y : e.Y;g.Clear(Color.Transparent);g.DrawRectangle(p, tempX - imageProcessBox1.SelectedRectangle.Left, tempY - imageProcessBox1.SelectedRectangle.Top, Math.Abs(e.X - m_ptOriginal.X), Math.Abs(e.Y - m_ptOriginal.Y));imageProcessBox1.Invalidate();}#endregion#region 绘制圆形if (tBtn_Ellipse.IsSelected) {g.DrawLine(Pens.Red, 0, 0, 200, 200);g.Clear(Color.Transparent);g.DrawEllipse(p, m_ptOriginal.X - imageProcessBox1.SelectedRectangle.Left, m_ptOriginal.Y - imageProcessBox1.SelectedRectangle.Top, e.X - m_ptOriginal.X, e.Y - m_ptOriginal.Y);imageProcessBox1.Invalidate();}#endregion#region 绘制箭头if (tBtn_Arrow.IsSelected) {g.Clear(Color.Transparent);System.Drawing.Drawing2D.AdjustableArrowCap lineArrow =new System.Drawing.Drawing2D.AdjustableArrowCap(4, 4, true);p.CustomEndCap = lineArrow;g.DrawLine(p, (Point)((Size)m_ptOriginal - (Size)imageProcessBox1.SelectedRectangle.Location), (Point)((Size)m_ptCurrent - (Size)imageProcessBox1.SelectedRectangle.Location));imageProcessBox1.Invalidate();}#endregion#region 绘制线条if (tBtn_Brush.IsSelected) {Point ptTemp = (Point)((Size)m_ptOriginal - (Size)imageProcessBox1.SelectedRectangle.Location);p.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;g.DrawLine(p, ptTemp, (Point)((Size)e.Location - (Size)imageProcessBox1.SelectedRectangle.Location));m_ptOriginal = e.Location;imageProcessBox1.Invalidate();}#endregionp.Dispose();}}}private void imageProcessBox1_MouseUp(object sender, MouseEventArgs e) { if (!imageProcessBox1.IsDrawed) { //如果没有成功绘制选取继续禁用窗体this.Enabled = false;imageProcessBox1.IsDrawOperationDot = false;} else if (!panel1.Visible) { //否则显示工具条this.SetToolBarLocation(); //重置工具条位置panel1.Visible = true;m_bmpLayerCurrent = imageProcessBox1.GetResultBmp(); //获取选取图形m_bmpLayerShow = new Bitmap(m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height);}//如果移动了选取位置重新获取选取的图形if (imageProcessBox1.Cursor == Cursors.SizeAll && m_ptOriginal != e.Location) m_bmpLayerCurrent = imageProcessBox1.GetResultBmp();if (!m_isStartDraw) return;Cursor.Clip = Rectangle.Empty;m_isStartDraw = false;if (e.Location == m_ptOriginal && !tBtn_Brush.IsSelected) return;this.SetLayer(); //将绘制的图形绘制到历史图层中}//绘制后期操作private void imageProcessBox1_Paint(object sender, PaintEventArgs e) {Graphics g = e.Graphics;if (m_layer.Count > 0) //绘制保存的历史记录的最后一张图g.DrawImage(m_layer[m_layer.Count - 1], imageProcessBox1.SelectedRectangle.Location);if (m_bmpLayerShow != null) //绘制当前正在拖动绘制的图形(即鼠标点下还没有抬起确认的图形)g.DrawImage(m_bmpLayerShow,imageProcessBox1.SelectedRectangle.Location);}#endregion//文本改变时重置文本框大小private void textBox1_TextChanged(object sender, EventArgs e) {Size se = TextRenderer.MeasureText(textBox1.Text, textBox1.Font);textBox1.Size = se.IsEmpty ? new Size(50, textBox1.Font.Height) : se;}//文本框失去焦点时绘制文本private void textBox1_Validating(object sender, CancelEventArgs e) {textBox1.Visible = false;if (string.IsNullOrEmpty(textBox1.Text.Trim())) { textBox1.Text = ""; return; }using (Graphics g = Graphics.FromImage(m_bmpLayerCurrent)) {SolidBrush sb = new SolidBrush(colorBox1.SelectedColor);g.DrawString(textBox1.Text, textBox1.Font, sb,textBox1.Left - imageProcessBox1.SelectedRectangle.Left,textBox1.Top - imageProcessBox1.SelectedRectangle.Top);sb.Dispose();textBox1.Text = "";this.SetLayer(); //将文本绘制到当前图层并存入历史记录imageProcessBox1.Invalidate();}}//窗体大小改变时重置字体从控件中获取字体大小private void textBox1_Resize(object sender, EventArgs e) {//在三个大小选择的按钮点击中设置字体大小太麻烦所以Resize中获取设置int se = 10;if (toolButton2.IsSelected) se = 12;if (toolButton3.IsSelected) se = 14;if (this.textBox1.Font.Height == se) return;textBox1.Font = new Font(this.Font.FontFamily, se);}//撤销private void tBtn_Cancel_Click(object sender, EventArgs e) {using (Graphics g = Graphics.FromImage(m_bmpLayerShow)) {g.Clear(Color.Transparent); //情况当前临时显示的图像}if (m_layer.Count > 0) { //删除最后一层m_layer.RemoveAt(m_layer.Count - 1);if (m_layer.Count > 0)m_bmpLayerCurrent = m_layer[m_layer.Count - 1].Clone(new Rectangle(0, 0, m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height), m_bmpLayerCurrent.PixelFormat);elsem_bmpLayerCurrent = imageProcessBox1.GetResultBmp();imageProcessBox1.Invalidate();imageProcessBox1.CanReset = m_layer.Count == 0 && !HaveSelectedToolButton();} else { //如果没有历史记录则取消本次截图this.Enabled = false;imageProcessBox1.ClearDraw();imageProcessBox1.IsDrawOperationDot = false;panel1.Visible = false;panel2.Visible = false;}}private void tBtn_Save_Click(object sender, EventArgs e) {SaveFileDialog saveDlg = new SaveFileDialog();saveDlg.Filter = "位图(*.bmp)|*.bmp|JPEG(*.jpg)|*.jpg";saveDlg.FilterIndex = 1;saveDlg.FileName = "CAPTURE_" + GetTimeString();if (saveDlg.ShowDialog() == DialogResult.OK) {switch (saveDlg.FilterIndex) {case 1:m_bmpLayerCurrent.Clone(new Rectangle(0, 0, m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height),System.Drawing.Imaging.PixelFormat.Format24bppRgb).Save(saveDlg.FileName,System.Drawing.Imaging.ImageFormat.Bmp);this.Close();break;case 2:m_bmpLayerCurrent.Save(saveDlg.FileName,System.Drawing.Imaging.ImageFormat.Jpeg);this.Close();break;}}}//将图像保存到剪贴板private void tBtn_Finish_Click(object sender, EventArgs e) {Clipboard.SetImage(m_bmpLayerCurrent);this.Close();}private void imageProcessBox1_DoubleClick(object sender, EventArgs e) {Clipboard.SetImage(m_bmpLayerCurrent);this.Close();}private void timer1_Tick(object sender, EventArgs e) {if (!this.Enabled)imageProcessBox1.SetInfoPoint(MousePosition.X, MousePosition.Y);}//根据鼠标位置找寻窗体平绘制边框private void FoundAndDrawWindowRect() {Win32.LPPOINT pt = new Win32.LPPOINT();pt.X = MousePosition.X; pt.Y = MousePosition.Y;IntPtr hWnd = Win32.ChildWindowFromPointEx(Win32.GetDesktopWindow(), pt, Win32.CWP_SKIPINVISIBL | Win32.CWP_SKIPDISABLED);if (hWnd != IntPtr.Zero) {IntPtr hTemp = hWnd;while (true) {Win32.ScreenToClient(hTemp, out pt);hTemp = Win32.ChildWindowFromPointEx(hTemp, pt, Win32.CWP_All);if (hTemp == IntPtr.Zero || hTemp == hWnd)break;hWnd = hTemp;pt.X = MousePosition.X; pt.Y = MousePosition.Y; //坐标还原为屏幕坐标}Win32.LPRECT rect = new Win32.LPRECT();Win32.GetWindowRect(hWnd, out rect);imageProcessBox1.SetSelectRect(new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top));}}//获取桌面图像private Bitmap GetScreen() {Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height);if (this.isCaptureCursor) { //是否捕获鼠标//如果直接将捕获当的鼠标画在bmp上光标不会反色指针边框也很浓也就是说//尽管bmp上绘制了图像绘制鼠标的时候还是以黑色作为鼠标的背景然后在将混合好的鼠标绘制到图像会很别扭//所以干脆直接在桌面把鼠标绘制出来再截取桌面using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { //传入0默认就是桌面Win32.GetDesktopWindow()也可以Win32.PCURSORINFO pci;pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Win32.PCURSORINFO));Win32.GetCursorInfo(out pci);if (pci.hCursor != IntPtr.Zero) {Cursor cur = new Cursor(pci.hCursor);g.CopyFromScreen(0, 0, 0, 0, bmp.Size); //在桌面绘制鼠标前先在桌面绘制一下当前的桌面图像//如果不绘制当前桌面那么cur.Draw的时候会是用历史桌面的快照进行鼠标的混合那么到时候混出现底色(测试中就是这样的)cur.Draw(g, new Rectangle((Point)((Size)MousePosition - (Size)cur.HotSpot), cur.Size));}}}//做完以上操作才开始捕获桌面图像using (Graphics g = Graphics.FromImage(bmp)) {g.CopyFromScreen(0, 0, 0, 0, bmp.Size);}return bmp;}//设置工具条位置private void SetToolBarLocation() {int tempX = imageProcessBox1.SelectedRectangle.Left;int tempY = imageProcessBox1.SelectedRectangle.Bottom + 5;int tempHeight = panel2.Visible ? panel2.Height + 2 : 0;if (tempY + panel1.Height + tempHeight >= this.Height)tempY = imageProcessBox1.SelectedRectangle.Top - panel1.Height - 10 - imageProcessBox1.Font.Height;if (tempY - tempHeight <= 0) {if (imageProcessBox1.SelectedRectangle.Top - 5 - imageProcessBox1.Font.Height >= 0)tempY = imageProcessBox1.SelectedRectangle.Top + 5;elsetempY = imageProcessBox1.SelectedRectangle.Top + 10 + imageProcessBox1.Font.Height;}if (tempX + panel1.Width >= this.Width)tempX = this.Width - panel1.Width - 5;panel1.Left = tempX;panel2.Left = tempX;panel1.Top = tempY;panel2.Top = imageProcessBox1.SelectedRectangle.Top > tempY ? tempY - tempHeight : panel1.Bottom + 2;}//确定是否工具条上面有被选中的按钮private bool HaveSelectedToolButton() {return tBtn_Rect.IsSelected || tBtn_Ellipse.IsSelected|| tBtn_Arrow.IsSelected || tBtn_Brush.IsSelected|| tBtn_Text.IsSelected;}//清空选中的工具条上的工具private void ClearToolBarBtnSelected() {tBtn_Rect.IsSelected = tBtn_Ellipse.IsSelected = tBtn_Arrow.IsSelected =tBtn_Brush.IsSelected = tBtn_Text.IsSelected = false;}//设置历史图层private void SetLayer() {if (this.IsDisposed) return;using (Graphics g = Graphics.FromImage(m_bmpLayerCurrent)) {g.DrawImage(m_bmpLayerShow, 0, 0);}Bitmap bmpTemp = m_bmpLayerCurrent.Clone(new Rectangle(0, 0, m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height), m_bmpLayerCurrent.PixelFormat);m_layer.Add(bmpTemp);}//保存时获取当前时间字符串作文默认文件名private string GetTimeString() {DateTime time = DateTime.Now;return time.Date.ToShortDateString().Replace("/", "") + "_" +time.ToLongTimeString().Replace(":", "");}}}。
模仿QQ MFC 源码
登陆框.h#pragma once#include"afxcmn.h"#include"afxwin.h"// CLoginDlg 对话框class CLoginDlg : public CDialog{DECLARE_DYNAMIC(CLoginDlg)public:CLoginDlg(CWnd* pParent = NULL); // 标准构造函数virtual ~CLoginDlg();// 对话框数据enum { IDD = IDD_DIALOG_LOGIN };protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持DECLARE_MESSAGE_MAP()public:afx_msg void OnBnClickedOk();CString m_strUsername;CString m_strPassord;afx_msg void OnBnClickedButtonClose();afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnLButtonUp(UINT nFlags, CPoint point);afx_msg void OnMouseMove(UINT nFlags, CPoint point);private:BOOL m_bMoving;CPoint m_ptPreMove;public:CLinkCtrl m_cLinkRegister;CLinkCtrl m_cLinkFindpwd;static DWORD m_nIconID;//用于存放登录后托盘显示的图标afx_msg void OnNMClickSyslinkRegister(NMHDR *pNMHDR, LRESULT *pResult);afx_msg void OnNMClickSyslinkFindpwd(NMHDR *pNMHDR, LRESULT *pResult);virtual BOOL OnInitDialog();afx_msg void OnBnClickedButtonList();CButton m_btnList;afx_msg void OnPaint();afx_msg void OnOnlin();afx_msg void OnQme();afx_msg void OnLeave();afx_msg void OnBusy();afx_msg void OnDarao();afx_msg void OnYinshen();afx_msg LRESULT OnShowTask(WPARAM wParam, LPARAM lParam);void ToTray(BOOL Show);CButton m_btnJianPan;CButton m_btnConfig;CToolTipCtrl toolTipCtrl[3];NOTIFYICONDATA m_nid;virtual BOOL PreTranslateMessage(MSG* pMsg);afx_msg void Onshowwindow();afx_msg void OnOpenmainpanel();afx_msg void OnHideWindows();afx_msg void OnButtonClose();afx_msg void OnBnClickedButtonMin();afx_msg void OnBnClickedButtonJianpan();afx_msg void OnCbnSelchangeComboUsername();BOOL m_isRemPassword;afx_msg void OnBnClickedCheckSavepwd();BOOL m_isAutoLogin;afx_msg void OnBnClickedCheckAutologin();afx_msg void OnTimer(UINT_PTR nIDEvent);BOOL m_isFirstLoginAccount;//hj};登陆框.cpp// LoginDlg.cpp : 实现文件//#include"stdafx.h"#include"QQDemo.h"#include"LoginDlg.h"#include"RegisterDlg.h"#include"SeekDlg.h"#define WM_SHOWTASK WM_USER+1// CLoginDlg 对话框IMPLEMENT_DYNAMIC(CLoginDlg, CDialog)DWORD CLoginDlg::m_nIconID = IDI_IMONLINE;CLoginDlg::CLoginDlg(CWnd* pParent/*=NULL*/): CDialog(CLoginDlg::IDD, pParent), m_strUsername(_T("")), m_strPassord(_T("")), m_bMoving(FALSE), m_isRemPassword(TRUE), m_isAutoLogin(FALSE), m_isFirstLoginAccount(TRUE){}CLoginDlg::~CLoginDlg(){Shell_NotifyIcon(NIM_DELETE,&m_nid);//从托盘中删除}void CLoginDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);DDX_CBString(pDX, IDC_COMBO_USERNAME, m_strUsername);DDX_Text(pDX, IDC_EDIT_PASSWORD, m_strPassord);DDX_Control(pDX, IDC_SYSLINK_REGISTER, m_cLinkRegister);DDX_Control(pDX, IDC_SYSLINK_FINDPWD, m_cLinkFindpwd);DDX_Control(pDX, IDC_BUTTON_LIST, m_btnList);DDX_Control(pDX, IDC_BUTTON_JIANPAN, m_btnJianPan);DDX_Control(pDX, IDC_BUTTON_CONFIG, m_btnConfig);DDX_Check(pDX, IDC_CHECK_SA VEPWD, m_isRemPassword);DDX_Check(pDX, IDC_CHECK_AUTOLOGIN, m_isAutoLogin);}BEGIN_MESSAGE_MAP(CLoginDlg, CDialog)ON_BN_CLICKED(IDOK, &CLoginDlg::OnBnClickedOk)ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CLoginDlg::OnBnClickedButtonClose)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_MESSAGE(WM_SHOWTASK, &CLoginDlg::OnShowTask)ON_NOTIFY(NM_CLICK, IDC_SYSLINK_REGISTER, &CLoginDlg::OnNMClickSyslinkRegister) ON_NOTIFY(NM_CLICK, IDC_SYSLINK_FINDPWD, &CLoginDlg::OnNMClickSyslinkFindpwd) ON_BN_CLICKED(IDC_BUTTON_LIST, &CLoginDlg::OnBnClickedButtonList)ON_WM_PAINT()ON_COMMAND(IDM_ONLIN, &CLoginDlg::OnOnlin)ON_COMMAND(IDM_QME, &CLoginDlg::OnQme)ON_COMMAND(IDM_LEA VE, &CLoginDlg::OnLeave)ON_COMMAND(IDM_BUSY, &CLoginDlg::OnBusy)ON_COMMAND(IDM_DARAO, &CLoginDlg::OnDarao)ON_COMMAND(IDM_YINSHEN, &CLoginDlg::OnYinshen)ON_COMMAND(ID_showWindow, &CLoginDlg::Onshowwindow)ON_COMMAND(IDC_BUTTON_CLOSE, &CLoginDlg::OnButtonClose)ON_COMMAND(1200,OnOpenmainpanel)ON_COMMAND(1201,OnHideWindows)ON_BN_CLICKED(IDC_BUTTON_MIN, &CLoginDlg::OnBnClickedButtonMin)ON_BN_CLICKED(IDC_BUTTON_JIANPAN, &CLoginDlg::OnBnClickedButtonJianpan)ON_CBN_SELCHANGE(IDC_COMBO_USERNAME, &CLoginDlg::OnCbnSelchangeComboUsername) ON_BN_CLICKED(IDC_CHECK_SA VEPWD, &CLoginDlg::OnBnClickedCheckSavepwd)ON_BN_CLICKED(IDC_CHECK_AUTOLOGIN, &CLoginDlg::OnBnClickedCheckAutologin)ON_WM_TIMER()END_MESSAGE_MAP()// CLoginDlg 消息处理程序void CLoginDlg::ToTray(BOOL Show){if(Show){UpdateData(TRUE);Shell_NotifyIcon(NIM_ADD,&m_nid); //放入托盘中ShowWindow(SW_HIDE); //隐藏主窗口}else{Shell_NotifyIcon(NIM_DELETE,&m_nid);//从托盘中删除}}//处理托盘的回调函数(也就是对托盘的一些消息响应如单击,右击,双击)LRESULT CLoginDlg::OnShowTask(WPARAM wParam, LPARAM lParam){switch(lParam){case WM_RBUTTONDOWN:{CRect rect;CPoint p;GetCursorPos(&p);CMenu menu;if(this->IsWindowVisible()){menu.CreatePopupMenu();menu.AppendMenu(MF_STRING,1201,_T("隐藏主面板"));menu.AppendMenu(MF_STRING,WM_DESTROY,_T("关闭"));menu.TrackPopupMenu(TPM_LEFTALIGN,p.x,p.y,this);}else{menu.CreatePopupMenu();menu.AppendMenu(MF_STRING,1200,_T("打开主面板"));menu.AppendMenu(MF_STRING,WM_DESTROY,_T("关闭"));menu.TrackPopupMenu(TPM_LEFTALIGN,p.x,p.y,this);}}break;case WM_LBUTTONDOWN:ShowWindow(SW_SHOW);break;}return 0;}void CLoginDlg::OnBnClickedOk(){UpdateData();BOOL isFind = FALSE;//判断是否已经找到密码CString temp;//存储格式化字符串if(m_strUsername == _T("")){MessageBox(_T("帐号不能为空!请重新输入!"));return;}if(m_strPassord == _T("")){MessageBox(_T("密码不能为空!请输入密码!"));return;}//判断该帐号是否已经注册(在qqData.ini文件中)//int nInqqdata;CString strAccountInqqData;CString strPasswordInqqData;int nCount=::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qqData.ini"));for(int i = 0;i < nCount;i++){temp.Format(_T("%d"),i + 1);::GetPrivateProfileString(_T("admin") + temp,_T("Account") + temp,m_strUsername, strAccountInqqData.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qqData.ini"));::GetPrivateProfileString(_T("admin") + temp,_T("Password") + temp,_T(""), strPasswordInqqData.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qqData.ini"));//如果账号,密码与配置文件中的数据一致则登录成功if (strAccountInqqData == m_strUsername){if(m_strPassord == strPasswordInqqData){isFind = TRUE;break;}}}if(!isFind){MessageBox(_T("账号或密码有错误,请确认后重新登录!"));return;}int bCount = ::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qq.ini"));CString strAccount;//存储本地读取文件中的账号CString strPassword;//存储本地文件中的密码CString strRemPassword;//存储配置文件中的记住密码状态CString strAutoLogin;//存储配置文件自动登录状态CString strLastLogin;//存储配置文件是否为上次登录状态BOOL isExistInqq=FALSE;//是否存在于本地的配置文件int nIndex;//帐号在配置文件中下标if (m_isRemPassword){strRemPassword = _T("1");}strRemPassword = _T("0");if (m_isAutoLogin){strAutoLogin = _T("1");}elsestrAutoLogin = _T("0");bCount++;//判断是否本地配置文件中已经存在该帐号的信息for (int i= 0;i < bCount;i++){nIndex=i + 1;temp.Format(_T("%d"),nIndex);::GetPrivateProfileString(_T("admin") + temp,_T("Account") + temp,_T(""), strAccount.GetBuffer(MAX_PA TH),MAX_PATH,_T(".\\qq.ini"));if(strAccount==m_strUsername){isExistInqq=TRUE;break;}}if (!isExistInqq){temp.Format(_T("%d"),bCount);::WritePrivateProfileString(_T("admin") +temp,_T("Account") + temp,m_strUsername,_T(".\\qq.ini"));//写入密码,当记住密码时为账户密码,否则密码为空if(m_isRemPassword){::WritePrivateProfileString(_T("admin") + temp,_T("Password") + temp,m_strPassord,_T(".\\qq.ini"));}else::WritePrivateProfileString(_T("admin") + temp,_T("Password") + temp,_T(""),_T(".\\qq.ini"));::WritePrivateProfileString(_T("admin") +temp,_T("isRemPassword") + temp,strRemPassword,_T(".\\qq.ini"));::WritePrivateProfileString(_T("admin") +temp,_T("isAutoLogin") + temp,strAutoLogin,_T(".\\qq.ini"));::WritePrivateProfileString(_T("FileCount"),_T("Count"),temp,_T(".\\qq.ini"));else{temp.Format(_T("%d"),nIndex);if(m_isRemPassword){::WritePrivateProfileString(_T("admin") + temp,_T("Password") + temp,m_strPassord,_T(".\\qq.ini"));}else::WritePrivateProfileString(_T("admin") + temp,_T("Password") + temp,_T(""),_T(".\\qq.ini"));::WritePrivateProfileString(_T("admin") + temp,_T("isRemPassword") + temp,strRemPassword,_T(".\\qq.ini"));::WritePrivateProfileString(_T("admin") + temp,_T("isAutoLogin") + temp,strAutoLogin,_T(".\\qq.ini"));}Shell_NotifyIcon(NIM_DELETE,&m_nid);//获得此时本地文件存在的帐号数目bCount = ::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qq.ini"));for(int i = 0;i < bCount;i++){temp.Format(_T("%d"),i + 1);::WritePrivateProfileString(_T("admin") + temp,_T("isLastLogin") + temp,_T("0"),_T(".\\qq.ini"));}//为现在这个帐号设置isLastLogin的值if (isExistInqq){temp.Format(_T("%d"),nIndex);::WritePrivateProfileString(_T("admin") + temp,_T("isLastLogin") + temp,_T("1"),_T(".\\qq.ini"));}else{temp.Format(_T("%d"),bCount);::WritePrivateProfileString(_T("admin") + temp,_T("isLastLogin") + temp,_T("1"),_T(".\\qq.ini"));}//对当前帐号的排名计数器设为,并写入本地配置文件中::WritePrivateProfileString(_T("admin") + temp,_T("Rank") + temp,_T("0"),_T(".\\qq.ini"));//遍历本地配置文件,除了本次登录的帐号外,其他帐号的排名计数都加for (int i = 0;i < bCount;i++){temp.Format(_T("%d"),i + 1);::GetPrivateProfileString(_T("admin") + temp,_T("isLastLogin") + temp,_T(""),strLastLogin.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));if (strLastLogin != _T("1")){int rank = GetPrivateProfileInt(_T("admin") + temp,_T("Rank") + temp,0,_T(".\\qq.ini"));rank++;CString strRank;strRank.Format(_T("%d"),rank);::WritePrivateProfileString(_T("admin") + temp,_T("Rank") + temp,strRank,_T(".\\qq.ini"));}}OnOK();}void CLoginDlg::OnLButtonDown(UINT nFlags, CPoint point){if (point.y <= 50){m_bMoving = TRUE;m_ptPreMove = point;ClientToScreen(&m_ptPreMove);//GetCapture();}CDialog::OnLButtonDown(nFlags, point);}void CLoginDlg::OnLButtonUp(UINT nFlags, CPoint point){m_bMoving = FALSE;CDialog::OnLButtonUp(nFlags, point);}void CLoginDlg::OnMouseMove(UINT nFlags, CPoint point){if (m_bMoving){CPoint ptTemp = point;ClientToScreen(&ptTemp);CPoint ptOffset = ptTemp - m_ptPreMove;m_ptPreMove = ptTemp;CRect rectWindow;GetWindowRect(&rectWindow);rectWindow += ptOffset;MoveWindow(&rectWindow);}CDialog::OnMouseMove(nFlags, point);}void CLoginDlg::OnNMClickSyslinkRegister(NMHDR *pNMHDR, LRESULT *pResult){// TODO: 在此添加控件通知处理程序代码//PNMLINK pNMLink = (PNMLINK)pNMHDR;//::ShellExecute(m_hWnd, _T("open"), pNMLink->item.szUrl, NULL, NULL, SW_SHOWNORMAL);CRegisterDlg dlg;if(IDOK != dlg.DoModal())return;//把注册信息存入qqData注册表UpdateData();int nCount = ::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qqData.ini"));nCount++;CString temp;temp.Format(_T("%d"),nCount);::WritePrivateProfileString(_T("admin") + temp,_T("Account") + temp,dlg.m_Reg_strAccount,_T(".\\qqData.ini"));::WritePrivateProfileString(_T("admin") + temp,_T("Password") + temp,dlg.m_Reg_strPassword,_T(".\\qqData.ini"));::WritePrivateProfileString(_T("FileCount"),_T("Count"),temp,_T(".\\qqData.ini"));*pResult = 0;}void CLoginDlg::OnNMClickSyslinkFindpwd(NMHDR *pNMHDR, LRESULT *pResult){// TODO: 在此添加控件通知处理程序代码//PNMLINK pNMLink = (PNMLINK)pNMHDR;//::ShellExecute(m_hWnd, _T("open"), pNMLink->item.szUrl, NULL, NULL, SW_SHOWNORMAL);CSeekDlg dlg;dlg.DoModal();*pResult = 0;}BOOL CLoginDlg::OnInitDialog(){CDialog::OnInitDialog();// TODO: 在此添加额外的初始化ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);CBitmap map1, map2, map3;map1.LoadBitmap(IDB_BITMAP1);m_btnList.SetBitmap(map1);map2.LoadBitmap(IDB_BITMAP9);m_btnJianPan.SetBitmap(map2);map3.LoadBitmap(IDB_BITMAP10);m_btnConfig.SetBitmap(map3);for (int i=0; i<3; ++i){toolTipCtrl[i].Create(this);}toolTipCtrl[0].AddTool(GetDlgItem(IDC_BUTTON_CONFIG), _T("设置"));toolTipCtrl[1].AddTool(GetDlgItem(IDC_BUTTON_MIN), _T("最小化"));toolTipCtrl[2].AddTool(GetDlgItem(IDC_BUTTON_CLOSE), _T("关闭"));m_nid.cbSize = (DWORD) sizeof(NOTIFYICONDATA);m_nid.hWnd = m_hWnd;m_nid.uID = IDI_OFFLINE;//IDR_MAINFRAME;m_nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_OFFLINE));m_nid.uFlags = NIF_ICON | NIF_MESSAGE|NIF_TIP;m_nid.uCallbackMessage = WM_SHOWTASK;wcscpy_s(m_nid.szTip,_T("QQ"));//实现任务栏无图标ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW,SWP_FRAMECHANGED);Shell_NotifyIcon(NIM_ADD, &m_nid);m_cLinkRegister.SetWindowText(_T("<ahref=\"/chs/index.html?from=client&ptlang=2052®key=&ADUIN=0&ADSESSION=0&ADT AG=CLIENT.QQ.4855_NewAccount_Btn.0&ADPUBNO=26095\">注册账号</a>"));m_cLinkFindpwd.SetWindowText(_T("<ahref=\"https:///cn2/findpsw/pc/pc_find_pwd_input_account?source_id=1003&ptlang=2052&aquin=105 8072426\">忘记密码</a>"));//获得本地配置文件中已经保存的账号数目int nCount = ::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qq.ini"));CString strAccount;//保存读取配置文件后的账号CString strPassword;//保存读取配置文件后的账号的密码CString temp;//保存格式化字符串int nShow;//显示帐号的个数//如果本地文件帐号数目小于四个,则把显示的数目设为帐号数目,否则显示四个if (nCount <= 4){nShow = nCount;}elsenShow = 4;//动态构造一个数组,存储每个帐号的登录排名计数(当前登录排名为,其他排名在之前基础上加)int *a = new int [nCount + 1];memset(a,0,nCount + 1);//把每个帐号的排名计数赋值给对应的数组元素for (int i = 0;i < nCount;i++){temp.Format(_T("%d"),i + 1);a[i] = ::GetPrivateProfileInt(_T("admin") + temp,_T("Rank") + temp,0,_T(".\\qq.ini"));}//对排名计数进行排序int i;int j;int k;for(i = 0;i < nCount;i++)for(j = i + 1;j < nCount;j++)if(a[i] > a[j]){k = a[i];a[i] = a[j];a[j] = k;}//把排名计数前指定位数增加到组合框for(int n= 0;n < nShow;n++){for (j = 0;j < nCount;j++){temp.Format(_T("%d"),j+1);if (a[n] == ::GetPrivateProfileInt(_T("admin") + temp,_T("Rank") + temp,0,_T(".\\qq.ini"))){::GetPrivateProfileString(_T("admin") + temp,_T("Account") + temp,_T(""), strAccount.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));((CComboBox*)GetDlgItem(IDC_COMBO_USERNAME))->InsertString(n,strAccount);break;}}}//把上次登录的帐号显示到组合框中CString isLastLogin;////保存配置文件中的是否为上次登录的账号int nIndex = 0;//存储上次登录账号的下标CString strRemPassword;//保存配置文件中的记住密码选择状态CString strAutoLogin;//保存配置文件中的自动登录选择状态for(int i = 0;i < nCount;i++){temp.Format(_T("%d"),i + 1);::GetPrivateProfileString(_T("admin") + temp,_T("isLastLogin") + temp,_T(""),isLastLogin.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));if (isLastLogin == _T("1")){nIndex = i + 1;break;}}//获得上一次登录的帐号,密码,记住密码状态,自动登陆状态temp.Format(_T("%d"),nIndex);::GetPrivateProfileString(_T("admin") + temp,_T("Account") + temp,_T(""), strAccount.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));::GetPrivateProfileString(_T("admin") + temp,_T("Password") + temp,_T(""), strPassword.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));::GetPrivateProfileString(_T("admin") + temp,_T("isRemPassword") + temp,_T(""), strRemPassword.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));::GetPrivateProfileString(_T("admin") + temp,_T("isAutoLogin") + temp,_T(""), strAutoLogin.GetBuffer(MAX_PATH),MAX_PA TH,_T(".\\qq.ini"));if (strRemPassword == _T("1")){m_isRemPassword = TRUE;}elsem_isRemPassword = FALSE;if (strAutoLogin == _T("1")){m_isAutoLogin = TRUE;m_isRemPassword = TRUE;}elsem_isAutoLogin = FALSE;m_strPassord = strPassword;UpdateData(FALSE);SetDlgItemText(IDC_COMBO_USERNAME,strAccount);SetTimer(1,5000,NULL);//设置定时器,用于自动登录//释放内存delete []a;return TRUE; // return TRUE unless you set the focus to a control// 异常: OCX 属性页应返回FALSE}void CLoginDlg::OnBnClickedButtonList(){// TODO: 在此添加控件通知处理程序代码CMenu menu, *pMenu;menu.LoadMenu(IDR_MENU1);pMenu = menu.GetSubMenu(0);CBitmap bitmap0,bitmap1,bitmap2,bitmap3,bitmap4,bitmap5,bitmap6,bitmap7;bitmap0.LoadBitmap(IDB_BITMAP1);bitmap1.LoadBitmap(IDB_BITMAP2);bitmap2.LoadBitmap(IDB_BITMAP3);bitmap3.LoadBitmap(IDB_BITMAP4);bitmap4.LoadBitmap(IDB_BITMAP5);bitmap5.LoadBitmap(IDB_BITMAP6);/*bitmap6.LoadBitmap(IDB_BITMAP7);bitmap7.LoadBitmap(IDB_BITMAP8);*/pMenu->SetMenuItemBitmaps(0, MF_BYPOSITION, &bitmap0, &bitmap0);pMenu->SetMenuItemBitmaps(1, MF_BYPOSITION, &bitmap1, &bitmap1);pMenu->SetMenuItemBitmaps(3, MF_BYPOSITION, &bitmap2, &bitmap2);pMenu->SetMenuItemBitmaps(4, MF_BYPOSITION, &bitmap3, &bitmap3);pMenu->SetMenuItemBitmaps(5, MF_BYPOSITION, &bitmap4, &bitmap4);pMenu->SetMenuItemBitmaps(7, MF_BYPOSITION, &bitmap5, &bitmap5);/*pMenu->SetMenuItemBitmaps(6, MF_BYPOSITION, &bitmap0, &bitmap0);pMenu->SetMenuItemBitmaps(7, MF_BYPOSITION, &bitmap0, &bitmap0);*/CRect rect;GetDlgItem(IDC_BUTTON_LIST)->GetWindowRect(&rect);pMenu->TrackPopupMenu(TPM_LEFTBUTTON,rect.right-rect.Width(), rect.bottom, this, 0);}void CLoginDlg::OnPaint(){CPaintDC dc(this); // device context for paintingCBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP12);CRect rect;GetClientRect(&rect);CDC demo;demo.CreateCompatibleDC(&dc);demo.SelectObject(&bitmap);//dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &demo, 0, 0, bitMap.bmWidth, bitMap.bmHeight, SRCCOPY);dc.BitBlt(0, 0, rect.Width(), rect.Height(), &demo, 0, 0, SRCCOPY);// 不为绘图消息调用CDialog::OnPaint()}void CLoginDlg::OnOnlin(){// TODO: 在此添加命令处理程序代码CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP1);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_IMONLINE;}void CLoginDlg::OnQme(){CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP2);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_QME;// TODO: 在此添加命令处理程序代码}void CLoginDlg::OnLeave(){// TODO: 在此添加命令处理程序代码CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP3);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_AWAY;}void CLoginDlg::OnBusy(){// TODO: 在此添加命令处理程序代码CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP4);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_BUSY;}void CLoginDlg::OnDarao(){// TODO: 在此添加命令处理程序代码CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP5);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_MUTE;}void CLoginDlg::OnYinshen(){// TODO: 在此添加命令处理程序代码CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP6);m_btnList.SetBitmap(bitmap);m_nIconID = IDI_INVISIBLE;}BOOL CLoginDlg::PreTranslateMessage(MSG* pMsg){// TODO: 在此添加专用代码和/或调用基类if (pMsg->message== WM_LBUTTONDOWN ||pMsg->message== WM_LBUTTONUP ||pMsg->message== WM_MOUSEMOVE)for (int i=0; i<3; ++i){toolTipCtrl[i].RelayEvent(pMsg);}return CDialog::PreTranslateMessage(pMsg);}void CLoginDlg::Onshowwindow(){// TODO: 在此添加命令处理程序代码ShowWindow(SW_SHOW);}void CLoginDlg::OnButtonClose(){// TODO: 在此添加命令处理程序代码PostMessage(WM_QUIT);ToTray(TRUE);}void CLoginDlg::OnBnClickedButtonClose(){static CRect rectLarge;static CRect rectSmall;if (rectLarge.IsRectNull()){CRect rectSeparator;GetWindowRect(&rectLarge);//获得变小前的对话框面积GetDlgItem(IDC_STATIC)->GetWindowRect(&rectSeparator);rectSmall.left = rectLarge.left;rectSmall.top = rectLarge.top;rectSmall.right = rectLarge.right;rectSmall.bottom = rectSeparator.bottom;}for (int i = rectSmall.Height(); i>=0; i--){SetWindowPos(NULL, 0, 0, rectSmall.Width(), i, SWP_NOMOVE | SWP_NOZORDER);Sleep(5);}//OnOK();PostMessage(WM_QUIT);ToTray(TRUE);}void CLoginDlg::OnBnClickedButtonMin(){// TODO: 在此添加控件通知处理程序代码ShowWindow(SW_HIDE);ToTray(TRUE);}void CLoginDlg::OnBnClickedButtonJianpan(){// TODO: 在此添加控件通知处理程序代码}void CLoginDlg::OnCbnSelchangeComboUsername(){m_isFirstLoginAccount=FALSE;//表示不是第一次登录的账号//获取当前选择的行,并显示到列表框中int nIndex = ((CComboBox*)GetDlgItem(IDC_COMBO_USERNAME))->GetCurSel();int nCount = ::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qq.ini"));((CComboBox*)GetDlgItem(IDC_COMBO_USERNAME))->GetLBText(nIndex,m_strUsername);int n=0;//保存账号在配置文件中的下标CString temp;//保存格式化的字符串CString strAccount;//保存在配置文件中的读取到的账号CString strPassword;//保存在配置文件中的读取到的账号的密码CString strRemPassword;//保存最近一次账号登录的记住密码状态CString strAutoLogin;//保存最近一次账号登录的自动登录状态//遍历配置文件,判断上次保存的密码记住状态!for(int i = 0;i < nCount;i++){temp.Format(_T("%d"),i + 1);::GetPrivateProfileString(_T("admin")+temp,_T("Account")+temp,_T(""),strAccount.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));if (m_strUsername == strAccount){n=i+1;::GetPrivateProfileString(_T("admin")+temp,_T("isRemPassword")+temp,_T(""),strRemPassword.GetBuffe r(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));if (strRemPassword==_T("1")){m_isRemPassword=TRUE;}elsem_isRemPassword=FALSE;break;}}//再考虑自动登录框的选择状态::GetPrivateProfileString(_T("admin")+temp,_T("isAutoLogin")+temp,_T(""),strAutoLogin.GetBuffer(MAX_PATH),MAX_PA TH,_T(".\\qq.ini"));//如果是自动登录,那要记住密码if(strAutoLogin == _T("1")){m_isRemPassword = TRUE;m_isAutoLogin = TRUE;}elsem_isAutoLogin = FALSE;temp.Format(_T("%d"),n);::GetPrivateProfileString(_T("admin") + temp,_T("Password") + temp,_T(""), strPassword.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));m_strPassord = strPassword;SetDlgItemText(IDC_EDIT_PASSWORD,m_strPassord);CButton *ptn = (CButton*)GetDlgItem(IDC_CHECK_SA VEPWD); //获得CheckBox的指针ptn->SetCheck(m_isRemPassword);//设置记住密码框选择状态CButton *qtn = (CButton*)GetDlgItem(IDC_CHECK_AUTOLOGIN); //获得CheckBox的指针qtn->SetCheck(m_isAutoLogin);//设置自动登录框选择状态}void CLoginDlg::OnBnClickedCheckSavepwd(){//如果记住密码状态没有选,则自动登录也不能选CButton *pRemPassWord = (CButton*)GetDlgItem(IDC_CHECK_SA VEPWD);CButton *pBtnAutoLogin = (CButton*)GetDlgItem(IDC_CHECK_AUTOLOGIN);if (pRemPassWord->GetCheck() == 0){pBtnAutoLogin->SetCheck(0);}}void CLoginDlg::OnBnClickedCheckAutologin(){// TODO: 在此添加控件通知处理程序代码//如果当前不是自动登录状态,则单击后,为自动登录状态,否则取消自动登录状态if (!m_isAutoLogin){m_isAutoLogin = TRUE;m_isRemPassword = TRUE; //如果为自动登录状态,则应该记住密码CButton *q = (CButton*)GetDlgItem(IDC_CHECK_SA VEPWD);q->SetCheck(m_isRemPassword);}else{m_isAutoLogin = FALSE;}CButton *p = (CButton*)GetDlgItem(IDC_CHECK_AUTOLOGIN); //获得CheckBox的指针p->SetCheck(m_isAutoLogin);//设置选择状态}void CLoginDlg::OnTimer(UINT_PTR nIDEvent){// 如果是不是上一次登录的账号,则返回if(!m_isFirstLoginAccount)return;UpdateData();int nCount=::GetPrivateProfileInt(_T("FileCount"),_T("Count"),0,_T(".\\qq.ini"));CString temp;//存储格式化字符串CString strAccount;//存储读取文件中的账号CString strPassword;//存储读取文件中的密码CString strAutoLogin;//存储读取文件中的自动登录状态//遍历配置文件,找到当前输入的账号密码,取得该账号的自动登录的选择状态for(int i = 0;i < nCount;i++){temp.Format(_T("%d"),i + 1);::GetPrivateProfileString(_T("admin")+temp,_T("Account")+temp,m_strUsername, strAccount.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));::GetPrivateProfileString(_T("admin")+temp,_T("Password")+temp,_T(""), strPassword.GetBuffer(MAX_PA TH),MAX_PA TH,_T(".\\qq.ini"));if ((m_strUsername == strAccount)&&(m_strPassord == strPassword)){::GetPrivateProfileString(_T("admin")+temp,_T("isAutoLogin")+temp,_T(""), strAutoLogin.GetBuffer(MAX_PATH),MAX_PA TH,_T(".\\qq.ini"));//如果为自动登录状态,则调用OnOk,关闭定时器if (strAutoLogin == _T("1")){OnOK();KillTimer(1);break;}}}CDialog::OnTimer(nIDEvent);}void CLoginDlg::OnOpenmainpanel(){//托盘右键菜单实现,隐藏主面板ShowWindow(SW_SHOW);}void CLoginDlg::OnHideWindows(){//托盘右键菜单实现,打开主面板ShowWindow(SW_HIDE);}主界面.h// QQDemoDlg.h : 头文件//#pragma once#include"Linkname.h"#include"RoomDlg.h"#include"GroupDlg.h"#include"SessionDlg.h"#include"Twitter.h"#include"afxwin.h"#include"EditDlg.h"// CQQDemoDlg 对话框class CQQDemoDlg : public CDialog{// 构造public:CQQDemoDlg(CWnd* pParent = NULL); // 标准构造函数~CQQDemoDlg();// 对话框数据enum { IDD = IDD_QQDEMO_DIALOG };protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现public:void ToTray(DWORD dwMessage,HICON hIcon);//用于托盘的增加,修改,删除操作protected://修正移动时窗口的大小void FixMoving(UINT fwSide, LPRECT pRect);//修正改改变窗口大小时窗口的大小void FixSizing(UINT fwSide, LPRECT pRect);//从收缩状态显示窗口void DoShow();//从显示状态收缩窗口void DoHide();//重载函数,只是为了方便调用BOOL SetWindowPos(const CWnd* pWndInsertAfter,LPCRECT pCRect, UINT nFlags = SWP_SHOWWINDOW);afx_msg void OnTimer(UINT nIDEvent);afx_msg void OnSizing(UINT fwSide, LPRECT pRect);afx_msg int OnCreate(LPCREA TESTRUCT lpCreateStruct);afx_msg void OnMoving(UINT fwSide, LPRECT pRect);。
基于JavaSocket网络编程的山寨QQ
基于Java Socket 网络编程的山寨QQ(学习韩顺平老师的视频整理出的笔记)内容含盖:1.Java 面向对象编程2.3.4.5.6.连入因特网,以及数据如何在它们之间传输的标准。
协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。
而IP是给因特网的每一台电脑规定一个地址。
二、端口端口详解在开始讲什么是端口之前,我们先来聊一聊什么是 port 呢?常常在网络上听说『我的主机开了多少的 port ,会不会被入侵呀!?或者是说『开那个 port 会比较安全?又,我的服务应该对应什么 port 呀?呵呵!很神奇吧!怎么一部主机上面有这么多的奇怪的port 呢?这个 port 有什么作用呢?择大于 1024 以上(因为0-1023有特殊作用,被预定,如FTP、HTTP、SMTP等)的 port 号来进行!其 TCP 封包会将(且只将) SYN 旗标设定起来!这是整个联机的第一个封包;·如果另一端(通常为 Server ) 接受这个请求的话(当然啰,特殊的服务需要以特殊的port 来进行,例如 FTP 的 port 21 ),则会向请求端送回整个联机的第二个封包!其上除了 SYN 旗标之外同时还将 ACK 旗标也设定起来,并同时在本机端建立资源以待联机之需;·然后,请求端获得服务端第一个响应封包之后,必须再响应对方一个确认封包,此时封包只带 ACK 旗标(事实上,后继联机中的所有封包都必须带有 ACK 旗标);·只有当服务端收到请求端的确认( ACK )封包(也就是整个联机的第三个封包)之后,两端的联机才能正式建立。
这就是所谓的 TCP 联机的'三次握手( Three-Way Handshake )',21TCP攻击者可以达到对目标计算机的初步了解。
QQ程序源代码
//---------------------------------------------------------------------
//复制自身到系统目录
//pAim:[in,out],初始为存放目标文件名缓冲区的指针,
//函数向缓冲区返回完整路径的目标文件名
//成功返回0,否则返回非0
递归枚举hFatherWindow指定的窗口下的所有子窗口和兄弟窗口,
返回和lstyle样式相同的窗口句柄,如果没有找到,返回NULL
---------------------------------------------------------------------*/
HWND GetStyleWindow(HWND hFatherWindow, const long lstyle);
//将FullName指定的dll文件以远程线程方式插入到Pid指定的进程里
//成功返回0,失败返回1
int InjectDll(const char *FullName, const DWORD Pid);
/*---------------------------------------------------------------------
#include <windows.h>
//---------------------------------------------------------------------
//判断系统版本,9x返回1,NT、2000、xp、2003返回2,其它返回0
int GetOsVer(void);
首先,判断系统版本,如果就9x,将自己复制到系统目录,如果复制成功,说明自身没有在系统目录运行那么需要启动系统目录下的实例,然后自己退出。再创建一个互斥量,保证只有一个实例存在。接下来,用RegisterServiceProcess函数将自己注册成一个服务程序,这样在9x下按ctrl+alt+del就不会看到了。最后,调用GetQQPass函数,监视QQ登录的情况。如果是NT系统,将自己安装为自动启动的系统服务,服务启动后,任务就是释放两个要插入其他进程的dll,把监视QQ登录窗口的dll插入到winlogon.exe进程中,然后就停止,这样就不会在任务管理器里面看到不正常的进程了。插入到winlogon.exe里面的线程负责监视是否有QQ登录,发现后就将GetQQPass函数作为一个线程插入到QQ进程中,当GetQQPass函数捕获到号码和密码时,就向设置好的邮箱发一封信。至于为什么要插入到winlogon.exe进程,只是习惯而已,当然,也可以插入到其他的系统进程里,但是注意一定要插入到系统进程,不能是用户进程。因为只有系统进程里的线程才能在任何用户登录的情况下都有权限做远程线程插入的动作。GetQQPass函数我使用很简单的办法,就是向QQ的号码和密码窗口发送WM_GETTEXT消息得到它们的内容。判断哪个窗口是号码窗口和密码窗口的办法也是最常用的,就是靠它们的style。首先用QQ登录窗口的类名得到QQ的登录窗口的句柄,再通过这个句柄找到号码窗口和密码窗口的句柄。类名和子窗口的style都是用spy++得到的。这里有一个细节,就是“QQ注册向导”窗口里面,选中“使用已有的QQ号码”以后和选中以前的号码与密码窗口的style是不一样的,当然我们要选中以后的style了。发邮件部分也很简陋,现在只在163和sina的测试过,还能用。其中base64编码部分的代码是以前从网上copy的,忘了从哪里看的了,总之感谢这段代码的作者。
(完整word版)山寨QQ(韩顺平版)(word文档良心出品)
这是一个简单的javaProject项目,没有涉及到数据库界面对这个项目中完成的功能进行阐述:1、qq用户登录:用户账号为1、2、3一直到50,密码都为123456,由于没有涉及到数据库,所以只是简单的在服务器进行验证。
2、实现1对1之间的聊天,实现1对多之间的聊天。
3、实现用户上线显示功能具体的演示为:1、启动服务器QqServer下com.qq.view.MyServerFrame,在该类下面启动服务器2、启动客户端QqClient下com.qq.view.QqClientLogin,在该类下面输入账号和密码登入ps:聊天时要把要把需要聊天的窗口都打开,才能看到。
比如1和2聊天,必须打开1对2聊天的窗口和2对1聊天的窗口QQ客户端:QQ服务器下面的是关于各个包的源代码,小伙伴们可以新建一个class,然后把这些拷贝上去就可以用了,当然前提是按照上面的工程创建好包Image文件夹下用到的图片:命名为:beibu.gif命名为:xiangdao.png命名为:quxiao.png命名为:qq.png命名为:mm.png命名为:clear.png命名为:dengru.pngQqClientConService类:package com.qq.client.model;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .Socket;import com.qq.client.tools.ClientConServerThread;import com.qq.client.tools.ManageClientConServerThread; import mon.Message;import er;/*** 客户端连接服务器后台* */public class QqClientConService {public Socket client;//判断是否成功登录,成功返回true,否则返回falsepublic boolean sendLoginInfoToServer(Object o) {boolean isLogin = false;try {//创建连接client = new Socket("localhost", 9999);ObjectOutputStream oos = newObjectOutputStream(client.getOutputStream());oos.writeObject(o);ObjectInputStream ois = newObjectInputStream(client.getInputStream());Message message = (Message)ois.readObject();//登录成功的判断if(message.getMesType()==1) {isLogin = true;//登录成功,创建一个改客户端和服务器的线程ClientConServerThread ccst = new ClientConServerThread(client);//把改线程添加到管理线程的map中ManageClientConServerThread.addClientConServerThread(((User )o).getName(), ccst);//启动该线程new Thread(ccst).start();}} catch (Exception e) {e.printStackTrace();}return isLogin;}}QqClientUser类:package com.qq.client.model;import er;/*** 这是QQ客户端,发送用户名和密码** */public class QqClientUser {//调用客户端连接服务器后台的方法,返回true为成功登录,false为登入失败public boolean checkUser(User user) {return newQqClientConService().sendLoginInfoToServer(user);}}ClientConServerThread类:package com.qq.client.tools;import java.io.ObjectInputStream;import .Socket;import com.qq.client.view.QqChar;import com.qq.client.view.QqFriendList;import mon.Message;import mon.MessageType;/*** 这是客户端和服务器保持通讯的线程* */public class ClientConServerThread implements Runnable{ public Socket client;public ClientConServerThread(Socket client) {this.client = client;}@Overridepublic void run() {//不停的读取从服务器发来的消息while(true) {try {ObjectInputStream ois = newObjectInputStream(client.getInputStream());Message message = (Message) ois.readObject();//判断发来的消息包是否为普通消息包,或者是返回在线好友的包if(message.getMesType() ==MessageType.message_common_mes) {//把从服务器发来的消息显示在聊天界面:1.从管理聊天窗口的类中取得该窗口 2.调用显示方法.QqChar qqChar =ManageQqChar.getQqChar(message.getGetter()+""+message.getSender());qqChar.showMessage(message);} else if(message.getMesType() == MessageType.message_ret_onLineFriend) {String getter = message.getGetter();//修改响应的好友列表QqFriendList qqFriendList = ManageQqFriendList.getQqFriendList(getter);//更新在线好友if(qqFriendList != null) {qqFriendList.updateFriend(message);}}} catch (Exception e) {e.printStackTrace();}}}}ManageClientConServerThread类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;/*** 这是一个管理客户端和服务器保持通讯的线程类* */public class ManageClientConServerThread {public static Map map = new HashMap<String, ClientConServerThread>();//把线程添加到map中public static void addClientConServerThread(String userName, ClientConServerThread ccst) {map.put(userName, ccst);}//根据用户名取得该线程public static ClientConServerThread getClientConServerThread(String userName) {return (ClientConServerThread)map.get(userName);}}ManageQqChar类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;import com.qq.client.view.QqChar;/*** 这是一个管理用户聊天界面的类* */public class ManageQqChar {public static Map map = new HashMap<String, QqChar>();//把用户聊天界面Qqchar添加到map中public static void addQqChar(String loginAndFriend, QqChar qqchar) {map.put(loginAndFriend, qqchar);}//根据登入用户和发送用户取得该聊天界面public static QqChar getQqChar(String loginAndFriend) { return (QqChar)map.get(loginAndFriend);}}ManageQqFriendList类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;import com.qq.client.view.QqFriendList;/*** 管理好友、黑名单..界面类* */public class ManageQqFriendList {public static Map map = new HashMap<String, QqFriendList>();//把用用户列表类添加到map中public static void addQqFriendList(String userName, QqFriendList list) {map.put(userName, list);}//根据登录用户取得该用户列表类public static QqFriendList getQqFriendList(String userName) { return (QqFriendList)map.get(userName);}}QqChar类:package com.qq.client.view;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.ObjectOutputStream;import java.util.Date;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JTextArea;import javax.swing.JTextField;import com.qq.client.tools.ManageClientConServerThread;import mon.Message;import mon.MessageType;/*** QQ聊天窗口** */public class QqChar extends JFrame implements ActionListener { JTextField jtf;//输入的文本框JTextArea jta;//文本区域JButton jb;//发送按钮JPanel jp;//装文本框和发送按钮的panelString friend;String userName;public static void main(String[] args) {QqChar qqChar = new QqChar("1","2");}public QqChar(String userName,String friend) {erName = userName;this.friend = friend;jtf = new JTextField(15);jta = new JTextArea();jb = new JButton("发送");jb.addActionListener(this);jp = new JPanel();jp.add(jtf);jp.add(jb);this.add(jta, "Center");this.add(jp, "South");this.setTitle(userName+" 正在和 " + friend + " 聊天");this.setIconImage(newImageIcon("image/qq.png").getImage());this.setSize(300, 200);this.setVisible(true);}public void showMessage(Message message) {String info=message.getSender()+" 对"+message.getGetter()+" 说:"+message.getContext()+"\r\n";this.jta.append(info);}@Overridepublic void actionPerformed(ActionEvent e) {//当点击发送按钮时,把消息发送到服务器端if(e.getSource() == jb) {Message message = new Message();message.setMesType(MessageType.message_common_mes);message.setSender(userName);message.setGetter(friend);message.setContext(jtf.getText());jtf.setText("");message.setTime(new Date().toString());try {ObjectOutputStream oos = newObjectOutputStream(ManageClientConServerThread.getClientConSer verThread(userName).client.getOutputStream());oos.writeObject(message);} catch (Exception e1) {e1.printStackTrace();}}}}QqClientLogin类:import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTabbedPane;import javax.swing.JTextField;import com.qq.client.model.QqClientUser;import com.qq.client.tools.ManageClientConServerThread; import com.qq.client.tools.ManageQqFriendList;import mon.Message;import mon.MessageType;import er;/*** QQ客户端登入窗口** */public class QqClientLogin extends JFrame implements ActionListener{//定义北部组件JLabel jbl1;//定义中部组件:其中中部组件有一个选项卡的窗口管理,有三个JPanel,一个文本框,一个密码框,4个JLabel,一个清除号码按钮,两个多选框JTabbedPane jtp;//选项卡窗口JPanel jp2;//QQ号码JPanel jp3;//手机号码JPanel jp4;//电子邮件JLabel jp2_jpl1;//QQ号码JLabel jp2_jpl2;//QQ密码JLabel jp2_jpl3;//忘记密码JLabel jp2_jpl4;//申请密码保护JButton jp2_jb1;//清除号码JTextField jp2_jtf;//文本框JPasswordField jp2_jpf;//密码框JCheckBox jp2_jcb1;//隐身登入JCheckBox jp2_jcb2;//记住密码//定义南部组件JPanel jp1;JButton jp1_jb1;//登入按钮JButton jp1_jb2;//取消按钮JButton jp1_jb3;//注册向导按钮public static void main(String[] args) {QqClientLogin qqClientLogin=new QqClientLogin();}public QqClientLogin() {//处理北部的组件jbl1 = new JLabel(new ImageIcon("image/beibu.gif"));//处理中部的组件jp2=new JPanel(new GridLayout(3,3));//把中部分成三行三列jp2_jpl1 = new JLabel("QQ号码", JLabel.CENTER);jp2_jpl2 = new JLabel("QQ密码", JLabel.CENTER);jp2_jpl3 = new JLabel("忘记密码", JLabel.CENTER);jp2_jpl3.setForeground(Color.blue);//把忘记密码设为蓝色jp2_jpl4 = new JLabel("申请密码保护", JLabel.CENTER);jp2_jb1 = new JButton(new ImageIcon("image/clear.png"));jp2_jtf = new JTextField();jp2_jpf = new JPasswordField();jp2_jcb1 = new JCheckBox("隐身登入");jp2_jcb2 = new JCheckBox("记住密码");//把控件按照顺序加入到jp2jp2.add(jp2_jpl1);jp2.add(jp2_jtf);jp2.add(jp2_jb1);jp2.add(jp2_jpl2);jp2.add(jp2_jpf);jp2.add(jp2_jpl3);jp2.add(jp2_jcb1);jp2.add(jp2_jcb2);jp2.add(jp2_jpl4);//创建选项卡窗口,把三个JPanel放进去,最后把选项卡放进JFrame 中jtp=new JTabbedPane();jtp.add("QQ号码",jp2);jp3= new JPanel();jtp.add("手机号码",jp3);jp4=new JPanel();jtp.add("电子邮件",jp4);//处理南部的组件jp1 = new JPanel();jp1_jb1 = new JButton(new ImageIcon("image/dengru.png"));jp1_jb1.addActionListener(this);jp1_jb2 = new JButton(new ImageIcon("image/quxiao.png"));jp1_jb3=new JButton(new ImageIcon("image/xiangdao.png"));//把三个按钮放进jp1中jp1.add(jp1_jb1);jp1.add(jp1_jb2);jp1.add(jp1_jb3);//把定义好的组件放入到JFrame中this.add(jbl1,"North");//放入北部组件this.add(jp1, "South");//放入南部组件this.add(jtp, "Center");//放入中部组件//定义JFrame的一些属性this.setSize(350, 240);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setIconImage(newImageIcon("image/qq.png").getImage());this.setResizable(false);//不允许放大,改变窗口大小等this.setVisible(true);}@Overridepublic void actionPerformed(ActionEvent e) {//用户点击登录按钮if(e.getSource()==jp1_jb1) {User user =new User();user.setName(jp2_jtf.getText().trim());user.setPassWord(newString(jp2_jpf.getPassword()).trim());QqClientUser qqClientUser = new QqClientUser();//判断是否登录成功if(qqClientUser.checkUser(user)) {try {//把创建好友列表提前QqFriendList qqList = newQqFriendList(jp2_jtf.getText());ManageQqFriendList.addQqFriendList(user.getName(), qqList);//发送一个要求返回在线好友的请求包ObjectOutputStream oos = new ObjectOutputStream(ManageClientConServerThread.getClientConServerThread(user.getName()).client.getOutputSt ream());Message message = new Message();message.setSender(user.getName());message.setMesType(MessageType.message_get_onLineFriend);//发送oos.writeObject(message);} catch (Exception e1) {e1.printStackTrace();}this.dispose();} else {JOptionPane.showMessageDialog(this,"QQ号码或者密码错误");}}}}QqFriendList类:package com.qq.client.view;import javax.swing.*;import com.qq.client.tools.ManageQqChar;import mon.Message;import java.awt.*;import java.awt.event.*;/*** 我的好友列表(包括陌生人和黑名单)* */public class QqFriendList extends JFrame implements ActionListener,MouseListener{//第一张卡片信息(我的好友列表)JPanel jphy1;//总panelJPanel jphy2;//中部的panelJPanel jphy3;//南部的panel,放两个buttonJButton jphy_jb1;//我的好友按钮,防在总panel的北部JButton jphy_jb2;//陌生人按钮,放在jphy3中JButton jphy_jb3;//黑名单按钮,放在jphy3中JScrollPane jsp1;//中部的滚动的paneJLabel jbls[];//中部在线好友的列表//第二张卡片信息(陌生人列表)JPanel jpmsr1;//总panelJPanel jpmsr2;//中部的panelJPanel jpmsr3;//南部的panel,放两个buttonJButton jpmsr_jb1;//我的好友按钮,放在jpmsr3中JButton jpmsr_jb2;//陌生人按钮,放在jpmsr3中JButton jpmsr_jb3;//黑名单按钮,放在总的panel的南部JScrollPane jsp2;//中部的滚动的paneString userName;//把整个JFrame变成卡片布局CardLayout c1;public static void main(String[] args) {QqFriendList qqFriendList = new QqFriendList("1");}public QqFriendList(String userName) {erName = userName;//处理第一张卡片jphy_jb1 = new JButton("我的好友");jphy_jb2 = new JButton("陌生人");jphy_jb2.addActionListener(this);jphy_jb3 = new JButton("黑名单");jphy1 = new JPanel(new BorderLayout());//总的JPaneljphy2= new JPanel(new GridLayout(50,1,4,4));//中部的JPanel,假定有五十个好友//给jphy2这个panel中初始化50个好友jbls = new JLabel[50];for(int i=0; i<jbls.length; i++) {jbls[i] = new JLabel(i+1+"", newImageIcon("image/mm.png"), JLabel.LEFT);jbls[i].setEnabled(false);if(jbls[i].getText().equals(userName)) {jbls[i].setEnabled(true);}jbls[i].addMouseListener(this);jphy2.add(jbls[i]);}jphy3 = new JPanel(new GridLayout(2, 1));//把黑名单按钮和陌生人按钮加入到jpyh3中jphy3.add(jphy_jb2);jphy3.add(jphy_jb3);//把jphy2放入滚动的pane中jsp1 = new JScrollPane(jphy2);//把jphy_jb1,jsp1,jphy3分别放入jphy1中北,中,南三个位置jphy1.add(jphy_jb1,"North");jphy1.add(jsp1,"Center");jphy1.add(jphy3,"South");//处理第二张卡片jpmsr_jb1 = new JButton("我的好友");jpmsr_jb1.addActionListener(this);jpmsr_jb2 = new JButton("陌生人");jpmsr_jb3 = new JButton("黑名单");jpmsr1 = new JPanel(new BorderLayout());//总的JPaneljpmsr2 = new JPanel(new GridLayout(20,1,4,4));//中部的JPanel,假定有二十个陌生人//给jpmsr2这个panel中初始化20个陌生人JLabel jbls2[] = new JLabel[20];for(int i=0; i<jbls2.length; i++) {jbls2[i] = new JLabel(i+1+"", newImageIcon("image/mm.png"), JLabel.LEFT);jpmsr2.add(jbls2[i]);}jpmsr3 = new JPanel(new GridLayout(2, 1));//把我的好友按钮和陌生人按钮加入到jpmsr3中jpmsr3.add(jpmsr_jb1);jpmsr3.add(jpmsr_jb2);//把jpmsr1放入滚动的pane中jsp2 = new JScrollPane(jpmsr2);//把jpmsr3,jsp2,jpmsr_jb3分别放入jpmsr1中北,中,南三个位置jpmsr1.add(jpmsr3,"North");jpmsr1.add(jsp2,"Center");jpmsr1.add(jpmsr_jb3,"South");//把卡片放入JFrame中c1 = new CardLayout();this.setLayout(c1);this.add(jphy1, "1");this.add(jpmsr1, "2");//在窗口显示自己的namethis.setTitle(userName);this.setSize(170, 450);this.setVisible(true);}//更新在线好友情况public void updateFriend(Message message) {String onLineFriend[] = message.getContext().split(" ");for(int i=0; i<onLineFriend.length; i++) {jbls[Integer.parseInt(onLineFriend[i])-1].setEnabled(true);}}@Overridepublic void mouseClicked(MouseEvent e) {//响应用户双击事件,并得到好友编号if(e.getClickCount() ==2) {String friendNo = ((JLabel)e.getSource()).getText();QqChar qqChar = new QqChar(userName,friendNo);//把新开的聊天窗口加入到管理聊天窗口的map中ManageQqChar.addQqChar(erName+" "+friendNo, qqChar);}}@Overridepublic void mousePressed(MouseEvent e) {}@Overridepublic void mouseReleased(MouseEvent e) {}@Overridepublic void mouseEntered(MouseEvent e) {//当鼠标移上去时,使好友头像变为红色JLabel j1 = (JLabel)e.getSource();j1.setForeground(Color.red);}@Overridepublic void mouseExited(MouseEvent e) { //当把鼠标移走时,恢复成黑色JLabel j1 = (JLabel)e.getSource();j1.setForeground(Color.black);}@Overridepublic void actionPerformed(ActionEvent e) { //如果点击了陌生人按钮,就显示第二张卡片if(e.getSource()==jphy_jb2) {c1.show(this.getContentPane(), "2");} else if(e.getSource()==jpmsr_jb1) {c1.show(this.getContentPane(), "1");}}}Message类:(由于客户端和服务器端的common包里面的东西是一样的,所以这里只发一遍)package mon;import java.io.Serializable;/*** 发送的消息的类* */public class Message implements Serializable{private int mesType;//服务器返回的信息包:1代表用户验证成功,2代表用户验证失败,3代表其他信息包;private String sender;//发送消息的人private String getter;//接收消息的人private String context;//发送的消息private String time;//发送的时间public int getMesType() {return mesType;}public void setMesType(int mesType) {this.mesType = mesType;}public String getSender() {return sender;}public void setSender(String sender) {this.sender = sender;}public String getGetter() {return getter;}public void setGetter(String getter) {this.getter = getter;}public String getContext() {return context;}public void setContext(String context) { this.context = context;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}}MessageType类:package mon;/*** 定义包的总类* */public interface MessageType {//表明登入成功的包int message_succeed = 1;//表明登入失败的包int message_login_fail = 2;//表明普通的包int message_common_mes = 3;//要求返回在线好友的包int message_get_onLineFriend = 4;//返回在线好友的包int message_ret_onLineFriend = 5; }User类:package mon;import java.io.Serializable;/*** 用户类* */public class User implements Serializable{ private String name;//用户名private String passWord;//密码public String getName() {return name;}public void setName(String name) { = name;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) { this.passWord = passWord;}}ManageClientThread类:package com.qq.server.model;import java.util.HashMap;import java.util.Iterator;import java.util.Map;/*** 这是一个管理服务器和客户端保持通讯的线程类* */public class ManageClientThread {public static Map map = new HashMap<String, SerConClientThread>();//向map中添加一个线程public static void addCilentThread(String userName, SerConClientThread sc) {map.put(userName, sc);}//根据userName取得一个线程public static SerConClientThread getCilentThread(String userName) {return (SerConClientThread) map.get(userName);}//返回当前在线的人的情况public static String getAllOnLineUser() {//使用迭代器完成Iterator it = map.keySet().iterator();String res = "";while(it.hasNext()) {res += it.next().toString() + " ";}return res;}}MyQqServer类:package com.qq.server.model;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .ServerSocket;import .Socket;import mon.Message;import er;/*** 这是QQ服务器** */public class MyQqServer {public ServerSocket server;public static void main(String[] args) {new MyQqServer();}public MyQqServer() {try {System.out.println("在9999服务器监听.....");server = new ServerSocket(9999);//阻塞,等待某个客户端来连接while(true){Socket client = server.accept();//读取从客户端发来的消息ObjectInputStream ois = newObjectInputStream(client.getInputStream());User user = (User)ois.readObject();System.out.println("姓名是==="+user.getName()+"===密码是---"+user.getPassWord()+"---");ObjectOutputStream oos = newObjectOutputStream(client.getOutputStream());Message message = new Message();//只要密码是123456都让它登录成功if(user.getPassWord().equals("123456")) {message.setMesType(1);oos.writeObject(message);//登入成功,开启一个线程SerConClientThread sc = new SerConClientThread(client);//把该线程加入到map中ManageClientThread.addCilentThread(user.getName(), sc);//启动线程sc.start();//通知其他在线用户sc.notifyOther(user.getName());} else {//登录不成功时message.setMesType(2);oos.writeObject(message);client.close();}}} catch (Exception e) {e.printStackTrace();}}}QqServerUser类由于没写东西,所以不用创建也可以。
qq源代码
UserHelper..cs类代码using System;using System.Collections.Generic;using System.Text;namespace MyQQ{//记录登录的用户Idclass UserHelper{public static int loginId; //登录的用户Id}}using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///聊天窗体///</summary>public partial class ChatForm : Form{public int friendId; // 当前聊天的好友号码public string nickName; // 当前聊天的好友昵称public int faceId; // 当前聊天的好友头像Idpublic ChatForm(){InitializeComponent();}// 窗体加载时的动作private void ChatForm_Load(object sender, EventArgs e){// 设置窗体标题this.Text = string.Format("与{0}聊天中",nickName);// 设置窗体顶部显示的好友信息picFace.Image = ilFaces.Images[faceId];lblFriend.Text = string.Format("{0}({1})",nickName,friendId);// 读取所有的未读消息,显示在窗体中ShowMessage();}// 关闭窗体private void btnClose_Click(object sender, EventArgs e){this.Close();}// 发送消息private void btnSend_Click(object sender, EventArgs e){if (txtChat.Text.Trim() == "") // 不能发送空消息{MessageBox.Show("不能发送空消息!", "提示", MessageBoxButtons.OK, rmation);return;}else if (txtChat.Text.Trim().Length > 50){MessageBox.Show("消息内容过长,请分为几条发送!", "提示", MessageBoxButtons.OK, rmation);return;}else// 发送消息,写入数据库{// MessageTypeId:1-表示聊天消息,为简化操作没有读取数据表,到S2可以用常量或者枚举实现// MessageState:0-表示消息状态是未读int result = -1; // 表示操作数据库的结果string sql = string.Format("INSERT INTO Messages (FromUserId, ToUserId, Message, MessageTypeId,MessageState) VALUES ({0},{1},'{2}',{3},{4})",UserHelper.loginId, friendId, txtChat.Text.Trim(), 1, 0);try{// 执行命令SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result != 1){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}txtChat.Text = ""; // 输入消息清空this.Close();}}///<summary>///读取所有的未读消息,显示在窗体中///</summary>private void ShowMessage(){string messageIdsString = ""; // 消息的Id组成的字符串string message; // 消息内容string messageTime; // 消息发出的时间// 读取消息的SQL语句string sql = string.Format("SELECT Id, Message,MessageTime From Messages WHERE FromUserId={0} AND ToUserId={1} AND MessageTypeId=1 AND MessageState=0",friendId,UserHelper.loginId);try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader reader = command.ExecuteReader();// 循环将消息添加到窗体上while (reader.Read()){messageIdsString += Convert.ToString(reader["Id"]) + "_";message = Convert.ToString(reader["Message"]);messageTime = Convert.ToDateTime(reader["MessageTime"]).ToString(); // 转换为日期类型,告诉学员lblMessages.Text += string.Format("\n{0} {1}\n{2}",nickName,messageTime,message);}reader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 把显示出的消息置为已读if (messageIdsString.Length > 1){messageIdsString.Remove(messageIdsString.Length - 1);SetMessageRead(messageIdsString, '_');}}///<summary>///把显示出的消息置为已读///</summary>private void SetMessageRead(string messageIdsString, char separator){string[] messageIds = messageIdsString.Split(separator); // 分割出每个消息Idstring sql = "Update Messages SET MessageState=1 WHERE Id="; // 更新状态的SQL语句的固定部分string updateSql; // 执行的SQL语句try{SqlCommand command = new SqlCommand(); // 创建Command对象command.Connection = DBHelper.connection; // 指定数据库连接DBHelper.connection.Open(); // 打开数据库连接foreach (string id in messageIds){if (id != ""){updateSql = sql + id; // 补充完整的SQL语句 mandText = updateSql; // 指定要执行的SQL语句int result = command.ExecuteNonQuery(); // 执行命令}}}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}}ChatForm.cs代码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///聊天窗体///</summary>public partial class ChatForm : Form{public int friendId; // 当前聊天的好友号码public string nickName; // 当前聊天的好友昵称public int faceId; // 当前聊天的好友头像Idpublic ChatForm(){InitializeComponent();}// 窗体加载时的动作private void ChatForm_Load(object sender, EventArgs e){// 设置窗体标题this.Text = string.Format("与{0}聊天中",nickName);// 设置窗体顶部显示的好友信息picFace.Image = ilFaces.Images[faceId];lblFriend.Text = string.Format("{0}({1})",nickName,friendId);// 读取所有的未读消息,显示在窗体中ShowMessage();}// 关闭窗体private void btnClose_Click(object sender, EventArgs e){this.Close();}// 发送消息private void btnSend_Click(object sender, EventArgs e){if (txtChat.Text.Trim() == "") // 不能发送空消息{MessageBox.Show("不能发送空消息!", "提示", MessageBoxButtons.OK, rmation);return;}else if (txtChat.Text.Trim().Length > 50){MessageBox.Show("消息内容过长,请分为几条发送!", "提示", MessageBoxButtons.OK, rmation);return;}else// 发送消息,写入数据库{// MessageTypeId:1-表示聊天消息,为简化操作没有读取数据表,到S2可以用常量或者枚举实现// MessageState:0-表示消息状态是未读int result = -1; // 表示操作数据库的结果string sql = string.Format("INSERT INTO Messages (FromUserId, ToUserId, Message, MessageTypeId, MessageState) VALUES ({0},{1},'{2}',{3},{4})",UserHelper.loginId, friendId, txtChat.Text.Trim(), 1, 0);try{// 执行命令SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result != 1){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}txtChat.Text = ""; // 输入消息清空this.Close();}}///<summary>///读取所有的未读消息,显示在窗体中///</summary>private void ShowMessage(){string messageIdsString = ""; // 消息的Id组成的字符串string message; // 消息内容string messageTime; // 消息发出的时间// 读取消息的SQL语句string sql = string.Format("SELECT Id, Message,MessageTime From Messages WHERE FromUserId={0} AND ToUserId={1} AND MessageTypeId=1 AND MessageState=0",friendId,UserHelper.loginId);try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader reader = command.ExecuteReader();// 循环将消息添加到窗体上while (reader.Read()){messageIdsString += Convert.ToString(reader["Id"]) + "_";message = Convert.ToString(reader["Message"]);messageTime = Convert.ToDateTime(reader["MessageTime"]).ToString(); // 转换为日期类型,告诉学员lblMessages.Text += string.Format("\n{0} {1}\n{2}",nickName,messageTime,message);}reader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 把显示出的消息置为已读if (messageIdsString.Length > 1){messageIdsString.Remove(messageIdsString.Length - 1);SetMessageRead(messageIdsString, '_');}}///<summary>///把显示出的消息置为已读///</summary>private void SetMessageRead(string messageIdsString, char separator){string[] messageIds = messageIdsString.Split(separator); // 分割出每个消息Idstring sql = "Update Messages SET MessageState=1 WHERE Id="; // 更新状态的SQL语句的固定部分string updateSql; // 执行的SQL语句try{SqlCommand command = new SqlCommand(); // 创建Command对象command.Connection = DBHelper.connection; // 指定数据库连接DBHelper.connection.Open(); // 打开数据库连接foreach (string id in messageIds){if (id != ""){updateSql = sql + id; // 补充完整的SQL语句 mandText = updateSql; // 指定要执行的SQL语句int result = command.ExecuteNonQuery(); // 执行命令}}}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}}private void lblMessages_Click(object sender, EventArgs e){}}}DBHelper.cs类代码using System;using System.Collections.Generic;using System.Text;using System.Data.SqlClient;namespace MyQQ{// 数据库帮助类,维护数据库连接字符串和数据库连接对象class DBHelper{private static string connString = "Data Source=.;database=MyQQ;integrated security=sspi";public static SqlConnection connection = new SqlConnection(connString);}}using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;namespace MyQQ{///<summary>///头像选择窗体///</summary>public partial class FacesForm : Form{public PersonalInfoForm personalInfoForm; // 个人信息窗体public FacesForm(){InitializeComponent();}1.FacesForm.cs代码private void FacesForm_Load(object sender, EventArgs e){for (int i = 0; i < ilFaces.Images.Count; i++){lvFaces.Items.Add(i.ToString());lvFaces.Items[i].ImageIndex = i;}}// 确定选择头像private void btnOK_Click(object sender, EventArgs e){if (lvFaces.SelectedItems.Count == 0){MessageBox.Show("请选择一个头像!", "提示", MessageBoxButtons.OK, rmation);}else{int faceId = lvFaces.SelectedItems[0].ImageIndex; // 获得当前选中的头像的索引personalInfoForm.ShowFace(faceId); // 设置个人信息窗体中显示的头像this.Close();}}// 双击时选择头像private void lvIcons_MouseDoubleClick(object sender, MouseEventArgs e){int faceId = lvFaces.SelectedItems[0].ImageIndex; // 获得当前选中的头像的索引 personalInfoForm.ShowFace(faceId); // 设置个人信息窗体中显示的头像this.Close();}// 关闭窗体private void btnCancel_Click(object sender, EventArgs e){this.Close();}}}LoginForm.csusing System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Data.SqlClient;namespace MyQQ{///<summary>///登录窗体///</summary>public partial class LoginForm : Form{public LoginForm(){InitializeComponent();}// 取消按钮的事件处理private void btnCancel_Click(object sender, EventArgs e){Application.Exit();}// 打开申请号码界面private void llbl_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {RegisterForm registerForm = new RegisterForm();registerForm.Show();}// 登录按钮事件处理private void btnLogin_Click(object sender, EventArgs e){bool error = false; // 标志在执行数据库操作的过程中是否出错// 如果输入验证成功,就验证身份,并转到相应的窗体if (ValidateInput()){int num = 0; // 数据库操作结果try{// 查询用的sql语句string sql = string.Format("SELECT COUNT(*) FROM Users WHERE Id={0} AND LoginPwd = '{1}'",int.Parse(txtLoginId.Text.Trim()), txtLoginPwd.Text.Trim());// 创建Command 对象SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open(); // 打开数据库连接num = Convert.ToInt32(command.ExecuteScalar());}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close(); // 关闭数据库连接}if (!error && (num == 1)) // 验证通过{// 设置登录的用户号码UserHelper.loginId = int.Parse(txtLoginId.Text.Trim());// 创建主窗体MainForm mainForm = new MainForm();mainForm.Show(); // 显示窗体this.Visible = false; // 当前窗体不可见}else{MessageBox.Show("输入的用户名或密码有误!", "登录提示", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}// 忘记密码标签private void llblFogetPwd_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {MessageBox.Show("该功能尚未开通!","提示",MessageBoxButtons.OK,rmation);}// 用户输入验证private bool ValidateInput(){// 验证用户输入if (txtLoginId.Text.Trim() == ""){MessageBox.Show("请输入登录的号码", "登录提示", MessageBoxButtons.OK, rmation);txtLoginId.Focus();return false;}else if (txtLoginPwd.Text.Trim() == ""){MessageBox.Show("请输入密码", "登录提示", MessageBoxButtons.OK, rmation);txtLoginPwd.Focus();return false;}return true;}}}MainForm.csusing System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using Aptech.UI;using System.Data.SqlClient;using System.Media;namespace MyQQ{///<summary>///登录后的主窗体///</summary>public partial class MainForm : Form{int fromUserId; // 消息的发起者int friendFaceId; // 发消息的好友的头像Idint messageImageIndex = 0; // 工具栏中的消息图标的索引public MainForm(){InitializeComponent();}// 窗体加载时发生private void MainForm_Load(object sender, EventArgs e) {// 工具栏的消息图标tsbtnMessageReading.Image = ilMessage.Images[0];// 显示个人的信息ShowSelfInfo();// 添加SideBar 的两个组sbFriends.AddGroup("我的好友");sbFriends.AddGroup("陌生人");// 向我的好友组中添加我的好友列表ShowFriendList();}// 窗体关闭后,退出应用程序private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {Application.Exit();}// 显示个人信息窗体private void tsbtnPersonalInfo_Click(object sender, EventArgs e){PersonalInfoForm personalInfoForm = new PersonalInfoForm();personalInfoForm.mainForm = this; // 将当前窗体本身传给个人信息窗体 personalInfoForm.Show();}// 显示查找好友窗体private void tsbtnSearchFriend_Click(object sender, EventArgs e){SearchFriendForm searchFriendForm = new SearchFriendForm();searchFriendForm.Show();}// 双击一项,弹出聊天窗体private void sbFriends_ItemDoubleClick(SbItemEventArgs e){// 消息timer停止运行if (tmrChatRequest.Enabled == true){tmrChatRequest.Stop();e.Item.ImageIndex = this.friendFaceId;}// 显示聊天窗体ChatForm chatForm = new ChatForm();chatForm.friendId = Convert.ToInt32(e.Item.Tag); // 号码chatForm.nickName = e.Item.Text; // 昵称chatForm.faceId = e.Item.ImageIndex; // 头像chatForm.Show();}// 点击刷新好友列表private void tsbtnUpdateFriendList_Click(object sender, EventArgs e){ShowFriendList();}// 定时扫描数据库,找到未读消息private void tmrMessage_Tick(object sender, EventArgs e){ShowFriendList(); // 刷新好友列表int messageTypeId = 1; // 消息类型int messageState = 1; // 消息状态// 找出未读消息对应的好友Idstring sql = string.Format("SELECT Top 1 FromUserId, MessageTypeId, MessageState FROM Messages WHERE ToUserId={0} AND MessageState=0", UserHelper.loginId);SqlCommand command;// 消息有两种类型:聊天消息、添加好友消息try{command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();// 循环读出一个未读消息if (dataReader.Read()){this.fromUserId = (int)dataReader["FromUserId"];messageTypeId = (int)dataReader["MessageTypeId"];messageState = (int)dataReader["MessageState"];}dataReader.Close();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 判断消息类型,如果是添加好友消息,就启动喇叭timer,让小喇叭闪烁if (messageTypeId == 2 && messageState == 0){SoundPlayer player = new SoundPlayer("system.wav");player.Play();tmrAddFriend.Start();}// 如果是聊天消息,就启动聊天timer,让好友头像闪烁else if (messageTypeId == 1 && messageState == 0){// 获得发消息的人的头像Idsql = "SELECT FaceId FROM Users WHERE Id=" + this.fromUserId;try{command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();this.friendFaceId = Convert.ToInt32(command.ExecuteScalar()); // 设置发消息的好友的头像索引}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 如果发消息的人没有在列表中就添加到陌生人列表中if (!HasShowUser(fromUserId)){UpdateStranger(fromUserId);}SoundPlayer player = new SoundPlayer("msg.wav");player.Play();tmrChatRequest.Start(); // 启动闪烁头像定时器}}// 控制喇叭闪烁private void tmrAddFriend_Tick(object sender, EventArgs e){// 反复修改它的图像messageImageIndex = messageImageIndex == 0 ? 1:0;tsbtnMessageReading.Image = ilMessage.Images[messageImageIndex];}// 单击时显示请求好友消息窗体private void tsbtnMessageReading_Click(object sender, EventArgs e){tmrAddFriend.Stop(); // 消息timer停止运行// 图片恢复正常messageImageIndex = 0;tsbtnMessageReading.Image = ilMessage.Images[messageImageIndex];// 显示系统消息窗体RequestForm requestForm = new RequestForm();requestForm.Show();}// 让相应的好友头像闪烁private void tmrChatRequest_Tick(object sender, EventArgs e){// 循环好友列表两个组中的每个item,找到发消息的好友,让他的头像闪烁for (int i = 0; i < 2; i++){for (int j = 0; j < sbFriends.Groups[i].Items.Count; j++){if(Convert.ToInt32(sbFriends.Groups[i].Items[j].Tag) == this.fromUserId) {if (sbFriends.Groups[i].Items[j].ImageIndex < 100){sbFriends.Groups[i].Items[j].ImageIndex = 100;// 索引为的图片是一个空白图片}else{sbFriends.Groups[i].Items[j].ImageIndex = this.friendFaceId;}sbFriends.Invalidate(); // 重新绘制,只要告诉学生需要这句话才能正常闪烁头像就行}}}}// 显示右键菜单时,控制哪些菜单不可见private void cmsFriendList_Opening(object sender, CancelEventArgs e){// 如果没有选中的项if (sbFriends.SeletedItem == null){tsmiDelete.Visible = false;}else{tsmiDelete.Visible = true;}// 如果选中的是陌生人,显示加为好友菜单if (sbFriends.SeletedItem != null && sbFriends.SeletedItem.Parent == sbFriends.Groups[1]){tsmiAddFriend.Visible = true;}else{tsmiAddFriend.Visible = false;}}// 显示大、小头像视图切换private void tsmiView_Click(object sender, EventArgs e){if (sbFriends.View == rgeIcon){sbFriends.View = SbView.SmallIcon;tsmiView.Text = "显示大头像";}else if (sbFriends.View == SbView.SmallIcon){sbFriends.View = rgeIcon;tsmiView.Text = "显示小头像";}}// 删除好友private void tsmiDelete_Click(object sender, EventArgs e){DialogResult result; // 对话框结果int deleteResult = 0; // 操作结果if (sbFriends.SeletedItem != null){result = MessageBox.Show("确实要删除该好友吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes) // 确认删除{if (sbFriends.VisibleGroup == sbFriends.Groups[0]){string sql = string.Format("DELETE FROM Friends WHERE HostId={0} AND FriendId={1}",UserHelper.loginId, Convert.ToInt32(sbFriends.SeletedItem.Tag));try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();deleteResult = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (deleteResult == 1){MessageBox.Show("好友已删除", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);}}else{MessageBox.Show("好友已删除", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);}}}}// 将选中的人加为好友private void tsmiAddFriend_Click(object sender, EventArgs e){int result = 0; // 操作结果string sql = string.Format("INSERT INTO Friends (HostId, FriendId) VALUES({0},{1})",UserHelper.loginId, Convert.ToInt32(sbFriends.SeletedItem.Tag));try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();result = command.ExecuteNonQuery();}catch (Exception ex){Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}if (result == 1){MessageBox.Show("添加成功!", "提示", MessageBoxButtons.OK, rmation);sbFriends.SeletedItem.Parent.Items.Remove(sbFriends.SeletedItem);ShowFriendList(); // 更新好友列表}else{MessageBox.Show("添加失败,请稍候再试!", "提示", MessageBoxButtons.OK, rmation);}}// 退出private void tsbtnExit_Click(object sender, EventArgs e){DialogResult result = MessageBox.Show("确实要退出吗?", "操作确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes){Application.Exit();}}// 可见组发生变化时,发出声音private void sbFriends_VisibleGroupChanged(SbGroupEventArgs e){SoundPlayer player = new SoundPlayer("folder.wav");player.Play();}///<summary>///登录后显示个人的信息///</summary>public void ShowSelfInfo(){string nickName = ""; // 昵称int faceId = 0; // 头像索引bool error = false; // 标识是否出现错误// 取得当前用户的昵称、头像string sql = string.Format("SELECT NickName, FaceId FROM Users WHERE Id={0}",UserHelper.loginId);try{// 查询SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();if (dataReader.Read()){if (!(dataReader["NickName"] is DBNull)) // 判断数据库类型是否为空 {nickName = Convert.ToString(dataReader["NickName"]);}faceId = Convert.ToInt32(dataReader["FaceId"]);}dataReader.Close();}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 根据操作数据库结果进行不同的操作if (error){MessageBox.Show("服务器请求失败!请重新登录!", "意外错误", MessageBoxButtons.OK, MessageBoxIcon.Error);Application.Exit();}else{// 在窗体标题显示登录的昵称、号码this.Text = UserHelper.loginId.ToString();this.picFace.Image = ilFaces.Images[faceId];this.lblLoginId.Text = string.Format("{0}({1})", nickName,UserHelper.loginId.ToString());}}///<summary>///向我的好友组中添加我的好友列表///</summary>private void ShowFriendList(){// 清空原来的列表sbFriends.Groups[0].Items.Clear();bool error = false; // 标识数据库是否出错// 查找有哪些好友string sql = string.Format("SELECT FriendId,NickName,FaceId FROM Users,Friends WHERE Friends.HostId={0} AND Users.Id=Friends.FriendId",UserHelper.loginId);try{// 执行查询SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader();// 循环添加好友列表while (dataReader.Read()){// 创建一个SideBar项SbItem item = new SbItem((string)dataReader["NickName"], (int)dataReader["FaceId"]);item.Tag = (int)dataReader["FriendId"]; // 将号码放在Tag属性中// SideBar中的组可以通过数组的方式访问,按照添加的顺序索引从开始// Groups[0]表示SideBar中的第一个组,也就是“我的好友”组sbFriends.Groups[0].Items.Add(item); // 向SideBar的“我的好友”组中添加项 }dataReader.Close();}catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 出错了if (error){MessageBox.Show("服务器发生意外错误!请尝试重新登录", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);Application.Exit();}}///<summary>///判断发消息的人是否在列表中///</summary>private bool HasShowUser(int loginId){bool find = false; // 表示是否在当前显示出的用户列表中找到了该用户// 循环SideBar 中的个组,寻找发消息的人是否在列表中for (int i = 0; i < 2; i++){for (int j = 0; j < sbFriends.Groups[i].Items.Count; j++){if (Convert.ToInt32(sbFriends.Groups[i].Items[j].Tag) == loginId){find = true;}}}return find;}///<summary>///更新陌生人列表///</summary>private void UpdateStranger(int loginId){// 选出这个人的基本信息string sql = "SELECT NickName, FaceId FROM Users WHERE Id=" + loginId;bool error = false; // 用来标识是否出现错误try{SqlCommand command = new SqlCommand(sql, DBHelper.connection);DBHelper.connection.Open();SqlDataReader dataReader = command.ExecuteReader(); // 查询if (dataReader.Read()){SbItem item = new SbItem((string)dataReader["NickName"],(int)dataReader["FaceId"]);item.Tag = this.fromUserId; // 将Id记录在Tag属性中sbFriends.Groups[1].Items.Add(item); // 向陌生人组中添加项}sbFriends.VisibleGroup = sbFriends.Groups[1]; // 设定陌生人组为可见组 }catch (Exception ex){error = true;Console.WriteLine(ex.Message);}finally{DBHelper.connection.Close();}// 出错了if (error){MessageBox.Show("服务器出现意外错误!", "抱歉", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}}(资料素材和资料部分来自网络,供参考。
QQ应用程序源代码
QQ源代码// MyQQ.cpp: implementation of the MyQQ class. //////////////////////////////////////////////////////////////////// // #include #include#include "winsock2.h"#include "MyQQ.h" #include "md5.h"#ifdef _DEBUG #undef THIS_FILEstatic char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif////////////////////////////////////////////////////////////////////// // Construction/Destruction////////////////////////////////////////////////////////////////////// MyQQ::MyQQ() {s = NULL;LoginToken = NULL; LoginTokenLength = 0; Status = 0; //下线 IsLogin = false; LastID = 0;MessageText = NULL; FriendListHead = NULL; FriendListTail = NULL;send_seq = random() & 0x0000ffff; LastOnline = time(NULL); UDPServerNum = 0; //服务器地址LoginServer = (char *)malloc(16*sizeof(char)); //QQ号 UserID = 0; //密码Password = NULL;//得到初始化密钥,按2004版InitKey = (unsigned char*)malloc(QQ_KEY_LENGTH);int i;for(i = 0; i < 16; i++) InitKey = rand();SessionKey = (unsigned char*)malloc(QQ_KEY_LENGTH); }MyQQ::~MyQQ() {if(LoginServer != NULL) free(LoginServer); if(MyIP != NULL) free(MyIP); if(MessageText != NULL) free(MessageText); if(Password != NULL) free(Pass word); if(InitKey != NULL) free(InitKey); if(PwdKey != NULL) free(PwdKey); if(SessionKey != NULL) free(SessionKey);if(FriendListHead != NULL) {QQFriend *p = FriendListHead->next; while(p != NULL) {free(FriendListHead); FriendListHead = p; p = p->next; }if(FriendListTail != NULL) free(FriendListTail); } }void MyQQ::Login(int pMode) {unsigned char *buf, *cursor, *raw_data, *encrypted_data; int seq_ret;int encrypted_len, bytes;//登录模式:1 为正常登录,2为隐身登录 ,3登录即离开 LoginMode = pMode;if(LoginToken == NULL) {//发送获取登录令牌的包 qq_get_logintoken(); } else {//2004登录包buf = (unsigned char*)malloc(MAX_PACKAGE_LENGTH); //包长65535 raw_data = (unsigned char*)malloc(QQ_LOGIN_DATA_LENGTH); //数据长encrypted_data = (unsigned char*)malloc(QQ_LOGIN_DATA_LENGTH + 16); //加密数据长度多16// 产生密文// 000-015 用PwdKey加密空串MCrypter.qq_crypt(ENCRYPT, (unsigned char*)"", 0, PwdKey, raw_data, &encrypted_le n);//016-051 36字节的固定内容memmove(raw_data + 16, login_16_51, 36);//052-052 登录方式raw_data[52] = (unsigned char)LoginMode;//053-068 16字节固定内容memmove(raw_data + 53, login_53_68, 16);//069 登录令牌长度 int pos = 69;raw_data[pos++] = (unsigned char)LoginTokenLength;//070-? 登录令牌memmove(raw_data + pos, LoginToken, LoginTokenLength);pos += LoginTokenLength;//未知字节0x40raw_data[pos++] = 0x40;//固定字节memmove(raw_data + pos, LOGIN_SEGMENTS, 100);pos += 100;//剩下的字节填零for(; pos < QQ_LOGIN_DATA_LENGTH; pos++) raw_data[pos] = 0x00;//加密MCrypter.qq_crypt(ENCRYPT, raw_data, QQ_LOGIN_DATA_LENGTH, InitKey, encryp ted_data, &encrypted_len);cursor = buf; bytes = 0;bytes += create_packet_head_seq(buf, &cursor, QQ_CMD_LOGIN, true, &seq_ret);bytes += create_packet_dw(buf, &cursor, UserID);bytes += create_packet_data(buf, &cursor, InitKey, QQ_KEY_LENGTH); bytes += c reate_packet_data(buf, &cursor, encrypted_data, encrypted_len); bytes += create_packet_b(b uf, &cursor, QQ_PACKET_TAIL);if (bytes == (cursor - buf)) //包被无误创建 {qq_send_packet(buf, bytes, QQ_CMD_LOGIN); }free(buf);free(raw_data);free(encrypted_data); } }//从包中读取一个字节int MyQQ::read_packet_b(unsigned char * buf, unsigned char ** cursor, int buflen, unsigned ch ar * b) {if(*cursor <= buf + buflen - sizeof(*b)) {*b = **(unsigned char **) cursor; *cursor += sizeof(*b); return sizeof(*b); } elsereturn -1; }//从包中读取一个字int MyQQ::read_packet_w(unsigned char * buf, unsigned char ** cursor, int buflen, short * w) {if(*cursor <= buf + buflen - sizeof(*w)) {*w = ntohs(**(short **) cursor); *cursor += sizeof(*w); return sizeof(*w); } e lsereturn -1; }//处理收到的消息void MyQQ::qq_process_recv_im(unsigned char* buf, int buf_len, short seq) {int len, bytes;unsigned char *data, *cursor; qq_recv_im_header *im_header;len = buf_len;data = (unsigned char *)malloc(len);if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len)) {if(len < 16) return; elseqq_send_packet_recv_im_ack(seq, data);cursor = data; bytes = 0;im_header = (qq_recv_im_header *)malloc(sizeof(qq_recv_im_header)); bytes += re ad_packet_dw(data, &cursor, len, &(im_header->sender_uid)); bytes += read_packet_dw(dat a, &cursor, len, &(im_header->receiver_uid)); bytes += read_packet_dw(data, &cursor, len, &(im_header->server_im_seq));bytes += read_packet_data(data, &cursor, len, (unsigned char *) & (im_header->sender_ip ), 4);bytes += read_packet_w(data, &cursor, len, &(im_header->sender_port)); bytes += re ad_packet_w(data, &cursor, len, &(im_header->im_type));if (bytes != 20) { // im_header的长度 return;}if (im_header->receiver_uid != UserID) {return; }LastID = im_header->sender_uid;switch (im_header->im_type) {case QQ_RECV_IM_TO_BUDDY:qq_process_recv_normal_im(data, &cursor, len); break;case QQ_RECV_IM_TO_UNKNOWN:qq_process_recv_normal_im(data, &cursor, len); break;case QQ_RECV_IM_GROUP_IM://qq_process_recv_group_im(data, &cursor, len, im_header->sender_uid, gc); break; case QQ_RECV_IM_ADD_TO_GROUP: //qq_process_recv_group_im_been_added(da ta, &cursor, len, im_header->sender_uid, gc); break;case QQ_RECV_IM_DEL_FROM_GROUP://qq_process_recv_group_im_been_removed(data, &cursor, len, im_header->sender_uid, gc); break;case QQ_RECV_IM_APPL Y_ADD_TO_GROUP: //qq_process_recv_group_im_apply _join(data, &cursor, len, im_header->sender_uid, gc); break;case QQ_RECV_IM_APPROVE_APPL Y_ADD_TO_GROUP://qq_process_recv_group_im_been_approved(data, &cursor, len, im_header->sender_uid, gc); break;case QQ_RECV_IM_REJCT_APPL Y_ADD_TO_GROUP: //qq_process_recv_group_i m_been_rejected(data, &cursor, len, im_header->sender_uid, gc); break;case QQ_RECV_IM_SYS_NOTIFICATION://_qq_process_recv_sys_im(data, &cursor, len, gc); break; default:break; }// switch } }//处理登录Reply的消息void MyQQ::qq_process_login_reply(unsigned char* buf, int buf_len) {if(IsLogin == true) return;int len, ret, bytes; unsigned char *data;len = buf_len;data = (unsigned char*)malloc(len);if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, PwdKey, data, &len)) {if (data[0] == QQ_LOGIN_REPL Y_OK) { ret = qq_process_login_ok(data, len); } else {ret = QQ_LOGIN_REPL Y_MISC_ERROR; }} else {len = buf_len;if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, InitKey, data, &len)) { bytes = 0;switch (data[0]) {case QQ_LOGIN_REPL Y_REDIRECT: ret = qq_process_login_redirect(data, len); break; case QQ_LOGIN_REPL Y_PWD_ERROR: ret = qq_process_login_wrong_pwd(data, len); brea k; default:ret = QQ_LOGIN_REPL Y_MISC_ERROR; }} else {ret = QQ_LOGIN_REPL Y_MISC_ERROR; } }switch (ret) {case QQ_LOGIN_REPL Y_PWD_ERROR:MessageBox(NULL,"QQ密码错误!","错误",MB_OK); break;case QQ_LOGIN_REPL Y_MISC_ERROR:MessageBox(NULL,"QQ登录出错,请重试!","错误",MB_OK); break;case QQ_LOGIN_REPL Y_OK: break;case QQ_LOGIN_REPL Y_REDIRECT: break; default: break;} // switch ret }void MyQQ::qq_process_group_cmd_reply(unsigned char* cursor, int len, short seq){}void MyQQ::qq_process_msg_sys(unsigned char* cursor, int len, short seq){}void MyQQ::qq_process_friend_change_status(unsigned char* buf, int buf_len) {int len, bytes;unsigned char *data, *cursor;len = buf_len;data = (unsigned char*)malloc(len); cursor = data;qq_buddy_status * ss;if(MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len)) {ss = (qq_buddy_status *)malloc(sizeof(qq_buddy_status)); bytes = 0;// 000-003: uidbytes += read_packet_dw(data, &cursor, len, &ss->uid); // 004-004: 0x01bytes += read_packet_b(data, &cursor, len, &ss->unknown1); // 005-008: ipss->ip = (unsigned char*)malloc(4);bytes += read_packet_data(data, &cursor, len, ss->ip, 4); // 009-010: portbytes += read_packet_w(data, &cursor, len, &ss->port); // 011-011: 0x00bytes += read_packet_b(data, &cursor, len, &ss->unknown2); // 012-012: statusbytes += read_packet_b(data, &cursor, len, &ss->status); // 013-014:bytes += read_packet_w(data, &cursor, len, &ss->unknown3); // 015-030: unknown keyss->unknown_key = (unsigned char*)malloc(QQ_KEY_LENGTH);bytes += read_packet_data(data, &cursor, len, ss->unknown_key, QQ_KEY_LENGTH); }//这里是更新好友的状态,可自己实现接口//I_QQChangeBuddyStatus(ss->uid, ss->status); }int MyQQ::qq_process_login_ok(unsigned char * data, int len) {qq_login_reply_ok lrop; int bytes;unsigned char* cursor;cursor = data; bytes = 0;// 000-000: reply codebytes += read_packet_b(data, &cursor, len, &lrop.result); // 001-016: session keylrop.session_key = (unsigned char*)malloc(QQ_KEY_LENGTH); memcpy(lrop.session_key,c ursor,QQ_KEY_LENGTH);cursor += QQ_KEY_LENGTH; bytes += QQ_KEY_LENGTH;// 017-020: login uidbytes += read_packet_dw(data, &cursor, len, &lrop.uid); // 021-024: server detected user public IPbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.client_ip, 4); // 025-026 : server detected user portbytes += read_packet_w(data, &cursor, len, &lrop.client_port); // 027-030: server detected itsel f ip ?bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.server_ip, 4); // 031-03 2: server listening portbytes += read_packet_w(data, &cursor, len, &lrop.server_port); // 033-036: login time for curre nt sessionbytes += read_packet_dw(data, &cursor, len, (DWORD *) & lrop.login_time); // 037-062: 26 b ytes, unknownbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown1, 26); // 063-066: unknown server1 ip addressbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown_server1_ip, 4 ); // 067-068: unknown server1 portbytes += read_packet_w(data, &cursor, len, &lrop.unknown_server1_port); // 069-072: unknow n server2 ip addressbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown_server2_ip, 4 ); // 073-074: unknown server2 portbytes += read_packet_w(data, &cursor, len, &lrop.unknown_server2_port); // 075-076: 2 bytes unknownbytes += read_packet_w(data, &cursor, len, &lrop.unknown2); // 077-078: 2 bytes unknownbytes += read_packet_w(data, &cursor, len, &lrop.unknown3); // 079-110: 32 bytes unknown bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown4, 32); // 111-1 22: 12 bytes unknownbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown5, 12); // 123-126: login IP of last sessionbytes += read_packet_data(data, &cursor, len, (unsigned char *) & st_client_ip, 4); // 127 -130: login time of last sessionbytes += read_packet_dw(data, &cursor, len, (DWORD *) & st_login_time); // 131-138: 8 bytes unknownbytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown6, 8); memcpy(SessionKey,lrop.session_key, QQ_KEY_LENGTH);sprintf(MyIP,"%d.%d.%d.%d",lrop.client_ip[0],lrop.client_ip[1],lrop.client_ip[2],lrop.client_ip [3]);MyPort = lrop.client_port; IsLogin = true;qq_send_packet_get_info(UserID);switch(LoginMode) {case 1: Status = 1; break; case 2: Status = 3; break; default:break; }qq_send_packet_change_status();GetFriendList();return QQ_LOGIN_REPL Y_OK; }int MyQQ::qq_process_login_redirect(unsigned char * data, int len) {int bytes, ret;unsigned char *cursor;qq_login_reply_redirect_packet lrrp;cursor = data; bytes = 0;// 000-000: reply codebytes += read_packet_b(data, &cursor, len, &lrrp.result);// 001-004: login uidbytes += read_packet_dw(data, &cursor, len, &lrrp.uid);// 005-008: redirected new server IPbytes += read_packet_data(data, &cursor, len, lrrp.new_server_ip, 4);// 009-010: redirected new server portbytes += read_packet_w(data, &cursor, len, &lrrp.new_server_port);if (bytes != QQ_LOGIN_REPL Y_REDIRECT_PACKET_LEN) {ret = QQ_LOGIN_REPL Y_MISC_ERROR; } else {sprintf(LoginServer,"%d.%d.%d.%d",lrrp.new_server_ip[0],lrrp.new_server_ip[1],lrrp.new_ser ver_ip[2],lrrp.new_server_ip[3]);//服务器端口LoginPort = lrrp.new_server_port;ServerAddr.sin_family = AF_INET;ServerAddr.sin_addr.s_addr = inet_addr(LoginServer); ServerAddr.sin_port = htons(LoginPort) ;//向新的服务器地址发送登录请求 Login(LoginMode);ret = QQ_LOGIN_REPL Y_REDIRECT; }return ret; }int MyQQ::qq_process_login_wrong_pwd(unsigned char * data, int len) {return QQ_LOGIN_REPL Y_PWD_ERROR; }void MyQQ::qq_send_packet_change_status() {unsigned char *raw_data, *cursor, away_cmd; DWORD misc_status;if (IsLogin == false) return;switch (Status) { case 1:away_cmd = QQ_BUDDY_ONLINE_NORMAL; break; case 2:away_cmd = QQ_BUDDY_ONLINE_INVISIBLE; break; case 3:away_cmd = QQ_BUDDY_ONLINE_AWAY; break; default:away_cmd = QQ_BUDDY_ONLINE_NORMAL; } // switchraw_data = (unsigned char*)malloc(5); cursor = raw_data; misc_status = 0x00000000; create_packet_b(raw_data, &cursor, away_cmd); create_packet_dw(raw_data, &cursor, misc_st atus);qq_send_cmd(QQ_CMD_CHANGE_ONLINE_STA TUS, TRUE, 0, TRUE, raw_data, 5); } void MyQQ::TurnInvisible() {Status = 2;qq_send_packet_change_status(); }void MyQQ::TurnVisible() {Status = 1;qq_send_packet_change_status(); }void MyQQ::TurnAway() {Status = 3;qq_send_packet_change_status(); }void MyQQ::Logout() { int i;for (i = 0; i < 4; i++)qq_send_cmd(QQ_CMD_LOGOUT, FALSE, 0xffff, FALSE, PwdKey, QQ_KEY_LENGTH); IsLogin = false; Status = 0;}void MyQQ::QQSendTextMessage(DWORD to_uid, char * msg, int type) {unsigned char *cursor, *raw_data; short client_tag, normal_im_type; int msg_len, raw_len, byte s; time_t now;unsigned char *md5; char *msg_filtered;char *font_size = NULL, *font_color = NULL, *font_name = NULL, *tmp; bool is_bold = FA LSE, is_italic = FALSE, is_underline = FALSE; const char *start, *end, *last;client_tag = QQ_CLIENT;normal_im_type = QQ_NORMAL_IM_TEXT;last = msg;msg_filtered = msg;msg_len = strlen(msg_filtered); now = time(NULL);md5 = gen_session_md5(UserID, SessionKey);int font_name_len, tail_len;font_name_len = DEFAULT_FONT_NAME_LEN;}void MyQQ::QQSendTextMessage(DWORD to_uid, char * msg, int type) {unsigned char *cursor, *raw_data; short client_tag, normal_im_type; int msg_len, raw_len, byte s; time_t now;unsigned char *md5; char *msg_filtered;char *font_size = NULL, *font_color = NULL, *font_name = NULL, *tmp; bool is_bold = FA LSE, is_italic = FALSE, is_underline = FALSE; const char *start, *end, *last;client_tag = QQ_CLIENT;normal_im_type = QQ_NORMAL_IM_TEXT;last = msg;msg_filtered = msg;msg_len = strlen(msg_filtered); now = time(NULL);md5 = gen_session_md5(UserID, SessionKey);int font_name_len, tail_len;font_name_len = DEFAULT_FONT_NAME_LEN;bytes += create_packet_b(raw_data, &cursor, 0x00); //043-043: sender icon//bytes += create_packet_b(raw_data, &cursor, qd->my_icon); bytes += create_packet_b(raw_d ata, &cursor, MyIcon); //044-046: always 0x00bytes += create_packet_w(raw_data, &cursor, 0x0000); bytes += create_packet_b(raw_data, & cursor, 0x00); //047-047: we use font attrbytes += create_packet_b(raw_data, &cursor, 0x01); //048-051: always 0x00bytes += create_packet_dw(raw_data, &cursor, 0x00000000); //052-052: text message type (no rmal/auto-reply) bytes += create_packet_b(raw_data, &cursor, type); //053- : msg ends with 0x00 bytes += create_packet_data(raw_data, &cursor, (unsigned char *)msg_filtered, msg_len); unsigned char *send_im_tail = qq_get_send_im_tail(font_color, font_size, font_name, false,fals e, false, tail_len);bytes += create_packet_data(raw_data, &cursor, send_im_tail, tail_len);if (bytes == raw_len) // create packet OK {qq_send_cmd(QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, cursor - raw_data); } } const unsigned char simsun[] = { 0xcb, 0xce, 0xcc, 0xe5 };font_name_len = DEFAULT_FONT_NAME_LEN; font_name = (const char*)&(simsun[0]); send_im_tail = (unsigned char*)malloc(tail_len);memcpy(send_im_tail + QQ_SEND_IM_AFTER_MSG_HEADER_LEN, font_name, tail_len - QQ_SEND_IM_AFTER_MSG_HEADER_LEN);send_im_tail[tail_len - 1] = tail_len;send_im_tail[0] = 0x00; send_im_tail[1] = 10;if (is_bold)send_im_tail[1] |= 0x20; if (is_italic)send_im_tail[1] |= 0x40; if (is_underline) send_im_tail[1] |= 0x80;send_im_tail[2] = send_im_tail[3] = send_im_tail[4] = 0;send_im_tail[5] = 0x00; send_im_tail[6] = 0x86; send_im_tail[7] = 0x22;return (unsigned char *) send_im_tail; }//处理普通的QQ消息void MyQQ::qq_process_recv_normal_im(unsigned char * data, unsigned char ** cursor, int len) { int bytes;qq_recv_normal_im_common *common;qq_recv_normal_im_unprocessed *im_unprocessed;if (*cursor >= (data + len - 1)) { return; } elsecommon = (qq_recv_normal_im_common *)malloc(sizeof(qq_recv_normal_im_common)); bytes = qq_normal_im_common_read(data, cursor, len, common); if (bytes < 0) { return; } switch (common->normal_im_type) { case QQ_NORMAL_IM_TEXT:qq_process_recv_normal_im_text (data, cursor, len, common); break;case QQ_NORMAL_IM_FILE_REJECT_UDP: //qq_process_recv_file_reject (data, cursor, len, // common->sender_uid, gc); break;case QQ_NORMAL_IM_FILE_APPROVE_UDP: //qq_process_recv_file_accept (data, cursor, len, // common->sender_uid, gc); break;case QQ_NORMAL_IM_FILE_REQUEST: //qq_process_recv_file_request (data, cursor, len, / / common->sender_uid, gc); break;case QQ_NORMAL_IM_FILE_CANCEL: //qq_process_recv_file_cancel (data, cursor, len, // c ommon->sender_uid, gc); break;case QQ_NORMAL_IM_FILE_NOTIFY: //qq_process_recv_file_notify (data, cursor, len, // co mmon->sender_uid, gc); break; default: return;} // normal_im_typeg_free (common->session_md5); }void MyQQ::qq_process_recv_normal_im_text(unsigned char * data, unsigned char ** cursor, i nt len, qq_recv_normal_im_common * common) {short gaim_msg_type;char *name;char *msg_with_gaim_smiley; char *msg_utf8_encoded; qq_recv_normal_im_text *im_text; if (*cursor >= (data + len - 1)) { return; } elseim_text = (qq_recv_normal_im_text *)malloc(sizeof(qq_recv_normal_im_text));im_text->common = common;read_packet_w(data, cursor, len, &(im_text->msg_seq)); read_packet_dw(data, cursor, len, &(i m_text->send_time)); read_packet_b(data, cursor, len, &(im_text->unknown1)); read_packet_b(d ata, cursor, len, &(im_text->sender_icon));read_packet_data(data, cursor, len, (unsigned char *) & (im_text->unknown2), 3); read_packet _b(data, cursor, len, &(im_text->is_there_font_attr));read_packet_data(data, cursor, len, (unsigned char *) & (im_text->unknown3), 4); read_packet _b(data, cursor, len, &(im_text->msg_type));if (im_text->msg_type == QQ_IM_AUTO_REPL Y) { im_text->is_there_font_attr = 0x00;im_text->msg = (unsigned char *)malloc(1024); memcpy(im_text->msg,*cursor, data + len - *c ursor); } else {if (im_text->is_there_font_attr) {im_text->msg = (unsigned char *)malloc(1500);memcpy(im_text->msg,*cursor, strlen((const char *)*cursor));im_text->msg[strlen((const char *)*cursor)] = 0; } else{ im_text->msg = (unsigned char *)malloc(1024); memcpy(im_text->msg,*cursor, data + len - *cursor); im_text->msg[data + len - *cursor] = 0; } }MessageText = im_text->msg; //如果需要自动回复 if(Status == 3) {//I_QQAutoReply()函数获取预先设置的自动回复消息内容,需自己实现 char* MText = I_QQAutoReply();QQSendTextMessage(common->sender_uid,MText,0x01); }//在主界面中显示消息//I_QQReceiveMessage((char *)MessageText,common->sender_uid); }int MyQQ::qq_normal_im_common_read(unsigned char * data, unsigned char ** cursor, int len , qq_recv_normal_im_common * common) { int bytes;bytes = 0;bytes += read_packet_w(data, cursor, len, &(common->sender_ver)); bytes += read_packet_dw (data, cursor, len, &(common->sender_uid)); bytes += read_packet_dw(data, cursor, len, &(comm on->receiver_uid));common->session_md5 = (unsigned char *)malloc(QQ_KEY_LENGTH); memcpy(common-> session_md5,*cursor, QQ_KEY_LENGTH); bytes += QQ_KEY_LENGTH; *cursor += QQ_KE Y_LENGTH;bytes += read_packet_w(data, cursor, len, &(common->normal_im_type));if (bytes != 28) { return -1; }return bytes; }。
山寨QQ(韩顺平版)
这是一个简单的javaProject项目,没有涉及到数据库界面对这个项目中完成的功能进行阐述:1、qq用户登录:用户账号为1、2、3一直到50,密码都为123456,由于没有涉及到数据库,所以只是简单的在服务器进行验证。
2、实现1对1之间的聊天,实现1对多之间的聊天。
3、实现用户上线显示功能具体的演示为:1、启动服务器QqServer下com.qq.view.MyServerFrame,在该类下面启动服务器2、启动客户端QqClient下com.qq.view.QqClientLogin,在该类下面输入账号和密码登入ps:聊天时要把要把需要聊天的窗口都打开,才能看到。
比如1和2聊天,必须打开1对2聊天的窗口和2对1聊天的窗口QQ客户端:QQ服务器下面的是关于各个包的源代码,小伙伴们可以新建一个class,然后把这些拷贝上去就可以用了,当然前提是按照上面的工程创建好包Image文件夹下用到的图片:命名为:beibu.gif命名为:xiangdao.png命名为:quxiao.png命名为:qq.png命名为:mm.png命名为:clear.png命名为:dengru.pngQqClientConService类:package com.qq.client.model;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .Socket;import com.qq.client.tools.ClientConServerThread;import com.qq.client.tools.ManageClientConServerThread; import mon.Message;import er;/*** 客户端连接服务器后台* */public class QqClientConService {public Socket client;//判断是否成功登录,成功返回true,否则返回falsepublic boolean sendLoginInfoToServer(Object o) {boolean isLogin = false;try {//创建连接client = new Socket("localhost", 9999);ObjectOutputStream oos = newObjectOutputStream(client.getOutputStream());oos.writeObject(o);ObjectInputStream ois = newObjectInputStream(client.getInputStream());Message message = (Message)ois.readObject();//登录成功的判断if(message.getMesType()==1) {isLogin = true;//登录成功,创建一个改客户端和服务器的线程ClientConServerThread ccst = new ClientConServerThread(client);//把改线程添加到管理线程的map中ManageClientConServerThread.addClientConServerThread(((User )o).getName(), ccst);//启动该线程new Thread(ccst).start();}} catch (Exception e) {e.printStackTrace();}return isLogin;}}QqClientUser类:package com.qq.client.model;import er;/*** 这是QQ客户端,发送用户名和密码** */public class QqClientUser {//调用客户端连接服务器后台的方法,返回true为成功登录,false为登入失败public boolean checkUser(User user) {return newQqClientConService().sendLoginInfoToServer(user);}}ClientConServerThread类:package com.qq.client.tools;import java.io.ObjectInputStream;import .Socket;import com.qq.client.view.QqChar;import com.qq.client.view.QqFriendList;import mon.Message;import mon.MessageType;/*** 这是客户端和服务器保持通讯的线程* */public class ClientConServerThread implements Runnable{ public Socket client;public ClientConServerThread(Socket client) {this.client = client;}@Overridepublic void run() {//不停的读取从服务器发来的消息while(true) {try {ObjectInputStream ois = newObjectInputStream(client.getInputStream());Message message = (Message) ois.readObject();//判断发来的消息包是否为普通消息包,或者是返回在线好友的包if(message.getMesType() ==MessageType.message_common_mes) {//把从服务器发来的消息显示在聊天界面:1.从管理聊天窗口的类中取得该窗口 2.调用显示方法.QqChar qqChar =ManageQqChar.getQqChar(message.getGetter()+""+message.getSender());qqChar.showMessage(message);} else if(message.getMesType() == MessageType.message_ret_onLineFriend) {String getter = message.getGetter();//修改响应的好友列表QqFriendList qqFriendList = ManageQqFriendList.getQqFriendList(getter);//更新在线好友if(qqFriendList != null) {qqFriendList.updateFriend(message);}}} catch (Exception e) {e.printStackTrace();}}}}ManageClientConServerThread类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;/*** 这是一个管理客户端和服务器保持通讯的线程类* */public class ManageClientConServerThread {public static Map map = new HashMap<String, ClientConServerThread>();//把线程添加到map中public static void addClientConServerThread(String userName, ClientConServerThread ccst) {map.put(userName, ccst);}//根据用户名取得该线程public static ClientConServerThread getClientConServerThread(String userName) {return (ClientConServerThread)map.get(userName);}}ManageQqChar类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;import com.qq.client.view.QqChar;/*** 这是一个管理用户聊天界面的类* */public class ManageQqChar {public static Map map = new HashMap<String, QqChar>();//把用户聊天界面Qqchar添加到map中public static void addQqChar(String loginAndFriend, QqChar qqchar) {map.put(loginAndFriend, qqchar);}//根据登入用户和发送用户取得该聊天界面public static QqChar getQqChar(String loginAndFriend) { return (QqChar)map.get(loginAndFriend);}}ManageQqFriendList类:package com.qq.client.tools;import java.util.HashMap;import java.util.Map;import com.qq.client.view.QqFriendList;/*** 管理好友、黑名单..界面类* */public class ManageQqFriendList {public static Map map = new HashMap<String, QqFriendList>();//把用用户列表类添加到map中public static void addQqFriendList(String userName, QqFriendList list) {map.put(userName, list);}//根据登录用户取得该用户列表类public static QqFriendList getQqFriendList(String userName) { return (QqFriendList)map.get(userName);}}package com.qq.client.view;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.ObjectOutputStream;import java.util.Date;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JTextArea;import javax.swing.JTextField;import com.qq.client.tools.ManageClientConServerThread;import mon.Message;import mon.MessageType;/*** QQ聊天窗口** */public class extends JFrame implements ActionListener { JTextField jtf;//输入的文本框JTextArea jta;//文本区域JButton jb;//发送按钮JPanel jp;//装文本框和发送按钮的panelString friend;String userName;public static void main(String[] args) {QqChar qqChar = new QqChar("1","2");}public QqChar(String userName,String friend) {erName = userName;this.friend = friend;jtf = new JTextField(15);jta = new JTextArea();jb = new JButton("发送");jb.addActionListener(this);jp = new JPanel();jp.add(jtf);jp.add(jb);this.add(jta, "Center");this.add(jp, "South");this.setTitle(userName+" 正在和 " + friend + " 聊天");this.setIconImage(newImageIcon("image/qq.png").getImage());this.setSize(300, 200);this.setVisible(true);}public void showMessage(Message message) {String info=message.getSender()+" 对"+message.getGetter()+" 说:"+message.getContext()+"\r\n";this.jta.append(info);}@Overridepublic void actionPerformed(ActionEvent e) {//当点击发送按钮时,把消息发送到服务器端if(e.getSource() == jb) {Message message = new Message();message.setMesType(MessageType.message_common_mes);message.setSender(userName);message.setGetter(friend);message.setContext(jtf.getText());jtf.setText("");message.setTime(new Date().toString());try {ObjectOutputStream oos = newObjectOutputStream(ManageClientConServerThread.getClientConSer verThread(userName).client.getOutputStream());oos.writeObject(message);} catch (Exception e1) {e1.printStackTrace();}}}}import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTabbedPane;import javax.swing.JTextField;import com.qq.client.model.QqClientUser;import com.qq.client.tools.ManageClientConServerThread; import com.qq.client.tools.ManageQqFriendList;import mon.Message;import mon.MessageType;import er;/*** QQ客户端登入窗口** */public class extends JFrame implements //定义北部组件JLabel jbl1;//定义中部组件:其中中部组件有一个选项卡的窗口管理,有三个JPanel,一个文本框,一个密码框,4个JLabel,一个清除号码按钮,两个多选框JTabbedPane jtp;//选项卡窗口JPanel jp2;//QQ号码JPanel jp3;//手机号码JPanel jp4;//电子邮件JLabel jp2_jpl1;//QQ号码JLabel jp2_jpl2;//QQ密码JLabel jp2_jpl3;//忘记密码JLabel jp2_jpl4;//申请密码保护JButton jp2_jb1;//清除号码JTextField jp2_jtf;//文本框JPasswordField jp2_jpf;//密码框JCheckBox jp2_jcb1;//隐身登入JCheckBox jp2_jcb2;//记住密码//定义南部组件JPanel jp1;JButton jp1_jb1;//登入按钮JButton jp1_jb2;//取消按钮JButton jp1_jb3;//注册向导按钮public static void main(String[] args) {QqClientLogin qqClientLogin=new QqClientLogin();}public QqClientLogin() {//处理北部的组件jbl1 = new JLabel(new ImageIcon("image/beibu.gif"));//处理中部的组件jp2=new JPanel(new GridLayout(3,3));//把中部分成三行三列jp2_jpl1 = new JLabel("QQ号码", JLabel.CENTER);jp2_jpl2 = new JLabel("QQ密码", JLabel.CENTER);jp2_jpl3 = new JLabel("忘记密码", JLabel.CENTER);jp2_jpl3.setForeground(Color.blue);//把忘记密码设为蓝色jp2_jpl4 = new JLabel("申请密码保护", JLabel.CENTER);jp2_jb1 = new JButton(new ImageIcon("image/clear.png"));jp2_jtf = new JTextField();jp2_jpf = new JPasswordField();jp2_jcb1 = new JCheckBox("隐身登入");jp2_jcb2 = new JCheckBox("记住密码");//把控件按照顺序加入到jp2jp2.add(jp2_jpl1);jp2.add(jp2_jtf);jp2.add(jp2_jb1);jp2.add(jp2_jpl2);jp2.add(jp2_jpf);jp2.add(jp2_jpl3);jp2.add(jp2_jcb1);jp2.add(jp2_jcb2);jp2.add(jp2_jpl4);//创建选项卡窗口,把三个JPanel放进去,最后把选项卡放进JFrame 中jtp=new JTabbedPane();jtp.add("QQ号码",jp2);jp3= new JPanel();jtp.add("手机号码",jp3);jp4=new JPanel();jtp.add("电子邮件",jp4);//处理南部的组件jp1 = new JPanel();jp1_jb1 = new JButton(new ImageIcon("image/dengru.png"));jp1_jb1.addActionListener(this);jp1_jb2 = new JButton(new ImageIcon("image/quxiao.png"));jp1_jb3=new JButton(new ImageIcon("image/xiangdao.png"));//把三个按钮放进jp1中jp1.add(jp1_jb1);jp1.add(jp1_jb2);jp1.add(jp1_jb3);//把定义好的组件放入到JFrame中this.add(jbl1,"North");//放入北部组件this.add(jp1, "South");//放入南部组件this.add(jtp, "Center");//放入中部组件//定义JFrame的一些属性this.setSize(350, 240);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setIconImage(newImageIcon("image/qq.png").getImage());this.setResizable(false);//不允许放大,改变窗口大小等this.setVisible(true);}@Overridepublic void actionPerformed(ActionEvent e) {//用户点击登录按钮if(e.getSource()==jp1_jb1) {User user =new User();user.setName(jp2_jtf.getText().trim());user.setPassWord(newString(jp2_jpf.getPassword()).trim());QqClientUser qqClientUser = new QqClientUser();//判断是否登录成功if(qqClientUser.checkUser(user)) {try {//把创建好友列表提前QqFriendList qqList = newQqFriendList(jp2_jtf.getText());ManageQqFriendList.addQqFriendList(user.getName(), qqList);//发送一个要求返回在线好友的请求包ObjectOutputStream oos = new ObjectOutputStream(ManageClientConServerThread.getClientConServerThread(user.getName()).client.getOutputSt ream());Message message = new Message();message.setSender(user.getName());message.setMesType(MessageType.message_get_onLineFriend);//发送oos.writeObject(message);} catch (Exception e1) {e1.printStackTrace();}this.dispose();} else {JOptionPane.showMessageDialog(this,"QQ号码或者密码错误");}}}}package com.qq.client.view;import javax.swing.*;import com.qq.client.tools.ManageQqChar;import mon.Message;import java.awt.*;import java.awt.event.*;/*** 我的好友列表(包括陌生人和黑名单)* */public class extends JFrame implements //第一张卡片信息(我的好友列表)JPanel jphy1;//总panelJPanel jphy2;//中部的panelJPanel jphy3;//南部的panel,放两个buttonJButton jphy_jb1;//我的好友按钮,防在总panel的北部JButton jphy_jb2;//陌生人按钮,放在jphy3中JButton jphy_jb3;//黑名单按钮,放在jphy3中JScrollPane jsp1;//中部的滚动的paneJLabel jbls[];//中部在线好友的列表//第二张卡片信息(陌生人列表)JPanel jpmsr1;//总panelJPanel jpmsr2;//中部的panelJPanel jpmsr3;//南部的panel,放两个buttonJButton jpmsr_jb1;//我的好友按钮,放在jpmsr3中JButton jpmsr_jb2;//陌生人按钮,放在jpmsr3中JButton jpmsr_jb3;//黑名单按钮,放在总的panel的南部JScrollPane jsp2;//中部的滚动的paneString userName;//把整个JFrame变成卡片布局CardLayout c1;public static void main(String[] args) {QqFriendList qqFriendList = new QqFriendList("1");}public QqFriendList(String userName) {erName = userName;//处理第一张卡片jphy_jb1 = new JButton("我的好友");jphy_jb2 = new JButton("陌生人");jphy_jb2.addActionListener(this);jphy_jb3 = new JButton("黑名单");jphy1 = new JPanel(new BorderLayout());//总的JPaneljphy2= new JPanel(new GridLayout(50,1,4,4));//中部的JPanel,假定有五十个好友//给jphy2这个panel中初始化50个好友jbls = new JLabel[50];for(int i=0; i<jbls.length; i++) {jbls[i] = new JLabel(i+1+"", newImageIcon("image/mm.png"), JLabel.LEFT);jbls[i].setEnabled(false);if(jbls[i].getText().equals(userName)) {jbls[i].setEnabled(true);}jbls[i].addMouseListener(this);jphy2.add(jbls[i]);}jphy3 = new JPanel(new GridLayout(2, 1));//把黑名单按钮和陌生人按钮加入到jpyh3中jphy3.add(jphy_jb2);jphy3.add(jphy_jb3);//把jphy2放入滚动的pane中jsp1 = new JScrollPane(jphy2);//把jphy_jb1,jsp1,jphy3分别放入jphy1中北,中,南三个位置jphy1.add(jphy_jb1,"North");jphy1.add(jsp1,"Center");jphy1.add(jphy3,"South");//处理第二张卡片jpmsr_jb1 = new JButton("我的好友");jpmsr_jb1.addActionListener(this);jpmsr_jb2 = new JButton("陌生人");jpmsr_jb3 = new JButton("黑名单");jpmsr1 = new JPanel(new BorderLayout());//总的JPaneljpmsr2 = new JPanel(new GridLayout(20,1,4,4));//中部的JPanel,假定有二十个陌生人//给jpmsr2这个panel中初始化20个陌生人JLabel jbls2[] = new JLabel[20];for(int i=0; i<jbls2.length; i++) {jbls2[i] = new JLabel(i+1+"", newImageIcon("image/mm.png"), JLabel.LEFT);jpmsr2.add(jbls2[i]);}jpmsr3 = new JPanel(new GridLayout(2, 1));//把我的好友按钮和陌生人按钮加入到jpmsr3中jpmsr3.add(jpmsr_jb1);jpmsr3.add(jpmsr_jb2);//把jpmsr1放入滚动的pane中jsp2 = new JScrollPane(jpmsr2);//把jpmsr3,jsp2,jpmsr_jb3分别放入jpmsr1中北,中,南三个位置jpmsr1.add(jpmsr3,"North");jpmsr1.add(jsp2,"Center");jpmsr1.add(jpmsr_jb3,"South");//把卡片放入JFrame中c1 = new CardLayout();this.setLayout(c1);this.add(jphy1, "1");this.add(jpmsr1, "2");//在窗口显示自己的namethis.setTitle(userName);this.setSize(170, 450);this.setVisible(true);}//更新在线好友情况public void updateFriend(Message message) {String onLineFriend[] = message.getContext().split(" ");for(int i=0; i<onLineFriend.length; i++) {jbls[Integer.parseInt(onLineFriend[i])-1].setEnabled(true);}}@Overridepublic void mouseClicked(MouseEvent e) {//响应用户双击事件,并得到好友编号if(e.getClickCount() ==2) {String friendNo = ((JLabel)e.getSource()).getText();QqChar qqChar = new QqChar(userName,friendNo);//把新开的聊天窗口加入到管理聊天窗口的map中ManageQqChar.addQqChar(erName+" "+friendNo, qqChar);}}@Overridepublic void mousePressed(MouseEvent e) {}@Overridepublic void mouseReleased(MouseEvent e) {}@Overridepublic void mouseEntered(MouseEvent e) {//当鼠标移上去时,使好友头像变为红色JLabel j1 = (JLabel)e.getSource();j1.setForeground(Color.red);}@Overridepublic void mouseExited(MouseEvent e) { //当把鼠标移走时,恢复成黑色JLabel j1 = (JLabel)e.getSource();j1.setForeground(Color.black);}@Overridepublic void actionPerformed(ActionEvent e) { //如果点击了陌生人按钮,就显示第二张卡片if(e.getSource()==jphy_jb2) {c1.show(this.getContentPane(), "2");} else if(e.getSource()==jpmsr_jb1) {c1.show(this.getContentPane(), "1");}}}package mon;import java.io.Serializable;/*** 发送的消息的类* */public class implements Serializable{private int mesType;//服务器返回的信息包:1代表用户验证成功,2代表用户验证失败,3代表其他信息包;private String sender;//发送消息的人private String getter;//接收消息的人private String context;//发送的消息private String time;//发送的时间public int getMesType() {return mesType;}public void setMesType(int mesType) {this.mesType = mesType;}public String getSender() {return sender;}public void setSender(String sender) {this.sender = sender;}public String getGetter() {return getter;}public void setGetter(String getter) {this.getter = getter;}public String getContext() {return context;}public void setContext(String context) { this.context = context;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}}MessageType类:package mon;/*** 定义包的总类* */public interface MessageType {//表明登入成功的包int message_succeed = 1;//表明登入失败的包int message_login_fail = 2;//表明普通的包int message_common_mes = 3;//要求返回在线好友的包int message_get_onLineFriend = 4;//返回在线好友的包int message_ret_onLineFriend = 5; }package mon;import java.io.Serializable;/*** 用户类* */public class implements Serializable{ private String name;//用户名private String passWord;//密码public String getName() {return name;}public void setName(String name) { = name;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) { this.passWord = passWord;}}ManageClientThread类:package com.qq.server.model;import java.util.HashMap;import java.util.Iterator;import java.util.Map;/*** 这是一个管理服务器和客户端保持通讯的线程类* */public class ManageClientThread {public static Map map = new HashMap<String, SerConClientThread>();//向map中添加一个线程public static void addCilentThread(String userName, SerConClientThread sc) {map.put(userName, sc);}//根据userName取得一个线程public static SerConClientThread getCilentThread(String userName) {return (SerConClientThread) map.get(userName);}//返回当前在线的人的情况public static String getAllOnLineUser() {//使用迭代器完成Iterator it = map.keySet().iterator();String res = "";while(it.hasNext()) {res += it.next().toString() + " ";}return res;}}MyQqServer类:package com.qq.server.model;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .ServerSocket;import .Socket;import mon.Message;import er;/*** 这是QQ服务器** */public class MyQqServer {public ServerSocket server;public static void main(String[] args) {new MyQqServer();}public MyQqServer() {try {System.out.println("在9999服务器监听.....");server = new ServerSocket(9999);//阻塞,等待某个客户端来连接while(true){Socket client = server.accept();//读取从客户端发来的消息ObjectInputStream ois = newObjectInputStream(client.getInputStream());User user = (User)ois.readObject();System.out.println("姓名是==="+user.getName()+"===密码是---"+user.getPassWord()+"---");ObjectOutputStream oos = newObjectOutputStream(client.getOutputStream());Message message = new Message();//只要密码是123456都让它登录成功if(user.getPassWord().equals("123456")) {message.setMesType(1);oos.writeObject(message);//登入成功,开启一个线程SerConClientThread sc = new SerConClientThread(client);//把该线程加入到map中ManageClientThread.addCilentThread(user.getName(), sc);//启动线程sc.start();//通知其他在线用户sc.notifyOther(user.getName());} else {//登录不成功时message.setMesType(2);oos.writeObject(message);client.close();}}} catch (Exception e) {e.printStackTrace();}}}QqServerUser类由于没写东西,所以不用创建也可以。
仿QQ聊天软件MyQQ源代码教学北大青鸟完整版
// 小头像 sbFriends.View = SbView.SmallIcon;
总结及项目答辩
教员对项目完成情况作总结 学员以小组形式按要求答辩
Thank you
注册、登录功能
第二次集中编码 (4学时)
查找/添加好友、部分聊天功能
第三次集中编码 (4学时)
个人信息显示、完整聊天功能
第四次集中编码 (4学时)
个人信息修改、完善整个功能
项目答辩、总结(4学时)
搭建项目框架 提交小组计划
项目准备阶段:A任务
建库 建表
Users Friends FriendShipPolicy
建关系
项目准备阶段:B任务
建表
Star BloodType Messages MessageType
项目准备阶段:C任务
第一次集中编码:A任务
设计注册窗体界面 实现用户注册功能
第一次集中编码:B任务
设计登录后主窗体 显示好友列表
第一次集中编码:C任务
设计登录窗体 实现登录功能
第一次集中编码:难点分析
注册与登录 好友管理 消息管理 个人设置
需求分析——界面分析
需要的界面:
注册界面 登录界面 登录后的主界面 查找/添加好友界面 聊天界面 系统消息界面 个人设置界面 头像列表界面
需求分析——辅助类分析
需要添加的辅助类:
DBHelper类 UserHelper 类
MyQQ 聊天工具
小组分工
组员 B
// 判断选中行的第一个单元格是否有值 if (dgvBasicResult.SelectedRows[0].Cells[0] != null) { // … }
[精华](盗窟版qq)源代码
关于山寨QQ的java的源代码
Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaSE, JavaEE, JavaME)的总称。
Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。
在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。
文库里没有关于山寨QQ的java的源代码,只能看了视频整理自己写了,特免费分享。
文档说明:根据java教学视频《韩顺平.循序渐进学.java.从入门到精通》(第87~94讲)整理得源相关代码。
代码调试无误,下载后调试有误的可评论留言联系。
image中图片附录在源代码后面。
工程文件夹:
(源代码)
jp1.add(jb2);
this.add(jp1);
this.setSize(500, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setV isible(true);
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if(arg0.getSource()==jb1)
{
new MyQqServer();
}
}
}
Image文件夹中图片。
JAVA论文
合肥财经学院专科毕业论文用Java编写的山寨版QQ姓名:_______________专业:_______________班级:_______________指导老师:_______________2010年月日用java编写的山寨版QQ摘要随着互联网的快速发展,网络聊天工具已经作为一种重要的信息交流工具,受到越来越多的网民的青睐。
目前,出现了很多非常不错的聊天工具,其中应用比较广泛的有Netmeeting、腾讯QQ、MSN-Messager等等。
该系统开发主要包括一个网络聊天服务器程序和一个网络聊天客户程序两个方面。
前者通过Socket套接字建立服务器,服务器能读取、转发客户端发来信息,并能刷新用户列表。
后者通过与服务器建立连接,来进行客户端与客户端的信息交流。
其中用到了局域网通信机制的原理,通过直接继承Thread类等来建立多线程。
开发中利用了计算机网络编程的基本理论知识,如TCP/IP协议、客户端/服务器端模式(Client/Server模式)、网络编程的设计方法等。
在网络编程中对信息的读取、发送,是利用流来实现信息的交换,其中介绍了对实现一个系统的信息流的分析,包含了一些基本的软件工程的方法。
经过分析这些情况,该局域网聊天工具采用Eclipse为基本开发环境和java语言进行编写,首先可在短时间内建立系统应用原型,然后,对初始原型系统进行不断修正和改进,直到形成可行系统。
关键词: 局域网、聊天、java、eclipse目录第一节引言 (01)第二节绪论2.1 JAVA的网络功能与编程 (02)2.1.1 JAVA概述 (03)2.1.2 JAVA的特点 (04)2.1.3 JAVA语言在网络上的应用 (05)2.2 TCP/IP (06)2.3 Soceket的简介 (07)第三节规划设计3.1 课题来源 (08)3.2 需求分析 (09)第四节系统分析与设计方案4.1 聊天系统的总体设计要点 (10)4.2 聊天系统的设计步骤及功能模块规划 (11)4.3 功能模块结构图 (12)第五节系统设计环境与测试5.1 开发环境和工具 (13)5.2 硬件环境 (14)5.3 聊天系统的测试 (15)第六节毕业设计总结6.1 毕业设计总结和展望 (16)6.2 经验和感想 (17)参考文献 (18)致谢 (19)21世纪是一个变幻莫测的世纪,是一个催人奋进的时代,科学技术的飞速发展,知识更替日新月异。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
关于山寨QQ的java的源代码
Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaSE, JavaEE, JavaME)的总称。
Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。
在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前景。
文库里没有关于山寨QQ的java的源代码,只能看了视频整理自己写了,特免费分享。
文档说明:根据java教学视频《韩顺平.循序渐进学.java.从入门到精通》(第87~94讲)整理得源相关代码。
代码调试无误,下载后调试有误的可评论留言联系。
image中图片附录在源代码后面。
工程文件夹:
(源代码)
/**
* 这是客户端连接服务器的后台
*/
package com.qq.client.model;
import com.qq.client.tools.*;
import java.util.*;
import .*;
import java.io.*;
import mon.*;
public class QqClientConServer {
public Socket s;
//发送第一次请求
public boolean sendLoginInfoToServer(Object o)
{
boolean b=false;
try {
// System.out.println("kk");
s=new Socket("127.0.0.1",9988);
ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
oos.writeObject(o);
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
Message ms=(Message)ois.readObject();
//这里就是验证用户登录的地方
if(ms.getMesType().equals("1"))
{
jp1.add(jb2);
this.add(jp1);
this.setSize(500, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if(arg0.getSource()==jb1)
{
new MyQqServer();
}
}
}
Image文件夹中图片。