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.

4768 lines
109 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name :
  4. mdkeys.cpp
  5. Abstract:
  6. Metabase key wrapper class
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. 2/17/2000 sergeia removed dependency on MFC
  14. --*/
  15. //
  16. // Include Files
  17. //
  18. #include "stdafx.h"
  19. #include "common.h"
  20. #include "inheritancedlg.h"
  21. #include "mdkeys.h"
  22. //
  23. // Constants
  24. //
  25. #define MB_TIMEOUT (15000) // Timeout in milliseconds
  26. #define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size
  27. //
  28. // CComAuthInfo implementation
  29. //
  30. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  31. /* static */
  32. BOOL
  33. CComAuthInfo::SplitUserNameAndDomain(
  34. IN OUT CString & strUserName,
  35. IN CString & strDomainName
  36. )
  37. /*++
  38. Routine Description:
  39. Split the user name and domain from the given
  40. username, which is in the format "domain\user".
  41. Return TRUE if the user name contained a domain
  42. FALSE if it did not
  43. Arguments:
  44. CString & strUserName : User name which may contain a domain name
  45. CString & strDomainName : Output domain name ("." if local)
  46. Return Value:
  47. TRUE if a domain is split off
  48. --*/
  49. {
  50. //
  51. // Assume local
  52. //
  53. strDomainName = _T(".");
  54. int nSlash = strUserName.Find(_T("\\"));
  55. if (nSlash >= 0)
  56. {
  57. strDomainName = strUserName.Left(nSlash);
  58. strUserName = strUserName.Mid(nSlash + 1);
  59. return TRUE;
  60. }
  61. return FALSE;
  62. }
  63. /* static */
  64. DWORD
  65. CComAuthInfo::VerifyUserPassword(
  66. IN LPCTSTR lpstrUserName,
  67. IN LPCTSTR lpstrPassword
  68. )
  69. /*++
  70. Routine Description:
  71. Verify the usernamer password combo checks out
  72. Arguments:
  73. LPCTSTR lpstrUserName : Domain/username combo
  74. LPCTSTR lpstrPassword : Password
  75. Return Value:
  76. ERROR_SUCCESS if the password checks out, an error code
  77. otherwise.
  78. --*/
  79. {
  80. CString strDomain;
  81. CString strUser(lpstrUserName);
  82. CString strPassword(lpstrPassword);
  83. SplitUserNameAndDomain(strUser, strDomain);
  84. //
  85. // In order to look up an account name, this process
  86. // must first be granted the privilege of doing so.
  87. //
  88. CError err;
  89. {
  90. HANDLE hToken;
  91. LUID AccountLookupValue;
  92. TOKEN_PRIVILEGES tkp;
  93. do
  94. {
  95. if (!::OpenProcessToken(GetCurrentProcess(),
  96. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  97. &hToken)
  98. )
  99. {
  100. err.GetLastWinError();
  101. break;
  102. }
  103. if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &AccountLookupValue))
  104. {
  105. err.GetLastWinError();
  106. break;
  107. }
  108. tkp.PrivilegeCount = 1;
  109. tkp.Privileges[0].Luid = AccountLookupValue;
  110. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  111. ::AdjustTokenPrivileges(
  112. hToken,
  113. FALSE,
  114. &tkp,
  115. sizeof(TOKEN_PRIVILEGES),
  116. (PTOKEN_PRIVILEGES)NULL,
  117. (PDWORD)NULL
  118. );
  119. err.GetLastWinError();
  120. if (err.Failed())
  121. {
  122. break;
  123. }
  124. HANDLE hUser = NULL;
  125. if (::LogonUser(
  126. (LPTSTR)(LPCTSTR)strUser,
  127. (LPTSTR)(LPCTSTR)strDomain,
  128. (LPTSTR)(LPCTSTR)strPassword,
  129. LOGON32_LOGON_NETWORK,
  130. LOGON32_PROVIDER_DEFAULT,
  131. &hUser
  132. ))
  133. {
  134. //
  135. // Success!
  136. //
  137. CloseHandle(hUser);
  138. }
  139. else
  140. {
  141. err.GetLastWinError();
  142. }
  143. //
  144. // Remove the privilege
  145. //
  146. }
  147. while(FALSE);
  148. }
  149. HANDLE hUser = NULL;
  150. if (::LogonUser(
  151. (LPTSTR)(LPCTSTR)strUser,
  152. (LPTSTR)(LPCTSTR)strDomain,
  153. (LPTSTR)(LPCTSTR)strPassword,
  154. LOGON32_LOGON_NETWORK,
  155. LOGON32_PROVIDER_DEFAULT,
  156. &hUser))
  157. {
  158. //
  159. // Success!
  160. //
  161. CloseHandle(hUser);
  162. }
  163. else
  164. {
  165. err.GetLastWinError();
  166. }
  167. return err;
  168. }
  169. CComAuthInfo::CComAuthInfo(
  170. IN LPCOLESTR lpszServerName OPTIONAL,
  171. IN LPCOLESTR lpszUserName OPTIONAL,
  172. IN LPCOLESTR lpszPassword OPTIONAL
  173. )
  174. /*++
  175. Routine Description:
  176. Construct CIIServer object
  177. Argument:
  178. LPCOLESTR lpszServerName : Server name or NULL for local computer
  179. LPCOLESTR lpszUserName : User name of blank for no impersonation
  180. LPCOLESTR lpszPassword : Password (might be blank or NULL)
  181. Return Value:
  182. N/A
  183. --*/
  184. : m_bstrServerName(),
  185. m_bstrUserName(lpszUserName),
  186. m_bstrPassword(lpszPassword),
  187. m_fLocal(FALSE)
  188. {
  189. SetComputerName(lpszServerName);
  190. }
  191. CComAuthInfo::CComAuthInfo(
  192. IN CComAuthInfo & auth
  193. )
  194. /*++
  195. Routine Description:
  196. Copy constructor
  197. Arguments:
  198. CComAuthInfo & auth : Source object to copy from
  199. Return Value:
  200. N/A
  201. --*/
  202. : m_bstrServerName(auth.m_bstrServerName),
  203. m_bstrUserName(auth.m_bstrUserName),
  204. m_bstrPassword(auth.m_bstrPassword),
  205. m_fLocal(auth.m_fLocal)
  206. {
  207. }
  208. CComAuthInfo::CComAuthInfo(
  209. IN CComAuthInfo * pAuthInfo OPTIONAL
  210. )
  211. /*++
  212. Routine Description:
  213. Copy constructor
  214. Arguments:
  215. CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
  216. Return Value:
  217. N/A
  218. --*/
  219. : m_bstrServerName(),
  220. m_bstrUserName(),
  221. m_bstrPassword(),
  222. m_fLocal(FALSE)
  223. {
  224. if (pAuthInfo)
  225. {
  226. //
  227. // Full authentication information available
  228. //
  229. m_bstrUserName = pAuthInfo->m_bstrUserName;
  230. m_bstrPassword = pAuthInfo->m_bstrPassword;
  231. m_bstrServerName = pAuthInfo->m_bstrServerName;
  232. m_fLocal = pAuthInfo->m_fLocal;
  233. }
  234. else
  235. {
  236. //
  237. // Local computer w/o impersonation
  238. //
  239. SetComputerName(NULL);
  240. }
  241. }
  242. CComAuthInfo &
  243. CComAuthInfo::operator =(
  244. IN CComAuthInfo & auth
  245. )
  246. /*++
  247. Routine Description:
  248. Assignment operator
  249. Arguments:
  250. CComAuthInfo & auth : Source object to copy from
  251. Return Value:
  252. Reference to current object
  253. --*/
  254. {
  255. m_bstrServerName = auth.m_bstrServerName;
  256. m_bstrUserName = auth.m_bstrUserName;
  257. m_bstrPassword = auth.m_bstrPassword;
  258. m_fLocal = auth.m_fLocal;
  259. return *this;
  260. }
  261. CComAuthInfo &
  262. CComAuthInfo::operator =(
  263. IN CComAuthInfo * pAuthInfo OPTIONAL
  264. )
  265. /*++
  266. Routine Description:
  267. Assignment operator
  268. Arguments:
  269. CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
  270. Return Value:
  271. Reference to current object
  272. --*/
  273. {
  274. if (pAuthInfo)
  275. {
  276. m_bstrUserName = pAuthInfo->m_bstrUserName;
  277. m_bstrPassword = pAuthInfo->m_bstrPassword;
  278. SetComputerName(pAuthInfo->m_bstrServerName);
  279. }
  280. else
  281. {
  282. //
  283. // Local computer w/o impersonation
  284. //
  285. m_bstrUserName.Empty();
  286. m_bstrPassword.Empty();
  287. SetComputerName(NULL);
  288. }
  289. return *this;
  290. }
  291. CComAuthInfo &
  292. CComAuthInfo::operator =(
  293. IN LPCTSTR lpszServerName
  294. )
  295. /*++
  296. Routine Description:
  297. Assignment operator. Assign computer name w/o impersonation
  298. Arguments:
  299. LPCTSTR lpszServerName : Source server name
  300. Return Value:
  301. Reference to current object
  302. --*/
  303. {
  304. RemoveImpersonation();
  305. SetComputerName(lpszServerName);
  306. return *this;
  307. }
  308. void
  309. CComAuthInfo::SetComputerName(
  310. IN LPCOLESTR lpszServerName OPTIONAL
  311. )
  312. /*++
  313. Routine Description:
  314. Store the computer name. Determine if its local.
  315. Arguments:
  316. LPCOLESTR lpszServername : Server name. NULL indicates the local computer
  317. Return Value:
  318. None
  319. --*/
  320. {
  321. if (lpszServerName && *lpszServerName)
  322. {
  323. //
  324. // Specific computer name specified
  325. //
  326. m_bstrServerName = lpszServerName;
  327. m_fLocal = ::IsServerLocal(lpszServerName);
  328. }
  329. else
  330. {
  331. //
  332. // Use local computer name
  333. //
  334. // CODEWORK: Cache static version of computername maybe?
  335. //
  336. TCHAR szLocalServer[MAX_PATH + 1];
  337. DWORD dwSize = MAX_PATH;
  338. VERIFY(::GetComputerName(szLocalServer, &dwSize));
  339. m_bstrServerName = szLocalServer;
  340. m_fLocal = TRUE;
  341. }
  342. }
  343. void
  344. CComAuthInfo::SetImpersonation(
  345. IN LPCOLESTR lpszUser,
  346. IN LPCOLESTR lpszPassword
  347. )
  348. /*++
  349. Routine Description:
  350. Set impersonation parameters
  351. Arguments:
  352. LPCOLESTR lpszUser : User name
  353. LPCOLESTR lpszPassword : Password
  354. Return Value:
  355. None
  356. --*/
  357. {
  358. m_bstrUserName = lpszUser;
  359. StorePassword(lpszPassword);
  360. }
  361. void
  362. CComAuthInfo::RemoveImpersonation()
  363. /*++
  364. Routine Description:
  365. Remove impersonation parameters
  366. Arguments:
  367. None
  368. Return Value:
  369. None
  370. --*/
  371. {
  372. m_bstrUserName.Empty();
  373. m_bstrPassword.Empty();
  374. }
  375. COSERVERINFO *
  376. CComAuthInfo::CreateServerInfoStruct() const
  377. /*++
  378. Routine Description:
  379. Create the server info structure. Might return NULL for the no frills case.
  380. Arguments:
  381. NULL
  382. Return Value:
  383. A COSERVERINFO structure, or NULL if the computer is local, and no
  384. impersonation is required.
  385. Notes:
  386. Caller must call FreeServerInfoStruct() to prevent memory leaks
  387. --*/
  388. {
  389. //
  390. // Be smart about the server name; optimize for local
  391. // computer name.
  392. //
  393. if (m_fLocal && !UsesImpersonation())
  394. {
  395. //
  396. // Special, no-frills case.
  397. //
  398. return NULL;
  399. }
  400. //
  401. // Create the COM server info for CoCreateInstanceEx
  402. //
  403. COSERVERINFO * pcsiName = NULL;
  404. do
  405. {
  406. pcsiName = new COSERVERINFO;
  407. if (!pcsiName)
  408. {
  409. break;
  410. }
  411. ZeroMemory(pcsiName, sizeof(COSERVERINFO));
  412. pcsiName->pwszName = m_bstrServerName;
  413. //
  414. // Set impersonation
  415. //
  416. if (UsesImpersonation())
  417. {
  418. COAUTHINFO * pAuthInfo = new COAUTHINFO;
  419. if (!pAuthInfo)
  420. {
  421. break;
  422. }
  423. ZeroMemory(pAuthInfo, sizeof(COAUTHINFO));
  424. COAUTHIDENTITY * pAuthIdentityData = new COAUTHIDENTITY;
  425. if (!pAuthIdentityData)
  426. {
  427. break;
  428. }
  429. ZeroMemory(pAuthIdentityData, sizeof(COAUTHIDENTITY));
  430. CString strUserName(m_bstrUserName);
  431. CString strPassword(m_bstrPassword);
  432. CString strDomain;
  433. //
  434. // Break up domain\username combo
  435. //
  436. SplitUserNameAndDomain(strUserName, strDomain);
  437. pAuthIdentityData->UserLength = strUserName.GetLength();
  438. if (pAuthIdentityData->UserLength != 0)
  439. {
  440. pAuthIdentityData->User = StrDup(strUserName);
  441. }
  442. pAuthIdentityData->DomainLength = strDomain.GetLength();
  443. if (pAuthIdentityData->DomainLength != 0)
  444. {
  445. pAuthIdentityData->Domain = StrDup(strDomain);
  446. }
  447. pAuthIdentityData->PasswordLength = strPassword.GetLength();
  448. if (pAuthIdentityData->PasswordLength)
  449. {
  450. pAuthIdentityData->Password = StrDup(strPassword);
  451. }
  452. pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  453. pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  454. pAuthInfo->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
  455. pAuthInfo->dwAuthnSvc = RPC_C_AUTHN_WINNT;
  456. pAuthInfo->dwAuthzSvc = RPC_C_AUTHZ_NONE;
  457. pAuthInfo->pwszServerPrincName = NULL;
  458. pAuthInfo->dwCapabilities = EOAC_NONE;
  459. pAuthInfo->pAuthIdentityData = pAuthIdentityData;
  460. pcsiName->pAuthInfo = pAuthInfo;
  461. }
  462. }
  463. while(FALSE);
  464. return pcsiName;
  465. }
  466. void
  467. CComAuthInfo::FreeServerInfoStruct(
  468. IN COSERVERINFO * pServerInfo
  469. ) const
  470. /*++
  471. Routine Description:
  472. As mentioned above -- free the server info structure
  473. Arguments:
  474. COSERVERINFO * pServerInfo : Server info structure
  475. Return Value:
  476. None
  477. --*/
  478. {
  479. if (pServerInfo)
  480. {
  481. if (pServerInfo->pAuthInfo)
  482. {
  483. if (pServerInfo->pAuthInfo->pAuthIdentityData)
  484. {
  485. if (pServerInfo->pAuthInfo->pAuthIdentityData)
  486. {
  487. LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->User);
  488. LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->Domain);
  489. LocalFree(pServerInfo->pAuthInfo->pAuthIdentityData->Password);
  490. delete pServerInfo->pAuthInfo->pAuthIdentityData;
  491. }
  492. }
  493. delete pServerInfo->pAuthInfo;
  494. }
  495. delete pServerInfo;
  496. }
  497. }
  498. HRESULT
  499. CComAuthInfo::ApplyProxyBlanket(
  500. IN OUT IUnknown * pInterface
  501. )
  502. /*++
  503. Routine Description:
  504. Set security information on the interface. The user name is of the form
  505. domain\username.
  506. Arguments:
  507. IUnknown * pInterface : Interface
  508. Return Value:
  509. HRESULT
  510. --*/
  511. {
  512. HRESULT hr = S_OK;
  513. COSERVERINFO * pcsiName = CreateServerInfoStruct();
  514. //
  515. // This method should only be called if we're using impersonation.
  516. // so the pcsiName returned should never be NULL.
  517. //
  518. ATLASSERT(pcsiName && pcsiName->pAuthInfo);
  519. DWORD dwAuthSvc, dwAuthzSvc, dwAuthnLevel, dwImplLevel, dwCaps;
  520. OLECHAR * pServerPrincName;
  521. RPC_AUTH_IDENTITY_HANDLE pAuthInfo;
  522. hr = ::CoQueryProxyBlanket(
  523. pInterface,
  524. &dwAuthSvc,
  525. &dwAuthzSvc,
  526. &pServerPrincName,
  527. &dwAuthnLevel,
  528. &dwImplLevel,
  529. &pAuthInfo,
  530. &dwCaps);
  531. if (pcsiName && pcsiName->pAuthInfo)
  532. {
  533. hr = ::CoSetProxyBlanket(
  534. pInterface,
  535. pcsiName->pAuthInfo->dwAuthnSvc,
  536. pcsiName->pAuthInfo->dwAuthzSvc,
  537. pcsiName->pAuthInfo->pwszServerPrincName,
  538. pcsiName->pAuthInfo->dwAuthnLevel,
  539. pcsiName->pAuthInfo->dwImpersonationLevel,
  540. pcsiName->pAuthInfo->pAuthIdentityData,
  541. pcsiName->pAuthInfo->dwCapabilities
  542. );
  543. FreeServerInfoStruct(pcsiName);
  544. }
  545. return hr;
  546. }
  547. //
  548. // CMetabasePath implemention
  549. //
  550. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  551. const LPCTSTR CMetabasePath::_cszMachine = SZ_MBN_MACHINE;
  552. const LPCTSTR CMetabasePath::_cszRoot = SZ_MBN_ROOT;
  553. const LPCTSTR CMetabasePath::_cszSep = SZ_MBN_SEP_STR;
  554. const TCHAR CMetabasePath::_chSep = SZ_MBN_SEP_CHAR;
  555. const CString CMetabasePath::_anySep = SZ_MBN_ANYSEP_STR;
  556. /*static*/
  557. BOOL
  558. CMetabasePath::IsSeparator(TCHAR c)
  559. {
  560. return _anySep.find(c) != CString::npos;
  561. }
  562. /* static */
  563. LPCTSTR
  564. CMetabasePath::ConvertToParentPath(
  565. CString& strMetaPath
  566. )
  567. /*++
  568. Routine Description:
  569. Given the path, convert it to the parent path
  570. e.g. "foo/bar/etc" returns "foo/bar"
  571. Arguments:
  572. CString & strMetaPath : Path to be converted
  573. Return value:
  574. Pointer to the converted path, or NULL in case of error
  575. --*/
  576. {
  577. // TRACE(_T("Getting parent path of %s\n"), strMetaPath);
  578. CString::size_type pos, pos_head;
  579. if ((pos = strMetaPath.find_last_of(SZ_MBN_ANYSEP_STR)) == strMetaPath.length() - 1)
  580. {
  581. strMetaPath.erase(pos);
  582. }
  583. pos = strMetaPath.find_last_of(SZ_MBN_ANYSEP_STR);
  584. if (pos == CString::npos)
  585. return strMetaPath;
  586. pos_head = strMetaPath.find_first_of(SZ_MBN_ANYSEP_STR);
  587. if (pos_head != pos)
  588. {
  589. strMetaPath.erase(pos);
  590. }
  591. // TRACE(_T("Parent path should be %s\n"), strMetaPath);
  592. return strMetaPath;
  593. }
  594. LPCTSTR
  595. CMetabasePath::ConvertToParentPath(
  596. CMetabasePath& path
  597. )
  598. {
  599. return CMetabasePath::ConvertToParentPath(path.m_strMetaPath);
  600. }
  601. /* static */
  602. LPCTSTR
  603. CMetabasePath::TruncatePath(
  604. int nLevel,
  605. LPCTSTR lpszMDPath,
  606. CString & strNewPath,
  607. CString * pstrRemainder OPTIONAL
  608. )
  609. /*++
  610. Routine Description:
  611. Truncate the given metabase path at the given level, that is,
  612. the nLevel'th separator in the path, starting at 0, where 0 will
  613. always give lpszPath back whether it started with a separator or not.
  614. Examples:
  615. "/lm/w3svc/1/foo" at level 2 returns "/lm/w3svc" as does
  616. "lm/w3svc/1/foo".
  617. Arguments:
  618. int nLevel 0-based separator count to truncate at.
  619. LPTSTR lpszMDPath Fully-qualified metabase path
  620. CString & strNewPath Returns truncated path
  621. CString * pstrRemainder Optionally returns the remainder past
  622. the nLevel'th separator.
  623. Return Value:
  624. The truncated path at the level requested. See examples above. *pstrRemainder
  625. returns the remainder of the path. If the path does not contain nLevel
  626. worth of separators, the entire path is returned, and the remainder will be
  627. blank.
  628. --*/
  629. {
  630. // ASSERT_PTR(lpszMDPath);
  631. ATLASSERT(nLevel >= 0);
  632. if (!lpszMDPath || nLevel < 0)
  633. {
  634. // TRACE(_T("TruncatePath: Invalid parameter\n"));
  635. return NULL;
  636. }
  637. // TRACE(_T("Source Path: %s\n"), lpszMDPath);
  638. //
  639. // Skip the first sep whether it exists or not
  640. //
  641. LPCTSTR lp = IsSeparator(*lpszMDPath) ? lpszMDPath + 1 : lpszMDPath;
  642. LPCTSTR lpRem = NULL;
  643. int cSeparators = 0;
  644. if (nLevel)
  645. {
  646. //
  647. // Advance to the requested separator level
  648. //
  649. while (*lp)
  650. {
  651. if (IsSeparator(*lp))
  652. {
  653. if (++cSeparators == nLevel)
  654. {
  655. break;
  656. }
  657. }
  658. ++lp;
  659. }
  660. if (!*lp)
  661. {
  662. //
  663. // End of path is considered a separator
  664. //
  665. ++cSeparators;
  666. }
  667. ATLASSERT(cSeparators <= nLevel);
  668. if (cSeparators == nLevel)
  669. {
  670. //
  671. // Break up the strings
  672. //
  673. strNewPath = lpszMDPath;
  674. strNewPath.erase(lp - lpszMDPath);
  675. // TRACE(_T("Path truncated at level %d : %s\n"), nLevel, strNewPath);
  676. if (*lp)
  677. {
  678. lpRem = ++lp;
  679. // TRACE(_T("Remainder: %s\n"), lpRem);
  680. }
  681. }
  682. }
  683. //
  684. // Return remainder
  685. //
  686. if (pstrRemainder && lpRem)
  687. {
  688. // ASSERT_WRITE_PTR(pstrRemainder);
  689. *pstrRemainder = lpRem;
  690. }
  691. return strNewPath;
  692. }
  693. /* static */
  694. DWORD
  695. CMetabasePath::GetInstanceNumber(
  696. IN LPCTSTR lpszMDPath
  697. )
  698. /*++
  699. Routine Description:
  700. Get the number of the instance referred to in the given metabase
  701. path.
  702. Examples: "lm/w3svc/1/foo/bar" will return 1
  703. "lm/w3svc/" will return 0 (master instance)
  704. "lm/bogus/path/" will return 0xffffffff (error)
  705. Arguments:
  706. LPCTSTR lpszMDPath : A metabase path.
  707. Return Value:
  708. Instance number (0 indicates master instance)
  709. or 0xffffffff if the path is in error.
  710. --*/
  711. {
  712. // TRACE(_T("Determining instance number of %s\n"), lpszMDPath);
  713. DWORD dwInstance = 0xffffffff;
  714. CString strService, strInst;
  715. if (GetServicePath(lpszMDPath, strService, &strInst))
  716. {
  717. if (strInst.IsEmpty())
  718. {
  719. dwInstance = MASTER_INSTANCE;
  720. }
  721. else
  722. {
  723. if (_istdigit(strInst.GetAt(0)))
  724. {
  725. dwInstance = _ttol(strInst);
  726. }
  727. }
  728. }
  729. return dwInstance;
  730. }
  731. /* static */
  732. LPCTSTR
  733. CMetabasePath::GetLastNodeName(
  734. IN LPCTSTR lpszMDPath,
  735. OUT CString & strNodeName
  736. )
  737. /*++
  738. Routine Description:
  739. Get the last nodename off the metabase path
  740. Example:
  741. "/lm/foo/bar/" returns "bar"
  742. Arguments:
  743. LPCTSTR lpszMDPath : Metabase path
  744. Return Value:
  745. Pointer to the node name or NULL in case of a malformed path.
  746. --*/
  747. {
  748. // ASSERT_PTR(lpszMDPath);
  749. if (!lpszMDPath || !*lpszMDPath)
  750. {
  751. return NULL;
  752. }
  753. // TRACE(_T("Getting last node name from %s\n"), lpszMDPath);
  754. LPCTSTR lp;
  755. LPCTSTR lpTail;
  756. lp = lpTail = lpszMDPath + lstrlen(lpszMDPath) - 1;
  757. //
  758. // Skip trailing separator
  759. //
  760. if (IsSeparator(*lp))
  761. {
  762. --lpTail;
  763. --lp;
  764. }
  765. strNodeName.Empty();
  766. while (*lp && !IsSeparator(*lp))
  767. {
  768. strNodeName += *(lp--);
  769. }
  770. strNodeName.MakeReverse();
  771. // TRACE(_T("Node is %s\n"), strNodeName);
  772. return strNodeName;
  773. }
  774. /* static */
  775. void
  776. CMetabasePath::SplitMetaPathAtInstance(
  777. LPCTSTR lpszMDPath,
  778. CString & strParent,
  779. CString & strAlias
  780. )
  781. /*++
  782. Routine Description:
  783. Split the given path into parent metabase root and alias, with the root
  784. being the instance path, and the alias everything following the
  785. instance.
  786. Arguments:
  787. LPCTSTR lpszMDPath : Input path
  788. CString & strParent : Outputs the parent path
  789. CString & strAlias : Outputs the alias name
  790. Return Value:
  791. None.
  792. --*/
  793. {
  794. // ASSERT_PTR(lpszMDPath);
  795. // TRACE(_T("Source Path %s\n"), lpszMDPath);
  796. strParent = lpszMDPath;
  797. strAlias.Empty();
  798. LPTSTR lp = (LPTSTR)lpszMDPath;
  799. if (lp == NULL)
  800. {
  801. return;
  802. }
  803. int cSeparators = 0;
  804. int iChar = 0;
  805. //
  806. // Looking for "LM/sss/ddd/" <-- 3d slash:
  807. //
  808. while (*lp && cSeparators < 2)
  809. {
  810. if (IsSeparator(*lp))
  811. {
  812. ++cSeparators;
  813. }
  814. ++iChar;
  815. }
  816. if (!*lp)
  817. {
  818. //
  819. // Bogus format
  820. //
  821. ASSERT_MSG("Bogus Format");
  822. return;
  823. }
  824. if (_istdigit(*lp))
  825. {
  826. //
  827. // Not at the master instance, skip one more.
  828. //
  829. while (*lp)
  830. {
  831. ++iChar;
  832. if (IsSeparator(*lp++))
  833. {
  834. break;
  835. }
  836. }
  837. if (!*lp)
  838. {
  839. //
  840. // Bogus format
  841. //
  842. ASSERT_MSG("Bogus Format");
  843. return;
  844. }
  845. }
  846. strAlias = strParent.Mid(iChar);
  847. strParent.erase(iChar);
  848. // TRACE(_T("Broken up into %s\n"), strParent);
  849. // TRACE(_T(" and %s\n"), strAlias);
  850. }
  851. /* static */
  852. BOOL
  853. CMetabasePath::IsHomeDirectoryPath(
  854. IN LPCTSTR lpszMetaPath
  855. )
  856. /*++
  857. Routine Description:
  858. Determine if the path given describes a root directory
  859. Arguments:
  860. LPCTSTR lpszMetaPath : Metabase path
  861. Return Value:
  862. TRUE if the path describes a root directory,
  863. FALSE if it does not
  864. --*/
  865. {
  866. // ASSERT_READ_PTR(lpszMetaPath);
  867. LPTSTR lpNode = lpszMetaPath ? StrPBrk(lpszMetaPath, _anySep) : NULL;
  868. if (lpNode)
  869. {
  870. return _tcsicmp(++lpNode, _cszRoot) == 0;
  871. }
  872. return FALSE;
  873. }
  874. /* static */
  875. BOOL
  876. CMetabasePath::IsMasterInstance(
  877. IN LPCTSTR lpszMDPath
  878. )
  879. /*++
  880. Routine Description:
  881. Determine if the given metabase path points to the master instance
  882. (site). This is essentially the service path.
  883. Arguments:
  884. LPCTSTR lpszMDPath : Metabase path.
  885. Return Value:
  886. TRUE if the path is the master instance,
  887. FALSE otherwise.
  888. --*/
  889. {
  890. // ASSERT_READ_PTR(lpszMDPath);
  891. if (!lpszMDPath || !*lpszMDPath)
  892. {
  893. return FALSE;
  894. }
  895. // TRACE(_T("Checking path %s\n"), lpszMDPath);
  896. CString strService;
  897. CString strRemainder;
  898. LPCTSTR lpPath = TruncatePath(2, lpszMDPath, strService, &strRemainder);
  899. return lpPath && !strService.IsEmpty() && strRemainder.IsEmpty();
  900. }
  901. /* static */
  902. LPCTSTR
  903. CMetabasePath::GetServiceInfoPath(
  904. IN LPCTSTR lpszMDPath,
  905. OUT CString & strInfoPath,
  906. IN LPCTSTR lpszDefService OPTIONAL
  907. )
  908. /*++
  909. Routine Description:
  910. Generate the appropriate metabase service info path for the given
  911. metabase path.
  912. For example:
  913. "lm/w3svc/1/foo/bar" Generates "lm/w3svc/info"
  914. Arguments:
  915. LPCTSTR lpszMDPath : Input metabase path
  916. CString & strInfoPath : Returns the info path
  917. LPCTSTR lpszDefService : Optionally specifies the default service to
  918. use (e.g "w3svc") if no service could be found
  919. in the path.
  920. Return Value:
  921. The info metabase path or NULL if one could not be generated.
  922. --*/
  923. {
  924. //
  925. // Capability info stored off the service path ("lm/w3svc").
  926. //
  927. CString strService;
  928. CString strRem;
  929. //
  930. // Strip off everything past the service
  931. //
  932. if (!TruncatePath(2, lpszMDPath, strService, &strRem)
  933. || strService.IsEmpty())
  934. {
  935. if (!lpszDefService)
  936. {
  937. // TRACEEOLID("Unable to generate info path");
  938. return NULL;
  939. }
  940. TRACEEOLID("Using default service for info path");
  941. //
  942. // Machine path (no service). Use web as default service to
  943. // look for capability and version info.
  944. //
  945. strService = CMetabasePath(TRUE, lpszDefService);
  946. }
  947. strInfoPath = CMetabasePath(FALSE, strService, SZ_MBN_INFO);
  948. // TRACE("Using %s to look for capability info\n", strInfoPath);
  949. return strInfoPath;
  950. }
  951. /* static */
  952. LPCTSTR
  953. CMetabasePath::CleanMetaPath(
  954. IN OUT CString & strMetaRoot
  955. )
  956. /*++
  957. Routine Description:
  958. Clean up the metabase path to one valid for internal consumption.
  959. This removes the beginning and trailing slashes off the path.
  960. Arguments:
  961. CString & strMetaRoot : Metabase path to be cleaned up.
  962. Return Value:
  963. Pointer to the metabase path
  964. --*/
  965. {
  966. if (!strMetaRoot.IsEmpty())
  967. {
  968. int hd = strMetaRoot.find_first_not_of(SZ_MBN_ANYSEP_STR);
  969. int tl = strMetaRoot.find_last_not_of(SZ_MBN_ANYSEP_STR);
  970. if (hd == CString::npos && tl == CString::npos)
  971. {
  972. // path contains only separators
  973. strMetaRoot.erase();
  974. return strMetaRoot;
  975. }
  976. else if (hd != CString::npos)
  977. {
  978. if (tl != CString::npos)
  979. tl++;
  980. strMetaRoot = strMetaRoot.substr(hd, tl - hd);
  981. }
  982. #if 0
  983. while (strMetaRoot.GetLength() > 0
  984. && IsSeparator(strMetaRoot[strMetaRoot.GetLength() - 1]))
  985. {
  986. strMetaRoot.erase(strMetaRoot.GetLength() - 1);
  987. }
  988. while (strMetaRoot.GetLength() > 0
  989. && IsSeparator(strMetaRoot[0]))
  990. {
  991. strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1);
  992. }
  993. #endif
  994. // looks like IISAdmin works only with separators "/"
  995. for (int i = 0; i < strMetaRoot.GetLength(); i++)
  996. {
  997. if (IsSeparator(strMetaRoot[i]))
  998. strMetaRoot.SetAt(i, _chSep);
  999. }
  1000. }
  1001. return strMetaRoot;
  1002. }
  1003. /* static */
  1004. LPCTSTR
  1005. CMetabasePath::CleanMetaPath(
  1006. IN OUT CMetabasePath & path
  1007. )
  1008. {
  1009. return CleanMetaPath(path.m_strMetaPath);
  1010. }
  1011. CMetabasePath::CMetabasePath(
  1012. IN BOOL fAddBasePath,
  1013. IN LPCTSTR lpszMDPath,
  1014. IN LPCTSTR lpszMDPath2 OPTIONAL,
  1015. IN LPCTSTR lpszMDPath3 OPTIONAL,
  1016. IN LPCTSTR lpszMDPath4 OPTIONAL
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Constructor.
  1021. Arguments:
  1022. BOOL fAddBasePath : TRUE to prepend base path ("LM")
  1023. FALSE if the path is complete
  1024. LPCTSTR lpszMDPath : Metabase path
  1025. LPCTSTR lpszMDPath2 : Optional child path
  1026. LPCTSTR lpszMDPath3 : Optional child path
  1027. LPCTSTR lpszMDPath4 : Optional child path
  1028. Return Value:
  1029. N/A
  1030. --*/
  1031. : m_strMetaPath()
  1032. {
  1033. ASSERT_READ_PTR(lpszMDPath);
  1034. if (fAddBasePath)
  1035. {
  1036. m_strMetaPath = _cszMachine;
  1037. AppendPath(lpszMDPath);
  1038. }
  1039. else
  1040. {
  1041. m_strMetaPath = lpszMDPath;
  1042. }
  1043. //
  1044. // Add optional path components
  1045. //
  1046. AppendPath(lpszMDPath2);
  1047. AppendPath(lpszMDPath3);
  1048. AppendPath(lpszMDPath4);
  1049. }
  1050. CMetabasePath::CMetabasePath(
  1051. IN LPCTSTR lpszSvc, OPTIONAL
  1052. IN DWORD dwInstance, OPTIONAL
  1053. IN LPCTSTR lpszParentPath, OPTIONAL
  1054. IN LPCTSTR lpszAlias OPTIONAL
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. Constructor. Construct with path components.
  1059. Arguments:
  1060. LPCTSTR lpszSvc : Service (may be NULL or "")
  1061. DWORD dwInstance : Instance number (may be 0 for master)
  1062. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1063. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1064. Return Value:
  1065. N/A
  1066. --*/
  1067. : m_strMetaPath()
  1068. {
  1069. BuildMetaPath(lpszSvc, dwInstance, lpszParentPath, lpszAlias);
  1070. }
  1071. void
  1072. CMetabasePath::AppendPath(
  1073. IN LPCTSTR lpszPath
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. Append path to current metabase path
  1078. Arguments:
  1079. LPCTSTR lpszPath : Metabase path
  1080. Return Value:
  1081. None
  1082. --*/
  1083. {
  1084. if (lpszPath && *lpszPath)
  1085. {
  1086. m_strMetaPath += _cszSep;
  1087. m_strMetaPath += lpszPath;
  1088. }
  1089. }
  1090. void
  1091. CMetabasePath::AppendPath(
  1092. IN DWORD dwInstance
  1093. )
  1094. /*++
  1095. Routine Description:
  1096. Append path to current metabase path
  1097. Arguments:
  1098. DWORD dwInstance : Instance path
  1099. Return Value:
  1100. None
  1101. --*/
  1102. {
  1103. // ASSERT(dwInstance >= 0);
  1104. if (!IS_MASTER_INSTANCE(dwInstance))
  1105. {
  1106. TCHAR szInstance[] = _T("4000000000");
  1107. _ltot(dwInstance, szInstance, 10);
  1108. m_strMetaPath += _cszSep;
  1109. m_strMetaPath += szInstance;
  1110. }
  1111. }
  1112. void
  1113. CMetabasePath::BuildMetaPath(
  1114. IN LPCTSTR lpszSvc OPTIONAL,
  1115. IN LPCTSTR lpszInstance OPTIONAL,
  1116. IN LPCTSTR lpszParentPath OPTIONAL,
  1117. IN LPCTSTR lpszAlias OPTIONAL
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Build a complete metapath with the given service name, instance
  1122. number and optional path components.
  1123. Arguments:
  1124. LPCTSTR lpszSvc : Service (may be NULL or "")
  1125. LPCTSTR lpszInstance : Instance (may be NULL or "")
  1126. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1127. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1128. Return Value:
  1129. Pointer to internal buffer containing the path.
  1130. --*/
  1131. {
  1132. m_strMetaPath = _cszMachine;
  1133. AppendPath(lpszSvc);
  1134. AppendPath(lpszInstance);
  1135. AppendPath(lpszParentPath);
  1136. if (lpszAlias && *lpszAlias)
  1137. {
  1138. //
  1139. // Special case: If the alias is root, but we're
  1140. // at the master instance, ignore this.
  1141. //
  1142. if (lpszInstance || ::lstrcmpi(_cszRoot, lpszAlias))
  1143. {
  1144. m_strMetaPath += _cszSep;
  1145. m_strMetaPath += lpszAlias;
  1146. }
  1147. }
  1148. // TRACE(_T("Generated metapath: %s\n"), m_strMetaPath );
  1149. }
  1150. void
  1151. CMetabasePath::BuildMetaPath(
  1152. IN LPCTSTR lpszSvc OPTIONAL,
  1153. IN DWORD dwInstance OPTIONAL,
  1154. IN LPCTSTR lpszParentPath OPTIONAL,
  1155. IN LPCTSTR lpszAlias OPTIONAL
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Build a complete metapath with the given service name, instance
  1160. number and optional path components.
  1161. Arguments:
  1162. LPCTSTR lpszSvc : Service (may be NULL or "")
  1163. DWORD dwInstance : Instance number (may be 0 for master)
  1164. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1165. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1166. Return Value:
  1167. Pointer to internal buffer containing the path.
  1168. --*/
  1169. {
  1170. m_strMetaPath = _cszMachine;
  1171. AppendPath(lpszSvc);
  1172. AppendPath(dwInstance);
  1173. AppendPath(lpszParentPath);
  1174. if (lpszAlias && *lpszAlias)
  1175. {
  1176. //
  1177. // Special case: If the alias is root, but we're
  1178. // at the master instance, ignore this.
  1179. //
  1180. if (!IS_MASTER_INSTANCE(dwInstance) || ::lstrcmpi(_cszRoot, lpszAlias))
  1181. {
  1182. m_strMetaPath += _cszSep;
  1183. m_strMetaPath += lpszAlias;
  1184. }
  1185. }
  1186. // TRACE(_T("Generated metapath: %s\n"), m_strMetaPath);
  1187. }
  1188. //
  1189. // CIISInterface class
  1190. //
  1191. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1192. CIISInterface::CIISInterface(
  1193. IN CComAuthInfo * pAuthInfo, OPTIONAL
  1194. IN HRESULT hrInterface OPTIONAL
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. Base class constructor.
  1199. Arguments:
  1200. CComAuthInfo * pAuthInfo : Auth info or NULL for local computer
  1201. HRESULT hrInterface : Initial error code. S_OK by default.
  1202. Return Value:
  1203. N/A
  1204. --*/
  1205. : m_auth(pAuthInfo),
  1206. m_hrInterface(hrInterface)
  1207. {
  1208. }
  1209. HRESULT
  1210. CIISInterface::Create(
  1211. IN int cInterfaces,
  1212. IN const IID rgIID[],
  1213. IN const GUID rgCLSID[],
  1214. OUT int * pnInterface, OPTIONAL
  1215. OUT IUnknown ** ppInterface
  1216. )
  1217. /*++
  1218. Routine Description:
  1219. Create interface. This will try a range of interfaces in order of priority.
  1220. Arguments:
  1221. int cInterfaces : Number of interfaces in array.
  1222. const IID * rgIID : Array if IIDs
  1223. const GUID * rgCLSID : Array of CLSIDs
  1224. int * pnInterface : Returns the interface index that was successful.
  1225. or NULL if not interested.
  1226. IUnknown ** ppInterface : Returns pointer to the interface.
  1227. Return Value:
  1228. HRESULT
  1229. Notes:
  1230. This will attempt to create an interface, in order of declaration in
  1231. the IID and CLSIS arrays. The first successful interface to be created
  1232. will have its index returned in *pnInterfaces.
  1233. --*/
  1234. {
  1235. ASSERT(cInterfaces > 0);
  1236. ASSERT(rgIID && rgCLSID && ppInterface);
  1237. COSERVERINFO * pcsiName = m_auth.CreateServerInfoStruct();
  1238. MULTI_QI rgmqResults;
  1239. CError err;
  1240. int nInterface;
  1241. //
  1242. // Try to create the interface in order
  1243. //
  1244. for (nInterface = 0; nInterface < cInterfaces; ++nInterface)
  1245. {
  1246. ZeroMemory(&rgmqResults, sizeof(rgmqResults));
  1247. rgmqResults.pIID = &rgIID[nInterface];
  1248. // TRACE("Attempting to create interface #%d\n", nInterface);
  1249. err = ::CoCreateInstanceEx(
  1250. rgCLSID[nInterface],
  1251. NULL,
  1252. CLSCTX_SERVER,
  1253. pcsiName,
  1254. 1,
  1255. &rgmqResults
  1256. );
  1257. if (err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED)
  1258. {
  1259. break;
  1260. }
  1261. }
  1262. if(err.Succeeded())
  1263. {
  1264. //
  1265. // Save the interface pointer
  1266. //
  1267. ASSERT_PTR(rgmqResults.pItf);
  1268. *ppInterface = rgmqResults.pItf;
  1269. if (pnInterface)
  1270. {
  1271. //
  1272. // Store successful interface index
  1273. //
  1274. *pnInterface = nInterface;
  1275. }
  1276. //
  1277. // Strangely enough, I now have still have to apply
  1278. // the proxy blanket. Apparently this is by design.
  1279. //
  1280. if (m_auth.UsesImpersonation())
  1281. {
  1282. ApplyProxyBlanket();
  1283. }
  1284. }
  1285. //
  1286. // Clean up
  1287. //
  1288. m_auth.FreeServerInfoStruct(pcsiName);
  1289. return err;
  1290. }
  1291. //
  1292. // CMetaInterface class
  1293. //
  1294. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1295. CMetaInterface::CMetaInterface(
  1296. IN CComAuthInfo * pAuthInfo OPTIONAL
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. Construct and initialize the interface
  1301. Arguments:
  1302. CComAuthInfo * pAuthInfo : Authentication info. NULL indicates
  1303. the local computer.
  1304. Return Value:
  1305. N/A
  1306. --*/
  1307. : CIISInterface(pAuthInfo),
  1308. m_pInterface(NULL),
  1309. m_iTimeOutValue(MB_TIMEOUT)
  1310. {
  1311. //
  1312. // Initialize the interface
  1313. //
  1314. m_hrInterface = Create();
  1315. }
  1316. CMetaInterface::CMetaInterface(
  1317. IN CMetaInterface * pInterface
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. Construct from existing interface (Copy Constructor)
  1322. Arguments:
  1323. CMetaInterface * pInterface : Existing interface
  1324. Return Value:
  1325. N/A
  1326. Notes:
  1327. Object will not take ownership of the interface,
  1328. it will merely add to the reference count, and
  1329. release it upon destruction
  1330. BUGBUG:
  1331. if pInterface is NULL, this will AV.
  1332. --*/
  1333. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  1334. m_pInterface(pInterface->m_pInterface),
  1335. m_iTimeOutValue(pInterface->m_iTimeOutValue)
  1336. {
  1337. ASSERT_READ_PTR(m_pInterface);
  1338. m_pInterface->AddRef();
  1339. }
  1340. CMetaInterface::~CMetaInterface()
  1341. /*++
  1342. Routine Description:
  1343. Destructor -- releases the interface
  1344. Arguments:
  1345. N/A
  1346. Return Value:
  1347. N/A
  1348. --*/
  1349. {
  1350. SAFE_RELEASE(m_pInterface);
  1351. }
  1352. HRESULT
  1353. CMetaInterface::Create()
  1354. {
  1355. return CIISInterface::Create(
  1356. 1,
  1357. &IID_IMSAdminBase,
  1358. &CLSID_MSAdminBase,
  1359. NULL,
  1360. (IUnknown **)&m_pInterface
  1361. );
  1362. }
  1363. //
  1364. // CMetaKey class
  1365. //
  1366. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1367. //
  1368. // Helper macros
  1369. //
  1370. #define ASSURE_PROPER_INTERFACE()\
  1371. if (!HasInterface()) { ASSERT_MSG("No interface"); return MD_ERROR_NOT_INITIALIZED; }
  1372. #define ASSURE_OPEN_KEY()\
  1373. if (!m_hKey && !m_fAllowRootOperations) { ASSERT_MSG("No open key"); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); }
  1374. #define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\
  1375. ZeroMemory(&md, sizeof(md)); \
  1376. if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\
  1377. { ASSERT_MSG("Bad property ID"); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); }
  1378. //
  1379. // Static Initialization
  1380. //
  1381. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1382. #define MD_SERVER_PLATFORM (IIS_MD_SERVER_BASE+100 )
  1383. #define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 )
  1384. #define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 )
  1385. #define MD_SERVER_CAPABILITIES (IIS_MD_SERVER_BASE+103 )
  1386. #ifndef MD_APP_PERIODIC_RESTART_TIME
  1387. #define MD_APP_PERIODIC_RESTART_TIME 2111
  1388. #endif
  1389. #ifndef MD_APP_PERIODIC_RESTART_REQUESTS
  1390. #define MD_APP_PERIODIC_RESTART_REQUESTS 2112
  1391. #endif
  1392. #ifndef MD_APP_PERIODIC_RESTART_SCHEDULE
  1393. #define MD_APP_PERIODIC_RESTART_SCHEDULE 2113
  1394. #endif
  1395. #ifndef MD_ASP_DISKTEMPLATECACHEDIRECTORY
  1396. #define MD_ASP_DISKTEMPLATECACHEDIRECTORY 7036
  1397. #endif
  1398. #ifndef MD_ASP_MAXDISKTEMPLATECACHEFILES
  1399. #define MD_ASP_MAXDISKTEMPLATECACHEFILES 7040
  1400. #endif
  1401. //
  1402. // Metabase table
  1403. //
  1404. const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] =
  1405. {
  1406. ///////////////////////////////////////////////////////////////////////////
  1407. //
  1408. // !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (Will
  1409. // ASSERT if not not sorted)
  1410. //
  1411. { MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1412. { MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1413. { MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1414. { MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT },
  1415. { MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS },
  1416. { MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT },
  1417. { MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1418. { MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1419. { MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE },
  1420. { MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG },
  1421. { MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT },
  1422. { MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  1423. { MD_WIN32_ERROR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1424. { MD_SERVER_PLATFORM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1425. { MD_SERVER_VERSION_MAJOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1426. { MD_SERVER_VERSION_MINOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1427. { MD_SERVER_CAPABILITIES, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1428. { MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  1429. { MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1430. { MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1431. { MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1432. { MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1433. { MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1434. { MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1435. { MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1436. { MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1437. { MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1438. { MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1439. { MD_NET_LOGON_WKS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1440. { MD_USE_HOST_NAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1441. { MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1442. { MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1443. { MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1444. { MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1445. { MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1446. { MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1447. { MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1448. { MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1449. { MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1450. { MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1451. { MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1452. { MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1453. { MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1454. { MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1455. { MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1456. { MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1457. { MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1458. { MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1459. { MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1460. { MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME },
  1461. { MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT },
  1462. { MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED },
  1463. // new stuff
  1464. { MD_APP_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
  1465. { MD_APP_PERIODIC_RESTART_REQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
  1466. { MD_APP_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_WAM, MULTISZ_METADATA, 0 },
  1467. // end new stuff
  1468. { MD_CPU_LIMITS_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMITS_ENABLED },
  1469. { MD_CPU_LIMIT_LOGEVENT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_LOGEVENT },
  1470. { MD_CPU_LIMIT_PRIORITY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PRIORITY },
  1471. { MD_CPU_LIMIT_PROCSTOP, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PROCSTOP },
  1472. { MD_CPU_LIMIT_PAUSE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PAUSE },
  1473. { MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1474. { MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1475. { MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1476. { MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1477. { MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1478. { MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH },
  1479. { MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME },
  1480. { MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD },
  1481. { MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 },
  1482. { MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1483. { MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE },
  1484. { MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGFILE_DIRECTORY },
  1485. { MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD },
  1486. { MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE },
  1487. { MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES },
  1488. { MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME },
  1489. { MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME },
  1490. { MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD },
  1491. { MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER },
  1492. { MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK },
  1493. { MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER },
  1494. { MD_CPU_LOGGING_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LOGGING_MASK },
  1495. { MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE },
  1496. { MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE },
  1497. { MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE },
  1498. { MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT },
  1499. { MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS },
  1500. { MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY },
  1501. { MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS },
  1502. { MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS },
  1503. { MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1504. { MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1505. { MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1506. { MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1507. { MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1508. { MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1509. { MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1510. { MD_SSL_USE_DS_MAPPER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1511. { MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION },
  1512. { MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM },
  1513. { MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES },
  1514. { MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS },
  1515. { MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM },
  1516. { MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING },
  1517. { MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE },
  1518. { MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION },
  1519. { MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR },
  1520. { MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT },
  1521. { MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED },
  1522. { MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT },
  1523. { MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN },
  1524. { MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD },
  1525. { MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS },
  1526. { MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP },
  1527. { MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM },
  1528. { MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC },
  1529. { MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME },
  1530. { MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD },
  1531. { MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH },
  1532. { MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG },
  1533. { MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL },
  1534. { MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED },
  1535. { MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM },
  1536. { MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS },
  1537. { MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT },
  1538. { MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS },
  1539. { MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER },
  1540. { MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE },
  1541. { MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT },
  1542. { MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES },
  1543. { MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED },
  1544. { MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1545. { MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON },
  1546. { MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS },
  1547. { MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER },
  1548. { MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE },
  1549. { MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE },
  1550. { MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX },
  1551. { MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT },
  1552. { MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT },
  1553. { MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS },
  1554. { MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE },
  1555. { MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE },
  1556. { MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE },
  1557. { MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG },
  1558. { MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG },
  1559. { MD_ASP_DISKTEMPLATECACHEDIRECTORY, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, 0 },
  1560. { MD_ASP_MAXDISKTEMPLATECACHEFILES, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, 0 },
  1561. };
  1562. #define NUM_ENTRIES (sizeof(CMetaKey::s_rgMetaTable) / sizeof(CMetaKey::s_rgMetaTable[0]))
  1563. /* static */
  1564. int
  1565. CMetaKey::MapMDIDToTableIndex(
  1566. IN DWORD dwID
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. Map MD id value to table index. Return -1 if not found
  1571. Arguments:
  1572. DWORD dwID : MD id value
  1573. Return Value:
  1574. Index into the table that coresponds to the MD id value
  1575. --*/
  1576. {
  1577. #ifdef _DEBUG
  1578. {
  1579. //
  1580. // Do a quick verification that our metadata
  1581. // table is sorted correctly.
  1582. //
  1583. static BOOL fTableChecked = FALSE;
  1584. if (!fTableChecked)
  1585. {
  1586. for (int n = 1; n < NUM_ENTRIES; ++n)
  1587. {
  1588. if (s_rgMetaTable[n].dwMDIdentifier
  1589. <= s_rgMetaTable[n - 1].dwMDIdentifier)
  1590. {
  1591. // TRACE("MD ID Table is out of order: Item is %d %s\n", n, s_rgMetaTable[n].dwMDIdentifier);
  1592. ASSERT_MSG("MD ID Table out of order");
  1593. }
  1594. }
  1595. //
  1596. // But only once.
  1597. //
  1598. ++fTableChecked;
  1599. }
  1600. }
  1601. #endif // _DEBUG
  1602. //
  1603. // Look up the ID in the table using a binary search
  1604. //
  1605. int nRange = NUM_ENTRIES;
  1606. int nLow = 0;
  1607. int nHigh = nRange - 1;
  1608. int nMid;
  1609. int nHalf;
  1610. while (nLow <= nHigh)
  1611. {
  1612. if (nHalf = nRange / 2)
  1613. {
  1614. nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1));
  1615. if (s_rgMetaTable[nMid].dwMDIdentifier == dwID)
  1616. {
  1617. return nMid;
  1618. }
  1619. else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID)
  1620. {
  1621. nHigh = --nMid;
  1622. nRange = nRange & 1 ? nHalf : nHalf - 1;
  1623. }
  1624. else
  1625. {
  1626. nLow = ++nMid;
  1627. nRange = nHalf;
  1628. }
  1629. }
  1630. else if (nRange)
  1631. {
  1632. return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1;
  1633. }
  1634. else
  1635. {
  1636. break;
  1637. }
  1638. }
  1639. return -1;
  1640. }
  1641. /* static */
  1642. BOOL
  1643. CMetaKey::GetMDFieldDef(
  1644. IN DWORD dwID,
  1645. OUT DWORD & dwMDIdentifier,
  1646. OUT DWORD & dwMDAttributes,
  1647. OUT DWORD & dwMDUserType,
  1648. OUT DWORD & dwMDDataType
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. Get information about metabase property
  1653. Arguments:
  1654. DWORD dwID : Meta ID
  1655. DWORD & dwMDIdentifier : Meta parms
  1656. DWORD & dwMDAttributes : Meta parms
  1657. DWORD & dwMDUserType : Meta parms
  1658. DWORD & dwMDDataType : Meta parms
  1659. Return Value:
  1660. TRUE for success, FALSE for failure.
  1661. --*/
  1662. {
  1663. int nID = MapMDIDToTableIndex(dwID);
  1664. if (nID == -1)
  1665. {
  1666. //
  1667. // Unrecognized meta data ID
  1668. //
  1669. ASSERT_MSG("Unrecognized meta data id");
  1670. return FALSE;
  1671. }
  1672. dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier;
  1673. dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes;
  1674. dwMDUserType = s_rgMetaTable[nID].dwMDUserType;
  1675. dwMDDataType = s_rgMetaTable[nID].dwMDDataType;
  1676. return TRUE;
  1677. }
  1678. /* static */
  1679. BOOL
  1680. CMetaKey::IsPropertyInheritable(
  1681. IN DWORD dwID
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. Check to see if the given property is inheritable
  1686. Arguments:
  1687. DWORD dwID : Metabase ID
  1688. Return Value:
  1689. TRUE if the metabase ID is inheritable, FALSE otherwise.
  1690. --*/
  1691. {
  1692. int nID = MapMDIDToTableIndex(dwID);
  1693. if (nID == -1)
  1694. {
  1695. //
  1696. // Unrecognized meta data ID
  1697. //
  1698. ASSERT_MSG("Unrecognized meta data ID");
  1699. return FALSE;
  1700. }
  1701. return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0;
  1702. }
  1703. /* static */
  1704. BOOL
  1705. CMetaKey::GetPropertyDescription(
  1706. IN DWORD dwID,
  1707. OUT CString & strName
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. Get a description for the given property
  1712. Arguments:
  1713. DWORD dwID : Property ID
  1714. CString & strName : Returns friendly property name
  1715. Return Value:
  1716. TRUE for success, FALSE for failure
  1717. --*/
  1718. {
  1719. int nID = MapMDIDToTableIndex(dwID);
  1720. if (nID == -1)
  1721. {
  1722. //
  1723. // Unrecognized meta data ID
  1724. //
  1725. ASSERT_MSG("Unrecognized meta data ID");
  1726. return FALSE;
  1727. }
  1728. UINT uID = s_rgMetaTable[nID].uStringID;
  1729. BOOL fResult = TRUE;
  1730. if (uID > 0)
  1731. {
  1732. fResult = (strName.LoadString(_Module.GetResourceInstance(), uID) != 0);
  1733. }
  1734. else
  1735. {
  1736. //
  1737. // Don't have a friendly name -- fake it
  1738. //
  1739. CComBSTR bstrFmt;
  1740. VERIFY(bstrFmt.LoadString(_Module.GetResourceInstance(), IDS_INHERITANCE_NO_NAME));
  1741. strName.Format(bstrFmt, dwID);
  1742. }
  1743. return fResult;
  1744. }
  1745. CMetaKey::CMetaKey(
  1746. IN CComAuthInfo * pAuthInfo OPTIONAL
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. Constructor that creates the interface, but does not open the key.
  1751. This is the ONLY constructor that allows operations from
  1752. METDATA_MASTER_ROOT_HANDLE (read operations obviously)
  1753. Arguments:
  1754. CComAuthInfo * pAuthInfo : If NULL, opens interface on local machine
  1755. Return Value:
  1756. N/A
  1757. --*/
  1758. : CMetaInterface(pAuthInfo),
  1759. m_hKey(METADATA_MASTER_ROOT_HANDLE),
  1760. m_hBase(NULL),
  1761. m_hrKey(S_OK),
  1762. m_dwFlags(0L),
  1763. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1764. m_strMetaPath(),
  1765. m_fAllowRootOperations(TRUE),
  1766. m_fOwnKey(TRUE)
  1767. {
  1768. m_hrKey = CMetaInterface::QueryResult();
  1769. //
  1770. // Do not open key
  1771. //
  1772. }
  1773. CMetaKey::CMetaKey(
  1774. IN CMetaInterface * pInterface
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. Construct with pre-existing interface. Does not
  1779. open any keys
  1780. Arguments:
  1781. CMetaInterface * pInterface : Preexisting interface
  1782. Return Value:
  1783. N/A
  1784. --*/
  1785. : CMetaInterface(pInterface),
  1786. m_hKey(NULL),
  1787. m_hBase(NULL),
  1788. m_strMetaPath(),
  1789. m_dwFlags(0L),
  1790. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1791. m_fAllowRootOperations(TRUE),
  1792. m_fOwnKey(TRUE)
  1793. {
  1794. m_hrKey = CMetaInterface::QueryResult();
  1795. }
  1796. CMetaKey::CMetaKey(
  1797. IN CComAuthInfo * pAuthInfo, OPTIONAL
  1798. IN LPCTSTR lpszMDPath, OPTIONAL
  1799. IN DWORD dwFlags,
  1800. IN METADATA_HANDLE hkBase
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. Fully defined constructor that opens a key
  1805. Arguments:
  1806. CComAuthInfo * pAuthInfo : Auth info or NULL
  1807. LPCTSTR lpszMDPath : Path or NULL
  1808. DWORD dwFlags : Open permissions
  1809. METADATA_HANDLE hkBase : Base key
  1810. Return Value:
  1811. N/A
  1812. --*/
  1813. : CMetaInterface(pAuthInfo),
  1814. // : CMetaInterface((CComAuthInfo *)NULL),
  1815. m_hKey(NULL),
  1816. m_hBase(NULL),
  1817. m_dwFlags(0L),
  1818. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1819. m_fAllowRootOperations(FALSE),
  1820. m_strMetaPath(),
  1821. m_fOwnKey(TRUE)
  1822. {
  1823. m_hrKey = CMetaInterface::QueryResult();
  1824. if (SUCCEEDED(m_hrKey))
  1825. {
  1826. m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
  1827. }
  1828. }
  1829. CMetaKey::CMetaKey(
  1830. IN CMetaInterface * pInterface,
  1831. IN LPCTSTR lpszMDPath, OPTIONAL
  1832. IN DWORD dwFlags,
  1833. IN METADATA_HANDLE hkBase
  1834. )
  1835. /*++
  1836. Routine Description:
  1837. Fully defined constructor that opens a key
  1838. Arguments:
  1839. CMetaInterface * pInterface : Existing interface
  1840. DWORD dwFlags : Open permissions
  1841. METADATA_HANDLE hkBase : Base key
  1842. LPCTSTR lpszMDPath : Path or NULL
  1843. Return Value:
  1844. N/A
  1845. --*/
  1846. : CMetaInterface(pInterface),
  1847. m_hKey(NULL),
  1848. m_hBase(NULL),
  1849. m_strMetaPath(),
  1850. m_dwFlags(0L),
  1851. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1852. m_fAllowRootOperations(FALSE),
  1853. m_fOwnKey(TRUE)
  1854. {
  1855. m_hrKey = CMetaInterface::QueryResult();
  1856. if (SUCCEEDED(m_hrKey))
  1857. {
  1858. m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
  1859. }
  1860. }
  1861. CMetaKey::CMetaKey(
  1862. IN BOOL fOwnKey,
  1863. IN CMetaKey * pKey
  1864. )
  1865. /*++
  1866. Routine Description:
  1867. Copy constructor.
  1868. Arguments:
  1869. BOOL fOwnKey : TRUE to take ownership of the key
  1870. const CMetaKey * pKey : Existing key
  1871. Return Value:
  1872. N/A
  1873. --*/
  1874. : CMetaInterface(pKey),
  1875. m_hKey(pKey->m_hKey),
  1876. m_hBase(pKey->m_hBase),
  1877. m_dwFlags(pKey->m_dwFlags),
  1878. m_cbInitialBufferSize(pKey->m_cbInitialBufferSize),
  1879. m_fAllowRootOperations(pKey->m_fAllowRootOperations),
  1880. m_hrKey(pKey->m_hrKey),
  1881. m_strMetaPath(pKey->m_strMetaPath),
  1882. m_fOwnKey(fOwnKey)
  1883. {
  1884. //
  1885. // No provisions for anything else at the moment
  1886. //
  1887. ASSERT(!m_fOwnKey);
  1888. }
  1889. CMetaKey::~CMetaKey()
  1890. /*++
  1891. Routine Description:
  1892. Destructor -- Close the key.
  1893. Arguments:
  1894. N/A
  1895. Return Value:
  1896. N/A
  1897. --*/
  1898. {
  1899. if (IsOpen() && m_fOwnKey)
  1900. {
  1901. Close();
  1902. }
  1903. }
  1904. /* virtual */
  1905. BOOL
  1906. CMetaKey::Succeeded() const
  1907. /*++
  1908. Routine Description:
  1909. Determine if object was constructed successfully
  1910. Arguments:
  1911. None
  1912. Return Value:
  1913. TRUE for success, FALSE for failure
  1914. --*/
  1915. {
  1916. return SUCCEEDED(m_hrKey);
  1917. }
  1918. /* virtual */
  1919. HRESULT
  1920. CMetaKey::QueryResult() const
  1921. /*++
  1922. Routine Description:
  1923. Return the construction error for this object
  1924. Arguments:
  1925. None
  1926. Return Value:
  1927. HRESULT from construction errors
  1928. --*/
  1929. {
  1930. return m_hrKey;
  1931. }
  1932. HRESULT
  1933. CMetaKey::Open(
  1934. IN DWORD dwFlags,
  1935. IN LPCTSTR lpszMDPath, OPTIONAL
  1936. IN METADATA_HANDLE hkBase
  1937. )
  1938. /*++
  1939. Routine Description:
  1940. Attempt to open a metabase key
  1941. Arguments:
  1942. DWORD dwFlags : Permission flags
  1943. LPCTSTR lpszMDPath : Optional path
  1944. METADATA_HANDLE hkBase : Base metabase key
  1945. Return Value:
  1946. HRESULT
  1947. --*/
  1948. {
  1949. ASSURE_PROPER_INTERFACE();
  1950. if (m_hKey != NULL)
  1951. {
  1952. ASSERT_MSG("Attempting to open key that already has an open handle");
  1953. // TRACEEOLID("Closing that key");
  1954. Close();
  1955. }
  1956. //
  1957. // Base key is stored for reopen purposes only
  1958. //
  1959. m_hBase = hkBase;
  1960. m_strMetaPath = lpszMDPath;
  1961. m_dwFlags = dwFlags;
  1962. return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey);
  1963. }
  1964. HRESULT
  1965. CMetaKey::CreatePathFromFailedOpen()
  1966. /*++
  1967. Routine Description:
  1968. If the path doesn't exist, create it. This method should be
  1969. called after an Open call failed (because it will have initialized
  1970. m_strMetaPath.
  1971. Arguments:
  1972. None
  1973. Return Value:
  1974. HRESULT
  1975. --*/
  1976. {
  1977. CString strParentPath;
  1978. CString strObjectName;
  1979. CString strSavePath(m_strMetaPath);
  1980. CMetabasePath::SplitMetaPathAtInstance(
  1981. m_strMetaPath,
  1982. strParentPath,
  1983. strObjectName
  1984. );
  1985. CError err(Open(
  1986. METADATA_PERMISSION_WRITE,
  1987. strParentPath
  1988. ));
  1989. if (err.Succeeded())
  1990. {
  1991. //
  1992. // This really should never fail, because we're opening
  1993. // the path at the instance.
  1994. //
  1995. err = AddKey(strObjectName);
  1996. }
  1997. if (IsOpen())
  1998. {
  1999. Close();
  2000. }
  2001. //
  2002. // The previous open wiped out the path...
  2003. //
  2004. m_strMetaPath = strSavePath;
  2005. return err;
  2006. }
  2007. HRESULT
  2008. CMetaKey::Close()
  2009. /*++
  2010. Routine Description:
  2011. Close the currently open key.
  2012. Arguments:
  2013. N/A
  2014. Return Value:
  2015. N/A
  2016. --*/
  2017. {
  2018. ASSURE_PROPER_INTERFACE();
  2019. HRESULT hr = S_OK;
  2020. ASSERT(m_hKey != NULL);
  2021. ASSERT(m_fOwnKey);
  2022. if (m_hKey)
  2023. {
  2024. hr = CloseKey(m_hKey);
  2025. if (SUCCEEDED(hr))
  2026. {
  2027. m_hKey = NULL;
  2028. }
  2029. }
  2030. return hr;
  2031. }
  2032. HRESULT
  2033. CMetaKey::ConvertToParentPath(
  2034. IN BOOL fImmediate
  2035. )
  2036. /*++
  2037. Routine Description:
  2038. Change the path to the parent path.
  2039. Arguments:
  2040. BOOL fImmediate : If TRUE, the immediate parent's path will be used
  2041. if FALSE, the first parent that really exists
  2042. Return Value:
  2043. HRESULT
  2044. ERROR_INVALID_PARAMETER if there is no valid path
  2045. --*/
  2046. {
  2047. BOOL fIsOpen = IsOpen();
  2048. if (fIsOpen)
  2049. {
  2050. Close();
  2051. }
  2052. CError err;
  2053. FOREVER
  2054. {
  2055. if (!CMetabasePath::ConvertToParentPath(m_strMetaPath))
  2056. {
  2057. //
  2058. // There is no parent path
  2059. //
  2060. err = ERROR_INVALID_PARAMETER;
  2061. break;
  2062. }
  2063. err = ReOpen();
  2064. //
  2065. // Path not found is the only valid error
  2066. // other than success.
  2067. //
  2068. if (fImmediate
  2069. || err.Succeeded()
  2070. || err.Win32Error() != ERROR_PATH_NOT_FOUND)
  2071. {
  2072. break;
  2073. }
  2074. }
  2075. //
  2076. // Remember to reset the construction error
  2077. // which referred to the parent path.
  2078. //
  2079. m_hrKey = err;
  2080. return err;
  2081. }
  2082. /* protected */
  2083. HRESULT
  2084. CMetaKey::GetPropertyValue(
  2085. IN DWORD dwID,
  2086. OUT IN DWORD & dwSize, OPTIONAL
  2087. OUT IN void *& pvData, OPTIONAL
  2088. OUT IN DWORD * pdwDataType, OPTIONAL
  2089. IN BOOL * pfInheritanceOverride, OPTIONAL
  2090. IN LPCTSTR lpszMDPath, OPTIONAL
  2091. OUT DWORD * pdwAttributes OPTIONAL
  2092. )
  2093. /*++
  2094. Routine Description:
  2095. Get metadata on the currently open key.
  2096. Arguments:
  2097. DWORD dwID : Property ID number
  2098. DWORD & dwSize : Buffer size (could be 0)
  2099. void *& pvData : Buffer -- will allocate if NULL
  2100. DWORD * pdwDataType : NULL or on in contains valid data types,
  2101. : on out contains actual data type
  2102. BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off
  2103. LPCTSTR lpszMDPath : Optional path off the open key
  2104. DWORD * pdwAttributes : Optionally returns attributes
  2105. Return Value:
  2106. HRESULT
  2107. ERROR_INVALID_HANDLE : If the handle is not open
  2108. ERROR_INVALID_PARAMETER : If the property id is not found,
  2109. or the data type doesn't match requested type
  2110. ERROR_OUTOFMEMORY : Out of memory
  2111. --*/
  2112. {
  2113. ASSURE_PROPER_INTERFACE();
  2114. ASSURE_OPEN_KEY();
  2115. METADATA_RECORD mdRecord;
  2116. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2117. //
  2118. // If unable to find this property ID in our table, or
  2119. // if we specified a desired type, and this type doesn't
  2120. // match it, give up.
  2121. //
  2122. if (pdwDataType && *pdwDataType != ALL_METADATA
  2123. && *pdwDataType != mdRecord.dwMDDataType)
  2124. {
  2125. ASSERT_MSG("Invalid parameter");
  2126. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2127. }
  2128. //
  2129. // Check to see if inheritance behaviour is overridden
  2130. //
  2131. if (pfInheritanceOverride)
  2132. {
  2133. if (*pfInheritanceOverride)
  2134. {
  2135. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  2136. }
  2137. else
  2138. {
  2139. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  2140. }
  2141. }
  2142. //
  2143. // This causes a bad parameter error on input otherwise
  2144. //
  2145. mdRecord.dwMDAttributes &= ~METADATA_REFERENCE;
  2146. //
  2147. // If we're looking for inheritable properties, the path
  2148. // doesn't have to be completely specified.
  2149. //
  2150. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  2151. {
  2152. mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED);
  2153. }
  2154. ASSERT(dwSize > 0 || pvData == NULL);
  2155. mdRecord.dwMDDataLen = dwSize;
  2156. mdRecord.pbMDData = (LPBYTE)pvData;
  2157. //
  2158. // If no buffer provided, allocate one.
  2159. //
  2160. HRESULT hr = S_OK;
  2161. BOOL fBufferTooSmall = FALSE;
  2162. BOOL fAllocatedMemory = FALSE;
  2163. DWORD dwInitSize = m_cbInitialBufferSize;
  2164. do
  2165. {
  2166. if(mdRecord.pbMDData == NULL)
  2167. {
  2168. mdRecord.dwMDDataLen = dwInitSize;
  2169. mdRecord.pbMDData = new BYTE[dwInitSize];
  2170. if(mdRecord.pbMDData == NULL && dwInitSize > 0)
  2171. {
  2172. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2173. break;
  2174. }
  2175. ++fAllocatedMemory;
  2176. }
  2177. //
  2178. // Get the data
  2179. //
  2180. DWORD dwRequiredDataLen = 0;
  2181. hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen);
  2182. //
  2183. // Re-fetch the buffer if it's too small.
  2184. //
  2185. fBufferTooSmall =
  2186. (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory;
  2187. if(fBufferTooSmall)
  2188. {
  2189. //
  2190. // Delete the old buffer, and set up for a re-fetch.
  2191. //
  2192. delete [] mdRecord.pbMDData;
  2193. mdRecord.pbMDData = NULL;
  2194. dwInitSize = dwRequiredDataLen;
  2195. }
  2196. }
  2197. while(fBufferTooSmall);
  2198. //
  2199. // Failed
  2200. //
  2201. if (FAILED(hr) && fAllocatedMemory)
  2202. {
  2203. delete [] mdRecord.pbMDData;
  2204. mdRecord.pbMDData = NULL;
  2205. }
  2206. dwSize = mdRecord.dwMDDataLen;
  2207. pvData = mdRecord.pbMDData;
  2208. if (pdwDataType != NULL)
  2209. {
  2210. //
  2211. // Return actual data type
  2212. //
  2213. *pdwDataType = mdRecord.dwMDDataType;
  2214. }
  2215. if (pdwAttributes != NULL)
  2216. {
  2217. //
  2218. // Return data attributes
  2219. //
  2220. *pdwAttributes = mdRecord.dwMDAttributes;
  2221. }
  2222. return hr;
  2223. }
  2224. /* protected */
  2225. HRESULT
  2226. CMetaKey::GetDataPaths(
  2227. OUT CStringListEx & strlDataPaths,
  2228. IN DWORD dwMDIdentifier,
  2229. IN DWORD dwMDDataType,
  2230. IN LPCTSTR lpszMDPath OPTIONAL
  2231. )
  2232. /*++
  2233. Routine Description:
  2234. Get data paths
  2235. Arguments:
  2236. Return Value:
  2237. HRESULT
  2238. --*/
  2239. {
  2240. ASSURE_PROPER_INTERFACE();
  2241. ASSURE_OPEN_KEY();
  2242. //
  2243. // Start with a small buffer
  2244. //
  2245. DWORD dwMDBufferSize = 1024;
  2246. LPTSTR lpszBuffer = NULL;
  2247. CError err;
  2248. do
  2249. {
  2250. delete [] lpszBuffer;
  2251. lpszBuffer = new TCHAR[dwMDBufferSize];
  2252. if (lpszBuffer == NULL)
  2253. {
  2254. err = ERROR_NOT_ENOUGH_MEMORY;
  2255. break;
  2256. }
  2257. err = CMetaInterface::GetDataPaths(
  2258. m_hKey,
  2259. lpszMDPath,
  2260. dwMDIdentifier,
  2261. dwMDDataType,
  2262. dwMDBufferSize,
  2263. lpszBuffer,
  2264. &dwMDBufferSize
  2265. );
  2266. }
  2267. while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER);
  2268. if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
  2269. {
  2270. //
  2271. // That's ok... this is some sort of physical directory
  2272. // that doesn't currently exist in the metabase, and
  2273. // which therefore doesn't have any descendants anyway.
  2274. //
  2275. ZeroMemory(lpszBuffer, dwMDBufferSize);
  2276. err.Reset();
  2277. }
  2278. if (err.Succeeded())
  2279. {
  2280. strlDataPaths.ConvertFromDoubleNullList(lpszBuffer);
  2281. delete [] lpszBuffer;
  2282. }
  2283. return err;
  2284. }
  2285. HRESULT
  2286. CMetaKey::CheckDescendants(
  2287. IN DWORD dwID,
  2288. IN CComAuthInfo * pAuthInfo, OPTIONAL
  2289. IN LPCTSTR lpszMDPath OPTIONAL
  2290. )
  2291. /*++
  2292. Routine Description:
  2293. Check for descendant overrides; If there are any, bring up a dialog
  2294. that displays them, and give the user the opportunity the remove
  2295. the overrides.
  2296. Arguments:
  2297. DWORD dwID : Property ID
  2298. CComAuthInfo * pAuthInfo : Server or NULL
  2299. LPCTSTR lpszMDPath : Metabase path or NULL
  2300. Return Value:
  2301. HRESULT
  2302. --*/
  2303. {
  2304. ASSURE_PROPER_INTERFACE();
  2305. HRESULT hr = S_OK;
  2306. METADATA_RECORD mdRecord;
  2307. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2308. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  2309. {
  2310. CStringListEx strlDataPaths;
  2311. hr = GetDataPaths(
  2312. strlDataPaths,
  2313. mdRecord.dwMDIdentifier,
  2314. mdRecord.dwMDDataType,
  2315. lpszMDPath
  2316. );
  2317. if (SUCCEEDED(hr) && !strlDataPaths.empty())
  2318. {
  2319. //
  2320. // Bring up the inheritance override dialog
  2321. //
  2322. CInheritanceDlg dlg(
  2323. dwID,
  2324. FROM_WRITE_PROPERTY,
  2325. pAuthInfo,
  2326. lpszMDPath,
  2327. strlDataPaths
  2328. );
  2329. if (!dlg.IsEmpty())
  2330. {
  2331. dlg.DoModal();
  2332. }
  2333. }
  2334. }
  2335. return hr;
  2336. }
  2337. /* protected */
  2338. HRESULT
  2339. CMetaKey::SetPropertyValue(
  2340. IN DWORD dwID,
  2341. IN DWORD dwSize,
  2342. IN void * pvData,
  2343. IN BOOL * pfInheritanceOverride, OPTIONAL
  2344. IN LPCTSTR lpszMDPath OPTIONAL
  2345. )
  2346. /*++
  2347. Routine Description:
  2348. Set metadata on the open key. The key must have been opened with
  2349. write permission.
  2350. Arguments:
  2351. DWORD dwID : Property ID
  2352. DWORD dwSize : Size of data
  2353. void * pvData : Data buffer
  2354. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2355. LPCTSTR lpszMDPath : Optional path off the open key
  2356. Return Value:
  2357. HRESULT
  2358. ERROR_INVALID_HANDLE : If the handle is not open
  2359. ERROR_INVALID_PARAMETER : If the property id is not found,
  2360. or the buffer is NULL or of size 0
  2361. --*/
  2362. {
  2363. ASSURE_PROPER_INTERFACE();
  2364. ASSURE_OPEN_KEY();
  2365. if (pvData == NULL && dwSize != 0)
  2366. {
  2367. ASSERT_MSG("No Data");
  2368. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2369. }
  2370. METADATA_RECORD mdRecord;
  2371. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2372. if (pfInheritanceOverride)
  2373. {
  2374. if (*pfInheritanceOverride)
  2375. {
  2376. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  2377. }
  2378. else
  2379. {
  2380. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  2381. }
  2382. }
  2383. mdRecord.dwMDDataLen = dwSize;
  2384. mdRecord.pbMDData = (LPBYTE)pvData;
  2385. return SetData(m_hKey, lpszMDPath, &mdRecord);
  2386. }
  2387. /* protected */
  2388. HRESULT
  2389. CMetaKey::GetAllData(
  2390. IN DWORD dwMDAttributes,
  2391. IN DWORD dwMDUserType,
  2392. IN DWORD dwMDDataType,
  2393. OUT DWORD * pdwMDNumEntries,
  2394. OUT DWORD * pdwMDDataLen,
  2395. OUT PBYTE * ppbMDData,
  2396. IN LPCTSTR lpszMDPath OPTIONAL
  2397. )
  2398. /*++
  2399. Routine Description:
  2400. Get all data off the open key. Buffer is created automatically.
  2401. Arguments:
  2402. DWORD dwMDAttributes : Attributes
  2403. DWORD dwMDUserType : User type to fetch
  2404. DWORD dwMDDataType : Data type to fetch
  2405. DWORD * pdwMDNumEntries : Returns number of entries read
  2406. DWORD * pdwMDDataLen : Returns size of data buffer
  2407. PBYTE * ppbMDData : Returns data buffer
  2408. LPCTSTR lpszMDPath : Optional data path
  2409. Return Value:
  2410. HRESULT
  2411. --*/
  2412. {
  2413. ASSURE_PROPER_INTERFACE();
  2414. ASSURE_OPEN_KEY();
  2415. //
  2416. // Check for valid parameters
  2417. //
  2418. if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries)
  2419. {
  2420. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2421. }
  2422. HRESULT hr = S_OK;
  2423. BOOL fBufferTooSmall = FALSE;
  2424. DWORD dwMDDataSetNumber;
  2425. DWORD dwRequiredBufferSize;
  2426. DWORD dwInitSize = m_cbInitialBufferSize;
  2427. *ppbMDData = NULL;
  2428. do
  2429. {
  2430. *pdwMDDataLen = dwInitSize;
  2431. *ppbMDData = new BYTE[dwInitSize];
  2432. if (ppbMDData == NULL && dwInitSize > 0)
  2433. {
  2434. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2435. break;
  2436. }
  2437. hr = CMetaInterface::GetAllData(
  2438. m_hKey,
  2439. lpszMDPath,
  2440. dwMDAttributes,
  2441. dwMDUserType,
  2442. dwMDDataType,
  2443. pdwMDNumEntries,
  2444. &dwMDDataSetNumber,
  2445. *pdwMDDataLen,
  2446. *ppbMDData,
  2447. &dwRequiredBufferSize
  2448. );
  2449. //
  2450. // Re-fetch the buffer if it's too small.
  2451. //
  2452. fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER);
  2453. if(fBufferTooSmall)
  2454. {
  2455. //
  2456. // Delete the old buffer, and set up for a re-fetch.
  2457. //
  2458. delete [] *ppbMDData;
  2459. dwInitSize = dwRequiredBufferSize;
  2460. }
  2461. }
  2462. while (fBufferTooSmall);
  2463. if (FAILED(hr))
  2464. {
  2465. //
  2466. // No good, be sure we don't leak anything
  2467. //
  2468. delete [] *ppbMDData;
  2469. dwInitSize = 0L;
  2470. }
  2471. return hr;
  2472. }
  2473. HRESULT
  2474. CMetaKey::QueryValue(
  2475. IN DWORD dwID,
  2476. IN OUT DWORD & dwValue,
  2477. IN BOOL * pfInheritanceOverride, OPTIONAL
  2478. IN LPCTSTR lpszMDPath, OPTIONAL
  2479. OUT DWORD * pdwAttributes OPTIONAL
  2480. )
  2481. /*++
  2482. Routine Description:
  2483. Fetch data as a DWORD
  2484. Arguments:
  2485. DWORD dwID : Property ID
  2486. DWORD & dwValue : Returns the value read in
  2487. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2488. LPCTSTR lpszMDPath : Optional path off the open key
  2489. DWORD * pdwAttributes : Optionally returns attributes
  2490. Return Value:
  2491. HRESULT
  2492. --*/
  2493. {
  2494. DWORD dwSize = sizeof(dwValue);
  2495. DWORD dwDataType = DWORD_METADATA;
  2496. void * pvData = &dwValue;
  2497. return GetPropertyValue(
  2498. dwID,
  2499. dwSize,
  2500. pvData,
  2501. &dwDataType,
  2502. pfInheritanceOverride,
  2503. lpszMDPath,
  2504. pdwAttributes
  2505. );
  2506. }
  2507. HRESULT
  2508. CMetaKey::QueryValue(
  2509. IN DWORD dwID,
  2510. IN OUT CString & strValue,
  2511. IN BOOL * pfInheritanceOverride, OPTIONAL
  2512. IN LPCTSTR lpszMDPath, OPTIONAL
  2513. OUT DWORD * pdwAttributes OPTIONAL
  2514. )
  2515. /*++
  2516. Routine Description:
  2517. Fetch data as a string
  2518. Arguments:
  2519. DWORD dwID : Property ID
  2520. DWORD & strValue : Returns the value read in
  2521. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2522. LPCTSTR lpszMDPath : Optional path off the open key
  2523. DWORD * pdwAttributes : Optionally returns attributes
  2524. Return Value:
  2525. HRESULT
  2526. --*/
  2527. {
  2528. //
  2529. // Get GetData allocate the buffer for us
  2530. //
  2531. DWORD dwSize = 0;
  2532. DWORD dwDataType = ALL_METADATA;
  2533. LPTSTR lpData = NULL;
  2534. HRESULT hr = GetPropertyValue(
  2535. dwID,
  2536. dwSize,
  2537. (void *&)lpData,
  2538. &dwDataType,
  2539. pfInheritanceOverride,
  2540. lpszMDPath,
  2541. pdwAttributes
  2542. );
  2543. if (SUCCEEDED(hr))
  2544. {
  2545. //
  2546. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2547. // (see registry functions), and data type conversions for DWORD
  2548. // or MULTISZ_METADATA or BINARY_METADATA
  2549. //
  2550. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2551. {
  2552. try
  2553. {
  2554. strValue = lpData;
  2555. }
  2556. catch(std::bad_alloc)
  2557. {
  2558. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  2559. }
  2560. }
  2561. else
  2562. {
  2563. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2564. }
  2565. }
  2566. if (lpData)
  2567. {
  2568. delete [] lpData;
  2569. }
  2570. return hr;
  2571. }
  2572. HRESULT
  2573. CMetaKey::QueryValue(
  2574. IN DWORD dwID,
  2575. IN OUT CComBSTR & strValue,
  2576. IN BOOL * pfInheritanceOverride, OPTIONAL
  2577. IN LPCTSTR lpszMDPath, OPTIONAL
  2578. OUT DWORD * pdwAttributes OPTIONAL
  2579. )
  2580. /*++
  2581. Routine Description:
  2582. Fetch data as a string
  2583. Arguments:
  2584. DWORD dwID : Property ID
  2585. DWORD & CComBSTR : Returns the value read in
  2586. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2587. LPCTSTR lpszMDPath : Optional path off the open key
  2588. DWORD * pdwAttributes : Optionally returns attributes
  2589. Return Value:
  2590. HRESULT
  2591. --*/
  2592. {
  2593. //
  2594. // Get GetData allocate the buffer for us
  2595. //
  2596. DWORD dwSize = 0;
  2597. DWORD dwDataType = ALL_METADATA;
  2598. LPTSTR lpData = NULL;
  2599. HRESULT hr = GetPropertyValue(
  2600. dwID,
  2601. dwSize,
  2602. (void *&)lpData,
  2603. &dwDataType,
  2604. pfInheritanceOverride,
  2605. lpszMDPath,
  2606. pdwAttributes
  2607. );
  2608. if (SUCCEEDED(hr))
  2609. {
  2610. //
  2611. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2612. // (see registry functions), and data type conversions for DWORD
  2613. // or MULTISZ_METADATA or BINARY_METADATA
  2614. //
  2615. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2616. {
  2617. strValue = lpData;
  2618. }
  2619. else
  2620. {
  2621. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2622. }
  2623. }
  2624. if (lpData)
  2625. {
  2626. delete [] lpData;
  2627. }
  2628. return hr;
  2629. }
  2630. HRESULT
  2631. CMetaKey::QueryValue(
  2632. IN DWORD dwID,
  2633. IN OUT CStringListEx & strlValue,
  2634. IN BOOL * pfInheritanceOverride, OPTIONAL
  2635. IN LPCTSTR lpszMDPath, OPTIONAL
  2636. OUT DWORD * pdwAttributes OPTIONAL
  2637. )
  2638. /*++
  2639. Routine Description:
  2640. Fetch data as a stringlist
  2641. Arguments:
  2642. DWORD dwID : Property ID
  2643. DWORD & strlValue : Returns the value read in
  2644. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2645. LPCTSTR lpszMDPath : Optional path off the open key
  2646. DWORD * pdwAttributes : Optionally returns attributes
  2647. Return Value:
  2648. HRESULT
  2649. --*/
  2650. {
  2651. //
  2652. // Get GetData allocate the buffer for us
  2653. //
  2654. DWORD dwSize = 0;
  2655. DWORD dwDataType = MULTISZ_METADATA;
  2656. LPTSTR lpData = NULL;
  2657. HRESULT hr = GetPropertyValue(
  2658. dwID,
  2659. dwSize,
  2660. (void *&)lpData,
  2661. &dwDataType,
  2662. pfInheritanceOverride,
  2663. lpszMDPath,
  2664. pdwAttributes
  2665. );
  2666. if (SUCCEEDED(hr))
  2667. {
  2668. //
  2669. // Notes: Consider accepting a single STRING
  2670. //
  2671. ASSERT(dwDataType == MULTISZ_METADATA);
  2672. DWORD err = strlValue.ConvertFromDoubleNullList(lpData, dwSize / sizeof(TCHAR));
  2673. hr = HRESULT_FROM_WIN32(err);
  2674. }
  2675. if (lpData)
  2676. {
  2677. delete [] lpData;
  2678. }
  2679. return hr;
  2680. }
  2681. HRESULT
  2682. CMetaKey::QueryValue(
  2683. IN DWORD dwID,
  2684. IN OUT CBlob & blValue,
  2685. IN BOOL * pfInheritanceOverride, OPTIONAL
  2686. IN LPCTSTR lpszMDPath, OPTIONAL
  2687. OUT DWORD * pdwAttributes OPTIONAL
  2688. )
  2689. /*++
  2690. Routine Description:
  2691. Fetch data as a binary blob
  2692. Arguments:
  2693. DWORD dwID : Property ID
  2694. DWORD CBlob & blValue : Returns the binary blob
  2695. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2696. LPCTSTR lpszMDPath : Optional path off the open key
  2697. DWORD * pdwAttributes : Optionally returns attributes
  2698. Return Value:
  2699. HRESULT
  2700. --*/
  2701. {
  2702. //
  2703. // Get GetData allocate the buffer for us
  2704. //
  2705. DWORD dwSize = 0;
  2706. DWORD dwDataType = BINARY_METADATA;
  2707. LPBYTE pbData = NULL;
  2708. HRESULT hr = GetPropertyValue(
  2709. dwID,
  2710. dwSize,
  2711. (void *&)pbData,
  2712. &dwDataType,
  2713. pfInheritanceOverride,
  2714. lpszMDPath,
  2715. pdwAttributes
  2716. );
  2717. if (SUCCEEDED(hr))
  2718. {
  2719. //
  2720. // Blob takes ownership of the data, so don't free it...
  2721. //
  2722. ASSERT_READ_PTR2(pbData, dwSize);
  2723. blValue.SetValue(dwSize, pbData, FALSE);
  2724. }
  2725. return hr;
  2726. }
  2727. HRESULT
  2728. CMetaKey::SetValue(
  2729. IN DWORD dwID,
  2730. IN CStringListEx & strlValue,
  2731. IN BOOL * pfInheritanceOverride, OPTIONAL
  2732. IN LPCTSTR lpszMDPath OPTIONAL
  2733. )
  2734. /*++
  2735. Routine Description:
  2736. Store data as string
  2737. Arguments:
  2738. DWORD dwID : Property ID
  2739. CStringListEx & strlValue : Value to be written
  2740. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2741. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2742. Return Value:
  2743. HRESULT
  2744. --*/
  2745. {
  2746. DWORD cCharacters;
  2747. LPTSTR lpstr = NULL;
  2748. //
  2749. // Flatten value
  2750. //
  2751. strlValue.ConvertToDoubleNullList(cCharacters, lpstr);
  2752. HRESULT hr = SetPropertyValue(
  2753. dwID,
  2754. cCharacters * sizeof(TCHAR),
  2755. (void *)lpstr,
  2756. pfInheritanceOverride,
  2757. lpszMDPath
  2758. );
  2759. delete [] lpstr;
  2760. return hr;
  2761. }
  2762. HRESULT
  2763. CMetaKey::SetValue(
  2764. IN DWORD dwID,
  2765. IN CBlob & blValue,
  2766. IN BOOL * pfInheritanceOverride, OPTIONAL
  2767. IN LPCTSTR lpszMDPath OPTIONAL
  2768. )
  2769. /*++
  2770. Routine Description:
  2771. Store data as binary
  2772. Arguments:
  2773. DWORD dwID : Property ID
  2774. CBlob & blValue : Value to be written
  2775. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2776. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2777. Return Value:
  2778. HRESULT
  2779. --*/
  2780. {
  2781. return SetPropertyValue(
  2782. dwID,
  2783. blValue.GetSize(),
  2784. (void *)blValue.GetData(),
  2785. pfInheritanceOverride,
  2786. lpszMDPath
  2787. );
  2788. }
  2789. HRESULT
  2790. CMetaKey::DeleteValue(
  2791. DWORD dwID,
  2792. LPCTSTR lpszMDPath OPTIONAL
  2793. )
  2794. /*++
  2795. Routine Description:
  2796. Delete data
  2797. Arguments:
  2798. DWORD dwID : Property ID of property to be deleted
  2799. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2800. Return Value:
  2801. HRESULT
  2802. --*/
  2803. {
  2804. ASSURE_PROPER_INTERFACE();
  2805. ASSURE_OPEN_KEY();
  2806. METADATA_RECORD mdRecord;
  2807. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2808. return DeleteData(
  2809. m_hKey,
  2810. lpszMDPath,
  2811. mdRecord.dwMDIdentifier,
  2812. mdRecord.dwMDDataType
  2813. );
  2814. }
  2815. HRESULT
  2816. CMetaKey::DoesPathExist(
  2817. IN LPCTSTR lpszMDPath
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. Determine if the path exists
  2822. Arguments:
  2823. LPCTSTR lpszMDPath : Relative path off the open key
  2824. Return Value:
  2825. HRESULT, or S_OK if the path exists.
  2826. --*/
  2827. {
  2828. ASSURE_PROPER_INTERFACE();
  2829. ASSURE_OPEN_KEY();
  2830. FILETIME ft;
  2831. return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE);
  2832. }
  2833. HRESULT
  2834. CMetaInterface::Regenerate()
  2835. /*++
  2836. Routine Description:
  2837. Attempt to recreate the interface pointer. This assumes that the interface
  2838. had been successfully created before, but has become invalid at some
  2839. point afterwards.
  2840. Arguments:
  2841. None
  2842. Return Value:
  2843. HRESULT
  2844. --*/
  2845. {
  2846. ASSERT_PTR(m_pInterface); // Must have been initialised
  2847. SAFE_RELEASE(m_pInterface);
  2848. m_hrInterface = Create();
  2849. return m_hrInterface;
  2850. }
  2851. //
  2852. // CWamInterface class
  2853. //
  2854. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  2855. CWamInterface::CWamInterface(
  2856. IN CComAuthInfo * pAuthInfo OPTIONAL
  2857. )
  2858. /*++
  2859. Routine Description:
  2860. Construct and initialize the interface.
  2861. Arguments:
  2862. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  2863. Return Value:
  2864. N/A
  2865. --*/
  2866. : CIISInterface(pAuthInfo),
  2867. m_pInterface(NULL),
  2868. m_fSupportsPooledProc(FALSE)
  2869. {
  2870. //
  2871. // Initialize the interface
  2872. //
  2873. m_hrInterface = Create();
  2874. }
  2875. CWamInterface::CWamInterface(
  2876. IN CWamInterface * pInterface
  2877. )
  2878. /*++
  2879. Routine Description:
  2880. Construct from existing interface (copy constructor)
  2881. Arguments:
  2882. CWamInterface * pInterface : Existing interface
  2883. Return Value:
  2884. N/A
  2885. --*/
  2886. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  2887. m_pInterface(pInterface->m_pInterface),
  2888. m_fSupportsPooledProc(FALSE)
  2889. {
  2890. ASSERT_PTR(m_pInterface);
  2891. m_pInterface->AddRef();
  2892. }
  2893. CWamInterface::~CWamInterface()
  2894. /*++
  2895. Routine Description:
  2896. Destructor -- releases the interface.
  2897. Arguments:
  2898. N/A
  2899. Return Value:
  2900. N/A
  2901. --*/
  2902. {
  2903. SAFE_RELEASE(m_pInterface);
  2904. }
  2905. /* protected */
  2906. HRESULT
  2907. CWamInterface::Create()
  2908. /*++
  2909. Routine Description:
  2910. Create the interface with DCOM
  2911. Arguments:
  2912. None
  2913. Return Value:
  2914. HRESULT
  2915. Notes:
  2916. First, it will attempt to create the new interface, if it
  2917. fails, it will attempt to create the downlevel interface
  2918. --*/
  2919. {
  2920. CLSID rgCLSID[2];
  2921. IID rgIID[2];
  2922. rgCLSID[1] = rgCLSID[0] = CLSID_WamAdmin;
  2923. rgIID[0] = IID_IWamAdmin2;
  2924. rgIID[1] = IID_IWamAdmin;
  2925. ASSERT(ARRAY_SIZE(rgCLSID) == ARRAY_SIZE(rgIID));
  2926. int cInterfaces = ARRAY_SIZE(rgCLSID);
  2927. int iInterface;
  2928. HRESULT hr = CIISInterface::Create(
  2929. cInterfaces,
  2930. rgIID,
  2931. rgCLSID,
  2932. &iInterface,
  2933. (IUnknown **)&m_pInterface
  2934. );
  2935. if (SUCCEEDED(hr))
  2936. {
  2937. //
  2938. // Only supported on IWamAdmin2
  2939. //
  2940. m_fSupportsPooledProc = (rgIID[iInterface] == IID_IWamAdmin2);
  2941. }
  2942. return hr;
  2943. }
  2944. HRESULT
  2945. CWamInterface::AppCreate(
  2946. IN LPCTSTR szMDPath,
  2947. IN DWORD dwAppProtection
  2948. )
  2949. /*++
  2950. Routine Description:
  2951. Create application
  2952. Arguments:
  2953. LPCTSTR szMDPath : Metabase path
  2954. DWORD dwAppProtection : APP_INPROC to create in-proc app
  2955. APP_OUTOFPROC to create out-of-proc app
  2956. APP_POOLEDPROC to create a pooled-proc app
  2957. Return Value:
  2958. HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested)
  2959. --*/
  2960. {
  2961. if (m_fSupportsPooledProc)
  2962. {
  2963. //
  2964. // Interface pointer is really IWamAdmin2, so call the new method
  2965. //
  2966. return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection);
  2967. }
  2968. //
  2969. // Call the downlevel API
  2970. //
  2971. if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC)
  2972. {
  2973. BOOL fInProc = (dwAppProtection == APP_INPROC);
  2974. ASSERT_PTR(m_pInterface);
  2975. return m_pInterface->AppCreate(szMDPath, fInProc);
  2976. }
  2977. return CError(ERROR_INVALID_PARAMETER);
  2978. }
  2979. //
  2980. // CMetaback Class
  2981. //
  2982. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  2983. const LPCTSTR CMetaBack::s_szMasterAppRoot =\
  2984. SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB;
  2985. CMetaBack::CMetaBack(
  2986. IN CComAuthInfo * pAuthInfo OPTIONAL
  2987. )
  2988. /*++
  2989. Routine Description:
  2990. Constructor for metabase backup/restore operations class. This object
  2991. is both a WAM interface and a METABASE interface.
  2992. Arguments:
  2993. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  2994. Return Value:
  2995. N/A
  2996. --*/
  2997. : m_dwIndex(0),
  2998. CMetaInterface(pAuthInfo),
  2999. CWamInterface(pAuthInfo)
  3000. {
  3001. }
  3002. /* virtual */
  3003. BOOL
  3004. CMetaBack::Succeeded() const
  3005. /*++
  3006. Routine Description:
  3007. Determine if object was constructed successfully.
  3008. Arguments:
  3009. None
  3010. Return Value:
  3011. TRUE for success, FALSE for failure
  3012. --*/
  3013. {
  3014. return CMetaInterface::Succeeded() && CWamInterface::Succeeded();
  3015. }
  3016. /* virtual */
  3017. HRESULT
  3018. CMetaBack::QueryResult() const
  3019. /*++
  3020. Routine Description:
  3021. Return the construction error for this object
  3022. Arguments:
  3023. None
  3024. Return Value:
  3025. HRESULT from construction errors
  3026. --*/
  3027. {
  3028. //
  3029. // Both interfaces must have constructed successfully
  3030. //
  3031. HRESULT hr = CMetaInterface::QueryResult();
  3032. if (SUCCEEDED(hr))
  3033. {
  3034. hr = CWamInterface::QueryResult();
  3035. }
  3036. return hr;
  3037. }
  3038. HRESULT
  3039. CMetaBack::Restore(
  3040. IN LPCTSTR lpszLocation,
  3041. IN DWORD dwVersion
  3042. )
  3043. /*++
  3044. Routine Description:
  3045. Restore metabase
  3046. Arguments:
  3047. DWORD dwVersion : Backup version
  3048. LPCTSTR lpszLocation : Backup location
  3049. Return Value:
  3050. HRESULT
  3051. --*/
  3052. {
  3053. //
  3054. // Backup and restore the application information from a restore
  3055. //
  3056. CString strPath(s_szMasterAppRoot);
  3057. HRESULT hr = AppDeleteRecoverable(strPath, TRUE);
  3058. if (SUCCEEDED(hr))
  3059. {
  3060. hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0);
  3061. if (SUCCEEDED(hr))
  3062. {
  3063. hr = AppRecover(strPath, TRUE);
  3064. }
  3065. }
  3066. return hr;
  3067. }
  3068. //
  3069. // CIISSvcControl class
  3070. //
  3071. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3072. CIISSvcControl::CIISSvcControl(
  3073. IN CComAuthInfo * pAuthInfo OPTIONAL
  3074. )
  3075. /*++
  3076. Routine Description:
  3077. Construct and initialize the interface.
  3078. Arguments:
  3079. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3080. Return Value:
  3081. N/A
  3082. --*/
  3083. : CIISInterface(pAuthInfo),
  3084. m_pInterface(NULL)
  3085. {
  3086. //
  3087. // Initialize the interface
  3088. //
  3089. m_hrInterface = Create();
  3090. }
  3091. CIISSvcControl::CIISSvcControl(
  3092. IN CIISSvcControl * pInterface
  3093. )
  3094. /*++
  3095. Routine Description:
  3096. Construct from existing interface (copy constructor)
  3097. Arguments:
  3098. CIISSvcControl * pInterface : Existing interface
  3099. Return Value:
  3100. N/A
  3101. --*/
  3102. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  3103. m_pInterface(pInterface->m_pInterface)
  3104. {
  3105. ASSERT_PTR(m_pInterface);
  3106. m_pInterface->AddRef();
  3107. }
  3108. CIISSvcControl::~CIISSvcControl()
  3109. /*++
  3110. Routine Description:
  3111. Destructor -- releases the interface.
  3112. Arguments:
  3113. N/A
  3114. Return Value:
  3115. N/A
  3116. --*/
  3117. {
  3118. SAFE_RELEASE(m_pInterface);
  3119. }
  3120. #ifdef KEVLAR
  3121. //
  3122. // CWebCluster class
  3123. //
  3124. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3125. CWebCluster::CWebCluster(
  3126. IN CComAuthInfo * pAuthInfo OPTIONAL
  3127. )
  3128. /*++
  3129. Routine Description:
  3130. Construct and initialize the interface.
  3131. Arguments:
  3132. CComAuthInfo * pAuthInfo : Authentication information.
  3133. NULL indicates the local computer
  3134. Return Value:
  3135. N/A
  3136. --*/
  3137. : CIISInterface(pAuthInfo),
  3138. m_pInterface(NULL)
  3139. {
  3140. //
  3141. // Initialize the interface
  3142. //
  3143. m_hrInterface = Create();
  3144. }
  3145. /* virtual */
  3146. CWebCluster::~CWebCluster()
  3147. /*++
  3148. Routine Description:
  3149. Destructor -- releases the interface.
  3150. Arguments:
  3151. N/A
  3152. Return Value:
  3153. N/A
  3154. --*/
  3155. {
  3156. SAFE_RELEASE(m_pInterface);
  3157. }
  3158. #endif // KEVLAR
  3159. //
  3160. // CMetaEnumerator Clas
  3161. //
  3162. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3163. CMetaEnumerator::CMetaEnumerator(
  3164. IN CComAuthInfo * pAuthInfo OPTIONAL,
  3165. IN LPCTSTR lpszMDPath OPTIONAL,
  3166. IN METADATA_HANDLE hkBase OPTIONAL
  3167. )
  3168. /*++
  3169. Routine Description:
  3170. Metabase enumerator constructor. This constructor creates a new interface
  3171. and opens a key.
  3172. Arguments:
  3173. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3174. LPCTSTR lpszMDPath : Metabase path
  3175. METADATA_HANDLE hkBase : Metabase handle
  3176. Return Value:
  3177. N/A
  3178. --*/
  3179. : CMetaKey(pAuthInfo, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
  3180. m_dwIndex(0L)
  3181. {
  3182. }
  3183. CMetaEnumerator::CMetaEnumerator(
  3184. IN CMetaInterface * pInterface,
  3185. IN LPCTSTR lpszMDPath, OPTIONAL
  3186. IN METADATA_HANDLE hkBase OPTIONAL
  3187. )
  3188. /*++
  3189. Routine Description:
  3190. Metabase enumerator constructor. This constructor uses an existing
  3191. interface and opens a key.
  3192. Arguments:
  3193. CMetaInterface * pInterface : Existing interface
  3194. LPCTSTR lpszMDPath : Metabase path
  3195. METADATA_HANDLE hkBase : Metabase handle
  3196. Return Value:
  3197. N/A
  3198. --*/
  3199. : CMetaKey(pInterface, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
  3200. m_dwIndex(0L)
  3201. {
  3202. }
  3203. CMetaEnumerator::CMetaEnumerator(
  3204. IN BOOL fOwnKey,
  3205. IN CMetaKey * pKey
  3206. )
  3207. /*++
  3208. Routine Description:
  3209. Metabase enumerator constructor. This constructor uses an existing
  3210. interface and open key.
  3211. Arguments:
  3212. BOOL fOwnKey : TRUE if we own the key (destructor will close)
  3213. CMetaKey * pKey : Open key
  3214. Return Value:
  3215. N/A
  3216. --*/
  3217. : CMetaKey(fOwnKey, pKey),
  3218. m_dwIndex(0L)
  3219. {
  3220. }
  3221. HRESULT
  3222. CMetaEnumerator::Next(
  3223. OUT CString & strKey,
  3224. IN LPCTSTR lpszMDPath OPTIONAL
  3225. )
  3226. /*++
  3227. Routine Description:
  3228. Get the next subkey
  3229. Arguments:
  3230. CString & str Returns keyname
  3231. LPCTSTR lpszMDPath Optional subpath
  3232. Return Value:
  3233. HRESULT
  3234. --*/
  3235. {
  3236. ASSURE_PROPER_INTERFACE();
  3237. ASSURE_OPEN_KEY();
  3238. TCHAR buf[MAX_PATH];
  3239. HRESULT hr = EnumKeys(m_hKey, lpszMDPath, buf, m_dwIndex++);
  3240. if (SUCCEEDED(hr))
  3241. strKey = buf;
  3242. return hr;
  3243. }
  3244. HRESULT
  3245. CMetaEnumerator::Next(
  3246. OUT DWORD & dwKey,
  3247. OUT CString & strKey,
  3248. IN LPCTSTR lpszMDPath OPTIONAL
  3249. )
  3250. /*++
  3251. Routine Description:
  3252. Get the next subkey as a DWORD. This skips non-numeric
  3253. keynames (including 0) until the first numeric key name
  3254. Arguments:
  3255. DWORD & dwKey Numeric key
  3256. CString & strKey Same key in string format
  3257. LPCTSTR lpszMDPath Optional subpath
  3258. Return Value:
  3259. HRESULT
  3260. --*/
  3261. {
  3262. ASSURE_PROPER_INTERFACE();
  3263. ASSURE_OPEN_KEY();
  3264. HRESULT hr;
  3265. TCHAR buf[MAX_PATH];
  3266. while (TRUE)
  3267. {
  3268. if (SUCCEEDED(hr = EnumKeys(m_hKey, lpszMDPath, buf, m_dwIndex++)))
  3269. {
  3270. if (0 != (dwKey = _ttoi(buf)))
  3271. {
  3272. strKey = buf;
  3273. break;
  3274. }
  3275. }
  3276. else
  3277. break;
  3278. }
  3279. return hr;
  3280. }
  3281. // This method moved from inline to remove dependency on IIDs and CLSIDs
  3282. HRESULT
  3283. CIISSvcControl::Create()
  3284. {
  3285. return CIISInterface::Create(
  3286. 1,
  3287. &IID_IIisServiceControl,
  3288. &CLSID_IisServiceControl,
  3289. NULL,
  3290. (IUnknown **)&m_pInterface
  3291. );
  3292. }
  3293. //
  3294. // CIISApplication class
  3295. //
  3296. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
  3297. CIISApplication::CIISApplication(
  3298. IN CComAuthInfo * pAuthInfo OPTIONAL,
  3299. IN LPCTSTR lpszMetapath
  3300. )
  3301. /*++
  3302. Routine Description:
  3303. Construct IIS application.
  3304. Arguments:
  3305. CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
  3306. local computer.
  3307. LPCTSTR lpszMetapath : Metabase path
  3308. Return Value:
  3309. N/A
  3310. --*/
  3311. : CWamInterface(pAuthInfo),
  3312. CMetaKey(pAuthInfo),
  3313. m_dwProcessProtection(APP_INPROC),
  3314. m_dwAppState(APPSTATUS_NOTDEFINED),
  3315. m_strFriendlyName(),
  3316. m_strAppRoot(),
  3317. m_strWamPath(lpszMetapath)
  3318. {
  3319. CommonConstruct();
  3320. }
  3321. void
  3322. CIISApplication::CommonConstruct()
  3323. /*++
  3324. Routine Description:
  3325. Perform common construction
  3326. Arguments:
  3327. None
  3328. Return Value:
  3329. None
  3330. --*/
  3331. {
  3332. //
  3333. // Munge the metapath so that WAM doesn't cough up a hairball.
  3334. //
  3335. //
  3336. // BUGBUG: CleanMetaPath() disabled currently
  3337. //
  3338. if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
  3339. {
  3340. m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
  3341. }
  3342. do
  3343. {
  3344. m_hrApp = CWamInterface::QueryResult();
  3345. if (FAILED(m_hrApp))
  3346. {
  3347. break;
  3348. }
  3349. m_hrApp = RefreshAppState();
  3350. if (HRESULT_CODE(m_hrApp) == ERROR_PATH_NOT_FOUND)
  3351. {
  3352. //
  3353. // "Path Not Found" errors are acceptable, since
  3354. // the application may not yet exist.
  3355. //
  3356. m_hrApp = S_OK;
  3357. }
  3358. }
  3359. while(FALSE);
  3360. }
  3361. /* virtual */
  3362. BOOL
  3363. CIISApplication::Succeeded() const
  3364. /*++
  3365. Routine Description:
  3366. Determine if object was constructed successfully
  3367. Arguments:
  3368. None
  3369. Return Value:
  3370. TRUE for success, FALSE for failure
  3371. --*/
  3372. {
  3373. return CMetaInterface::Succeeded()
  3374. && CWamInterface::Succeeded()
  3375. && SUCCEEDED(m_hrApp);
  3376. }
  3377. /* virtual */
  3378. HRESULT
  3379. CIISApplication::QueryResult() const
  3380. /*++
  3381. Routine Description:
  3382. Return the construction error for this object
  3383. Arguments:
  3384. None
  3385. Return Value:
  3386. HRESULT from construction errors
  3387. --*/
  3388. {
  3389. //
  3390. // Both interfaces must have constructed successfully
  3391. //
  3392. HRESULT hr = CMetaInterface::QueryResult();
  3393. if (SUCCEEDED(hr))
  3394. {
  3395. hr = CWamInterface::QueryResult();
  3396. if (SUCCEEDED(hr))
  3397. {
  3398. hr = m_hrApp;
  3399. }
  3400. }
  3401. return hr;
  3402. }
  3403. HRESULT
  3404. CIISApplication::RefreshAppState()
  3405. /*++
  3406. Routine Description:
  3407. Refresh the application state
  3408. Arguments:
  3409. None
  3410. Return Value:
  3411. HRESULT
  3412. --*/
  3413. {
  3414. ASSERT(!m_strWamPath.IsEmpty());
  3415. HRESULT hr, hrKeys;
  3416. hr = AppGetStatus(m_strWamPath, &m_dwAppState);
  3417. if (FAILED(hr))
  3418. {
  3419. m_dwAppState = APPSTATUS_NOTDEFINED;
  3420. }
  3421. m_strAppRoot.Empty();
  3422. hrKeys = QueryValue(MD_APP_ROOT, m_strAppRoot, NULL, m_strWamPath);
  3423. m_dwProcessProtection = APP_INPROC;
  3424. hrKeys = QueryValue(
  3425. MD_APP_ISOLATED,
  3426. m_dwProcessProtection,
  3427. NULL,
  3428. m_strWamPath
  3429. );
  3430. m_strFriendlyName.Empty();
  3431. hrKeys = QueryValue(
  3432. MD_APP_FRIENDLY_NAME,
  3433. m_strFriendlyName,
  3434. NULL,
  3435. m_strWamPath
  3436. );
  3437. return hr;
  3438. }
  3439. HRESULT
  3440. CIISApplication::Create(
  3441. IN LPCTSTR lpszName, OPTIONAL
  3442. IN DWORD dwAppProtection
  3443. )
  3444. /*++
  3445. Routine Description:
  3446. Create the application
  3447. Arguments:
  3448. LPCTSTR lpszName : Application name
  3449. DWORD dwAppProtection : APP_INPROC to create in-proc app
  3450. APP_OUTOFPROC to create out-of-proc app
  3451. APP_POOLEDPROC to create a pooled-proc app
  3452. Return Value:
  3453. HRESULT
  3454. --*/
  3455. {
  3456. ASSERT(!m_strWamPath.IsEmpty());
  3457. HRESULT hr = AppCreate(m_strWamPath, dwAppProtection);
  3458. if (SUCCEEDED(hr))
  3459. {
  3460. //
  3461. // Write the friendly app name, which we maintain
  3462. // ourselves. Empty it first, because we might
  3463. // have picked up a name from inheritance.
  3464. //
  3465. m_strFriendlyName.Empty();
  3466. hr = WriteFriendlyName(lpszName);
  3467. RefreshAppState();
  3468. }
  3469. return hr;
  3470. }
  3471. HRESULT
  3472. CIISApplication::WriteFriendlyName(
  3473. IN LPCTSTR lpszName
  3474. )
  3475. /*++
  3476. Routine Description:
  3477. Write the friendly name. This will not write anything
  3478. if the name is the same as it was
  3479. Arguments:
  3480. LPCTSTR lpszName : New friendly name
  3481. Return Value:
  3482. HRESULT
  3483. --*/
  3484. {
  3485. HRESULT hr = S_OK;
  3486. if (m_strFriendlyName.CompareNoCase(lpszName) != 0)
  3487. {
  3488. hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
  3489. if (SUCCEEDED(hr))
  3490. {
  3491. ASSERT_PTR(lpszName);
  3492. CString str(lpszName);
  3493. hr = SetValue(MD_APP_FRIENDLY_NAME, str);
  3494. Close();
  3495. if (SUCCEEDED(hr))
  3496. {
  3497. m_strFriendlyName = lpszName;
  3498. }
  3499. }
  3500. }
  3501. return hr;
  3502. }