OSDN Git Service

Installer: Textual change
[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         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 = _T( "text/plain");\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 += GetCompatibleString(FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z")).GetBuffer(0),FALSE);\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         csSubject += FormatString ( _T("X-Mailer: TortoiseGit\r\nMIME-Version: 1.0\r\nContent-Type: %s; %s boundary=%s\r\n\r\n") , \r
550                 m_csMIMEContentType, m_csCharSet, m_csPartBoundary );\r
551 \r
552         return Send ( csSubject );\r
553 }\r
554 \r
555 BOOL CHwSMTP::SendBody()\r
556 {\r
557         CString csBody, csTemp;\r
558 \r
559         if ( m_StrAryAttach.GetSize() > 0 )\r
560         {\r
561                 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );\r
562                 csBody += csTemp;\r
563                 \r
564                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
565                 csBody += csTemp;\r
566                 \r
567                 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: 7Bit\r\n\r\n"),\r
568                         m_csCharSet );\r
569                 csBody += csTemp;\r
570         }\r
571 \r
572         //csTemp.Format ( _T("%s\r\n"), m_csBody );\r
573         csBody += m_csBody;\r
574         csBody += _T("\r\n");\r
575 \r
576         return Send ( csBody );\r
577 }\r
578 \r
579 BOOL CHwSMTP::SendAttach()\r
580 {\r
581         int nCountAttach = (int)m_StrAryAttach.GetSize();\r
582         if ( nCountAttach < 1 ) return TRUE;\r
583 \r
584         for ( int i=0; i<nCountAttach; i++ )\r
585         {\r
586                 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )\r
587                         return FALSE;\r
588         }\r
589 \r
590         return TRUE;\r
591 }\r
592 \r
593 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)\r
594 {\r
595         ASSERT ( lpszFileName );\r
596         CString csAttach, csTemp;\r
597 \r
598         csTemp = lpszFileName;\r
599         CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );\r
600         csShortFileName.TrimLeft ( _T("\\") );\r
601 \r
602         csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
603         csAttach += csTemp;\r
604 \r
605         csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );\r
606         csAttach += csTemp;\r
607 \r
608         csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );\r
609         csAttach += csTemp;\r
610 \r
611         csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );\r
612         csAttach += csTemp;\r
613 \r
614         DWORD dwFileSize =  hwGetFileAttr(lpszFileName);\r
615         if ( dwFileSize > 5*1024*1024 )\r
616         {\r
617                 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );\r
618                 return FALSE;\r
619         }\r
620         char *pBuf = new char[dwFileSize+1];\r
621         if ( !pBuf ) \r
622         {\r
623                 ::AfxThrowMemoryException ();\r
624                 return FALSE;\r
625         }\r
626 \r
627         if(!Send ( csAttach ))\r
628                 return FALSE;\r
629 \r
630         CFile file;\r
631         CStringA filedata;\r
632         try\r
633         {\r
634                 if ( !file.Open ( lpszFileName, CFile::modeRead ) )\r
635                 {\r
636                         m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );\r
637                         return FALSE;\r
638                 }\r
639                 UINT nFileLen = file.Read ( pBuf, dwFileSize );\r
640                 CBase64 Base64Encode;\r
641                 filedata = Base64Encode.Encode ( pBuf, nFileLen );\r
642                 filedata += _T("\r\n\r\n");\r
643         }\r
644         catch ( CFileException e )\r
645         {\r
646                 e.Delete();\r
647                 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );\r
648                 delete[] pBuf;\r
649                 return FALSE;\r
650         }\r
651 \r
652         if(!SendBuffer( filedata.GetBuffer() ))\r
653                 return FALSE;\r
654 \r
655 \r
656         delete[] pBuf;\r
657         \r
658         return TRUE;\r
659         //return Send ( csAttach );\r
660 }\r
661 \r
662 CString CHwSMTP::GetLastErrorText()\r
663 {\r
664         return m_csLastError;\r
665 }\r
666 \r
667 \r
668 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )\r
669 {\r
670         CEMailObject *pEMailObject = (CEMailObject*)lpParameter;\r
671         ASSERT ( pEMailObject );\r
672 \r
673         CHwSMTP HwSMTP;\r
674         BOOL bRet = HwSMTP.SendEmail (\r
675                 pEMailObject->m_csSmtpSrvHost,\r
676                 pEMailObject->m_csUserName,\r
677                 pEMailObject->m_csPasswd,\r
678                 pEMailObject->m_bMustAuth,\r
679                 pEMailObject->m_csAddrFrom,\r
680                 pEMailObject->m_csAddrTo,\r
681                 pEMailObject->m_csSubject,\r
682                 pEMailObject->m_csBody,\r
683                 pEMailObject->m_csCharSet,\r
684                 &pEMailObject->m_StrAryAttach,\r
685                 pEMailObject->m_StrCC,\r
686                 pEMailObject->m_nSmtpSrvPort,\r
687                 pEMailObject->m_csSender\r
688                 );\r
689         if ( !bRet)\r
690         {\r
691 #ifdef _DEBUG\r
692                 CString csError = HwSMTP.GetLastErrorText ();\r
693                 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );\r
694                 AfxMessageBox ( csError );\r
695 #endif\r
696         }\r
697 \r
698         m_CSFor__g_PtrAry_Threads.Lock ();\r
699         int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );\r
700         if ( nFindPos >= 0 )\r
701                 g_PtrAry_Threads.RemoveAt ( nFindPos );\r
702         m_CSFor__g_PtrAry_Threads.Unlock ();\r
703 \r
704         delete pEMailObject;\r
705         return bRet;\r
706 }\r
707 \r
708 //\r
709 // ÓàSMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷ÓàEndOfSMTP() º¯Êý\r
710 //\r
711 BOOL SendEmail (\r
712                                 BOOL bViaThreadSend,\r
713                                 LPCTSTR lpszSmtpSrvHost,\r
714                                 LPCTSTR lpszUserName,\r
715                                 LPCTSTR lpszPasswd,\r
716                                 BOOL bMustAuth,\r
717                                 LPCTSTR lpszAddrFrom,\r
718                                 LPCTSTR lpszAddrTo,\r
719                                 LPCTSTR lpszFromName,\r
720                                 LPCTSTR lpszReceiverName,\r
721                                 LPCTSTR lpszSubject,\r
722                                 LPCTSTR lpszBody,\r
723                                 LPCTSTR lpszCharSet/*=NULL*/,\r
724                                 CStringArray *pStrAryAttach/*=NULL*/,\r
725                                 LPCTSTR pStrAryCC/*=NULL*/,\r
726                                 UINT nSmtpSrvPort/*=25*/,\r
727                                 LPCTSTR lpszSender,\r
728                                 LPCTSTR lpszToList\r
729                                 )\r
730 {\r
731         if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||\r
732                 !lpszSubject || lstrlen(lpszSubject) < 1 ||\r
733                 !lpszBody || lstrlen(lpszBody) < 1 )\r
734         {\r
735                 AfxMessageBox ( _T("Parameter error !") );\r
736                 return FALSE;\r
737         }\r
738 \r
739         CEMailObject *pEMailObject = new CEMailObject (\r
740                 lpszSmtpSrvHost,\r
741                 lpszUserName,\r
742                 lpszPasswd,\r
743                 bMustAuth,\r
744                 lpszAddrFrom,\r
745                 lpszAddrTo,\r
746                 lpszFromName,\r
747                 lpszReceiverName,\r
748                 lpszSubject,\r
749                 lpszBody,\r
750                 lpszCharSet,\r
751                 pStrAryAttach,\r
752                 pStrAryCC,\r
753                 nSmtpSrvPort,\r
754                 lpszSender,\r
755                 lpszToList\r
756                 );\r
757         if ( !pEMailObject ) return FALSE;\r
758 \r
759         BOOL bRet = FALSE;\r
760         if ( bViaThreadSend )\r
761         {\r
762                 DWORD dwThreadId = 0;\r
763                 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );\r
764                 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);\r
765                 m_CSFor__g_PtrAry_Threads.Lock();\r
766                 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );\r
767                 m_CSFor__g_PtrAry_Threads.Unlock();\r
768                 ResumeThread ( pEMailObject->m_hThread );\r
769         }\r
770         else\r
771         {\r
772                 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );\r
773         }\r
774 \r
775         return bRet;\r
776 }\r
777 \r
778 void EndOfSMTP ()\r
779 {\r
780         // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï\r
781         for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )\r
782         {\r
783                 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);\r
784                 if ( HANDLE_IS_VALID(hThread) )\r
785                 {\r
786                         WaitForThreadEnd ( &hThread, 30*1000 );\r
787                 }\r
788         }\r
789         g_PtrAry_Threads.RemoveAll ();\r
790 }\r
791 \r
792 \r
793 //\r
794 // ½«×Ö·û´® lpszOrg ×ª»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ\r
795 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));\r
796 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );\r
797 //\r
798 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )\r
799 {\r
800         m_bNewBuffer = FALSE;\r
801         m_pszData = NULL;\r
802         m_nDataSize = 0;\r
803         m_nCharactersNumber = 0;\r
804         if ( !lpszOrg ) return;\r
805         \r
806         // ÅжÏԭʼ×Ö·û´®µÄ±àÂ뷽ʽ\r
807         BOOL bOrgIsUnicode = FALSE;\r
808         if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;\r
809         else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;\r
810         else\r
811         {\r
812 #ifdef UNICODE\r
813                 bOrgIsUnicode = TRUE;\r
814 #else\r
815                 bOrgIsUnicode = FALSE;\r
816 #endif\r
817         }\r
818         \r
819         // ¼ÆËã×Ö·û´®¸öÊýºÍÐèÒªµÄÄ¿±ê»º³å´óС\r
820         if ( bOrgIsUnicode )\r
821         {\r
822                 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);\r
823                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);\r
824         }\r
825         else\r
826         {\r
827                 m_nCharactersNumber = (int)strlen((char*)lpszOrg);\r
828                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);\r
829         }\r
830         \r
831         // Ê¹Óõ÷ÓÃÕß´«ÈëµÄ»º³å\r
832         if ( pOutBuf && nOutBufSize > 0 )\r
833         {\r
834                 m_pszData = pOutBuf;\r
835                 m_nDataSize = nOutBufSize;\r
836         }\r
837         // ×Ô¼ºÉêÇëÄڴ滺³å\r
838         else\r
839         {\r
840                 m_pszData = (char*)new BYTE[m_nDataSize];\r
841                 if ( !m_pszData )\r
842                 {\r
843                         ::AfxThrowMemoryException ();\r
844                         return;\r
845                 }\r
846                 m_bNewBuffer = TRUE;\r
847         }\r
848         memset ( m_pszData, 0, m_nDataSize );\r
849         \r
850         if ( bOrgIsUnicode )\r
851         {\r
852                 m_nCharactersNumber = WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize/sizeof(char)-1, NULL, NULL );\r
853                 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );\r
854         }\r
855         else\r
856         {\r
857                 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );\r
858                 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );\r
859                 m_nCharactersNumber = (int)strlen ( m_pszData );\r
860         }\r
861         m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);\r
862 }\r
863 \r
864 CMultiByteString::~CMultiByteString ()\r
865 {\r
866         if ( m_bNewBuffer && m_pszData )\r
867         {\r
868                 delete[] m_pszData;\r
869         }\r
870 }\r
871 \r
872 //\r
873 // ½« lpszOrg ×ª»»Îª¸Ã³ÌÐòʹÓõıàÂë×Ö·û´®£¬Èç¹û¸Ã³ÌÐòÊÇ UNICODE ¾ÍתΪ UNICODE£¬Èç¹ûÊÇ ANSI ¾ÍתΪ ANSI µÄ\r
874 //\r
875 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )\r
876 {\r
877         if ( !lpszOrg ) return _T("");\r
878         \r
879         TRY\r
880         {\r
881 #ifdef UNICODE\r
882                 if ( bOrgIsUnicode )\r
883                 {\r
884                         if ( nOrgLength > 0 )\r
885                         {\r
886                                 WCHAR *szRet = new WCHAR[nOrgLength+1];\r
887                                 if ( !szRet ) return _T("");\r
888                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );\r
889                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );\r
890                                 CString csRet = szRet;\r
891                                 delete[] szRet;\r
892                                 return csRet;\r
893                         }\r
894                         else if ( nOrgLength == 0 )\r
895                                 return _T("");\r
896                         else\r
897                                 return (LPCTSTR)lpszOrg;\r
898                 }\r
899                 \r
900                 if ( nOrgLength < 0 )\r
901                         nOrgLength = (int)strlen((const char*)lpszOrg);\r
902                 int nWideCount = nOrgLength + 1;\r
903                 WCHAR *wchar = new WCHAR[nWideCount];\r
904                 if ( !wchar ) return _T("");\r
905                 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );\r
906                 ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);\r
907                 CString csRet = wchar;\r
908                 delete[] wchar;\r
909                 return csRet;\r
910 #else\r
911                 if ( !bOrgIsUnicode )\r
912                 {\r
913                         if ( nOrgLength > 0 )\r
914                         {\r
915                                 char *szRet = new char[nOrgLength+1];\r
916                                 if ( !szRet ) return _T("");\r
917                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );\r
918                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );\r
919                                 CString csRet = szRet;\r
920                                 delete[] szRet;\r
921                                 return csRet;\r
922                         }\r
923                         else if ( nOrgLength == 0 )\r
924                                 return _T("");\r
925                         else\r
926                                 return (LPCTSTR)lpszOrg;\r
927                 }\r
928                 \r
929                 if ( nOrgLength < 0 )\r
930                         nOrgLength = (int)wcslen((WCHAR*)lpszOrg);\r
931                 int nMultiByteCount = nOrgLength + 1;\r
932                 char *szMultiByte = new char[nMultiByteCount];\r
933                 if ( !szMultiByte ) return _T("");\r
934                 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );\r
935                 ::WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL );\r
936                 CString csRet = szMultiByte;\r
937                 delete[] szMultiByte;\r
938                 return csRet;\r
939 #endif\r
940         }\r
941         CATCH_ALL(e)\r
942         {\r
943                 THROW_LAST ();\r
944         }\r
945         END_CATCH_ALL\r
946                 \r
947                 return _T("");\r
948 }\r
949 \r
950 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )\r
951 {       \r
952         // If null, return empty string\r
953         if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )\r
954                 return _T("");\r
955         \r
956         UDATE ud;\r
957         if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))\r
958         {\r
959                 return _T("");\r
960         }\r
961         \r
962         struct tm tmTemp;\r
963         tmTemp.tm_sec   = ud.st.wSecond;\r
964         tmTemp.tm_min   = ud.st.wMinute;\r
965         tmTemp.tm_hour  = ud.st.wHour;\r
966         tmTemp.tm_mday  = ud.st.wDay;\r
967         tmTemp.tm_mon   = ud.st.wMonth - 1;\r
968         tmTemp.tm_year  = ud.st.wYear - 1900;\r
969         tmTemp.tm_wday  = ud.st.wDayOfWeek;\r
970         tmTemp.tm_yday  = ud.wDayOfYear - 1;\r
971         tmTemp.tm_isdst = 0;\r
972         \r
973         CString strDate;\r
974         LPTSTR lpszTemp = strDate.GetBufferSetLength(256);\r
975         _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp);\r
976         strDate.ReleaseBuffer();\r
977         \r
978         return strDate;\r
979 }\r
980 \r
981 CString FormatString ( LPCTSTR lpszStr, ... )\r
982 {\r
983         TCHAR *buf = NULL;\r
984         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
985         for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )\r
986         {\r
987                 buf = new TCHAR[nBufCount];\r
988                 if ( !buf )\r
989                 {\r
990                         ::AfxThrowMemoryException ();\r
991                         return _T("");\r
992                 }\r
993                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
994                 \r
995                 va_list  va;\r
996                 va_start (va, lpszStr);\r
997                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);\r
998                 va_end(va);\r
999                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
1000                         break;\r
1001                 delete[] buf; buf = NULL;\r
1002         }\r
1003         if ( !buf )\r
1004         {\r
1005                 return _T("");\r
1006         }\r
1007         \r
1008         CString csMsg = buf;\r
1009         delete[] buf; buf = NULL;\r
1010         return csMsg;\r
1011 }\r
1012 \r
1013 /********************************************************************************\r
1014 * Function Type :       Global\r
1015 * Parameter             :       lpFileName      -       Îļþ·¾¶\r
1016 * Return Value  :       -1                      -       Ê§°Ü\r
1017 *                                       >=0                     -       Îļþ´óС\r
1018 * Description   :       »ñÈ¡ÎļþÊôÐÔ ( Îļþ´óС¡¢´´½¨Ê±¼ä )\r
1019 *********************************************************************************/\r
1020 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )\r
1021 {\r
1022         if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;\r
1023         \r
1024         CFileStatus fileStatus;\r
1025         fileStatus.m_attribute = 0;\r
1026         fileStatus.m_size = 0;\r
1027         memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );\r
1028         BOOL bRet = FALSE;\r
1029         TRY\r
1030         {\r
1031                 if ( CFile::GetStatus(lpFileName,fileStatus) )\r
1032                 {\r
1033                         bRet = TRUE;\r
1034                 }\r
1035         }\r
1036         CATCH (CFileException, e)\r
1037         {\r
1038                 ASSERT ( FALSE );\r
1039                 bRet = FALSE;\r
1040         }\r
1041         CATCH_ALL(e)\r
1042         {\r
1043                 ASSERT ( FALSE );\r
1044                 bRet = FALSE;\r
1045         }\r
1046         END_CATCH_ALL;\r
1047         \r
1048         if ( pFileStatus )\r
1049         {\r
1050                 pFileStatus->m_ctime = fileStatus.m_ctime;\r
1051                 pFileStatus->m_mtime = fileStatus.m_mtime;\r
1052                 pFileStatus->m_atime = fileStatus.m_atime;\r
1053                 pFileStatus->m_size = fileStatus.m_size;\r
1054                 pFileStatus->m_attribute = fileStatus.m_attribute;\r
1055                 pFileStatus->_m_padding = fileStatus._m_padding;\r
1056                 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );\r
1057                 \r
1058         }\r
1059         \r
1060         return (int)fileStatus.m_size;\r
1061 }\r
1062 \r
1063 //\r
1064 // ½«Ò»¸ö±íʾ×Ö½ÚµÄÊýÓÿɶÁÐԺõÄ×Ö·û´®À´±íʾ£¬ÀýÈ罫 12345678 ×Ö½Úת»»Îª£º\r
1065 // 11.77M\r
1066 // nFlag        -       0 : ×Ô¶¯Æ¥Å䵥λ\r
1067 //                              1 : ÒÔ Kb Îªµ¥Î»\r
1068 //                              2 : ÒÔ Mb Îªµ¥Î»\r
1069 //                              3 : ÒÔ Gb Îªµ¥Î»\r
1070 // \r
1071 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )\r
1072 {\r
1073         CString csRes;\r
1074         if ( nFlag == 0 )\r
1075         {\r
1076                 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )\r
1077                         csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
1078                 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )\r
1079                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
1080                 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )\r
1081                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
1082                 else\r
1083                         csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );\r
1084         }\r
1085         else if ( nFlag == 1 )\r
1086         {\r
1087                 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
1088         }\r
1089         else if ( nFlag == 2 )\r
1090         {\r
1091                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
1092         }\r
1093         else if ( nFlag == 3 )\r
1094         {\r
1095                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
1096         }\r
1097         \r
1098         return csRes;\r
1099 }\r
1100 \r
1101 //\r
1102 // µÈ´ýÏß³ÌÍ˳ö\r
1103 //\r
1104 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )\r
1105 {\r
1106         BOOL bRet = TRUE;\r
1107         ASSERT ( phThread );\r
1108         if ( !(*phThread) ) return TRUE;\r
1109         if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )\r
1110         {\r
1111                 bRet = FALSE;\r
1112                 ::TerminateThread ( *phThread, 0 );\r
1113         }\r
1114         ::CloseHandle ( *phThread );\r
1115         (*phThread) = NULL;\r
1116         return bRet;\r
1117 }\r