OSDN Git Service

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