?? 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 + -