⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 secretchatdlg.cpp

📁 一个用RSA算法实现加密通信的聊天程序。
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		//向对方提示我断开连接
		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 + -