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.

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