📄 secretchatdlg.cpp
字号:
//向对方提示我断开连接
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(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -