COUNTER.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:10k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // counter.cpp : Defines the initialization routines for the DLL.
  3. //
  4. // Written by Jeff Miller
  5. // of Microsoft Product Support Services, Languages Developer Support
  6. //
  7. // This is a part of the Microsoft Foundation Classes C++ library.
  8. // Copyright (C) 1992-1998 Microsoft Corporation
  9. // All rights reserved.
  10. //
  11. // This source code is only intended as a supplement to the
  12. // Microsoft Foundation Classes Reference and related
  13. // electronic documentation provided with the library.
  14. // See these sources for detailed information regarding the
  15. // Microsoft Foundation Classes product.
  16. // This ISAPI DLL can be called in three ways:
  17. // <IMG SRC="/scripts/counter.dll?clock">
  18. // will return an x-bitmap image containing the current system time
  19. // <IMG SRC="/scripts/counter.dll/mydir/mypage.htm">
  20. // will return an x-bitmap image containing the accumulated
  21. // count for the identifier /mydir/mypage.htm
  22. // <IMG SRC="/scripts/counter.dll">
  23. // will return an x-bitmap image containing the accumulated
  24. // count for the page which called the DLL.
  25. #include <afx.h>
  26. #include <afxdb.h>
  27. #include <afxisapi.h>
  28. #include "resource.h"
  29. #include "counter.h"
  30. #include "charset.h"
  31. // This program sends back xbitmap images rather than HTML.
  32. static const TCHAR szContentType[] = _T("Content-Type: image/x-xbitmaprn");
  33. // The following defines the location and filename for the log file.
  34. // This should be placed in a location that can be read and written to.
  35. static const TCHAR szLogFile[] = _T("C:\counter.log");
  36. // The following two headers will tell the client never to cache
  37. // this information, as it is dynamic.
  38. static const TCHAR szExpires[] = _T("Expires: Thu, 01 Jan 1995 01:00:00 GMTrn");
  39. static const TCHAR szNoCache[] = _T("Pragma: no-cachern");
  40. ///////////////////////////////////////////////////////////////////////
  41. // command-parsing map
  42. BEGIN_PARSE_MAP(CCounterExtension, CHttpServer)
  43. ON_PARSE_COMMAND(Clock, CCounterExtension, ITS_EMPTY)
  44. ON_PARSE_COMMAND(Default, CCounterExtension, ITS_EMPTY)
  45. DEFAULT_PARSE_COMMAND(Default, CCounterExtension)
  46. END_PARSE_MAP(CCounterExtension)
  47. ///////////////////////////////////////////////////////////////////////
  48. // The one and only CCounterExtension object
  49. CCounterExtension theExtension;
  50. ///////////////////////////////////////////////////////////////////////
  51. // CCounterExtension implementation
  52. CCounterExtension::CCounterExtension()
  53. {
  54. }
  55. CCounterExtension::~CCounterExtension()
  56. {
  57. }
  58. BOOL CCounterExtension::GetExtensionVersion(HSE_VERSION_INFO* pVer)
  59. {
  60. // Call default implementation for initialization
  61. CHttpServer::GetExtensionVersion(pVer);
  62. // Load description string
  63. TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1];
  64. ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
  65. IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN));
  66. _tcscpy(pVer->lpszExtensionDesc, sz);
  67. return TRUE;
  68. }
  69. ///////////////////////////////////////////////////////////////////////
  70. // CCounterExtension command handlers
  71. void CCounterExtension::Default(CHttpServerContext* pCtxt)
  72. {
  73. // We don't call StartContent() or WriteTitle() here due to the
  74. // fact that those will send back tags appropriate only to
  75. // HTML pages.  We will be sending back an image.
  76. // Don't allow these pages to be cached
  77. AddHeader(pCtxt, szExpires);
  78. AddHeader(pCtxt, szNoCache);
  79. TCHAR pstrBuffer[1024];
  80. // Check to see if a path was given after the DLL's name,
  81. // such as <IMG SRC="/scripts/counter.dll/mydir/mypage.htm">
  82. // If so, use the given path.  Otherwise, use the URL of
  83. // the page which called this DLL.
  84. if (_tcsclen(pCtxt->m_pECB->lpszPathInfo) != 0)
  85. {
  86. _tcscpy(pstrBuffer, pCtxt->m_pECB->lpszPathInfo);
  87. }
  88. else
  89. {
  90. // HTTP_REFERER contains the full URL of the page which
  91. // called this DLL.
  92. DWORD dwSize = 1024;
  93. pCtxt->GetServerVariable(_T("HTTP_REFERER"), pstrBuffer, &dwSize);
  94. }
  95. // Call member function to see how many times the requested
  96. // page has been accessed and update that count.
  97. // GetPageCount will return -1 if there was a problem reading the
  98. // counter log file.
  99. CString szPath(pstrBuffer);
  100. int nCount = GetPageCount(szPath);
  101. if (nCount != -1)
  102. {
  103. // call member function to output an xbitmap image
  104. // containing the digits
  105. CString szCount;
  106. szCount.Format(_T("%d"), nCount);
  107. OutputXBM(pCtxt, szCount);
  108. }
  109. // EndContent() is only appropriate for HTML files, so we
  110. // don't call it here.
  111. }
  112. void CCounterExtension::Clock(CHttpServerContext* pCtxt)
  113. {
  114. // Clock
  115. // Called when DLL is accessed using the format
  116. // <IMG SRC="/scripts/counter.dll?Clock">
  117. // We don't call StartContent() or WriteTitle() here due to the
  118. // fact that those will send back tags appropriate only to
  119. // HTML pages.  We will be sending back an image.
  120. // Don't allow these pages to be cached
  121. AddHeader(pCtxt, szExpires);
  122. AddHeader(pCtxt, szNoCache);
  123. // Get the current system time, and put it into a form
  124. // which our function will accept.
  125. CTime time = CTime::GetCurrentTime();
  126. CString szTime = time.Format(_T("%H%%%M"));
  127. // call member function to output an xbitmap image
  128. // containing the digits
  129. OutputXBM(pCtxt, szTime);
  130. // EndContent() is only appropriate for HTML files, so we
  131. // don't call it here.
  132. }
  133. void CCounterExtension::OutputXBM(CHttpServerContext* pCtxt, CString& szDigits)
  134. {
  135. // Function to take in a string containing the digits 0..9 and the character
  136. // ':' and output an xbitmap image of those digits to the stream
  137. // Start by writing the proper content type to the client
  138. AddHeader(pCtxt, szContentType);
  139. // NOTE: this code as is will only work properly with image data
  140. // that has a width = 8
  141. int nFinalWidth = char_width * szDigits.GetLength();
  142. int nFinalHeight = char_height;
  143. // write out the XBM header.  We cast to long int because there is
  144. // no CHttpServerContext << operator overload that accepts an
  145. // integer.
  146. *pCtxt << _T("#define counter_width ") << (long int)nFinalWidth << _T("rn");
  147. *pCtxt << _T("#define counter_height ") << (long int)nFinalHeight << _T("rn");
  148. *pCtxt << _T("static unsigned char counter_bits[] = {rn");
  149. // Now for each horizontal line of output, get the bitmap for each
  150. // character for that line and output it.
  151. for (int nLine=0; nLine<nFinalHeight; nLine++)
  152. {
  153. for (int nChar=0; nChar<szDigits.GetLength(); nChar++)
  154. {
  155. int nDigitOffset;
  156. if (szDigits[nChar] >= __TEXT('0') && szDigits[nChar] <= __TEXT('9'))
  157. nDigitOffset = szDigits[nChar] - __TEXT('0');
  158. else
  159. // colon is in index 10 in the bitmap array
  160. nDigitOffset = 10;
  161. CString szHex;
  162. szHex.Format(_T("0x%02X, "), char_bits[nDigitOffset][nLine]);
  163. *pCtxt << szHex;
  164. }
  165. }
  166. *pCtxt << _T("};rn");
  167. }
  168. int CCounterExtension::GetPageCount(CString& szPage)
  169. {
  170. // Given a unique page identifier (szPage), check our "database"
  171. // to see how many times this page has been accessed, then
  172. // return that count.  If this function fails, -1 will be returned.
  173. CFile file;
  174. CFileException e;
  175. int nOpenAttempts = 0;
  176. // make sure only one thread operates on the log file at a time
  177. while (TRUE)
  178. {
  179. if (file.Open(szLogFile,
  180. CFile::modeRead | CFile::shareExclusive
  181. | CFile::modeCreate | CFile::modeNoTruncate, &e))
  182. {
  183. // we opened the file, so continue onwards
  184. break;
  185. }
  186. else
  187. {
  188. // we couldn't open the file...figure out why
  189. if (e.m_cause == CFileException::sharingViolation)
  190. {
  191. // sharing violation
  192. // another thread must have the file open, so wait and retry
  193. ::Sleep(100);
  194. // increase the attempt counter
  195. nOpenAttempts++;
  196. if (nOpenAttempts == 30)
  197. {
  198. // too many retries. something's amiss
  199. CString szErrText;
  200. szErrText.LoadString(IDS_RETRYERR);
  201. TRACE0(szErrText);
  202. // return error code
  203. return -1;
  204. }
  205. }
  206. else
  207. {
  208. // not a sharing violation error
  209. // so it's probably serious
  210. TCHAR szCause[255];
  211. e.GetErrorMessage(szCause, 255);
  212. CString szErrText;
  213. szErrText.LoadString(IDS_OPENERR);
  214. TRACE1(szErrText, szCause);
  215. // return error code
  216. return -1;
  217. }
  218. }
  219. }
  220. // we've now successfully opened the log file so let's read it!
  221. CArchive archive(&file, CArchive::load);
  222. // Serialize in the data from the file
  223. try
  224. {
  225. m_Paths.Serialize(archive);
  226. }
  227. catch (CArchiveException* e)
  228. {
  229. // if we get endOfFile, it probably means that the counter
  230. // log file doesn't exist yet, so it's not a fatal error
  231. if (e->m_cause != CArchiveException::endOfFile)
  232. {
  233. TCHAR szCause[255];
  234. e->GetErrorMessage(szCause, 255);
  235. CString szErrText;
  236. szErrText.LoadString(IDS_SERIALIZEERR);
  237. TRACE1(szErrText, szCause);
  238. m_Paths.RemoveAll();
  239. archive.Close();
  240. file.Close();
  241. e->Delete();
  242. return -1;
  243. }
  244. e->Delete();
  245. }
  246. archive.Close();
  247. file.Close();
  248. // Try to find the page identifier in the log
  249. int nVal = 0;
  250. CString szCount;
  251. if (m_Paths.Lookup(szPage, szCount))
  252. nVal = atoi(szCount);
  253. // Increment the count.
  254. nVal++;
  255. // Set the new value.
  256. szCount.Format(_T("%d"), nVal);
  257. m_Paths.SetAt(szPage, szCount);
  258. // Write the updated log
  259. if ( !file.Open(szLogFile,
  260. CFile::modeWrite | CFile::shareExclusive
  261. | CFile::modeCreate, &e) )
  262. {
  263. TCHAR szCause[255];
  264. e.GetErrorMessage(szCause, 255);
  265. CString szErrText;
  266. szErrText.LoadString(IDS_OPENERR);
  267. TRACE1(szErrText, szCause);
  268. // return error code
  269. return -1;
  270. }
  271. CArchive archiveStore(&file, CArchive::store);
  272. try
  273. {
  274. m_Paths.Serialize(archiveStore);
  275. }
  276. catch (CArchiveException* e)
  277. {
  278. TCHAR szCause[255];
  279. e->GetErrorMessage(szCause, 255);
  280. CString szErrText;
  281. szErrText.LoadString(IDS_SERIALIZEERR);
  282. TRACE1(szErrText, szCause);
  283. archiveStore.Close();
  284. file.Close();
  285. e->Delete();
  286. // return error code
  287. return -1;
  288. }
  289. archiveStore.Close();
  290. file.Close();
  291. // Return the count we received
  292. return nVal;
  293. }