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.

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