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; 
 
}