Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
14 KiB

  1. //
  2. // MODULE: CommonREGCONNECT.CPP
  3. //
  4. // PURPOSE: read - write to the registry; common code for Online TS and Local TS, which differ
  5. // on many functions of this class
  6. //
  7. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  8. //
  9. // AUTHOR: Oleg Kalosha, Joe Mabel
  10. //
  11. // ORIGINAL DATE: 8-24-98 in Online TS. This file abstracted 1-19-98
  12. //
  13. // NOTES:
  14. //
  15. // Version Date By Comments
  16. //--------------------------------------------------------------------
  17. // V3.0 08-04-98 OK
  18. // V3.0 09-10-98 JM backslashing; access log file info
  19. // V3.1 01-19-98 JM branch out version exclusively for Local TS
  20. #pragma warning(disable:4786)
  21. #include "stdafx.h"
  22. #include "apgtsregconnect.h"
  23. #include "event.h"
  24. #include "apgtsevt.h"
  25. #include "apgtscls.h"
  26. #include "apgts.h"
  27. #include "apiwraps.h"
  28. CMutexOwner CAPGTSRegConnector::s_mx(_T("APGTSRegConnector"));
  29. ////////////////////////////////////////////////////////////////////////////////////
  30. // CAPGTSRegConnector
  31. ////////////////////////////////////////////////////////////////////////////////////
  32. CAPGTSRegConnector::~CAPGTSRegConnector()
  33. {
  34. }
  35. // When this lock is held, it locks against not just other threads locking this object,
  36. // but against other threads locking any objects of class CAPGTSRegConnector.
  37. void CAPGTSRegConnector::Lock()
  38. {
  39. WAIT_INFINITE( s_mx.Handle() );
  40. }
  41. void CAPGTSRegConnector::Unlock()
  42. {
  43. ::ReleaseMutex(s_mx.Handle());
  44. }
  45. bool CAPGTSRegConnector::IsRead()
  46. {
  47. bool ret = false;
  48. Lock();
  49. ret = m_RegistryInfo.m_bIsRead;
  50. Unlock();
  51. return ret;
  52. }
  53. // the root key (typically "SOFTWARE\Microsoft" in Local TS or "SOFTWARE\\ISAPITroubleShoot" in Online TS) exists
  54. bool CAPGTSRegConnector::Exists()
  55. {
  56. bool ret = false;
  57. CRegUtil reg;
  58. Lock();
  59. if (reg.Open(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), KEY_QUERY_VALUE))
  60. if (reg.Open(RegThisProgram(), KEY_QUERY_VALUE))
  61. ret = true;
  62. reg.Close();
  63. Unlock();
  64. return ret;
  65. }
  66. /*static*/ CString & CAPGTSRegConnector::StringFromConnector(ERegConnector e, CString & str)
  67. {
  68. switch (e)
  69. {
  70. case eResourcePath: str = FULLRESOURCE_STR; break;
  71. case eVrootPath: str = VROOTPATH_STR; break;
  72. case eMaxThreads: str = MAX_THREADS_STR; break;
  73. case eThreadsPP: str = THREADS_PER_PROCESSOR_STR; break;
  74. case eMaxWQItems: str = MAX_WORK_QUEUE_ITEMS_STR; break;
  75. case eCookieLife: str = COOKIE_LIFE_IN_MINS_STR; break;
  76. case eReloadDelay: str = RELOAD_DELAY_STR; break;
  77. case eDetailedEventLogging: str = DETAILED_EVENT_LOGGING_STR; break;
  78. case eLogFilePath: str = LOG_FILE_DIR_STR; break;
  79. case eTopicFileExtension: str = LOG_FILE_DIR_STR; break;
  80. case eSniffAutomatic: str = SNIFF_AUTOMATIC_STR; break;
  81. case eSniffManual: str = SNIFF_MANUAL_STR; break;
  82. default: str = _T(""); break;
  83. }
  84. return str;
  85. }
  86. /*static*/ CAPGTSRegConnector::ERegConnector CAPGTSRegConnector::ConnectorFromString( const CString & str)
  87. {
  88. ERegConnector e = eIndefinite;
  89. if (str == FULLRESOURCE_STR)
  90. e = eResourcePath;
  91. else if (str == VROOTPATH_STR)
  92. e = eVrootPath;
  93. else if (str == MAX_THREADS_STR)
  94. e = eMaxThreads;
  95. else if (str == THREADS_PER_PROCESSOR_STR)
  96. e = eThreadsPP;
  97. else if (str == MAX_WORK_QUEUE_ITEMS_STR)
  98. e = eMaxWQItems;
  99. else if (str == COOKIE_LIFE_IN_MINS_STR)
  100. e = eCookieLife;
  101. else if (str == RELOAD_DELAY_STR)
  102. e = eReloadDelay;
  103. else if (str == DETAILED_EVENT_LOGGING_STR)
  104. e = eDetailedEventLogging;
  105. else if (str == LOG_FILE_DIR_STR)
  106. e = eLogFilePath;
  107. else if (str == SNIFF_AUTOMATIC_STR)
  108. e = eSniffAutomatic;
  109. else if (str == SNIFF_MANUAL_STR)
  110. e = eSniffManual;
  111. return e;
  112. }
  113. /*static*/ bool CAPGTSRegConnector::IsNumeric(ERegConnector e)
  114. {
  115. switch (e)
  116. {
  117. case eMaxThreads: return true;
  118. case eThreadsPP: return true;
  119. case eMaxWQItems: return true;
  120. case eCookieLife: return true;
  121. case eReloadDelay: return true;
  122. case eDetailedEventLogging: return true;
  123. case eSniffAutomatic: return true;
  124. case eSniffManual: return true;
  125. default: return false;
  126. }
  127. }
  128. /*static*/ bool CAPGTSRegConnector::IsString(ERegConnector e)
  129. {
  130. switch (e)
  131. {
  132. case eResourcePath: return true;
  133. case eVrootPath: return true;
  134. case eLogFilePath: return true;
  135. case eTopicFileExtension: return true;
  136. default: return false;
  137. }
  138. }
  139. ////////////////////////////////////////////////////////
  140. // The following 2 functions set values in the registry. Note that they do NOT
  141. // maintain member values. That must be done at a higher level.
  142. // Like CRegUtil::SetNumericValue(), and CRegUtil::SetStringValue(),
  143. // these assume we already have right key open.
  144. // These also assume we have the relevant lock.
  145. void CAPGTSRegConnector::SetNumericValue(CRegUtil &reg, ERegConnector e, DWORD dwValue)
  146. {
  147. CString str;
  148. if( IsNumeric(e) && reg.SetNumericValue(StringFromConnector(e, str), dwValue))
  149. return;
  150. // either inappropriate input or otherwise couldn't set value
  151. throw CAPGTSRegConnectorException(__FILE__, __LINE__, reg, e);
  152. }
  153. //
  154. // See comments on CAPGTSRegConnector::SetNumericValue
  155. void CAPGTSRegConnector::SetStringValue(CRegUtil &reg, ERegConnector e, CString strValue)
  156. {
  157. CString str;
  158. if( IsString(e) && reg.SetStringValue(StringFromConnector(e, str), strValue))
  159. return;
  160. // either inappropriate input or otherwise couldn't set value
  161. throw CAPGTSRegConnectorException(__FILE__, __LINE__, reg, e);
  162. }
  163. ///////////////////////////////////////////////////////////
  164. ///////////////////////////////////////////////////////////
  165. // The following 3 functions set values in the registry. Note that they do NOT
  166. // maintain member values. Typically, these are to be used in a CAPGTSRegConnector
  167. // that exists briefly for the sole purpose of setting registry values.
  168. //
  169. // If there is a CRegistryMonitor in existence -- whether it is this object itself
  170. // or a distinct object -- it will become aware of this change by monitoring
  171. // the registry and will behave accordingly.
  172. //
  173. // SetOneNumericValue() is a higher-level way to set a numeric value.
  174. // Does not assume anything about open keys or held locks.
  175. // Does assume value is in the usual area where APGTS stores its registry data.
  176. bool CAPGTSRegConnector::SetOneNumericValue(ERegConnector e, DWORD dwValue)
  177. {
  178. bool bRet=true;
  179. Lock();
  180. try
  181. {
  182. CRegUtil reg;
  183. bool was_created = false;
  184. if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE))
  185. {
  186. if (reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE))
  187. {
  188. SetNumericValue(reg, e, dwValue);
  189. }
  190. }
  191. }
  192. catch(CAPGTSRegConnectorException& exception)
  193. {
  194. exception.Log();
  195. exception.Close();
  196. bRet=false;
  197. }
  198. Unlock();
  199. return bRet;
  200. }
  201. //
  202. // See comments on CAPGTSRegConnector::SetOneNumericValue
  203. // SetOneStringValue() is a higher-level way to set a string value.
  204. // Does not assume anything about open keys or held locks.
  205. // Does assume value is in the usual area where APGTS stores its registry data.
  206. bool CAPGTSRegConnector::SetOneStringValue(ERegConnector e, const CString & strValue)
  207. {
  208. bool bRet=true;
  209. Lock();
  210. try
  211. {
  212. CRegUtil reg;
  213. bool was_created = false;
  214. if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE))
  215. {
  216. if (reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE))
  217. {
  218. SetStringValue(reg, e, strValue);
  219. }
  220. }
  221. }
  222. catch(CAPGTSRegConnectorException& exception)
  223. {
  224. exception.Log();
  225. exception.Close();
  226. bRet=false;
  227. }
  228. Unlock();
  229. return bRet;
  230. }
  231. //
  232. // See comments on CAPGTSRegConnector::SetOneNumericValue. This is the public function
  233. // Function returns true if strName represents a value we maintain.
  234. // bChanged returns true if the value is changed. If the function returns false, bChanged
  235. // always returns false.
  236. bool CAPGTSRegConnector::SetOneValue(const CString & strName, const CString & strValue, bool &bChanged)
  237. {
  238. ERegConnector e = ConnectorFromString(strName);
  239. if (IsNumeric(e))
  240. {
  241. bChanged = SetOneNumericValue(e, _ttoi(strValue));
  242. return true;
  243. }
  244. else if (IsString(e))
  245. {
  246. bChanged = SetOneStringValue(e, strValue);
  247. return true;
  248. }
  249. else
  250. {
  251. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  252. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  253. SrcLoc.GetSrcFileLineStr(),
  254. _T(""), _T(""),
  255. EV_GTS_ERROR_INVALIDREGCONNECTOR );
  256. bChanged = false;
  257. return false;
  258. }
  259. }
  260. //////////////////////////////////////////////////////
  261. // Having read a string strNew from the registry & done any massaging it gets,
  262. // assign this string value to the appropriate variable strPersist.
  263. // Returns true and logs dwEvent if strPersist is changed (new value differs from old).
  264. /*static*/ bool CAPGTSRegConnector::AssignString(CString & strPersist, const CString & strNew, DWORD dwEvent)
  265. {
  266. if (!(strNew == strPersist))
  267. {
  268. CString str = strPersist;
  269. str += _T(" | ");
  270. str += strNew;
  271. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  272. CEvent::ReportWFEvent(SrcLoc.GetSrcFileLineStr(),
  273. SrcLoc.GetSrcFileLineStr(),
  274. str,
  275. _T(""),
  276. dwEvent);
  277. strPersist = strNew;
  278. return true;
  279. }
  280. return false;
  281. }
  282. // Having read a numeric dwNew from the registry
  283. // assign this value to the appropriate variable dwPersist.
  284. // Also used a second time if we need to force the value to an acceptable number.
  285. // Returns true and logs dwEvent if dwPersist is changed (new value differs from old).
  286. // If dwEventDecrease is non-zero, it provides a distinct message to log if the value
  287. // is decreased rather than increased.
  288. /*static*/ bool CAPGTSRegConnector::AssignNumeric(DWORD & dwPersist, DWORD dwNew,
  289. DWORD dwEvent, DWORD dwEventDecrease /* =0 */)
  290. {
  291. if (dwNew != dwPersist)
  292. {
  293. CString strOld;
  294. strOld.Format(_T("%d"), dwPersist );
  295. CString strNew;
  296. strNew.Format(_T("%d"), dwNew);
  297. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  298. CEvent::ReportWFEvent(SrcLoc.GetSrcFileLineStr(),
  299. SrcLoc.GetSrcFileLineStr(),
  300. strOld,
  301. strNew,
  302. (dwEventDecrease != 0 && dwNew < dwPersist) ?
  303. dwEventDecrease : dwEvent);
  304. dwPersist = dwNew;
  305. return true;
  306. }
  307. return false;
  308. }
  309. /*static*/ bool CAPGTSRegConnector::ForceRangeOfNumeric(
  310. DWORD & dw,
  311. DWORD dwDefault,
  312. DWORD dwEvent,
  313. DWORD dwMin, /*=1*/
  314. DWORD dwMax /*=ABS_MAX_REG_PARAM_VAL*/
  315. )
  316. {
  317. // do limited validation;
  318. if (dw > dwMax || dw < dwMin)
  319. {
  320. AssignNumeric(dw, dwDefault, dwEvent);
  321. return true;
  322. }
  323. return false;
  324. }
  325. // pump data into m_RegistryInfo - PLUS sets absent data in registry to default.
  326. // OUTPUT maskChanged or-ed ERegConnector-based mask of elements that have been
  327. // changed since last read
  328. // OUTPUT maskCreated or-ed ERegConnector-based mask of elements that were created
  329. // in registry (because they previously didn't exist in registry)
  330. bool CAPGTSRegConnector::Read(int & maskChanged, int & maskCreated)
  331. {
  332. bool ret = true;
  333. Lock();
  334. try {
  335. ReadUpdateRegistry(maskChanged, maskCreated);
  336. m_RegistryInfo.m_bIsRead = true;
  337. }
  338. catch(CAPGTSRegConnectorException& exception)
  339. {
  340. exception.Log();
  341. exception.Close();
  342. ret = false;
  343. }
  344. Unlock();
  345. return ret;
  346. }
  347. void CAPGTSRegConnector::Clear()
  348. {
  349. Lock();
  350. // Check if our registry tree exists.
  351. if (!Exists())
  352. {
  353. // Rebuilds our registry tree if it has been damaged or deleted.
  354. CRegUtil reg;
  355. bool was_created = false;
  356. if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE))
  357. reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE);
  358. reg.Close();
  359. }
  360. m_RegistryInfo.SetToDefault();
  361. Unlock();
  362. }
  363. bool CAPGTSRegConnector::GetNumericInfo(ERegConnector en, DWORD& out)
  364. {
  365. bool ret = true;
  366. Lock();
  367. if (en == eMaxThreads)
  368. out = m_RegistryInfo.dwMaxThreads;
  369. else if (en == eThreadsPP)
  370. out = m_RegistryInfo.dwThreadsPP;
  371. else if (en == eMaxWQItems)
  372. out = m_RegistryInfo.dwMaxWQItems;
  373. else if (en == eCookieLife)
  374. out = m_RegistryInfo.dwCookieLife;
  375. else if (en == eReloadDelay)
  376. out = m_RegistryInfo.dwReloadDelay;
  377. else if (en == eDetailedEventLogging)
  378. out = m_RegistryInfo.dwDetailedEventLogging;
  379. else if (en == eSniffAutomatic)
  380. out = m_RegistryInfo.dwSniffAutomatic;
  381. else if (en == eSniffManual)
  382. out = m_RegistryInfo.dwSniffManual;
  383. else
  384. ret = false;
  385. Unlock();
  386. return ret;
  387. }
  388. bool CAPGTSRegConnector::GetStringInfo(ERegConnector en, CString& out)
  389. {
  390. bool ret = true;
  391. Lock();
  392. if (en == eResourcePath)
  393. out = m_RegistryInfo.strResourcePath;
  394. else if (en == eVrootPath)
  395. out = m_RegistryInfo.strVrootPath;
  396. else if (en == eLogFilePath)
  397. out = m_RegistryInfo.strLogFilePath;
  398. else if (en == eTopicFileExtension)
  399. out = m_RegistryInfo.strTopicFileExtension;
  400. else
  401. ret = false;
  402. Unlock();
  403. return ret;
  404. }
  405. // AddBackslash appends a backslash ('\') to CStrings that do not already end in '\'.
  406. /* static */void CAPGTSRegConnector::AddBackslash(CString & str)
  407. {
  408. int len = str.GetLength();
  409. if (len && str.Right(1).Find('\\') >= 0)
  410. {
  411. // do nothing, already has backslash
  412. }
  413. else
  414. // add backslash
  415. str += "\\";
  416. return;
  417. }
  418. // BackslashIt replaces all frontslashes ('/') in str with backslashes ('\')
  419. // and (optionally) forces termination with a backslash
  420. /* static */void CAPGTSRegConnector::BackslashIt(CString & str, bool bForce)
  421. {
  422. int loc;
  423. while ((loc = str.Find('/')) != -1)
  424. {
  425. str = str.Left(loc) + "\\" + str.Mid(loc+1);
  426. }
  427. if (bForce)
  428. AddBackslash(str);
  429. }
  430. // APGTS key access
  431. CString CAPGTSRegConnector::ThisProgramFullKey()
  432. {
  433. CString str;
  434. str.Format(_T("%s\\%s"), RegSoftwareLoc(), RegThisProgram());
  435. return str;
  436. }
  437. ////////////////////////////////////////////////////////////////////////////////////
  438. // CAPGTSRegConnectorException
  439. ////////////////////////////////////////////////////////////////////////////////////
  440. void CAPGTSRegConnectorException::Log()
  441. {
  442. CString str;
  443. switch (eVariable)
  444. {
  445. case CAPGTSRegConnector::eResourcePath:
  446. case CAPGTSRegConnector::eVrootPath:
  447. case CAPGTSRegConnector::eMaxThreads:
  448. case CAPGTSRegConnector::eThreadsPP:
  449. case CAPGTSRegConnector::eMaxWQItems:
  450. case CAPGTSRegConnector::eCookieLife:
  451. case CAPGTSRegConnector::eReloadDelay:
  452. case CAPGTSRegConnector::eDetailedEventLogging:
  453. case CAPGTSRegConnector::eLogFilePath:
  454. case CAPGTSRegConnector::eSniffAutomatic:
  455. case CAPGTSRegConnector::eSniffManual:
  456. CAPGTSRegConnector::StringFromConnector(eVariable, str); break;
  457. case CAPGTSRegConnector::eProblemWithKey: str = _T("Can't open reg key"); break;
  458. case CAPGTSRegConnector::eProblemWithLogKey: str = _T("Can't open IIS reg key"); break;
  459. case CAPGTSRegConnector::eIndefinite: // falls through to default.
  460. default: str = _T("<Problem not specified>"); break;
  461. }
  462. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  463. CEvent::ReportWFEvent(GetSrcFileLineStr(),
  464. SrcLoc.GetSrcFileLineStr(),
  465. str,
  466. _T(""),
  467. TSERR_REG_READ_WRITE_PROBLEM);
  468. }