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.

4839 lines
92 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name :
  4. inetprop.cpp
  5. Abstract:
  6. Internet Properties base classes
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include "comprop.h"
  18. #include "inetprop.h"
  19. #include "idlg.h"
  20. #include "mmc.h"
  21. extern "C"
  22. {
  23. #include <lm.h>
  24. }
  25. #ifdef _DEBUG
  26. #undef THIS_FILE
  27. static char BASED_CODE THIS_FILE[] = __FILE__;
  28. #endif
  29. //
  30. // Period to sleep while waiting for service to attain desired state
  31. //
  32. #define SLEEP_INTERVAL (500L)
  33. //
  34. // Maximum time to wait for service to attain desired state
  35. //
  36. #define MAX_SLEEP (180000) // For a service
  37. #define MAX_SLEEP_INST ( 30000) // For an instance
  38. //
  39. // Instance numbers
  40. //
  41. #define FIRST_INSTANCE (1)
  42. #define LAST_INSTANCE (0xffffffff)
  43. #define MAX_INSTANCE_LEN (32)
  44. //
  45. // Calling instance
  46. //
  47. HINSTANCE hDLLInstance;
  48. //
  49. // Utility Functions
  50. //
  51. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  52. //
  53. // Base registry key definition
  54. //
  55. #define SZ_REG_KEY_BASE _T("Software\\Microsoft\\%s")
  56. const LPCTSTR g_cszTemplates = SZ_MBN_INFO SZ_MBN_SEP_STR SZ_MBN_TEMPLATES;
  57. const LPCTSTR g_cszCompression = SZ_MBN_FILTERS SZ_MBN_SEP_STR SZ_MBN_COMPRESSION SZ_MBN_SEP_STR SZ_MBN_PARAMETERS;
  58. const LPCTSTR g_cszMachine = SZ_MBN_MACHINE;
  59. const LPCTSTR g_cszMimeMap = SZ_MBN_MIMEMAP;
  60. const LPCTSTR g_cszRoot = SZ_MBN_ROOT;
  61. const LPCTSTR g_cszSep = SZ_MBN_SEP_STR;
  62. const LPCTSTR g_cszInfo = SZ_MBN_INFO;
  63. const TCHAR g_chSep = SZ_MBN_SEP_CHAR;
  64. LPCTSTR
  65. GenerateRegistryKey(
  66. OUT CString & strBuffer,
  67. IN LPCTSTR lpszSubKey OPTIONAL
  68. )
  69. /*++
  70. Routine Description:
  71. Generate a registry key name based on the current app, and a
  72. provided subkey (optional)
  73. Arguments:
  74. CString & strBuffer : Buffer to create registry key name into.
  75. LPCTSTR lpszSubKey : Subkey name or NULL
  76. Return Value:
  77. Pointer to the registry key value
  78. --*/
  79. {
  80. try
  81. {
  82. //
  83. // Use the app name as the primary registry name
  84. //
  85. CWinApp * pApp = ::AfxGetApp();
  86. if (!pApp)
  87. {
  88. TRACEEOLID("No app object -- can't generate registry key name");
  89. ASSERT(FALSE);
  90. return NULL;
  91. }
  92. strBuffer.Format(SZ_REG_KEY_BASE, pApp->m_pszAppName);
  93. if (lpszSubKey)
  94. {
  95. strBuffer += _T("\\");
  96. strBuffer += lpszSubKey;
  97. }
  98. TRACEEOLID("Registry key is " << strBuffer);
  99. }
  100. catch(CMemoryException * e)
  101. {
  102. TRACEEOLID("!!!exception building regkey");
  103. e->ReportError();
  104. e->Delete();
  105. return NULL;
  106. }
  107. return strBuffer;
  108. }
  109. NET_API_STATUS
  110. QueryInetServiceStatus(
  111. IN LPCTSTR lpszServer,
  112. IN LPCTSTR lpszService,
  113. OUT int * pnState
  114. )
  115. /*++
  116. Routine Description:
  117. Determine the status of the given service on the given machine.
  118. Arguments:
  119. LPCTSTR lpszServer : Server name
  120. LPCTSTR lpszService : Service name
  121. int * pnState : Returns the service state
  122. Return Value:
  123. Error return code
  124. --*/
  125. {
  126. #ifdef NO_SERVICE_CONTROLLER
  127. *pnState = INetServiceUnknown;
  128. return ERROR_SUCCESS;
  129. #else
  130. SC_HANDLE hScManager;
  131. NET_API_STATUS err = ERROR_SUCCESS;
  132. hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_ENUMERATE_SERVICE);
  133. if (hScManager == NULL)
  134. {
  135. return ::GetLastError();
  136. }
  137. SC_HANDLE hService = ::OpenService(hScManager,
  138. lpszService, SERVICE_QUERY_STATUS);
  139. if (hService == NULL)
  140. {
  141. err = ::GetLastError();
  142. }
  143. else
  144. {
  145. SERVICE_STATUS ss;
  146. VERIFY(::QueryServiceStatus(hService, &ss));
  147. VERIFY(::QueryServiceStatus(hService, &ss));
  148. switch(ss.dwCurrentState)
  149. {
  150. case SERVICE_STOPPED:
  151. case SERVICE_STOP_PENDING:
  152. *pnState = INetServiceStopped;
  153. break;
  154. case SERVICE_RUNNING:
  155. case SERVICE_START_PENDING:
  156. case SERVICE_CONTINUE_PENDING:
  157. *pnState = INetServiceRunning;
  158. break;
  159. case SERVICE_PAUSE_PENDING:
  160. case SERVICE_PAUSED:
  161. *pnState = INetServicePaused;
  162. break;
  163. default:
  164. *pnState = INetServiceUnknown;
  165. }
  166. //
  167. // Make sure this is a controllable service
  168. //
  169. if ( (*pnState == INetServiceRunning || *pnState == INetServicePaused)
  170. && !(ss.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
  171. {
  172. TRACEEOLID("Service not controllable -- ignored");
  173. ::CloseServiceHandle(hService);
  174. ::CloseServiceHandle(hScManager);
  175. return ERROR_SERVICE_START_HANG;
  176. }
  177. ::CloseServiceHandle(hService);
  178. }
  179. ::CloseServiceHandle(hScManager);
  180. return err;
  181. #endif // NO_SERVICE_CONTROLLER
  182. }
  183. NET_API_STATUS
  184. ChangeInetServiceState(
  185. IN LPCTSTR lpszServer,
  186. IN LPCTSTR lpszService,
  187. IN int nNewState,
  188. OUT int * pnCurrentState
  189. )
  190. /*++
  191. Routine Description:
  192. Start/stop/pause or continue a _service_
  193. Arguments:
  194. LPCTSTR lpszServer : Server name
  195. LPCTSTR lpszService : Service name
  196. int nNewState : INetService* definition.
  197. int * pnCurrentState : Ptr to current state (will be changed)
  198. Return Value:
  199. Error return code
  200. --*/
  201. {
  202. #ifdef NO_SERVICE_CONTROLLER
  203. *pnCurrentState = INetServiceUnknown;
  204. return ERROR_SERVICE_REQUEST_TIMEOUT;
  205. #else
  206. SC_HANDLE hService = NULL;
  207. SC_HANDLE hScManager = NULL;
  208. NET_API_STATUS err = ERROR_SUCCESS;
  209. do
  210. {
  211. hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_ALL_ACCESS);
  212. if (hScManager == NULL)
  213. {
  214. err = ::GetLastError();
  215. break;
  216. }
  217. hService = ::OpenService(hScManager, lpszService, SERVICE_ALL_ACCESS);
  218. if (hService == NULL)
  219. {
  220. err = ::GetLastError();
  221. break;
  222. }
  223. BOOL fSuccess = FALSE;
  224. DWORD dwTargetState;
  225. DWORD dwPendingState = 0;
  226. SERVICE_STATUS ss;
  227. switch(nNewState)
  228. {
  229. case INetServiceStopped:
  230. dwTargetState = SERVICE_STOPPED;
  231. dwPendingState = SERVICE_STOP_PENDING;
  232. fSuccess = ::ControlService(hService, SERVICE_CONTROL_STOP, &ss);
  233. break;
  234. case INetServiceRunning:
  235. dwTargetState = SERVICE_RUNNING;
  236. if (*pnCurrentState == INetServicePaused)
  237. {
  238. dwPendingState = SERVICE_CONTINUE_PENDING;
  239. fSuccess = ::ControlService(hService,
  240. SERVICE_CONTROL_CONTINUE, &ss);
  241. }
  242. else
  243. {
  244. dwPendingState = SERVICE_START_PENDING;
  245. fSuccess = ::StartService(hService, 0, NULL);
  246. }
  247. break;
  248. case INetServicePaused:
  249. dwTargetState = SERVICE_PAUSED;
  250. dwPendingState = SERVICE_PAUSE_PENDING;
  251. fSuccess = ::ControlService(hService, SERVICE_CONTROL_PAUSE, &ss);
  252. break;
  253. default:
  254. ASSERT(FALSE && "Invalid service state requested");
  255. err = ERROR_INVALID_PARAMETER;
  256. }
  257. if (!fSuccess && err == ERROR_SUCCESS)
  258. {
  259. err = ::GetLastError();
  260. }
  261. if (err != ERROR_SUCCESS) {
  262. break;
  263. }
  264. //
  265. // Wait for the service to attain desired state, timeout
  266. // after 3 minutes.
  267. //
  268. DWORD dwSleepTotal = 0L;
  269. while (dwSleepTotal < MAX_SLEEP)
  270. {
  271. if (!::QueryServiceStatus(hService, &ss))
  272. {
  273. err = ::GetLastError();
  274. break;
  275. }
  276. if (ss.dwCurrentState != dwPendingState)
  277. {
  278. //
  279. // Done one way or another
  280. //
  281. if (ss.dwCurrentState != dwTargetState)
  282. {
  283. //
  284. // Did not achieve desired result. Something went
  285. // wrong.
  286. //
  287. if (ss.dwWin32ExitCode)
  288. {
  289. err = ss.dwWin32ExitCode;
  290. }
  291. }
  292. break;
  293. }
  294. //
  295. // Still pending...
  296. //
  297. ::Sleep(SLEEP_INTERVAL);
  298. dwSleepTotal += SLEEP_INTERVAL;
  299. }
  300. if (dwSleepTotal >= MAX_SLEEP)
  301. {
  302. err = ERROR_SERVICE_REQUEST_TIMEOUT;
  303. }
  304. //
  305. // Update state information
  306. //
  307. switch(ss.dwCurrentState)
  308. {
  309. case SERVICE_STOPPED:
  310. case SERVICE_STOP_PENDING:
  311. *pnCurrentState = INetServiceStopped;
  312. break;
  313. case SERVICE_RUNNING:
  314. case SERVICE_START_PENDING:
  315. case SERVICE_CONTINUE_PENDING:
  316. *pnCurrentState = INetServiceRunning;
  317. break;
  318. case SERVICE_PAUSE_PENDING:
  319. case SERVICE_PAUSED:
  320. *pnCurrentState = INetServicePaused;
  321. break;
  322. default:
  323. *pnCurrentState = INetServiceUnknown;
  324. }
  325. }
  326. while(FALSE);
  327. if (hService)
  328. {
  329. ::CloseServiceHandle(hService);
  330. }
  331. if (hScManager)
  332. {
  333. ::CloseServiceHandle(hScManager);
  334. }
  335. return err;
  336. #endif // NO_SERVICE_CONTROLLER
  337. }
  338. BOOL
  339. IsServerLocal(
  340. IN LPCTSTR lpszServer
  341. )
  342. /*++
  343. Routine Description:
  344. Check to see if the given name refers to the local machine
  345. Arguments:
  346. LPCTSTR lpszServer : Server name
  347. Return Value:
  348. TRUE if the given name refers to the local computer, FALSE otherwise
  349. Note:
  350. Doesn't work if the server is an ip address
  351. --*/
  352. {
  353. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  354. DWORD dwSize = sizeof(szComputerName);
  355. if (GetComputerName(szComputerName, &dwSize)
  356. && !lstrcmpi(szComputerName, PURE_COMPUTER_NAME(lpszServer)))
  357. {
  358. return TRUE;
  359. }
  360. return FALSE;
  361. }
  362. BOOL
  363. DoesServerExist(
  364. IN LPCTSTR lpszServer
  365. )
  366. /*++
  367. Routine Description:
  368. Check to make sure the machine exists
  369. Arguments:
  370. LPCTSTR lpszServer : machine name
  371. Return Value:
  372. TRUE if the server exists, FALSE otherwise.
  373. --*/
  374. {
  375. #ifdef NO_SERVICE_CONTROLLER
  376. //
  377. // Assume it exists
  378. //
  379. return TRUE;
  380. #else
  381. //
  382. // CODEWORK: This is not the best way to do this, especially
  383. // not across proxies and what not.
  384. //
  385. SC_HANDLE hScManager;
  386. NET_API_STATUS err = ERROR_SUCCESS;
  387. hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_CONNECT);
  388. if (hScManager == NULL)
  389. {
  390. err = ::GetLastError();
  391. }
  392. ::CloseServiceHandle(hScManager);
  393. return err != RPC_S_SERVER_UNAVAILABLE;
  394. #endif // NO_SERVICE_CONTROLLER
  395. }
  396. BOOL
  397. GetVolumeInformationSystemFlags(
  398. IN LPCTSTR lpszPath,
  399. OUT DWORD * pdwSystemFlags
  400. )
  401. /*++
  402. Routine Description:
  403. Get the system flags for the path in question
  404. Arguments:
  405. LPCTSTR lpszPath : Path
  406. DWORD * pdwSystemFlags : Returns system flags
  407. Return Value:
  408. TRUE for success, FALSE for failure.
  409. --*/
  410. {
  411. ASSERT(pdwSystemFlags != NULL);
  412. TRACEEOLID("Getting system flags for " << lpszPath);
  413. DWORD dwMaxComponentLength;
  414. TCHAR szRoot[MAX_PATH + 1];
  415. TCHAR szFileSystem[MAX_PATH + 1];
  416. //
  417. // Generating root path
  418. //
  419. if (IsUNCName(lpszPath))
  420. {
  421. //
  422. // Root path of a UNC path is \\foo\bar\
  423. //
  424. ASSERT(lstrlen(lpszPath) < MAX_PATH);
  425. int cSlashes = 0;
  426. LPCTSTR lpszSrc = lpszPath;
  427. LPTSTR lpszDst = szRoot;
  428. while (cSlashes < 4 && *lpszSrc)
  429. {
  430. if ((*lpszDst++ = *lpszSrc++) == '\\')
  431. {
  432. ++cSlashes;
  433. }
  434. }
  435. if (!*lpszSrc)
  436. {
  437. *lpszDst++ = '\\';
  438. }
  439. *lpszDst = '\0';
  440. }
  441. else
  442. {
  443. ::wsprintf(szRoot, _T("%c:\\"), *lpszPath);
  444. }
  445. TRACEEOLID("Root path is " << szRoot);
  446. return ::GetVolumeInformation(
  447. szRoot,
  448. NULL,
  449. 0,
  450. NULL,
  451. &dwMaxComponentLength,
  452. pdwSystemFlags,
  453. szFileSystem,
  454. STRSIZE(szFileSystem)
  455. );
  456. }
  457. LPTSTR
  458. ISMAllocString(
  459. IN CString & str
  460. )
  461. /*++
  462. Routine Description:
  463. Allocate and copy string using ISM allocator
  464. Arguments:
  465. CString & str : string
  466. Return Value:
  467. Pointer to the allocated string
  468. --*/
  469. {
  470. LPTSTR lp = (LPTSTR)ISMAllocMem((str.GetLength() + 1)* sizeof(TCHAR));
  471. if (lp != NULL)
  472. {
  473. lstrcpy(lp, str);
  474. }
  475. return lp;
  476. }
  477. //
  478. // Utility classes
  479. //
  480. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  481. CBlob::CBlob()
  482. /*++
  483. Routine Description:
  484. NULL constructor
  485. Arguments:
  486. None
  487. Return Value:
  488. N/A
  489. --*/
  490. : m_pbItem(NULL),
  491. m_dwSize(0L)
  492. {
  493. }
  494. CBlob::CBlob(
  495. IN DWORD dwSize,
  496. IN PBYTE pbItem,
  497. IN BOOL fMakeCopy
  498. )
  499. /*++
  500. Routine Description:
  501. Constructor
  502. Arguments:
  503. DWORD dwSize : Size of memory block
  504. PBYTE pbItem : Pointer to memory block
  505. BOOL fMakeCopy : If TRUE, makes a copy of the memory block.
  506. If FALSE, takes ownership of the pointer.
  507. Return Value:
  508. N/A
  509. --*/
  510. : m_pbItem(NULL),
  511. m_dwSize(0L)
  512. {
  513. SetValue(dwSize, pbItem, fMakeCopy);
  514. }
  515. CBlob::CBlob(
  516. IN const CBlob & blob
  517. )
  518. /*++
  519. Routine Description:
  520. Copy constructor
  521. Arguments:
  522. const CBlob & blob : Source blob
  523. Return Value:
  524. N/A
  525. Notes:
  526. This contructor makes a copy of the memory block in question.
  527. --*/
  528. : m_pbItem(NULL),
  529. m_dwSize(0L)
  530. {
  531. SetValue(blob.GetSize(), blob.m_pbItem, TRUE);
  532. }
  533. void
  534. CBlob::SetValue(
  535. IN DWORD dwSize,
  536. IN PBYTE pbItem,
  537. IN BOOL fMakeCopy OPTIONAL
  538. )
  539. /*++
  540. Routine Description:
  541. Assign the value to this binary object. If fMakeCopy is FALSE,
  542. the blob will take ownership of the pointer, otherwise a copy
  543. will be made.
  544. Arguments:
  545. DWORD dwSize : Size in bytes
  546. PBYTE pbItem : Byte streadm
  547. BOOL fMakeCopy : If true, make a copy, else assign pointer
  548. Return Value:
  549. None
  550. --*/
  551. {
  552. if (!IsEmpty())
  553. {
  554. TRACEEOLID("Assigning value to non-empty blob. Cleaning up");
  555. CleanUp();
  556. }
  557. if (dwSize > 0L)
  558. {
  559. //
  560. // Make private copy
  561. //
  562. m_dwSize = dwSize;
  563. if (fMakeCopy)
  564. {
  565. m_pbItem = (PBYTE)AllocMem(m_dwSize);
  566. if (m_pbItem != NULL)
  567. CopyMemory(m_pbItem, pbItem, dwSize);
  568. }
  569. else
  570. {
  571. m_pbItem = pbItem;
  572. }
  573. }
  574. }
  575. void
  576. CBlob::CleanUp()
  577. /*++
  578. Routine Description:
  579. Delete data pointer, and reset pointer and size.
  580. Arguments:
  581. None
  582. Return Value:
  583. None
  584. --*/
  585. {
  586. if (m_pbItem)
  587. {
  588. FreeMem(m_pbItem);
  589. }
  590. m_pbItem = NULL;
  591. m_dwSize = 0L;
  592. }
  593. CBlob &
  594. CBlob::operator =(
  595. IN const CBlob & blob
  596. )
  597. /*++
  598. Routine Description:
  599. Assign values from another CBlob.
  600. Arguments:
  601. const CBlob & blob : Source blob
  602. Return Value:
  603. Reference to this object
  604. --*/
  605. {
  606. //
  607. // Make copy of data
  608. //
  609. SetValue(blob.GetSize(), blob.m_pbItem, TRUE);
  610. return *this;
  611. }
  612. BOOL
  613. CBlob::operator ==(
  614. IN const CBlob & blob
  615. ) const
  616. /*++
  617. Routine Description:
  618. Compare two binary large objects. In order to match, the objects
  619. must be the same size, and byte identical.
  620. Arguments:
  621. const CBlob & blob : Blob to compare against.
  622. Return Value:
  623. TRUE if the objects match, FALSE otherwise.
  624. --*/
  625. {
  626. if (GetSize() != blob.GetSize())
  627. {
  628. return FALSE;
  629. }
  630. return memcmp(m_pbItem, blob.m_pbItem, GetSize()) == 0;
  631. }
  632. CMetaProperties::CMetaProperties(
  633. IN LPCTSTR lpszServerName,
  634. IN LPCTSTR lpszService, OPTIONAL
  635. IN DWORD dwInstance, OPTIONAL
  636. IN LPCTSTR lpszParentPath, OPTIONAL
  637. IN LPCTSTR lpszAlias OPTIONAL
  638. )
  639. /*++
  640. Routine Description:
  641. Constructor -- creates the interface
  642. Arguments:
  643. LPCTSTR lpszServerName : Server name
  644. LPCTSTR lpszService : Service name or NULL
  645. DWORD dwInstance : Instance number or 0
  646. LPCTSTR lpszParentPath : Parent path or NULL
  647. LPCTSTR lpszAlias : Alias name or NULL
  648. Return Value:
  649. N/A
  650. --*/
  651. : m_hResult(S_OK),
  652. m_dwNumEntries(0),
  653. m_dwMDUserType(ALL_METADATA),
  654. m_dwMDDataType(ALL_METADATA),
  655. m_dwMDDataLen(0),
  656. m_pbMDData(NULL),
  657. m_fInherit(TRUE),
  658. CMetaKey(lpszServerName)
  659. {
  660. //
  661. // Build the metabase path (prior to GetAllData)
  662. //
  663. BuildMetaPath(
  664. m_strMetaRoot,
  665. lpszService,
  666. dwInstance,
  667. lpszParentPath,
  668. lpszAlias
  669. );
  670. }
  671. CMetaProperties::CMetaProperties(
  672. IN const CMetaInterface * pInterface,
  673. IN LPCTSTR lpszService, OPTIONAL
  674. IN DWORD dwInstance, OPTIONAL
  675. IN LPCTSTR lpszParentPath, OPTIONAL
  676. IN LPCTSTR lpszAlias OPTIONAL
  677. )
  678. /*++
  679. Routine Description:
  680. Constructor -- attach to an existing interface.
  681. Arguments:
  682. CMetaInterface * pInterface : Existing interface
  683. LPCTSTR lpszService : Service name or NULL
  684. DWORD dwInstance : Instance number or 0
  685. LPCTSTR lpszParentPath : Parent path or NULL
  686. LPCTSTR lpszAlias : Alias name or NULL
  687. Return Value:
  688. N/A
  689. --*/
  690. : m_hResult(S_OK),
  691. m_dwNumEntries(0),
  692. m_dwMDUserType(ALL_METADATA),
  693. m_dwMDDataType(ALL_METADATA),
  694. m_dwMDDataLen(0),
  695. m_pbMDData(NULL),
  696. m_fInherit(TRUE),
  697. CMetaKey(pInterface)
  698. {
  699. //
  700. // Build the metabase path
  701. //
  702. BuildMetaPath(
  703. m_strMetaRoot,
  704. lpszService,
  705. dwInstance,
  706. lpszParentPath,
  707. lpszAlias
  708. );
  709. }
  710. CMetaProperties::CMetaProperties(
  711. IN const CMetaKey * pKey,
  712. IN LPCTSTR lpszMDPath
  713. )
  714. /*++
  715. Routine Description:
  716. Construct from open key
  717. Arguments:
  718. const CMetaKey * pKey : Open key
  719. LPCTSTR lpszMDPath : Path
  720. Return Value:
  721. N/A
  722. --*/
  723. : m_hResult(S_OK),
  724. m_dwNumEntries(0),
  725. m_dwMDUserType(ALL_METADATA),
  726. m_dwMDDataType(ALL_METADATA),
  727. m_dwMDDataLen(0),
  728. m_pbMDData(NULL),
  729. m_strMetaRoot(lpszMDPath),
  730. m_fInherit(TRUE),
  731. CMetaKey(FALSE, pKey)
  732. {
  733. }
  734. CMetaProperties::CMetaProperties(
  735. IN const CMetaKey * pKey,
  736. IN DWORD dwPath
  737. )
  738. /*++
  739. Routine Description:
  740. Construct from open key
  741. Arguments:
  742. const CMetaKey * pKey : Open key
  743. DWORD dwPath : Path (instance number probably)
  744. Return Value:
  745. N/A
  746. --*/
  747. : m_hResult(S_OK),
  748. m_dwNumEntries(0),
  749. m_dwMDUserType(ALL_METADATA),
  750. m_dwMDDataType(ALL_METADATA),
  751. m_dwMDDataLen(0),
  752. m_pbMDData(NULL),
  753. m_fInherit(TRUE),
  754. CMetaKey(FALSE, pKey)
  755. {
  756. _ltot(dwPath, m_strMetaRoot.GetBuffer(32), 10);
  757. m_strMetaRoot.ReleaseBuffer();
  758. }
  759. CMetaProperties::~CMetaProperties()
  760. /*++
  761. Routine Description:
  762. Destructor -- clean up
  763. Arguments:
  764. N/A
  765. Return Value:
  766. N/A
  767. --*/
  768. {
  769. Cleanup();
  770. }
  771. /* virtual */
  772. HRESULT
  773. CMetaProperties::LoadData()
  774. /*++
  775. Routine Description:
  776. Fetch all data with or without inheritance, and call the derived
  777. class to parse the data into fields.
  778. Arguments:
  779. None
  780. Return Value:
  781. HRESULT
  782. --*/
  783. {
  784. //
  785. // Get all data off the master root
  786. //
  787. DWORD dwMDAttributes = METADATA_NO_ATTRIBUTES;
  788. if (m_fInherit)
  789. {
  790. dwMDAttributes = METADATA_INHERIT
  791. | METADATA_PARTIAL_PATH
  792. | METADATA_ISINHERITED;
  793. }
  794. m_hResult = GetAllData(
  795. dwMDAttributes,
  796. m_dwMDUserType,
  797. m_dwMDDataType,
  798. &m_dwNumEntries,
  799. &m_dwMDDataLen,
  800. &m_pbMDData,
  801. m_strMetaRoot
  802. );
  803. if (SUCCEEDED(m_hResult))
  804. {
  805. //
  806. // Call the derived class to break up data into fields
  807. //
  808. ParseFields();
  809. }
  810. Cleanup();
  811. return m_hResult;
  812. }
  813. void
  814. CMetaProperties::Cleanup()
  815. /*++
  816. Routine Description:
  817. Free data
  818. Arguments:
  819. None
  820. Return Value:
  821. None
  822. --*/
  823. {
  824. SAFE_FREEMEM(m_pbMDData);
  825. m_dwNumEntries = 0;
  826. m_dwMDDataLen = 0;
  827. }
  828. /* virtual */
  829. HRESULT
  830. CMetaProperties::QueryResult() const
  831. /*++
  832. Routine Description:
  833. Determine the construction return code
  834. Arguments:
  835. None
  836. Return Value:
  837. HRESULT
  838. --*/
  839. {
  840. HRESULT hr = CMetaKey::QueryResult();
  841. return SUCCEEDED(hr) ? m_hResult : hr;
  842. }
  843. HRESULT
  844. CMetaProperties::OpenForWriting(
  845. IN BOOL fCreate OPTIONAL
  846. )
  847. /*++
  848. Routine Description:
  849. Attempt to open the path for writing. If fCreate is TRUE
  850. (default), then create the path if it doesn't yet exist
  851. Arguments:
  852. BOOL fCreate : If TRUE, create the path if it doesn't exist.
  853. Return Value:
  854. HRESULT
  855. Notes:
  856. If the key is already open, this will fire an ASSERT and close
  857. it.
  858. --*/
  859. {
  860. CError err;
  861. if (IsOpen())
  862. {
  863. TRACEEOLID("Key already open -- closing");
  864. ASSERT(FALSE);
  865. Close();
  866. }
  867. BOOL fNewPath;
  868. do
  869. {
  870. fNewPath = FALSE;
  871. err = Open(
  872. METADATA_PERMISSION_WRITE,
  873. METADATA_MASTER_ROOT_HANDLE,
  874. m_strMetaRoot
  875. );
  876. if (err.Win32Error() == ERROR_PATH_NOT_FOUND && fCreate)
  877. {
  878. TRACEEOLID("Metabase path doesn't exist -- creating it");
  879. err = CreatePathFromFailedOpen();
  880. fNewPath = err.Succeeded();
  881. }
  882. }
  883. while(fNewPath);
  884. return err;
  885. }
  886. //
  887. // Machine properties
  888. //
  889. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  890. CMachineProps::CMachineProps(
  891. IN LPCTSTR lpszServerName
  892. )
  893. /*++
  894. Routine Description:
  895. Constructor for machine properties object
  896. Arguments:
  897. LPCTSTR lpszServerName : Server name
  898. Return Value:
  899. N/A
  900. --*/
  901. : CMetaProperties(
  902. lpszServerName,
  903. NULL,
  904. MASTER_INSTANCE
  905. ),
  906. //
  907. // Default properties
  908. //
  909. m_nMaxNetworkUse(DEF_BANDWIDTH)
  910. {
  911. }
  912. CMachineProps::CMachineProps(
  913. IN const CMetaInterface * pInterface
  914. )
  915. /*++
  916. Routine Description:
  917. Constructor for machine properties object
  918. Arguments:
  919. CMetaInterface * pInterface : Existing interface
  920. Return Value:
  921. N/A
  922. --*/
  923. : CMetaProperties(
  924. pInterface,
  925. NULL,
  926. MASTER_INSTANCE
  927. ),
  928. //
  929. // Default properties
  930. //
  931. m_nMaxNetworkUse(DEF_BANDWIDTH)
  932. {
  933. }
  934. /* virtual */
  935. void
  936. CMachineProps::ParseFields()
  937. /*++
  938. Routine Description:
  939. Parse the fetched data into fields
  940. Arguments:
  941. None
  942. Return Value:
  943. None
  944. --*/
  945. {
  946. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  947. HANDLE_META_RECORD(MD_MAX_BANDWIDTH, m_nMaxNetworkUse)
  948. END_PARSE_META_RECORDS
  949. }
  950. HRESULT
  951. CMachineProps::WriteDirtyProps()
  952. /*++
  953. Routine Description:
  954. Write dirty properties
  955. Arguments:
  956. None
  957. Return Value:
  958. HRESULT
  959. --*/
  960. {
  961. CError err;
  962. BEGIN_META_WRITE()
  963. META_WRITE(MD_MAX_BANDWIDTH, m_nMaxNetworkUse)
  964. END_META_WRITE(err);
  965. return err;
  966. }
  967. //
  968. // Compression Properties
  969. //
  970. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  971. CIISCompressionProps::CIISCompressionProps(
  972. IN LPCTSTR lpszServerName,
  973. IN LPCTSTR lpszService, OPTIONAL
  974. IN DWORD dwInstance, OPTIONAL
  975. IN LPCTSTR lpszParent, OPTIONAL
  976. IN LPCTSTR lpszAlias OPTIONAL
  977. )
  978. /*++
  979. Routine Description:
  980. Constructor for compression properties object
  981. Arguments:
  982. LPCTSTR lpszServerName : Server name
  983. LPCTSTR lpszService : Service name (must be w3svc)
  984. DWORD dwInstance : Instance (must be master)
  985. LPCTSTR lpszParent : Parent path (must be NULL)
  986. LPCTSTR lpszAlias : Alias name (must be NULL)
  987. Return Value:
  988. N/A
  989. --*/
  990. : CMetaProperties(
  991. lpszServerName,
  992. lpszService,
  993. dwInstance,
  994. lpszParent,
  995. g_cszCompression
  996. ),
  997. //
  998. // Default properties
  999. //
  1000. m_fEnableStaticCompression(FALSE),
  1001. m_fEnableDynamicCompression(FALSE),
  1002. m_fLimitDirectorySize(FALSE),
  1003. m_fPathDoesNotExist(FALSE),
  1004. m_dwDirectorySize(0xffffffff),
  1005. m_strDirectory()
  1006. {
  1007. //
  1008. // Override base parameters
  1009. //
  1010. m_fInherit = FALSE;
  1011. }
  1012. /* virtual */
  1013. HRESULT
  1014. CIISCompressionProps::LoadData()
  1015. /*++
  1016. Routine Description:
  1017. Fetch all data with or without inheritance, and call the derived
  1018. class to parse the data into fields.
  1019. Arguments:
  1020. None
  1021. Return Value:
  1022. HRESULT
  1023. --*/
  1024. {
  1025. CError err(CMetaProperties::LoadData());
  1026. m_fPathDoesNotExist = (err.Win32Error() == ERROR_PATH_NOT_FOUND);
  1027. return err;
  1028. }
  1029. /* virtual */
  1030. void
  1031. CIISCompressionProps::ParseFields()
  1032. /*++
  1033. Routine Description:
  1034. Parse the fetched data into fields
  1035. Arguments:
  1036. None
  1037. Return Value:
  1038. None
  1039. --*/
  1040. {
  1041. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  1042. HANDLE_META_RECORD(MD_HC_DO_STATIC_COMPRESSION, m_fEnableStaticCompression)
  1043. HANDLE_META_RECORD(MD_HC_DO_DYNAMIC_COMPRESSION, m_fEnableDynamicCompression)
  1044. HANDLE_META_RECORD(MD_HC_DO_DISK_SPACE_LIMITING, m_fLimitDirectorySize)
  1045. HANDLE_META_RECORD(MD_HC_MAX_DISK_SPACE_USAGE, m_dwDirectorySize)
  1046. HANDLE_META_RECORD(MD_HC_COMPRESSION_DIRECTORY, m_strDirectory)
  1047. END_PARSE_META_RECORDS
  1048. }
  1049. /* virtual */
  1050. HRESULT
  1051. CIISCompressionProps::WriteDirtyProps()
  1052. /*++
  1053. Routine Description:
  1054. Write dirty properties
  1055. Arguments:
  1056. None
  1057. Return Value:
  1058. HRESULT
  1059. --*/
  1060. {
  1061. CError err;
  1062. BEGIN_META_WRITE()
  1063. META_WRITE(MD_HC_DO_STATIC_COMPRESSION, m_fEnableStaticCompression)
  1064. META_WRITE(MD_HC_DO_DYNAMIC_COMPRESSION, m_fEnableDynamicCompression)
  1065. META_WRITE(MD_HC_DO_DISK_SPACE_LIMITING, m_fLimitDirectorySize)
  1066. META_WRITE(MD_HC_MAX_DISK_SPACE_USAGE, m_dwDirectorySize)
  1067. META_WRITE(MD_HC_COMPRESSION_DIRECTORY, m_strDirectory)
  1068. END_META_WRITE(err);
  1069. return err;
  1070. }
  1071. //
  1072. // Mime Types Properties
  1073. //
  1074. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1075. CMimeTypes::CMimeTypes(
  1076. IN LPCTSTR lpszServerName,
  1077. IN LPCTSTR lpszService OPTIONAL,
  1078. IN DWORD dwInstance OPTIONAL,
  1079. IN LPCTSTR lpszParent OPTIONAL,
  1080. IN LPCTSTR lpszAlias OPTIONAL
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Mime types list constructor
  1085. Arguments:
  1086. LPCTSTR lpszServerName : Name of the server containing the metabase
  1087. LPCTSTR lpszService : Service name (e.g. "w3svc" or NULL)
  1088. DWORD dwInstance : Instance number (could be MASTER_INSTANCE)
  1089. LPCTSTR lpszParent : Parent path
  1090. LPCTSTR lpszAlias : Alias name
  1091. Return Value:
  1092. N/A
  1093. --*/
  1094. : CMetaProperties(
  1095. lpszServerName,
  1096. lpszService,
  1097. dwInstance,
  1098. lpszParent,
  1099. dwInstance == MASTER_INSTANCE && lpszService == NULL
  1100. ? g_cszMimeMap
  1101. : lpszAlias
  1102. ),
  1103. //
  1104. // Default properties
  1105. //
  1106. m_strlMimeTypes()
  1107. {
  1108. }
  1109. CMimeTypes::CMimeTypes(
  1110. IN const CMetaInterface * pInterface,
  1111. IN LPCTSTR lpszService OPTIONAL,
  1112. IN DWORD dwInstance OPTIONAL,
  1113. IN LPCTSTR lpszParent OPTIONAL,
  1114. IN LPCTSTR lpszAlias OPTIONAL
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. Mime types list constructor
  1119. Arguments:
  1120. CMetaInterface * pInterface : Existing interface
  1121. LPCTSTR lpszService : Service name (e.g. "w3svc" or NULL)
  1122. DWORD dwInstance : Instance number (could be MASTER_INSTANCE)
  1123. LPCTSTR lpszParent : Parent path
  1124. LPCTSTR lpszAlias : Alias name
  1125. Return Value:
  1126. N/A
  1127. --*/
  1128. : CMetaProperties(
  1129. pInterface,
  1130. lpszService,
  1131. dwInstance,
  1132. lpszParent,
  1133. dwInstance == MASTER_INSTANCE && lpszService == NULL
  1134. ? g_cszMimeMap
  1135. : lpszAlias
  1136. ),
  1137. //
  1138. // Default properties
  1139. //
  1140. m_strlMimeTypes()
  1141. {
  1142. }
  1143. void
  1144. CMimeTypes::ParseFields()
  1145. /*++
  1146. Routine Description:
  1147. Parse the fetched data into fields
  1148. Arguments:
  1149. None
  1150. Return Value:
  1151. None
  1152. --*/
  1153. {
  1154. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  1155. HANDLE_META_RECORD(MD_MIME_MAP, m_strlMimeTypes)
  1156. END_PARSE_META_RECORDS
  1157. }
  1158. /* virtual */
  1159. HRESULT
  1160. CMimeTypes::WriteDirtyProps()
  1161. /*++
  1162. Routine Description:
  1163. Write the dirty properties to the metabase
  1164. Arguments:
  1165. None
  1166. Return Value:
  1167. HRESULT
  1168. --*/
  1169. {
  1170. CError err;
  1171. BEGIN_META_WRITE()
  1172. META_WRITE(MD_MIME_MAP, m_strlMimeTypes);
  1173. END_META_WRITE(err);
  1174. return err;
  1175. }
  1176. //
  1177. // Server Capabilities
  1178. //
  1179. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1180. CServerCapabilities::CServerCapabilities(
  1181. IN LPCTSTR lpszServerName,
  1182. IN LPCTSTR lpszService, OPTIONAL
  1183. IN DWORD dwInstance OPTIONAL
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Constructor for server capabilities object
  1188. Arguments:
  1189. LPCTSTR lpszServerName : Server name
  1190. LPCTSTR lpszService : Service name (optional)
  1191. DWORD dwInstance : Instance number -- ignored (will be removed)
  1192. Return Value:
  1193. N/A
  1194. --*/
  1195. : CMetaProperties(
  1196. lpszServerName,
  1197. lpszService,
  1198. MASTER_INSTANCE,
  1199. g_cszInfo
  1200. ),
  1201. //
  1202. // Default properties
  1203. //
  1204. m_dwPlatform(),
  1205. m_dwVersionMajor(),
  1206. m_dwVersionMinor(),
  1207. m_dwCapabilities((DWORD)~IIS_CAP1_10_CONNECTION_LIMIT),
  1208. m_dwConfiguration(0L)
  1209. {
  1210. m_dwMDUserType = IIS_MD_UT_SERVER;
  1211. m_dwMDDataType = DWORD_METADATA;
  1212. }
  1213. /* virtual */
  1214. void
  1215. CServerCapabilities::ParseFields()
  1216. /*++
  1217. Routine Description:
  1218. Parse the fetched data into fields
  1219. Arguments:
  1220. None
  1221. Return Value:
  1222. None
  1223. --*/
  1224. {
  1225. //
  1226. // Only reading UT_SERVER, DWORD_METADATA.
  1227. //
  1228. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  1229. HANDLE_META_RECORD(MD_SERVER_PLATFORM, m_dwPlatform)
  1230. HANDLE_META_RECORD(MD_SERVER_VERSION_MAJOR, m_dwVersionMajor)
  1231. HANDLE_META_RECORD(MD_SERVER_VERSION_MINOR, m_dwVersionMinor)
  1232. HANDLE_META_RECORD(MD_SERVER_CAPABILITIES, m_dwCapabilities)
  1233. HANDLE_META_RECORD(MD_SERVER_CONFIGURATION_INFO, m_dwConfiguration)
  1234. END_PARSE_META_RECORDS
  1235. }
  1236. //
  1237. // Instance Properties
  1238. //
  1239. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1240. /* static */
  1241. LPCTSTR
  1242. CInstanceProps::GetDisplayText(
  1243. OUT CString & strName,
  1244. IN LPCTSTR szComment,
  1245. IN LPCTSTR szHostHeaderName,
  1246. IN LPCTSTR szServiceName,
  1247. IN CIPAddress & ia,
  1248. IN UINT uPort,
  1249. IN DWORD dwID
  1250. )
  1251. /*++
  1252. Routine Description:
  1253. Build display text from instance information
  1254. Arguments:
  1255. CString & strName
  1256. LPCTSTR szComment
  1257. LPCTSTR szHostHeaderName
  1258. LPCTSTR szServiceName
  1259. CIPAddress & ia
  1260. UINT uPort
  1261. DWORD dwID
  1262. Return Value:
  1263. Pointer to the name buffer.
  1264. --*/
  1265. {
  1266. //
  1267. // Generate display name
  1268. //
  1269. // First use the comment,
  1270. // if that's not available, use the host header name,
  1271. // if that's not available, use the IP address:port.
  1272. // If that's not available, use the instance number.
  1273. //
  1274. //
  1275. CString strFmt;
  1276. if (szComment && *szComment)
  1277. {
  1278. strName = szComment;
  1279. }
  1280. else if (szHostHeaderName && *szHostHeaderName)
  1281. {
  1282. strName = szHostHeaderName;
  1283. }
  1284. else
  1285. {
  1286. #ifndef _COMSTATIC
  1287. HINSTANCE hOld = AfxGetResourceHandle();
  1288. AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME));
  1289. #endif // _COMSTATIC
  1290. if(!ia.IsZeroValue() && uPort != 0)
  1291. {
  1292. VERIFY(strFmt.LoadString(IDS_INSTANCE_PORT_FMT));
  1293. strName.Format(strFmt,(LPCTSTR)ia, uPort);
  1294. }
  1295. else
  1296. {
  1297. // VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT));
  1298. // strName.Format(strFmt, szServiceName, dwID);
  1299. if (0 == _tcscmp(szServiceName, _T("FTP")))
  1300. {
  1301. VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT_FTP));
  1302. }
  1303. else if (0 == _tcscmp(szServiceName, _T("Web")))
  1304. {
  1305. VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT_WEB));
  1306. }
  1307. strName.Format(strFmt, dwID);
  1308. }
  1309. #ifndef _COMSTATIC
  1310. AfxSetResourceHandle(hOld);
  1311. #endif // _COMSTATIC
  1312. }
  1313. return strName;
  1314. }
  1315. /* static */
  1316. void
  1317. CInstanceProps::CrackBinding(
  1318. IN CString strBinding,
  1319. OUT CIPAddress & iaIpAddress,
  1320. OUT UINT & nTCPPort,
  1321. OUT CString & strDomainName
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. Helper function to crack a binding string
  1326. Arguments:
  1327. CString strBinding : Binding string to be parsed
  1328. CIPAddress & iaIpAddress : IP Address output
  1329. UINT & nTCPPort : TCP Port
  1330. CString & strDomainName : Domain (host) header name
  1331. Return Value:
  1332. None
  1333. --*/
  1334. {
  1335. //
  1336. // Zero initialize
  1337. //
  1338. iaIpAddress.SetZeroValue();
  1339. nTCPPort = 0;
  1340. strDomainName.Empty();
  1341. int iColonPos = strBinding.Find(_TCHAR(':'));
  1342. if(iColonPos != -1)
  1343. {
  1344. //
  1345. // Get the IP address
  1346. //
  1347. iaIpAddress = strBinding.Left(iColonPos);
  1348. //
  1349. // Look for the second colon
  1350. //
  1351. strBinding = strBinding.Mid(iColonPos + 1);
  1352. iColonPos = strBinding.Find(_TCHAR(':'));
  1353. }
  1354. if(iColonPos != -1)
  1355. {
  1356. //
  1357. // Get the port number
  1358. //
  1359. nTCPPort = ::_ttol(strBinding.Left(iColonPos));
  1360. //
  1361. // Look for the NULL termination
  1362. //
  1363. strBinding = strBinding.Mid(iColonPos + 1);
  1364. iColonPos = strBinding.Find(_TCHAR('\0'));
  1365. }
  1366. if(iColonPos != -1)
  1367. {
  1368. strDomainName = strBinding.Left(iColonPos);
  1369. }
  1370. }
  1371. /* static */
  1372. void
  1373. CInstanceProps::CrackSecureBinding(
  1374. IN CString strBinding,
  1375. OUT CIPAddress & iaIpAddress,
  1376. OUT UINT & nSSLPort
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Helper function to crack a secure binding string
  1381. Arguments:
  1382. CString strBinding : Binding string to be parsed
  1383. CIPAddress & iaIpAddress : IP Address output
  1384. UINT & nSSLPort : SSL Port
  1385. Return Value:
  1386. None
  1387. --*/
  1388. {
  1389. //
  1390. // Same as regular binding without domain name
  1391. //
  1392. CString strDomainName;
  1393. CrackBinding(strBinding, iaIpAddress, nSSLPort, strDomainName);
  1394. ASSERT(strDomainName.IsEmpty());
  1395. }
  1396. /* static */
  1397. int
  1398. CInstanceProps::FindMatchingSecurePort(
  1399. IN CStringList & strlSecureBindings,
  1400. IN CIPAddress & iaIPAddress,
  1401. OUT UINT & nSSLPort
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. Find the SSL port applicable to the given IP Address.
  1406. Arguments:
  1407. CStringList & strlSecureBindings : Input stringlist of secure bindings
  1408. CIPAddress & iaIPAddress : IP Address to target
  1409. UINT & nSSLPort : Returns the SSL Port
  1410. Return Value:
  1411. The index of the binding string, or -1 if not found.
  1412. Notes:
  1413. The SSL port will be set to 0, if the IP address does not exist.
  1414. A 0.0.0.0 ip address translates to "All Unassigned".
  1415. --*/
  1416. {
  1417. nSSLPort = 0;
  1418. int cItems = 0;
  1419. POSITION pos = strlSecureBindings.GetHeadPosition();
  1420. while(pos)
  1421. {
  1422. CString & strBinding = strlSecureBindings.GetNext(pos);
  1423. CIPAddress ia;
  1424. UINT nPort;
  1425. CrackSecureBinding(strBinding, ia, nPort);
  1426. if (ia == iaIPAddress)
  1427. {
  1428. //
  1429. // Found it!
  1430. //
  1431. nSSLPort = nPort;
  1432. return cItems;
  1433. }
  1434. ++cItems;
  1435. }
  1436. //
  1437. // Not found
  1438. //
  1439. return -1;
  1440. }
  1441. /* static */
  1442. BOOL
  1443. CInstanceProps::IsPortInUse(
  1444. IN CStringList & strlBindings,
  1445. IN CIPAddress & iaIPAddress,
  1446. IN UINT nPort
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. Check to see if the give ip address/port combination is in use.
  1451. Arguments:
  1452. CStringList & strlBindings : Input stringlist of bindings
  1453. CIPAddress & iaIpAddress : IP Address target
  1454. UINT nPort : Port
  1455. Return Value:
  1456. TRUE if the given ip address/port combo is in use
  1457. Notes:
  1458. Host header name is ignored
  1459. --*/
  1460. {
  1461. POSITION pos = strlBindings.GetHeadPosition();
  1462. while(pos)
  1463. {
  1464. CString & strBinding = strlBindings.GetNext(pos);
  1465. CIPAddress ia;
  1466. UINT n;
  1467. CString str;
  1468. CrackBinding(strBinding, ia, n, str);
  1469. if (ia == iaIPAddress && n == nPort)
  1470. {
  1471. //
  1472. // Found it!
  1473. //
  1474. return TRUE;
  1475. }
  1476. }
  1477. //
  1478. // Not found
  1479. //
  1480. return FALSE;
  1481. }
  1482. /* static */
  1483. void
  1484. CInstanceProps::BuildBinding(
  1485. OUT CString & strBinding,
  1486. IN CIPAddress & iaIpAddress,
  1487. IN UINT & nTCPPort,
  1488. IN CString & strDomainName
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. Build up a binding string from its component parts
  1493. Arguments:
  1494. CString & strBinding : Output binding string
  1495. CIPAddress & iaIpAddress : ip address (could be 0.0.0.0)
  1496. UINT & nTCPPort : TCP Port
  1497. CString & strDomainName : Domain name (host header)
  1498. Return Value:
  1499. None.
  1500. --*/
  1501. {
  1502. if (!iaIpAddress.IsZeroValue())
  1503. {
  1504. strBinding.Format(
  1505. _T("%s:%d:%s"),
  1506. (LPCTSTR)iaIpAddress,
  1507. nTCPPort,
  1508. (LPCTSTR)strDomainName
  1509. );
  1510. }
  1511. else
  1512. {
  1513. //
  1514. // Leave the ip address field blank
  1515. //
  1516. strBinding.Format(_T(":%d:%s"), nTCPPort, (LPCTSTR)strDomainName);
  1517. }
  1518. }
  1519. /* static */
  1520. void
  1521. CInstanceProps::BuildSecureBinding(
  1522. OUT CString & strBinding,
  1523. IN CIPAddress & iaIpAddress,
  1524. IN UINT & nSSLPort
  1525. )
  1526. /*++
  1527. Routine Description:
  1528. Build up a binding string from its component parts
  1529. Arguments:
  1530. CString & strBinding : Output binding string
  1531. CIPAddress & iaIpAddress : ip address (could be 0.0.0.0)
  1532. UINT & nSSLPort : SSL Port
  1533. Return Value:
  1534. None.
  1535. --*/
  1536. {
  1537. CString strDomainName;
  1538. BuildBinding(strBinding, iaIpAddress, nSSLPort, strDomainName);
  1539. }
  1540. CInstanceProps::CInstanceProps(
  1541. IN LPCTSTR lpszServerName,
  1542. IN LPCTSTR lpszService, // e.g. "W3SVC"
  1543. IN DWORD dwInstance OPTIONAL,
  1544. IN UINT nDefPort OPTIONAL
  1545. )
  1546. /*++
  1547. Routine Description:
  1548. Constructor for instance properties
  1549. Arguments:
  1550. LPCTSTR lpszServerName : Name of server
  1551. LPCTSTR lpszService : Name of service (e.g. "W3SVC")
  1552. DWORD dwInstance : Instance number (or MASTER_INSTANCE)
  1553. Return Value:
  1554. N/A
  1555. --*/
  1556. : CMetaProperties(lpszServerName, lpszService, dwInstance),
  1557. m_dwInstance(dwInstance),
  1558. m_dwWin32Error(ERROR_SUCCESS),
  1559. //
  1560. // Default Instance Values
  1561. //
  1562. m_strlBindings(),
  1563. m_strComment(),
  1564. m_fNotDeletable(FALSE),
  1565. m_fCluster(FALSE),
  1566. m_nTCPPort(nDefPort),
  1567. m_iaIpAddress(NULL_IP_ADDRESS),
  1568. m_strDomainName(),
  1569. m_dwState(MD_SERVER_STATE_STOPPED),
  1570. m_nISMState(INetServiceUnknown)
  1571. {
  1572. //
  1573. // Fetch just enough info for the enumeration
  1574. //
  1575. m_dwMDUserType = IIS_MD_UT_SERVER;
  1576. }
  1577. CInstanceProps::CInstanceProps(
  1578. IN const CMetaInterface * pInterface,
  1579. IN LPCTSTR lpszService, // e.g. "W3SVC"
  1580. IN DWORD dwInstance OPTIONAL,
  1581. IN UINT nDefPort OPTIONAL
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. Constructor that uses an existing interface
  1586. Arguments:
  1587. CMetaInterface * pInterface : Existing interface
  1588. LPCTSTR lpszService : Name of service (e.g. "W3SVC")
  1589. DWORD dwInstance : Instance number (or MASTER_INSTANCE)
  1590. Return Value:
  1591. N/A
  1592. --*/
  1593. : CMetaProperties(pInterface, lpszService, dwInstance),
  1594. m_dwInstance(dwInstance),
  1595. m_dwWin32Error(ERROR_SUCCESS),
  1596. //
  1597. // Default Instance Values
  1598. //
  1599. m_strlBindings(),
  1600. m_strComment(),
  1601. m_fNotDeletable(FALSE),
  1602. m_fCluster(FALSE),
  1603. m_nTCPPort(nDefPort),
  1604. m_iaIpAddress((LONG)0),
  1605. m_strDomainName(),
  1606. m_dwState(MD_SERVER_STATE_STOPPED),
  1607. m_nISMState(INetServiceUnknown)
  1608. {
  1609. //
  1610. // Fetch enough for enumeration only
  1611. //
  1612. m_dwMDUserType = IIS_MD_UT_SERVER;
  1613. }
  1614. CInstanceProps::CInstanceProps(
  1615. IN CMetaKey * pKey,
  1616. IN DWORD dwInstance,
  1617. IN UINT nDefPort OPTIONAL
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Read instance properties off an open key
  1622. Arguments:
  1623. CMetaKey * pKey : Open key
  1624. DWORD dwInstance : Instance number
  1625. UINT nDefPort : Default port number
  1626. Return Value:
  1627. N/A
  1628. --*/
  1629. : CMetaProperties(pKey, dwInstance),
  1630. m_dwInstance(dwInstance),
  1631. m_dwWin32Error(ERROR_SUCCESS),
  1632. //
  1633. // Default Instance Values
  1634. //
  1635. m_strlBindings(),
  1636. m_strComment(),
  1637. m_fNotDeletable(FALSE),
  1638. m_fCluster(FALSE),
  1639. m_nTCPPort(nDefPort),
  1640. m_iaIpAddress((LONG)0),
  1641. m_strDomainName(),
  1642. m_dwState(MD_SERVER_STATE_STOPPED),
  1643. m_nISMState(INetServiceUnknown)
  1644. {
  1645. //
  1646. // Fetch enough for enumeration only
  1647. //
  1648. m_dwMDUserType = IIS_MD_UT_SERVER;
  1649. }
  1650. void
  1651. CInstanceProps::SetISMStateFromServerState()
  1652. /*++
  1653. Routine Description:
  1654. Translate server state to ISM state value
  1655. Arguments:
  1656. None.
  1657. Return Value:
  1658. None.
  1659. --*/
  1660. {
  1661. //
  1662. // Derive Values
  1663. //
  1664. switch(m_dwState)
  1665. {
  1666. case MD_SERVER_STATE_STARTED:
  1667. m_nISMState = INetServiceRunning;
  1668. break;
  1669. case MD_SERVER_STATE_STOPPED:
  1670. m_nISMState = INetServiceStopped;
  1671. break;
  1672. case MD_SERVER_STATE_PAUSED:
  1673. m_nISMState = INetServicePaused;
  1674. break;
  1675. case MD_SERVER_STATE_CONTINUING:
  1676. default:
  1677. m_nISMState = INetServiceUnknown;
  1678. break;
  1679. }
  1680. }
  1681. /* virtual */
  1682. void
  1683. CInstanceProps::ParseFields()
  1684. /*++
  1685. Routine Description:
  1686. Break into fields.
  1687. Arguments:
  1688. None.
  1689. Return Value:
  1690. None.
  1691. --*/
  1692. {
  1693. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  1694. HANDLE_META_RECORD(MD_SERVER_BINDINGS, m_strlBindings)
  1695. HANDLE_META_RECORD(MD_SERVER_COMMENT, m_strComment)
  1696. HANDLE_META_RECORD(MD_SERVER_STATE, m_dwState)
  1697. HANDLE_META_RECORD(MD_WIN32_ERROR, m_dwWin32Error);
  1698. HANDLE_META_RECORD(MD_NOT_DELETABLE, m_fNotDeletable);
  1699. HANDLE_META_RECORD(MD_CLUSTER_ENABLED, m_fCluster);
  1700. END_PARSE_META_RECORDS
  1701. //
  1702. // Crack the primary binding
  1703. //
  1704. if (MP_V(m_strlBindings).GetCount() > 0)
  1705. {
  1706. CString & strBinding = MP_V(m_strlBindings).GetHead();
  1707. CrackBinding(strBinding, m_iaIpAddress, m_nTCPPort, m_strDomainName);
  1708. }
  1709. SetISMStateFromServerState();
  1710. }
  1711. /* virtual */
  1712. HRESULT
  1713. CInstanceProps::WriteDirtyProps()
  1714. /*++
  1715. Routine Description:
  1716. Write the dirty properties to the metabase
  1717. Arguments:
  1718. None
  1719. Return Value:
  1720. HRESULT
  1721. --*/
  1722. {
  1723. CError err;
  1724. BEGIN_META_WRITE()
  1725. META_WRITE(MD_SERVER_BINDINGS, m_strlBindings)
  1726. META_WRITE(MD_SERVER_COMMENT, m_strComment)
  1727. META_WRITE(MD_SERVER_STATE, m_dwState)
  1728. END_META_WRITE(err);
  1729. return err;
  1730. }
  1731. HRESULT
  1732. CInstanceProps::ChangeState(
  1733. IN int nNewState
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Change the state of the instance
  1738. Arguments:
  1739. int nNewState : ISM service state value
  1740. Return Value:
  1741. HRESULT
  1742. --*/
  1743. {
  1744. DWORD dwTargetState;
  1745. DWORD dwPendingState;
  1746. DWORD dwCommand;
  1747. CError err;
  1748. switch(nNewState)
  1749. {
  1750. case INetServiceStopped:
  1751. dwTargetState = MD_SERVER_STATE_STOPPED;
  1752. dwPendingState = MD_SERVER_STATE_STOPPING;
  1753. dwCommand = MD_SERVER_COMMAND_STOP;
  1754. break;
  1755. case INetServiceRunning:
  1756. dwTargetState = MD_SERVER_STATE_STARTED;
  1757. if (m_nISMState == INetServicePaused)
  1758. {
  1759. dwPendingState = MD_SERVER_STATE_CONTINUING;
  1760. dwCommand = MD_SERVER_COMMAND_CONTINUE;
  1761. }
  1762. else
  1763. {
  1764. dwPendingState = MD_SERVER_STATE_STARTING;
  1765. dwCommand = MD_SERVER_COMMAND_START;
  1766. }
  1767. break;
  1768. case INetServicePaused:
  1769. dwTargetState = MD_SERVER_STATE_PAUSED;
  1770. dwPendingState = MD_SERVER_STATE_PAUSING;
  1771. dwCommand = MD_SERVER_COMMAND_PAUSE;
  1772. break;
  1773. default:
  1774. ASSERT(FALSE && "Invalid service state requested");
  1775. err = ERROR_INVALID_PARAMETER;
  1776. }
  1777. err = OpenForWriting(FALSE);
  1778. if (err.Succeeded())
  1779. {
  1780. err = SetValue(MD_SERVER_COMMAND, dwCommand);
  1781. Close();
  1782. }
  1783. if (err.Succeeded())
  1784. {
  1785. //
  1786. // Wait for the service to attain desired state, timeout
  1787. // after specified interval
  1788. //
  1789. DWORD dwSleepTotal = 0L;
  1790. DWORD dwOldState = m_dwState;
  1791. if (dwOldState == dwTargetState)
  1792. {
  1793. //
  1794. // Current state matches desired
  1795. // state already. ISM must be behind
  1796. // the times.
  1797. //
  1798. return err;
  1799. }
  1800. //
  1801. // CODEWORK: Write a 0 win32error to the instance properties
  1802. // prior to attempting to start the instance.
  1803. //
  1804. m_dwWin32Error = 0;
  1805. while (dwSleepTotal < MAX_SLEEP_INST)
  1806. {
  1807. err = LoadData();
  1808. if (err.Failed())
  1809. {
  1810. break;
  1811. }
  1812. if ((m_dwState != dwPendingState && m_dwState != dwOldState)
  1813. || m_dwWin32Error != ERROR_SUCCESS
  1814. )
  1815. {
  1816. //
  1817. // Done one way or another
  1818. //
  1819. if (m_dwState != dwTargetState)
  1820. {
  1821. //
  1822. // Did not achieve desired result. Something went
  1823. // wrong.
  1824. //
  1825. if (m_dwWin32Error)
  1826. {
  1827. err = m_dwWin32Error;
  1828. }
  1829. }
  1830. break;
  1831. }
  1832. //
  1833. // Still pending...
  1834. //
  1835. ::Sleep(SLEEP_INTERVAL);
  1836. dwSleepTotal += SLEEP_INTERVAL;
  1837. }
  1838. if (dwSleepTotal >= MAX_SLEEP_INST)
  1839. {
  1840. //
  1841. // Timed out. If there is a real error in the metabase
  1842. // use it, otherwise use a generic timeout error
  1843. //
  1844. err = m_dwWin32Error;
  1845. if (err.Succeeded())
  1846. {
  1847. err = ERROR_SERVICE_REQUEST_TIMEOUT;
  1848. }
  1849. }
  1850. //
  1851. // Update state information
  1852. //
  1853. SetISMStateFromServerState();
  1854. }
  1855. return err;
  1856. }
  1857. /* static */
  1858. HRESULT
  1859. CInstanceProps::Add(
  1860. IN const CMetaInterface * pInterface,
  1861. IN LPCTSTR lpszService,
  1862. IN LPCTSTR lpszHomePath,
  1863. IN LPCTSTR lpszUserName, OPTIONAL
  1864. IN LPCTSTR lpszPassword, OPTIONAL
  1865. IN LPCTSTR lpszDescription, OPTIONAL
  1866. IN LPCTSTR lpszBinding, OPTIONAL
  1867. IN LPCTSTR lpszSecureBinding, OPTIONAL
  1868. IN DWORD * pdwPermissions, OPTIONAL
  1869. IN DWORD * pdwDirBrowsing, OPTIONAL
  1870. IN DWORD * pwdAuthFlags, OPTIONAL
  1871. OUT DWORD * pdwInstance OPTIONAL
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. Create a new instance. Find a free instance number, and attempt
  1876. to create it. Optionally return the new instance number.
  1877. Arguments:
  1878. const CMetaInterface * pInterface : Existing interface
  1879. LPCTSTR lpszService : Service name
  1880. LPCTSTR lpszHomePath : physical path for the new home directory
  1881. LPCTSTR lpszUserName : User name
  1882. LPCTSTR lpszPassword : Password
  1883. LPCTSTR lpszDescription : Optional instance description.
  1884. LPCTSTR lpszBinding : Binding string
  1885. LPCTSTR lpszSecureBinding : Secure binding string
  1886. DWORD * pdwPermission : Permission bits
  1887. DWORD * pdwDirBrowsing : Directory browsing
  1888. DWORD * pwdAuthFlags : Authorization flags
  1889. DWORD * pdwInstance : Buffer to the new instance number
  1890. Return Value:
  1891. HRESULT
  1892. --*/
  1893. {
  1894. CMetaKey mk(pInterface, METADATA_PERMISSION_WRITE, lpszService);
  1895. CError err(mk.QueryResult());
  1896. if (err.Failed())
  1897. {
  1898. //
  1899. // The service key MUST exist!
  1900. //
  1901. ASSERT(err.Win32Error() != ERROR_PATH_NOT_FOUND);
  1902. return err;
  1903. }
  1904. //
  1905. // Loop through until we find a free instance number. This
  1906. // is not ideal, but the only way to do this for now.
  1907. //
  1908. CString strPath;
  1909. LPTSTR lp = strPath.GetBuffer(MAX_INSTANCE_LEN);
  1910. for (DWORD dw = FIRST_INSTANCE; dw <= LAST_INSTANCE; ++dw)
  1911. {
  1912. ::_ultot(dw, lp, 10);
  1913. err = mk.DoesPathExist(lp);
  1914. if (err.Failed())
  1915. {
  1916. if (err.Win32Error() != ERROR_PATH_NOT_FOUND)
  1917. {
  1918. //
  1919. // Unexpected error
  1920. //
  1921. return err;
  1922. }
  1923. //
  1924. // Ok, now create it
  1925. //
  1926. strPath.ReleaseBuffer();
  1927. err = mk.AddKey(strPath);
  1928. if (err.Succeeded())
  1929. {
  1930. if (pdwInstance)
  1931. {
  1932. //
  1933. // Store instance number
  1934. //
  1935. *pdwInstance = dw;
  1936. }
  1937. //
  1938. // Write the key name (hack for beta 2)
  1939. //
  1940. CString strKeyName;
  1941. CString strKeyDirName;
  1942. if (!::lstrcmpi(lpszService, _T("w3svc")))
  1943. {
  1944. strKeyName = _T("IIsWebServer");
  1945. strKeyDirName = _T("IIsWebVirtualDir");
  1946. }
  1947. else if (!::lstrcmpi(lpszService, _T("msftpsvc")))
  1948. {
  1949. strKeyName = _T("IIsFtpServer");
  1950. strKeyDirName = _T("IIsFtpVirtualDir");
  1951. }
  1952. else
  1953. {
  1954. ASSERT(FALSE && "unrecognize service name");
  1955. }
  1956. err = mk.SetValue(
  1957. MD_KEY_TYPE,
  1958. strKeyName,
  1959. NULL,
  1960. strPath
  1961. );
  1962. //
  1963. // Optionally write the description field
  1964. //
  1965. if (lpszDescription)
  1966. {
  1967. CString strDescription(lpszDescription);
  1968. err = mk.SetValue(
  1969. MD_SERVER_COMMENT,
  1970. strDescription,
  1971. NULL,
  1972. strPath
  1973. );
  1974. }
  1975. //
  1976. // The service binding
  1977. //
  1978. if (lpszBinding)
  1979. {
  1980. CString strBinding(lpszBinding);
  1981. CStringListEx strlBindings;
  1982. strlBindings.AddTail(strBinding);
  1983. err = mk.SetValue(
  1984. MD_SERVER_BINDINGS,
  1985. strlBindings,
  1986. NULL,
  1987. strPath
  1988. );
  1989. }
  1990. //
  1991. // The secure binding
  1992. //
  1993. if (lpszSecureBinding)
  1994. {
  1995. CString strBinding(lpszSecureBinding);
  1996. CStringListEx strlBindings;
  1997. strlBindings.AddTail(strBinding);
  1998. err = mk.SetValue(
  1999. MD_SECURE_BINDINGS,
  2000. strlBindings,
  2001. NULL,
  2002. strPath
  2003. );
  2004. }
  2005. strPath += g_cszSep;
  2006. strPath += g_cszRoot;
  2007. //
  2008. // Now add the home directory for it
  2009. //
  2010. err = mk.AddKey(strPath);
  2011. if(err.Succeeded())
  2012. {
  2013. CString strHomePath(lpszHomePath);
  2014. err = mk.SetValue(MD_VR_PATH, strHomePath, NULL, strPath);
  2015. err = mk.SetValue(MD_KEY_TYPE, strKeyDirName, NULL, strPath);
  2016. if (pwdAuthFlags)
  2017. {
  2018. err = mk.SetValue(
  2019. MD_AUTHORIZATION,
  2020. *pwdAuthFlags,
  2021. NULL,
  2022. strPath
  2023. );
  2024. }
  2025. if (lpszUserName != NULL)
  2026. {
  2027. ASSERT(lpszPassword != NULL);
  2028. CString strUserName(lpszUserName);
  2029. err = mk.SetValue(
  2030. MD_VR_USERNAME,
  2031. strUserName,
  2032. NULL,
  2033. strPath
  2034. );
  2035. }
  2036. if (lpszPassword != NULL)
  2037. {
  2038. ASSERT(lpszUserName != NULL);
  2039. CString strPassword(lpszPassword);
  2040. err = mk.SetValue(
  2041. MD_VR_PASSWORD,
  2042. strPassword,
  2043. NULL,
  2044. strPath
  2045. );
  2046. }
  2047. if (pdwPermissions != NULL)
  2048. {
  2049. err = mk.SetValue(
  2050. MD_ACCESS_PERM,
  2051. *pdwPermissions,
  2052. NULL,
  2053. strPath
  2054. );
  2055. }
  2056. if (pdwDirBrowsing != NULL)
  2057. {
  2058. //
  2059. // WWW only
  2060. //
  2061. err = mk.SetValue(
  2062. MD_DIRECTORY_BROWSING,
  2063. *pdwDirBrowsing,
  2064. NULL,
  2065. strPath
  2066. );
  2067. }
  2068. }
  2069. }
  2070. return err;
  2071. }
  2072. }
  2073. //
  2074. // 4 billion instances???!!!!! This error message
  2075. // may not be ideal, but it will have to do for now.
  2076. //
  2077. return CError::HResult(ERROR_SHARING_BUFFER_EXCEEDED);
  2078. }
  2079. /* static */
  2080. HRESULT
  2081. CInstanceProps::Delete(
  2082. IN const CMetaInterface * pInterface,
  2083. IN LPCTSTR lpszService,
  2084. IN DWORD dwInstance
  2085. )
  2086. /*++
  2087. Routine Description:
  2088. Delete the given instance number
  2089. Arguments:
  2090. LPCTSTR lpszServer : Server name
  2091. LPCTSTR lpszService : Service name (e.g. W3SVC)
  2092. DWORD dwInstance : Instance number to be deleted
  2093. Return Value:
  2094. HRESULT
  2095. --*/
  2096. {
  2097. CMetaKey mk(pInterface, METADATA_PERMISSION_WRITE, lpszService);
  2098. CError err(mk.QueryResult());
  2099. if (err.Failed())
  2100. {
  2101. return err;
  2102. }
  2103. CString strPath;
  2104. LPTSTR lp = strPath.GetBuffer(MAX_INSTANCE_LEN);
  2105. ::_ltot(dwInstance, lp, 10);
  2106. strPath.ReleaseBuffer();
  2107. err = mk.DeleteKey(strPath);
  2108. return err;
  2109. }
  2110. //
  2111. // Child node properties
  2112. //
  2113. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  2114. //
  2115. // Redirect tags
  2116. //
  2117. const TCHAR CChildNodeProps::s_chTagSep = _T(',');
  2118. const LPCTSTR CChildNodeProps::s_cszExactDestination = _T("EXACT_DESTINATION");
  2119. const LPCTSTR CChildNodeProps::s_cszChildOnly = _T("CHILD_ONLY");
  2120. const LPCTSTR CChildNodeProps::s_cszPermanent = _T("PERMANENT");
  2121. CChildNodeProps::CChildNodeProps(
  2122. IN LPCTSTR lpszServerName,
  2123. IN LPCTSTR lpszService, OPTIONAL
  2124. IN DWORD dwInstance, OPTIONAL
  2125. IN LPCTSTR lpszParent, OPTIONAL
  2126. IN LPCTSTR lpszAlias, OPTIONAL
  2127. IN BOOL fInherit, OPTIONAL
  2128. IN BOOL fPathOnly OPTIONAL
  2129. )
  2130. /*++
  2131. Routine Description:
  2132. Child node properties (Can be file, dir, or vdir)
  2133. Arguments:
  2134. LPCTSTR lpszServerName : Server name
  2135. LPCTSTR lpszService : Service name
  2136. DWORD dwInstance : Instance number (or MASTER INSTANCE)
  2137. LPCTSTR lpszParent : Parent path (can be NULL or blank)
  2138. LPCTSTR lpszAlias : Alias name (can be NULL or blank)
  2139. BOOL fInherit : TRUE to inherit values, FALSE otherwise
  2140. BOOL fPathOnly : TRUE to only fetch the path
  2141. Return Value:
  2142. N/A
  2143. --*/
  2144. : CMetaProperties(
  2145. lpszServerName,
  2146. lpszService,
  2147. dwInstance,
  2148. lpszParent,
  2149. lpszAlias
  2150. ),
  2151. m_strAlias(lpszAlias),
  2152. m_strRedirectStatement(),
  2153. m_strRedirectPath(),
  2154. m_fExact(FALSE),
  2155. m_fChild(FALSE),
  2156. m_fPermanent(FALSE),
  2157. m_dwAccessPerms(0L),
  2158. m_dwDirBrowsing(0L),
  2159. m_dwWin32Error(ERROR_SUCCESS),
  2160. m_fIsAppRoot(FALSE),
  2161. m_fAppIsolated(FALSE),
  2162. //
  2163. // Default properties
  2164. //
  2165. m_fPathInherited(FALSE),
  2166. m_strPath()
  2167. {
  2168. if (fPathOnly)
  2169. {
  2170. //
  2171. // Fetch only the homeroot physical path
  2172. //
  2173. m_dwMDUserType = IIS_MD_UT_FILE;
  2174. m_dwMDDataType = STRING_METADATA;
  2175. }
  2176. m_strFullMetaPath = m_strMetaRoot;
  2177. //
  2178. // Override base parameters
  2179. //
  2180. m_fInherit = fInherit;
  2181. }
  2182. CChildNodeProps::CChildNodeProps(
  2183. IN const CMetaInterface * pInterface,
  2184. IN LPCTSTR lpszService, OPTIONAL
  2185. IN DWORD dwInstance, OPTIONAL
  2186. IN LPCTSTR lpszParent, OPTIONAL
  2187. IN LPCTSTR lpszAlias, OPTIONAL
  2188. IN BOOL fInherit, OPTIONAL
  2189. IN BOOL fPathOnly OPTIONAL
  2190. )
  2191. /*++
  2192. Routine Description:
  2193. Child node properties (Can be file, dir, or vdir)
  2194. Arguments:
  2195. CMetaInterface * pInterface : Existing interface
  2196. LPCTSTR lpszService : Service name
  2197. DWORD dwInstance : Instance number (or MASTER INSTANCE)
  2198. LPCTSTR lpszParent : Parent path (can be NULL or blank)
  2199. LPCTSTR lpszAlias : Alias name (can be NULL or blank)
  2200. BOOL fInherit : TRUE to inherit values, FALSE otherwise
  2201. BOOL fPathOnly : TRUE to only fetch the path
  2202. Return Value:
  2203. N/A
  2204. --*/
  2205. : CMetaProperties(
  2206. pInterface,
  2207. lpszService,
  2208. dwInstance,
  2209. lpszParent,
  2210. lpszAlias
  2211. ),
  2212. m_strAlias(lpszAlias),
  2213. m_strRedirectStatement(),
  2214. m_strRedirectPath(),
  2215. m_fExact(FALSE),
  2216. m_fChild(FALSE),
  2217. m_fPermanent(FALSE),
  2218. m_dwAccessPerms(0L),
  2219. m_dwDirBrowsing(0L),
  2220. m_dwWin32Error(ERROR_SUCCESS),
  2221. m_fIsAppRoot(FALSE),
  2222. m_fAppIsolated(FALSE),
  2223. //
  2224. // Default properties
  2225. //
  2226. m_fPathInherited(FALSE),
  2227. m_strPath()
  2228. {
  2229. if (fPathOnly)
  2230. {
  2231. //
  2232. // Fetch only the homeroot physical path
  2233. //
  2234. m_dwMDUserType = IIS_MD_UT_FILE;
  2235. m_dwMDDataType = STRING_METADATA;
  2236. }
  2237. m_strFullMetaPath = m_strMetaRoot;
  2238. //
  2239. // Override base parameters
  2240. //
  2241. m_fInherit = fInherit;
  2242. }
  2243. CChildNodeProps::CChildNodeProps(
  2244. IN const CMetaKey * pKey,
  2245. IN LPCTSTR lpszPath, OPTIONAL
  2246. IN BOOL fInherit, OPTIONAL
  2247. IN BOOL fPathOnly OPTIONAL
  2248. )
  2249. /*++
  2250. Routine Description:
  2251. Construct from open key
  2252. Arguments:
  2253. const CMetaKey * pKey Open key
  2254. LPCTSTR lpszPath Path
  2255. BOOL fInherit TRUE to inherit properties
  2256. BOOL fPathOnly TRUE to only fetch the path
  2257. Return Value:
  2258. N/A
  2259. --*/
  2260. : CMetaProperties(pKey, lpszPath),
  2261. m_strAlias(lpszPath), // ISSUE: Could be more than a node name
  2262. m_strRedirectStatement(),
  2263. m_strRedirectPath(),
  2264. m_fExact(FALSE),
  2265. m_fChild(FALSE),
  2266. m_fPermanent(FALSE),
  2267. m_dwAccessPerms(0L),
  2268. m_dwDirBrowsing(0L),
  2269. m_dwWin32Error(ERROR_SUCCESS),
  2270. m_fIsAppRoot(FALSE),
  2271. m_fAppIsolated(FALSE),
  2272. //
  2273. // Default properties
  2274. //
  2275. m_fPathInherited(FALSE),
  2276. m_strPath()
  2277. {
  2278. if (fPathOnly)
  2279. {
  2280. m_dwMDUserType = IIS_MD_UT_FILE;
  2281. m_dwMDDataType = STRING_METADATA;
  2282. }
  2283. else
  2284. {
  2285. //
  2286. // Build full metabase path, because we need to compare it
  2287. // against the app root path
  2288. //
  2289. m_strFullMetaPath = pKey->QueryMetaPath();
  2290. if (lpszPath && *lpszPath)
  2291. {
  2292. m_strFullMetaPath += SZ_MBN_SEP_STR;
  2293. m_strFullMetaPath += lpszPath;
  2294. }
  2295. }
  2296. //
  2297. // Override base parameters
  2298. //
  2299. m_fInherit = fInherit;
  2300. }
  2301. void
  2302. CChildNodeProps::ParseRedirectStatement()
  2303. /*++
  2304. Routine Description:
  2305. Break down the redirect statement into its component parts (path
  2306. plus directives)
  2307. Arguments:
  2308. None
  2309. Return Value:
  2310. None
  2311. --*/
  2312. {
  2313. m_fExact = FALSE;
  2314. m_fChild = FALSE;
  2315. m_fPermanent = FALSE;
  2316. m_strRedirectPath = m_strRedirectStatement;
  2317. int nComma = m_strRedirectPath.Find(s_chTagSep);
  2318. if (nComma >= 0)
  2319. {
  2320. //
  2321. // Check past the separator for these tags
  2322. //
  2323. LPCTSTR lpstr = m_strRedirectPath;
  2324. lpstr += (nComma + 1);
  2325. m_fExact = _tcsstr(lpstr, s_cszExactDestination) != NULL;
  2326. m_fChild = _tcsstr(lpstr, s_cszChildOnly) != NULL;
  2327. m_fPermanent = _tcsstr(lpstr, s_cszPermanent) != NULL;
  2328. m_strRedirectPath.ReleaseBuffer(nComma);
  2329. }
  2330. }
  2331. void
  2332. CChildNodeProps::BuildRedirectStatement()
  2333. /*++
  2334. Routine Description:
  2335. Assemble the redirect statement from its component parts (path
  2336. plus directives)
  2337. Arguments:
  2338. None
  2339. Return Value:
  2340. None
  2341. --*/
  2342. {
  2343. CString strStatement = m_strRedirectPath;
  2344. ASSERT(strStatement.Find(s_chTagSep) < 0);
  2345. if (m_fExact)
  2346. {
  2347. strStatement += s_chTagSep;
  2348. strStatement += _T(' ');
  2349. strStatement += s_cszExactDestination;
  2350. }
  2351. if (m_fChild)
  2352. {
  2353. strStatement += s_chTagSep;
  2354. strStatement += _T(' ');
  2355. strStatement += s_cszChildOnly;
  2356. }
  2357. if (m_fPermanent)
  2358. {
  2359. strStatement += s_chTagSep;
  2360. strStatement += _T(' ');
  2361. strStatement += s_cszPermanent;
  2362. }
  2363. m_strRedirectStatement = strStatement;
  2364. }
  2365. /* virtual */
  2366. void
  2367. CChildNodeProps::ParseFields()
  2368. /*++
  2369. Routine Description:
  2370. Break into fields.
  2371. Arguments:
  2372. None.
  2373. Return Value:
  2374. None.
  2375. --*/
  2376. {
  2377. BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
  2378. HANDLE_INHERITED_META_RECORD(MD_VR_PATH, m_strPath, m_fPathInherited)
  2379. HANDLE_META_RECORD(MD_HTTP_REDIRECT, m_strRedirectStatement)
  2380. HANDLE_META_RECORD(MD_WIN32_ERROR, m_dwWin32Error)
  2381. HANDLE_META_RECORD(MD_ACCESS_PERM, m_dwAccessPerms)
  2382. HANDLE_META_RECORD(MD_DIRECTORY_BROWSING, m_dwDirBrowsing)
  2383. HANDLE_META_RECORD(MD_APP_ROOT, m_strAppRoot)
  2384. HANDLE_META_RECORD(MD_APP_ISOLATED, m_fAppIsolated)
  2385. END_PARSE_META_RECORDS
  2386. //
  2387. // Check to see if this is an application root
  2388. //
  2389. if (!MP_V(m_strAppRoot).IsEmpty())
  2390. {
  2391. TRACEEOLID("App root: " << m_strAppRoot);
  2392. //
  2393. // CODEWORK: It's faster to set our app root to the path
  2394. // that WAM expects than to strip off each instance.
  2395. //
  2396. //
  2397. // Clean App root
  2398. //
  2399. if (MP_V(m_strAppRoot)[MP_V(m_strAppRoot).GetLength() - 1] == _T('/'))
  2400. {
  2401. MP_V(m_strAppRoot).ReleaseBuffer(
  2402. MP_V(m_strAppRoot).GetLength() - 1
  2403. );
  2404. }
  2405. if (MP_V(m_strAppRoot)[0] == _T('/'))
  2406. {
  2407. MP_V(m_strAppRoot) = MP_V(m_strAppRoot).Right(
  2408. MP_V(m_strAppRoot).GetLength() - 1
  2409. );
  2410. }
  2411. m_fIsAppRoot = m_strFullMetaPath.CompareNoCase(m_strAppRoot) == 0;
  2412. }
  2413. //
  2414. // Break down redirect statement into component parts
  2415. //
  2416. ParseRedirectStatement();
  2417. }
  2418. /* virtual */
  2419. HRESULT
  2420. CChildNodeProps::WriteDirtyProps()
  2421. /*++
  2422. Routine Description:
  2423. Write the dirty properties to the metabase
  2424. Arguments:
  2425. None
  2426. Return Value:
  2427. HRESULT
  2428. --*/
  2429. {
  2430. CError err;
  2431. BEGIN_META_WRITE()
  2432. META_WRITE(MD_VR_PATH, m_strPath)
  2433. META_WRITE(MD_ACCESS_PERM, m_dwAccessPerms)
  2434. META_WRITE(MD_DIRECTORY_BROWSING, m_dwDirBrowsing)
  2435. if (IsRedirected())
  2436. {
  2437. //
  2438. // (Re-)Assemble the redirect statement from its component parts
  2439. //
  2440. BuildRedirectStatement();
  2441. META_WRITE_INHERITANCE(MD_HTTP_REDIRECT, m_strRedirectStatement, m_fInheritRedirect)
  2442. }
  2443. else
  2444. {
  2445. META_DELETE(MD_HTTP_REDIRECT)
  2446. }
  2447. END_META_WRITE(err);
  2448. return err;
  2449. }
  2450. /* static */
  2451. HRESULT
  2452. CChildNodeProps::Add(
  2453. IN const CMetaInterface * pInterface,
  2454. IN LPCTSTR lpszService,
  2455. IN DWORD dwInstance, OPTIONAL
  2456. IN LPCTSTR lpszParentPath, OPTIONAL
  2457. IN LPCTSTR lpszAlias,
  2458. OUT CString & strAliasCreated,
  2459. IN DWORD * pdwPermissions, OPTIONAL
  2460. IN DWORD * pdwDirBrowsing, OPTIONAL
  2461. IN LPCTSTR lpszVrPath, OPTIONAL
  2462. IN LPCTSTR lpszUserName, OPTIONAL
  2463. IN LPCTSTR lpszPassword, OPTIONAL
  2464. IN BOOL fExactName
  2465. )
  2466. /*++
  2467. Routine Description:
  2468. Create new child node. Optionally, this will append a number
  2469. to the alias name to ensure uniqueness
  2470. Arguments:
  2471. const CMetaInterface * pInterface : Existing interface
  2472. LPCTSTR lpszService : Service name
  2473. DWORD dwInstance : Instance number (could be MASTER_INSTANCE)
  2474. LPCTSTR lpszParentPath : Parent path (could be NULL)
  2475. LPCTSTR lpszAlias : Desired alias name
  2476. CString & strAliasCreated : Alias created (may differ)
  2477. DWORD * pdwPermissions : Permissions
  2478. DWORD * pdwDirBrowsing : Directory browsing
  2479. LPCTSTR lpszVrPath : VrPath property
  2480. LPCTSTR lpszUserName : User name
  2481. LPCTSTR lpszPassword : Password
  2482. BOOL fExactName : If TRUE, do not change the name
  2483. to enforce uniqueness.
  2484. Return Value:
  2485. HRESULT
  2486. --*/
  2487. {
  2488. CMetaKey mk(pInterface);
  2489. CError err(mk.QueryResult());
  2490. if (err.Failed())
  2491. {
  2492. //
  2493. // Hopeless...
  2494. //
  2495. return err;
  2496. }
  2497. BOOL fNewPath;
  2498. do
  2499. {
  2500. fNewPath = FALSE;
  2501. err = mk.Open(
  2502. METADATA_PERMISSION_WRITE,
  2503. lpszService,
  2504. dwInstance,
  2505. lpszParentPath
  2506. );
  2507. if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
  2508. {
  2509. //
  2510. // This could happen -- creating a virtual
  2511. // server underneath a physical directory
  2512. // which does not exist in the metabase
  2513. //
  2514. err = mk.Open(
  2515. METADATA_PERMISSION_WRITE,
  2516. lpszService,
  2517. dwInstance
  2518. );
  2519. if (err.Failed())
  2520. {
  2521. //
  2522. // This really should never fail, because we're opening
  2523. // the path at the instance.
  2524. //
  2525. TRACEEOLID("Instance path does not exist");
  2526. ASSERT(FALSE);
  2527. break;
  2528. }
  2529. err = mk.AddKey(lpszParentPath);
  2530. fNewPath = err.Succeeded();
  2531. mk.Close();
  2532. }
  2533. }
  2534. while(fNewPath);
  2535. if (err.Failed())
  2536. {
  2537. return err;
  2538. }
  2539. strAliasCreated = lpszAlias;
  2540. DWORD dw = 2;
  2541. FOREVER
  2542. {
  2543. //
  2544. // Append a number if the name is not unique.
  2545. //
  2546. err = mk.DoesPathExist(strAliasCreated);
  2547. if (err.Failed())
  2548. {
  2549. if (err.Win32Error() != ERROR_PATH_NOT_FOUND)
  2550. {
  2551. //
  2552. // Unexpected error
  2553. //
  2554. return err;
  2555. }
  2556. //
  2557. // Ok, now create it
  2558. //
  2559. err = mk.AddKey(strAliasCreated);
  2560. if (err.Succeeded())
  2561. {
  2562. //
  2563. // Write the ADSI key name (hack for beta 2)
  2564. //
  2565. CString strKeyName;
  2566. if (!::lstrcmpi(lpszService, _T("w3svc")))
  2567. {
  2568. strKeyName = _T("IIsWebVirtualDir");
  2569. }
  2570. else if (!::lstrcmpi(lpszService, _T("msftpsvc")))
  2571. {
  2572. strKeyName = _T("IIsFtpVirtualDir");
  2573. }
  2574. else
  2575. {
  2576. ASSERT(FALSE && "unrecognize service name");
  2577. }
  2578. err = mk.SetValue(
  2579. MD_KEY_TYPE,
  2580. strKeyName,
  2581. NULL,
  2582. strAliasCreated
  2583. );
  2584. if (lpszVrPath != NULL)
  2585. {
  2586. CString strVrPath(lpszVrPath);
  2587. err = mk.SetValue(
  2588. MD_VR_PATH,
  2589. strVrPath,
  2590. NULL,
  2591. strAliasCreated
  2592. );
  2593. }
  2594. if (lpszUserName != NULL)
  2595. {
  2596. ASSERT(lpszPassword != NULL);
  2597. CString strUserName(lpszUserName);
  2598. err = mk.SetValue(
  2599. MD_VR_USERNAME,
  2600. strUserName,
  2601. NULL,
  2602. strAliasCreated
  2603. );
  2604. }
  2605. if (lpszPassword != NULL)
  2606. {
  2607. ASSERT(lpszUserName != NULL);
  2608. CString strPassword(lpszPassword);
  2609. err = mk.SetValue(
  2610. MD_VR_PASSWORD,
  2611. strPassword,
  2612. NULL,
  2613. strAliasCreated
  2614. );
  2615. }
  2616. if (pdwPermissions != NULL)
  2617. {
  2618. err = mk.SetValue(
  2619. MD_ACCESS_PERM,
  2620. *pdwPermissions,
  2621. NULL,
  2622. strAliasCreated
  2623. );
  2624. }
  2625. if (pdwDirBrowsing != NULL)
  2626. {
  2627. //
  2628. // WWW only
  2629. //
  2630. err = mk.SetValue(
  2631. MD_DIRECTORY_BROWSING,
  2632. *pdwDirBrowsing,
  2633. NULL,
  2634. strAliasCreated
  2635. );
  2636. }
  2637. }
  2638. return err;
  2639. }
  2640. //
  2641. // Name is not unique, increase the number and try
  2642. // again if permitted to so. Otherwise return the
  2643. // 'path exists' error.
  2644. //
  2645. if (fExactName)
  2646. {
  2647. err = ERROR_ALREADY_EXISTS;
  2648. return err;
  2649. }
  2650. TCHAR szNumber[32];
  2651. ::_ultot(dw++, szNumber, 10);
  2652. strAliasCreated = lpszAlias;
  2653. strAliasCreated += szNumber;
  2654. //
  2655. // Continue on...
  2656. //
  2657. }
  2658. }
  2659. /* static */
  2660. HRESULT
  2661. CChildNodeProps::Delete(
  2662. IN const CMetaInterface * pInterface,
  2663. IN LPCTSTR lpszService,
  2664. IN DWORD dwInstance, OPTIONAL
  2665. IN LPCTSTR lpszParentPath, OPTIONAL
  2666. IN LPCTSTR lpszNode
  2667. )
  2668. /*++
  2669. Routine Description:
  2670. Delete child node off the given parent path
  2671. Arguments:
  2672. const CMetaInterface * pInterface, Existing interface
  2673. LPCTSTR lpszService : Service name
  2674. DWORD dwInstance : Instance number (could be MASTER_INSTANCE)
  2675. LPCTSTR lpszParentPath : Parent path (could be NULL)
  2676. LPCTSTR lpszNode : Name of node to be deleted
  2677. Return Value:
  2678. HRESULT
  2679. --*/
  2680. {
  2681. CMetaKey mk(
  2682. pInterface,
  2683. METADATA_PERMISSION_WRITE,
  2684. lpszService,
  2685. dwInstance,
  2686. lpszParentPath
  2687. );
  2688. CError err(mk.QueryResult());
  2689. if (err.Failed())
  2690. {
  2691. return err;
  2692. }
  2693. err = mk.DeleteKey(lpszNode);
  2694. return err;
  2695. }
  2696. /* static */
  2697. HRESULT
  2698. CChildNodeProps::Rename(
  2699. IN const CMetaInterface * pInterface,
  2700. IN LPCTSTR lpszService,
  2701. IN DWORD dwInstance, OPTIONAL
  2702. IN LPCTSTR lpszParentPath, OPTIONAL
  2703. IN LPCTSTR lpszOldName,
  2704. IN LPCTSTR lpszNewName
  2705. )
  2706. /*++
  2707. Routine Description:
  2708. Rename a child node off the given path
  2709. Arguments:
  2710. IN const CMetaInterface * pInterface : Existing interface
  2711. LPCTSTR lpszService : Service name
  2712. DWORD dwInstance : Instance number (could be MASTER_INSTANCE)
  2713. LPCTSTR lpszParentPath : Parent path (could be NULL)
  2714. LPCTSTR lpszOldName : Old node name
  2715. LPCTSTR lpszNewName : New node name
  2716. Return Value:
  2717. HRESULT
  2718. --*/
  2719. {
  2720. CMetaKey mk(
  2721. pInterface,
  2722. METADATA_PERMISSION_WRITE,
  2723. lpszService,
  2724. dwInstance,
  2725. lpszParentPath
  2726. );
  2727. CError err(mk.QueryResult());
  2728. if (err.Failed())
  2729. {
  2730. return err;
  2731. }
  2732. err = mk.RenameKey(lpszOldName, lpszNewName);
  2733. return err;
  2734. }
  2735. //
  2736. // ISM Helpers
  2737. //
  2738. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  2739. HRESULT
  2740. COMDLL_RebindInterface(
  2741. OUT IN CMetaInterface * pInterface,
  2742. OUT BOOL * pfContinue,
  2743. IN DWORD dwCancelError
  2744. )
  2745. /*++
  2746. Routine Description:
  2747. Rebind the interface
  2748. Arguments:
  2749. CMetaInterface * pInterface : Interface to rebind
  2750. BOOL * pfContinue : Returns TRUE to continue.
  2751. DWORD dwCancelError : Return code on cancel
  2752. Return Value:
  2753. HRESULT
  2754. --*/
  2755. {
  2756. CError err;
  2757. CString str, strFmt;
  2758. ASSERT(pInterface != NULL);
  2759. ASSERT(pfContinue != NULL);
  2760. VERIFY(strFmt.LoadString(IDS_RECONNECT_WARNING));
  2761. str.Format(strFmt, (LPCTSTR)pInterface->QueryServerName());
  2762. if (*pfContinue = (YesNoMessageBox(str)))
  2763. {
  2764. //
  2765. // Attempt to rebind the handle
  2766. //
  2767. err = pInterface->Regenerate();
  2768. }
  2769. else
  2770. {
  2771. //
  2772. // Do not return an error in this case.
  2773. //
  2774. err = dwCancelError;
  2775. }
  2776. return err;
  2777. }
  2778. HRESULT
  2779. COMDLL_ISMEnumerateInstances(
  2780. IN CMetaInterface * pInterface,
  2781. OUT ISMINSTANCEINFO * pii,
  2782. OUT IN HANDLE * phEnum,
  2783. IN LPCTSTR lpszService
  2784. )
  2785. /*++
  2786. Routine Description:
  2787. Enumerate Instances. First call with *phEnum == NULL.
  2788. Arguments:
  2789. CMetaInterface * pInterface : Existing interface
  2790. ISMINSTANCEINFO * pii : Buffer
  2791. HANDLE * phEnum : Enumeration handle.
  2792. LPCTSTR lpszService : Service name
  2793. Return Value:
  2794. HRESULT
  2795. --*/
  2796. {
  2797. ASSERT(pii != NULL);
  2798. ASSERT(phEnum != NULL);
  2799. ASSERT(pii->dwSize == ISMINSTANCEINFO_SIZE);
  2800. ASSERT(pInterface != NULL);
  2801. CMetaEnumerator * pme = (CMetaEnumerator *)*phEnum;
  2802. if (pme == NULL)
  2803. {
  2804. //
  2805. // Starting enumeration
  2806. //
  2807. pme = new CMetaEnumerator(pInterface, lpszService);
  2808. }
  2809. if (pme == NULL)
  2810. {
  2811. return CError::HResult(ERROR_NOT_ENOUGH_MEMORY);
  2812. }
  2813. CError err(pme->QueryResult());
  2814. if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
  2815. {
  2816. //
  2817. // Base path didn't exist
  2818. //
  2819. err = ERROR_NO_MORE_ITEMS;
  2820. }
  2821. CString strHome;
  2822. if (err.Succeeded())
  2823. {
  2824. DWORD dwInstance;
  2825. err = pme->Next(dwInstance);
  2826. if (err.Succeeded())
  2827. {
  2828. //
  2829. // Read off the open key
  2830. //
  2831. CInstanceProps inst(pme, dwInstance);
  2832. err = inst.LoadData();
  2833. DWORD dwWin32Error = err;
  2834. if (err.Win32Error() == ERROR_ACCESS_DENIED)
  2835. {
  2836. err.Reset();
  2837. }
  2838. if (err.Succeeded())
  2839. {
  2840. inst.FillInstanceInfo(pii, dwWin32Error);
  2841. inst.GetHomePath(strHome);
  2842. TRACEEOLID(strHome);
  2843. //
  2844. // Get home directory path
  2845. //
  2846. CChildNodeProps home(
  2847. pme,
  2848. strHome,
  2849. WITHOUT_INHERITANCE,
  2850. TRUE // Path only
  2851. );
  2852. err = home.LoadData();
  2853. if (err.Win32Error() == ERROR_ACCESS_DENIED)
  2854. {
  2855. err.Reset();
  2856. }
  2857. if (err.Succeeded())
  2858. {
  2859. home.FillInstanceInfo(pii);
  2860. }
  2861. }
  2862. }
  2863. }
  2864. if (err.Win32Error() == ERROR_NO_MORE_ITEMS
  2865. || err.Win32Error() == RPC_S_SERVER_UNAVAILABLE)
  2866. {
  2867. //
  2868. // Finished the enumerator
  2869. //
  2870. delete pme;
  2871. pme = NULL;
  2872. }
  2873. *phEnum = (HANDLE)pme;
  2874. return err;
  2875. }
  2876. HRESULT
  2877. COMDLL_ISMEnumerateChildren(
  2878. IN CMetaInterface * pInterface,
  2879. OUT ISMCHILDINFO * pii,
  2880. OUT IN HANDLE * phEnum,
  2881. IN LPCTSTR lpszService,
  2882. IN DWORD dwInstance,
  2883. IN LPCTSTR lpszParent
  2884. )
  2885. /*++
  2886. Routine Description:
  2887. Enumerate children. First call with *phEnum == NULL.
  2888. Arguments:
  2889. CMetaInterface * pInterface : Existing interface
  2890. ISMCHILDINFO * pii : Buffer
  2891. HANDLE * phEnum : Enumeration handle.
  2892. LPCTSTR lpszService : Service name
  2893. DWORD dwInstance : Instance number
  2894. LPCTSTR lpszParent : Parent path
  2895. Return Value:
  2896. HRESULT
  2897. --*/
  2898. {
  2899. ASSERT(pii != NULL);
  2900. ASSERT(phEnum != NULL);
  2901. ASSERT(pii->dwSize == ISMCHILDINFO_SIZE);
  2902. ASSERT(pInterface != NULL);
  2903. BOOL fDone = FALSE;
  2904. CMetaEnumerator * pme = (CMetaEnumerator *)*phEnum;
  2905. if (pme == NULL)
  2906. {
  2907. //
  2908. // Starting enumeration
  2909. //
  2910. pme = new CMetaEnumerator(
  2911. pInterface,
  2912. lpszService,
  2913. dwInstance,
  2914. lpszParent
  2915. );
  2916. }
  2917. if (pme == NULL)
  2918. {
  2919. return CError::HResult(ERROR_NOT_ENOUGH_MEMORY);
  2920. }
  2921. CError err(pme->QueryResult());
  2922. if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
  2923. {
  2924. err = ERROR_NO_MORE_ITEMS;
  2925. }
  2926. if (err.Succeeded())
  2927. {
  2928. do
  2929. {
  2930. CString strAlias;
  2931. err = pme->Next(strAlias);
  2932. if (err.Succeeded())
  2933. {
  2934. CChildNodeProps child(pme, strAlias, WITH_INHERITANCE, FALSE);
  2935. err = child.LoadData();
  2936. DWORD dwWin32Error = err.Win32Error();
  2937. if (err.Failed())
  2938. {
  2939. //
  2940. // Filter out the non-fatal errors
  2941. //
  2942. switch(err.Win32Error())
  2943. {
  2944. case ERROR_ACCESS_DENIED:
  2945. case ERROR_FILE_NOT_FOUND:
  2946. case ERROR_PATH_NOT_FOUND:
  2947. err.Reset();
  2948. break;
  2949. default:
  2950. TRACEEOLID("Fatal error occurred " << err);
  2951. }
  2952. }
  2953. if (err.Succeeded())
  2954. {
  2955. //
  2956. // Skip non-virtual directories (that is, those with
  2957. // inherited vrpaths)
  2958. //
  2959. if (!child.IsPathInherited())
  2960. {
  2961. //
  2962. // Fetch error overrides stored error value
  2963. //
  2964. child.FillChildInfo(pii);
  2965. fDone = TRUE;
  2966. }
  2967. }
  2968. }
  2969. }
  2970. while (err.Succeeded() && !fDone);
  2971. }
  2972. if (err.Win32Error() == ERROR_NO_MORE_ITEMS
  2973. || err.Win32Error() == RPC_S_SERVER_UNAVAILABLE)
  2974. {
  2975. //
  2976. // Finished the enumerator
  2977. //
  2978. delete pme;
  2979. pme = NULL;
  2980. }
  2981. *phEnum = (HANDLE)pme;
  2982. return err;
  2983. }
  2984. DWORD
  2985. DetermineIfAdministrator(
  2986. IN CMetaInterface * pInterface,
  2987. IN LPCTSTR lpszService,
  2988. IN DWORD dwInstance,
  2989. OUT BOOL* pfAdministrator
  2990. )
  2991. /*++
  2992. Routine Description:
  2993. Attempt to actually resolve whether or not the current user
  2994. has administrator or merely "operator" access. Until this method
  2995. is called by the derived class, the user is assumed to have
  2996. full administrator access, and may therefore get "access denied"
  2997. errors in inconvenient places.
  2998. The method to determine admin access is rather poor at the moment.
  2999. There's a dummy metabase property that only allows admins to write
  3000. to it, so we try to write to it to see if we're an admin.
  3001. Arguments:
  3002. LPCTSTR lpszService : Service name. e.g. "w3svc"
  3003. DWORD dwInstance : Instance number
  3004. Return Value:
  3005. Error return code. This will also set the m_fHasAdminAccess member
  3006. --*/
  3007. {
  3008. *pfAdministrator = FALSE;
  3009. //
  3010. // Reuse existing interface we have lying around.
  3011. //
  3012. CMetaKey mk(pInterface);
  3013. CError err(mk.QueryResult());
  3014. if (err.Succeeded())
  3015. {
  3016. err = mk.Open(
  3017. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  3018. lpszService,
  3019. dwInstance
  3020. );
  3021. if (err.Succeeded())
  3022. {
  3023. //
  3024. // Write some nonsense
  3025. //
  3026. DWORD dwDummy = 0x1234;
  3027. err = mk.SetValue(MD_ISM_ACCESS_CHECK, dwDummy);
  3028. mk.Close();
  3029. }
  3030. }
  3031. ASSERT(err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED);
  3032. *pfAdministrator = (err.Succeeded());
  3033. #ifdef _DEBUG
  3034. if (*pfAdministrator)
  3035. {
  3036. TRACEEOLID("You are a full admin.");
  3037. }
  3038. else
  3039. {
  3040. TRACEEOLID("You're just a lowly operator at best. Error code is " << err);
  3041. }
  3042. #endif // _DEBUG
  3043. if (err.Win32Error() == ERROR_ACCESS_DENIED)
  3044. {
  3045. //
  3046. // Expected result
  3047. //
  3048. err.Reset();
  3049. }
  3050. return err.Win32Error();
  3051. }
  3052. IMPLEMENT_DYNAMIC(CInetPropertySheet, CPropertySheet)
  3053. CInetPropertySheet::CInetPropertySheet(
  3054. IN UINT nIDCaption,
  3055. IN LPCTSTR lpszServer,
  3056. IN LPCTSTR lpszService, OPTIONAL
  3057. IN DWORD dwInstance, OPTIONAL
  3058. IN LPCTSTR lpszParent, OPTIONAL
  3059. IN LPCTSTR lpszAlias, OPTIONAL
  3060. IN CWnd * pParentWnd, OPTIONAL
  3061. IN LPARAM lParam, OPTIONAL
  3062. IN LONG_PTR handle, OPTIONAL
  3063. IN UINT iSelectPage OPTIONAL
  3064. )
  3065. /*++
  3066. Routine Description:
  3067. IIS Property Sheet constructor
  3068. Arguments:
  3069. UINT nIDCaption : Caption resource string
  3070. LPCTSTR lpszServer : Server name
  3071. LPCTSTR lpszService : Service name
  3072. DWORD dwInstance : Instance number
  3073. LPCTSTR lpszParent : Parent path
  3074. LPCTSTR lpszAlias : Alias name
  3075. CWnd * pParentWnd : Optional parent window
  3076. LPARAM lParam : MMC Console parameter
  3077. LONG_PTR handle : MMC Console handle
  3078. UINT iSelectPage : Initial page to be selected
  3079. Return Value:
  3080. N/A
  3081. --*/
  3082. : CPropertySheet(nIDCaption, pParentWnd, iSelectPage),
  3083. m_cap(lpszServer, lpszService, dwInstance),
  3084. m_strServer(lpszServer),
  3085. m_strService(lpszService),
  3086. m_dwInstance(dwInstance),
  3087. m_strParent(lpszParent),
  3088. m_strAlias(lpszAlias),
  3089. m_bModeless(FALSE),
  3090. m_hConsole(handle),
  3091. m_lParam(lParam),
  3092. m_fHasAdminAccess(TRUE), // assumed by default
  3093. m_refcount(0)
  3094. {
  3095. m_cap.LoadData();
  3096. Initialize();
  3097. }
  3098. CInetPropertySheet::CInetPropertySheet(
  3099. IN LPCTSTR lpszCaption,
  3100. IN LPCTSTR lpszServer,
  3101. IN LPCTSTR lpszService, OPTIONAL
  3102. IN DWORD dwInstance, OPTIONAL
  3103. IN LPCTSTR lpszParent, OPTIONAL
  3104. IN LPCTSTR lpszAlias, OPTIONAL
  3105. IN CWnd * pParentWnd, OPTIONAL
  3106. IN LPARAM lParam, OPTIONAL
  3107. IN LONG_PTR handle, OPTIONAL
  3108. IN UINT iSelectPage OPTIONAL
  3109. )
  3110. /*++
  3111. Routine Description:
  3112. IIS Property Sheet constructor
  3113. Arguments:
  3114. UINT nIDCaption : Caption resource string
  3115. LPCTSTR lpszServer : Server name
  3116. LPCTSTR lpszService : Service name
  3117. DWORD dwInstance : Instance number
  3118. LPCTSTR lpszParent : Parent path
  3119. LPCTSTR lpszAlias : Alias name
  3120. CWnd * pParentWnd : Optional parent window
  3121. LPARAM lParam : MMC Console parameter
  3122. LONG_PTR handle : MMC Console handle
  3123. UINT iSelectPage : Initial page to be selected
  3124. Return Value:
  3125. N/A
  3126. --*/
  3127. : CPropertySheet(lpszCaption, pParentWnd, iSelectPage),
  3128. m_cap(lpszServer, lpszService, dwInstance),
  3129. m_strServer(lpszServer),
  3130. m_strService(lpszService),
  3131. m_dwInstance(dwInstance),
  3132. m_strParent(lpszParent),
  3133. m_strAlias(lpszAlias),
  3134. m_bModeless(FALSE),
  3135. m_hConsole(handle),
  3136. m_lParam(lParam),
  3137. m_fHasAdminAccess(TRUE), // assumed by default
  3138. m_refcount(0)
  3139. {
  3140. m_cap.LoadData();
  3141. Initialize();
  3142. }
  3143. void
  3144. CInetPropertySheet::NotifyMMC()
  3145. /*++
  3146. Routine Description:
  3147. Notify MMC that changes have been made, so that the changes are
  3148. reflected.
  3149. Arguments:
  3150. None
  3151. Return Value:
  3152. None
  3153. --*/
  3154. {
  3155. //
  3156. // Notify MMC to update changes.
  3157. //
  3158. if (m_hConsole != NULL)
  3159. {
  3160. ASSERT(m_lParam != 0L);
  3161. MMCPropertyChangeNotify(m_hConsole, m_lParam);
  3162. }
  3163. }
  3164. CInetPropertySheet::~CInetPropertySheet()
  3165. /*++
  3166. Routine Description:
  3167. IIS Property Sheet destructor
  3168. Arguments:
  3169. N/A
  3170. Return Value:
  3171. N/A
  3172. --*/
  3173. {
  3174. NotifyMMC();
  3175. if (m_hConsole != NULL)
  3176. {
  3177. MMCFreeNotifyHandle(m_hConsole);
  3178. }
  3179. }
  3180. void
  3181. CInetPropertySheet::Initialize()
  3182. /*++
  3183. Routine Description:
  3184. Initialize the sheet information by finding out information about
  3185. the computer being administered.
  3186. Arguments:
  3187. None
  3188. Return Value:
  3189. None
  3190. --*/
  3191. {
  3192. m_fLocal = ::IsServerLocal(m_strServer);
  3193. DWORD dwError = DetermineAdminAccess(m_strService, m_dwInstance);
  3194. ASSERT(dwError == ERROR_SUCCESS);
  3195. }
  3196. void
  3197. CInetPropertySheet::AddRef()
  3198. /*++
  3199. Routine Description:
  3200. Increase the refcount
  3201. Arguments:
  3202. None
  3203. Return Value:
  3204. None
  3205. --*/
  3206. {
  3207. ++m_refcount;
  3208. }
  3209. void
  3210. CInetPropertySheet::Release()
  3211. /*++
  3212. Routine Description:
  3213. Decrease the ref count, and if 0, delete the object
  3214. Arguments:
  3215. None
  3216. Return Value:
  3217. None
  3218. --*/
  3219. {
  3220. if (--m_refcount <= 0)
  3221. {
  3222. delete this;
  3223. }
  3224. }
  3225. void
  3226. CInetPropertySheet::WinHelp(
  3227. IN DWORD dwData,
  3228. IN UINT nCmd
  3229. )
  3230. /*++
  3231. Routine Description:
  3232. WinHelp override. We can't use the base class, because our
  3233. 'sheet' doesn't have a window handle
  3234. Arguments:
  3235. DWORD dwData : Help data
  3236. UINT nCmd : Help command
  3237. Return Value:
  3238. None
  3239. --*/
  3240. {
  3241. if (m_hWnd == NULL)
  3242. {
  3243. //
  3244. // Special case
  3245. //
  3246. CWnd * pWnd = ::AfxGetMainWnd();
  3247. if (pWnd != NULL)
  3248. {
  3249. pWnd->WinHelp(dwData, nCmd);
  3250. }
  3251. return;
  3252. }
  3253. CPropertySheet::WinHelp(dwData, nCmd);
  3254. }
  3255. //
  3256. // Message Map
  3257. //
  3258. BEGIN_MESSAGE_MAP(CInetPropertySheet, CPropertySheet)
  3259. //{{AFX_MSG_MAP(CInetPropertySheet)
  3260. //}}AFX_MSG_MAP
  3261. END_MESSAGE_MAP()
  3262. //
  3263. // CInetPropertyPage property page
  3264. //
  3265. IMPLEMENT_DYNAMIC(CInetPropertyPage, CPropertyPage)
  3266. /* static */
  3267. UINT
  3268. CALLBACK
  3269. CInetPropertyPage::PropSheetPageProc(
  3270. IN HWND hWnd,
  3271. IN UINT uMsg,
  3272. IN LPPROPSHEETPAGE ppsp
  3273. )
  3274. /*++
  3275. Routine Description:
  3276. Property page callback procedure. The page is allocated on the heap,
  3277. and deletes itself when it's destroyed.
  3278. Arguments:
  3279. HWND hWnd,
  3280. UINT uMsg,
  3281. LPPROPSHEETPAGE ppsp
  3282. Return Value:
  3283. Message dependent.
  3284. --*/
  3285. {
  3286. CInetPropertyPage * pThis = (CInetPropertyPage *)ppsp->lParam;
  3287. switch(uMsg)
  3288. {
  3289. case PSPCB_RELEASE:
  3290. if (--(pThis->m_refcount) <= 0)
  3291. {
  3292. //
  3293. // Save callback on the stack, since 'this' will be deleted.
  3294. //
  3295. LPFNPSPCALLBACK pfn = pThis->m_pfnOriginalPropSheetPageProc;
  3296. delete pThis;
  3297. return (pfn)(hWnd, uMsg, ppsp);
  3298. }
  3299. break;
  3300. case PSPCB_CREATE:
  3301. //
  3302. // Don't increase refcount.
  3303. //
  3304. default:
  3305. break;
  3306. }
  3307. return (pThis->m_pfnOriginalPropSheetPageProc)(hWnd, uMsg, ppsp);
  3308. }
  3309. #ifdef _DEBUG
  3310. /* virtual */
  3311. void
  3312. CInetPropertyPage::AssertValid() const
  3313. {
  3314. }
  3315. /* virtual */
  3316. void
  3317. CInetPropertyPage::Dump(CDumpContext& dc) const
  3318. {
  3319. }
  3320. #endif // _DEBUG
  3321. CInetPropertyPage::CInetPropertyPage(
  3322. IN UINT nIDTemplate,
  3323. IN CInetPropertySheet * pSheet,
  3324. IN UINT nIDCaption,
  3325. IN BOOL fEnableEnhancedFonts OPTIONAL
  3326. )
  3327. /*++
  3328. Routine Description:
  3329. IIS Property Page Constructor
  3330. Arguments:
  3331. UINT nIDTemplate : Resource template
  3332. CInetPropertySheet * pSheet : Associated property sheet
  3333. UINT nIDCaption : Caption ID
  3334. BOOL fEnableEnhancedFonts : Enable enhanced fonts
  3335. Return Value:
  3336. N/A
  3337. --*/
  3338. : CPropertyPage(nIDTemplate, nIDCaption),
  3339. m_nHelpContext(nIDTemplate + 0x20000),
  3340. m_fEnableEnhancedFonts(fEnableEnhancedFonts),
  3341. m_refcount(1),
  3342. m_bChanged(FALSE),
  3343. m_pSheet(pSheet)
  3344. {
  3345. //{{AFX_DATA_INIT(CInetPropertyPage)
  3346. //}}AFX_DATA_INIT
  3347. m_pfnOriginalPropSheetPageProc = m_psp.pfnCallback;
  3348. m_psp.lParam = (LPARAM)this;
  3349. m_psp.pfnCallback = CInetPropertyPage::PropSheetPageProc;
  3350. m_psp.dwFlags |= (PSP_HASHELP | PSP_USECALLBACK);
  3351. m_pSheet->AddRef();
  3352. ASSERT(m_pSheet != NULL);
  3353. }
  3354. CInetPropertyPage::~CInetPropertyPage()
  3355. /*++
  3356. Routine Description:
  3357. IIS Property Page Destructor
  3358. Arguments:
  3359. N/A
  3360. Return Value:
  3361. N/A
  3362. --*/
  3363. {
  3364. m_pSheet->Release();
  3365. }
  3366. void
  3367. CInetPropertyPage::DoDataExchange(
  3368. IN CDataExchange * pDX
  3369. )
  3370. /*++
  3371. Routine Description:
  3372. Initialise/Store control data
  3373. Arguments:
  3374. CDataExchange * pDX - DDX/DDV control structure
  3375. Return Value:
  3376. None
  3377. --*/
  3378. {
  3379. CPropertyPage::DoDataExchange(pDX);
  3380. //{{AFX_DATA_MAP(CInetPropertyPage)
  3381. //}}AFX_DATA_MAP
  3382. }
  3383. //
  3384. // Message Map
  3385. //
  3386. BEGIN_MESSAGE_MAP(CInetPropertyPage, CPropertyPage)
  3387. //{{AFX_MSG_MAP(CInetPropertyPage)
  3388. ON_COMMAND(ID_HELP, OnHelp)
  3389. ON_WM_HELPINFO()
  3390. //}}AFX_MSG_MAP
  3391. END_MESSAGE_MAP()
  3392. //
  3393. // Message Handlers
  3394. //
  3395. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3396. /* virtual */
  3397. BOOL
  3398. CInetPropertyPage::OnInitDialog()
  3399. /*++
  3400. Routine Description:
  3401. WM_INITDIALOG handler. Initialize the dialog. Reset changed
  3402. status (sometimes gets set by e.g. spinboxes when the dialog is
  3403. constructed), so make sure the dialog is considered clean.
  3404. Arguments:
  3405. None
  3406. Return Value:
  3407. TRUE if no focus is to be set automatically, FALSE if the focus
  3408. is already set.
  3409. --*/
  3410. {
  3411. m_bChanged = FALSE;
  3412. //
  3413. // Tell derived class to load its configuration parameters
  3414. //
  3415. CError err(LoadConfigurationParameters());
  3416. if (err.Succeeded())
  3417. {
  3418. err = FetchLoadedValues();
  3419. }
  3420. BOOL bResult = CPropertyPage::OnInitDialog();
  3421. err.MessageBoxOnFailure();
  3422. if (m_fEnableEnhancedFonts)
  3423. {
  3424. CFont * pFont = &m_fontBold;
  3425. if (CreateSpecialDialogFont(this, pFont))
  3426. {
  3427. ApplyFontToControls(this, pFont, IDC_ED_BOLD1, IDC_ED_BOLD5);
  3428. }
  3429. }
  3430. return bResult;
  3431. }
  3432. void
  3433. CInetPropertyPage::OnHelp()
  3434. /*++
  3435. Routine Description:
  3436. 'Help' button handler
  3437. Arguments:
  3438. None
  3439. Return Value:
  3440. None
  3441. --*/
  3442. {
  3443. m_pSheet->WinHelp(m_nHelpContext);
  3444. }
  3445. BOOL
  3446. CInetPropertyPage::OnHelpInfo(
  3447. IN HELPINFO * pHelpInfo
  3448. )
  3449. /*++
  3450. Routine Description:
  3451. Eat "help info" command
  3452. Arguments:
  3453. None
  3454. Return Value:
  3455. None
  3456. --*/
  3457. {
  3458. OnHelp();
  3459. return TRUE;
  3460. }
  3461. BOOL
  3462. CInetPropertyPage::OnApply()
  3463. /*++
  3464. Routine Description:
  3465. Handle "OK" or "APPLY". Call the derived class to save its stuff,
  3466. and set the dirty state depending on whether saving succeeded or
  3467. failed.
  3468. Arguments:
  3469. None
  3470. Return Value:
  3471. None
  3472. --*/
  3473. {
  3474. BOOL bSuccess = TRUE;
  3475. if (IsDirty())
  3476. {
  3477. CError err(SaveInfo());
  3478. if (err.MessageBoxOnFailure())
  3479. {
  3480. //
  3481. // Failed, sheet will not be dismissed.
  3482. //
  3483. // CODEWORK: This page should be activated.
  3484. //
  3485. bSuccess = FALSE;
  3486. }
  3487. SetModified(!bSuccess);
  3488. }
  3489. return bSuccess;
  3490. }
  3491. void
  3492. CInetPropertyPage::SetModified(
  3493. IN BOOL bChanged
  3494. )
  3495. /*++
  3496. Routine Description:
  3497. Keep private check on dirty state of the property page.
  3498. Arguments:
  3499. BOOL bChanged : Dirty flag
  3500. Return Value:
  3501. None
  3502. --*/
  3503. {
  3504. CPropertyPage::SetModified(bChanged);
  3505. m_bChanged = bChanged;
  3506. }
  3507. #ifndef _COMSTATIC
  3508. static AFX_EXTENSION_MODULE extensionDLL = {NULL, NULL};
  3509. extern "C" int APIENTRY
  3510. DllMain(
  3511. IN HINSTANCE hInstance,
  3512. IN DWORD dwReason,
  3513. IN LPVOID lpReserved
  3514. )
  3515. /*++
  3516. Routine Description:
  3517. DLL Main entry point
  3518. Arguments:
  3519. HINSTANCE hInstance : Instance handle
  3520. DWORD dwReason : DLL_PROCESS_ATTACH, etc
  3521. LPVOID lpReserved : Reserved value
  3522. Return Value:
  3523. 1 for succesful initialisation, 0 for failed initialisation
  3524. --*/
  3525. {
  3526. switch (dwReason)
  3527. {
  3528. case DLL_PROCESS_ATTACH:
  3529. ASSERT(hInstance != NULL);
  3530. hDLLInstance = hInstance;
  3531. if (!::AfxInitExtensionModule(extensionDLL, hInstance)
  3532. || !InitIntlSettings()
  3533. || !InitErrorFunctionality()
  3534. )
  3535. {
  3536. return 0;
  3537. }
  3538. break ;
  3539. case DLL_PROCESS_DETACH:
  3540. //
  3541. // termination
  3542. //
  3543. TerminateIntlSettings();
  3544. TerminateErrorFunctionality();
  3545. ::AfxTermExtensionModule(extensionDLL);
  3546. break;
  3547. }
  3548. //
  3549. // Succes loading the DLL
  3550. //
  3551. return 1;
  3552. }
  3553. extern "C" void WINAPI
  3554. InitIISUIDll()
  3555. /*++
  3556. Routine Description:
  3557. Initialize the DLL
  3558. Arguments:
  3559. None
  3560. Return Value:
  3561. None
  3562. --*/
  3563. {
  3564. new CDynLinkLibrary(extensionDLL);
  3565. hDLLInstance = extensionDLL.hResource;
  3566. }
  3567. #endif // _COMSTATIC