How to build a COM to Send and Receive Multi File by ATL
CodeWorrior April 24,2002.
Introduction
The COM can send and receive Multi file from Server .
The project code has been built with VC++ 6.0 SP5 / ATL3.0 and tested on Win2K Professional.
Getting started
1.Create an ATL Project by useing ATL COM AppWizard ,name it as what you want,
at the step 1 :choose Support MFC;
2.Insert New ATL object by menu/toolbar,select Control -->lite Control-->
names: short name-->TestThread
attributes: support ISupportErrorInfo
support Connection_Points
interface -->Dual
thread model -->Apartment
Misc: inVisible at runtime
then click ok;
3. At classview ,right click CTestThread select Add Method,
add three method and the .idl file can found code like following lines
interface ITestThread : IDispatch
{
[id(1), helpstring("MultiThread Download File From Server")] HRESULT DownFile([in]BSTR bstrString);
[id(2), helpstring("Show About")] HRESULT About();
[id(3), helpstring("method SendFile")] HRESULT SendFile([in]BSTR bstrstring,[in]BSTR bstrFileString);
}
4.In TestThread.cpp add following codes:
// TestThread.cpp : Implementation of CTestThread
#include "stdafx.h"
#include "ThreadTest.h"
#include "TestThread.h"
#include "AboutDlg.h"
/////////////////////////////////////////////////////////////////////////////
// CTestThread
////////////////////////////////////////////
//
// 全局
char* msg[10];
DWORD WINAPI ReceiveFile(LPVOID);
CSocket sockClient;
SOCKET_STREAM_FILE_INFO StreamFileInfo;
// 全局定义完毕
////////////////////////////////////////////
STDMETHODIMP CTestThread::DownFile(BSTR bstrString)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
///////////////////////////////////////////////////////////
//
// 负责文件的下载工作,消息字符串在这里需要处理
//
///////////////////////////////////////////////////////////
USES_CONVERSION;
//分解消息串,并发送给服务器。
LPTSTR lpMsg;
lpMsg = OLE2T(bstrString);
char* chMsgString;
chMsgString = lpMsg;
char* msg[10];
int i = 0;
char *Split;
Split=strtok(chMsgString,":");
strcpy(lpMsg,Split);
while(Split!=NULL)
{
Split=strtok(NULL,":");
if(Split!=NULL)
{
//MessageBox(Split,"TestSplitString",MB_OK);
i = i+1;
msg[i] = Split;
//AfxMessageBox(msg[i]);
}
}
AfxSocketInit(NULL);
sockClient.Create();
if(!sockClient.Connect(lpMsg,1028))
{
AfxMessageBox("Connect to server Fail!");
sockClient.Close();
return S_FALSE;
}
try
{
SOCKET_USERINFO UserInfo; //// msg[]次序可能需要变动
strcpy(UserInfo.UserName,msg[1]);
strcpy(UserInfo.Database,msg[2]);
strcpy(UserInfo.DocID,msg[3]);
strcpy(UserInfo.EditMode,msg[4]);
strcpy(UserInfo.DotName,msg[5]);
strcpy(UserInfo.MultiUser,msg[6]);
strcpy(UserInfo.AttID,msg[7]);
sockClient.Send(&UserInfo,sizeof(SOCKET_USERINFO));
//测试用代码
//HRESULT hr= sockClient.Receive(&StreamFileInfo,
// sizeof(SOCKET_STREAM_FILE_INFO));
//sockClient.Receive(&UserInfo,sizeof(SOCKET_USERINFO));
while(1)
{
HANDLE hThread;
DWORD dwThreadID;
hThread = CreateThread(NULL,0,ReceiveFile,0,0,&dwThreadID);
Sleep(5000);
::WaitForSingleObject(hThread,200);
CloseHandle(hThread);
try
{
if(sockClient.Receive((void*)m_szBuffer,4,0))
{
//////////////////////////////////////////
//
// 如果接收到信息,则比较,为"end"则结束while
// 循环,否则继续循环创建线程接收文件
//
//////////////////////////////////////////
strcpy(m_szFlag,"end");
if(m_szBuffer == m_szFlag)
{
break; //Receive Data =="end" ,Exit While Block
}
}
else
///////////////////////////////////////
//
// 如果没有接收到任何信息,退出循环
//
//////////////////////////////////////
break;
}
catch(...)
{
break; //while Catch Error ,break;
}
}
sockClient.Close();
}
catch( ... )
{
ATLTRACE(_T("Test"));
sockClient.Close();
return S_FALSE;
}
::SysFreeString(bstrString);
return S_OK;
}
DWORD WINAPI ReceiveFile(LPVOID p)
{
CoInitializeEx(0,COINIT_MULTITHREADED);
////////////////////////////
// 以下代码经过测试可以正常接受文件
//
sockClient.Receive(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));
///////////////////////////////////////////////////////////////
//
// 添加代码,判断接收到的文件名是否含有".JPG",有则设置你
// 保存目录为 "d:\imgtemp\" ,不是则保存为 "c:\info21\"
//
///////////////////////////////////////////////////////////////
::CreateDirectory(_T("C:\\Info21\\"),NULL);
::SetCurrentDirectory(_T("C:\\Info21\\")); //设置下载文件的目录
try
{
//AfxMessageBox(StreamFileInfo.szFileTitle);
CFile destFile(StreamFileInfo.szFileTitle ,//设置下载后的文件名
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
UINT dwRead = 0; //接收文件
while(dwRead<StreamFileInfo.nFileSizeLow)
{
byte* data = new byte[1024]; //1k blocks to the buffer
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);
SetFileAttributes(StreamFileInfo.szFileTitle,StreamFileInfo.dwFileAttributes);
destFile.Close(); // One File Receive over.
}
catch(...)
{
MessageBox(NULL,_T("Receive File Error!! And Socket Will DisConnect!!"),_T("Receive File"), MB_ICONINFORMATION|MB_OK);
sockClient.Close();
////AfxMessageBox("文件下载失败!");
return S_FALSE;
}
MessageBox(NULL,_T("File All Received Complete!!"),_T("Receive File"),MB_OK);
CoUninitialize();
return 0;
}
STDMETHODIMP CTestThread::About()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
///////////////////////////////////////////////////
//
// Show About
//
///////////////////////////////////////////////////
CAboutDlg dlg;
dlg.DoModal();
return S_OK;
}
STDMETHODIMP CTestThread::SendFile(BSTR bstrString ,BSTR bstrFileString)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
/////////////////////////////////////////////////////
// 发送文件到服务器
// 参数为 消息串(bstrString),文件路径(bstrFileString)
///////////////////////////////////////////////////////
USES_CONVERSION;
LPTSTR lpMsg;
lpMsg = OLE2T(bstrString);
char* chMsgString;
chMsgString = lpMsg;
char* msg[10];
int i = 0;
char *Split;
Split=strtok(chMsgString,":"); ////分解消息串
strcpy(lpMsg,Split);
while(Split!=NULL)
{
Split=strtok(NULL,":");
if(Split!=NULL)
{
//MessageBox(Split,"TestSplitString",MB_OK);
i = i+1;
msg[i] = Split;
//AfxMessageBox(msg[i]);
}
}
AfxSocketInit(NULL);
sockClient.Create();
if(!sockClient.Connect(lpMsg,1028))
{
AfxMessageBox("Connect to server Fail!");
sockClient.Close();
return S_FALSE;
}
SOCKET_USERINFO UserInfo; //// msg[]次序可能需要变动
////与服务器协定
strcpy(UserInfo.UserName,msg[1]);
strcpy(UserInfo.Database,msg[2]);
strcpy(UserInfo.DocID,msg[3]);
strcpy(UserInfo.EditMode,msg[4]);
strcpy(UserInfo.DotName,msg[5]);
strcpy(UserInfo.MultiUser,msg[6]);
strcpy(UserInfo.AttID,msg[7]);
sockClient.Send(&UserInfo,sizeof(SOCKET_USERINFO));
//::SetCurrentDirectory(bstrFileString);
Recurse(bstrFileString); //搜索指定目录下的文件并传送到服务器
sockClient.Close();
::SysFreeString(bstrString);
::SysFreeString(bstrFileString);
return S_OK;
}
void CTestThread::Recurse(BSTR FilePath)
{
USES_CONVERSION;
CFileFind finder;
BSTR pstr = FilePath;
//查找条件
CString strWildcard(pstr);
strWildcard += _T("\\*.*");
BOOL bWorking = finder.FindFile(strWildcard);
while (bWorking)
{
bWorking = finder.FindNextFile();
//
// 输出文件名
CString strFilename = finder.GetFilePath();
if(strFilename!= ".")
{
if(strFilename!="..")
{
SendFile(T2OLE(strFilename));
}
}
}
finder.Close();
::SysFreeString(FilePath);
}
HRESULT CTestThread::SendFile(BSTR DocFile)
{
USES_CONVERSION;
char* filename = OLE2T(DocFile);
CFile myFile;
if(!myFile.Open( filename ,/* conversion BSTR to char* */
CFile::modeRead | CFile::typeBinary))
{
//文件打开失败直接返回。在 " . " and " .. " 两个目录文件的情况下出现。
return 0;
}
SOCKET_STREAM_FILE_INFO StreamFileInfo;
WIN32_FIND_DATA FindFileData;
FindClose(FindFirstFile(myFile.GetFilePath(),&FindFileData));
memset(&StreamFileInfo,0,sizeof(SOCKET_STREAM_FILE_INFO));
strcpy(StreamFileInfo.szFileTitle,myFile.GetFileName());
StreamFileInfo.nFileSizeLow = FindFileData.nFileSizeLow;
sockClient.Send(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));
UINT dwRead=0;
while(dwRead<StreamFileInfo.nFileSizeLow)
{
byte* data = new byte[5120];
UINT dw=myFile.Read(data, 5120);
sockClient.Send(data, dw);
dwRead+=dw;
}
myFile.Close();
::SysFreeString(DocFile);
return S_OK;
}
for the About method ,you must add a dialog and named AboutDlg,ok.
User Define Struct must be add to TestThread.h file:
typedef struct _SOCKET_STREAM_FILE_INFO {
TCHAR szFileTitle[128];
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
} SOCKET_STREAM_FILE_INFO, * PSOCKET_STREAM_FILE_INFO;
typedef struct _SOCKET_USERINFO
{
TCHAR UserName[128];
TCHAR Database[128];
TCHAR DocID[256];
TCHAR AttID[256];
TCHAR DotName[128];
TCHAR MultiUser[128];
TCHAR EditMode[128];
TCHAR UserTime[128];
}SOCKET_USERINFO, * PSOCKET_USERINFO;
following two variable must be add to CTestThread class
char m_szBuffer[4];
char m_szFlag[4] ;
add #include "afxsock.h" to StdAfx.h file
Happy programming. :-)
Good Luck!!! Contract me ,please mail to : CodeWorrior@hotmail.com.
If you need Source Code ,Give me your e_mail address !!