Leaked source code of windows server 2003
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.

1846 lines
54 KiB

  1. /*===================================================================
  2. Microsoft IIS
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: WAMREG
  6. File: Auxfunc.cpp
  7. implementation of supporting functions for WAMREG, including
  8. interface to Register and Unregister WAM CLSID in registry,
  9. interface to Create Package with MTS,
  10. Owner: LeiJin
  11. Note:
  12. ===================================================================*/
  13. #include "common.h"
  14. #include "auxfunc.h"
  15. #include "iiscnfgp.h"
  16. #include "dbgutil.h"
  17. #include "iwamreg.h"
  18. #include <inetinfo.h>
  19. //==================================================================
  20. // Global data definitions
  21. //
  22. //==================================================================
  23. //
  24. // string contains the physical path of wamreg.dll, ie. c:\winnt\system32\inetsrv\wam.dll
  25. //
  26. CHAR WamRegRegistryConfig::m_szWamDllPath[MAX_PATH];
  27. //
  28. // the permission to access the registry
  29. //
  30. const REGSAM WamRegRegistryConfig::samDesired = KEY_READ | KEY_WRITE;
  31. //
  32. // A thread will first grab a token, and wait until the token matches the m_dwServiceNum,
  33. // In such way, the order of threads making the requests are perserved.
  34. // m_hWriteLock (Event) is used for the blocking other threads
  35. // m_csWAMREGLock is used for access the m_dwServiceToken and m_dwServiceNum
  36. //
  37. // private global, static variables for WamAdmLock
  38. WamAdmLock WamRegGlobal::m_WamAdmLock;
  39. WamRegGlobal g_WamRegGlobal;
  40. WamRegRegistryConfig g_RegistryConfig;
  41. //
  42. // Defined at /LM/W3SVC/
  43. // Default package ID(IIS In-Process Application) and the default WAMCLSID(IISWAM.W3SVC).
  44. //
  45. const WCHAR WamRegGlobal::g_szIISInProcPackageID[] =
  46. W3_INPROC_PACKAGE_ID;
  47. const WCHAR WamRegGlobal::g_szInProcWAMCLSID[] =
  48. W3_INPROC_WAM_CLSID;
  49. const WCHAR WamRegGlobal::g_szInProcWAMProgID[] = L"IISWAM.W3SVC";
  50. const WCHAR WamRegGlobal::g_szIISOOPPoolPackageID[] =
  51. W3_OOP_POOL_PACKAGE_ID;
  52. const WCHAR WamRegGlobal::g_szOOPPoolWAMCLSID[] =
  53. W3_OOP_POOL_WAM_CLSID;
  54. const WCHAR WamRegGlobal::g_szOOPPoolWAMProgID[] = L"IISWAM.OutofProcessPool";
  55. const WCHAR WamRegGlobal::g_szIISInProcPackageName[] = DEFAULT_PACKAGENAME;
  56. const WCHAR WamRegGlobal::g_szIISOOPPoolPackageName[] = L"IIS Out-Of-Process Pooled Applications";
  57. const WCHAR WamRegGlobal::g_szMDAppPathPrefix[] = L"/LM/W3SVC/";
  58. const DWORD WamRegGlobal::g_cchMDAppPathPrefix =
  59. (sizeof(L"/LM/W3SVC/")/sizeof(WCHAR)) - 1;
  60. const WCHAR WamRegGlobal::g_szMDW3SVCRoot[] = L"/LM/W3SVC";
  61. const DWORD WamRegGlobal::g_cchMDW3SVCRoot = (sizeof(L"/LM/W3SVC")/sizeof(WCHAR)) - 1;
  62. #ifndef DBGERROR
  63. #define DBGERROR(args) ((void)0) /* Do Nothing */
  64. #endif
  65. BOOL WamRegGlobal::Init(VOID)
  66. {
  67. return m_WamAdmLock.Init();
  68. }
  69. BOOL WamRegGlobal::UnInit(VOID)
  70. {
  71. return m_WamAdmLock.UnInit();
  72. }
  73. WamAdmLock::WamAdmLock()
  74. : m_dwServiceToken(0),
  75. m_dwServiceNum(0),
  76. m_hWriteLock((HANDLE)NULL)
  77. {
  78. }
  79. /*===================================================================
  80. Init
  81. Init certain variables for this supporting module of WAMREG.
  82. Return: NONE
  83. ===================================================================*/
  84. BOOL WamAdmLock::Init()
  85. {
  86. BOOL fReturn = TRUE;
  87. INITIALIZE_CRITICAL_SECTION(&m_csLock);
  88. m_hWriteLock = IIS_CREATE_EVENT(
  89. "WamAdmLock::m_hWriteLock",
  90. &m_hWriteLock,
  91. TRUE,
  92. TRUE
  93. );
  94. if (m_hWriteLock == NULL)
  95. {
  96. DBGPRINTF((DBG_CONTEXT, "Failed to create m_hWriteLock(Event). error = %08x",
  97. GetLastError()));
  98. fReturn = FALSE;
  99. }
  100. return fReturn;
  101. }
  102. /*===================================================================
  103. UnInit
  104. Uninit certain variables for this supporting module of WAMREG.
  105. Return: NONE
  106. ===================================================================*/
  107. BOOL WamAdmLock::UnInit()
  108. {
  109. BOOL fReturn = TRUE;
  110. DeleteCriticalSection(&m_csLock);
  111. if (m_hWriteLock)
  112. {
  113. BOOL fTemp = CloseHandle(m_hWriteLock);
  114. if ( fTemp == FALSE)
  115. {
  116. DBGPRINTF((DBG_CONTEXT, "error in CloseHandle. errno = %d\n", GetLastError()));
  117. fReturn = FALSE;
  118. }
  119. m_hWriteLock = (HANDLE)0;
  120. }
  121. return fReturn;
  122. }
  123. /*===================================================================
  124. GetNextServiceToken
  125. Obtain the next service token when a thread enters WAMREG, if the token
  126. obtained by the thread is not the same as m_dwServiceNum, the thread has
  127. to wait until the token it owns is same as m_dwServiceNum.
  128. The function returns a token value.
  129. Return: DWORD, Next Service Token
  130. ===================================================================*/
  131. DWORD WamAdmLock::GetNextServiceToken( )
  132. {
  133. DWORD dwToken;
  134. Lock();
  135. dwToken = m_dwServiceToken;
  136. m_dwServiceToken++;
  137. UnLock();
  138. return dwToken;
  139. }
  140. /*===================================================================
  141. FAppPathAllowConfig
  142. Test to see if we can make configuration changes(Delete/Create) on a path. Currently,
  143. this function is used to block changes to the default application/package. The default
  144. in proc package should not be deleted/altered at runtime.
  145. Parameter:
  146. pwszMetabasePath
  147. Return: BOOL
  148. Side affect: TRUE if we can configure the app on the app path.
  149. ===================================================================*/
  150. BOOL WamRegGlobal::FAppPathAllowConfig
  151. (
  152. IN LPCWSTR pwszMetabasePath
  153. )
  154. {
  155. BOOL fReturn = TRUE;
  156. DWORD cchMDPath = 0;
  157. DBG_ASSERT(pwszMetabasePath);
  158. // Since szMDPath has a path that always starts with "/LM/W3SVC/", the input size must be
  159. // greater that length of "/LM/W3SVC/", This check is necessary to protect that the default
  160. // IIS (inproc) package being deleted by accident.
  161. cchMDPath = wcslen(pwszMetabasePath);
  162. if (cchMDPath <= WamRegGlobal::g_cchMDAppPathPrefix)
  163. {
  164. fReturn = FALSE;
  165. }
  166. return fReturn;
  167. }
  168. /*===================================================================
  169. FIsW3SVCRoot
  170. Test to see the MetabasePath is same as L"/LM/W3SVC".
  171. Parameter:
  172. pwszMetabasePath
  173. Return: BOOL
  174. Side affect: TRUE if we can configure the app on the app path.
  175. ===================================================================*/
  176. BOOL WamRegGlobal::FIsW3SVCRoot
  177. (
  178. IN LPCWSTR wszMetabasePath
  179. )
  180. {
  181. INT iReturn;
  182. DBG_ASSERT(wszMetabasePath != NULL);
  183. iReturn = _wcsnicmp(wszMetabasePath, WamRegGlobal::g_szMDW3SVCRoot, WamRegGlobal::g_cchMDW3SVCRoot+1);
  184. return (iReturn == 0 ? TRUE : FALSE);
  185. }
  186. /*===================================================================
  187. AcquireLock
  188. Get a write lock, there can only be one thread doing work via DCOM interface, (i.e. has the write lock).
  189. All other threads calling WamAdmin interfaces are blocked in this function. After returning from
  190. this call, the thread is guaranteed to be a "Critical Section".
  191. A simple CriticalSection only solve half of the problem. It guarantees the mutual exclusive condition.
  192. But once a thread leaves the CS, the CS can not control which blocking threads can access CS next.
  193. Parameter:
  194. NONE.
  195. Return: HRESULT
  196. Side affect: Once returned, thread is in a "Critical Section".
  197. ===================================================================*/
  198. VOID WamAdmLock::AcquireWriteLock( )
  199. {
  200. DWORD dwWaitReturn = WAIT_OBJECT_0;
  201. DWORD dwMyToken = GetNextServiceToken();
  202. BOOL fIsMyTurn = FALSE; // Assume it is not my turn before we try to acquire the lock.
  203. DBG_ASSERT(m_hWriteLock);
  204. do {
  205. dwWaitReturn = WaitForSingleObject(m_hWriteLock, INFINITE);
  206. //
  207. // Check for successful return.
  208. //
  209. if (dwWaitReturn == WAIT_OBJECT_0)
  210. {
  211. Lock();
  212. if (dwMyToken == m_dwServiceNum)
  213. {
  214. fIsMyTurn = TRUE;
  215. }
  216. UnLock();
  217. }
  218. else
  219. {
  220. //
  221. // A failure down this code path might cause a busy loop...
  222. // However, such failure is very unlikely. Attach a debugger can tell the story immediately.
  223. //
  224. DBGPRINTF((DBG_CONTEXT, "WaitForSingleObject failed, function returns %08x, errno = %08x\n",
  225. dwWaitReturn,
  226. GetLastError()));
  227. DBG_ASSERT(FALSE);
  228. }
  229. } while (FALSE == fIsMyTurn);
  230. ResetEvent(m_hWriteLock);
  231. IF_DEBUG(WAMREG_MTS)
  232. {
  233. DBGPRINTF((DBG_CONTEXT, "Thread %08x acquired the WriteLock of WAMREG, ServiceNum is %d.\n",
  234. GetCurrentThreadId(),
  235. dwMyToken));
  236. }
  237. }
  238. /*===================================================================
  239. ReleaseLock
  240. Release a write lock. See comments in CWmRgSrv::AcquireLock.
  241. Parameter:
  242. NONE.
  243. Return: HRESULT
  244. Side affect: Leave "Critical Section".
  245. ===================================================================*/
  246. VOID WamAdmLock::ReleaseWriteLock( )
  247. {
  248. //CONSIDER: m_dwServerNum out-of-bound
  249. Lock();
  250. IF_DEBUG(WAMREG_MTS)
  251. {
  252. DBGPRINTF((DBG_CONTEXT, "Thread %08x released the WriteLock of WAMREG, ServiceNum is %d.\n",
  253. GetCurrentThreadId(),
  254. m_dwServiceNum));
  255. }
  256. m_dwServiceNum++;
  257. SetEvent(m_hWriteLock);
  258. UnLock();
  259. }
  260. /*===================================================================
  261. RegisterCLSID
  262. Register a WAM CLSID and a ProgID..After a successful registerCLSID call, you
  263. should have
  264. My Computer\HKEY_CLASSES_ROOT\CLSID\{szCLSIDEntryIn}
  265. \InProcServer32 "...physical location of wam.dll"
  266. \ProgID szProgIDIn
  267. \VersionIndependentProgID "IISWAM.W3SVC"
  268. Parameter:
  269. szCLSIDEntryIn: CLSID for a WAM.
  270. szProgIDIn: ProgID for the WAM.
  271. fSetVIProgID: TRUE if this function needs to set the Version Independent ProgID.
  272. FALSE, Otherwise.
  273. Return: HRESULT
  274. NOTE: Registry API should use ANSI version, otherwise, it will cause trouble on Win95.
  275. ===================================================================*/
  276. HRESULT WamRegRegistryConfig::RegisterCLSID
  277. (
  278. IN LPCWSTR szCLSIDEntryIn,
  279. IN LPCWSTR szProgIDIn,
  280. IN BOOL fSetVIProgID
  281. )
  282. {
  283. static const CHAR szWAMDLL[] = "wam.dll";
  284. static const CHAR szClassDesc[] = "Web Application Manager Object";
  285. static const CHAR szThreadingModel[] = "ThreadingModel";
  286. static const CHAR szInprocServer32[] = "InprocServer32";
  287. static const CHAR szTEXT_VIProgID[] = "VersionIndependentProgID";
  288. static const CHAR szTEXT_ProgID[] = "ProgID";
  289. static const CHAR szTEXT_Clsid[] = "Clsid";
  290. static const CHAR szFreeThreaded[] = "Free";
  291. static const CHAR szVIProgID[] = "IISWAM.Application";
  292. HRESULT hr = E_FAIL;
  293. HKEY hkeyT = NULL, hkey2 = NULL;
  294. CHAR szCLSIDPath[100] = "CLSID\\"; // CLSID\\{....} , less that 100.
  295. CHAR szCLSIDEntry[uSizeCLSID]; // ANSI version of CLSID.
  296. CHAR* szProgID = NULL; // a pointer to ANSI version of ProgID.
  297. DWORD dwSizeofProgID = 0; // # of char of ProgID.
  298. DBG_ASSERT(szProgIDIn);
  299. DBG_ASSERT(szCLSIDEntryIn);
  300. //
  301. // Make a clsid ID.
  302. //
  303. WideCharToMultiByte(CP_ACP, 0, szCLSIDEntryIn, -1, szCLSIDEntry, uSizeCLSID, NULL, NULL);
  304. strncat(szCLSIDPath, szCLSIDEntry, uSizeCLSID);
  305. //
  306. // Make a Prog ID.
  307. //
  308. // *2 for DBCS enabling for App MD path
  309. dwSizeofProgID = wcslen(szProgIDIn)*2 + 1;
  310. szProgID = new CHAR[dwSizeofProgID];
  311. if (NULL == szProgID)
  312. {
  313. hr = E_OUTOFMEMORY;
  314. goto LErrExit;
  315. }
  316. WideCharToMultiByte(CP_ACP, 0, szProgIDIn, -1, szProgID, dwSizeofProgID, NULL, NULL);
  317. // install the CLSID key
  318. // Setting the value of the description creates the key for the clsid
  319. //
  320. if ((RegSetValueA(HKEY_CLASSES_ROOT, szCLSIDPath, REG_SZ, szClassDesc,
  321. strlen(szClassDesc)) != ERROR_SUCCESS))
  322. goto LErrExit;
  323. //
  324. // Open the CLSID key so we can set values on it
  325. //
  326. if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szCLSIDPath, 0, samDesired, &hkeyT) != ERROR_SUCCESS)
  327. goto LErrExit;
  328. //
  329. // install the InprocServer32 key and open the sub-key to set the named value
  330. //
  331. if ((RegSetValueA(hkeyT, szInprocServer32, REG_SZ, m_szWamDllPath, strlen(m_szWamDllPath)) != ERROR_SUCCESS) ||
  332. (RegOpenKeyExA(hkeyT, szInprocServer32, 0, samDesired, &hkey2) != ERROR_SUCCESS))
  333. goto LErrExit;
  334. //
  335. // install the ProgID key and version independent ProgID key
  336. //
  337. if ((RegSetValueA(hkeyT, szTEXT_ProgID, REG_SZ, szProgID, strlen(szProgID)) != ERROR_SUCCESS) ||
  338. (RegSetValueA(hkeyT, szTEXT_VIProgID, REG_SZ, szVIProgID, strlen(szVIProgID)) != ERROR_SUCCESS))
  339. goto LErrExit;
  340. if (RegCloseKey(hkeyT) != ERROR_SUCCESS)
  341. goto LErrExit;
  342. hkeyT = hkey2;
  343. hkey2 = NULL;
  344. //
  345. // install the ThreadingModel named value
  346. //
  347. if (RegSetValueExA(hkeyT, szThreadingModel, 0, REG_SZ, (const BYTE *)szFreeThreaded,
  348. strlen(szFreeThreaded)) != ERROR_SUCCESS)
  349. goto LErrExit;
  350. if (RegCloseKey(hkeyT) != ERROR_SUCCESS)
  351. goto LErrExit;
  352. else
  353. hkeyT = NULL;
  354. // Set up ProgID key
  355. if ((RegSetValueA(HKEY_CLASSES_ROOT, szProgID, REG_SZ, szClassDesc,
  356. strlen(szClassDesc)) != ERROR_SUCCESS))
  357. goto LErrExit;
  358. if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szProgID, 0, samDesired, &hkeyT) != ERROR_SUCCESS)
  359. goto LErrExit;
  360. if ((RegSetValueA(hkeyT, szTEXT_Clsid, REG_SZ, szCLSIDEntry, strlen(szCLSIDEntry)) != ERROR_SUCCESS))
  361. goto LErrExit;
  362. if (RegCloseKey(hkeyT) != ERROR_SUCCESS)
  363. goto LErrExit;
  364. else
  365. hkeyT = NULL;
  366. // Set up Version Independent key only at setup IIS default time
  367. if (fSetVIProgID)
  368. {
  369. if ((RegSetValueA(HKEY_CLASSES_ROOT, szVIProgID, REG_SZ, szClassDesc,
  370. strlen(szClassDesc)) != ERROR_SUCCESS))
  371. goto LErrExit;
  372. if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szVIProgID, 0, samDesired, &hkeyT) != ERROR_SUCCESS)
  373. goto LErrExit;
  374. if ((RegSetValueA(hkeyT, szTEXT_Clsid, REG_SZ, szCLSIDEntry, strlen(szCLSIDEntry)) != ERROR_SUCCESS))
  375. goto LErrExit;
  376. if (RegCloseKey(hkeyT) != ERROR_SUCCESS)
  377. goto LErrExit;
  378. else
  379. hkeyT = NULL;
  380. }
  381. hr = NOERROR;
  382. LErrExit:
  383. if (szProgID)
  384. {
  385. delete [] szProgID;
  386. szProgID = NULL;
  387. }
  388. if (hkeyT)
  389. {
  390. RegCloseKey(hkeyT);
  391. }
  392. if (hkey2)
  393. {
  394. RegCloseKey(hkey2);
  395. }
  396. return hr;
  397. }
  398. /*===================================================================
  399. UnRegisterCLSID
  400. UnRegister a WAM CLSID & a corresponding WAM PROG ID.
  401. Parameter:
  402. szCLSIDEntryIn: [in] CLSID for a WAM.
  403. fDeleteVIProgID: TRUE, to delete the version independent prog id, FALSE, not touch VI progID.
  404. Return: HRESULT
  405. ===================================================================*/
  406. HRESULT WamRegRegistryConfig::UnRegisterCLSID
  407. (
  408. IN LPCWSTR wszCLSIDEntryIn,
  409. IN BOOL fDeleteVIProgID
  410. )
  411. {
  412. HRESULT hr = E_FAIL;
  413. HKEY hkey = NULL;
  414. CHAR szCLSIDEntry[uSizeCLSID];
  415. CHAR szCLSIDPath[100] = "CLSID\\";
  416. WCHAR *szProgID = NULL;
  417. CLSID Clsid_WAM;
  418. static const WCHAR szVIProgID[] = L"IISWAM.Application";
  419. DBG_ASSERT(wszCLSIDEntryIn);
  420. //
  421. // Make a clsid ID.
  422. //
  423. WideCharToMultiByte(CP_ACP, 0, wszCLSIDEntryIn, -1, szCLSIDEntry, uSizeCLSID, NULL, NULL);
  424. strncat(szCLSIDPath, szCLSIDEntry, uSizeCLSID);
  425. //
  426. // UnRegister ProgID and Version Independent Prog ID.
  427. //
  428. hr = CLSIDFromString((WCHAR *)wszCLSIDEntryIn, &Clsid_WAM);
  429. if (SUCCEEDED(hr))
  430. {
  431. hr = ProgIDFromCLSID(Clsid_WAM, &szProgID);
  432. if (SUCCEEDED(hr))
  433. {
  434. hr = UnRegisterProgID(szProgID);
  435. CoTaskMemFree(szProgID);
  436. szProgID = NULL;
  437. }
  438. else
  439. {
  440. DBGPRINTF((DBG_CONTEXT, "error = %08x\n", hr));
  441. }
  442. }
  443. else
  444. {
  445. DBGPRINTF((DBG_CONTEXT, "error = %08x\n", hr));
  446. }
  447. if (fDeleteVIProgID)
  448. {
  449. hr = UnRegisterProgID(szVIProgID);
  450. if (FAILED(hr))
  451. {
  452. DBGPRINTF((DBG_CONTEXT, "error = %08x\n", hr));
  453. }
  454. }
  455. DWORD dwReg;
  456. //
  457. // Open the HKEY_CLASSES_ROOT\CLSID\{...} key so we can delete its subkeys
  458. //
  459. dwReg = RegOpenKeyExA(HKEY_CLASSES_ROOT, szCLSIDPath, 0, samDesired, &hkey);
  460. if (dwReg == ERROR_SUCCESS)
  461. {
  462. DWORD iKey = 0;
  463. CHAR szKeyName[MAX_PATH];
  464. DWORD cbKeyName;
  465. //
  466. // Enumerate all its subkeys, and delete them
  467. // for (iKey=0;;iKey++) might not work with multiple sub keys, the last interation has iKey >
  468. // the actually number of subkeys left. Set iKey = 0, so that we can always delete them all.
  469. //
  470. while(TRUE)
  471. {
  472. cbKeyName = sizeof(szKeyName);
  473. if (RegEnumKeyExA(hkey, iKey, szKeyName, &cbKeyName, 0, NULL, 0, NULL) != ERROR_SUCCESS)
  474. break;
  475. if (RegDeleteKeyA(hkey, szKeyName) != ERROR_SUCCESS)
  476. break;
  477. }
  478. // Close the key, and then delete it
  479. dwReg = RegCloseKey(hkey);
  480. if ( dwReg != ERROR_SUCCESS)
  481. {
  482. DBGPRINTF((DBG_CONTEXT, "error = %08x\n", HRESULT_FROM_WIN32(dwReg)));
  483. }
  484. }
  485. dwReg = RegDeleteKeyA(HKEY_CLASSES_ROOT, szCLSIDPath);
  486. if ( dwReg != ERROR_SUCCESS)
  487. {
  488. DBGPRINTF((DBG_CONTEXT, "error = %08x\n", HRESULT_FROM_WIN32(dwReg)));
  489. }
  490. //
  491. // Return hr Result
  492. //
  493. if (SUCCEEDED(hr))
  494. {
  495. if (dwReg != ERROR_SUCCESS)
  496. {
  497. hr = HRESULT_FROM_WIN32(dwReg);
  498. }
  499. }
  500. else
  501. {
  502. DBG_ASSERT((DBG_CONTEXT, "Failed to UnRegisterCLSID, %S, fDeleteVIProgID = %s\n",
  503. wszCLSIDEntryIn,
  504. (fDeleteVIProgID ? "TRUE" : "FALSE")));
  505. }
  506. return hr;
  507. }
  508. /*===================================================================
  509. UnRegisterProgID
  510. UnRegister a Prog ID.
  511. Parameter:
  512. szProgID: [in] Prog ID can be a version independent Prog ID.
  513. Return: HRESULT
  514. ===================================================================*/
  515. HRESULT WamRegRegistryConfig::UnRegisterProgID
  516. (
  517. IN LPCWSTR szProgIDIn
  518. )
  519. {
  520. HKEY hkey = NULL;
  521. DWORD iKey;
  522. DWORD cbKeyName;
  523. DWORD dwSizeofProgID;
  524. CHAR szKeyName[255];
  525. CHAR* szProgID = NULL;
  526. HRESULT hr = E_FAIL;
  527. DBG_ASSERT(szProgIDIn);
  528. //
  529. // Make a Prog ID.
  530. //
  531. // DBCS enabling *2
  532. dwSizeofProgID = wcslen(szProgIDIn)*2 + 1;
  533. szProgID = new CHAR[dwSizeofProgID];
  534. if (NULL == szProgID)
  535. {
  536. hr = E_OUTOFMEMORY;
  537. goto LErrExit;
  538. }
  539. WideCharToMultiByte(CP_ACP, 0, szProgIDIn, -1, szProgID, dwSizeofProgID, NULL, NULL);
  540. // Open the HKEY_CLASSES_ROOT\szProgID key so we can delete its subkeys
  541. if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szProgID, 0, samDesired, &hkey) != ERROR_SUCCESS)
  542. goto LErrExit;
  543. // Enumerate all its subkeys, and delete them
  544. for (iKey=0;;iKey++)
  545. {
  546. cbKeyName = sizeof(szKeyName);
  547. if (RegEnumKeyExA(hkey, iKey, szKeyName, &cbKeyName, 0, NULL, 0, NULL) != ERROR_SUCCESS)
  548. break;
  549. if (RegDeleteKeyA(hkey, szKeyName) != ERROR_SUCCESS)
  550. goto LErrExit;
  551. }
  552. // Close the key, and then delete it
  553. if (RegCloseKey(hkey) != ERROR_SUCCESS)
  554. goto LErrExit;
  555. else
  556. hkey = NULL;
  557. if (RegDeleteKeyA(HKEY_CLASSES_ROOT, szProgID) != ERROR_SUCCESS)
  558. goto LErrExit;
  559. hr = NOERROR;
  560. LErrExit:
  561. if (szProgID)
  562. delete [] szProgID;
  563. if (hkey)
  564. RegCloseKey(hkey);
  565. return hr;
  566. }
  567. /*===================================================================
  568. LoadWamDllPath
  569. Read Wam Dll Path from Registry. This function is implemented in ANSI version
  570. of Registry API(Win95 compatibility).
  571. Parameter:
  572. Return: HRESULT
  573. Side Affect:
  574. NONE.
  575. ===================================================================*/
  576. HRESULT WamRegRegistryConfig::LoadWamDllPath
  577. (
  578. void
  579. )
  580. {
  581. LONG lReg = 0;
  582. HKEY hKey = NULL;
  583. HRESULT hr = NOERROR;
  584. m_szWamDllPath[0] = '\0';
  585. lReg = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  586. "Software\\Microsoft\\InetStp",
  587. 0,
  588. KEY_READ,
  589. &hKey);
  590. if (lReg == ERROR_SUCCESS)
  591. {
  592. LONG lErr = 0;
  593. DWORD dwType;
  594. CHAR szWamDllName[] = "\\wam.dll";
  595. DWORD cbData = (sizeof(m_szWamDllPath) - sizeof(szWamDllName));
  596. lErr = RegQueryValueExA(hKey,
  597. "InstallPath",
  598. 0,
  599. &dwType,
  600. (LPBYTE)m_szWamDllPath,
  601. &cbData);
  602. if (lErr == ERROR_SUCCESS)
  603. {
  604. if (dwType == REG_SZ)
  605. {
  606. strncat(m_szWamDllPath, szWamDllName, sizeof(szWamDllName));
  607. hr = NOERROR;
  608. }
  609. else
  610. {
  611. hr = E_UNEXPECTED;
  612. DBGPRINTF((DBG_CONTEXT, "Wrong Type for InstallPath registry key.dwType = %d\n",
  613. dwType));
  614. }
  615. }
  616. else
  617. {
  618. hr = HRESULT_FROM_WIN32(lErr);
  619. }
  620. RegCloseKey(hKey);
  621. }
  622. else
  623. {
  624. hr = HRESULT_FROM_WIN32(lReg);
  625. }
  626. return hr;
  627. }
  628. /*===================================================================
  629. SzWamProgID
  630. Make a WAM Prog ID, if the MetabasePath is null, assume it is the default,
  631. that is WAM de
  632. fault, so, it will be IISWAM.W3SVC. Otherwise, the format is
  633. IISWAM.__1__Application__Path where application path is \\LM\w3svc\1\
  634. Application_path.
  635. Parameter:
  636. szMetabasePath: [in] MetabasePath.
  637. Return:
  638. TYPE: LPWSTR, a string contains ProgID
  639. NULL, if failed.
  640. Side Affect:
  641. Allocate memory for return result use new. Caller needs to free szWamProgID
  642. use delete[].
  643. ===================================================================*/
  644. HRESULT WamRegGlobal::SzWamProgID
  645. (
  646. IN LPCWSTR pwszMetabasePath,
  647. OUT LPWSTR* ppszWamProgID
  648. )
  649. {
  650. HRESULT hr = NOERROR;
  651. static WCHAR wszIISProgIDPreFix[] = L"IISWAM.";
  652. WCHAR *pwszResult = NULL;
  653. WCHAR *pwszApplicationPath = NULL;
  654. UINT uPrefixLen = (sizeof(wszIISProgIDPreFix) / sizeof(WCHAR));
  655. DBG_ASSERT(pwszMetabasePath);
  656. *ppszWamProgID = NULL;
  657. //
  658. // Make a new WAM Prog ID based on pwszMetabasepath
  659. //
  660. WCHAR *pStr, *pResult;
  661. UINT uSize = 0;
  662. //
  663. // CONSIDER: use (sizeof(L"/LM/W3SVC/")/sizeof(WCHAR) - 1) for 10
  664. // CONSIDER: use global const for L"/LM/W3SVC/"
  665. // Since all paths start with /LM/W3SVC/, omit the prefix.
  666. //
  667. if (_wcsnicmp(pwszMetabasePath, L"\\LM\\W3SVC\\", 10) == 0 ||
  668. _wcsnicmp(pwszMetabasePath, L"/LM/W3SVC/", 10) == 0)
  669. {
  670. pwszApplicationPath = (WCHAR *)(pwszMetabasePath + 10);
  671. }
  672. else
  673. {
  674. *ppszWamProgID = NULL;
  675. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  676. }
  677. if (SUCCEEDED(hr))
  678. {
  679. pStr = pwszApplicationPath;
  680. //
  681. // Calculate uSize for allocation
  682. //
  683. while(*pStr != NULL)
  684. {
  685. //
  686. // '/' or '\\' will be converted to '__', from 1 char to 2 chars.
  687. //
  688. if (*pStr == '\\' || *pStr == '/')
  689. uSize ++;
  690. pStr++;
  691. uSize++;
  692. }
  693. DBG_ASSERT(uSize > 0);
  694. uSize += uPrefixLen;
  695. // uSize takes the null terminator into count.
  696. pwszResult = new WCHAR[uSize];
  697. if (pwszResult != NULL)
  698. {
  699. wcsncpy(pwszResult, wszIISProgIDPreFix, uPrefixLen);
  700. pStr = pwszApplicationPath;
  701. pResult = pwszResult + uPrefixLen - 1;
  702. while(*pStr != NULL)
  703. {
  704. if (*pStr == '\\' || *pStr == '/')
  705. {
  706. *pResult++ = '_';
  707. *pResult++ = '_';
  708. pStr++;
  709. }
  710. else
  711. {
  712. *pResult++ = *pStr++;
  713. }
  714. }
  715. // NULL Terminating the result
  716. pwszResult[uSize-1] = '\0';
  717. }
  718. else
  719. {
  720. hr = E_OUTOFMEMORY;
  721. }
  722. }
  723. if (SUCCEEDED(hr))
  724. {
  725. *ppszWamProgID = pwszResult;
  726. }
  727. return hr;
  728. }
  729. /*===================================================================
  730. GetViperPackageName
  731. Make a Package Name. Follow the naming conversion, "IIS-{web site name/
  732. application name}"
  733. Parameter:
  734. szMetabasePath: [in] MetabasePath.
  735. Return: HRESULT
  736. Side Affect:
  737. Allocate memory for return result use new. Caller needs to free
  738. szPackageName using delete[].
  739. ===================================================================*/
  740. HRESULT WamRegGlobal::GetViperPackageName
  741. (
  742. IN LPCWSTR wszMetabasePath,
  743. OUT LPWSTR* ppszPackageNameOut
  744. )
  745. {
  746. static WCHAR wszPackageNamePreFix[] = L"IIS-{";
  747. static WCHAR wszPackageNamePostFix[] = L"}";
  748. WCHAR wszServerName[500];
  749. WCHAR* pwszPackageName;
  750. WCHAR *wszResult = NULL;
  751. WCHAR *pStr, *pResult;
  752. UINT cPackageName = 0;
  753. UINT cServerName = 0;
  754. UINT uSize = 0;
  755. HRESULT hr = NOERROR;
  756. WamRegMetabaseConfig MDConfig;
  757. if ((_wcsnicmp(wszMetabasePath, WamRegGlobal::g_szMDAppPathPrefix, WamRegGlobal::g_cchMDAppPathPrefix) == 0) ||
  758. (_wcsnicmp(wszMetabasePath, WamRegGlobal::g_szMDAppPathPrefix, WamRegGlobal::g_cchMDAppPathPrefix) == 0))
  759. {
  760. hr = MDConfig.GetWebServerName(wszMetabasePath, wszServerName, sizeof(wszServerName));
  761. if (SUCCEEDED(hr))
  762. {
  763. cServerName = wcslen(wszServerName);
  764. }
  765. }
  766. else
  767. {
  768. hr = E_FAIL;
  769. DBGPRINTF((DBG_CONTEXT, "Unknown metabase path %S\n", wszMetabasePath));
  770. DBG_ASSERT(FALSE); // Confused ??? MetabasePath has other format? not start with /LM/W3SVC/ ???
  771. }
  772. if (SUCCEEDED(hr))
  773. {
  774. pwszPackageName = (WCHAR *)(wszMetabasePath + 10);
  775. // Explanation: skip the 1 at /LM/W3SVC/1/, 1 is the virtual server, the
  776. // naming conversion
  777. // will replace the number 1 with some nice name(from GetWebServerName call).
  778. while(*pwszPackageName != NULL)
  779. {
  780. if (*pwszPackageName == L'\\' || *pwszPackageName == L'/')
  781. break;
  782. pwszPackageName++;
  783. }
  784. DBG_ASSERT(pwszPackageName != NULL); // We must be able find '\\' or '/' before we scan the whole path.
  785. cPackageName = wcslen(pwszPackageName);
  786. pStr = pwszPackageName;
  787. // 8 = wcslen(TEXT("IIS-{")) + wcslen(TEXT("}")) + '/' + null terminator
  788. uSize = 8 + cPackageName + cServerName;
  789. wszResult = new WCHAR [uSize];
  790. if (wszResult != NULL)
  791. {
  792. //
  793. // IIS-{
  794. //
  795. pResult = wszResult;
  796. wcsncpy(wszResult, wszPackageNamePreFix, sizeof(wszPackageNamePreFix) / sizeof(WCHAR));
  797. pResult += sizeof(wszPackageNamePreFix) / sizeof(WCHAR) - 1;
  798. //
  799. // IIS-{ Web Sever Name
  800. //
  801. wcsncpy(pResult, wszServerName, cServerName + 1);
  802. pResult += cServerName;
  803. //
  804. // IIS-{ Web Server Name /
  805. //
  806. wcsncpy(pResult, L"/", sizeof(L"/"));
  807. pResult += 1; // sizeof(TEXT("/")) == 2
  808. //
  809. // IIS-{ Web Server Name / PackageName(ApplicationName)
  810. //
  811. wcsncpy(pResult, pwszPackageName, cPackageName + 1);
  812. pResult += cPackageName;
  813. //
  814. // IIS-{ Web Server Name / PackageName(ApplicationName) } \n
  815. //
  816. wcsncpy(pResult, wszPackageNamePostFix, sizeof(wszPackageNamePostFix) / sizeof(WCHAR));
  817. }
  818. else
  819. {
  820. hr = E_OUTOFMEMORY;
  821. }
  822. }
  823. if (FAILED(hr))
  824. {
  825. if (wszResult)
  826. {
  827. delete[] wszResult;
  828. wszResult = NULL;
  829. }
  830. *ppszPackageNameOut = NULL;
  831. }
  832. else
  833. {
  834. DBG_ASSERT(wszResult);
  835. *ppszPackageNameOut = wszResult;
  836. }
  837. return hr;
  838. }
  839. /*===================================================================
  840. ConstructFullPath
  841. When use GetDataPaths call, it only returns patial path relative to a metabase path.
  842. (sub node of a metabase path). This fuction will contruct the complete metabase path to
  843. a sub node.
  844. Parameter:
  845. pwszMetabasePathPrefix: [in] MetabasePath.
  846. pwszPartialPath
  847. ppwszResult result buffer
  848. Return: HRESULT
  849. Side Affect:
  850. Allocate memory for return result use new. Caller needs to free
  851. *ppwszResult using delete[].
  852. ===================================================================*/
  853. HRESULT WamRegGlobal::ConstructFullPath
  854. (
  855. IN LPCWSTR pwszMetabasePathPrefix,
  856. IN DWORD dwcPrefix,
  857. IN LPCWSTR pwszPartialPath,
  858. OUT LPWSTR* ppwszResult
  859. )
  860. {
  861. HRESULT hr = NOERROR;
  862. DWORD cchPrefix = dwcPrefix;
  863. DWORD cchPartialPath = 0;
  864. DWORD cchFullPath = 0;
  865. WCHAR *pResult = NULL;
  866. BOOL fHasEndSlash = FALSE;
  867. DBG_ASSERT(pwszPartialPath != NULL);
  868. if (pwszMetabasePathPrefix[dwcPrefix-1] == L'\\' ||
  869. pwszMetabasePathPrefix[dwcPrefix-1] == L'/')
  870. {
  871. cchPrefix--;
  872. }
  873. cchPartialPath = wcslen(pwszPartialPath);
  874. // Skip the ending '/' of pwszPartialPath if thereis any.
  875. if (cchPartialPath > 0 &&
  876. (pwszPartialPath[cchPartialPath-1] == L'/'
  877. || pwszPartialPath[cchPartialPath-1] == L'\\'))
  878. {
  879. cchPartialPath--;
  880. fHasEndSlash=TRUE;
  881. }
  882. cchFullPath = cchPrefix + cchPartialPath + 1;
  883. pResult = new WCHAR [cchFullPath];
  884. if (pResult)
  885. {
  886. memcpy(pResult, pwszMetabasePathPrefix, cchPrefix*sizeof(WCHAR));
  887. memcpy(pResult+cchPrefix, pwszPartialPath, cchPartialPath*sizeof(WCHAR));
  888. pResult[cchFullPath-1] = L'\0';
  889. }
  890. else
  891. {
  892. hr = E_OUTOFMEMORY;
  893. }
  894. *ppwszResult = pResult;
  895. return hr;
  896. }
  897. /*===================================================================
  898. GetNewSzGUID
  899. Generate a new GUID and put into *ppszGUID.
  900. Parameter:
  901. LPWSTR *ppszGUID a pointer to an array, allocated in this function
  902. and freed by caller.
  903. Return: HRESULT
  904. ===================================================================*/
  905. HRESULT WamRegGlobal::GetNewSzGUID(OUT LPWSTR *ppszGUID)
  906. {
  907. GUID GUID_Temp;
  908. HRESULT hr;
  909. DBG_ASSERT(ppszGUID);
  910. // Create a new WAM CLSID
  911. hr = CoCreateGuid(&GUID_Temp);
  912. if (SUCCEEDED(hr))
  913. {
  914. hr = StringFromCLSID(GUID_Temp, ppszGUID);
  915. if (FAILED(hr))
  916. {
  917. *ppszGUID = NULL;
  918. }
  919. }
  920. return hr;
  921. }
  922. /*===================================================================
  923. CreatePooledApp
  924. Register a WAM CLSID.
  925. Parameter:
  926. szMetabasePath: [in] MetabaseKey.
  927. Return: HRESULT
  928. ===================================================================*/
  929. HRESULT WamRegGlobal::CreatePooledApp
  930. (
  931. IN LPCWSTR szMetabasePath,
  932. IN BOOL fInProc,
  933. IN BOOL fRecover
  934. )
  935. {
  936. HRESULT hr = NOERROR;
  937. WamRegMetabaseConfig MDConfig;
  938. DBG_ASSERT(szMetabasePath);
  939. if (SUCCEEDED(hr))
  940. {
  941. MDPropItem rgProp[IWMDP_MAX];
  942. MDConfig.InitPropItemData(&rgProp[0]);
  943. // Update APPRoot
  944. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_ROOT, szMetabasePath);
  945. //Update AppIsolated
  946. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_ISOLATED,
  947. (fInProc) ? static_cast<DWORD>(eAppRunInProc)
  948. : static_cast<DWORD>(eAppRunOutProcInDefaultPool));
  949. //
  950. // in case this is an recover operation, we do not remove App Friendly Name.
  951. //
  952. if (!fRecover)
  953. {
  954. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_FRIENDLY_NAME, L"");
  955. }
  956. hr = MDConfig.UpdateMD( rgProp, METADATA_INHERIT, szMetabasePath );
  957. }
  958. if (FAILED(hr))
  959. {
  960. HRESULT hrT = NOERROR;
  961. DBGPRINTF((DBG_CONTEXT, "Failed to create in proc application. path = %S, error = %08x\n",
  962. szMetabasePath,
  963. hr));
  964. }
  965. return hr;
  966. }
  967. /*===================================================================
  968. CreateOutProcApp
  969. Create an out prop application.
  970. Parameter:
  971. szMetabasePath: [in] MetabaseKey.
  972. fRecover [in] if TRUE, we recover/recreate the application.
  973. fSaveMB [in] if TRUE, save metabase immediately
  974. Return: HRESULT
  975. ===================================================================*/
  976. HRESULT WamRegGlobal::CreateOutProcApp(
  977. IN LPCWSTR szMetabasePath,
  978. IN BOOL fRecover, /* = FALSE */
  979. IN BOOL fSaveMB /* = TRUE */
  980. )
  981. {
  982. WCHAR *szWAMCLSID = NULL;
  983. WCHAR *szPackageID = NULL;
  984. WCHAR *szNameForNewPackage = NULL;
  985. HRESULT hr;
  986. HRESULT hrRegister = E_FAIL;
  987. HRESULT hrPackage = E_FAIL;
  988. HRESULT hrMetabase = E_FAIL;
  989. WCHAR szIdentity[MAX_PATH];
  990. WCHAR szPwd[MAX_PATH];
  991. WamRegMetabaseConfig MDConfig;
  992. WamRegPackageConfig PackageConfig;
  993. DBG_ASSERT(szMetabasePath);
  994. hr = GetNewSzGUID(&szWAMCLSID);
  995. if (FAILED(hr))
  996. {
  997. DBGPRINTF((DBG_CONTEXT, "Failed to create a new szGUID. error = %08x\n", hr));
  998. return hr;
  999. }
  1000. else
  1001. {
  1002. WCHAR *szProgID = NULL;
  1003. // Do WAM CLSID registration
  1004. //
  1005. hr = SzWamProgID(szMetabasePath, &szProgID);
  1006. if (FAILED(hr))
  1007. {
  1008. DBGPRINTF((DBG_CONTEXT, "Failed to Create WAM ProgID, hr = %08x\n",
  1009. hr));
  1010. }
  1011. else
  1012. {
  1013. hr = g_RegistryConfig.RegisterCLSID(szWAMCLSID, szProgID, FALSE);
  1014. hrRegister = hr;
  1015. delete [] szProgID;
  1016. szProgID = NULL;
  1017. if (FAILED(hrRegister))
  1018. {
  1019. DBGPRINTF((DBG_CONTEXT, "Failed to registerCLSID. error %08x\n", hr));
  1020. }
  1021. }
  1022. }
  1023. if (SUCCEEDED(hr))
  1024. {
  1025. WCHAR szLastOutProcPackageID[uSizeCLSID];
  1026. //
  1027. // When an outproc package gets deleted, it might/might not removed from the MTS,
  1028. // the next time, same app path marked as out-proc again, we try to reuse the outproc
  1029. // package. Therefore, we need to save the OutprogPackageID as LastOutProcPackageID.
  1030. //
  1031. szLastOutProcPackageID[0] = NULL;
  1032. MDConfig.MDGetLastOutProcPackageID(szMetabasePath, szLastOutProcPackageID);
  1033. if (szLastOutProcPackageID[0] == NULL)
  1034. {
  1035. hr = GetNewSzGUID(&szPackageID);
  1036. }
  1037. else
  1038. {
  1039. szPackageID = (WCHAR *)CoTaskMemAlloc(uSizeCLSID*sizeof(WCHAR));
  1040. if (szPackageID == NULL)
  1041. {
  1042. hr = E_OUTOFMEMORY;
  1043. }
  1044. else
  1045. {
  1046. wcsncpy(szPackageID, szLastOutProcPackageID, uSizeCLSID);
  1047. }
  1048. }
  1049. }
  1050. if (SUCCEEDED(hr))
  1051. {
  1052. hr = GetViperPackageName(szMetabasePath, &szNameForNewPackage);
  1053. }
  1054. if (SUCCEEDED(hr))
  1055. {
  1056. hr = MDConfig.MDGetIdentity(szIdentity, sizeof(szIdentity), szPwd, sizeof(szPwd));
  1057. }
  1058. if (SUCCEEDED(hr))
  1059. {
  1060. //
  1061. // Create the catalog object etc for MTS configuration
  1062. //
  1063. hr = PackageConfig.CreateCatalog();
  1064. if (FAILED(hr))
  1065. {
  1066. DBGPRINTF((DBG_CONTEXT, "Failed to call MTS Admin API. error %08x\n", hr));
  1067. }
  1068. else
  1069. {
  1070. hr = PackageConfig.CreatePackage(
  1071. szPackageID,
  1072. szNameForNewPackage,
  1073. szIdentity,
  1074. szPwd );
  1075. if (SUCCEEDED(hr))
  1076. {
  1077. hr = PackageConfig.AddComponentToPackage(
  1078. szPackageID,
  1079. szWAMCLSID);
  1080. if (FAILED(hr))
  1081. {
  1082. PackageConfig.RemovePackage(szPackageID);
  1083. }
  1084. }
  1085. }
  1086. hrPackage = hr;
  1087. }
  1088. if (SUCCEEDED(hr))
  1089. {
  1090. MDPropItem rgProp[IWMDP_MAX];
  1091. MDConfig.InitPropItemData(&rgProp[0]);
  1092. // Update WAMCLSID
  1093. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_WAMCLSID, szWAMCLSID);
  1094. // Update APPRoot
  1095. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_ROOT, szMetabasePath);
  1096. //Update AppIsolated
  1097. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_ISOLATED, 1);
  1098. //Update AppPackageName
  1099. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_PACKAGE_NAME, szNameForNewPackage);
  1100. //Update AppPackageID
  1101. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_PACKAGEID, szPackageID);
  1102. //
  1103. // in case this is an recover operation, we do not remove App Friendly Name.
  1104. //
  1105. if (!fRecover)
  1106. {
  1107. // It doesn't really make sense to set this on every isolated application.
  1108. // This will be much easier to administer globally if we allow it to be set
  1109. // at a higher level.
  1110. // MDConfig.MDSetPropItem(&rgProp[0], IWMDP_OOP_RECOVERLIMIT, APP_OOP_RECOVER_LIMIT_DEFAULT);
  1111. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_FRIENDLY_NAME, L"");
  1112. }
  1113. // Attempt to Save the metabase changes immediately. We want to ensure
  1114. // that the COM+ package is not orphaned.
  1115. hr = MDConfig.UpdateMD(rgProp, METADATA_INHERIT, szMetabasePath, fSaveMB );
  1116. if (FAILED(hr))
  1117. {
  1118. // Removed AbortUpdateMD call - we shouldn't wax the MB settings or
  1119. // we will orphan the COM+ package.
  1120. DBGPRINTF((
  1121. DBG_CONTEXT,
  1122. "Failed to set metabase properties on (%S). error == %08x\n",
  1123. szMetabasePath,
  1124. hr
  1125. ));
  1126. }
  1127. hrMetabase = hr;
  1128. }
  1129. if (FAILED(hr))
  1130. {
  1131. HRESULT hrT = NOERROR;
  1132. DBGPRINTF((DBG_CONTEXT, "Failed to create out proc application. path = %S, error = %08x\n",
  1133. szMetabasePath,
  1134. hr));
  1135. if (SUCCEEDED(hrPackage))
  1136. {
  1137. hrT = PackageConfig.RemovePackage( szPackageID);
  1138. }
  1139. if (SUCCEEDED(hrRegister))
  1140. {
  1141. hrT = g_RegistryConfig.UnRegisterCLSID(szWAMCLSID, FALSE);
  1142. if (FAILED(hrT))
  1143. {
  1144. DBGPRINTF((DBG_CONTEXT, "Rollback: Failed to UnRegisterCLSID. error = %08x\n", hr));
  1145. }
  1146. }
  1147. }
  1148. if (szWAMCLSID)
  1149. {
  1150. CoTaskMemFree(szWAMCLSID);
  1151. szWAMCLSID = NULL;
  1152. }
  1153. if (szPackageID)
  1154. {
  1155. CoTaskMemFree(szPackageID);
  1156. szWAMCLSID = NULL;
  1157. }
  1158. if (szNameForNewPackage)
  1159. {
  1160. delete [] szNameForNewPackage;
  1161. szNameForNewPackage = NULL;
  1162. }
  1163. return hr;
  1164. }
  1165. HRESULT
  1166. WamRegGlobal::CreateOutProcAppReplica(
  1167. IN LPCWSTR szMetabasePath,
  1168. IN LPCWSTR szAppName,
  1169. IN LPCWSTR szWamClsid,
  1170. IN LPCWSTR szAppId
  1171. )
  1172. /*++
  1173. Function:
  1174. Called by the DeSerialize replication method to create a
  1175. new oop application.
  1176. Arguments:
  1177. szMetabasePath
  1178. szAppName
  1179. szWamClsid
  1180. szAppId
  1181. Return:
  1182. --*/
  1183. {
  1184. HRESULT hr = NOERROR;
  1185. DBG_ASSERT(szMetabasePath);
  1186. DBG_ASSERT(szWamClsid);
  1187. DBG_ASSERT(szAppId);
  1188. //
  1189. // Register wam.dll as a new component
  1190. //
  1191. WCHAR * szProgID = NULL;
  1192. BOOL fRegisteredWam = FALSE;
  1193. hr = SzWamProgID(szMetabasePath, &szProgID);
  1194. if( SUCCEEDED(hr) )
  1195. {
  1196. DBG_ASSERT( szProgID != NULL );
  1197. hr = g_RegistryConfig.RegisterCLSID( szWamClsid,
  1198. szProgID,
  1199. FALSE
  1200. );
  1201. if( SUCCEEDED(hr) )
  1202. {
  1203. fRegisteredWam = TRUE;
  1204. }
  1205. delete [] szProgID;
  1206. szProgID = NULL;
  1207. }
  1208. if( FAILED(hr) )
  1209. {
  1210. DBGERROR(( DBG_CONTEXT,
  1211. "Failed to register wam.dll. hr=%08x\n",
  1212. hr
  1213. ));
  1214. }
  1215. //
  1216. // Get required application info
  1217. //
  1218. BOOL fGetCOMAppInfo = FALSE;
  1219. WCHAR szIdentity[MAX_PATH];
  1220. WCHAR szPwd[MAX_PATH];
  1221. WamRegMetabaseConfig MDConfig;
  1222. if( fRegisteredWam )
  1223. {
  1224. hr = MDConfig.MDGetIdentity( szIdentity,
  1225. sizeof(szIdentity),
  1226. szPwd,
  1227. sizeof(szPwd)
  1228. );
  1229. if( SUCCEEDED(hr) )
  1230. {
  1231. fGetCOMAppInfo = TRUE;
  1232. }
  1233. else
  1234. {
  1235. DBGERROR(( DBG_CONTEXT,
  1236. "Failed get required COM application info. hr=%08x\n",
  1237. hr
  1238. ));
  1239. }
  1240. }
  1241. //
  1242. // Create the COM+ application
  1243. //
  1244. if( fGetCOMAppInfo )
  1245. {
  1246. WamRegPackageConfig PackageConfig;
  1247. hr = PackageConfig.CreateCatalog();
  1248. if( SUCCEEDED(hr) )
  1249. {
  1250. hr = PackageConfig.CreatePackage(
  1251. szAppId,
  1252. szAppName,
  1253. szIdentity,
  1254. szPwd );
  1255. if( SUCCEEDED(hr) )
  1256. {
  1257. hr = PackageConfig.AddComponentToPackage(
  1258. szAppId,
  1259. szWamClsid
  1260. );
  1261. }
  1262. // On failure we might want to cleanup, but I'm not sure
  1263. // that really makes sense.
  1264. }
  1265. // At this point, we would normally set the metabase properties
  1266. // but we will let the MB replication handle that for us.
  1267. // Note: if the MB replication fails, we will be left with
  1268. // a bunch of orphaned com applications
  1269. if( FAILED(hr) )
  1270. {
  1271. DBGERROR(( DBG_CONTEXT,
  1272. "COM+ App creation failed. AppId(%S) Name(%S) "
  1273. "Clsid(%S) hr=%08x\n",
  1274. szAppId,
  1275. szAppName,
  1276. szWamClsid,
  1277. hr
  1278. ));
  1279. }
  1280. }
  1281. return hr;
  1282. }
  1283. /*===================================================================
  1284. DeleteApp
  1285. Register a WAM CLSID.
  1286. Parameter:
  1287. szMetabasePath: [in] MetabaseKey.
  1288. fDeletePackage: [in] when uninstall, this flag is true, we delete all IIS created packages.
  1289. fRemoveAppPool [in] Should the AppPoolId Property be removed
  1290. Return: HRESULT
  1291. ===================================================================*/
  1292. HRESULT WamRegGlobal::DeleteApp
  1293. (
  1294. IN LPCWSTR szMetabasePath,
  1295. IN BOOL fRecover,
  1296. IN BOOL fRemoveAppPool
  1297. )
  1298. {
  1299. WCHAR szWAMCLSID[uSizeCLSID];
  1300. WCHAR szPackageID[uSizeCLSID];
  1301. DWORD dwAppMode = eAppRunInProc;
  1302. DWORD dwCallBack;
  1303. HRESULT hr, hrRegistry;
  1304. METADATA_HANDLE hMetabase = NULL;
  1305. WamRegMetabaseConfig MDConfig;
  1306. hr = MDConfig.MDGetDWORD(szMetabasePath, MD_APP_ISOLATED, &dwAppMode);
  1307. // return immediately, no application is defined, nothing to delete.
  1308. if (hr == MD_ERROR_DATA_NOT_FOUND)
  1309. {
  1310. return NOERROR;
  1311. }
  1312. if (FAILED(hr))
  1313. {
  1314. return hr;
  1315. }
  1316. //
  1317. //Set App State to be PAUSE/DISABLE, so that after we remove the application from
  1318. //run time WAM_DICTATOR lookup table, new request won't trigger the application to
  1319. //retstart.
  1320. //WAM_DICTATOR has code to check for this state.
  1321. //
  1322. hr = MDConfig.MDSetAppState(szMetabasePath, APPSTATUS_PAUSE);
  1323. if( FAILED(hr) )
  1324. {
  1325. DBGPRINTF(( DBG_CONTEXT,
  1326. "MDSetAppState Failed hr=%08x\n",
  1327. hr
  1328. ));
  1329. }
  1330. hr = W3ServiceUtil(szMetabasePath, APPCMD_DELETE, &dwCallBack);
  1331. if( FAILED(hr) )
  1332. {
  1333. DBGPRINTF(( DBG_CONTEXT,
  1334. "W3ServiceUtil APPCMD_DELETE Failed on (%S) hr=%08x\n",
  1335. szMetabasePath,
  1336. hr
  1337. ));
  1338. }
  1339. if (dwAppMode == eAppRunOutProcIsolated)
  1340. {
  1341. // Get WAM_CLSID, and PackageID.
  1342. hr = MDConfig.MDGetIDs(szMetabasePath, szWAMCLSID, szPackageID, dwAppMode);
  1343. // Remove the WAM from the package.
  1344. if (SUCCEEDED(hr))
  1345. {
  1346. WamRegPackageConfig PackageConfig;
  1347. HRESULT hrPackage;
  1348. hr = PackageConfig.CreateCatalog();
  1349. if ( FAILED( hr))
  1350. {
  1351. DBGPRINTF(( DBG_CONTEXT,
  1352. "Failed to Create MTS catalog hr=%08x\n",
  1353. hr));
  1354. }
  1355. else
  1356. {
  1357. hr = PackageConfig.RemoveComponentFromPackage(szPackageID,
  1358. szWAMCLSID,
  1359. dwAppMode);
  1360. if (FAILED(hr))
  1361. {
  1362. DBGPRINTF((DBG_CONTEXT, "Failed to remove component from package, \npackageid = %S, wamclsid = %S, hr = %08x\n",
  1363. szPackageID,
  1364. szWAMCLSID,
  1365. hr));
  1366. }
  1367. }
  1368. hrPackage = hr;
  1369. }
  1370. // Unregister WAM
  1371. hr = g_RegistryConfig.UnRegisterCLSID(szWAMCLSID, FALSE);
  1372. if (FAILED(hr))
  1373. {
  1374. DBGPRINTF((DBG_CONTEXT, "Failed to UnRegister WAMCLSID(%S), hr = %08x\n",
  1375. szWAMCLSID,
  1376. hr));
  1377. hrRegistry = hr;
  1378. }
  1379. }
  1380. if (SUCCEEDED(hr))
  1381. {
  1382. BOOL fChanged = FALSE;
  1383. MDPropItem rgProp[IWMDP_MAX];
  1384. MDConfig.InitPropItemData(&rgProp[0]);
  1385. if (dwAppMode == static_cast<DWORD>(eAppRunOutProcIsolated))
  1386. {
  1387. // Delete AppPackageName. (Inherited from W3SVC)
  1388. // Delete AppPackageID. (Inherited from W3SVC)
  1389. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_PACKAGE_NAME);
  1390. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_PACKAGEID);
  1391. // Delete WAMCLSID
  1392. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_WAMCLSID);
  1393. if (TsIsNtServer() || TsIsNtWksta())
  1394. {
  1395. MDConfig.MDSetPropItem(&rgProp[0], IWMDP_LAST_OUTPROC_PID, szPackageID);
  1396. }
  1397. fChanged = TRUE;
  1398. }
  1399. // If this is DeleteRecoverable mode, we do not delete APP_ROOT, APP_ISOLATED,
  1400. // OOP_RECOVERLIMIT and APP_STATE.
  1401. if (!fRecover)
  1402. {
  1403. // Delete AppFriendlyName
  1404. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_FRIENDLY_NAME);
  1405. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_ROOT);
  1406. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_ISOLATED);
  1407. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_APPSTATE);
  1408. if (fRemoveAppPool)
  1409. {
  1410. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_OOP_APP_APPPOOL_ID);
  1411. }
  1412. if (dwAppMode == static_cast<DWORD>(eAppRunOutProcIsolated))
  1413. {
  1414. // This will only be set for older isolated applications.
  1415. // Since we ignore the result of UpdateMD below, it is ok
  1416. // for us to try to delete the property.
  1417. MDConfig.MDDeletePropItem(&rgProp[0], IWMDP_OOP_RECOVERLIMIT);
  1418. }
  1419. fChanged = TRUE;
  1420. }
  1421. // For DeleteRecover operation, and the app is not outproc isolated,
  1422. // No property changes, therefore, no need to update metabase.
  1423. if (fChanged)
  1424. {
  1425. MDConfig.UpdateMD(rgProp, METADATA_NO_ATTRIBUTES, szMetabasePath);
  1426. }
  1427. }
  1428. return NOERROR;
  1429. }
  1430. /*===================================================================
  1431. RecoverApp
  1432. Recover an application based on MD_APP_ISOLATED property.
  1433. Parameter:
  1434. szMetabasePath: [in] MetabaseKey.
  1435. Return: HRESULT
  1436. ===================================================================*/
  1437. HRESULT WamRegGlobal::RecoverApp
  1438. (
  1439. IN LPCWSTR szMetabasePath,
  1440. IN BOOL fForceRecover
  1441. )
  1442. {
  1443. HRESULT hr = NOERROR;
  1444. DWORD dwAppMode = 0;
  1445. WamRegMetabaseConfig MDConfig;
  1446. hr = MDConfig.MDGetDWORD(szMetabasePath, MD_APP_ISOLATED, &dwAppMode);
  1447. if (hr == MD_ERROR_DATA_NOT_FOUND)
  1448. {
  1449. hr = NOERROR;
  1450. }
  1451. else
  1452. {
  1453. if (SUCCEEDED(hr))
  1454. {
  1455. if (fForceRecover)
  1456. {
  1457. if (dwAppMode == static_cast<DWORD>(eAppRunOutProcInDefaultPool))
  1458. {
  1459. hr = CreatePooledApp(szMetabasePath, FALSE);
  1460. }
  1461. else if (dwAppMode == static_cast<DWORD>(eAppRunInProc))
  1462. {
  1463. hr = CreatePooledApp(szMetabasePath, TRUE);
  1464. }
  1465. else
  1466. {
  1467. hr = CreateOutProcApp(szMetabasePath);
  1468. }
  1469. }
  1470. if (SUCCEEDED(hr))
  1471. {
  1472. HRESULT hrT = NOERROR;
  1473. hrT = MDConfig.MDRemoveProperty(szMetabasePath, MD_APP_STATE, DWORD_METADATA);
  1474. if (FAILED(hrT))
  1475. {
  1476. if (hrT != MD_ERROR_DATA_NOT_FOUND)
  1477. {
  1478. DBGPRINTF((DBG_CONTEXT, "Failed to remove MD_APP_STATE from path %S, hr = %08x\n",
  1479. szMetabasePath,
  1480. hrT));
  1481. }
  1482. }
  1483. }
  1484. }
  1485. }
  1486. return hr;
  1487. }
  1488. /*============================================================================
  1489. W3ServiceUtil
  1490. sink function that unload/shutdown/querystatus of an application currently in the runtime
  1491. table.
  1492. Parameter:
  1493. szMDPath the application Path.
  1494. dwCommand The command.
  1495. pdwCallBackResult Contains the HRESULT from w3svc.dll.
  1496. ==============================================================================*/
  1497. HRESULT WamRegGlobal::W3ServiceUtil
  1498. (
  1499. IN LPCWSTR szMDPath,
  1500. IN DWORD dwCommand,
  1501. OUT DWORD* pdwCallBackResult
  1502. )
  1503. {
  1504. HRESULT hr = NOERROR;
  1505. if (g_pfnW3ServiceSink)
  1506. {
  1507. #ifndef _IIS_6_0
  1508. // DBCS enabling for IIS 5.1
  1509. INT cSize = wcslen(szMDPath)*2 + 1;
  1510. CHAR *szPathT = new CHAR[cSize];
  1511. if (szPathT)
  1512. {
  1513. WideCharToMultiByte(0, 0, szMDPath, -1, szPathT, cSize, NULL, NULL);
  1514. hr = g_pfnW3ServiceSink(szPathT,
  1515. dwCommand,
  1516. pdwCallBackResult);
  1517. }
  1518. else
  1519. {
  1520. hr = E_OUTOFMEMORY;
  1521. }
  1522. delete [] szPathT;
  1523. #else
  1524. //
  1525. // IIS 6's implementation uses UNICODE directly, so
  1526. // we'll avoid the WideCharToMultiByte nonsense and
  1527. // just cast the path to fit the function arguments.
  1528. //
  1529. // We're not changing the function prototype purely
  1530. // because we are minimizing code churn in this module.
  1531. //
  1532. // IIS 6 gets the unicode directly
  1533. hr = g_pfnW3ServiceSink(reinterpret_cast<LPCSTR>(szMDPath),
  1534. dwCommand,
  1535. pdwCallBackResult);
  1536. #endif // _IIS_6_0
  1537. }
  1538. else
  1539. {
  1540. *pdwCallBackResult = APPSTATUS_NOW3SVC;
  1541. hr = NOERROR;
  1542. }
  1543. return hr;
  1544. }