📄 secretchatdlg.cpp
字号:
// SecretChatDlg.cpp : implementation file
//
#include "stdafx.h"
#include "SecretChat.h"
#include "SecretChatDlg.h"
#include "ClientSocket.h" /*客户机套接字头文件*/
#include "SecretChatDlg.h"
/*****需要下面的说明才能用播放声音函数*******/
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
/********************************************/
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
// CSecretChatDlg dialog
CSecretChatDlg::CSecretChatDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSecretChatDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSecretChatDlg)
m_message = _T("");
m_messageNote = _T("");
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hOnline = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hOffline = AfxGetApp()->LoadIcon(IDI_OFFLINE);
}
void CSecretChatDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSecretChatDlg)
DDX_Control(pDX, IDC_FRIENDNAME, m_friendNameStatic);
DDX_Control(pDX, IDC_USERNAME, m_userNameStatic);
DDX_Control(pDX, IDC_STATUSMESSAGES, m_statusMessages);
DDX_Control(pDX, IDC_MESSAGENOTE, m_messageNoteEdit);
DDX_Control(pDX, IDC_MESSAGE, m_messageEdit);
DDX_Text(pDX, IDC_MESSAGE, m_message);
DDX_Text(pDX, IDC_MESSAGENOTE, m_messageNote);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSecretChatDlg, CDialog)
//{{AFX_MSG_MAP(CSecretChatDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_GETIP, OnGetip)
ON_BN_CLICKED(IDC_NOTE, OnNote)
ON_BN_CLICKED(IDC_SEND, OnSend)
ON_BN_CLICKED(IDC_CONNECT_DISCONNECTION, OnConnectDisconnection)
ON_BN_CLICKED(IDC_SECRETKEY, OnSecretkey)
ON_BN_CLICKED(IDC_SETUP, OnSetup)
ON_BN_CLICKED(IDC_USERNAME, OnUsername)
ON_BN_CLICKED(IDC_FRIENDNAME, OnFriendname)
ON_BN_CLICKED(IDC_SENDFILE, OnSendfile)
ON_COMMAND(ID_TOP, OnTop)
ON_COMMAND(ID_SHOW, OnShow)
ON_COMMAND(ID_HIDE, OnHide)
ON_COMMAND(ID_EMAIL, OnEmail)
ON_COMMAND(ID_HOMEPAGE, OnHomepage)
ON_COMMAND(ID_HELP, OnHelp)
ON_COMMAND(ID_EXIT, OnExit)
ON_COMMAND(ID_JIAMI, OnJiami)
ON_COMMAND(ID_ABOUT, OnAbout)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_RUNHIDE, RunHide) //运行时隐藏窗口
ON_MESSAGE(MYWM_NOTIFYICON,OnMyIconNotify) //托盘事件函数
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSecretChatDlg message handlers
DWORD WINAPI send_thread(LPVOID param) //发送消息线程函数
{
CSecretChatDlg *pMain = (CSecretChatDlg *)param;
//加密
MessagePackage package;
package.n = pMain->m_message.GetLength(); //正文的长度
do
{
pMain->m_public_key_send.set_requires(true);
pMain->m_private_key_send.set_requires(true); //由于最后位是0,而m最后位不为0,它都是true
pMain->TextToMessagePackage(package, pMain->m_message); //将要发送的消息转化成消息包
/*//////////test(send-1.txt)///////////
用这四个测试终于找出了在Debug版没问题而在Release版中有
问题的原因了,就是Debug中requires初始化的值未非零而Release的确为零
CFile file;
file.Open(
"d:\\send-1.txt",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
char buf[256 + 12];
::MoveMemory(
buf, //目标
&package,//源内容
sizeof(MessageDollop) + 12);
file.Write(
buf + 12,
sizeof(MessageDollop)); //写入信息
file.Close();
/////////////////////*/
/*这里用来测试TextToMessagePackage有没有BUG,原来错误在下面
CFile file;
file.Open(
"d:\\send.txt",
CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary);
file.Write(
&package,
sizeof(MessageDollop) + 12); //写入信息
file.Close();
*/
pMain->m_private_key_send.decrypt(package); //用用户私有密钥签名
//★错在这里★签名后的数就不一定会小于另一个m了,所以就会有时对有说错
pMain->m_public_key_send.encrypt(package); //用好友公开密钥加密,这里是不能修改消息块的
/*这里可以测试第二次加密数的合格率,还挺高的放心吧
if(!pMain->m_public_key.requires)
{
MessageBox("不合格一次了","public_key::encrypt",MB_ICONSTOP);
}*/
}while(!pMain->m_public_key_send.get_requires() || !pMain->m_private_key_send.get_requires());
/*///////test(send-2.txt)/////////////
CFile file;
file.Open(
"d:\\send-2.txt",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
char buf[256 + 12];
::MoveMemory(
buf, //目标
&package,//源内容
sizeof(MessageDollop) + 12);
file.Write(
buf + 12,
sizeof(MessageDollop)); //写入信息
file.Close();
///////////////////*/
//发送消息包
int quotient, remainder;
quotient = (pMain->m_message.GetLength() * 2) / sizeof(MessageDollop);
remainder = (pMain->m_message.GetLength() * 2) % sizeof(MessageDollop);
quotient = remainder?++quotient:quotient;
pMain->SendData(package, 12 + quotient * sizeof(MessageDollop));
//发送消息提示信息和处理
pMain->send_or_receive_tip(TRUE);
pMain->m_send--; //完成一条消息的发送
return 0;
}
DWORD WINAPI receive_thread(LPVOID param) //发送消息线程函数
{
CSecretChatDlg * pMain = (CSecretChatDlg *)param;
//获取临界区的控制权(m_cs.LockCount会加1)?不一定所以出现了严重的错误
::EnterCriticalSection(&pMain->m_cs_receive);
/*//////test(receive-1.txt)////////////将特殊的数据写入文件在找BUG中很有用
CFile file;
file.Open(
"d:\\receive-1.txt",
CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary);
char buf[256 + 12];
::MoveMemory(
buf, //目标
&pMain->m_receive_message_package[0],//源内容
sizeof(MessageDollop) + 12);
file.Write(
buf + 12,
sizeof(MessageDollop)); //写入信息
file.Close();
/////////////////
pMain->m_private_key.requires = true;
pMain->m_public_key.requires = true;*/
pMain->m_private_key_receive.set_requires(true); //要设为1
pMain->m_public_key_receive.set_requires(true); //要设为1
pMain->m_private_key_receive.decrypt(pMain->m_receive_message_package[0]); //用用户私有密钥解密
pMain->m_public_key_receive.encrypt(pMain->m_receive_message_package[0]); //用好友公开密钥签名
/*//////////test(receive-2.txt)//////////
file.Open(
"d:\\receive-2.txt",
CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary);
::MoveMemory(
buf, //目标
&pMain->m_receive_message_package[0],//源内容
sizeof(MessageDollop) + 12);
file.Write(
buf + 12,
sizeof(MessageDollop)); //写入信息
file.Close();
////////////////////*/
/*这里用来测试MessagePackageToText有没有BUG
CFile file;
file.Open(
"d:\\receive.txt",
CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary);
file.Write(
&msg,
sizeof(MessageDollop) + 12); //写入信息
file.Close();
*/
pMain->MessagePackageToText(pMain->m_receive_message_package[0]); //将要接收的消息包转化成常规格式
//检验对方的签名
if(pMain->m_receive_digital_ID.IsDigitalID())
{
//如果所有消息块的ID不等于消息包的ID这就不是一条完整的消息,那一定通不过签名
if(!(pMain->m_receive_message_dollop_ID == pMain->m_receive_message_package_ID))
{
::MessageBox(
NULL,
"这不是一条完整的消息",
"密聊",
MB_ICONEXCLAMATION);
}
pMain->send_or_receive_tip(FALSE);
}
else
{
//告诉对方我还没识别这条消息的身份
pMain->m_receive_message_package[0].head = HEAD_DIGITAL_SIGNATURE;
pMain->m_receive_message_package[0].ID = HEAD_DIGITAL_SIGNATURE_NO;
pMain->SendData(pMain->m_receive_message_package[0], 12);
::MessageBox(
NULL,
"对方不是 " + pMain->GetFriendName() + " 好友或没有 "
+ pMain->GetUserName() + " 用户的公钥",
"接收失败身份不确认",
MB_ICONEXCLAMATION);
}
//回复是否收到消息
pMain->m_receive_message_package[0].head = HEAD_REVERT_TEXT;
pMain->m_receive_message_package[0].ID = NULL;
DWORD d1[4];
pMain->m_receive_message_dollop_ID.Store(d1);
::MoveMemory(
pMain->m_receive_message_package[0].data, //目标
d1, //源内容
16);
pMain->SendData(pMain->m_receive_message_package[0], 12 + 16);
if(AfxGetApp()->GetProfileInt("General", "ArriveShow", 0))
{ //显示消息窗口
if(AfxGetApp()->GetProfileInt("General", "Tray", 1))
{
if(pMain->IsWindowVisible())
{
pMain->ShowWindow( SW_SHOWNORMAL);
}
else
{
pMain->ShowWindow( SW_MINIMIZE);
pMain->ShowWindow( SW_SHOWNORMAL);
}
}
else
{
pMain->ShowWindow( SW_SHOWNORMAL);
}
}
//现在还有pMain->m_receive个消息包等待着,这里采用先进先出的方式处理
for(int i = 0;i < pMain->m_receive;i++)
{
::MoveMemory(
&pMain->m_receive_message_package[i], //目标
&pMain->m_receive_message_package[i + 1],//源内容
sizeof(MessagePackage));
}
//收到的消息数安全减1
::InterlockedDecrement(&pMain->m_receive);
//释放临界区(m_cs.LockCount会减1)?不一定所以刚才错了
::LeaveCriticalSection(&pMain->m_cs_receive);
return 0;
}
/*连接不能在线程了完成否则对方无法创建得到服务器套接字对象,
所以就发不了消息给客户机了
DWORD WINAPI connect_thread(LPVOID param) //连接线程的临界区,只需要一个线程就可以了
{
CSecretChatDlg * pMain = (CSecretChatDlg *)param;
::EnterCriticalSection(&pMain->m_cs_connect);
pMain->m_pSocket = new CClientSocket; //确定了指向那个套接字
pMain->m_pSocket->Create(); //创建套接字对象
pMain->m_statusMessages.SetWindowText("连接中...");
if( pMain->m_pSocket->Connect(pMain->m_IP, pMain->m_port) )
{
pMain->m_clientOrService = FALSE; //客户端
pMain->connect_succeed_update();
}
else
{
pMain->m_statusMessages.SetWindowText("连接失败!");
if(!AfxGetApp()->GetProfileInt("General", "LANStartup", 0))
{ //没有启动周期连接LAN,就要提示连接失败
pMain->PlayWaveSound(IDR_OFFLINE); //连接失败时的声音提示
}
//关闭套接字
pMain->CloseSocket();
}
::LeaveCriticalSection(&pMain->m_cs_connect);
return 0;
}*/
/*DWORD WINAPI zai_xian_biao_ji_thread(LPVOID param) //定时在线通知线程的临界区,只需要一个线程就可以了
{
CSecretChatDlg * pMain = (CSecretChatDlg *)param;
::EnterCriticalSection(&pMain->m_cs_zai_xian_biao_ji);
if(pMain->m_online)
{
//每隔30秒向对方发送一次在线通知
MessagePackage msg;
msg.head = HEAD_ZAIXIANBIAOJI;
pMain->SendData(msg, 12);
//当连续有6个30秒没收到对方的在线通知就断定对方不在断开了
pMain->m_zai_xian_biao_ji++; //在线标记计算器加一
if(pMain->m_zai_xian_biao_ji > 6)
{
pMain->Disconnection();
pMain->m_statusMessages.SetWindowText("对方意外的断开了连接!"); //已经断开服务器连接
}
}
::LeaveCriticalSection(&pMain->m_cs_zai_xian_biao_ji);
return 0;
}*/
typedef struct _SOCKET_STREAM_FILE_INFO {
TCHAR szFileTitle[128]; //文件的标题名
DWORD dwFileAttributes; //文件的属性
FILETIME ftCreationTime; //文件的创建时间
FILETIME ftLastAccessTime; //文件的最后访问时间
FILETIME ftLastWriteTime; //文件的最后修改时间
DWORD nFileSizeHigh; //文件大小的高位双字
DWORD nFileSizeLow; //文件大小的低位双字
DWORD dwReserved0; //保留,为0
DWORD dwReserved1; //保留,为0
} SOCKET_STREAM_FILE_INFO, * PSOCKET_STREAM_FILE_INFO;
DWORD WINAPI send_file_thread(LPVOID param) //发送文件线程
{ //需要参数发送的文件名
CSecretChatDlg * pMain = (CSecretChatDlg *)param;
CFile myFile;
if(!myFile.Open(pMain->m_send_file_name, CFile::modeRead | CFile::typeBinary))
{
//恢复现场
myFile.Close();
pMain->send_file_comeback_scene();
AfxMessageBox("文件不存在!",MB_OK | MB_ICONERROR);
return 0;
}
CSocket sockSrvr;
sockSrvr.Create(LISTEN_PORT + 5);
sockSrvr.Listen();
CSocket sockRecv;
sockSrvr.Accept(sockRecv);
SOCKET_STREAM_FILE_INFO StreamFileInfo;
WIN32_FIND_DATA FindFileData;
FindClose(FindFirstFile(pMain->m_send_file_name, &FindFileData));
memset(&StreamFileInfo, 0, sizeof(SOCKET_STREAM_FILE_INFO));
strcpy(StreamFileInfo.szFileTitle, myFile.GetFileTitle());
StreamFileInfo.dwFileAttributes = FindFileData.dwFileAttributes;
StreamFileInfo.ftCreationTime = FindFileData.ftCreationTime;
StreamFileInfo.ftLastAccessTime = FindFileData.ftLastAccessTime;
StreamFileInfo.ftLastWriteTime = FindFileData.ftLastWriteTime;
StreamFileInfo.nFileSizeHigh = FindFileData.nFileSizeHigh;
StreamFileInfo.nFileSizeLow = FindFileData.nFileSizeLow;
sockRecv.Send(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));
UINT dwRead=0;
while(dwRead < StreamFileInfo.nFileSizeLow)
{
if(!pMain->m_send_file)//m_send_file是中止标志
break;
//显示文件进度情况
CString str1;
int percentage;
percentage = (dwRead * 100) / StreamFileInfo.nFileSizeLow;
str1.Format(
"文件发送百分比 %i" ,
percentage);
str1 += "%";
pMain->SetWindowText(str1);
byte data[1024];
UINT dw = myFile.Read(data, 1024);
sockRecv.Send(data, dw);
dwRead += dw;
}
myFile.Close();
sockRecv.Close();
//恢复现场
pMain->send_file_comeback_scene();
AfxMessageBox("发送完毕!");
return 0;
}
DWORD WINAPI receive_file_thread(LPVOID param) //接收文件线程
{ //需要参数发送方IP地址,保持的文件名
CSecretChatDlg * pMain = (CSecretChatDlg *)param;
CSocket sockClient;
sockClient.Create();
if(!sockClient.Connect(pMain->GetFriendIP(), LISTEN_PORT + 5))
{ //恢复现场
pMain->send_file_comeback_scene();
//提示连接失败
MessagePackage msg;
msg.head = HEAD_SENDFILE;
msg.ID = HEAD_SENDFILE_STOP;
pMain->SendData(msg, 12);
AfxMessageBox("连接到对方机器失败!");
return 0;
}
SOCKET_STREAM_FILE_INFO StreamFileInfo;
sockClient.Receive(&StreamFileInfo, sizeof(SOCKET_STREAM_FILE_INFO));
CFile destFile(
pMain->m_receive_file_name,
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
UINT dwRead = 0;
while(dwRead < StreamFileInfo.nFileSizeLow)
{
if(!pMain->m_send_file)//m_send_file是中止标志
break;
//显示文件进度情况
CString str1;
int percentage;
percentage = (dwRead * 100) / StreamFileInfo.nFileSizeLow;
str1.Format(
"文件接收百分比 %i" ,
percentage);
str1 += "%";
pMain->SetWindowText(str1);
byte data[1024];
memset(data,0,1024);
UINT dw = sockClient.Receive(data, 1024);
destFile.Write(data, dw);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -