www.pudn.com > 密聊源程序.rar > SecretChatDlg.cpp
// SecretChatDlg.cpp : implementation file // #include "stdafx.h" #include "SecretChat.h" #include "SecretChatDlg.h" #include "ClientSocket.h" /*客户机套接字头文件*/ #include "SecretChatDlg.h" /*****需要下面的说明才能用播放声音函数*******/ #include#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); dwRead += dw; } SetFileTime((HANDLE)destFile.m_hFile,&StreamFileInfo.ftCreationTime, &StreamFileInfo.ftLastAccessTime,&StreamFileInfo.ftLastWriteTime); destFile.Close(); SetFileAttributes(StreamFileInfo.szFileTitle,StreamFileInfo.dwFileAttributes); sockClient.Close(); //询问打开文件,还是用递送消息吧,反正没事 if(pMain->m_send_file)//m_send_file是中止标志 pMain->PostMessage( WM_RUNHIDE,1,0); //恢复现场 pMain->send_file_comeback_scene(); //AfxMessageBox("接收完毕!"); return 0; } /* DWORD WINAPI send_file_thread(LPVOID param) //发送文件线程 { CSecretChatDlg * pMain = (CSecretChatDlg *)param; MessagePackage msg; msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_TEXT; msg.n = SENDFILESIZE; //::Sleep(100); //发送的太快就会出错 //把消息包分成若干块大小为SENDFILESIZE CFile file; if(!file.Open( pMain->m_send_file_name, CFile::modeRead | CFile::typeBinary)) { AfxMessageBox("发送的文件无法读取"); return 0; } file.Seek(pMain->m_send_file_seek_position, CFile::begin); file.Read(msg.data, SENDFILESIZE);//返回的是现在读写文件的位置 pMain->m_send_file_seek_position += SENDFILESIZE; pMain->SendData(msg, SENDFILESIZE + 12/消息包头部长度/); file.Close(); return 0; } DWORD WINAPI receive_file_thread(LPVOID param) //接收文件线程 { CSecretChatDlg * pMain = (CSecretChatDlg *)param; MessagePackage msg; msg = pMain->m_receive_file_buffer; CFile file; if(!file.Open( pMain->m_receive_file_name, CFile::modeWrite | CFile::typeBinary)) { AfxMessageBox("发送的文件无法读取"); return 0; } file.SeekToEnd(); //每次从尾部写入 file.Write(msg.data, msg.n); pMain->m_send_file_seek_position += msg.n; //已经接收文件的大小 if(file.GetLength() >= (unsigned int)pMain->m_send_file_length) { //这就表示接收完了文件 file.SetLength(pMain->m_send_file_length); file.Close(); //提示成功接收 msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_SUCCEED; pMain->SendData(msg, 12); //恢复现场 pMain->send_file_comeback_scene(); //询问打开文件,还是用递送消息吧,反正没事 pMain->PostMessage( WM_RUNHIDE,1,0); } else { file.Close(); //收到一个块后,就向对方确认之后再接收 msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_CONCENT; pMain->SendData(msg, 12); } return 0; }*/ /////////////////////////////////// //在任务栏状态区添加图标 BOOL MyTaskBarAddIcon(HWND hwnd,UINT uID,HICON hicon,LPSTR lpszTip) { BOOL res; NOTIFYICONDATA tnid; tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.hWnd = hwnd; tnid.uID = uID; tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; tnid.uCallbackMessage = MYWM_NOTIFYICON; tnid.hIcon = hicon; if (lpszTip) lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip)); else tnid.szTip[0] = '\0'; res = Shell_NotifyIcon(NIM_ADD,&tnid); if (hicon) DestroyIcon(hicon); return res; } //从任务栏状态区删除图标 BOOL MyTaskBarDeleteIcon( UINT uID,HWND hwnd) { BOOL res; NOTIFYICONDATA tnid; tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.hWnd = hwnd; tnid.uID = uID; res = Shell_NotifyIcon(NIM_DELETE, &tnid); return res; } ///////////////// //托盘图标事件 void CSecretChatDlg::OnMyIconNotify(WPARAM wParam/*uID*/,LPARAM lParam/*消息标识值*/) { switch( lParam) { case WM_LBUTTONDOWN: //点击图标 if (IsWindowVisible()) //如果窗口已打开,隐藏窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow(SW_HIDE); //隐藏动画 } else //否则,显示窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow( SW_SHOWNORMAL); //显示动画 } break; case WM_RBUTTONDOWN: //右击图标 //右击是为了弹出菜单 //要弹出菜单主菜单的属性必须要取消view as popup属性 CPoint point; GetCursorPos( &point); CMenu menu; VERIFY( menu.LoadMenu( IDR_ICONMENU)); CMenu * pMenu = menu.GetSubMenu(0); if(AfxGetApp()->GetProfileInt("General", "Top", 0)) { //总在前面标记 pMenu->CheckMenuItem( ID_TOP,MF_CHECKED | MF_BYCOMMAND); } //要显示窗口还是隐藏 if( IsWindowVisible()) { pMenu->DeleteMenu( ID_SHOW,MF_BYCOMMAND); } else { pMenu->DeleteMenu( ID_HIDE,MF_BYCOMMAND); } pMenu->TrackPopupMenu( 32,point.x,point.y,this); break; } } BOOL CSecretChatDlg::OnInitDialog() { CDialog::OnInitDialog(); //没有联机 m_online = FALSE; //窗口初始化显示和设置函数 InitializationWindow(); /*创建套接字,并在套接字上监听连接*/ m_socketListen.Create(LISTEN_PORT); m_bListen = m_socketListen.Listen(); //返回值可以判断是否监听成功,否则就已有实例在监听 //关闭服务器和客户机的套接字对象 m_pSocket = NULL; m_socketListen.m_pServiceSocket = NULL; //每隔30秒就向另一方发在线通知,还是不要这个在线通知了这样会减少一些错误吧 SetTimer(1003, 30000, NULL); //初始化CRITICAL_SECTION变量(m_cs.LockCount会等于-1)?不一定 ::InitializeCriticalSection(&m_cs_receive); //可以发送文件 m_send_file = FALSE; //测试部分 return TRUE; // return TRUE unless you set the focus to a control } void CSecretChatDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { //CAboutDlg dlgAbout; //dlgAbout.DoModal(); m_setupDlg.m_index = 4; m_setupDlg.DoModal(); } else if(nID == IDS_JIAMI) { HKEY hkey; char sz[MAX_PATH]; //缓冲区必须要和设置时的相同才能读到数据 DWORD dwtype, sl = MAX_PATH; ::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\文件密使\\Application", NULL, KEY_ALL_ACCESS, &hkey); ::RegQueryValueEx( hkey, "DirectoryName", NULL, &dwtype, (LPBYTE)sz, &sl); ::RegCloseKey(hkey); CString strJiaMi = sz; ::ShellExecute( NULL, "open", strJiaMi + "\\jiami.exe", "", "", SW_SHOW); } else if(nID == IDS_HELP) { ::ShellExecute( m_hWnd, "open", "http://www.wjmshome.com/SecretChat.htm", "", "", SW_SHOWNORMAL); } else if(nID == SC_MINIMIZE) { //利用这两个动作就可实现动画了 if(AfxGetApp()->GetProfileInt("General", "Tray", 1)) { ShowWindow( SW_MINIMIZE); ShowWindow(SW_HIDE); //隐藏动画 } else { ShowWindow( SW_MINIMIZE); } } CDialog::OnSysCommand(nID, lParam); } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CSecretChatDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } HCURSOR CSecretChatDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CSecretChatDlg::OnTimer(UINT nIDEvent) { if(nIDEvent == 1001) //只负责清除状态提示栏的信息 { m_statusMessages.SetWindowText(""); } //LAN启动周期性连接 else if(nIDEvent == 1002) { if(m_online) return; //只有在没有连接的情况下才,进行LAN周期性连接 m_IP = AfxGetApp()->GetProfileString("General", "LANIP"); m_port = LISTEN_PORT; if(!prevent_connect()) return; //防止自己连接自己 m_statusMessages.SetWindowText("连接中..."); /*连接不能在线程了完成否则对方无法创建得到服务器套接字对象, 所以就发不了消息给客户机了*/ if( (NULL != (m_pSocket = new CClientSocket)) //确定了指向那个套接字 && m_pSocket->Create() ) //创建套接字对象 { if(m_pSocket->Connect(m_IP, m_port) ) { m_clientOrService = FALSE; //客户端 connect_succeed_update(); } else { CloseSocket();//关闭套接字 } } /*非主线程进入得地址不能访问套接字对象 unsigned long nThreadID; ::CreateThread( NULL, 0, connect_thread, this, 0, &nThreadID);*/ } /************每隔30秒就向另一方发在线通知**********/ else if(nIDEvent == 1003) { if(m_online) { //每隔30秒向对方发送一次在线通知 MessagePackage msg; msg.head = HEAD_ZAIXIANBIAOJI; SendData(msg, 12); //当连续有6个30秒没收到对方的在线通知就断定对方不在断开了 m_zai_xian_biao_ji++; //在线标记计算器加一 if(m_zai_xian_biao_ji > 6) { if(!m_send_file) //发送文件时不要断开,因为可能由于发送文件使得消息无法发送出去,而产生了错误 { Disconnection(); m_statusMessages.SetWindowText("对方意外的断开了连接!"); //已经断开服务器连接 } } } /*unsigned long nThreadID; ::CreateThread( NULL, 0, zai_xian_biao_ji_thread, this, 0, &nThreadID);*/ } CDialog::OnTimer(nIDEvent); } void CSecretChatDlg::OnOK() { // TODO: Add extra validation here //CDialog::OnOK(); } void CSecretChatDlg::OnCancel() { //文件传送问答 if(m_send_file) { if(MessageBox( "是否要取消文件传送?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { //::TerminateThread( // m_send_file_thread_handle, // NO_ERROR); //结束线程 MessagePackage msg; msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_STOP; SendData(msg, 12); //恢复现场 send_file_comeback_scene(); } return; } if(m_online) //联机时或文件传送中的处理,要用户断开连接才能断开 { if(MessageBox( "连接中,是否关闭?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDNO) { return; } //只是告诉对方我已经关闭密聊 MessagePackage msg; msg.head = HEAD_DISCONNECTION; msg.ID = HEAD_DISCONNECTION_CLOSE; SendData(msg, 12); Disconnection(); } //清除 MyTaskBarDeleteIcon(101, m_hWnd); //从任务栏状态区删除图标 //保存窗口位置 if(IsWindowVisible() && !IsIconic()) { //要可见,没最小化 CRect rect; GetWindowRect(rect); //保存窗口位置 CString str; str.Format("%i,%i,%i,%i", rect.top, rect.bottom, rect.left, rect.right); AfxGetApp()->WriteProfileString("Window", "Position", str); } CDialog::OnCancel(); } void CSecretChatDlg::OnConnectDisconnection() //连接和断开 { //文件传送问答 if(m_send_file) { if(MessageBox( "是否要取消文件传送?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { //::TerminateThread( // m_send_file_thread_handle, // NO_ERROR); //结束线程 MessagePackage msg; msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_STOP; SendData(msg, 12); //恢复现场 send_file_comeback_scene(); } return; } if(m_online) //联机时的处理 { if( MessageBox( "是否要断开连接?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDNO) { return; } //向对方提示我断开连接 MessagePackage msg; msg.head = HEAD_DISCONNECTION; msg.ID = HEAD_DISCONNECTION_INFORM; SendData(msg, 12); Disconnection(); } else //没联机时的处理 { //连接之前必须要有一个私钥并且要有一个被选中 if(!ValidatePrivateKey()) return; if(Connect()) //建立连接 { //连接成功后,就要判断有没好友公钥 ValidatePublicKey(); } } } void CSecretChatDlg::OnGetip() //获得本机IP地址 { /********************************************************/ //IP-1 char szHostName[128]; //本机网络名 CString szIP; //本机IP地址 if( gethostname( szHostName, 128) == 0 ) { struct hostent *pHost; int i, j; pHost = gethostbyname(szHostName); for(i = 0;pHost != NULL && pHost->h_addr_list[i] != NULL;i++) { for(j = 0;j < pHost->h_length;j++ ) { CString addr; if(j > 0 ) szIP += "."; addr.Format("%u", (unsigned int)((unsigned char*) pHost->h_addr_list[i])[j]); szIP += addr; } } } CString IP_1 = szIP; //IP-2 char mane1[30]; ZeroMemory(mane1,sizeof(char)*30); gethostname(mane1,30); struct hostent *myhost; myhost = gethostbyname(mane1); char* myip = inet_ntoa(*((struct in_addr*)myhost->h_addr_list[0])); CString IP_2 = myip; //IP-3 WORD wVersionRequested; WSADATA wsaData; char name[255]; CString ip;PHOSTENT hostinfo; wVersionRequested = MAKEWORD( 2, 0 ); if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) { if( gethostname ( name, sizeof(name)) == 0) { if((hostinfo = gethostbyname(name)) != NULL) { ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); } } WSACleanup( ); } CString IP_3 = ip; //选择最短的IP地址 CString IP = IP_1; if(IP.GetLength() > IP_2.GetLength()) IP = IP_2; if(IP.GetLength() > IP_3.GetLength()) IP = IP_3; /*********************************************************/ CEdit *pIP = (CEdit *)GetDlgItem(IDC_STATUSMESSAGES); CString str = szHostName; str = "主机名:" + str + " IP地址:" + IP; pIP->SetWindowText(str); // pIP->SetWindowText("请用\"密聊\"进行联系,我的IP地址是:" + szIP); pIP->SetFocus(); pIP->SetSel(0, -1); } void CSecretChatDlg::OnNote() //密聊记录 { CFileFind find; CString fileName = m_appName + "\\user\\" + GetUserName() + "-" + GetFriendName() + ".txt"; if(!find.FindFile(fileName)) { MessageBox( "没有 " + fileName + " 记录文件", "密聊", MB_ICONEXCLAMATION); return; } ::ShellExecute( m_hWnd, "open", fileName, "", "", SW_SHOW); } void CSecretChatDlg::OnSend() //发送消息 { /*先关闭了Socket在发送数据会怎样? 当要很多时间长可以到发送或接收消息的线程调用了SendData函数时, 而Socket确被这时被关闭了,那么这样就产生了致命性的错误了, 不过如果强行的关闭这两个线程还可以的 CloseSocket(); MessagePackage msg; SendData(msg,12); */ //必须要设置私钥和公钥,没有连线的时候才 // if(!ValidatePrivateKey()) return; // if(!ValidatePublicKey()) return; //未连接不能发送消息 if(!m_online) { MessageBeep(MB_OK); m_statusMessages.SetWindowText("没有联机"); m_messageEdit.SetFocus(); return; } //消息没发送出去,就不能发第二条消息 if(m_send != 0) { MessageBeep(MB_OK); m_statusMessages.SetWindowText("正在发送消息,请稍等..."); return; } else { m_statusMessages.SetWindowText("消息发送中"); } //发送的消息不能太长 m_messageEdit.GetWindowText(m_message); int messageLength/*发送消息的长度*/ = m_message.GetLength(); if(messageLength == 0) { MessageBeep(MB_OK); m_statusMessages.SetWindowText("空的消息"); m_messageEdit.SetFocus(); return; } /* else if(messageLength > 1024 && messageLength <= DATA_LENGTH) { if(MessageBox( "较长的消息需要几分钟时间,\r\n是否继续发送?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDNO) { return; } }*/ else if(messageLength > DATA_LENGTH / 4)//当处理的长度MessagePackage时会出现异常错误 { MessageBox( "发送的消息不希望超过 1K", "密聊", MB_ICONEXCLAMATION); return; } //公钥和私钥如果相同就提示不安全 CString strUser = GetUserName(); strUser.MakeLower(); CString strFriend = GetFriendName(); strFriend.MakeLower(); if(strUser == strFriend) { if(MessageBox( "相同的私钥和公钥将失去通话安全,\r\n是否继续通话?", "密聊", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDNO) { m_setupDlg.m_index = 0; m_setupDlg.DoModal(); return; } } m_send++; //正在发送着一条消息 unsigned long nThreadID; ::CreateThread( NULL, 0, send_thread, this, 0, &nThreadID); } void CSecretChatDlg::Receive(MessagePackage &package) //接收到正文消息 { // int arithmometer(0); // while(!(ValidatePrivateKey() && ValidatePublicKey())) // {//必须要把私钥和公钥安装好了,才能开始接收消息 // if(arithmometer++ > 5) // break; // }; if(m_receive >= MESSAGE_COUNT - 1) { //告诉对方有消息没收到 package.head = HEAD_REVERT_TEXT; package.ID = 1;//1表示不能同时收不到这么多消息 SendData(package, 12); MessageBox( "正在同时接收的消息超过规定的限度", "拒绝接收", MB_ICONINFORMATION); return; } //m_cs.LockCount可以表示接收到的消息条数?不时m_receive才是 m_receive_message_package[/*收到的消息数安全加1*/ ::InterlockedIncrement(&m_receive)] = package; //为了把消息包传给线程 unsigned long nThreadID; ::CreateThread( NULL, 0, receive_thread, this, 0, &nThreadID); } void CSecretChatDlg::ReceiveRevert(MessagePackage &package) //接收到对方的回复 { if(package.ID == 1) { MessageBox( "你同时发送的消息超过规定的限度,对方有消息没收到", "拒绝接收", MB_ICONINFORMATION); return; } DWORD d1[4]; __DWORD128 b1; ::MoveMemory( d1, //目标 package.data, //源内容 16); b1.Load(d1); if(m_send_message_package_ID_find(b1))//在这里它是发送时设定的 { //n表示有多少位是不空闲的它小于32,因为32时就不能添加了 int n = get_bit_count(m_send_message_package_ID_index, 1); CString str; if(n == 0) { str = "成功发送消息 (对方确认收到所有消息)"; } else { str.Format( "成功发送消息 (有 %i 条消息未确认对方收到)", n); //这里不行可能由于会并行访问m_send_message_package_ID_index所引起的 //这是由于时间的等待关系,因为Debug版速度慢所以看不出来,在Release版中这里是并行处理的 }str = "成功发送消息"; m_statusMessages.SetWindowText(str); if(AfxGetApp()->GetProfileInt("General", "ArriveSound", 1)) { ::MessageBeep(MB_ICONASTERISK); } } } void CSecretChatDlg::InitializationWindow() //设定初始化窗口 { // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu, strJiaMi, strHelp; strAboutMenu.LoadString(IDS_ABOUTBOX); strJiaMi.LoadString(IDS_JIAMI); strHelp.LoadString(IDS_HELP); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); //分隔菜单 pSysMenu->AppendMenu(MF_STRING, IDS_JIAMI, strJiaMi); pSysMenu->AppendMenu(MF_STRING, IDS_HELP, strHelp); pSysMenu->AppendMenu(MF_SEPARATOR); //分隔菜单 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } pSysMenu->DeleteMenu(SC_MAXIMIZE,MF_BYCOMMAND); pSysMenu->DeleteMenu(SC_SIZE,MF_BYCOMMAND); //修改系统菜单 //pSysMenu->DeleteMenu(61728/*恢复菜单ID*/,MF_BYCOMMAND); } SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon //设置开始的窗口标题(连接还是未连接) SetWindowText("密聊 (未连接)"); //播撒随机数的种子,rand()才能生成随机数 srand((unsigned int)::GetTickCount()); //设置按钮样式 CString str = "连接"; m_connect.SubclassDlgItem(IDC_CONNECT_DISCONNECTION, this); m_connect.SetIcon(IDI_CONNECT); m_connect.SetTooltipText(&str); m_connect.SetBtnCursor(IDC_HAND); m_connect.SetActiveFgColor(RGB(255, 255, 255)); str = "通讯双方的密钥设置和密钥管理"; m_publickeymanager.SubclassDlgItem(IDC_SECRETKEY, this); m_publickeymanager.SetIcon(IDI_IDIOGRAPH); m_publickeymanager.SetTooltipText(&str); m_publickeymanager.SetBtnCursor(IDC_HAND); m_publickeymanager.SetActiveFgColor(RGB(255, 255, 255)); str = "获得本机的IP地址"; m_getIP.SubclassDlgItem(IDC_GETIP, this); m_getIP.SetIcon(IDI_IP); m_getIP.SetTooltipText(&str); m_getIP.SetBtnCursor(IDC_HAND); m_getIP.SetActiveFgColor(RGB(255, 255, 255)); str = "密聊记录"; m_note.SubclassDlgItem(IDC_NOTE, this); m_note.SetIcon(IDI_NOTE); m_note.SetTooltipText(&str); m_note.SetBtnCursor(IDC_HAND); m_note.SetActiveFgColor(RGB(255, 255, 255)); str = "退出"; m_exit.SubclassDlgItem(IDCANCEL, this); //启动星星管理器 m_exit.SetIcon(IDI_EXIT); m_exit.SetTooltipText(&str); m_exit.SetBtnCursor(IDC_HAND); m_exit.SetActiveFgColor(RGB(255, 255, 255)); str = "发送消息(Ctrl + Enter)"; m_send_button.SubclassDlgItem(IDC_SEND, this); //启动密聊 m_send_button.SetTooltipText(&str); m_send_button.SetBtnCursor(IDC_HAND); m_send_button.SetActiveFgColor(RGB(255, 255, 255)); str = "设置"; m_setup.SubclassDlgItem(IDC_SETUP, this); //启动密聊 m_setup.SetIcon(IDI_SETUP); m_setup.SetTooltipText(&str); m_setup.SetBtnCursor(IDC_HAND); m_setup.SetActiveFgColor(RGB(255, 255, 255)); str = "发送文件"; m_sendfile.SubclassDlgItem(IDC_SENDFILE, this); //启动密聊 m_sendfile.SetIcon(IDI_SENDFILE); m_sendfile.SetTooltipText(&str); m_sendfile.SetBtnCursor(IDC_HAND); m_sendfile.SetActiveFgColor(RGB(255, 255, 255)); //获得应用程序目录名 ::GetCurrentDirectory( MAX_PATH, m_appName.GetBuffer(MAX_PATH));//获取应用程序目录 m_appName.ReleaseBuffer(); //另一种获取应用程序目录名的有效方法 CString strApp = __argv[0]; int iApp = strApp.ReverseFind('\\'); CSecretKeyEdit temp; char cApp[MAX_PATH]; temp.CStringToChar(cApp, strApp, iApp); cApp[iApp] = 0; m_appName = cApp; //安装应该程序别名和注册现在的版本 set_app_alias("SecChat"); AfxGetApp()->WriteProfileString( "Application", "DirectoryName", m_appName); AfxGetApp()->WriteProfileInt( "Application", "Version", APPLICATION_VERSION); //新建friend和user文件夹 WIN32_FIND_DATA wfd; HANDLE hSearch; hSearch = ::FindFirstFile(m_appName + "\\" + "friend", &wfd); if(hSearch == INVALID_HANDLE_VALUE/*不存在*/) { ::CreateDirectory(m_appName + "\\" + "friend", NULL); } hSearch = ::FindFirstFile(m_appName + "\\" + "user", &wfd); if(hSearch == INVALID_HANDLE_VALUE/*不存在*/) { ::CreateDirectory(m_appName + "\\" + "user", NULL); } //设置工具提示 m_userNameStatic.SetLink(TRUE,FALSE); m_userNameStatic.SetTextColor(RGB(0,128,192)); m_userNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); m_friendNameStatic.SetLink(TRUE,FALSE); m_friendNameStatic.SetTextColor(RGB(255,128,128)); m_friendNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); EnableToolTips(TRUE); m_toolTip.Create(this); m_toolTip.Activate(TRUE); m_toolTip.AddTool( &m_userNameStatic, "查看用户的私钥信息"); m_toolTip.AddTool( &m_friendNameStatic, "查看好友的公钥信息"); //当启动时运行就要隐藏窗口 if(AfxGetApp()->GetProfileInt("General", "Startup", 0)) { GetWindowRect(m_rect); //默认为现在的位置 //保证不闪烁...绝对有效 SetWindowPos(&CWnd::wndNoTopMost, 0, 0,0, 0,SWP_HIDEWINDOW); ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); /*上面并没有隐藏窗口所以再用MoveWindow函数是就会显示窗口了, 应该在PostMessage中先用ShowWindow(SW_HIDE),再用MoveWindow(m_rect)*/ PostMessage( WM_RUNHIDE,0,0); } //显示帮助信息 CString strHelp; strHelp.LoadString(IDS_USEHELP); m_messageNoteEdit.SetWindowText(strHelp); //恢复窗口位置 CString str1; str1 = AfxGetApp()->GetProfileString("Window", "Position", ""); CRect saveRect/*保存窗口大小*/, nowRect/*现在窗口的大小*/; _stscanf(str1, "%i,%i,%i,%i", &saveRect.top, &saveRect.bottom, &saveRect.left, &saveRect.right); //必须判断是合格的矩形尺寸,否则不改变窗口的大小 GetWindowRect(&nowRect); if( (saveRect.bottom - saveRect.top == nowRect.bottom - nowRect.top) && (saveRect.right - saveRect.left == nowRect.right - nowRect.left) ) { //恢复窗口位置 MoveWindow(&saveRect); } MyUpdateData(); //根据注册表数据进行设置 } void CSecretChatDlg::PlayWaveSound(DWORD wave/*资源中的声音ID*/) //播放资源中的声音文件 { /*******播放资源中的.wav文件*******/ HRSRC hRsrc = ::FindResource( AfxGetResourceHandle(), MAKEINTRESOURCE(wave/*资源ID*/), "WAVE"/*要和资源中的文件夹名相同*/); HGLOBAL hglb = ::LoadResource( AfxGetResourceHandle(), hRsrc); ::sndPlaySound( (LPCTSTR)::LockResource(hglb), SND_MEMORY | SND_SYNC | SND_NODEFAULT); ::FreeResource(hglb); /**********************************/ } BOOL CSecretChatDlg::Disconnection() //断开连接 { if(!m_online) //联机时的处理 return TRUE; /*正在发送或接收消息时不能断开连接,否则会出现严重的错误提示 if(m_send != 0 || m_receive != -1) { MessageBox( "发送或接收消息时,请别断开连接", "密聊", MB_ICONEXCLAMATION); return FALSE; }*/ m_statusMessages.SetWindowText("已经断开连接"); //已经断开服务器连接 //断开连接成功后改变按钮的状态 CString str = "连接"; m_connect.SetIcon(IDI_CONNECT); m_connect.SetTooltipText(&str); m_connect.SetWindowText(str); /*这里有些逻辑错误,双方会造成循环发送HEAD_DISCONNECTION消息 MessagePackage msg; msg.head = HEAD_DISCONNECTION; SendData(msg, 12); */ m_online = FALSE; //提示断线 TrayIcon(); //设置状态区图标 SetWindowText("密聊 (未连接)"); //提示已连接还是未连接 //关闭套接字 CloseSocket();//断开了那还怎么发通知断线消息给对方呀? PlayWaveSound(IDR_OFFLINE); //断开时的声音提示 return TRUE; } BOOL CSecretChatDlg::Connect() //建立连接 { if(m_online) //没联机时的处理 return TRUE; if(m_connectDlg.DoModal() != IDOK) { return FALSE; } m_IP = m_connectDlg.m_IP; m_port = m_connectDlg.m_port; if(!prevent_connect()) return FALSE; //防止自己连接自己 m_statusMessages.SetWindowText("连接中..."); /*连接不能在线程了完成否则对方无法创建得到服务器套接字对象, 所以就发不了消息给客户机了*/ if( (NULL != (m_pSocket = new CClientSocket)) //确定了指向那个套接字 && m_pSocket->Create() ) //创建套接字对象 { if(m_pSocket->Connect(m_IP, m_port) ) { //成功连接的IP地址记入注册表中 AfxGetApp()->WriteProfileString("Connect", "IPHistory", m_IP); m_clientOrService = FALSE; //客户端 connect_succeed_update(); } else { CloseSocket();//关闭套接字 m_statusMessages.SetWindowText("连接失败!"); PlayWaveSound(IDR_OFFLINE); //连接失败时的声音提示 return FALSE; } } else { return FALSE; } /* unsigned long nThreadID; ::CreateThread( NULL, 0, connect_thread, this, 0, &nThreadID);*/ return TRUE; } int CSecretChatDlg::SendData(MessagePackage &msg, int n) //发送数据 { //断开连接就不能再发送消息了 if(!m_online) return 0; if(m_clientOrService) //服务器端 { m_socketListen.m_pServiceSocket->Send(&msg, n); //错误提示 CuoWuTiShi(); } else //客户机端 { m_pSocket->Send(&msg, n); //错误提示 CuoWuTiShi(); } return 0; } void CSecretChatDlg::WinHelp(DWORD dwData, UINT nCmd) //按下F1打开帮助文件 { ::ShellExecute( m_hWnd, "open", "http://www.wjmshome.com/SecretChat.htm", "", "", SW_SHOWNORMAL); //CDialog::WinHelp(dwData, nCmd); } void CSecretChatDlg::OnSecretkey() //通讯双方的密钥设置和密钥管理 { m_setupDlg.m_index = 0; if(m_setupDlg.DoModal() == IDOK) { } } void CSecretChatDlg::OnSetup() //常规设置 { m_setupDlg.m_index = 3; if(m_setupDlg.DoModal() == IDOK) { } } BOOL CSecretChatDlg::InstallPrivateKey(CString fileName/*安装的文件名*/) { if(fileName == "") { //当没说明安装的文件时,就安装默认的 fileName = m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey"); } CFile file; SecretKey secretKey; if(!file.Open( fileName, CFile::modeReadWrite | CFile::typeBinary)) return FALSE; if(file.GetLength() != sizeof(SecretKey)) return FALSE; file.SeekToBegin(); file.Read(&secretKey, sizeof(SecretKey)); file.Close(); if(secretKey.ID != SECRETKEY_ID) return FALSE; if(secretKey.privateOrPublic != SECRETKEY_PRIVATE) return FALSE; m_userNameStatic.SetWindowText(AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey")); m_userNameStatic.SetLink(TRUE,FALSE); m_userNameStatic.SetTextColor(RGB(0,128,192)); m_userNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); m_private_key_send.SK_to_vlong(secretKey.sk/*自己的私钥*/); m_private_key_receive.SK_to_vlong(secretKey.sk/*自己的私钥*/); return TRUE; } BOOL CSecretChatDlg::InstallPublicKey(CString fileName/*安装的文件名*/) { if(fileName == "") { //当没说明安装的文件时,就安装默认的 fileName = m_appName + "\\friend\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey"); } CFile file; SecretKey secretKey; if(!file.Open( fileName, CFile::modeReadWrite | CFile::typeBinary)) return FALSE; if(file.GetLength() != sizeof(SecretKey)) return FALSE; file.SeekToBegin(); file.Read(&secretKey, sizeof(SecretKey)); file.Close(); if(secretKey.ID != SECRETKEY_ID) return FALSE; if(secretKey.privateOrPublic != SECRETKEY_PUBLIC) return FALSE; m_friendNameStatic.SetWindowText(AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey")); m_friendNameStatic.SetLink(TRUE,FALSE); m_friendNameStatic.SetTextColor(RGB(255,128,128)); m_friendNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); m_public_key_send.PK_to_vlong(secretKey.pk/*对方的公钥*/); m_public_key_receive.PK_to_vlong(secretKey.pk/*对方的公钥*/); return TRUE; } BOOL CSecretChatDlg::MyUpdateData() //根据注册表数据进行设置 { //显示出私钥和公钥名 m_userNameStatic.SetWindowText( AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey")); m_friendNameStatic.SetWindowText( AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey")); m_userNameStatic.SetLink(TRUE,FALSE); m_userNameStatic.SetTextColor(RGB(0,128,192)); m_userNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); m_friendNameStatic.SetLink(TRUE,FALSE); m_friendNameStatic.SetTextColor(RGB(255,128,128)); m_friendNameStatic.SetLinkCursor(AfxGetApp()->LoadCursor( IDC_HAND)); //顶层窗口 if(AfxGetApp()->GetProfileInt("General", "Top", 0)) { ::SetWindowPos( GetSafeHwnd(), HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); } else { ::SetWindowPos( GetSafeHwnd(), HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); } //显示位置 TrayIcon(); //LAN启动周期性连接 if(AfxGetApp()->GetProfileInt("General", "LANStartup", 0)) { SetTimer(1002, 60000, NULL); //以60秒为周期连接LAN } else { KillTimer(1002); } //安装私钥和公钥 InstallPrivateKey(); InstallPublicKey(); return TRUE; } BOOL CSecretChatDlg::PreTranslateMessage(MSG* pMsg) { //快捷键 if( pMsg->message == WM_KEYDOWN) { BOOL bCtrl = ::GetKeyState( VK_CONTROL) & 0x8000; BOOL bShift = ::GetKeyState( VK_SHIFT) & 0x8000; BOOL bAlt = ::GetKeyState( VK_MENU) & 0x8000; switch( pMsg->wParam) { case VK_ESCAPE: //不能Esc就退出程序 if(AfxGetApp()->GetProfileInt("General", "Tray", 1)) { ShowWindow( SW_MINIMIZE); ShowWindow(SW_HIDE); //隐藏动画 } else { ShowWindow( SW_MINIMIZE); } return TRUE; //必须要立即返回 break; case VK_RETURN: if( bCtrl) { SendMessage( WM_COMMAND, IDC_SEND); return TRUE; } break; case 'J': if( bCtrl) { HKEY hkey; char sz[MAX_PATH]; //缓冲区必须要和设置时的相同才能读到数据 DWORD dwtype, sl = MAX_PATH; ::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\文件密使\\Application", NULL, KEY_ALL_ACCESS, &hkey); ::RegQueryValueEx( hkey, "DirectoryName", NULL, &dwtype, (LPBYTE)sz, &sl); ::RegCloseKey(hkey); CString strJiaMi = sz; ::ShellExecute( NULL, "open", strJiaMi + "\\jiami.exe", "", "", SW_SHOW); return TRUE; } break; } } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ m_toolTip.RelayEvent(pMsg); // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% return CDialog::PreTranslateMessage(pMsg); } void CSecretChatDlg::OnUsername() //查看用户的私钥信息 { CSecretKeyEdit secretKeyEditDlg; secretKeyEditDlg.m_select = SECRETKEY_PRIVATE; if(secretKeyEditDlg.validateSecretKey( m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey")) != SECRETKEY_PRIVATE) { MessageBox( "不是用户私钥文件", "密聊", MB_ICONINFORMATION); return; } secretKeyEditDlg.DoModal(); } void CSecretChatDlg::OnFriendname() //查看好友的公钥信息 { CSecretKeyEdit secretKeyEditDlg; secretKeyEditDlg.m_select = SECRETKEY_PUBLIC; if(secretKeyEditDlg.validateSecretKey( m_appName + "\\friend\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey")) != SECRETKEY_PUBLIC) { MessageBox( "不是好友公钥文件", "密聊", MB_ICONINFORMATION); return; } secretKeyEditDlg.DoModal(); } BOOL CSecretChatDlg::AskPublicKey() //请求获得连线好友的公钥文件 { if(m_online) { MessagePackage msg; msg.head = HEAD_CLAIM_PUBLIC_KEY; SendData(msg, sizeof(msg)); return TRUE; } else { MessageBox( "需要联机才能请求获得对方的公钥文件", "密聊", MB_ICONINFORMATION); return FALSE; } } BOOL CSecretChatDlg::ClaimPublicKey(MessagePackage &msg) //请求对方的公钥 { //生成公钥信息 SecretKey secretKey; CFile file; if(!file.Open( m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey"), CFile::modeReadWrite | CFile::typeBinary)) return FALSE; if(file.GetLength() != sizeof(SecretKey)) return FALSE; file.SeekToBegin(); file.Read(&secretKey, sizeof(SecretKey)); file.Close(); //清除私钥信息 char chTemp[2048 / 8]; for(int i = 0;i < (2048 / 8);i++) { chTemp[i] = 0; } ::MoveMemory( (char *)&secretKey.sk, //目标 chTemp, //源内容 2048 / 8); secretKey.privateOrPublic = SECRETKEY_PUBLIC;//公钥标记 msg.head = HEAD_REVERT_PUBLIC_KEY; //回复给对方 ::MoveMemory( msg.data, //目标 (char *)&secretKey, //源内容 sizeof(SecretKey)); //公钥文件信息包涵公钥文件名 SendData(msg, sizeof(msg)); return TRUE; } BOOL CSecretChatDlg::RevertPublicKey(MessagePackage &msg) //接收对方的公钥 { SecretKey secretKey; CSecretKeyEdit secretKeyEditDlg; CString fileName; CFile file; CFileFind find; ::MoveMemory( (char *)&secretKey, //目标 msg.data, //源内容 sizeof(SecretKey)); //公钥文件信息包涵公钥文件名 fileName = //密钥的文件全路径 m_appName + "\\friend\\" + secretKeyEditDlg.CharToCString(secretKey.userName, 32) + ".pk"; if(find.FindFile(fileName)) //文件存在 { MessageBox( "对方的公钥文件 " + secretKeyEditDlg.CharToCString(secretKey.userName, 32) + ".pk 已经存在", "密聊", MB_ICONEXCLAMATION); return FALSE; } //生成公钥文件 file.Open( fileName,//密钥的文件全路径 CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary); file.Write( &secretKey, sizeof(SecretKey)); //写入信息 file.Close(); //把注册表好友公钥文件名改成现在的连线好友 AfxGetApp()->WriteProfileString( "SecretKeySetup", "FriendPublicKey", secretKeyEditDlg.CharToCString(secretKey.userName, 32) + ".pk"); //提示成功 MessageBox( "已经获得公钥 " + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey"), "密聊", MB_ICONINFORMATION); MyUpdateData(); //更新设置 return TRUE; } BOOL CSecretChatDlg::ValidatePrivateKey() //验证私钥的设置情况 { //连接之情必须要有一个私钥并且要有一个被选中 WIN32_FIND_DATA wfd; HANDLE hSearch; //判断是否至少有一个私钥文件 hSearch = ::FindFirstFile( m_appName + "\\user\\*.sk" , &wfd); if(hSearch == INVALID_HANDLE_VALUE) { //没有私钥存在,就要提示生成新的密钥 MessageBox( "没有任何用户私钥文件,请先创建新的密钥", "密聊", MB_ICONINFORMATION); CSecretKeyEdit secretKeyEditDlg; secretKeyEditDlg.m_select = SELECT_CREATE; secretKeyEditDlg.DoModal(); return FALSE; //没有生成密钥将永远不能进行连接 } hSearch = ::FindFirstFile( m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey"), &wfd); if(hSearch == INVALID_HANDLE_VALUE) { //没有选择私钥,提示要选择 MessageBox( "通讯前必须选择用户私钥文件", "密聊", MB_ICONINFORMATION); m_setupDlg.m_index = 1; m_setupDlg.DoModal(); //选择私钥和公钥 return FALSE; //没有选中将永远不能进行连接 } //还有判断它是合格的私钥文件 CSecretKeyEdit secretKeyEditDlg; if(secretKeyEditDlg.validateSecretKey( m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey")) != SECRETKEY_PRIVATE) { MessageBox( AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey") + " 不是合格的私钥文件", "密聊", MB_ICONINFORMATION); m_setupDlg.m_index = 1; m_setupDlg.DoModal(); return FALSE; //不合格将永远不能进行连接 } if(!InstallPrivateKey()) //安装私钥文件 { MessageBox( "无法安装用户私钥文件", "密聊", MB_ICONINFORMATION); return FALSE; } return TRUE; } BOOL CSecretChatDlg::ValidatePublicKey() //验证公钥的设置情况 { WIN32_FIND_DATA wfd; HANDLE hSearch; //连接成功后,就要判断有没好友公钥 //判断是否至少有一个公钥文件 hSearch = ::FindFirstFile( m_appName + "\\friend\\*.pk" , &wfd); if(hSearch == INVALID_HANDLE_VALUE) { //没有公钥存在,就要提示请求获取新的公钥 if(MessageBox( "没有任何好友公钥文件,是否请求获取对方的公钥?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { //获取对方的公钥 AskPublicKey(); } return FALSE; } //查看公钥是否被选中 hSearch = ::FindFirstFile( m_appName + "\\friend\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey"), &wfd); if(hSearch == INVALID_HANDLE_VALUE) { //没有选择公钥,提示要选择和获取新的公钥 if(MessageBox( "请选择好友公钥文件或请求获取对方的公钥,\r\n是否请求获取对方的公钥?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { //获取对方的公钥 AskPublicKey(); } else { m_setupDlg.m_index = 2; m_setupDlg.DoModal(); } return FALSE; } //还有判断它是合格的公钥文件 CSecretKeyEdit secretKeyEditDlg; if(secretKeyEditDlg.validateSecretKey( m_appName + "\\friend\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey")) != SECRETKEY_PUBLIC) { MessageBox( AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey") + " 不是合格的公钥文件", "密聊", MB_ICONINFORMATION); m_setupDlg.m_index = 2; m_setupDlg.DoModal(); return FALSE; //不合格将永远不能进行连接 } if(!InstallPublicKey()) //安装公钥文件 { MessageBox( "无法安装好友公钥文件", "密聊", MB_ICONINFORMATION); return FALSE; } return TRUE; } LRESULT CSecretChatDlg::RunHide(WPARAM wParam,LPARAM lParam) //运行时隐藏窗口 { if(wParam == 0) { ShowWindow(SW_HIDE); //隐藏窗口 MoveWindow(m_rect); return 0; } if(wParam == 1)//询问打开接收到的文件 { if(MessageBox( "是否打开 " + m_receive_file_name + " 文件?", "密聊", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES) { ::ShellExecute( NULL, "open", m_receive_file_name, "", "", SW_SHOW); } return 0; } if(wParam == 2) { int arithmometer(0); while(!(ValidatePrivateKey() && ValidatePublicKey())) {//必须要把私钥和公钥安装好了,才能开始接收消息 if(arithmometer++ == 5) break; }; if(arithmometer != 5) { //向对方发送"你好!我们可以进行安全通话了。" } } return 0; } void CSecretChatDlg::TrayIcon() //设置状态区图标 { if(AfxGetApp()->GetProfileInt("General", "Tray", 1)) { //必须先删除图标才能用这种方法更改任务栏状态区图标 MyTaskBarDeleteIcon( 101, m_hWnd); if(m_online) { MyTaskBarAddIcon( m_hWnd, 101, m_hOnline, "文件密使 - 密聊(已连接)");//在任务栏状态区添加图标 } else { MyTaskBarAddIcon( m_hWnd, 101, m_hOffline, "文件密使 - 密聊(未连接)");//在任务栏状态区添加图标 } } else { MyTaskBarDeleteIcon( 101, m_hWnd); //从任务栏状态区删除图标 } } void CSecretChatDlg::TextToMessagePackage(MessagePackage &package, CString strm) //将明文strm转化成消息包 { MessageDollop *pDollop; __DWORD128 b1, b2; int quotient, remainder, i, j; CSecretKeyEdit secretKeyEditDlg; //只为了转换时间格式 char chm[DATA_LENGTH]; //明文 // package.n/*明文长度*/ = strm.GetLength(); secretKeyEditDlg.CStringToChar(chm, strm, package.n); quotient = (package.n * 2) / sizeof(MessageDollop); remainder = (package.n * 2) % sizeof(MessageDollop); if(remainder != 0) { quotient++; //多余的补零 for(i = package.n;i < (package.n + (int)sizeof(MessageDollop) / 2 - remainder);i++) { chm[i] = 0; } } pDollop = new MessageDollop[quotient]; //消息块是消息包的元素 //分配每条消息块和总消息包的ID b2.Nil(); for(i = 0;i < quotient;i++) { b1.RandCount(); //没有生成随机的数吗? b2 = b2 + b1; b1.Store(pDollop[i].messageDollop_ID/*每个消息块的ID*/); } /* for(int s = 0;s < 32;s++) { if(b2 == m_send_message_package_ID[s]) { //这里表示b1.RandCount()没有生成随机数 //TRACE("这里出错了"); AfxMessageBox("出现了相同的随机数了"); } }*/ //把它添加到发送消息ID数组中,可以等下查询 m_send_message_package_ID_add(b2/*这里b2变成了消息包的ID了*/); //获得当前的时间 CTime time = CTime::GetCurrentTime(); m_send_time = time.Format("%Y-%m-%d %H:%M:%S"); //写入数字标识 b1.DigitalID();//这里b1变成了数字标识了 for(i = 0;i < quotient;i++) { //把消息块合并成消息包 //必须为0,否则会无法进行加解密 pDollop[i].nil[0] = 0; //消息包ID b2.Store(pDollop[i].messagePackage_ID); //数字标识 b1.Store(pDollop[i].digital_ID); //发送时间 secretKeyEditDlg.CStringToChar( pDollop[i].time, m_send_time, 20); //获得正文内容 ::MoveMemory( pDollop[i].text, chm + i * sizeof(MessageDollop) / 2, sizeof(MessageDollop) / 2);//除2是因为只要得到正文信息 //设置随机数 srand((unsigned)::GetTickCount()); //播撒随机数的种子,rand()才能生成随机数 for(j = 0;j < 16;j++) { pDollop[i].randCount[j] = (char)(0x41+rand()%0xAF); //pDollop[j应该是i的这样会产生无法回复的错误].randCount[j] = (char)rand(); } //把信息存储到消息包中 ::MoveMemory( package.data + i * sizeof(MessageDollop),//目标 (char *)&pDollop[i], //源内容 sizeof(MessageDollop)); } //设置消息包的头信息 package.head = HEAD_TEXT; delete[] pDollop; } void CSecretChatDlg::MessagePackageToText(MessagePackage &package)//将消息包转化成明文 { MessageDollop *pDollop; __DWORD128 b1, b2; BOOL bMessagePackageID = TRUE; //只要有一个数字标识不合就永远不能给m_receive_digital_ID合 int quotient, remainder, i; CSecretKeyEdit secretKeyEditDlg; //只为了转换时间格式 quotient = (package.n * 2) / sizeof(MessageDollop); remainder = (package.n * 2) % sizeof(MessageDollop); quotient = remainder?++quotient:quotient;//quotient代表有几个消息块 pDollop = new MessageDollop[quotient]; //消息块是消息包的元素 m_receive_message_dollop_ID.Nil(); for(i = 0;i < quotient;i++) { //把消息包分成若干块 ::MoveMemory( (char *)&pDollop[i], //目标 package.data + i * sizeof(MessageDollop),//源内容 sizeof(MessageDollop)); //获得正文内容 ::MoveMemory( m_receive_text + i * sizeof(MessageDollop) / 2, pDollop[i].text, sizeof(MessageDollop) / 2);//除2是因为只要得到正文信息 //获得数字标识 if(bMessagePackageID) { b1.Load(pDollop[i].digital_ID); //对方签名的数字标识 b2.DigitalID(); if(!(b1 == b2))//只要有一个消息块不合,就不能使得m_messagePackageID合格 { bMessagePackageID = FALSE; } m_receive_digital_ID = b1; } //获得消息包的ID b1.Load(pDollop[i].messageDollop_ID/*每个消息块的ID*/); m_receive_message_dollop_ID = m_receive_message_dollop_ID + b1; } //获得整个消息包的ID m_receive_message_package_ID.Load(pDollop[0].messagePackage_ID/*消息包的ID*/); //获得消息发送的时间 m_receive_time = secretKeyEditDlg.CharToCString(pDollop[0].time, 20); //获取正文的长度 m_receive_text_length = package.n; delete[] pDollop; } CString CSecretChatDlg::GetUserName() //获得通信的用户名 { CString fileName = m_appName + "\\user\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "UserPrivateKey"); CFile file; SecretKey secretKey; if(!file.Open( fileName, CFile::modeReadWrite | CFile::typeBinary)) return ""; if(file.GetLength() != sizeof(SecretKey)) return ""; file.SeekToBegin(); file.Read(&secretKey, sizeof(SecretKey)); file.Close(); if(secretKey.ID != SECRETKEY_ID) return ""; if(secretKey.privateOrPublic != SECRETKEY_PRIVATE) return ""; return secretKey.userName; } CString CSecretChatDlg::GetFriendName() //获得通信的好友名 { CString fileName = m_appName + "\\friend\\" + AfxGetApp()->GetProfileString("SecretKeySetup", "FriendPublicKey"); CFile file; SecretKey secretKey; if(!file.Open( fileName, CFile::modeReadWrite | CFile::typeBinary)) return ""; if(file.GetLength() != sizeof(SecretKey)) return ""; file.SeekToBegin(); file.Read(&secretKey, sizeof(SecretKey)); file.Close(); if(secretKey.ID != SECRETKEY_ID) return ""; if(secretKey.privateOrPublic != SECRETKEY_PUBLIC) return ""; return secretKey.userName; } void CSecretChatDlg::send_or_receive_tip(BOOL sendOrReceive)//发送和收到消息提示信息和处理 { CString nowMessage; //现在获得的信息 CFileFind find; //查找文件用 CFile file; CString fileName; //消息记录文件名 if(sendOrReceive) { //发送 nowMessage = "(" + m_send_time + ")\t" + GetUserName() + "\r\n" + m_message + "\r\n"; m_messageNote += nowMessage; m_statusMessages.SetWindowText("发送消息"); m_messageNoteEdit.SetWindowText(m_messageNote); //将消息记录框滚动到最尾 m_messageNoteEdit.LineScroll(m_messageNoteEdit.GetLineCount()); m_messageEdit.SetWindowText(""); //焦点再回到消息输入框 m_messageEdit.SetFocus(); PlayWaveSound(IDR_MESSAGESEND); } else { CSecretKeyEdit secretKeyEditDlg; //只为了转换密文格式 nowMessage = "(" + m_receive_time + ")\t" + GetFriendName() + "\r\n" + secretKeyEditDlg.CharToCString(m_receive_text, m_receive_text_length) + "\r\n"; m_messageNote += nowMessage; m_statusMessages.SetWindowText("收到消息"); m_messageNoteEdit.SetWindowText(m_messageNote); //将消息记录框滚动到最尾 m_messageNoteEdit.LineScroll(m_messageNoteEdit.GetLineCount()); //焦点再回到消息输入框 m_messageEdit.SetFocus(); PlayWaveSound(IDR_MESSAGERECEIVE); } fileName = m_appName + "\\user\\" + GetUserName() + "-" + GetFriendName() + ".txt"; if(!find.FindFile(fileName)) { //没有记录文件就新建一个 if(!file.Open( fileName, CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary)) return; } else { if(!file.Open( fileName, CFile::modeReadWrite | CFile::typeBinary)) return; } file.SeekToEnd(); file.Write(nowMessage, nowMessage.GetLength()); file.Close(); } ///////////////位运算函数///////////// DWORD exponential(DWORD n/*幂级数*/, DWORD a/*底数*/)//求指数运算 { DWORD s = 1; for(DWORD i = 0;i < n;i++) { s *= a; } return s; } void bit_to_index(DWORD bit, DWORD &index, BOOL count) { //返回bit第一个位为count的索引 for(index = 0;index < 32;index++) { BOOL temp = bit & exponential(index); if(temp != 0) { //temp的值除了0和1还有其他的值,这里只能用0和1 temp = 1; } if( count == temp) { return; } } //index == 32时表示bit没有一个位是count的 } DWORD bit_to_index(DWORD bit, BOOL count) { //返回bit第一个位为count的索引 for(int i = 0;i < 32;i++) { BOOL temp = bit & exponential(i); if(temp != 0) { //temp的值除了0和1还有其他的值,这里只能用0和1 temp = 1; } if( count == temp) { return i; } } return i; //index == 32时表示bit没有一个位是count的 } int get_bit_count(DWORD bit, BOOL count) { //获得bit中有多少个位是count的值 int s = 0; for(int i = 0;i < 32;i++) { BOOL temp = bit & exponential(i); if(temp != 0) { //temp的值除了0和1还有其他的值,这里只能用0和1 temp = 1; } if( count == temp) { s += 1; } } return s; } BOOL get_bit(DWORD bit, DWORD index) { //获得bit中的index的值 return bit & exponential(index)?1:0; } void set_bit(DWORD &bit, DWORD index, BOOL count) { //设置bit中的index个位为count //0 <= index < 32 if(count) { bit |= exponential(index); } else { bit ^= exponential(index); } } //////////////////////// int CSecretChatDlg::m_send_message_package_ID_add(__DWORD128 &add) { int n; n = bit_to_index(m_send_message_package_ID_index, 0); //获得第一个为0的索引 if(n == 32) { //n==32表示没有空位添加,就要从0开始了 n = 0; m_send_message_package_ID_index = 0x00000000; } m_send_message_package_ID[n] = add; //添加到空的索引 //内容会在Debug窗口中显示 //TRACE("m_send_message_package_ID_index = %u\n", m_send_message_package_ID_index); set_bit(m_send_message_package_ID_index, n, 1); //这个位置使他变忙 //内容会在Debug窗口中显示 //TRACE("m_send_message_package_ID_index = %u\n", m_send_message_package_ID_index); return n; } int CSecretChatDlg::m_send_message_package_ID_find(__DWORD128 &find) { for(int i = 0;i < 32;i++) { //m_send_message_package_ID_index第i位必须要为1 if(m_send_message_package_ID[i] == find && get_bit(m_send_message_package_ID_index, i)) { m_send_message_package_ID[i].Nil(); set_bit(m_send_message_package_ID_index, i, 0); //这个位置使他变空闲 return TRUE; //找到了 } } return FALSE; //没找到 } int CSecretChatDlg::m_send_message_package_ID_del(__DWORD128 &del) { //m_send_message_package_ID_find有这个功能了 return 0; } void CSecretChatDlg::set_app_alias(CString app_alias) {//安装应用程序别名 HKEY hkey; app_alias = "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + app_alias + ".exe"; ::RegCreateKey( HKEY_LOCAL_MACHINE/*主键*/, app_alias, &hkey); //创建子键 ::RegSetValueEx( hkey, ""/*键值*/, 0, REG_SZ, (LPBYTE)__argv[0]/*键值的数据*/, MAX_PATH); //把sz的数据写入到记事本键值 ::RegCloseKey(hkey); //关闭 } void CSecretChatDlg::message_version(MessagePackage &msg) //双方通讯版本的处理 { m_friend_message_version = msg.ID; if(m_friend_message_version/*对方的版本号*/ < MESSAGE_VERSION) { //当对方的版本比自己低时处理 } else if(m_friend_message_version > MESSAGE_VERSION) { //对方有更高的版本 if(MessageBox( "对方有更新的版本,是否下载最新的版本?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { ::ShellExecute( NULL, "open", "http://www.wjmshome.com", "", "", SW_SHOWNORMAL); } } else { } } void CSecretChatDlg::signalled_friend_version() { //告知好友我这里的通讯版本号 //连接成功后向对方告知自己的版本号和一些其他信息 MessagePackage msg; msg.head = HEAD_VERSION; msg.ID = MESSAGE_VERSION; //自己的版本号 msg.n = 0; SendData(msg, 12); } void CSecretChatDlg::connect_succeed_update()//连接成功后显示更新 { m_statusMessages.SetWindowText("连接成功 " + GetFriendIP()); //连接服务器 //连接成功后改变按钮的状态 CString str = "断开"; m_connect.SetIcon(IDI_DISCONNECTION); m_connect.SetTooltipText(&str); m_connect.SetWindowText(str); m_online = TRUE; //提示在线 TrayIcon(); //设置状态区图标 SetWindowText("密聊 (已连接)"); //提示已连接还是未连接 PlayWaveSound(IDR_ONLINE); //联机时的声音提示 m_zai_xian_biao_ji = 0; //取消等待时间记录 //设置发送0条消息 m_send = 0; m_send_message_package_ID_index = 0x00000000; m_receive = -1; //正在接收的消息条数,应该在每次连接成功时设置 for(int i = 0;i < 32;i++) { m_send_message_package_ID[i].Nil(); } //连接成功后向对方告知自己的版本号和一些其他信息 signalled_friend_version(); //验证私钥和公钥 PostMessage( WM_RUNHIDE,2,0); //获取对方的IP地址,保持在连接对话中可以随时连接 m_connectDlg.m_IP = GetFriendIP(); MyUpdateData(); //更新设置 } void CSecretChatDlg::OnSendfile() //发送文件给对方 { if(m_send_file) { if(MessageBox( "是否要取消文件传送?", "密聊", MB_YESNO | MB_ICONQUESTION) == IDYES) { //::TerminateThread( // m_send_file_thread_handle, // NO_ERROR); //结束线程 MessagePackage msg; msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_STOP; SendData(msg, 12); //恢复现场 send_file_comeback_scene(); } return; } if(!m_online) { m_statusMessages.SetWindowText("未联机"); MessageBeep(MB_OK); return; } /*if(MESSAGE_VERSION > m_friend_message_version) { //在这里可以通知对方,要它更新最新的版本才能传送文件 msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_VERSION_UPDATE; SendData(msg, 12); m_statusMessages.SetWindowText("对方需要更新版本"); ::MessageBeep(MB_OK); return; }*/ CString str = "所有文件(*.*)|*.*|"; CFileDialog fileName( TRUE, 0, 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, str, this); if(fileName.DoModal() != 1) return; CFile file; if(!file.Open( fileName.GetFileName(), CFile::modeRead | CFile::typeBinary)) { file.Close(); MessageBox( "不能读文件", "密聊", MB_ICONEXCLAMATION); return; } m_send_file_length = file.GetLength(); m_send_file_name = file.GetFileName();//获取文件名 if(m_send_file_length == 0) { file.Close(); MessageBox( "文件长度为零", "密聊", MB_ICONEXCLAMATION); return; } if(m_send_file_length > 1024 * 1024 * 100) { file.Close(); MessageBox( "过大的文件", "密聊", MB_ICONEXCLAMATION); return; } //告诉对方我要发送文件的具体信息 MessagePackage msg; msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_ENQUIRY; msg.n = m_send_file_length; msg.data[m_send_file_name.GetLength()] = 0; CSecretKeyEdit temp; temp.CStringToChar( msg.data, m_send_file_name, m_send_file_name.GetLength()); SendData(msg, sizeof(MessagePackage)); m_send_file_name = file.GetFilePath(); //获得文件全路径 // m_send_file_seek_position = 0; //文件的读写位置 m_send_file = FALSE; //还没开始传送 } void CSecretChatDlg::receive_file(MessagePackage &msg) //接收文件或相关信息 { /*msg.ID对文件的操作,HEAD_SENDFILE_ENQUIRY询问是否接收文件,HEAD_SENDFILE_CONCENT接收, HEAD_SENDFILE_NO_CONCENT不接收,HEAD_SENDFILE_TEXT表示data为文件名n表示文件名长度, HEAD_SENDFILE_STOP中止发送或接收,HEAD_SENDFILE_SUCCEED表示成功,HEAD_SENDFILE_NO_SUCCEED表示失败... /msg.n表示文件的长度,或其他的定义 msg.data文件的内容,一次只发sizeof(MessagePackage) - 12*/ if(msg.ID == HEAD_SENDFILE_ENQUIRY) { //对方发来询问发送文件过来 CString str1, str2; str1 = msg.data, str2.Format( "收到文件 " + str1 + " 长度 %i 字节,是否接收?", msg.n); if(MessageBox( str2, "接收文件", MB_ICONQUESTION | MB_YESNO) == IDNO) { msg.ID = HEAD_SENDFILE_NO_CONCENT; SendData(msg, 12); return; } CString str = "所有文件(*.*)|*.*|"; CFileDialog fileName( FALSE, "", str1, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, str, this); if(fileName.DoModal() == 1) { m_receive_file_name = fileName.GetPathName(); m_send_file_length = msg.n; //新建文件 CFile file; if(!file.Open( m_receive_file_name, CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary)) { msg.ID = HEAD_SENDFILE_NO_CONCENT; SendData(msg, 12); file.Close(); return; } /*if(MESSAGE_VERSION > m_friend_message_version) { //在这里可以通知对方,要它更新最新的版本才能传送文件 msg.head = HEAD_SENDFILE; msg.ID = HEAD_SENDFILE_VERSION_UPDATE; SendData(msg, 12); m_statusMessages.SetWindowText("对方需要更新版本"); ::MessageBeep(MB_OK); return; }*/ // m_send_file_seek_position = 0; //虽然没有但把它用在白分率好 msg.ID = HEAD_SENDFILE_CONCENT; SendData(msg, 12); } else { msg.ID = HEAD_SENDFILE_NO_CONCENT; SendData(msg, 12); return; } } else if(msg.ID == HEAD_SENDFILE_CONCENT_RECEIVE) { //可以接收文件了 //::Sleep(3000); //改变现场 if(!m_send_file) { //改变现场 CString str = "取消接收"; m_sendfile.SetIcon(IDI_SENDSTOP); m_sendfile.SetTooltipText(&str); m_statusMessages.SetWindowText("接收文件中"); m_send_file = TRUE; //传送文件中 } //接收对方文件线程 unsigned long nThreadID; m_send_file_thread_handle = ::CreateThread( NULL, 0, receive_file_thread, this, 0, &nThreadID); } else if(msg.ID == HEAD_SENDFILE_CONCENT) { //改变现场 if(!m_send_file) { CString str = "取消发送"; m_sendfile.SetIcon(IDI_SENDSTOP); m_sendfile.SetTooltipText(&str); m_statusMessages.SetWindowText("发送文件中"); m_send_file = TRUE; //传送文件中 } //对方允许就发送文件线程 unsigned long nThreadID; m_send_file_thread_handle = ::CreateThread( NULL, 0, send_file_thread, this, 0, &nThreadID); //提示对方可以接收 msg.ID = HEAD_SENDFILE_CONCENT_RECEIVE; SendData(msg, 12); } else if(msg.ID ==HEAD_SENDFILE_NO_CONCENT ) { //对方不接收文件 MessageBox( "对方取消接收文件", "密聊", MB_ICONINFORMATION); return; } else if(msg.ID == HEAD_SENDFILE_STOP) { //中止文件发送或接收就要中止线程了 //::TerminateThread( // m_send_file_thread_handle, // NO_ERROR); //结束线程 //恢复现场 send_file_comeback_scene(); MessageBox( "对方已经停止文件传送或连接失败", "密聊", MB_ICONSTOP); } // else if(msg.ID == HEAD_SENDFILE_SUCCEED) // { //恢复现场 // send_file_comeback_scene(); // } // else if(msg.ID == HEAD_SENDFILE_NO_SUCCEED) // { //::TerminateThread( // m_send_file_thread_handle, // NO_ERROR); //结束线程 //恢复现场 // send_file_comeback_scene(); // } else if(msg.ID == HEAD_SENDFILE_VERSION_UPDATE) //文件传送版本处理,如果升级中有了改动就不能在这样处理的 { //低版本不知高版本要做什么事,而高版本可以知道低版本会要做什么事 if(MessageBox( "对方希望你更新版本,是否下载最新的版本?", "文件传送", MB_YESNO | MB_ICONQUESTION) == IDYES) { ::ShellExecute( NULL, "open", "http://www.wjmshome.com", "", "", SW_SHOWNORMAL); } } } void CSecretChatDlg::CloseSocket() { //关闭所以的套接字对象 if(NULL != m_pSocket) { delete m_pSocket; m_pSocket = NULL; } if(NULL != m_socketListen.m_pServiceSocket) { delete m_socketListen.m_pServiceSocket; m_socketListen.m_pServiceSocket = NULL; } } BOOL CSecretChatDlg::prevent_connect() //防止自己连接自己 { if(m_bListen) { //当已经监听端口后,就不能在连接本机的IP CString strIP; char szHostName[128]; //本机网络名 if(m_IP == "127.0.0.1") return FALSE; if( gethostname( szHostName, 128) == 0 ) { struct hostent *pHost; int i, j; pHost = gethostbyname(szHostName); for(i = 0;pHost != NULL && pHost->h_addr_list[i] != NULL;i++) { for(j = 0;j < pHost->h_length;j++ ) { CString addr; if(j > 0 ) strIP += "."; addr.Format("%u", (unsigned int)((unsigned char*) pHost->h_addr_list[i])[j]); strIP += addr; } } } if(m_IP == strIP) return FALSE; } return TRUE; } //状态区图标的响应事件 void CSecretChatDlg::OnTop() { BOOL bTop = AfxGetApp()->GetProfileInt("General", "Top", 0); bTop = !bTop; if(bTop) { ::SetWindowPos( GetSafeHwnd(),HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); } else { ::SetWindowPos( GetSafeHwnd(),HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); } AfxGetApp()->WriteProfileInt("General", "Top", bTop); } void CSecretChatDlg::OnShow() { if (IsWindowVisible()) //如果窗口已打开,隐藏窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow(SW_HIDE); //隐藏动画 } else //否则,显示窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow( SW_SHOWNORMAL); //显示动画 } } void CSecretChatDlg::OnHide() { if (IsWindowVisible()) //如果窗口已打开,隐藏窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow(SW_HIDE); //隐藏动画 } else //否则,显示窗口 { //利用这两个动作就可实现动画了 ShowWindow( SW_MINIMIZE); ShowWindow( SW_SHOWNORMAL); //显示动画 } } void CSecretChatDlg::OnEmail() { ::ShellExecute( m_hWnd, "open", "mailto:webmaster@wjmshome.com?subject=联系、问题或建议!&body=你好!%0A%0D%0A%0D 我下载了文件密使3.0版...%0a%0d", "", "", SW_SHOWNORMAL); } void CSecretChatDlg::OnHomepage() { ::ShellExecute( m_hWnd, "open", "http://www.wjmshome.com", "", "", SW_SHOWNORMAL); } void CSecretChatDlg::OnHelp() { ::ShellExecute( m_hWnd, "open", m_appName + "\\jimhelp.chm", "", "", SW_SHOW); } void CSecretChatDlg::OnExit() { SendMessage( WM_COMMAND, IDCANCEL); } void CSecretChatDlg::OnJiami() { HKEY hkey; char sz[MAX_PATH]; //缓冲区必须要和设置时的相同才能读到数据 DWORD dwtype, sl = MAX_PATH; ::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\文件密使\\Application", NULL, KEY_ALL_ACCESS, &hkey); ::RegQueryValueEx( hkey, "DirectoryName", NULL, &dwtype, (LPBYTE)sz, &sl); ::RegCloseKey(hkey); CString strJiaMi = sz; ::ShellExecute( NULL, "open", strJiaMi + "\\jiami.exe", "", "", SW_SHOW); } void CSecretChatDlg::OnAbout() { static sohw(true); if(sohw) { m_setupDlg.m_index = 4; sohw = false; m_setupDlg.DoModal(); sohw = !sohw; } } void CSecretChatDlg::send_file_comeback_scene() //回复发送文件或接收文件前的现场 { m_send_file = FALSE; //取消文件传送或接收状态 CString str = "发送文件"; m_sendfile.SetIcon(IDI_SENDFILE); m_sendfile.SetTooltipText(&str); m_statusMessages.SetWindowText("文件传送完成"); //设置开始的窗口标题(连接还是未连接) if(m_online) { SetWindowText("密聊 (已连接)"); } else { SetWindowText("密聊 (未连接)"); } ::MessageBeep(MB_OK); } BOOL CSecretChatDlg::CuoWuTiShi() { /* int errorCount = GetLastError(); LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCount,//WSAGetLastError() MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); //AfxMessageBox( (LPCTSTR)lpMsgBuf); CFileFind find; CString str = (LPCTSTR)lpMsgBuf; if(errorCount == 0) { return TRUE; } CFile file; if(!find.FindFile(m_appName + "\\error.txt")) { if(!file.Open( m_appName + "\\error.txt", CFile::modeCreate | CFile::modeReadWrite | CFile::typeBinary)) return FALSE; } else { if(!file.Open( m_appName + "\\error.txt", CFile::modeReadWrite | CFile::typeBinary)) return FALSE; } file.SeekToEnd(); file.Write( str, str.GetLength()); //写入信息 file.Close(); // Free the buffer. LocalFree( lpMsgBuf);*/ if(GetLastError() != 0) { m_statusMessages.SetWindowText("发送或接收出现了错误"); ::MessageBeep(MB_OK); return FALSE; } return TRUE; } void CSecretChatDlg::disconnection_message(MessagePackage &msg) //断线通知 { if(msg.ID == HEAD_DISCONNECTION_INFORM) //对方询问我是否允许他断开连接 { Disconnection(); //我也要断开连接了 } if(msg.ID == HEAD_DISCONNECTION_CLOSE) //对方关闭密聊 { Disconnection(); m_statusMessages.SetWindowText("对方已经关闭密聊"); } } CString CSecretChatDlg::GetFriendIP() //获得连接方的IP地址 { //获取对方的IP地址和端口号 CString friendIP; UINT port; if(m_clientOrService) //服务器端 { m_socketListen.m_pServiceSocket->GetPeerName(friendIP,port); } else //客户机端 { m_pSocket->GetPeerName(friendIP,port); } return friendIP; }