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.

3965 lines
91 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name :
  4. mdkeys.cpp
  5. Abstract:
  6. Metabase key wrapper class
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include "comprop.h"
  18. #include "idlg.h"
  19. #include "mdkeys.h"
  20. //
  21. // Constants
  22. //
  23. #define MB_TIMEOUT (15000) // Timeout in milliseconds
  24. #define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size
  25. //
  26. // CMetaInterface class
  27. //
  28. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  29. CMetaInterface::CMetaInterface(
  30. IN LPCTSTR lpszServerName OPTIONAL
  31. )
  32. /*++
  33. Routine Description:
  34. Construct and initialize the interface
  35. Arguments:
  36. LPCTSTR lpszServerName : Server name. NULL indicates the local computer
  37. Return Value:
  38. N/A
  39. --*/
  40. : m_pInterface(NULL),
  41. m_iTimeOutValue(MB_TIMEOUT),
  42. m_strServerName(),
  43. m_hrInterface(S_OK)
  44. {
  45. //
  46. // Initialize the interface
  47. //
  48. m_hrInterface = Create(lpszServerName);
  49. }
  50. CMetaInterface::CMetaInterface(
  51. IN const CMetaInterface * pInterface
  52. )
  53. /*++
  54. Routine Description:
  55. Construct from existing interface (Copy Constructor)
  56. Arguments:
  57. CMetaInterface * pInterface : Existing interface
  58. Return Value:
  59. N/A
  60. Notes:
  61. Object will not take ownership of the interface,
  62. it will merely add to the reference count, and
  63. release it upon destruction
  64. --*/
  65. : m_pInterface(pInterface->m_pInterface),
  66. m_iTimeOutValue(pInterface->m_iTimeOutValue),
  67. m_strServerName(pInterface->m_strServerName),
  68. m_hrInterface(pInterface->m_hrInterface)
  69. {
  70. ASSERT(m_pInterface != NULL);
  71. m_pInterface->AddRef();
  72. }
  73. CMetaInterface::~CMetaInterface()
  74. /*++
  75. Routine Description:
  76. Destructor -- releases the interface
  77. Arguments:
  78. N/A
  79. Return Value:
  80. N/A
  81. --*/
  82. {
  83. SAFE_RELEASE(m_pInterface);
  84. }
  85. /* protected */
  86. HRESULT
  87. CMetaInterface::Create(
  88. IN LPCTSTR lpszServerName OPTIONAL
  89. )
  90. /*++
  91. Routine Description:
  92. Create the interface with DCOM.
  93. Arguments:
  94. lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax.
  95. Could be NULL, in which case the local computer is used.
  96. Return Value:
  97. HRESULT
  98. Notes:
  99. This function is smart enough to substitute NULL if the server
  100. name provided is in fact the local computer name. Presumably,
  101. that's faster.
  102. --*/
  103. {
  104. COSERVERINFO * pcsiName = NULL;
  105. COSERVERINFO csiName;
  106. //
  107. // Be smart about the server name; optimize for local
  108. // computer name.
  109. //
  110. if (lpszServerName = ::NormalizeServerName(lpszServerName))
  111. {
  112. //
  113. // Create the COM server info for CoCreateInstanceEx
  114. //
  115. ::ZeroMemory(&csiName, sizeof(csiName));
  116. csiName.pwszName = (LPWSTR)lpszServerName;
  117. pcsiName = &csiName;
  118. }
  119. //
  120. // Query the MD COM interface
  121. //
  122. MULTI_QI rgmqResults[1];
  123. rgmqResults[0].pIID = &IID_IMSAdminBase;
  124. rgmqResults[0].pItf = NULL;
  125. rgmqResults[0].hr = 0;
  126. //
  127. // Create a instance of the object and get the interface
  128. //
  129. HRESULT hr = ::CoCreateInstanceEx(
  130. GETAdminBaseCLSID(TRUE),
  131. NULL,
  132. CLSCTX_SERVER,
  133. pcsiName,
  134. 1,
  135. rgmqResults
  136. );
  137. //
  138. // It failed, try with non-service MD
  139. //
  140. if (FAILED(hr))
  141. {
  142. //
  143. // inetinfo.exe run as user program
  144. //
  145. TRACEEOLID("Failed to create admin interface, second attempt");
  146. hr = ::CoCreateInstanceEx(
  147. GETAdminBaseCLSID(FALSE),
  148. NULL,
  149. CLSCTX_SERVER,
  150. pcsiName,
  151. 1,
  152. rgmqResults
  153. );
  154. }
  155. if(SUCCEEDED(hr))
  156. {
  157. //
  158. // Save the interface pointer
  159. //
  160. m_pInterface = (IMSAdminBase *)rgmqResults[0].pItf;
  161. ASSERT(m_pInterface != NULL);
  162. }
  163. if (lpszServerName && *lpszServerName)
  164. {
  165. m_strServerName = lpszServerName;
  166. }
  167. else
  168. {
  169. //
  170. // Use local computer name
  171. //
  172. DWORD dwSize = MAX_PATH;
  173. LPTSTR lpName = m_strServerName.GetBuffer(dwSize);
  174. GetComputerName(lpName, &dwSize);
  175. m_strServerName.ReleaseBuffer();
  176. }
  177. return hr;
  178. }
  179. HRESULT
  180. CMetaInterface::Regenerate()
  181. /*++
  182. Routine Description:
  183. Attempt to recreate the interface pointer. This assumes that the interface
  184. had been successfully created before, but has become invalid at some
  185. point afterwards.
  186. Arguments:
  187. None
  188. Return Value:
  189. HRESULT
  190. --*/
  191. {
  192. ASSERT(!m_strServerName.IsEmpty()); // Must've been initialized
  193. ASSERT(m_pInterface != NULL); // As above
  194. SAFE_RELEASE(m_pInterface);
  195. m_hrInterface = Create(m_strServerName);
  196. return m_hrInterface;
  197. }
  198. /* virtual */
  199. BOOL
  200. CMetaInterface::Succeeded() const
  201. /*++
  202. Routine Description:
  203. Determine if object was constructed successfully.
  204. Arguments:
  205. None
  206. Return Value:
  207. TRUE for success, FALSE for failure
  208. --*/
  209. {
  210. return SUCCEEDED(m_hrInterface);
  211. }
  212. /* virtual */
  213. HRESULT
  214. CMetaInterface::QueryResult() const
  215. /*++
  216. Routine Description:
  217. Return the construction error for this object.
  218. Arguments:
  219. None
  220. Return Value:
  221. HRESULT from construction errors
  222. --*/
  223. {
  224. return m_hrInterface;
  225. }
  226. //
  227. // CWamInterface class
  228. //
  229. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  230. CWamInterface::CWamInterface(
  231. IN LPCTSTR lpszServerName OPTIONAL
  232. )
  233. /*++
  234. Routine Description:
  235. Construct and initialize the interface.
  236. Arguments:
  237. LPCTSTR lpszServerName : Server name, use NULL to indicate the local
  238. computer name.
  239. Return Value:
  240. N/A
  241. --*/
  242. : m_pInterface(NULL),
  243. m_strServerName(),
  244. m_fSupportsPooledProc(FALSE),
  245. m_hrInterface(S_OK)
  246. {
  247. //
  248. // Initialize the interface
  249. //
  250. m_hrInterface = Create(lpszServerName);
  251. }
  252. CWamInterface::CWamInterface(
  253. IN const CWamInterface * pInterface
  254. )
  255. /*++
  256. Routine Description:
  257. Construct from existing interface (copy constructor)
  258. Arguments:
  259. CWamInterface * pInterface : Existing interface
  260. Return Value:
  261. N/A
  262. --*/
  263. : m_pInterface(pInterface->m_pInterface),
  264. m_strServerName(pInterface->m_strServerName),
  265. m_fSupportsPooledProc(FALSE),
  266. m_hrInterface(pInterface->m_hrInterface)
  267. {
  268. ASSERT(m_pInterface != NULL);
  269. m_pInterface->AddRef();
  270. }
  271. CWamInterface::~CWamInterface()
  272. /*++
  273. Routine Description:
  274. Destructor -- releases the interface.
  275. Arguments:
  276. N/A
  277. Return Value:
  278. N/A
  279. --*/
  280. {
  281. SAFE_RELEASE(m_pInterface);
  282. }
  283. /* protected */
  284. HRESULT
  285. CWamInterface::Create(
  286. IN LPCTSTR lpszServerName OPTIONAL
  287. )
  288. /*++
  289. Routine Description:
  290. Create the interface with DCOM
  291. Arguments:
  292. lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax.
  293. Could be NULL, in which case the local computer is used.
  294. Return Value:
  295. HRESULT
  296. Notes:
  297. This function is smart enough to substitute NULL if the server
  298. name provided is in fact the local computer name. Presumably,
  299. that's faster.
  300. First, it will attempt to create the new interface, if it
  301. fails, it will attempt to create the downlevel interface
  302. --*/
  303. {
  304. COSERVERINFO * pcsiName = NULL;
  305. COSERVERINFO csiName;
  306. //
  307. // Be smart about the server name; optimize for local
  308. // computer name.
  309. //
  310. if (lpszServerName = ::NormalizeServerName(lpszServerName))
  311. {
  312. //
  313. // Create the COM server info for CoCreateInstanceEx
  314. //
  315. ::ZeroMemory(&csiName, sizeof(csiName));
  316. csiName.pwszName = (LPWSTR)lpszServerName;
  317. pcsiName = &csiName;
  318. }
  319. //
  320. // First try to do the new interface
  321. //
  322. MULTI_QI rgmqResults[1];
  323. rgmqResults[0].pIID = &IID_IWamAdmin2;
  324. rgmqResults[0].pItf = NULL;
  325. rgmqResults[0].hr = 0;
  326. //
  327. // Create a instance of the object and get the interface
  328. //
  329. HRESULT hr = ::CoCreateInstanceEx(
  330. CLSID_WamAdmin,
  331. NULL,
  332. CLSCTX_SERVER,
  333. pcsiName,
  334. 1,
  335. rgmqResults
  336. );
  337. m_fSupportsPooledProc = SUCCEEDED(hr);
  338. if (hr == E_NOINTERFACE)
  339. {
  340. //
  341. // Attempt to create the downlevel version
  342. //
  343. TRACEEOLID("Attempting downlevel WAM interface");
  344. rgmqResults[0].pIID = &IID_IWamAdmin;
  345. hr = ::CoCreateInstanceEx(
  346. CLSID_WamAdmin,
  347. NULL,
  348. CLSCTX_SERVER,
  349. pcsiName,
  350. 1,
  351. rgmqResults
  352. );
  353. }
  354. if(SUCCEEDED(hr))
  355. {
  356. //
  357. // Save the interface pointer
  358. //
  359. m_pInterface = (IWamAdmin *)rgmqResults[0].pItf;
  360. ASSERT(m_pInterface != NULL);
  361. }
  362. if (lpszServerName && *lpszServerName)
  363. {
  364. m_strServerName = lpszServerName;
  365. }
  366. else
  367. {
  368. //
  369. // Use local computer name
  370. //
  371. DWORD dwSize = MAX_PATH;
  372. LPTSTR lpName = m_strServerName.GetBuffer(dwSize);
  373. GetComputerName(lpName, &dwSize);
  374. m_strServerName.ReleaseBuffer();
  375. }
  376. return hr;
  377. }
  378. /* virtual */
  379. BOOL
  380. CWamInterface::Succeeded() const
  381. /*++
  382. Routine Description:
  383. Determine if object was constructed successfully
  384. Arguments:
  385. None
  386. Return Value:
  387. TRUE for success, FALSE for failure
  388. --*/
  389. {
  390. return SUCCEEDED(m_hrInterface);
  391. }
  392. /* virtual */
  393. HRESULT
  394. CWamInterface::QueryResult() const
  395. /*++
  396. Routine Description:
  397. Return the construction error for this object
  398. Arguments:
  399. None
  400. Return Value:
  401. HRESULT from construction errors
  402. --*/
  403. {
  404. return m_hrInterface;
  405. }
  406. HRESULT
  407. CWamInterface::AppCreate(
  408. IN LPCTSTR szMDPath,
  409. IN DWORD dwAppProtection
  410. )
  411. /*++
  412. Routine Description:
  413. Create application
  414. Arguments:
  415. LPCTSTR szMDPath : Metabase path
  416. DWORD dwAppProtection : APP_INPROC to create in-proc app
  417. APP_OUTOFPROC to create out-of-proc app
  418. APP_POOLEDPROC to create a pooled-proc app
  419. Return Value:
  420. HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested)
  421. --*/
  422. {
  423. if (m_fSupportsPooledProc)
  424. {
  425. //
  426. // Interface pointer is really IWamAdmin2, so call the new method
  427. //
  428. return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection);
  429. }
  430. //
  431. // Call the downlevel API
  432. //
  433. if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC)
  434. {
  435. BOOL fInProc = (dwAppProtection == APP_INPROC);
  436. ASSERT(m_pInterface != NULL);
  437. return m_pInterface->AppCreate(szMDPath, fInProc);
  438. }
  439. return CError(ERROR_INVALID_PARAMETER);
  440. }
  441. //
  442. // CMetaback Class
  443. //
  444. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  445. const LPCTSTR CMetaBack::s_szMasterAppRoot =\
  446. SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB;
  447. CMetaBack::CMetaBack(
  448. IN LPCTSTR lpszServerName OPTIONAL
  449. )
  450. /*++
  451. Routine Description:
  452. Constructor for metabase backup/restore operations class. This object
  453. is both a WAM interface and a METABASE interface.
  454. Arguments:
  455. LPCTSTR lpszServerName : Server name. Use NULL to indicate the local
  456. computer name.
  457. Return Value:
  458. N/A
  459. --*/
  460. : m_dwIndex(0),
  461. CMetaInterface(lpszServerName),
  462. CWamInterface(lpszServerName)
  463. {
  464. }
  465. /* virtual */
  466. BOOL
  467. CMetaBack::Succeeded() const
  468. /*++
  469. Routine Description:
  470. Determine if object was constructed successfully.
  471. Arguments:
  472. None
  473. Return Value:
  474. TRUE for success, FALSE for failure
  475. --*/
  476. {
  477. return CMetaInterface::Succeeded() && CWamInterface::Succeeded();
  478. }
  479. /* virtual */
  480. HRESULT
  481. CMetaBack::QueryResult() const
  482. /*++
  483. Routine Description:
  484. Return the construction error for this object
  485. Arguments:
  486. None
  487. Return Value:
  488. HRESULT from construction errors
  489. --*/
  490. {
  491. //
  492. // Both interfaces must have constructed successfully
  493. //
  494. HRESULT hr = CMetaInterface::QueryResult();
  495. if (SUCCEEDED(hr))
  496. {
  497. hr = CWamInterface::QueryResult();
  498. }
  499. return hr;
  500. }
  501. HRESULT
  502. CMetaBack::Restore(
  503. IN LPCTSTR lpszLocation,
  504. IN DWORD dwVersion
  505. )
  506. /*++
  507. Routine Description:
  508. Restore metabase
  509. Arguments:
  510. DWORD dwVersion : Backup version
  511. LPCTSTR lpszLocation : Backup location
  512. Return Value:
  513. HRESULT
  514. --*/
  515. {
  516. //
  517. // Backup and restore the application information from a restore
  518. //
  519. CString strPath(s_szMasterAppRoot);
  520. HRESULT hr = AppDeleteRecoverable(strPath, TRUE);
  521. if (SUCCEEDED(hr))
  522. {
  523. hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0);
  524. if (SUCCEEDED(hr))
  525. {
  526. hr = AppRecover(strPath, TRUE);
  527. }
  528. }
  529. return hr;
  530. }
  531. HRESULT
  532. CMetaBack::BackupWithPassword(
  533. IN LPCTSTR lpszLocation,
  534. IN LPCTSTR lpszPassword
  535. )
  536. {
  537. return CMetaInterface::BackupWithPassword(
  538. lpszLocation,
  539. MD_BACKUP_NEXT_VERSION,
  540. MD_BACKUP_SAVE_FIRST,
  541. lpszPassword
  542. );
  543. }
  544. HRESULT
  545. CMetaBack::RestoreWithPassword(
  546. IN LPCTSTR lpszLocation,
  547. IN DWORD dwVersion,
  548. IN LPCTSTR lpszPassword
  549. )
  550. /*++
  551. Routine Description:
  552. Restore metabase
  553. Arguments:
  554. DWORD dwVersion : Backup version
  555. LPCTSTR lpszLocation : Backup location
  556. LPCTSTR lpszPassword : Backup password
  557. Return Value:
  558. HRESULT
  559. --*/
  560. {
  561. //
  562. // Backup and restore the application information from a restore
  563. //
  564. CString strPath(s_szMasterAppRoot);
  565. HRESULT hr = AppDeleteRecoverable(strPath, TRUE);
  566. if (SUCCEEDED(hr))
  567. {
  568. hr = CMetaInterface::RestoreWithPassword(lpszLocation, dwVersion, 0, lpszPassword);
  569. if (SUCCEEDED(hr))
  570. {
  571. hr = AppRecover(strPath, TRUE);
  572. }
  573. }
  574. return hr;
  575. }
  576. //
  577. // CIISSvcControl class
  578. //
  579. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  580. CIISSvcControl::CIISSvcControl(
  581. IN LPCTSTR lpszServerName OPTIONAL
  582. )
  583. /*++
  584. Routine Description:
  585. Construct and initialize the interface.
  586. Arguments:
  587. LPCTSTR lpszServerName : Server name, use NULL to indicate the local
  588. computer name.
  589. Return Value:
  590. N/A
  591. --*/
  592. : m_pInterface(NULL),
  593. m_strServerName(),
  594. m_hrInterface(S_OK)
  595. {
  596. //
  597. // Initialize the interface
  598. //
  599. m_hrInterface = Create(lpszServerName);
  600. }
  601. CIISSvcControl::CIISSvcControl(
  602. IN const CIISSvcControl * pInterface
  603. )
  604. /*++
  605. Routine Description:
  606. Construct from existing interface (copy constructor)
  607. Arguments:
  608. CIISSvcControl * pInterface : Existing interface
  609. Return Value:
  610. N/A
  611. --*/
  612. : m_pInterface(pInterface->m_pInterface),
  613. m_strServerName(pInterface->m_strServerName),
  614. m_hrInterface(pInterface->m_hrInterface)
  615. {
  616. ASSERT(m_pInterface != NULL);
  617. m_pInterface->AddRef();
  618. }
  619. CIISSvcControl::~CIISSvcControl()
  620. /*++
  621. Routine Description:
  622. Destructor -- releases the interface.
  623. Arguments:
  624. N/A
  625. Return Value:
  626. N/A
  627. --*/
  628. {
  629. SAFE_RELEASE(m_pInterface);
  630. }
  631. /* protected */
  632. HRESULT
  633. CIISSvcControl::Create(
  634. IN LPCTSTR lpszServerName OPTIONAL
  635. )
  636. /*++
  637. Routine Description:
  638. Create the interface with DCOM
  639. Arguments:
  640. lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax.
  641. Could be NULL, in which case the local computer is used.
  642. Return Value:
  643. HRESULT
  644. Notes:
  645. This function is smart enough to substitute NULL if the server
  646. name provided is in fact the local computer name. Presumably,
  647. that's faster.
  648. --*/
  649. {
  650. COSERVERINFO * pcsiName = NULL;
  651. COSERVERINFO csiName;
  652. //
  653. // Be smart about the server name; optimize for local
  654. // computer name.
  655. //
  656. if (lpszServerName = ::NormalizeServerName(lpszServerName))
  657. {
  658. //
  659. // Create the COM server info for CoCreateInstanceEx
  660. //
  661. ::ZeroMemory(&csiName, sizeof(csiName));
  662. csiName.pwszName = (LPWSTR)lpszServerName;
  663. pcsiName = &csiName;
  664. }
  665. //
  666. // Query the MD COM interface
  667. //
  668. MULTI_QI rgmqResults[1];
  669. rgmqResults[0].pIID = &IID_IIisServiceControl;
  670. rgmqResults[0].pItf = NULL;
  671. rgmqResults[0].hr = 0;
  672. //
  673. // Create a instance of the object and get the interface
  674. //
  675. HRESULT hr = ::CoCreateInstanceEx(
  676. CLSID_IisServiceControl,
  677. NULL,
  678. CLSCTX_SERVER,
  679. pcsiName,
  680. 1,
  681. rgmqResults
  682. );
  683. if(SUCCEEDED(hr))
  684. {
  685. //
  686. // Save the interface pointer
  687. //
  688. m_pInterface = (IIisServiceControl *)rgmqResults[0].pItf;
  689. ASSERT(m_pInterface != NULL);
  690. }
  691. if (lpszServerName && *lpszServerName)
  692. {
  693. m_strServerName = lpszServerName;
  694. }
  695. else
  696. {
  697. //
  698. // Use local computer name
  699. //
  700. DWORD dwSize = MAX_PATH;
  701. LPTSTR lpName = m_strServerName.GetBuffer(dwSize);
  702. GetComputerName(lpName, &dwSize);
  703. m_strServerName.ReleaseBuffer();
  704. }
  705. return hr;
  706. }
  707. /* virtual */
  708. BOOL
  709. CIISSvcControl::Succeeded() const
  710. /*++
  711. Routine Description:
  712. Determine if object was constructed successfully
  713. Arguments:
  714. None
  715. Return Value:
  716. TRUE for success, FALSE for failure
  717. --*/
  718. {
  719. return SUCCEEDED(m_hrInterface);
  720. }
  721. /* virtual */
  722. HRESULT
  723. CIISSvcControl::QueryResult() const
  724. /*++
  725. Routine Description:
  726. Return the construction error for this object
  727. Arguments:
  728. None
  729. Return Value:
  730. HRESULT from construction errors
  731. --*/
  732. {
  733. return m_hrInterface;
  734. }
  735. //
  736. // CMetaKey class
  737. //
  738. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  739. //
  740. // Helper macros
  741. //
  742. #define ASSURE_PROPER_INTERFACE()\
  743. if (!HasInterface()) { ASSERT(FALSE); return MD_ERROR_NOT_INITIALIZED; }
  744. #define ASSURE_OPEN_KEY()\
  745. if (!m_hKey && !m_fAllowRootOperations) { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); }
  746. #define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\
  747. ZeroMemory(&md, sizeof(md)); \
  748. if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\
  749. { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); }
  750. //
  751. // Static Initialization
  752. //
  753. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  754. const LPCTSTR CMetaKey::s_cszCompression =
  755. SZ_MBN_FILTERS SZ_MBN_SEP_STR SZ_MBN_COMPRESSION;
  756. const LPCTSTR CMetaKey::s_cszMachine = SZ_MBN_MACHINE;
  757. const LPCTSTR CMetaKey::s_cszMimeMap = SZ_MBN_MIMEMAP;
  758. const LPCTSTR CMetaKey::s_cszRoot = SZ_MBN_ROOT;
  759. const LPCTSTR CMetaKey::s_cszSep = SZ_MBN_SEP_STR;
  760. const LPCTSTR CMetaKey::s_cszInfo = SZ_MBN_INFO;
  761. const TCHAR CMetaKey::s_chSep = SZ_MBN_SEP_CHAR;
  762. //
  763. // Metabase table
  764. //
  765. const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] =
  766. {
  767. //
  768. // !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (will
  769. // be verified in the debug version)
  770. //
  771. { MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  772. { MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  773. { MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  774. { MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT },
  775. { MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS },
  776. { MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT },
  777. { MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  778. { MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  779. { MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE },
  780. { MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG },
  781. { MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT },
  782. { MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  783. { MD_WIN32_ERROR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  784. { MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  785. { MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  786. { MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  787. { MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  788. { MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  789. { MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  790. { MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  791. { MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  792. { MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  793. { MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  794. { MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  795. { MD_NET_LOGON_WKS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  796. { MD_USE_HOST_NAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  797. { MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  798. { MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  799. { MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  800. { MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  801. { MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  802. { MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  803. { MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  804. { MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  805. { MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  806. { MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  807. { MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  808. { MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  809. { MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  810. { MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  811. { MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  812. { MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  813. { MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  814. { MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  815. { MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  816. { MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME },
  817. { MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT },
  818. { MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED },
  819. { MD_CPU_LIMITS_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMITS_ENABLED },
  820. { MD_CPU_LIMIT_LOGEVENT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_LOGEVENT },
  821. { MD_CPU_LIMIT_PRIORITY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PRIORITY },
  822. { MD_CPU_LIMIT_PROCSTOP, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PROCSTOP },
  823. { MD_CPU_LIMIT_PAUSE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PAUSE },
  824. { MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  825. { MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  826. { MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  827. { MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  828. { MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  829. { MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH },
  830. { MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME },
  831. { MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD },
  832. { MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 },
  833. { MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  834. { MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE },
  835. { MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGFILE_DIRECTORY },
  836. { MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD },
  837. { MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE },
  838. { MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES },
  839. { MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME },
  840. { MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME },
  841. { MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD },
  842. { MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER },
  843. { MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK },
  844. { MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER },
  845. { MD_CPU_LOGGING_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LOGGING_MASK },
  846. { MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE },
  847. { MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE },
  848. { MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE },
  849. { MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT },
  850. { MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS },
  851. { MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY },
  852. { MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS },
  853. { MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS },
  854. { MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  855. { MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  856. { MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  857. { MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  858. { MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  859. { MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  860. { MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  861. { MD_SSL_USE_DS_MAPPER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  862. { MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION },
  863. { MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM },
  864. { MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES },
  865. { MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS },
  866. { MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM },
  867. { MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING },
  868. { MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE },
  869. { MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION },
  870. { MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR },
  871. { MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT },
  872. { MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED },
  873. { MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT },
  874. { MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN },
  875. { MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD },
  876. { MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS },
  877. { MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP },
  878. { MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM },
  879. { MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC },
  880. { MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME },
  881. { MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD },
  882. { MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH },
  883. { MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG },
  884. { MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL },
  885. { MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED },
  886. { MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM },
  887. { MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS },
  888. { MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT },
  889. { MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS },
  890. { MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER },
  891. { MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE },
  892. { MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT },
  893. { MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES },
  894. { MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED },
  895. { MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  896. { MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON },
  897. { MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS },
  898. { MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER },
  899. { MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE },
  900. { MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE },
  901. { MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX },
  902. { MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT },
  903. { MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT },
  904. { MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS },
  905. { MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE },
  906. { MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE },
  907. { MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE },
  908. { MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG },
  909. { MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG },
  910. };
  911. #define NUM_ENTRIES (sizeof(CMetaKey::s_rgMetaTable) / sizeof(CMetaKey::s_rgMetaTable[0]))
  912. /* static */
  913. int
  914. CMetaKey::MapMDIDToTableIndex(
  915. IN DWORD dwID
  916. )
  917. /*++
  918. Routine Description:
  919. Map MD id value to table index. Return -1 if not found
  920. Arguments:
  921. DWORD dwID : MD id value
  922. Return Value:
  923. Index into the table that coresponds to the MD id value
  924. --*/
  925. {
  926. #ifdef _DEBUG
  927. {
  928. //
  929. // Do a quick verification that our metadata
  930. // table is sorted correctly.
  931. //
  932. static BOOL fTableChecked = FALSE;
  933. if (!fTableChecked)
  934. {
  935. for (int n = 1; n < NUM_ENTRIES; ++n)
  936. {
  937. if (s_rgMetaTable[n].dwMDIdentifier
  938. <= s_rgMetaTable[n - 1].dwMDIdentifier)
  939. {
  940. TRACEEOLID("MD ID Table is out of order: Item is "
  941. << n
  942. << " "
  943. << s_rgMetaTable[n].dwMDIdentifier
  944. );
  945. ASSERT(FALSE);
  946. }
  947. }
  948. //
  949. // But only once.
  950. //
  951. ++fTableChecked;
  952. }
  953. }
  954. #endif // _DEBUG
  955. //
  956. // Look up the ID in the table using a binary search
  957. //
  958. int nRange = NUM_ENTRIES;
  959. int nLow = 0;
  960. int nHigh = nRange - 1;
  961. int nMid;
  962. int nHalf;
  963. while (nLow <= nHigh)
  964. {
  965. if (nHalf = nRange / 2)
  966. {
  967. nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1));
  968. if (s_rgMetaTable[nMid].dwMDIdentifier == dwID)
  969. {
  970. return nMid;
  971. }
  972. else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID)
  973. {
  974. nHigh = --nMid;
  975. nRange = nRange & 1 ? nHalf : nHalf - 1;
  976. }
  977. else
  978. {
  979. nLow = ++nMid;
  980. nRange = nHalf;
  981. }
  982. }
  983. else if (nRange)
  984. {
  985. return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1;
  986. }
  987. else
  988. {
  989. break;
  990. }
  991. }
  992. return -1;
  993. }
  994. /* static */
  995. BOOL
  996. CMetaKey::GetMDFieldDef(
  997. IN DWORD dwID,
  998. OUT DWORD & dwMDIdentifier,
  999. OUT DWORD & dwMDAttributes,
  1000. OUT DWORD & dwMDUserType,
  1001. OUT DWORD & dwMDDataType
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. Get information about metabase property
  1006. Arguments:
  1007. DWORD dwID : Meta ID
  1008. DWORD & dwMDIdentifier : Meta parms
  1009. DWORD & dwMDAttributes : Meta parms
  1010. DWORD & dwMDUserType : Meta parms
  1011. DWORD & dwMDDataType : Meta parms
  1012. Return Value:
  1013. TRUE for success, FALSE for failure.
  1014. --*/
  1015. {
  1016. int nID = MapMDIDToTableIndex(dwID);
  1017. if (nID == -1)
  1018. {
  1019. //
  1020. // Unrecognized meta data ID
  1021. //
  1022. ASSERT(FALSE);
  1023. return FALSE;
  1024. }
  1025. dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier;
  1026. dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes;
  1027. dwMDUserType = s_rgMetaTable[nID].dwMDUserType;
  1028. dwMDDataType = s_rgMetaTable[nID].dwMDDataType;
  1029. return TRUE;
  1030. }
  1031. /* static */
  1032. BOOL
  1033. CMetaKey::IsPropertyInheritable(
  1034. IN DWORD dwID
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. Check to see if the given property is inheritable
  1039. Arguments:
  1040. DWORD dwID : Metabase ID
  1041. Return Value:
  1042. TRUE if the metabase ID is inheritable, FALSE otherwise.
  1043. --*/
  1044. {
  1045. int nID = MapMDIDToTableIndex(dwID);
  1046. if (nID == -1)
  1047. {
  1048. //
  1049. // Unrecognized meta data ID
  1050. //
  1051. ASSERT(FALSE);
  1052. return FALSE;
  1053. }
  1054. return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0;
  1055. }
  1056. /* static */
  1057. BOOL
  1058. CMetaKey::GetPropertyDescription(
  1059. IN DWORD dwID,
  1060. OUT CString & strName
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. Get a description for the given property
  1065. Arguments:
  1066. DWORD dwID : Property ID
  1067. CString & strName : Returns friendly property name
  1068. Return Value:
  1069. TRUE for success, FALSE for failure
  1070. --*/
  1071. {
  1072. int nID = MapMDIDToTableIndex(dwID);
  1073. if (nID == -1)
  1074. {
  1075. //
  1076. // Unrecognized meta data ID
  1077. //
  1078. ASSERT(FALSE);
  1079. return FALSE;
  1080. }
  1081. UINT uID = s_rgMetaTable[nID].uStringID;
  1082. #ifndef _COMSTATIC
  1083. HINSTANCE hOld = ::AfxGetResourceHandle();
  1084. ::AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME));
  1085. #endif // _COMSTATIC
  1086. BOOL fResult = TRUE;
  1087. if (uID > 0)
  1088. {
  1089. fResult = (strName.LoadString(uID) != 0);
  1090. }
  1091. else
  1092. {
  1093. //
  1094. // Don't have a friendly name -- fake it
  1095. //
  1096. CString strFmt;
  1097. VERIFY(strFmt.LoadString(IDS_INHERITANCE_NO_NAME));
  1098. strName.Format(strFmt, dwID);
  1099. }
  1100. #ifndef _COMSTATIC
  1101. ::AfxSetResourceHandle(hOld);
  1102. #endif // _COMSTATIC
  1103. return fResult;
  1104. }
  1105. /* static */
  1106. void
  1107. CMetaKey::SplitMetaPath(
  1108. IN LPCTSTR lpPath,
  1109. OUT CString & strParent,
  1110. OUT CString & strAlias
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. Split the given path into parent metabase root and alias
  1115. Arguments:
  1116. LPCTSTR lpPath : Input path
  1117. CString & strParent : Outputs the parent path
  1118. CString & strAlias : Outputs the alias name
  1119. Return Value:
  1120. None.
  1121. --*/
  1122. {
  1123. TRACEEOLID("Source Path " << lpPath);
  1124. strParent = lpPath;
  1125. strAlias.Empty();
  1126. int cSlash = strParent.ReverseFind(g_chSep);
  1127. ASSERT(cSlash >= 0);
  1128. if (cSlash >= 0)
  1129. {
  1130. strAlias = strParent.Mid(++cSlash);
  1131. strParent.ReleaseBuffer(--cSlash);
  1132. }
  1133. TRACEEOLID("Broken up into " << strParent);
  1134. TRACEEOLID(" and " << strAlias);
  1135. }
  1136. /* static */
  1137. void
  1138. CMetaKey::SplitMetaPathAtInstance(
  1139. IN LPCTSTR lpPath,
  1140. OUT CString & strParent,
  1141. OUT CString & strAlias
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. Split the given path into parent metabase root and alias, with the root
  1146. being the instance path, and the alias everything following the
  1147. instance.
  1148. Arguments:
  1149. LPCTSTR lpPath : Input path
  1150. CString & strParent : Outputs the parent path
  1151. CString & strAlias : Outputs the alias name
  1152. Return Value:
  1153. None.
  1154. --*/
  1155. {
  1156. TRACEEOLID("Source Path " << lpPath);
  1157. strParent = lpPath;
  1158. strAlias.Empty();
  1159. LPTSTR lp = strParent.GetBuffer(0);
  1160. ASSERT(lp);
  1161. int cSeparators = 0;
  1162. int iChar = 0;
  1163. //
  1164. // Looking for "LM/sss/ddd/" <-- 3d slash:
  1165. //
  1166. while (*lp && cSeparators < 2)
  1167. {
  1168. if (*lp++ == g_chSep)
  1169. {
  1170. ++cSeparators;
  1171. }
  1172. ++iChar;
  1173. }
  1174. if (!*lp)
  1175. {
  1176. //
  1177. // Bogus format
  1178. //
  1179. ASSERT(FALSE);
  1180. return;
  1181. }
  1182. if (_istdigit(*lp))
  1183. {
  1184. //
  1185. // Not at the master instance, skip one more.
  1186. //
  1187. while (*lp)
  1188. {
  1189. ++iChar;
  1190. if (*lp++ == g_chSep)
  1191. {
  1192. break;
  1193. }
  1194. }
  1195. if (!*lp)
  1196. {
  1197. //
  1198. // Bogus format
  1199. //
  1200. ASSERT(FALSE);
  1201. return;
  1202. }
  1203. }
  1204. strAlias = strParent.Mid(iChar);
  1205. strParent.ReleaseBuffer(--iChar);
  1206. TRACEEOLID("Broken up into " << strParent);
  1207. TRACEEOLID(" and " << strAlias);
  1208. }
  1209. /* static */
  1210. LPCTSTR
  1211. CMetaKey::BuildMetaPath(
  1212. OUT CString & strPath,
  1213. IN LPCTSTR lpSvc OPTIONAL,
  1214. IN DWORD dwInstance OPTIONAL,
  1215. IN LPCTSTR lpParentPath OPTIONAL,
  1216. IN LPCTSTR lpAlias OPTIONAL
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. Build a complete metapath with the given service name, instance
  1221. number and optional path components.
  1222. Arguments:
  1223. CString & strPath : Destination path
  1224. LPCTSTR lpSvc : Service (may be NULL or "")
  1225. DWORD dwInstance : Instance number (may be 0 for master)
  1226. LPCTSTR lpParentPath : Parent path (may be NULL or "")
  1227. LPCTSTR lpAlias : Alias (may be NULL or "")
  1228. Return Value:
  1229. Pointer to internal buffer containing the path.
  1230. --*/
  1231. {
  1232. try
  1233. {
  1234. strPath = s_cszMachine;
  1235. if (lpSvc && *lpSvc)
  1236. {
  1237. strPath += s_cszSep;
  1238. strPath += lpSvc;
  1239. }
  1240. ASSERT(dwInstance >= 0);
  1241. if (dwInstance != MASTER_INSTANCE)
  1242. {
  1243. TCHAR szInstance[] = _T("4000000000");
  1244. strPath += s_cszSep;
  1245. _ltot(dwInstance, szInstance, 10);
  1246. strPath += szInstance;
  1247. }
  1248. if (lpParentPath && *lpParentPath)
  1249. {
  1250. strPath += s_cszSep;
  1251. strPath += lpParentPath;
  1252. }
  1253. if (lpAlias && *lpAlias)
  1254. {
  1255. //
  1256. // Special case: If the alias is root, but we're
  1257. // at the master instance, ignore this.
  1258. //
  1259. if (dwInstance != MASTER_INSTANCE ||
  1260. lstrcmpi(s_cszRoot, lpAlias) != 0)
  1261. {
  1262. strPath += s_cszSep;
  1263. strPath += lpAlias;
  1264. }
  1265. }
  1266. TRACEEOLID("Generated metapath: " << strPath);
  1267. }
  1268. catch(CMemoryException * e)
  1269. {
  1270. strPath.Empty();
  1271. e->ReportError();
  1272. e->Delete();
  1273. }
  1274. return strPath;
  1275. }
  1276. /* static */
  1277. LPCTSTR
  1278. CMetaKey::ConvertToParentPath(
  1279. OUT IN CString & strMetaPath
  1280. )
  1281. /*++
  1282. Routine Description:
  1283. Given the path, convert it to the parent path
  1284. e.g. "foo/bar/etc" returns "foo/bar"
  1285. Arguments:
  1286. CString & strMetaPath : Path to be converted
  1287. Return value:
  1288. Pointer to the converted path, or NULL in case of error
  1289. --*/
  1290. {
  1291. TRACEEOLID("Getting parent path of " << strMetaPath);
  1292. LPTSTR lpszPath = strMetaPath.GetBuffer(1);
  1293. LPTSTR lpszTail = lpszPath + lstrlen(lpszPath) - 1;
  1294. LPTSTR lpszReturn = NULL;
  1295. do
  1296. {
  1297. if (lpszTail <= lpszPath)
  1298. {
  1299. break;
  1300. }
  1301. //
  1302. // Strip trailing backslash
  1303. //
  1304. if (*lpszTail == s_chSep)
  1305. {
  1306. *lpszTail-- = _T('\0');
  1307. }
  1308. //
  1309. // Search for parent
  1310. //
  1311. while (lpszTail > lpszPath && *lpszTail != s_chSep)
  1312. {
  1313. --lpszTail;
  1314. }
  1315. if (lpszTail <= lpszPath)
  1316. {
  1317. break;
  1318. }
  1319. *lpszTail = _T('\0');
  1320. lpszReturn = lpszPath;
  1321. }
  1322. while(FALSE);
  1323. strMetaPath.ReleaseBuffer();
  1324. TRACEEOLID("Parent path should be " << strMetaPath);
  1325. return lpszReturn;
  1326. }
  1327. /* static */
  1328. void
  1329. CMetaKey::ConvertToParentPath(
  1330. IN OUT CString & strService,
  1331. IN OUT DWORD & dwInstance,
  1332. IN OUT CString & strParent,
  1333. IN OUT CString & strAlias
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. Change the input parameters so that they are valid
  1338. for the immediate parent of the path described
  1339. Arguments:
  1340. CString & strService : Service name
  1341. DWORD & dwInstance : Instance number
  1342. CString & strParent : Parent path
  1343. CString & strAlias : Node name
  1344. Return Value:
  1345. None
  1346. --*/
  1347. {
  1348. if (!strAlias.IsEmpty())
  1349. {
  1350. strAlias.Empty();
  1351. }
  1352. else
  1353. {
  1354. if (!strParent.IsEmpty())
  1355. {
  1356. int nSep = strParent.ReverseFind(g_chSep);
  1357. if (nSep >= 0)
  1358. {
  1359. strParent.ReleaseBuffer(nSep);
  1360. }
  1361. else
  1362. {
  1363. strParent.Empty();
  1364. }
  1365. }
  1366. else
  1367. {
  1368. if (dwInstance != MASTER_INSTANCE)
  1369. {
  1370. dwInstance = MASTER_INSTANCE;
  1371. }
  1372. else
  1373. {
  1374. strService.Empty();
  1375. }
  1376. }
  1377. }
  1378. }
  1379. /* static */
  1380. BOOL
  1381. CMetaKey::IsHomeDirectoryPath(
  1382. IN LPCTSTR lpszMetaPath
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. Determine if the path given describes a root directory
  1387. Arguments:
  1388. LPCTSTR lpszMetaPath : Metabase path
  1389. Return Value:
  1390. TRUE if the path describes a root directory,
  1391. FALSE if it does not
  1392. --*/
  1393. {
  1394. ASSERT(lpszMetaPath != NULL);
  1395. LPTSTR lpNode = _tcsrchr(lpszMetaPath, s_chSep);
  1396. if (lpNode)
  1397. {
  1398. return _tcsicmp(++lpNode, g_cszRoot) == 0;
  1399. }
  1400. return FALSE;
  1401. }
  1402. /* static */
  1403. LPCTSTR
  1404. CMetaKey::CleanMetaPath(
  1405. IN OUT CString & strMetaRoot
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. Clean up the metabase path to one valid for internal consumption.
  1410. This removes the beginning and trailing slashes off the path
  1411. Arguments:
  1412. CString & strMetaRoot : Metabase path to be cleaned up.
  1413. Return Value:
  1414. Pointer to the metabase path
  1415. --*/
  1416. {
  1417. TRACEEOLID("Dirty metapath: " << strMetaRoot);
  1418. if (!strMetaRoot.IsEmpty())
  1419. {
  1420. if (strMetaRoot[strMetaRoot.GetLength() - 1] == SZ_MBN_SEP_CHAR)
  1421. {
  1422. strMetaRoot.ReleaseBuffer(strMetaRoot.GetLength() - 1);
  1423. }
  1424. if (strMetaRoot[0] == SZ_MBN_SEP_CHAR)
  1425. {
  1426. strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1);
  1427. }
  1428. }
  1429. TRACEEOLID("Clean metapath: " << strMetaRoot);
  1430. return strMetaRoot;
  1431. }
  1432. CMetaKey::CMetaKey(
  1433. IN LPCTSTR lpszServerName OPTIONAL
  1434. )
  1435. /*++
  1436. Routine Description:
  1437. Constructor that creates the interface, but does not open the key.
  1438. This is the ONLY constructor that allows operations from
  1439. METDATA_MASTER_ROOT_HANDLE (read operations obviously)
  1440. Arguments:
  1441. LPCTSTR lpszServerName : If NULL, opens interface on local machine
  1442. Return Value:
  1443. N/A
  1444. --*/
  1445. : CMetaInterface(lpszServerName),
  1446. m_hKey(METADATA_MASTER_ROOT_HANDLE),
  1447. m_hBase(NULL),
  1448. m_hrKey(S_OK),
  1449. m_dwFlags(0L),
  1450. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1451. m_strMetaPath(),
  1452. m_fAllowRootOperations(TRUE),
  1453. m_fOwnKey(TRUE)
  1454. {
  1455. m_hrKey = CMetaInterface::QueryResult();
  1456. //
  1457. // Do not open key
  1458. //
  1459. }
  1460. CMetaKey::CMetaKey(
  1461. IN const CMetaInterface * pInterface
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. Construct with pre-existing interface. Does not
  1466. open any keys
  1467. Arguments:
  1468. CMetaInterface * pInterface : Preexisting interface
  1469. Return Value:
  1470. N/A
  1471. --*/
  1472. : CMetaInterface(pInterface),
  1473. m_hKey(NULL),
  1474. m_hBase(NULL),
  1475. m_strMetaPath(),
  1476. m_dwFlags(0L),
  1477. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1478. m_fAllowRootOperations(TRUE),
  1479. m_fOwnKey(TRUE)
  1480. {
  1481. m_hrKey = CMetaInterface::QueryResult();
  1482. }
  1483. CMetaKey::CMetaKey(
  1484. IN LPCTSTR lpszServerName,
  1485. IN DWORD dwFlags,
  1486. IN METADATA_HANDLE hkBase,
  1487. IN LPCTSTR lpszMDPath
  1488. )
  1489. /*++
  1490. Routine Description:
  1491. Fully defined constructor that opens a key
  1492. Arguments:
  1493. LPCTSTR lpszServerName : Server name
  1494. DWORD dwFlags : Open permissions
  1495. METADATA_HANDLE hkBase : Base key
  1496. LPCTSTR lpszMDPath : Path or NULL
  1497. Return Value:
  1498. N/A
  1499. --*/
  1500. : CMetaInterface(lpszServerName),
  1501. m_hKey(NULL),
  1502. m_hBase(NULL),
  1503. m_dwFlags(0L),
  1504. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1505. m_fAllowRootOperations(FALSE),
  1506. m_strMetaPath(),
  1507. m_fOwnKey(TRUE)
  1508. {
  1509. m_hrKey = CMetaInterface::QueryResult();
  1510. if (SUCCEEDED(m_hrKey))
  1511. {
  1512. m_hrKey = Open(dwFlags, hkBase, lpszMDPath);
  1513. }
  1514. }
  1515. CMetaKey::CMetaKey(
  1516. IN const CMetaInterface * pInterface,
  1517. IN DWORD dwFlags,
  1518. IN METADATA_HANDLE hkBase,
  1519. IN LPCTSTR lpszMDPath
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. Fully defined constructor that opens a key
  1524. Arguments:
  1525. CMetaInterface * pInterface : Existing interface
  1526. DWORD dwFlags : Open permissions
  1527. METADATA_HANDLE hkBase : Base key
  1528. LPCTSTR lpszMDPath : Path or NULL
  1529. Return Value:
  1530. N/A
  1531. --*/
  1532. : CMetaInterface(pInterface),
  1533. m_hKey(NULL),
  1534. m_hBase(NULL),
  1535. m_strMetaPath(),
  1536. m_dwFlags(0L),
  1537. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1538. m_fAllowRootOperations(FALSE),
  1539. m_fOwnKey(TRUE)
  1540. {
  1541. m_hrKey = CMetaInterface::QueryResult();
  1542. if (SUCCEEDED(m_hrKey))
  1543. {
  1544. m_hrKey = Open(dwFlags, hkBase, lpszMDPath);
  1545. }
  1546. }
  1547. CMetaKey::CMetaKey(
  1548. IN LPCTSTR lpszServerName,
  1549. IN DWORD dwFlags,
  1550. IN LPCTSTR lpSvc, OPTIONAL
  1551. IN DWORD dwInstance, OPTIONAL
  1552. IN LPCTSTR lpParentPath, OPTIONAL
  1553. IN LPCTSTR lpAlias OPTIONAL
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. Constructor with path components
  1558. Arguments:
  1559. LPCTSTR lpszServerName : Server name
  1560. DWORD dwFlags : Open permissions
  1561. LPCTSTR lpSvc : Service name or NULL
  1562. DWORD dwInstance, : Instance number of 0
  1563. LPCTSTR lpParentPath : Parent path or NULL
  1564. LPCTSTR lpAlias : Alias name or NULL
  1565. Return Value:
  1566. N/A
  1567. --*/
  1568. : CMetaInterface(lpszServerName),
  1569. m_hKey(NULL),
  1570. m_hBase(NULL),
  1571. m_strMetaPath(),
  1572. m_dwFlags(0L),
  1573. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1574. m_fAllowRootOperations(FALSE),
  1575. m_fOwnKey(TRUE)
  1576. {
  1577. m_hrKey = CMetaInterface::QueryResult();
  1578. if (SUCCEEDED(m_hrKey))
  1579. {
  1580. m_hrKey = Open(dwFlags, lpSvc, dwInstance, lpParentPath, lpAlias);
  1581. }
  1582. }
  1583. CMetaKey::CMetaKey(
  1584. IN const CMetaInterface * pInterface,
  1585. IN DWORD dwFlags,
  1586. IN LPCTSTR lpSvc, OPTIONAL
  1587. IN DWORD dwInstance, OPTIONAL
  1588. IN LPCTSTR lpParentPath, OPTIONAL
  1589. IN LPCTSTR lpAlias OPTIONAL
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. Constructor with path components
  1594. Arguments:
  1595. CMetaInterface * pInterface : Existing interface
  1596. DWORD dwFlags : Open permissions
  1597. LPCTSTR lpSvc : Service name or NULL
  1598. DWORD dwInstance, : Instance number of 0
  1599. LPCTSTR lpParentPath : Parent path or NULL
  1600. LPCTSTR lpAlias : Alias name or NULL
  1601. Return Value:
  1602. N/A
  1603. --*/
  1604. : CMetaInterface(pInterface),
  1605. m_hKey(NULL),
  1606. m_hBase(NULL),
  1607. m_dwFlags(0L),
  1608. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1609. m_fAllowRootOperations(FALSE),
  1610. m_strMetaPath(),
  1611. m_fOwnKey(TRUE)
  1612. {
  1613. m_hrKey = CMetaInterface::QueryResult();
  1614. if (SUCCEEDED(m_hrKey))
  1615. {
  1616. m_hrKey = Open(dwFlags, lpSvc, dwInstance, lpParentPath, lpAlias);
  1617. }
  1618. }
  1619. CMetaKey::CMetaKey(
  1620. IN BOOL fOwnKey,
  1621. IN const CMetaKey * pKey
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. Copy constructor.
  1626. Arguments:
  1627. BOOL fOwnKey : TRUE to take ownership of the key
  1628. const CMetaKey * pKey : Existing key
  1629. Return Value:
  1630. N/A
  1631. --*/
  1632. : CMetaInterface(pKey),
  1633. m_hKey(pKey->m_hKey),
  1634. m_hBase(pKey->m_hBase),
  1635. m_dwFlags(pKey->m_dwFlags),
  1636. m_cbInitialBufferSize(pKey->m_cbInitialBufferSize),
  1637. m_fAllowRootOperations(pKey->m_fAllowRootOperations),
  1638. m_hrKey(pKey->m_hrKey),
  1639. m_strMetaPath(pKey->m_strMetaPath),
  1640. m_fOwnKey(fOwnKey)
  1641. {
  1642. //
  1643. // No provisions for anything else at the moment
  1644. //
  1645. ASSERT(!m_fOwnKey);
  1646. }
  1647. CMetaKey::~CMetaKey()
  1648. /*++
  1649. Routine Description:
  1650. Destructor -- Close the key.
  1651. Arguments:
  1652. N/A
  1653. Return Value:
  1654. N/A
  1655. --*/
  1656. {
  1657. if (IsOpen() && m_fOwnKey)
  1658. {
  1659. Close();
  1660. }
  1661. }
  1662. /* virtual */
  1663. BOOL
  1664. CMetaKey::Succeeded() const
  1665. /*++
  1666. Routine Description:
  1667. Determine if object was constructed successfully
  1668. Arguments:
  1669. None
  1670. Return Value:
  1671. TRUE for success, FALSE for failure
  1672. --*/
  1673. {
  1674. return SUCCEEDED(m_hrKey);
  1675. }
  1676. /* virtual */
  1677. HRESULT
  1678. CMetaKey::QueryResult() const
  1679. /*++
  1680. Routine Description:
  1681. Return the construction error for this object
  1682. Arguments:
  1683. None
  1684. Return Value:
  1685. HRESULT from construction errors
  1686. --*/
  1687. {
  1688. return m_hrKey;
  1689. }
  1690. HRESULT
  1691. CMetaKey::Open(
  1692. IN DWORD dwFlags,
  1693. IN METADATA_HANDLE hkBase,
  1694. IN LPCTSTR lpszMDPath OPTIONAL
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. Attempt to open a metabase key
  1699. Arguments:
  1700. METADATA_HANDLE hkBase : Base metabase key
  1701. LPCTSTR lpszMDPath : Optional path
  1702. DWORD dwFlags : Permission flags
  1703. Return Value:
  1704. HRESULT
  1705. --*/
  1706. {
  1707. ASSURE_PROPER_INTERFACE();
  1708. if (m_hKey != NULL)
  1709. {
  1710. TRACEEOLID("Attempting to open key that already has an open handle");
  1711. ASSERT(FALSE);
  1712. TRACEEOLID("Closing that key");
  1713. Close();
  1714. }
  1715. //
  1716. // Base key is stored for reopen purposes only
  1717. //
  1718. m_hBase = hkBase;
  1719. m_strMetaPath = lpszMDPath;
  1720. m_dwFlags = dwFlags;
  1721. return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey);
  1722. }
  1723. HRESULT
  1724. CMetaKey::Open(
  1725. IN DWORD dwFlags,
  1726. IN LPCTSTR lpSvc, OPTIONAL
  1727. IN DWORD dwInstance, OPTIONAL
  1728. IN LPCTSTR lpParentPath, OPTIONAL
  1729. IN LPCTSTR lpAlias OPTIONAL
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. Build metapath from components, and open key
  1734. Arguments:
  1735. Return Value:
  1736. HRESULT
  1737. --*/
  1738. {
  1739. m_hBase = METADATA_MASTER_ROOT_HANDLE;
  1740. BuildMetaPath(m_strMetaPath, lpSvc, dwInstance, lpParentPath, lpAlias);
  1741. return Open(dwFlags, m_hBase, m_strMetaPath);
  1742. }
  1743. HRESULT
  1744. CMetaKey::ConvertToParentPath(
  1745. IN BOOL fImmediate
  1746. )
  1747. /*++
  1748. Routine Description:
  1749. Change the path to the parent path.
  1750. Arguments:
  1751. BOOL fImmediate : If TRUE, the immediate parent's path will be used
  1752. if FALSE, the first parent that really exists
  1753. Return Value:
  1754. HRESULT
  1755. ERROR_INVALID_PARAMETER if there is no valid path
  1756. --*/
  1757. {
  1758. BOOL fIsOpen = IsOpen();
  1759. if (fIsOpen)
  1760. {
  1761. Close();
  1762. }
  1763. CError err;
  1764. FOREVER
  1765. {
  1766. if (!ConvertToParentPath(m_strMetaPath))
  1767. {
  1768. //
  1769. // There is no parent path
  1770. //
  1771. err = ERROR_INVALID_PARAMETER;
  1772. break;
  1773. }
  1774. err = ReOpen();
  1775. //
  1776. // Path not found is the only valid error
  1777. // other than success.
  1778. //
  1779. if (fImmediate
  1780. || err.Succeeded()
  1781. || err.Win32Error() != ERROR_PATH_NOT_FOUND)
  1782. {
  1783. break;
  1784. }
  1785. }
  1786. //
  1787. // Remember to reset the construction error
  1788. // which referred to the parent path.
  1789. //
  1790. m_hrKey = err;
  1791. return err;
  1792. }
  1793. HRESULT
  1794. CMetaKey::CreatePathFromFailedOpen()
  1795. /*++
  1796. Routine Description:
  1797. If the path doesn't exist, create it. This method should be
  1798. called after an Open call failed (because it will have initialized
  1799. m_strMetaPath.
  1800. Arguments:
  1801. None
  1802. Return Value:
  1803. HRESULT
  1804. --*/
  1805. {
  1806. CString strParentPath;
  1807. CString strObjectName;
  1808. CString strSavePath(m_strMetaPath);
  1809. SplitMetaPathAtInstance(
  1810. m_strMetaPath,
  1811. strParentPath,
  1812. strObjectName
  1813. );
  1814. CError err(Open(
  1815. METADATA_PERMISSION_WRITE,
  1816. METADATA_MASTER_ROOT_HANDLE,
  1817. strParentPath
  1818. ));
  1819. if (err.Succeeded())
  1820. {
  1821. //
  1822. // This really should never fail, because we're opening
  1823. // the path at the instance.
  1824. //
  1825. err = AddKey(strObjectName);
  1826. }
  1827. if (IsOpen())
  1828. {
  1829. Close();
  1830. }
  1831. //
  1832. // The previous open wiped out the path...
  1833. //
  1834. m_strMetaPath = strSavePath;
  1835. return err;
  1836. }
  1837. HRESULT
  1838. CMetaKey::Close()
  1839. /*++
  1840. Routine Description:
  1841. Close the currently open key.
  1842. Arguments:
  1843. N/A
  1844. Return Value:
  1845. N/A
  1846. --*/
  1847. {
  1848. ASSURE_PROPER_INTERFACE();
  1849. HRESULT hr = S_OK;
  1850. ASSERT(m_hKey != NULL);
  1851. ASSERT(m_fOwnKey);
  1852. if (m_hKey)
  1853. {
  1854. hr = CloseKey(m_hKey);
  1855. if (SUCCEEDED(hr))
  1856. {
  1857. m_hKey = NULL;
  1858. }
  1859. }
  1860. return hr;
  1861. }
  1862. /* protected */
  1863. HRESULT
  1864. CMetaKey::GetPropertyValue(
  1865. IN DWORD dwID,
  1866. OUT IN DWORD & dwSize, OPTIONAL
  1867. OUT IN void *& pvData, OPTIONAL
  1868. OUT IN DWORD * pdwDataType, OPTIONAL
  1869. IN BOOL * pfInheritanceOverride, OPTIONAL
  1870. IN LPCTSTR lpszMDPath, OPTIONAL
  1871. OUT DWORD * pdwAttributes OPTIONAL
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. Get metadata on the currently open key.
  1876. Arguments:
  1877. DWORD dwID : Property ID number
  1878. DWORD & dwSize : Buffer size (could be 0)
  1879. void *& pvData : Buffer -- will allocate if NULL
  1880. DWORD * pdwDataType : NULL or on in contains valid data types,
  1881. : on out contains actual data type
  1882. BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off
  1883. LPCTSTR lpszMDPath : Optional path off the open key
  1884. DWORD * pdwAttributes : Optionally returns attributes
  1885. Return Value:
  1886. HRESULT
  1887. ERROR_INVALID_HANDLE : If the handle is not open
  1888. ERROR_INVALID_PARAMETER : If the property id is not found,
  1889. or the data type doesn't match requested type
  1890. ERROR_OUTOFMEMORY : Out of memory
  1891. --*/
  1892. {
  1893. ASSURE_PROPER_INTERFACE();
  1894. ASSURE_OPEN_KEY();
  1895. METADATA_RECORD mdRecord;
  1896. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  1897. //
  1898. // If unable to find this property ID in our table, or
  1899. // if we specified a desired type, and this type doesn't
  1900. // match it, give up.
  1901. //
  1902. if (pdwDataType && *pdwDataType != ALL_METADATA
  1903. && *pdwDataType != mdRecord.dwMDDataType)
  1904. {
  1905. ASSERT(FALSE);
  1906. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1907. }
  1908. //
  1909. // Check to see if inheritance behaviour is overridden
  1910. //
  1911. if (pfInheritanceOverride)
  1912. {
  1913. if (*pfInheritanceOverride)
  1914. {
  1915. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  1916. }
  1917. else
  1918. {
  1919. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  1920. }
  1921. }
  1922. //
  1923. // This causes a bad parameter error on input otherwise
  1924. //
  1925. mdRecord.dwMDAttributes &= ~METADATA_REFERENCE;
  1926. //
  1927. // If we're looking for inheritable properties, the path
  1928. // doesn't have to be completely specified.
  1929. //
  1930. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  1931. {
  1932. mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED);
  1933. }
  1934. ASSERT(dwSize > 0 || pvData == NULL);
  1935. mdRecord.dwMDDataLen = dwSize;
  1936. mdRecord.pbMDData = (LPBYTE)pvData;
  1937. //
  1938. // If no buffer provided, allocate one.
  1939. //
  1940. HRESULT hr = S_OK;
  1941. BOOL fBufferTooSmall;
  1942. BOOL fAllocatedMemory = FALSE;
  1943. DWORD dwInitSize = m_cbInitialBufferSize;
  1944. do
  1945. {
  1946. if(mdRecord.pbMDData == NULL)
  1947. {
  1948. mdRecord.dwMDDataLen = dwInitSize;
  1949. mdRecord.pbMDData = (LPBYTE)AllocMem(dwInitSize);
  1950. if(mdRecord.pbMDData == NULL && dwInitSize > 0)
  1951. {
  1952. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  1953. break;
  1954. }
  1955. ++fAllocatedMemory;
  1956. }
  1957. //
  1958. // Get the data
  1959. //
  1960. DWORD dwRequiredDataLen = 0;
  1961. hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen);
  1962. //
  1963. // Re-fetch the buffer if it's too small.
  1964. //
  1965. fBufferTooSmall =
  1966. (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory;
  1967. if(fBufferTooSmall)
  1968. {
  1969. //
  1970. // Delete the old buffer, and set up for a re-fetch.
  1971. //
  1972. FreeMem(mdRecord.pbMDData);
  1973. mdRecord.pbMDData = NULL;
  1974. dwInitSize = dwRequiredDataLen;
  1975. }
  1976. }
  1977. while(fBufferTooSmall);
  1978. //
  1979. // Failed
  1980. //
  1981. if(FAILED(hr) && fAllocatedMemory)
  1982. {
  1983. FreeMem(mdRecord.pbMDData);
  1984. mdRecord.pbMDData = NULL;
  1985. }
  1986. dwSize = mdRecord.dwMDDataLen;
  1987. pvData = mdRecord.pbMDData;
  1988. if (pdwDataType != NULL)
  1989. {
  1990. //
  1991. // Return actual data type
  1992. //
  1993. *pdwDataType = mdRecord.dwMDDataType;
  1994. }
  1995. if (pdwAttributes != NULL)
  1996. {
  1997. //
  1998. // Return data attributes
  1999. //
  2000. *pdwAttributes = mdRecord.dwMDAttributes;
  2001. }
  2002. return hr;
  2003. }
  2004. /* protected */
  2005. HRESULT
  2006. CMetaKey::GetDataPaths(
  2007. OUT CStringListEx & strlDataPaths,
  2008. IN DWORD dwMDIdentifier,
  2009. IN DWORD dwMDDataType,
  2010. IN LPCTSTR lpszMDPath OPTIONAL
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. Get data paths
  2015. Arguments:
  2016. Return Value:
  2017. HRESULT
  2018. --*/
  2019. {
  2020. ASSURE_PROPER_INTERFACE();
  2021. ASSURE_OPEN_KEY();
  2022. //
  2023. // Start with a small buffer
  2024. //
  2025. DWORD dwMDBufferSize = 1024;
  2026. LPTSTR lpszBuffer = NULL;
  2027. CError err;
  2028. do
  2029. {
  2030. if (lpszBuffer != NULL)
  2031. {
  2032. FreeMem(lpszBuffer);
  2033. }
  2034. lpszBuffer = AllocTString(dwMDBufferSize);
  2035. if (lpszBuffer == NULL)
  2036. {
  2037. err = ERROR_NOT_ENOUGH_MEMORY;
  2038. break;
  2039. }
  2040. err = CMetaInterface::GetDataPaths(
  2041. m_hKey,
  2042. lpszMDPath,
  2043. dwMDIdentifier,
  2044. dwMDDataType,
  2045. dwMDBufferSize,
  2046. lpszBuffer,
  2047. &dwMDBufferSize
  2048. );
  2049. }
  2050. while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER);
  2051. if (err.Succeeded() && (err.Win32Error() == ERROR_PATH_NOT_FOUND))
  2052. {
  2053. //
  2054. // That's ok... this is some sort of physical directory
  2055. // that doesn't currently exist in the metabase, and
  2056. // which therefore doesn't have any descendants anyway.
  2057. //
  2058. ZeroMemory(lpszBuffer, dwMDBufferSize);
  2059. err.Reset();
  2060. }
  2061. if (err.Succeeded())
  2062. {
  2063. ConvertDoubleNullListToStringList(lpszBuffer, strlDataPaths);
  2064. FreeMem(lpszBuffer);
  2065. }
  2066. return err;
  2067. }
  2068. HRESULT
  2069. CMetaKey::CheckDescendants(
  2070. IN DWORD dwID,
  2071. IN LPCTSTR lpszServer,
  2072. IN LPCTSTR lpszMDPath OPTIONAL
  2073. )
  2074. /*++
  2075. Routine Description:
  2076. Check for descendant overrides; If there are any, bring up a dialog
  2077. that displays them, and give the user the opportunity the remove
  2078. the overrides.
  2079. Arguments:
  2080. DWORD dwID : Property ID
  2081. Return Value:
  2082. HRESULT
  2083. --*/
  2084. {
  2085. ASSURE_PROPER_INTERFACE();
  2086. HRESULT hr = S_OK;
  2087. METADATA_RECORD mdRecord;
  2088. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2089. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  2090. {
  2091. CStringListEx strlDataPaths;
  2092. hr = GetDataPaths(
  2093. strlDataPaths,
  2094. mdRecord.dwMDIdentifier,
  2095. mdRecord.dwMDDataType,
  2096. lpszMDPath
  2097. );
  2098. if (SUCCEEDED(hr) && !strlDataPaths.IsEmpty())
  2099. {
  2100. CInheritanceDlg dlg(
  2101. dwID,
  2102. FROM_WRITE_PROPERTY,
  2103. lpszServer,
  2104. lpszMDPath,
  2105. strlDataPaths
  2106. );
  2107. if (!dlg.IsEmpty())
  2108. {
  2109. dlg.DoModal();
  2110. }
  2111. }
  2112. }
  2113. return hr;
  2114. }
  2115. /* protected */
  2116. HRESULT
  2117. CMetaKey::SetPropertyValue(
  2118. IN DWORD dwID,
  2119. IN DWORD dwSize,
  2120. IN void * pvData,
  2121. IN BOOL * pfInheritanceOverride, OPTIONAL
  2122. IN LPCTSTR lpszMDPath OPTIONAL
  2123. )
  2124. /*++
  2125. Routine Description:
  2126. Set metadata on the open key. The key must have been opened with
  2127. write permission.
  2128. Arguments:
  2129. DWORD dwID : Property ID
  2130. DWORD dwSize : Size of data
  2131. void * pvData : Data buffer
  2132. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2133. LPCTSTR lpszMDPath : Optional path off the open key
  2134. Return Value:
  2135. HRESULT
  2136. ERROR_INVALID_HANDLE : If the handle is not open
  2137. ERROR_INVALID_PARAMETER : If the property id is not found,
  2138. or the buffer is NULL or of size 0
  2139. --*/
  2140. {
  2141. ASSURE_PROPER_INTERFACE();
  2142. ASSURE_OPEN_KEY();
  2143. if (pvData == NULL && dwSize != 0)
  2144. {
  2145. ASSERT(FALSE);
  2146. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2147. }
  2148. METADATA_RECORD mdRecord;
  2149. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2150. if (pfInheritanceOverride)
  2151. {
  2152. if (*pfInheritanceOverride)
  2153. {
  2154. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  2155. }
  2156. else
  2157. {
  2158. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  2159. }
  2160. }
  2161. mdRecord.dwMDDataLen = dwSize;
  2162. mdRecord.pbMDData = (LPBYTE)pvData;
  2163. return SetData(m_hKey, lpszMDPath, &mdRecord);
  2164. }
  2165. /* protected */
  2166. HRESULT
  2167. CMetaKey::GetAllData(
  2168. IN DWORD dwMDAttributes,
  2169. IN DWORD dwMDUserType,
  2170. IN DWORD dwMDDataType,
  2171. OUT DWORD * pdwMDNumEntries,
  2172. OUT DWORD * pdwMDDataLen,
  2173. OUT PBYTE * ppbMDData,
  2174. IN LPCTSTR lpszMDPath OPTIONAL
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. Get all data off the open key. Buffer is created automatically.
  2179. Arguments:
  2180. DWORD dwMDAttributes : Attributes
  2181. DWORD dwMDUserType : User type to fetch
  2182. DWORD dwMDDataType : Data type to fetch
  2183. DWORD * pdwMDNumEntries : Returns number of entries read
  2184. DWORD * pdwMDDataLen : Returns size of data buffer
  2185. PBYTE * ppbMDData : Returns data buffer
  2186. LPCTSTR lpszMDPath : Optional data path
  2187. Return Value:
  2188. HRESULT
  2189. --*/
  2190. {
  2191. ASSURE_PROPER_INTERFACE();
  2192. ASSURE_OPEN_KEY();
  2193. //
  2194. // Check for valid parameters
  2195. //
  2196. if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries)
  2197. {
  2198. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2199. }
  2200. HRESULT hr = S_OK;
  2201. BOOL fBufferTooSmall;
  2202. DWORD dwMDDataSetNumber;
  2203. DWORD dwRequiredBufferSize;
  2204. DWORD dwInitSize = m_cbInitialBufferSize;
  2205. *ppbMDData = NULL;
  2206. do
  2207. {
  2208. *pdwMDDataLen = dwInitSize;
  2209. *ppbMDData = (LPBYTE)AllocMem(dwInitSize);
  2210. if (ppbMDData == NULL && dwInitSize > 0)
  2211. {
  2212. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2213. break;
  2214. }
  2215. hr = CMetaInterface::GetAllData(
  2216. m_hKey,
  2217. lpszMDPath,
  2218. dwMDAttributes,
  2219. dwMDUserType,
  2220. dwMDDataType,
  2221. pdwMDNumEntries,
  2222. &dwMDDataSetNumber,
  2223. *pdwMDDataLen,
  2224. *ppbMDData,
  2225. &dwRequiredBufferSize
  2226. );
  2227. //
  2228. // Re-fetch the buffer if it's too small.
  2229. //
  2230. fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER);
  2231. if(fBufferTooSmall)
  2232. {
  2233. //
  2234. // Delete the old buffer, and set up for a re-fetch.
  2235. //
  2236. SAFE_FREEMEM(*ppbMDData);
  2237. dwInitSize = dwRequiredBufferSize;
  2238. }
  2239. }
  2240. while (fBufferTooSmall);
  2241. if (FAILED(hr))
  2242. {
  2243. //
  2244. // No good, be sure we don't leak anything
  2245. //
  2246. SAFE_FREEMEM(*ppbMDData);
  2247. dwInitSize = 0L;
  2248. }
  2249. return hr;
  2250. }
  2251. HRESULT
  2252. CMetaKey::QueryValue(
  2253. IN DWORD dwID,
  2254. IN OUT DWORD & dwValue,
  2255. IN BOOL * pfInheritanceOverride, OPTIONAL
  2256. IN LPCTSTR lpszMDPath, OPTIONAL
  2257. OUT DWORD * pdwAttributes OPTIONAL
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. Fetch data as a DWORD
  2262. Arguments:
  2263. DWORD dwID : Property ID
  2264. DWORD & dwValue : Returns the value read in
  2265. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2266. LPCTSTR lpszMDPath : Optional path off the open key
  2267. DWORD * pdwAttributes : Optionally returns attributes
  2268. Return Value:
  2269. HRESULT
  2270. --*/
  2271. {
  2272. DWORD dwSize = sizeof(dwValue);
  2273. DWORD dwDataType = DWORD_METADATA;
  2274. void * pvData = &dwValue;
  2275. return GetPropertyValue(
  2276. dwID,
  2277. dwSize,
  2278. pvData,
  2279. &dwDataType,
  2280. pfInheritanceOverride,
  2281. lpszMDPath,
  2282. pdwAttributes
  2283. );
  2284. }
  2285. HRESULT
  2286. CMetaKey::QueryValue(
  2287. IN DWORD dwID,
  2288. IN OUT CString & strValue,
  2289. IN BOOL * pfInheritanceOverride, OPTIONAL
  2290. IN LPCTSTR lpszMDPath, OPTIONAL
  2291. OUT DWORD * pdwAttributes OPTIONAL
  2292. )
  2293. /*++
  2294. Routine Description:
  2295. Fetch data as a string
  2296. Arguments:
  2297. DWORD dwID : Property ID
  2298. DWORD & strValue : Returns the value read in
  2299. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2300. LPCTSTR lpszMDPath : Optional path off the open key
  2301. DWORD * pdwAttributes : Optionally returns attributes
  2302. Return Value:
  2303. HRESULT
  2304. --*/
  2305. {
  2306. //
  2307. // Get GetData allocate the buffer for us
  2308. //
  2309. DWORD dwSize = 0;
  2310. DWORD dwDataType = ALL_METADATA;
  2311. LPTSTR lpData = NULL;
  2312. HRESULT hr = GetPropertyValue(
  2313. dwID,
  2314. dwSize,
  2315. (void *&)lpData,
  2316. &dwDataType,
  2317. pfInheritanceOverride,
  2318. lpszMDPath,
  2319. pdwAttributes
  2320. );
  2321. if (SUCCEEDED(hr))
  2322. {
  2323. //
  2324. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2325. // (see registry functions), and data type conversions for DWORD
  2326. // or MULTISZ_METADATA or BINARY_METADATA
  2327. //
  2328. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2329. {
  2330. try
  2331. {
  2332. strValue = lpData;
  2333. }
  2334. catch(CMemoryException * e)
  2335. {
  2336. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  2337. strValue.Empty();
  2338. e->Delete();
  2339. }
  2340. }
  2341. else
  2342. {
  2343. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2344. }
  2345. }
  2346. if (lpData)
  2347. {
  2348. FreeMem(lpData);
  2349. }
  2350. return hr;
  2351. }
  2352. HRESULT
  2353. CMetaKey::QueryValue(
  2354. IN DWORD dwID,
  2355. IN OUT CStringListEx & strlValue,
  2356. IN BOOL * pfInheritanceOverride, OPTIONAL
  2357. IN LPCTSTR lpszMDPath, OPTIONAL
  2358. OUT DWORD * pdwAttributes OPTIONAL
  2359. )
  2360. /*++
  2361. Routine Description:
  2362. Fetch data as a stringlist
  2363. Arguments:
  2364. DWORD dwID : Property ID
  2365. DWORD & strlValue : Returns the value read in
  2366. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2367. LPCTSTR lpszMDPath : Optional path off the open key
  2368. DWORD * pdwAttributes : Optionally returns attributes
  2369. Return Value:
  2370. HRESULT
  2371. --*/
  2372. {
  2373. //
  2374. // Get GetData allocate the buffer for us
  2375. //
  2376. DWORD dwSize = 0;
  2377. DWORD dwDataType = MULTISZ_METADATA;
  2378. LPTSTR lpData = NULL;
  2379. HRESULT hr = GetPropertyValue(
  2380. dwID,
  2381. dwSize,
  2382. (void *&)lpData,
  2383. &dwDataType,
  2384. pfInheritanceOverride,
  2385. lpszMDPath,
  2386. pdwAttributes
  2387. );
  2388. if (SUCCEEDED(hr))
  2389. {
  2390. //
  2391. // Notes: Consider accepting a single STRING
  2392. //
  2393. ASSERT(dwDataType == MULTISZ_METADATA);
  2394. DWORD err = ConvertDoubleNullListToStringList(
  2395. lpData,
  2396. strlValue,
  2397. dwSize / sizeof(TCHAR)
  2398. );
  2399. hr = HRESULT_FROM_WIN32(err);
  2400. }
  2401. if (lpData)
  2402. {
  2403. FreeMem(lpData);
  2404. }
  2405. return hr;
  2406. }
  2407. HRESULT
  2408. CMetaKey::QueryValue(
  2409. IN DWORD dwID,
  2410. IN OUT CBlob & blValue,
  2411. IN BOOL * pfInheritanceOverride, OPTIONAL
  2412. IN LPCTSTR lpszMDPath, OPTIONAL
  2413. OUT DWORD * pdwAttributes OPTIONAL
  2414. )
  2415. /*++
  2416. Routine Description:
  2417. Fetch data as a binary blob
  2418. Arguments:
  2419. DWORD dwID : Property ID
  2420. DWORD CBlob & blValue : Returns the binary blob
  2421. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2422. LPCTSTR lpszMDPath : Optional path off the open key
  2423. DWORD * pdwAttributes : Optionally returns attributes
  2424. Return Value:
  2425. HRESULT
  2426. --*/
  2427. {
  2428. //
  2429. // Get GetData allocate the buffer for us
  2430. //
  2431. DWORD dwSize = 0;
  2432. DWORD dwDataType = BINARY_METADATA;
  2433. LPBYTE pbData = NULL;
  2434. HRESULT hr = GetPropertyValue(
  2435. dwID,
  2436. dwSize,
  2437. (void *&)pbData,
  2438. &dwDataType,
  2439. pfInheritanceOverride,
  2440. lpszMDPath,
  2441. pdwAttributes
  2442. );
  2443. if (SUCCEEDED(hr))
  2444. {
  2445. //
  2446. // Blob takes ownership of the data, so don't free it...
  2447. //
  2448. ASSERT(pbData != NULL);
  2449. blValue.SetValue(dwSize, pbData, FALSE);
  2450. }
  2451. return hr;
  2452. }
  2453. HRESULT
  2454. CMetaKey::SetValue(
  2455. IN DWORD dwID,
  2456. IN CStringListEx & strlValue,
  2457. IN BOOL * pfInheritanceOverride, OPTIONAL
  2458. IN LPCTSTR lpszMDPath OPTIONAL
  2459. )
  2460. /*++
  2461. Routine Description:
  2462. Store data as string
  2463. Arguments:
  2464. DWORD dwID : Property ID
  2465. CStringListEx & strlValue : Value to be written
  2466. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2467. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2468. Return Value:
  2469. HRESULT
  2470. --*/
  2471. {
  2472. DWORD cCharacters;
  2473. LPTSTR lpstr = NULL;
  2474. //
  2475. // Flatten value
  2476. //
  2477. ConvertStringListToDoubleNullList(
  2478. strlValue,
  2479. cCharacters,
  2480. lpstr
  2481. );
  2482. HRESULT hr = SetPropertyValue(
  2483. dwID,
  2484. cCharacters * sizeof(TCHAR),
  2485. (void *)lpstr,
  2486. pfInheritanceOverride,
  2487. lpszMDPath
  2488. );
  2489. SAFE_FREEMEM(lpstr);
  2490. return hr;
  2491. }
  2492. HRESULT
  2493. CMetaKey::SetValue(
  2494. IN DWORD dwID,
  2495. IN CBlob & blValue,
  2496. IN BOOL * pfInheritanceOverride, OPTIONAL
  2497. IN LPCTSTR lpszMDPath OPTIONAL
  2498. )
  2499. /*++
  2500. Routine Description:
  2501. Store data as binary
  2502. Arguments:
  2503. DWORD dwID : Property ID
  2504. CBlob & blValue : Value to be written
  2505. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2506. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2507. Return Value:
  2508. HRESULT
  2509. --*/
  2510. {
  2511. return SetPropertyValue(
  2512. dwID,
  2513. blValue.GetSize(),
  2514. (void *)blValue.GetData(),
  2515. pfInheritanceOverride,
  2516. lpszMDPath
  2517. );
  2518. }
  2519. HRESULT
  2520. CMetaKey::DeleteValue(
  2521. DWORD dwID,
  2522. LPCTSTR lpszMDPath OPTIONAL
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. Delete data
  2527. Arguments:
  2528. DWORD dwID : Property ID of property to be deleted
  2529. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2530. Return Value:
  2531. HRESULT
  2532. --*/
  2533. {
  2534. ASSURE_PROPER_INTERFACE();
  2535. ASSURE_OPEN_KEY();
  2536. METADATA_RECORD mdRecord;
  2537. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2538. return DeleteData(
  2539. m_hKey,
  2540. lpszMDPath,
  2541. mdRecord.dwMDIdentifier,
  2542. mdRecord.dwMDDataType
  2543. );
  2544. }
  2545. HRESULT
  2546. CMetaKey::DoesPathExist(
  2547. IN LPCTSTR lpszMDPath
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. Determine if the path exists
  2552. Arguments:
  2553. LPCTSTR lpszMDPath : Relative path off the open key
  2554. Return Value:
  2555. HRESULT, or S_OK if the path exists.
  2556. --*/
  2557. {
  2558. ASSURE_PROPER_INTERFACE();
  2559. ASSURE_OPEN_KEY();
  2560. FILETIME ft;
  2561. return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE);
  2562. }
  2563. //
  2564. // CMetaEnumerator Clas
  2565. //
  2566. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  2567. CMetaEnumerator::CMetaEnumerator(
  2568. IN LPCTSTR lpszServerName,
  2569. IN LPCTSTR lpSvc, OPTIONAL
  2570. IN DWORD dwInstance, OPTIONAL
  2571. IN LPCTSTR lpParentPath, OPTIONAL
  2572. IN LPCTSTR lpAlias OPTIONAL
  2573. )
  2574. /*++
  2575. Routine Description:
  2576. Construct a new interface
  2577. Arguments:
  2578. LPCTSTR lpszServerName : Server name
  2579. LPCTSTR lpSvc : Service name or NULL
  2580. DWORD dwInstance, : Instance number of 0
  2581. LPCTSTR lpParentPath : Parent path or NULL
  2582. LPCTSTR lpAlias : Alias name or NULL
  2583. Return Value:
  2584. N/A
  2585. --*/
  2586. : CMetaKey(
  2587. lpszServerName,
  2588. METADATA_PERMISSION_READ,
  2589. lpSvc,
  2590. dwInstance,
  2591. lpParentPath,
  2592. lpAlias
  2593. ),
  2594. m_dwIndex(0L)
  2595. {
  2596. }
  2597. CMetaEnumerator::CMetaEnumerator(
  2598. IN CMetaInterface * pInterface,
  2599. IN LPCTSTR lpSvc, OPTIONAL
  2600. IN DWORD dwInstance, OPTIONAL
  2601. IN LPCTSTR lpParentPath, OPTIONAL
  2602. IN LPCTSTR lpAlias OPTIONAL
  2603. )
  2604. /*++
  2605. Routine Description:
  2606. Construct with existing interface
  2607. Arguments:
  2608. CMetaInterface * pInterface : Interface
  2609. LPCTSTR lpSvc : Service name or NULL
  2610. DWORD dwInstance, : Instance number of 0
  2611. LPCTSTR lpParentPath : Parent path or NULL
  2612. LPCTSTR lpAlias : Alias name or NULL
  2613. Return Value:
  2614. N/A
  2615. --*/
  2616. : CMetaKey(
  2617. pInterface,
  2618. METADATA_PERMISSION_READ,
  2619. lpSvc,
  2620. dwInstance,
  2621. lpParentPath,
  2622. lpAlias
  2623. ),
  2624. m_dwIndex(0L)
  2625. {
  2626. }
  2627. HRESULT
  2628. CMetaEnumerator::Next(
  2629. OUT CString & strKey,
  2630. IN LPCTSTR lpszMDPath OPTIONAL
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. Get the next subkey
  2635. Arguments:
  2636. CString & str Returns keyname
  2637. LPCTSTR lpszMDPath Optional subpath
  2638. Return Value:
  2639. HRESULT
  2640. --*/
  2641. {
  2642. ASSURE_PROPER_INTERFACE();
  2643. ASSURE_OPEN_KEY();
  2644. LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
  2645. HRESULT hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
  2646. strKey.ReleaseBuffer();
  2647. return hr;
  2648. }
  2649. HRESULT
  2650. CMetaEnumerator::Next(
  2651. OUT DWORD & dwKey,
  2652. IN LPCTSTR lpszMDPath OPTIONAL
  2653. )
  2654. /*++
  2655. Routine Description:
  2656. Get the next subkey as a DWORD. This skips non-numeric
  2657. keynames (including 0) until the first numeric key name
  2658. Arguments:
  2659. DWORD & dwKey Numeric key
  2660. LPCTSTR lpszMDPath Optional subpath
  2661. Return Value:
  2662. HRESULT
  2663. --*/
  2664. {
  2665. ASSURE_PROPER_INTERFACE();
  2666. ASSURE_OPEN_KEY();
  2667. HRESULT hr;
  2668. BOOL fContinue = TRUE;
  2669. CString strKey;
  2670. while (fContinue)
  2671. {
  2672. fContinue = FALSE;
  2673. LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
  2674. hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
  2675. strKey.ReleaseBuffer();
  2676. if (SUCCEEDED(hr))
  2677. {
  2678. if (!(dwKey = _ttoi((LPCTSTR)strKey)))
  2679. {
  2680. //
  2681. // Ignore this one
  2682. //
  2683. fContinue = TRUE;
  2684. }
  2685. }
  2686. }
  2687. return hr;
  2688. }
  2689. //
  2690. // CIISApplication class
  2691. //
  2692. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
  2693. CIISApplication::CIISApplication(
  2694. IN LPCTSTR lpszServer,
  2695. IN LPCTSTR lpszMetapath
  2696. )
  2697. /*++
  2698. Routine Description:
  2699. Constructor. Create the interfaces, and fetch the state
  2700. Arguments:
  2701. LPCTSTR lpszServer : Server name
  2702. LPCTSTR lpszMetapath : Metabase path
  2703. Return Value:
  2704. N/A
  2705. --*/
  2706. : CWamInterface(lpszServer),
  2707. CMetaKey(lpszServer),
  2708. m_dwProcessProtection(APP_INPROC),
  2709. m_dwAppState(APPSTATUS_NOTDEFINED),
  2710. m_strFriendlyName(),
  2711. m_strAppRoot(),
  2712. m_strWamPath(lpszMetapath)
  2713. {
  2714. CommonConstruct();
  2715. }
  2716. CIISApplication::CIISApplication(
  2717. IN LPCTSTR lpszServer,
  2718. IN LPCTSTR lpSvc,
  2719. IN DWORD dwInstance,
  2720. IN LPCTSTR lpParentPath, OPTIONAL
  2721. IN LPCTSTR lpAlias OPTIONAL
  2722. )
  2723. /*++
  2724. Routine Description:
  2725. Constructor. Create the interfaces, and fetch the state
  2726. Arguments:
  2727. LPCTSTR lpszServer : Server name
  2728. LPCTSTR lpSvc : Service (may be NULL or "")
  2729. DWORD dwInstance : Instance number (may be 0 for master)
  2730. LPCTSTR lpParentPath : Parent path (may be NULL or "")
  2731. LPCTSTR lpAlias : Alias (may be NULL or "")
  2732. Return Value:
  2733. N/A
  2734. --*/
  2735. : CWamInterface(lpszServer),
  2736. CMetaKey(lpszServer),
  2737. m_dwProcessProtection(APP_INPROC),
  2738. m_dwAppState(APPSTATUS_NOTDEFINED),
  2739. m_strFriendlyName(),
  2740. m_strAppRoot()
  2741. {
  2742. BuildMetaPath(m_strWamPath, lpSvc, dwInstance, lpParentPath, lpAlias);
  2743. CommonConstruct();
  2744. }
  2745. void
  2746. CIISApplication::CommonConstruct()
  2747. /*++
  2748. Routine Description:
  2749. Perform common construction
  2750. Arguments:
  2751. None
  2752. Return Value:
  2753. None
  2754. --*/
  2755. {
  2756. //
  2757. // Munge the metapath so that WAM doesn't cough up a hairball.
  2758. //
  2759. if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
  2760. {
  2761. m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
  2762. }
  2763. do
  2764. {
  2765. m_hrApp = CWamInterface::QueryResult();
  2766. if (FAILED(m_hrApp))
  2767. {
  2768. break;
  2769. }
  2770. m_hrApp = RefreshAppState();
  2771. if (HRESULT_CODE(m_hrApp) == ERROR_PATH_NOT_FOUND)
  2772. {
  2773. //
  2774. // "Path Not Found" errors are acceptable, since
  2775. // the application may not yet exist.
  2776. //
  2777. m_hrApp = S_OK;
  2778. }
  2779. }
  2780. while(FALSE);
  2781. }
  2782. /* virtual */
  2783. BOOL
  2784. CIISApplication::Succeeded() const
  2785. /*++
  2786. Routine Description:
  2787. Determine if object was constructed successfully
  2788. Arguments:
  2789. None
  2790. Return Value:
  2791. TRUE for success, FALSE for failure
  2792. --*/
  2793. {
  2794. return CMetaInterface::Succeeded()
  2795. && CWamInterface::Succeeded()
  2796. && SUCCEEDED(m_hrApp);
  2797. }
  2798. /* virtual */
  2799. HRESULT
  2800. CIISApplication::QueryResult() const
  2801. /*++
  2802. Routine Description:
  2803. Return the construction error for this object
  2804. Arguments:
  2805. None
  2806. Return Value:
  2807. HRESULT from construction errors
  2808. --*/
  2809. {
  2810. //
  2811. // Both interfaces must have constructed successfully
  2812. //
  2813. HRESULT hr = CMetaInterface::QueryResult();
  2814. if (SUCCEEDED(hr))
  2815. {
  2816. hr = CWamInterface::QueryResult();
  2817. if (SUCCEEDED(hr))
  2818. {
  2819. hr = m_hrApp;
  2820. }
  2821. }
  2822. return hr;
  2823. }
  2824. HRESULT
  2825. CIISApplication::RefreshAppState()
  2826. /*++
  2827. Routine Description:
  2828. Refresh the application state
  2829. Arguments:
  2830. None
  2831. Return Value:
  2832. HRESULT
  2833. --*/
  2834. {
  2835. ASSERT(!m_strWamPath.IsEmpty());
  2836. HRESULT hr, hrKeys;
  2837. hr = AppGetStatus(m_strWamPath, &m_dwAppState);
  2838. if (FAILED(hr))
  2839. {
  2840. m_dwAppState = APPSTATUS_NOTDEFINED;
  2841. }
  2842. m_strAppRoot.Empty();
  2843. hrKeys = QueryValue(MD_APP_ROOT, m_strAppRoot, NULL, m_strWamPath);
  2844. m_dwProcessProtection = APP_INPROC;
  2845. hrKeys = QueryValue(
  2846. MD_APP_ISOLATED,
  2847. m_dwProcessProtection,
  2848. NULL,
  2849. m_strWamPath
  2850. );
  2851. m_strFriendlyName.Empty();
  2852. hrKeys = QueryValue(
  2853. MD_APP_FRIENDLY_NAME,
  2854. m_strFriendlyName,
  2855. NULL,
  2856. m_strWamPath
  2857. );
  2858. return hr;
  2859. }
  2860. HRESULT
  2861. CIISApplication::Create(
  2862. IN LPCTSTR lpszName, OPTIONAL
  2863. IN DWORD dwAppProtection
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. Create the application
  2868. Arguments:
  2869. LPCTSTR lpszName : Application name
  2870. DWORD dwAppProtection : APP_INPROC to create in-proc app
  2871. APP_OUTOFPROC to create out-of-proc app
  2872. APP_POOLEDPROC to create a pooled-proc app
  2873. Return Value:
  2874. HRESULT
  2875. --*/
  2876. {
  2877. ASSERT(!m_strWamPath.IsEmpty());
  2878. HRESULT hr = AppCreate(m_strWamPath, dwAppProtection);
  2879. if (SUCCEEDED(hr))
  2880. {
  2881. //
  2882. // Write the friendly app name, which we maintain
  2883. // ourselves. Empty it first, because we might
  2884. // have picked up a name from inheritance.
  2885. //
  2886. m_strFriendlyName.Empty();
  2887. hr = WriteFriendlyName(lpszName);
  2888. RefreshAppState();
  2889. }
  2890. return hr;
  2891. }
  2892. HRESULT
  2893. CIISApplication::WriteFriendlyName(
  2894. IN LPCTSTR lpszName
  2895. )
  2896. /*++
  2897. Routine Description:
  2898. Write the friendly name. This will not write anything
  2899. if the name is the same as it was
  2900. Arguments:
  2901. LPCTSTR lpszName : New friendly name
  2902. Return Value:
  2903. HRESULT
  2904. --*/
  2905. {
  2906. HRESULT hr = S_OK;
  2907. if (m_strFriendlyName.CompareNoCase(lpszName) != 0)
  2908. {
  2909. hr = Open(
  2910. METADATA_PERMISSION_WRITE,
  2911. METADATA_MASTER_ROOT_HANDLE,
  2912. m_strWamPath
  2913. );
  2914. if (SUCCEEDED(hr))
  2915. {
  2916. ASSERT(lpszName != NULL);
  2917. CString str(lpszName);
  2918. hr = SetValue(MD_APP_FRIENDLY_NAME, str);
  2919. Close();
  2920. if (SUCCEEDED(hr))
  2921. {
  2922. m_strFriendlyName = lpszName;
  2923. }
  2924. }
  2925. }
  2926. return hr;
  2927. }