OSDN Git Service

Send email to multi person success and add CC and TO list
[tortoisegit/TortoiseGitJp.git] / src / Utils / HwSMTP.cpp
1 // HwSMTP.cpp: implementation of the CHwSMTP class.\r
2 //\r
3 //////////////////////////////////////////////////////////////////////\r
4 \r
5 #include "stdafx.h"\r
6 #include "afxstr.h"\r
7 #include "HwSMTP.h"\r
8 #include "CBase64.h"\r
9 #include "SpeedPostEmail.h"\r
10 #include "Windns.h"\r
11 #include <Afxmt.h>\r
12 \r
13 #ifdef _DEBUG\r
14 #undef THIS_FILE\r
15 static char THIS_FILE[]=__FILE__;\r
16 #define new DEBUG_NEW\r
17 #endif\r
18 \r
19 CPtrArray g_PtrAry_Threads;\r
20 ::CCriticalSection m_CSFor__g_PtrAry_Threads;\r
21 \r
22 class CEMailObject\r
23 {\r
24 public:\r
25         CEMailObject (\r
26                 LPCTSTR lpszSmtpSrvHost,\r
27                 LPCTSTR lpszUserName,\r
28                 LPCTSTR lpszPasswd,\r
29                 BOOL bMustAuth,\r
30                 LPCTSTR lpszAddrFrom,\r
31                 LPCTSTR lpszAddrTo,\r
32                 LPCTSTR lpszFromName,\r
33                 LPCTSTR lpszReceiverName,\r
34                 LPCTSTR lpszSubject,\r
35                 LPCTSTR lpszBody,\r
36                 LPCTSTR lpszCharSet,\r
37                 CStringArray *pStrAryAttach,\r
38                 LPCTSTR pStrAryCC,\r
39                 UINT nSmtpSrvPort,\r
40                 LPCTSTR pSender,\r
41                 LPCTSTR pToList\r
42                 )\r
43         {\r
44                 m_csSmtpSrvHost = GET_SAFE_STRING(lpszSmtpSrvHost);\r
45                 m_csUserName = GET_SAFE_STRING(lpszUserName);\r
46                 m_csPasswd = GET_SAFE_STRING(lpszPasswd);\r
47                 m_bMustAuth = bMustAuth;\r
48                 m_csAddrFrom = GET_SAFE_STRING(lpszAddrFrom);\r
49                 m_csAddrTo = GET_SAFE_STRING(lpszAddrTo);\r
50                 m_csFromName = GET_SAFE_STRING(lpszFromName);\r
51                 m_csReceiverName = GET_SAFE_STRING(lpszReceiverName);\r
52                 m_csSubject = GET_SAFE_STRING(lpszSubject);\r
53                 m_csBody = GET_SAFE_STRING(lpszBody);\r
54                 m_csCharSet = GET_SAFE_STRING(lpszCharSet);\r
55                 m_StrCC = GET_SAFE_STRING(pStrAryCC);\r
56                 m_csSender = GET_SAFE_STRING(pSender);\r
57                 m_csToList = GET_SAFE_STRING(pToList);\r
58 \r
59                 if ( pStrAryAttach )\r
60                         m_StrAryAttach.Append ( *pStrAryAttach );\r
61                 \r
62                 m_nSmtpSrvPort = nSmtpSrvPort;\r
63                 m_hThread = NULL;\r
64         }\r
65 \r
66 public:\r
67         CString m_csSmtpSrvHost;\r
68         CString m_csUserName;\r
69         CString m_csPasswd;\r
70         BOOL m_bMustAuth;\r
71         CString m_csAddrFrom;\r
72         CString m_csAddrTo;\r
73         CString m_csFromName;\r
74         CString m_csReceiverName;\r
75         CString m_csSubject;\r
76         CString m_csBody;\r
77         CString m_csCharSet;\r
78         CStringArray m_StrAryAttach;\r
79         CString m_StrCC;\r
80         UINT m_nSmtpSrvPort;\r
81         CString m_csSender;\r
82         CString m_csToList;\r
83 \r
84         HANDLE m_hThread;\r
85 };\r
86 \r
87 //////////////////////////////////////////////////////////////////////\r
88 // Construction/Destruction\r
89 //////////////////////////////////////////////////////////////////////\r
90 \r
91 CHwSMTP::CHwSMTP () :\r
92         m_bConnected ( FALSE ),\r
93         m_nSmtpSrvPort ( 25 ),\r
94         m_bMustAuth ( TRUE )\r
95 {\r
96         m_csMIMEContentType = _T( "multipart/mixed");\r
97         m_csPartBoundary = _T( "WC_MAIL_PaRt_BoUnDaRy_05151998" );\r
98         m_csNoMIMEText = _T( "This is a multi-part message in MIME format." );\r
99         //m_csCharSet = _T("\r\n\tcharset=\"iso-8859-1\"\r\n");\r
100 }\r
101 \r
102 CHwSMTP::~CHwSMTP()\r
103 {\r
104 }\r
105 \r
106 void CHwSMTP::GetNameAddress(CString &in, CString &name,CString &address)\r
107 {\r
108         int start,end;\r
109         start=in.Find(_T('<'));\r
110         end=in.Find(_T('>'));\r
111 \r
112         if(start >=0 && end >=0)\r
113         {\r
114                 name=in.Left(start);\r
115                 address=in.Mid(start+1,end-start-1);\r
116         }\r
117         else\r
118                 address=in;\r
119 }\r
120 \r
121 CString CHwSMTP::GetServerAddress(CString &email)\r
122 {\r
123         CString str;\r
124         int start,end;\r
125         \r
126         start = email.Find(_T("<"));\r
127         end = email.Find(_T(">"));\r
128 \r
129         if(start>=0 && end >=0)\r
130         {\r
131                 str=email.Mid(start+1,end-start-1);\r
132         }\r
133         else\r
134         {\r
135                 str=email;\r
136         }\r
137 \r
138         start = str.Find(_T('@'));\r
139         return str.Mid(start+1);\r
140 \r
141 }\r
142 \r
143 BOOL CHwSMTP::SendSpeedEmail\r
144                 (\r
145                         LPCTSTR lpszAddrFrom,\r
146                         LPCTSTR lpszAddrTo,\r
147                         LPCTSTR lpszSubject,\r
148                         LPCTSTR lpszBody,\r
149                         LPCTSTR lpszCharSet,                                            // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"\r
150                         CStringArray *pStrAryAttach,\r
151                         LPCTSTR pStrAryCC,\r
152                         UINT    nSmtpSrvPort,\r
153                         LPCTSTR pSend \r
154                 )\r
155 {\r
156 \r
157         BOOL ret=true;\r
158         CString To;\r
159         To += GET_SAFE_STRING(lpszAddrTo);\r
160         To += _T(";");\r
161         To += GET_SAFE_STRING(pStrAryCC);\r
162 \r
163         std::map<CString,std::vector<CString>> Address;\r
164 \r
165         int start = 0;\r
166         while( start >= 0 )\r
167         {\r
168                 CString one= To.Tokenize(_T(";"),start);\r
169                 one=one.Trim();\r
170                 if(one.IsEmpty())\r
171                         continue;\r
172                 \r
173                 CString addr;\r
174                 addr = GetServerAddress(one);\r
175                 if(addr.IsEmpty())\r
176                         continue;\r
177                 \r
178                 \r
179                 Address[addr].push_back(one);           \r
180 \r
181         }\r
182 \r
183         std::map<CString,std::vector<CString>>::iterator itr1  =  Address.begin();\r
184     for(  ;  itr1  !=  Address.end();  ++itr1 )\r
185     {\r
186         PDNS_RECORD pDnsRecord; \r
187 \r
188                 DnsQuery(itr1->first ,\r
189                                     DNS_TYPE_MX,DNS_QUERY_BYPASS_CACHE,\r
190                                             NULL,                   //Contains DNS server IP address.\r
191                         &pDnsRecord,                //Resource record that contains the response.\r
192                         NULL\r
193                                                 ); \r
194                 \r
195                 CString to;\r
196                 to.Empty();\r
197                 for(int i=0;i<itr1->second.size();i++)\r
198                 {\r
199                         to+=itr1->second[i];\r
200                         to+=_T(";");\r
201                 }\r
202                 if(to.IsEmpty())\r
203                         continue;\r
204 \r
205                 if(!SendEmail(pDnsRecord->Data.MX.pNameExchange,NULL,NULL,false,\r
206                                 lpszAddrFrom,to,lpszSubject,lpszBody,lpszCharSet,pStrAryAttach,pStrAryCC,\r
207                                 25,pSend,lpszAddrTo))\r
208                         ret = false;\r
209 \r
210                 //SendEmail(itr1.first,NULL,NULL,false,lpszAddrFrom,,lpszFromname);\r
211                 DnsRecordListFree(pDnsRecord,DnsFreeRecordList);\r
212     }   \r
213 \r
214         return ret;\r
215 }\r
216 BOOL CHwSMTP::SendEmail (\r
217                 LPCTSTR lpszSmtpSrvHost,\r
218                 LPCTSTR lpszUserName,\r
219                 LPCTSTR lpszPasswd,\r
220                 BOOL bMustAuth,\r
221                 LPCTSTR lpszAddrFrom,\r
222                 LPCTSTR lpszAddrTo,\r
223                 LPCTSTR lpszSubject,\r
224                 LPCTSTR lpszBody,\r
225                 LPCTSTR lpszCharSet,                                            // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"\r
226                 CStringArray *pStrAryAttach/*=NULL*/,\r
227                 LPCTSTR pStrAryCC/*=NULL*/,\r
228                 UINT nSmtpSrvPort,/*=25*/\r
229                 LPCTSTR pSender,\r
230                 LPCTSTR pToList\r
231                 )\r
232 {\r
233         TRACE ( _T("·¢ËÍÓʼþ£º%s,  %s\n"), lpszAddrTo, lpszBody );\r
234         m_StrAryAttach.RemoveAll();\r
235 \r
236         m_StrCC += GET_SAFE_STRING(pStrAryCC);\r
237 \r
238         m_csSmtpSrvHost = GET_SAFE_STRING ( lpszSmtpSrvHost );\r
239         if ( m_csSmtpSrvHost.GetLength() <= 0 )\r
240         {\r
241                 m_csLastError.Format ( _T("Parameter Error!") );\r
242                 return FALSE;\r
243         }\r
244         m_csUserName = GET_SAFE_STRING ( lpszUserName );\r
245         m_csPasswd = GET_SAFE_STRING ( lpszPasswd );\r
246         m_bMustAuth = bMustAuth;\r
247         if ( m_bMustAuth && m_csUserName.GetLength() <= 0 )\r
248         {\r
249                 m_csLastError.Format ( _T("Parameter Error!") );\r
250                 return FALSE;\r
251         }\r
252 \r
253         m_csAddrFrom = GET_SAFE_STRING ( lpszAddrFrom );\r
254         m_csAddrTo = GET_SAFE_STRING ( lpszAddrTo );\r
255 //      m_csFromName = GET_SAFE_STRING ( lpszFromName );\r
256 //      m_csReceiverName = GET_SAFE_STRING ( lpszReceiverName );\r
257         m_csSubject = GET_SAFE_STRING ( lpszSubject );\r
258         m_csBody = GET_SAFE_STRING ( lpszBody );\r
259         \r
260         this->m_csSender = GET_SAFE_STRING(pSender);\r
261         this->m_csToList = GET_SAFE_STRING(pToList);\r
262 \r
263         m_nSmtpSrvPort = nSmtpSrvPort;\r
264 \r
265         if ( lpszCharSet && lstrlen(lpszCharSet) > 0 )\r
266                 m_csCharSet.Format ( _T("\r\n\tcharset=\"%s\"\r\n"), lpszCharSet );\r
267 \r
268         if      (\r
269                         m_csAddrFrom.GetLength() <= 0 || m_csAddrTo.GetLength() <= 0 \r
270                 )\r
271         {\r
272                 m_csLastError.Format ( _T("Parameter Error!") );\r
273                 return FALSE;\r
274         }\r
275 \r
276         if ( pStrAryAttach )\r
277         {\r
278                 m_StrAryAttach.Append ( *pStrAryAttach );\r
279         }\r
280         if ( m_StrAryAttach.GetSize() < 1 )\r
281                 m_csMIMEContentType = _T( "text/plain");\r
282 \r
283         // ´´½¨Socket\r
284         m_SendSock.Close();\r
285         if ( !m_SendSock.Create () )\r
286         {\r
287                 m_csLastError.Format ( _T("Create socket failed!") );\r
288                 return FALSE;\r
289         }\r
290 \r
291         // Á¬½Óµ½·þÎñÆ÷\r
292         if ( !m_SendSock.Connect ( m_csSmtpSrvHost, m_nSmtpSrvPort ) )\r
293         {\r
294                 m_csLastError.Format ( _T("Connect to [ %s ] failed"), m_csSmtpSrvHost );\r
295                 TRACE ( _T("%d\n"), GetLastError() );\r
296                 return FALSE;\r
297         }\r
298         if ( !GetResponse( _T("220") ) ) return FALSE;\r
299 \r
300         m_bConnected = TRUE;\r
301         return SendEmail();\r
302 \r
303 }\r
304 \r
305 \r
306 BOOL CHwSMTP::GetResponse ( LPCTSTR lpszVerifyCode, int *pnCode/*=NULL*/)\r
307 {\r
308         if ( !lpszVerifyCode || lstrlen(lpszVerifyCode) < 1 )\r
309                 return FALSE;\r
310 \r
311         char szRecvBuf[1024] = {0};\r
312         int nRet = 0;\r
313         char szStatusCode[4] = {0};\r
314         nRet = m_SendSock.Receive ( szRecvBuf, sizeof(szRecvBuf) );\r
315         TRACE ( _T("Received : %s\r\n"), szRecvBuf );\r
316         if ( nRet <= 0 )\r
317         {\r
318                 m_csLastError.Format ( _T("Receive TCP data failed") );\r
319                 return FALSE;\r
320         }\r
321 //      TRACE ( _T("ÊÕµ½·þÎñÆ÷»ØÓ¦£º%s\n"), szRecvBuf );\r
322 \r
323         memcpy ( szStatusCode, szRecvBuf, 3 );\r
324         if ( pnCode ) (*pnCode) = atoi ( szStatusCode );\r
325 \r
326         if ( strcmp ( szStatusCode, CMultiByteString(lpszVerifyCode).GetBuffer() ) != 0 )\r
327         {\r
328                 m_csLastError.Format ( _T("Received invalid response  : %s"), GetCompatibleString(szRecvBuf,FALSE) );\r
329                 return FALSE;\r
330         }\r
331 \r
332         return TRUE;\r
333 }\r
334 BOOL CHwSMTP::SendBuffer(char *buff,int size)\r
335 {\r
336         if(size<0)\r
337                 size=strlen(buff);\r
338         if ( !m_bConnected )\r
339         {\r
340                 m_csLastError.Format ( _T("Didn't connect") );\r
341                 return FALSE;\r
342         }\r
343 \r
344         if ( m_SendSock.Send ( buff, size ) != size )\r
345         {\r
346                 m_csLastError.Format ( _T("Socket send data failed") );\r
347                 return FALSE;\r
348         }\r
349         \r
350         return TRUE;\r
351 }\r
352 // ÀûÓÃsocket·¢ËÍÊý¾Ý£¬Êý¾Ý³¤¶È²»Äܳ¬¹ý10M\r
353 BOOL CHwSMTP::Send(CString &str )\r
354 {\r
355         if ( !m_bConnected )\r
356         {\r
357                 m_csLastError.Format ( _T("Didn't connect") );\r
358                 return FALSE;\r
359         }\r
360 \r
361         CMultiByteString cbsData ( str );\r
362         \r
363         TRACE ( _T("Send : %s\r\n"), cbsData.GetBuffer() );\r
364         if ( m_SendSock.Send ( cbsData.GetBuffer(), cbsData.GetLength() ) != cbsData.GetLength() )\r
365         {\r
366                 m_csLastError.Format ( _T("Socket send data failed") );\r
367                 return FALSE;\r
368         }\r
369         \r
370         return TRUE;\r
371 }\r
372 \r
373 BOOL CHwSMTP::SendEmail()\r
374 {\r
375         BOOL bRet = TRUE;\r
376         char szLocalHostName[64] = {0};\r
377         gethostname ( (char*)szLocalHostName, sizeof(szLocalHostName) );\r
378 \r
379         // hello£¬ÎÕÊÖ\r
380         CString str;\r
381         str.Format(_T("HELO %s\r\n"), GetCompatibleString(szLocalHostName,FALSE));\r
382         if ( !Send (  str ))\r
383         {\r
384                 return FALSE;\r
385         }\r
386         if ( !GetResponse ( _T("250") ) )\r
387         {\r
388                 return FALSE;\r
389         }\r
390         // Éí·ÝÑéÖ¤\r
391         if ( m_bMustAuth && !auth() )\r
392         {\r
393                 return FALSE;\r
394         }\r
395         // ·¢ËÍÓʼþÍ·\r
396         if ( !SendHead() )\r
397         {\r
398                 return FALSE;\r
399         }\r
400         // ·¢ËÍÓʼþÖ÷Ìâ\r
401         if ( !SendSubject() )\r
402         {\r
403                 return FALSE;\r
404         }\r
405         // ·¢ËÍÓʼþÕýÎÄ\r
406         if ( !SendBody() )\r
407         {\r
408                 return FALSE;\r
409         }\r
410         // ·¢Ë͸½¼þ\r
411         if ( !SendAttach() )\r
412         {\r
413                 return FALSE;\r
414         }\r
415         // ½áÊøÓʼþÕýÎÄ\r
416         if ( !Send ( CString(_T(".\r\n") ) ) ) return FALSE;\r
417         if ( !GetResponse ( _T("250") ) )\r
418                 return FALSE;\r
419 \r
420         // Í˳ö·¢ËÍ\r
421         if ( HANDLE_IS_VALID(m_SendSock.m_hSocket) )\r
422                 Send ( CString(_T("QUIT\r\n")) );\r
423         m_bConnected = FALSE;\r
424 \r
425         return bRet;\r
426 }\r
427 \r
428 BOOL CHwSMTP::auth()\r
429 {\r
430         int nResponseCode = 0;\r
431         if ( !Send ( CString(_T("auth login\r\n")) ) ) return FALSE;\r
432         if ( !GetResponse ( _T("334"), &nResponseCode ) ) return FALSE;\r
433         if ( nResponseCode != 334 )     // ²»ÐèÒªÑéÖ¤Óû§ÃûºÍÃÜÂë\r
434                 return TRUE;\r
435         \r
436         CBase64 Base64Encode;\r
437         CMultiByteString cbsUserName ( m_csUserName ), cbsPasswd ( m_csPasswd );\r
438         CString csBase64_UserName = GetCompatibleString ( Base64Encode.Encode ( cbsUserName.GetBuffer(), cbsUserName.GetLength() ).GetBuffer(0), FALSE );\r
439         CString csBase64_Passwd = GetCompatibleString ( Base64Encode.Encode ( cbsPasswd.GetBuffer(), cbsPasswd.GetLength() ).GetBuffer(0), FALSE );\r
440 \r
441         CString str;\r
442         str.Format( _T("%s\r\n"), csBase64_UserName );\r
443         if ( !Send ( str ) ) \r
444                 return FALSE;\r
445 \r
446         if ( !GetResponse ( _T("334") ) )\r
447         {\r
448                 m_csLastError.Format ( _T("Authentication UserName failed") );\r
449                 return FALSE;\r
450         }\r
451         \r
452         str.Format(_T("%s\r\n"), csBase64_Passwd );\r
453         if ( !Send ( str ) ) \r
454                 return FALSE;\r
455 \r
456         if ( !GetResponse ( _T("235") ) )\r
457         {\r
458                 m_csLastError.Format ( _T("Authentication Password failed") );\r
459                 return FALSE;\r
460         }\r
461 \r
462         return TRUE;\r
463 }\r
464 \r
465 BOOL CHwSMTP::SendHead()\r
466 {\r
467         CString str;\r
468         CString name,addr;\r
469         GetNameAddress(m_csAddrFrom,name,addr);\r
470 \r
471         str.Format( _T("MAIL From: <%s>\r\n"), addr );\r
472         if ( !Send ( str  ) ) return FALSE;\r
473 \r
474         if ( !GetResponse ( _T("250") ) ) return FALSE;\r
475         \r
476         int start=0;\r
477         while(start>=0)\r
478         {\r
479                 CString one=m_csAddrTo.Tokenize(_T(";"),start);\r
480                 one=one.Trim();\r
481                 if(one.IsEmpty())\r
482                         continue;\r
483 \r
484                 \r
485                 GetNameAddress(one,name,addr);\r
486                 \r
487                 str.Format(_T("RCPT TO: <%s>\r\n"), addr );\r
488                 if ( !Send ( str ) ) return FALSE;\r
489                 if ( !GetResponse ( _T("250") ) ) return FALSE;\r
490         }\r
491 \r
492 #if 0\r
493         for ( int i=0; i<m_StrAryCC.GetSize(); i++ )\r
494         {\r
495                 str.Format(_T("RCPT TO: <%s>\r\n"), m_StrAryCC.GetAt(i)  );\r
496                 if ( !Send ( str ) ) return FALSE;\r
497                 if ( !GetResponse ( _T("250") ) ) return FALSE;\r
498         }\r
499 #endif\r
500 \r
501         if ( !Send ( CString(_T("DATA\r\n") ) ) ) return FALSE;\r
502         if ( !GetResponse ( CString(_T("354") )) ) return FALSE;        \r
503 \r
504         return TRUE;\r
505 }\r
506 \r
507 BOOL CHwSMTP::SendSubject()\r
508 {\r
509         CString csSubject;\r
510         csSubject += _T("Date: ");\r
511         COleDateTime tNow = COleDateTime::GetCurrentTime();\r
512         if ( tNow > 1 )\r
513         {\r
514                 csSubject += GetCompatibleString(FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z")).GetBuffer(0),FALSE);\r
515         }\r
516         csSubject += _T("\r\n");\r
517         csSubject += FormatString ( _T("From: %s\r\n"), this->m_csAddrFrom);\r
518         \r
519         csSubject += FormatString ( _T("CC: %s\r\n"), this->m_StrCC);\r
520         \r
521         if(m_csSender.IsEmpty())\r
522                 m_csSender =  this->m_csAddrFrom;\r
523         \r
524         csSubject += FormatString ( _T("Sender: %s\r\n"), this->m_csSender);\r
525         \r
526         if(this->m_csToList.IsEmpty())\r
527                 m_csToList = m_csReceiverName;\r
528         \r
529         csSubject += FormatString ( _T("To: %s\r\n"), this->m_csToList);\r
530 \r
531         CString m_csToList;\r
532 \r
533         csSubject += FormatString ( _T("Subject: %s\r\n"), m_csSubject );\r
534         csSubject += FormatString ( _T("X-Mailer: TortoiseGit\r\nMIME-Version: 1.0\r\nContent-Type: %s; %s boundary=%s\r\n\r\n") , \r
535                 m_csMIMEContentType, m_csCharSet, m_csPartBoundary );\r
536 \r
537         return Send ( csSubject );\r
538 }\r
539 \r
540 BOOL CHwSMTP::SendBody()\r
541 {\r
542         CString csBody, csTemp;\r
543 \r
544         if ( m_StrAryAttach.GetSize() > 0 )\r
545         {\r
546                 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );\r
547                 csBody += csTemp;\r
548                 \r
549                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
550                 csBody += csTemp;\r
551                 \r
552                 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: 7Bit\r\n\r\n"),\r
553                         m_csCharSet );\r
554                 csBody += csTemp;\r
555         }\r
556 \r
557         //csTemp.Format ( _T("%s\r\n"), m_csBody );\r
558         csBody += m_csBody;\r
559         csBody += _T("\r\n");\r
560 \r
561         return Send ( csBody );\r
562 }\r
563 \r
564 BOOL CHwSMTP::SendAttach()\r
565 {\r
566         int nCountAttach = (int)m_StrAryAttach.GetSize();\r
567         if ( nCountAttach < 1 ) return TRUE;\r
568 \r
569         for ( int i=0; i<nCountAttach; i++ )\r
570         {\r
571                 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )\r
572                         return FALSE;\r
573         }\r
574 \r
575         return TRUE;\r
576 }\r
577 \r
578 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)\r
579 {\r
580         ASSERT ( lpszFileName );\r
581         CString csAttach, csTemp;\r
582 \r
583         csTemp = lpszFileName;\r
584         CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );\r
585         csShortFileName.TrimLeft ( _T("\\") );\r
586 \r
587         csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
588         csAttach += csTemp;\r
589 \r
590         csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );\r
591         csAttach += csTemp;\r
592 \r
593         csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );\r
594         csAttach += csTemp;\r
595 \r
596         csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );\r
597         csAttach += csTemp;\r
598 \r
599         DWORD dwFileSize =  hwGetFileAttr(lpszFileName);\r
600         if ( dwFileSize > 5*1024*1024 )\r
601         {\r
602                 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );\r
603                 return FALSE;\r
604         }\r
605         char *pBuf = new char[dwFileSize+1];\r
606         if ( !pBuf ) \r
607         {\r
608                 ::AfxThrowMemoryException ();\r
609                 return FALSE;\r
610         }\r
611 \r
612         if(!Send ( csAttach ))\r
613                 return FALSE;\r
614 \r
615         CFile file;\r
616         CStringA filedata;\r
617         try\r
618         {\r
619                 if ( !file.Open ( lpszFileName, CFile::modeRead ) )\r
620                 {\r
621                         m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );\r
622                         return FALSE;\r
623                 }\r
624                 UINT nFileLen = file.Read ( pBuf, dwFileSize );\r
625                 CBase64 Base64Encode;\r
626                 filedata = Base64Encode.Encode ( pBuf, nFileLen );\r
627                 filedata += _T("\r\n\r\n");\r
628         }\r
629         catch ( CFileException e )\r
630         {\r
631                 e.Delete();\r
632                 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );\r
633                 delete[] pBuf;\r
634                 return FALSE;\r
635         }\r
636 \r
637         if(!SendBuffer( filedata.GetBuffer() ))\r
638                 return FALSE;\r
639 \r
640 \r
641         delete[] pBuf;\r
642         \r
643         return TRUE;\r
644         //return Send ( csAttach );\r
645 }\r
646 \r
647 CString CHwSMTP::GetLastErrorText()\r
648 {\r
649         return m_csLastError;\r
650 }\r
651 \r
652 \r
653 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )\r
654 {\r
655         CEMailObject *pEMailObject = (CEMailObject*)lpParameter;\r
656         ASSERT ( pEMailObject );\r
657 \r
658         CHwSMTP HwSMTP;\r
659         BOOL bRet = HwSMTP.SendEmail (\r
660                 pEMailObject->m_csSmtpSrvHost,\r
661                 pEMailObject->m_csUserName,\r
662                 pEMailObject->m_csPasswd,\r
663                 pEMailObject->m_bMustAuth,\r
664                 pEMailObject->m_csAddrFrom,\r
665                 pEMailObject->m_csAddrTo,\r
666                 pEMailObject->m_csSubject,\r
667                 pEMailObject->m_csBody,\r
668                 pEMailObject->m_csCharSet,\r
669                 &pEMailObject->m_StrAryAttach,\r
670                 pEMailObject->m_StrCC,\r
671                 pEMailObject->m_nSmtpSrvPort,\r
672                 pEMailObject->m_csSender\r
673                 );\r
674         if ( !bRet)\r
675         {\r
676 #ifdef _DEBUG\r
677                 CString csError = HwSMTP.GetLastErrorText ();\r
678                 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );\r
679                 AfxMessageBox ( csError );\r
680 #endif\r
681         }\r
682 \r
683         m_CSFor__g_PtrAry_Threads.Lock ();\r
684         int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );\r
685         if ( nFindPos >= 0 )\r
686                 g_PtrAry_Threads.RemoveAt ( nFindPos );\r
687         m_CSFor__g_PtrAry_Threads.Unlock ();\r
688 \r
689         delete pEMailObject;\r
690         return bRet;\r
691 }\r
692 \r
693 //\r
694 // ÓàSMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷ÓàEndOfSMTP() º¯Êý\r
695 //\r
696 BOOL SendEmail (\r
697                                 BOOL bViaThreadSend,\r
698                                 LPCTSTR lpszSmtpSrvHost,\r
699                                 LPCTSTR lpszUserName,\r
700                                 LPCTSTR lpszPasswd,\r
701                                 BOOL bMustAuth,\r
702                                 LPCTSTR lpszAddrFrom,\r
703                                 LPCTSTR lpszAddrTo,\r
704                                 LPCTSTR lpszFromName,\r
705                                 LPCTSTR lpszReceiverName,\r
706                                 LPCTSTR lpszSubject,\r
707                                 LPCTSTR lpszBody,\r
708                                 LPCTSTR lpszCharSet/*=NULL*/,\r
709                                 CStringArray *pStrAryAttach/*=NULL*/,\r
710                                 LPCTSTR pStrAryCC/*=NULL*/,\r
711                                 UINT nSmtpSrvPort/*=25*/,\r
712                                 LPCTSTR lpszSender,\r
713                                 LPCTSTR lpszToList\r
714                                 )\r
715 {\r
716         if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||\r
717                 !lpszSubject || lstrlen(lpszSubject) < 1 ||\r
718                 !lpszBody || lstrlen(lpszBody) < 1 )\r
719         {\r
720                 AfxMessageBox ( _T("Parameter error !") );\r
721                 return FALSE;\r
722         }\r
723 \r
724         CEMailObject *pEMailObject = new CEMailObject (\r
725                 lpszSmtpSrvHost,\r
726                 lpszUserName,\r
727                 lpszPasswd,\r
728                 bMustAuth,\r
729                 lpszAddrFrom,\r
730                 lpszAddrTo,\r
731                 lpszFromName,\r
732                 lpszReceiverName,\r
733                 lpszSubject,\r
734                 lpszBody,\r
735                 lpszCharSet,\r
736                 pStrAryAttach,\r
737                 pStrAryCC,\r
738                 nSmtpSrvPort,\r
739                 lpszSender,\r
740                 lpszToList\r
741                 );\r
742         if ( !pEMailObject ) return FALSE;\r
743 \r
744         BOOL bRet = FALSE;\r
745         if ( bViaThreadSend )\r
746         {\r
747                 DWORD dwThreadId = 0;\r
748                 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );\r
749                 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);\r
750                 m_CSFor__g_PtrAry_Threads.Lock();\r
751                 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );\r
752                 m_CSFor__g_PtrAry_Threads.Unlock();\r
753                 ResumeThread ( pEMailObject->m_hThread );\r
754         }\r
755         else\r
756         {\r
757                 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );\r
758         }\r
759 \r
760         return bRet;\r
761 }\r
762 \r
763 void EndOfSMTP ()\r
764 {\r
765         // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï\r
766         for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )\r
767         {\r
768                 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);\r
769                 if ( HANDLE_IS_VALID(hThread) )\r
770                 {\r
771                         WaitForThreadEnd ( &hThread, 30*1000 );\r
772                 }\r
773         }\r
774         g_PtrAry_Threads.RemoveAll ();\r
775 }\r
776 \r
777 \r
778 //\r
779 // ½«×Ö·û´® lpszOrg ×ª»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ\r
780 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));\r
781 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );\r
782 //\r
783 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )\r
784 {\r
785         m_bNewBuffer = FALSE;\r
786         m_pszData = NULL;\r
787         m_nDataSize = 0;\r
788         m_nCharactersNumber = 0;\r
789         if ( !lpszOrg ) return;\r
790         \r
791         // ÅжÏԭʼ×Ö·û´®µÄ±àÂ뷽ʽ\r
792         BOOL bOrgIsUnicode = FALSE;\r
793         if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;\r
794         else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;\r
795         else\r
796         {\r
797 #ifdef UNICODE\r
798                 bOrgIsUnicode = TRUE;\r
799 #else\r
800                 bOrgIsUnicode = FALSE;\r
801 #endif\r
802         }\r
803         \r
804         // ¼ÆËã×Ö·û´®¸öÊýºÍÐèÒªµÄÄ¿±ê»º³å´óС\r
805         if ( bOrgIsUnicode )\r
806         {\r
807                 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);\r
808                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);\r
809         }\r
810         else\r
811         {\r
812                 m_nCharactersNumber = (int)strlen((char*)lpszOrg);\r
813                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);\r
814         }\r
815         \r
816         // Ê¹Óõ÷ÓÃÕß´«ÈëµÄ»º³å\r
817         if ( pOutBuf && nOutBufSize > 0 )\r
818         {\r
819                 m_pszData = pOutBuf;\r
820                 m_nDataSize = nOutBufSize;\r
821         }\r
822         // ×Ô¼ºÉêÇëÄڴ滺³å\r
823         else\r
824         {\r
825                 m_pszData = (char*)new BYTE[m_nDataSize];\r
826                 if ( !m_pszData )\r
827                 {\r
828                         ::AfxThrowMemoryException ();\r
829                         return;\r
830                 }\r
831                 m_bNewBuffer = TRUE;\r
832         }\r
833         memset ( m_pszData, 0, m_nDataSize );\r
834         \r
835         if ( bOrgIsUnicode )\r
836         {\r
837                 m_nCharactersNumber = WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize/sizeof(char)-1, NULL, NULL );\r
838                 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );\r
839         }\r
840         else\r
841         {\r
842                 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );\r
843                 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );\r
844                 m_nCharactersNumber = (int)strlen ( m_pszData );\r
845         }\r
846         m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);\r
847 }\r
848 \r
849 CMultiByteString::~CMultiByteString ()\r
850 {\r
851         if ( m_bNewBuffer && m_pszData )\r
852         {\r
853                 delete[] m_pszData;\r
854         }\r
855 }\r
856 \r
857 //\r
858 // ½« lpszOrg ×ª»»Îª¸Ã³ÌÐòʹÓõıàÂë×Ö·û´®£¬Èç¹û¸Ã³ÌÐòÊÇ UNICODE ¾ÍתΪ UNICODE£¬Èç¹ûÊÇ ANSI ¾ÍתΪ ANSI µÄ\r
859 //\r
860 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )\r
861 {\r
862         if ( !lpszOrg ) return _T("");\r
863         \r
864         TRY\r
865         {\r
866 #ifdef UNICODE\r
867                 if ( bOrgIsUnicode )\r
868                 {\r
869                         if ( nOrgLength > 0 )\r
870                         {\r
871                                 WCHAR *szRet = new WCHAR[nOrgLength+1];\r
872                                 if ( !szRet ) return _T("");\r
873                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );\r
874                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );\r
875                                 CString csRet = szRet;\r
876                                 delete[] szRet;\r
877                                 return csRet;\r
878                         }\r
879                         else if ( nOrgLength == 0 )\r
880                                 return _T("");\r
881                         else\r
882                                 return (LPCTSTR)lpszOrg;\r
883                 }\r
884                 \r
885                 if ( nOrgLength < 0 )\r
886                         nOrgLength = (int)strlen((const char*)lpszOrg);\r
887                 int nWideCount = nOrgLength + 1;\r
888                 WCHAR *wchar = new WCHAR[nWideCount];\r
889                 if ( !wchar ) return _T("");\r
890                 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );\r
891                 ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);\r
892                 CString csRet = wchar;\r
893                 delete[] wchar;\r
894                 return csRet;\r
895 #else\r
896                 if ( !bOrgIsUnicode )\r
897                 {\r
898                         if ( nOrgLength > 0 )\r
899                         {\r
900                                 char *szRet = new char[nOrgLength+1];\r
901                                 if ( !szRet ) return _T("");\r
902                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );\r
903                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );\r
904                                 CString csRet = szRet;\r
905                                 delete[] szRet;\r
906                                 return csRet;\r
907                         }\r
908                         else if ( nOrgLength == 0 )\r
909                                 return _T("");\r
910                         else\r
911                                 return (LPCTSTR)lpszOrg;\r
912                 }\r
913                 \r
914                 if ( nOrgLength < 0 )\r
915                         nOrgLength = (int)wcslen((WCHAR*)lpszOrg);\r
916                 int nMultiByteCount = nOrgLength + 1;\r
917                 char *szMultiByte = new char[nMultiByteCount];\r
918                 if ( !szMultiByte ) return _T("");\r
919                 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );\r
920                 ::WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL );\r
921                 CString csRet = szMultiByte;\r
922                 delete[] szMultiByte;\r
923                 return csRet;\r
924 #endif\r
925         }\r
926         CATCH_ALL(e)\r
927         {\r
928                 THROW_LAST ();\r
929         }\r
930         END_CATCH_ALL\r
931                 \r
932                 return _T("");\r
933 }\r
934 \r
935 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )\r
936 {       \r
937         // If null, return empty string\r
938         if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )\r
939                 return _T("");\r
940         \r
941         UDATE ud;\r
942         if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))\r
943         {\r
944                 return _T("");\r
945         }\r
946         \r
947         struct tm tmTemp;\r
948         tmTemp.tm_sec   = ud.st.wSecond;\r
949         tmTemp.tm_min   = ud.st.wMinute;\r
950         tmTemp.tm_hour  = ud.st.wHour;\r
951         tmTemp.tm_mday  = ud.st.wDay;\r
952         tmTemp.tm_mon   = ud.st.wMonth - 1;\r
953         tmTemp.tm_year  = ud.st.wYear - 1900;\r
954         tmTemp.tm_wday  = ud.st.wDayOfWeek;\r
955         tmTemp.tm_yday  = ud.wDayOfYear - 1;\r
956         tmTemp.tm_isdst = 0;\r
957         \r
958         CString strDate;\r
959         LPTSTR lpszTemp = strDate.GetBufferSetLength(256);\r
960         _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp);\r
961         strDate.ReleaseBuffer();\r
962         \r
963         return strDate;\r
964 }\r
965 \r
966 CString FormatString ( LPCTSTR lpszStr, ... )\r
967 {\r
968         TCHAR *buf = NULL;\r
969         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
970         for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )\r
971         {\r
972                 buf = new TCHAR[nBufCount];\r
973                 if ( !buf )\r
974                 {\r
975                         ::AfxThrowMemoryException ();\r
976                         return _T("");\r
977                 }\r
978                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
979                 \r
980                 va_list  va;\r
981                 va_start (va, lpszStr);\r
982                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);\r
983                 va_end(va);\r
984                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
985                         break;\r
986                 delete[] buf; buf = NULL;\r
987         }\r
988         if ( !buf )\r
989         {\r
990                 return _T("");\r
991         }\r
992         \r
993         CString csMsg = buf;\r
994         delete[] buf; buf = NULL;\r
995         return csMsg;\r
996 }\r
997 \r
998 /********************************************************************************\r
999 * Function Type :       Global\r
1000 * Parameter             :       lpFileName      -       Îļþ·¾¶\r
1001 * Return Value  :       -1                      -       Ê§°Ü\r
1002 *                                       >=0                     -       Îļþ´óС\r
1003 * Description   :       »ñÈ¡ÎļþÊôÐÔ ( Îļþ´óС¡¢´´½¨Ê±¼ä )\r
1004 *********************************************************************************/\r
1005 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )\r
1006 {\r
1007         if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;\r
1008         \r
1009         CFileStatus fileStatus;\r
1010         fileStatus.m_attribute = 0;\r
1011         fileStatus.m_size = 0;\r
1012         memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );\r
1013         BOOL bRet = FALSE;\r
1014         TRY\r
1015         {\r
1016                 if ( CFile::GetStatus(lpFileName,fileStatus) )\r
1017                 {\r
1018                         bRet = TRUE;\r
1019                 }\r
1020         }\r
1021         CATCH (CFileException, e)\r
1022         {\r
1023                 ASSERT ( FALSE );\r
1024                 bRet = FALSE;\r
1025         }\r
1026         CATCH_ALL(e)\r
1027         {\r
1028                 ASSERT ( FALSE );\r
1029                 bRet = FALSE;\r
1030         }\r
1031         END_CATCH_ALL;\r
1032         \r
1033         if ( pFileStatus )\r
1034         {\r
1035                 pFileStatus->m_ctime = fileStatus.m_ctime;\r
1036                 pFileStatus->m_mtime = fileStatus.m_mtime;\r
1037                 pFileStatus->m_atime = fileStatus.m_atime;\r
1038                 pFileStatus->m_size = fileStatus.m_size;\r
1039                 pFileStatus->m_attribute = fileStatus.m_attribute;\r
1040                 pFileStatus->_m_padding = fileStatus._m_padding;\r
1041                 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );\r
1042                 \r
1043         }\r
1044         \r
1045         return (int)fileStatus.m_size;\r
1046 }\r
1047 \r
1048 //\r
1049 // ½«Ò»¸ö±íʾ×Ö½ÚµÄÊýÓÿɶÁÐԺõÄ×Ö·û´®À´±íʾ£¬ÀýÈ罫 12345678 ×Ö½Úת»»Îª£º\r
1050 // 11.77M\r
1051 // nFlag        -       0 : ×Ô¶¯Æ¥Å䵥λ\r
1052 //                              1 : ÒÔ Kb Îªµ¥Î»\r
1053 //                              2 : ÒÔ Mb Îªµ¥Î»\r
1054 //                              3 : ÒÔ Gb Îªµ¥Î»\r
1055 // \r
1056 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )\r
1057 {\r
1058         CString csRes;\r
1059         if ( nFlag == 0 )\r
1060         {\r
1061                 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )\r
1062                         csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
1063                 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )\r
1064                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
1065                 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )\r
1066                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
1067                 else\r
1068                         csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );\r
1069         }\r
1070         else if ( nFlag == 1 )\r
1071         {\r
1072                 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
1073         }\r
1074         else if ( nFlag == 2 )\r
1075         {\r
1076                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
1077         }\r
1078         else if ( nFlag == 3 )\r
1079         {\r
1080                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
1081         }\r
1082         \r
1083         return csRes;\r
1084 }\r
1085 \r
1086 //\r
1087 // µÈ´ýÏß³ÌÍ˳ö\r
1088 //\r
1089 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )\r
1090 {\r
1091         BOOL bRet = TRUE;\r
1092         ASSERT ( phThread );\r
1093         if ( !(*phThread) ) return TRUE;\r
1094         if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )\r
1095         {\r
1096                 bRet = FALSE;\r
1097                 ::TerminateThread ( *phThread, 0 );\r
1098         }\r
1099         ::CloseHandle ( *phThread );\r
1100         (*phThread) = NULL;\r
1101         return bRet;\r
1102 }\r