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.

913 lines
20 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2001
  5. //
  6. // File: capool.cxx
  7. //
  8. // Contents: Contains methods for CIISApplicationPool object
  9. //
  10. // History: 11-09-2000 BrentMid Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "iisext.hxx"
  14. #pragma hdrstop
  15. //
  16. // Period to sleep while waiting for service to attain desired state
  17. //
  18. #define SLEEP_INTERVAL (500L)
  19. #define MAX_SLEEP_INST (60000) // For an instance
  20. // Class CIISApplicationPool
  21. DEFINE_IPrivateDispatch_Implementation(CIISApplicationPool)
  22. DEFINE_DELEGATING_IDispatch_Implementation(CIISApplicationPool)
  23. DEFINE_CONTAINED_IADs_Implementation(CIISApplicationPool)
  24. DEFINE_IADsExtension_Implementation(CIISApplicationPool)
  25. CIISApplicationPool::CIISApplicationPool():
  26. _pUnkOuter(NULL),
  27. _pADs(NULL),
  28. _pszServerName(NULL),
  29. _pszPoolName(NULL),
  30. _pszMetaBasePath(NULL),
  31. _pAdminBase(NULL),
  32. _pDispMgr(NULL),
  33. _fDispInitialized(FALSE)
  34. {
  35. ENLIST_TRACKING(CIISApplicationPool);
  36. }
  37. HRESULT
  38. CIISApplicationPool::CreateApplicationPool(
  39. IUnknown *pUnkOuter,
  40. REFIID riid,
  41. void **ppvObj
  42. )
  43. {
  44. CCredentials Credentials;
  45. CIISApplicationPool FAR * pApplicationPool = NULL;
  46. HRESULT hr = S_OK;
  47. BSTR bstrAdsPath = NULL;
  48. OBJECTINFO ObjectInfo;
  49. POBJECTINFO pObjectInfo = &ObjectInfo;
  50. CLexer * pLexer = NULL;
  51. LPWSTR pszIISPathName = NULL;
  52. LPWSTR *pszPoolName;
  53. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  54. hr = AllocateApplicationPoolObject(pUnkOuter, Credentials, &pApplicationPool);
  55. BAIL_ON_FAILURE(hr);
  56. //
  57. // get ServerName and pszPath
  58. //
  59. hr = pApplicationPool->_pADs->get_ADsPath(&bstrAdsPath);
  60. BAIL_ON_FAILURE(hr);
  61. pLexer = new CLexer();
  62. hr = pLexer->Initialize(bstrAdsPath);
  63. BAIL_ON_FAILURE(hr);
  64. //
  65. // Parse the pathname
  66. //
  67. hr = ADsObject(pLexer, pObjectInfo);
  68. BAIL_ON_FAILURE(hr);
  69. pszIISPathName = AllocADsStr(bstrAdsPath);
  70. if (!pszIISPathName) {
  71. hr = E_OUTOFMEMORY;
  72. BAIL_ON_FAILURE(hr);
  73. }
  74. *pszIISPathName = L'\0';
  75. hr = BuildIISPathFromADsPath(
  76. pObjectInfo,
  77. pszIISPathName
  78. );
  79. BAIL_ON_FAILURE(hr);
  80. pszPoolName = &(ObjectInfo.ComponentArray[ObjectInfo.NumComponents-1].szComponent);
  81. hr = pApplicationPool->InitializeApplicationPoolObject(
  82. pObjectInfo->TreeName,
  83. pszIISPathName,
  84. *pszPoolName );
  85. BAIL_ON_FAILURE(hr);
  86. //
  87. // pass non-delegating IUnknown back to the aggregator
  88. //
  89. *ppvObj = (INonDelegatingUnknown FAR *) pApplicationPool;
  90. if (bstrAdsPath)
  91. {
  92. ADsFreeString(bstrAdsPath);
  93. }
  94. if (pLexer) {
  95. delete pLexer;
  96. }
  97. if (pszIISPathName ) {
  98. FreeADsStr( pszIISPathName );
  99. }
  100. FreeObjectInfo( &ObjectInfo );
  101. RRETURN(hr);
  102. error:
  103. if (bstrAdsPath) {
  104. ADsFreeString(bstrAdsPath);
  105. }
  106. if (pLexer) {
  107. delete pLexer;
  108. }
  109. if (pszIISPathName ) {
  110. FreeADsStr( pszIISPathName );
  111. }
  112. FreeObjectInfo( &ObjectInfo );
  113. *ppvObj = NULL;
  114. delete pApplicationPool;
  115. RRETURN(hr);
  116. }
  117. CIISApplicationPool::~CIISApplicationPool( )
  118. {
  119. if (_pszServerName) {
  120. FreeADsStr(_pszServerName);
  121. }
  122. if (_pszMetaBasePath) {
  123. FreeADsStr(_pszMetaBasePath);
  124. }
  125. if (_pszPoolName) {
  126. FreeADsStr(_pszPoolName);
  127. }
  128. delete _pDispMgr;
  129. }
  130. STDMETHODIMP
  131. CIISApplicationPool::QueryInterface(
  132. REFIID iid,
  133. LPVOID FAR* ppv
  134. )
  135. {
  136. HRESULT hr = S_OK;
  137. hr = _pUnkOuter->QueryInterface(iid,ppv);
  138. RRETURN(hr);
  139. }
  140. HRESULT
  141. CIISApplicationPool::AllocateApplicationPoolObject(
  142. IUnknown *pUnkOuter,
  143. CCredentials& Credentials,
  144. CIISApplicationPool ** ppApplicationPool
  145. )
  146. {
  147. CIISApplicationPool FAR * pApplicationPool = NULL;
  148. IADs FAR * pADs = NULL;
  149. CAggregateeDispMgr FAR * pDispMgr = NULL;
  150. HRESULT hr = S_OK;
  151. pApplicationPool = new CIISApplicationPool();
  152. if (pApplicationPool == NULL) {
  153. hr = E_OUTOFMEMORY;
  154. }
  155. BAIL_ON_FAILURE(hr);
  156. pDispMgr = new CAggregateeDispMgr;
  157. if (pDispMgr == NULL) {
  158. hr = E_OUTOFMEMORY;
  159. }
  160. BAIL_ON_FAILURE(hr);
  161. hr = pDispMgr->LoadTypeInfoEntry(
  162. LIBID_IISExt,
  163. IID_IISApplicationPool,
  164. (IISApplicationPool *)pApplicationPool,
  165. DISPID_REGULAR
  166. );
  167. BAIL_ON_FAILURE(hr);
  168. //
  169. // Store the IADs Pointer, but again do NOT ref-count
  170. // this pointer - we keep the pointer around, but do
  171. // a release immediately.
  172. //
  173. hr = pUnkOuter->QueryInterface(IID_IADs, (void **)&pADs);
  174. pADs->Release();
  175. pApplicationPool->_pADs = pADs;
  176. //
  177. // Store the pointer to the pUnkOuter object
  178. // AND DO NOT add ref this pointer
  179. //
  180. pApplicationPool->_pUnkOuter = pUnkOuter;
  181. pApplicationPool->_Credentials = Credentials;
  182. pApplicationPool->_pDispMgr = pDispMgr;
  183. *ppApplicationPool = pApplicationPool;
  184. RRETURN(hr);
  185. error:
  186. delete pDispMgr;
  187. delete pApplicationPool;
  188. RRETURN(hr);
  189. }
  190. HRESULT
  191. CIISApplicationPool::InitializeApplicationPoolObject(
  192. LPWSTR pszServerName,
  193. LPWSTR pszPath,
  194. LPWSTR pszPoolName
  195. )
  196. {
  197. HRESULT hr = S_OK;
  198. if (pszServerName) {
  199. _pszServerName = AllocADsStr(pszServerName);
  200. if (!_pszServerName) {
  201. hr = E_OUTOFMEMORY;
  202. BAIL_ON_FAILURE(hr);
  203. }
  204. }
  205. if (pszPath) {
  206. _pszMetaBasePath = AllocADsStr(pszPath);
  207. if (!_pszMetaBasePath) {
  208. hr = E_OUTOFMEMORY;
  209. BAIL_ON_FAILURE(hr);
  210. }
  211. }
  212. if (pszPoolName) {
  213. _pszPoolName = AllocADsStr(pszPoolName);
  214. if (!_pszPoolName) {
  215. hr = E_OUTOFMEMORY;
  216. BAIL_ON_FAILURE(hr);
  217. }
  218. }
  219. hr = InitServerInfo(pszServerName, &_pAdminBase);
  220. BAIL_ON_FAILURE(hr);
  221. error:
  222. RRETURN(hr);
  223. }
  224. STDMETHODIMP
  225. CIISApplicationPool::ADSIInitializeDispatchManager(
  226. long dwExtensionId
  227. )
  228. {
  229. HRESULT hr = S_OK;
  230. if (_fDispInitialized) {
  231. RRETURN(E_FAIL);
  232. }
  233. hr = _pDispMgr->InitializeDispMgr(dwExtensionId);
  234. if (SUCCEEDED(hr)) {
  235. _fDispInitialized = TRUE;
  236. }
  237. RRETURN(hr);
  238. }
  239. STDMETHODIMP
  240. CIISApplicationPool::ADSIInitializeObject(
  241. THIS_ BSTR lpszUserName,
  242. BSTR lpszPassword,
  243. long lnReserved
  244. )
  245. {
  246. CCredentials NewCredentials(lpszUserName, lpszPassword, lnReserved);
  247. _Credentials = NewCredentials;
  248. RRETURN(S_OK);
  249. }
  250. STDMETHODIMP
  251. CIISApplicationPool::ADSIReleaseObject()
  252. {
  253. delete this;
  254. RRETURN(S_OK);
  255. }
  256. STDMETHODIMP
  257. CIISApplicationPool::NonDelegatingQueryInterface(
  258. REFIID iid,
  259. LPVOID FAR* ppv
  260. )
  261. {
  262. ASSERT(ppv);
  263. if (IsEqualIID(iid, IID_IISApplicationPool)) {
  264. *ppv = (IADsUser FAR *) this;
  265. } else if (IsEqualIID(iid, IID_IADsExtension)) {
  266. *ppv = (IADsExtension FAR *) this;
  267. } else if (IsEqualIID(iid, IID_IUnknown)) {
  268. //
  269. // probably not needed since our 3rd party extension does not stand
  270. // alone and provider does not ask for this, but to be safe
  271. //
  272. *ppv = (INonDelegatingUnknown FAR *) this;
  273. } else {
  274. *ppv = NULL;
  275. return E_NOINTERFACE;
  276. }
  277. //
  278. // Delegating AddRef to aggregator for IADsExtesnion and IISApplicationPool.
  279. // AddRef on itself for IPrivateUnknown. (both tested.)
  280. //
  281. ((IUnknown *) (*ppv)) -> AddRef();
  282. return S_OK;
  283. }
  284. //
  285. // IADsExtension::Operate()
  286. //
  287. STDMETHODIMP
  288. CIISApplicationPool::Operate(
  289. THIS_ DWORD dwCode,
  290. VARIANT varUserName,
  291. VARIANT varPassword,
  292. VARIANT varFlags
  293. )
  294. {
  295. RRETURN(E_NOTIMPL);
  296. }
  297. //
  298. // Helper routine for ExecMethod.
  299. // Gets Win32 error from the metabase
  300. //
  301. HRESULT
  302. CIISApplicationPool::IISGetAppPoolWin32Error(
  303. METADATA_HANDLE hObjHandle,
  304. HRESULT* phrError)
  305. {
  306. DBG_ASSERT(phrError != NULL);
  307. long lWin32Error = 0;
  308. DWORD dwLen;
  309. METADATA_RECORD mr = {
  310. MD_WIN32_ERROR,
  311. METADATA_NO_ATTRIBUTES,
  312. IIS_MD_UT_SERVER,
  313. DWORD_METADATA,
  314. sizeof(DWORD),
  315. (unsigned char*)&lWin32Error,
  316. 0
  317. };
  318. HRESULT hr = _pAdminBase->GetData(
  319. hObjHandle,
  320. _pszMetaBasePath,
  321. &mr,
  322. &dwLen);
  323. if(hr == MD_ERROR_DATA_NOT_FOUND)
  324. {
  325. hr = S_FALSE;
  326. }
  327. //
  328. // Set out param
  329. //
  330. *phrError = HRESULT_FROM_WIN32(lWin32Error);
  331. RRETURN(hr);
  332. }
  333. //
  334. // Helper Functions
  335. //
  336. HRESULT
  337. CIISApplicationPool::IISGetAppPoolState(
  338. METADATA_HANDLE hObjHandle,
  339. PDWORD pdwState
  340. )
  341. {
  342. HRESULT hr = S_OK;
  343. DWORD dwBufferSize = sizeof(DWORD);
  344. METADATA_RECORD mdrMDData;
  345. LPBYTE pBuffer = (LPBYTE)pdwState;
  346. MD_SET_DATA_RECORD(&mdrMDData,
  347. MD_APPPOOL_STATE, // server state
  348. METADATA_NO_ATTRIBUTES,
  349. IIS_MD_UT_SERVER,
  350. DWORD_METADATA,
  351. dwBufferSize,
  352. pBuffer);
  353. hr = InitServerInfo(_pszServerName, &_pAdminBase);
  354. BAIL_ON_FAILURE(hr);
  355. hr = _pAdminBase->GetData(
  356. hObjHandle,
  357. _pszMetaBasePath,
  358. &mdrMDData,
  359. &dwBufferSize
  360. );
  361. if (FAILED(hr)) {
  362. if( hr == MD_ERROR_DATA_NOT_FOUND )
  363. {
  364. //
  365. // If the data is not there, but the path exists, then the
  366. // most likely cause is that the app pool is not running and
  367. // this object was just created.
  368. //
  369. // Since MD_APPPOOL_STATE would be set as stopped if the
  370. // app pool were running when the key is added, we'll just
  371. // say that it's stopped.
  372. //
  373. *pdwState = MD_APPPOOL_STATE_STOPPED;
  374. hr = S_FALSE;
  375. }
  376. else if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) ||
  377. ((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) &&
  378. (HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) ||
  379. hr == RPC_E_DISCONNECTED || hr == MD_ERROR_SECURE_CHANNEL_FAILURE) {
  380. hr = ReCacheAdminBase(_pszServerName, &_pAdminBase);
  381. BAIL_ON_FAILURE(hr);
  382. hr = _pAdminBase->GetData(
  383. hObjHandle,
  384. _pszMetaBasePath,
  385. &mdrMDData,
  386. &dwBufferSize
  387. );
  388. if (FAILED(hr))
  389. {
  390. if( hr == MD_ERROR_DATA_NOT_FOUND )
  391. {
  392. *pdwState = MD_APPPOOL_STATE_STOPPED;
  393. hr = S_FALSE;
  394. }
  395. }
  396. BAIL_ON_FAILURE(hr);
  397. }
  398. else
  399. {
  400. BAIL_ON_FAILURE(hr);
  401. }
  402. }
  403. error:
  404. RRETURN(hr);
  405. }
  406. HRESULT
  407. CIISApplicationPool::IISSetCommand(
  408. METADATA_HANDLE hObjHandle,
  409. DWORD dwControl
  410. )
  411. {
  412. HRESULT hr = S_OK;
  413. DWORD dwBufferSize = sizeof(DWORD);
  414. METADATA_RECORD mdrMDData;
  415. LPBYTE pBuffer = (LPBYTE)&dwControl;
  416. MD_SET_DATA_RECORD(&mdrMDData,
  417. MD_APPPOOL_COMMAND, // app pool command
  418. METADATA_NO_ATTRIBUTES,
  419. IIS_MD_UT_SERVER,
  420. DWORD_METADATA,
  421. dwBufferSize,
  422. pBuffer);
  423. hr = _pAdminBase->SetData(
  424. hObjHandle,
  425. L"",
  426. &mdrMDData
  427. );
  428. BAIL_ON_FAILURE(hr);
  429. error:
  430. RRETURN(hr);
  431. }
  432. //
  433. // Helper routine for ExecMethod.
  434. // Clears Win32 error
  435. //
  436. HRESULT
  437. CIISApplicationPool::IISClearAppPoolWin32Error(
  438. METADATA_HANDLE hObjHandle )
  439. {
  440. long lWin32Error = 0;
  441. METADATA_RECORD mr = {
  442. MD_WIN32_ERROR,
  443. METADATA_VOLATILE,
  444. IIS_MD_UT_SERVER,
  445. DWORD_METADATA,
  446. sizeof(DWORD),
  447. (unsigned char*)&lWin32Error,
  448. 0
  449. };
  450. HRESULT hr = _pAdminBase->SetData(
  451. hObjHandle,
  452. L"",
  453. &mr );
  454. RRETURN(hr);
  455. }
  456. HRESULT
  457. CIISApplicationPool::IISControlAppPool(
  458. DWORD dwControl
  459. )
  460. {
  461. METADATA_HANDLE hObjHandle = NULL;
  462. DWORD dwTargetState;
  463. DWORD dwState = 0;
  464. DWORD dwSleepTotal = 0L;
  465. HRESULT hr = S_OK;
  466. HRESULT hrMbNode = S_OK;
  467. switch(dwControl)
  468. {
  469. case MD_APPPOOL_COMMAND_STOP:
  470. dwTargetState = MD_APPPOOL_STATE_STOPPED;
  471. break;
  472. case MD_SERVER_COMMAND_START:
  473. dwTargetState = MD_APPPOOL_STATE_STARTED;
  474. break;
  475. default:
  476. hr = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
  477. BAIL_ON_FAILURE(hr);
  478. }
  479. hr = IISGetAppPoolState(METADATA_MASTER_ROOT_HANDLE, &dwState);
  480. BAIL_ON_FAILURE(hr);
  481. if (dwState == dwTargetState) {
  482. RRETURN (hr);
  483. }
  484. //
  485. // Write the command to the metabase
  486. //
  487. hr = OpenAdminBaseKey(
  488. _pszServerName,
  489. _pszMetaBasePath,
  490. METADATA_PERMISSION_WRITE,
  491. &_pAdminBase,
  492. &hObjHandle
  493. );
  494. BAIL_ON_FAILURE(hr);
  495. hr = IISClearAppPoolWin32Error(hObjHandle);
  496. BAIL_ON_FAILURE(hr);
  497. hr = IISSetCommand(hObjHandle, dwControl);
  498. BAIL_ON_FAILURE(hr);
  499. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  500. while (dwSleepTotal < MAX_SLEEP_INST) {
  501. hr = IISGetAppPoolState(METADATA_MASTER_ROOT_HANDLE, &dwState);
  502. BAIL_ON_FAILURE(hr);
  503. hrMbNode = 0;
  504. hr = IISGetAppPoolWin32Error(METADATA_MASTER_ROOT_HANDLE, &hrMbNode);
  505. BAIL_ON_FAILURE(hr);
  506. //
  507. // Done one way or another
  508. //
  509. if (dwState == dwTargetState)
  510. {
  511. break;
  512. }
  513. // check to see if there was a Win32 error from the app pool
  514. if (FAILED(hrMbNode))
  515. {
  516. hr = hrMbNode;
  517. BAIL_ON_FAILURE(hr);
  518. }
  519. //
  520. // Still waiting...
  521. //
  522. ::Sleep(SLEEP_INTERVAL);
  523. dwSleepTotal += SLEEP_INTERVAL;
  524. }
  525. if (dwSleepTotal >= MAX_SLEEP_INST)
  526. {
  527. //
  528. // Timed out. If there is a real error in the metabase
  529. // use it, otherwise use a generic timeout error
  530. //
  531. hr = HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT);
  532. }
  533. error :
  534. if (_pAdminBase && hObjHandle) {
  535. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  536. }
  537. RRETURN (hr);
  538. }
  539. STDMETHODIMP
  540. CIISApplicationPool::Start(THIS)
  541. {
  542. RRETURN(IISControlAppPool(MD_APPPOOL_COMMAND_START));
  543. }
  544. STDMETHODIMP
  545. CIISApplicationPool::Stop(THIS)
  546. {
  547. RRETURN(IISControlAppPool(MD_APPPOOL_COMMAND_STOP));
  548. }
  549. STDMETHODIMP
  550. CIISApplicationPool::Recycle(THIS)
  551. {
  552. HRESULT hr = S_OK;
  553. COSERVERINFO csiName;
  554. COSERVERINFO *pcsiParam = &csiName;
  555. IClassFactory * pcsfFactory = NULL;
  556. IIISApplicationAdmin * pAppAdmin = NULL;
  557. memset(pcsiParam, 0, sizeof(COSERVERINFO));
  558. //
  559. // special case to handle "localhost" to work-around ole32 bug
  560. //
  561. if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) {
  562. pcsiParam->pwszName = NULL;
  563. }
  564. else {
  565. pcsiParam->pwszName = _pszServerName;
  566. }
  567. csiName.pAuthInfo = NULL;
  568. pcsiParam = &csiName;
  569. hr = CoGetClassObject(
  570. CLSID_WamAdmin,
  571. CLSCTX_SERVER,
  572. pcsiParam,
  573. IID_IClassFactory,
  574. (void**) &pcsfFactory
  575. );
  576. BAIL_ON_FAILURE(hr);
  577. hr = pcsfFactory->CreateInstance(
  578. NULL,
  579. IID_IIISApplicationAdmin,
  580. (void **) &pAppAdmin
  581. );
  582. BAIL_ON_FAILURE(hr);
  583. hr = pAppAdmin->RecycleApplicationPool( _pszPoolName );
  584. BAIL_ON_FAILURE(hr);
  585. error:
  586. if (pcsfFactory) {
  587. pcsfFactory->Release();
  588. }
  589. if (pAppAdmin) {
  590. pAppAdmin->Release();
  591. }
  592. RRETURN(hr);
  593. }
  594. STDMETHODIMP
  595. CIISApplicationPool::EnumAppsInPool(
  596. VARIANT FAR* pvBuffer
  597. )
  598. {
  599. HRESULT hr = S_OK;
  600. COSERVERINFO csiName;
  601. COSERVERINFO *pcsiParam = &csiName;
  602. IClassFactory * pcsfFactory = NULL;
  603. IIISApplicationAdmin * pAppAdmin = NULL;
  604. BSTR bstr = NULL;
  605. memset(pcsiParam, 0, sizeof(COSERVERINFO));
  606. //
  607. // special case to handle "localhost" to work-around ole32 bug
  608. //
  609. if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) {
  610. pcsiParam->pwszName = NULL;
  611. }
  612. else {
  613. pcsiParam->pwszName = _pszServerName;
  614. }
  615. csiName.pAuthInfo = NULL;
  616. pcsiParam = &csiName;
  617. hr = CoGetClassObject(
  618. CLSID_WamAdmin,
  619. CLSCTX_SERVER,
  620. pcsiParam,
  621. IID_IClassFactory,
  622. (void**) &pcsfFactory
  623. );
  624. BAIL_ON_FAILURE(hr);
  625. hr = pcsfFactory->CreateInstance(
  626. NULL,
  627. IID_IIISApplicationAdmin,
  628. (void **) &pAppAdmin
  629. );
  630. BAIL_ON_FAILURE(hr);
  631. hr = pAppAdmin->EnumerateApplicationsInPool( _pszPoolName, &bstr );
  632. BAIL_ON_FAILURE(hr);
  633. hr = MakeVariantFromStringArray( (LPWSTR)bstr, pvBuffer);
  634. BAIL_ON_FAILURE(hr);
  635. error:
  636. if (pcsfFactory) {
  637. pcsfFactory->Release();
  638. }
  639. if (pAppAdmin) {
  640. pAppAdmin->Release();
  641. }
  642. RRETURN(hr);
  643. }
  644. HRESULT
  645. CIISApplicationPool::MakeVariantFromStringArray(
  646. LPWSTR pszList,
  647. VARIANT *pvVariant
  648. )
  649. {
  650. HRESULT hr = S_OK;
  651. SAFEARRAY *aList = NULL;
  652. SAFEARRAYBOUND aBound;
  653. LPWSTR pszStrList;
  654. WCHAR wchPath[MAX_PATH];
  655. if ( (pszList != NULL) && (0 != wcslen(pszList)) )
  656. {
  657. long nCount = 0;
  658. long i = 0;
  659. pszStrList = pszList;
  660. if (*pszStrList == L'\0') {
  661. nCount = 1;
  662. pszStrList++;
  663. }
  664. while (*pszStrList != L'\0') {
  665. while (*pszStrList != L'\0') {
  666. pszStrList++;
  667. }
  668. nCount++;
  669. pszStrList++;
  670. }
  671. aBound.lLbound = 0;
  672. aBound.cElements = nCount;
  673. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  674. if ( aList == NULL )
  675. {
  676. hr = E_OUTOFMEMORY;
  677. BAIL_ON_FAILURE(hr);
  678. }
  679. pszStrList = pszList;
  680. for (i = 0; i < nCount; i++ )
  681. {
  682. VARIANT v;
  683. VariantInit(&v);
  684. V_VT(&v) = VT_BSTR;
  685. hr = ADsAllocString( pszStrList, &(V_BSTR(&v)));
  686. BAIL_ON_FAILURE(hr);
  687. hr = SafeArrayPutElement( aList, &i, &v );
  688. VariantClear(&v);
  689. BAIL_ON_FAILURE(hr);
  690. pszStrList += wcslen(pszStrList) + 1;
  691. }
  692. VariantInit( pvVariant );
  693. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  694. V_ARRAY(pvVariant) = aList;
  695. }
  696. else
  697. {
  698. aBound.lLbound = 0;
  699. aBound.cElements = 0;
  700. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  701. if ( aList == NULL )
  702. {
  703. hr = E_OUTOFMEMORY;
  704. BAIL_ON_FAILURE(hr);
  705. }
  706. VariantInit( pvVariant );
  707. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  708. V_ARRAY(pvVariant) = aList;
  709. }
  710. return S_OK;
  711. error:
  712. if ( aList )
  713. SafeArrayDestroy( aList );
  714. return hr;
  715. }