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.

630 lines
16 KiB

  1. // NextLink.cpp : Implementation of CNextLink
  2. #include "stdafx.h"
  3. #include "NxtLnk.h"
  4. #include "NextLink.h"
  5. #define MAX_RESSTRINGSIZE 512
  6. CNextLink::LinkFileMapT CNextLink::s_linkFileMap;
  7. /////////////////////////////////////////////////////////////////////////////
  8. // CNextLink
  9. STDMETHODIMP CNextLink::InterfaceSupportsErrorInfo(REFIID riid)
  10. {
  11. static const IID* arr[] =
  12. {
  13. &IID_INextLink,
  14. };
  15. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  16. {
  17. if (InlineIsEqualGUID(*arr[i],riid))
  18. return S_OK;
  19. }
  20. return S_FALSE;
  21. }
  22. STDMETHODIMP CNextLink::get_GetNextURL(BSTR bstrLinkFile, BSTR * pVal)
  23. {
  24. SCODE rc = E_FAIL;
  25. try
  26. {
  27. CLinkFilePtr pLinkFile;
  28. String strPage;
  29. if ( GetFileAndPage( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETNEXTURL, bstrLinkFile, pLinkFile, strPage ) )
  30. {
  31. if ( pLinkFile.IsValid() )
  32. {
  33. CReader rdr(*pLinkFile);
  34. CLinkPtr pLink = pLinkFile->NextLink( strPage );
  35. if ( pLink.IsValid() )
  36. {
  37. if ( pVal )
  38. {
  39. if ( *pVal )
  40. {
  41. ::SysFreeString( *pVal );
  42. }
  43. HRESULT hr;
  44. CMBCSToWChar convStr;
  45. if (hr = convStr.Init(pLink->Link().c_str(),
  46. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  47. throw _com_error(hr);
  48. }
  49. *pVal = ::SysAllocString(convStr.GetString());
  50. THROW_IF_NULL(*pVal);
  51. rc = S_OK;
  52. }
  53. else
  54. {
  55. rc = E_POINTER;
  56. }
  57. }
  58. }
  59. }
  60. }
  61. catch ( _com_error& ce )
  62. {
  63. rc = ce.Error();
  64. }
  65. catch ( ... )
  66. {
  67. rc = E_FAIL;
  68. }
  69. return rc;
  70. }
  71. STDMETHODIMP CNextLink::get_GetNextDescription(BSTR bstrLinkFile, BSTR * pVal)
  72. {
  73. SCODE rc = E_FAIL;
  74. try
  75. {
  76. CLinkFilePtr pLinkFile;
  77. String strPage;
  78. if ( GetFileAndPage( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETNEXTDESCRIPTION, bstrLinkFile, pLinkFile, strPage ) )
  79. {
  80. if ( pLinkFile.IsValid() )
  81. {
  82. CReader rdr(*pLinkFile);
  83. CLinkPtr pLink = pLinkFile->NextLink( strPage );
  84. if ( pLink.IsValid() )
  85. {
  86. if ( pVal )
  87. {
  88. if ( *pVal )
  89. {
  90. ::SysFreeString( *pVal );
  91. }
  92. HRESULT hr;
  93. CMBCSToWChar convStr;
  94. if (hr = convStr.Init(pLink->Desc().c_str(),
  95. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  96. throw _com_error(hr);
  97. }
  98. *pVal = ::SysAllocString(convStr.GetString());
  99. THROW_IF_NULL(*pVal);
  100. rc = S_OK;
  101. }
  102. else
  103. {
  104. rc = E_POINTER;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. catch ( _com_error& ce )
  111. {
  112. rc = ce.Error();
  113. }
  114. catch ( ... )
  115. {
  116. rc = E_FAIL;
  117. }
  118. return rc;
  119. }
  120. STDMETHODIMP CNextLink::get_GetPreviousURL(BSTR bstrLinkFile, BSTR * pVal)
  121. {
  122. SCODE rc = E_FAIL;
  123. try
  124. {
  125. CLinkFilePtr pLinkFile;
  126. String strPage;
  127. if ( GetFileAndPage( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETPREVIOUSURL, bstrLinkFile, pLinkFile, strPage ) )
  128. {
  129. if ( pLinkFile.IsValid() )
  130. {
  131. CReader rdr(*pLinkFile);
  132. CLinkPtr pLink = pLinkFile->PreviousLink( strPage );
  133. if ( pLink.IsValid() )
  134. {
  135. if ( pVal )
  136. {
  137. if ( *pVal )
  138. {
  139. ::SysFreeString( *pVal );
  140. }
  141. HRESULT hr;
  142. CMBCSToWChar convStr;
  143. if (hr = convStr.Init(pLink->Link().c_str(),
  144. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  145. throw _com_error(hr);
  146. }
  147. *pVal = ::SysAllocString(convStr.GetString());
  148. THROW_IF_NULL( *pVal );
  149. rc = S_OK;
  150. }
  151. else
  152. {
  153. rc = E_POINTER;
  154. }
  155. }
  156. }
  157. }
  158. }
  159. catch ( _com_error& ce )
  160. {
  161. rc = ce.Error();
  162. }
  163. catch ( ... )
  164. {
  165. rc = E_FAIL;
  166. }
  167. return rc;
  168. }
  169. STDMETHODIMP CNextLink::get_GetPreviousDescription(BSTR bstrLinkFile, BSTR * pVal)
  170. {
  171. SCODE rc = E_FAIL;
  172. try
  173. {
  174. CLinkFilePtr pLinkFile;
  175. String strPage;
  176. if ( GetFileAndPage( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETPREVIOUSDDESCRIPTION, bstrLinkFile, pLinkFile, strPage ) )
  177. {
  178. if ( pLinkFile.IsValid() )
  179. {
  180. CReader rdr(*pLinkFile);
  181. CLinkPtr pLink = pLinkFile->PreviousLink( strPage );
  182. if ( pLink.IsValid() )
  183. {
  184. if ( pVal )
  185. {
  186. if ( *pVal )
  187. {
  188. ::SysFreeString( *pVal );
  189. }
  190. HRESULT hr;
  191. CMBCSToWChar convStr;
  192. if (hr = convStr.Init(pLink->Desc().c_str(),
  193. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  194. throw _com_error(hr);
  195. }
  196. *pVal = ::SysAllocString(convStr.GetString());
  197. THROW_IF_NULL( *pVal );
  198. rc = S_OK;
  199. }
  200. else
  201. {
  202. rc = E_POINTER;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. catch ( _com_error& ce )
  209. {
  210. rc = ce.Error();
  211. }
  212. catch ( ... )
  213. {
  214. rc = E_FAIL;
  215. }
  216. return rc;
  217. }
  218. STDMETHODIMP CNextLink::get_GetNthURL(BSTR bstrLinkFile, int nIndex, BSTR * pVal)
  219. {
  220. SCODE rc = E_FAIL;
  221. try
  222. {
  223. CLinkFilePtr pLinkFile = LinkFile( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETNTHURL, bstrLinkFile );
  224. if ( pLinkFile.IsValid() )
  225. {
  226. CReader rdr(*pLinkFile);
  227. if ( (nIndex <= 0) || (nIndex > pLinkFile->NumLinks()) ) {
  228. RaiseException( IDS_ERROR_INVALID_NTH_INDEX );
  229. goto err;
  230. }
  231. CLinkPtr pLink = pLinkFile->Link( nIndex );
  232. if ( pLink.IsValid() )
  233. {
  234. if ( pVal )
  235. {
  236. if (*pVal)
  237. {
  238. ::SysFreeString(*pVal);
  239. }
  240. HRESULT hr;
  241. CMBCSToWChar convStr;
  242. if (hr = convStr.Init(pLink->Link().c_str(),
  243. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  244. throw _com_error(hr);
  245. }
  246. *pVal = ::SysAllocString(convStr.GetString());
  247. THROW_IF_NULL(*pVal);
  248. rc = S_OK;
  249. }
  250. else
  251. {
  252. rc = E_POINTER;
  253. }
  254. }
  255. }
  256. }
  257. catch ( _com_error& ce )
  258. {
  259. rc = ce.Error();
  260. }
  261. catch ( ... )
  262. {
  263. rc = E_FAIL;
  264. }
  265. err:
  266. return rc;
  267. }
  268. STDMETHODIMP CNextLink::get_GetNthDescription(BSTR bstrLinkFile, int nIndex, BSTR * pVal)
  269. {
  270. SCODE rc = E_FAIL;
  271. try
  272. {
  273. CLinkFilePtr pLinkFile = LinkFile( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETNTHDESCRIPTION, bstrLinkFile );
  274. if ( pLinkFile.IsValid() )
  275. {
  276. CReader rdr(*pLinkFile);
  277. if ( (nIndex <= 0) || (nIndex > pLinkFile->NumLinks()) ) {
  278. RaiseException( IDS_ERROR_INVALID_NTH_INDEX );
  279. goto err;
  280. }
  281. CLinkPtr pLink = pLinkFile->Link( nIndex );
  282. if ( pLink.IsValid() )
  283. {
  284. if ( pVal )
  285. {
  286. if ( *pVal )
  287. {
  288. ::SysFreeString( *pVal );
  289. }
  290. HRESULT hr;
  291. CMBCSToWChar convStr;
  292. if (hr = convStr.Init(pLink->Desc().c_str(),
  293. pLinkFile->fUTF8() ? 65001 : CP_ACP)) {
  294. throw _com_error(hr);
  295. }
  296. *pVal = ::SysAllocString(convStr.GetString());
  297. THROW_IF_NULL( *pVal );
  298. rc = S_OK;
  299. }
  300. else
  301. {
  302. rc = E_POINTER;
  303. }
  304. }
  305. }
  306. }
  307. catch ( _com_error& ce )
  308. {
  309. rc = ce.Error();
  310. }
  311. catch ( ... )
  312. {
  313. rc = E_FAIL;
  314. }
  315. err:
  316. return rc;
  317. }
  318. STDMETHODIMP CNextLink::get_GetListCount(BSTR bstrLinkFile, int * pVal)
  319. {
  320. SCODE rc = E_FAIL;
  321. try
  322. {
  323. CLinkFilePtr pLinkFile = LinkFile( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETLISTCOUNT, bstrLinkFile );
  324. if ( pLinkFile.IsValid() )
  325. {
  326. CReader rdr(*pLinkFile);
  327. *pVal = pLinkFile->NumLinks();
  328. rc = S_OK;
  329. }
  330. }
  331. catch ( _com_error& ce )
  332. {
  333. rc = ce.Error();
  334. }
  335. catch ( ... )
  336. {
  337. rc = E_FAIL;
  338. }
  339. return rc;
  340. }
  341. STDMETHODIMP CNextLink::get_GetListIndex(BSTR bstrLinkFile, int * pVal)
  342. {
  343. SCODE rc = E_FAIL;
  344. try
  345. {
  346. CLinkFilePtr pLinkFile;
  347. String strPage;
  348. if ( GetFileAndPage( IDS_ERROR_CANNOT_XLATE_VIRT_ROOT_GETLISTINDEX, bstrLinkFile, pLinkFile, strPage ) )
  349. {
  350. if ( pLinkFile.IsValid() )
  351. {
  352. CReader rdr(*pLinkFile);
  353. *pVal = pLinkFile->LinkIndex( strPage );
  354. rc = S_OK;
  355. }
  356. }
  357. }
  358. catch ( _com_error& ce )
  359. {
  360. rc = ce.Error();
  361. }
  362. catch ( ... )
  363. {
  364. rc = E_FAIL;
  365. }
  366. return rc;
  367. }
  368. STDMETHODIMP CNextLink::get_About(BSTR * pVal)
  369. {
  370. USES_CONVERSION;
  371. #ifdef _DEBUG
  372. LPCTSTR szVersion = _T("Debug");
  373. #else
  374. LPCTSTR szVersion = _T("Release");
  375. #endif
  376. const int kAboutSize = 1024;
  377. _TCHAR szAboutFmt[kAboutSize];
  378. _TCHAR szBuffer[ kAboutSize + sizeof(__DATE__) + sizeof(__TIME__) + sizeof(szVersion) ];
  379. ::LoadString( _Module.GetResourceInstance(), IDS_ABOUT_FMT, szAboutFmt, kAboutSize );
  380. _stprintf(szBuffer, szAboutFmt, szVersion, __DATE__, __TIME__);
  381. if ( pVal )
  382. {
  383. if ( *pVal )
  384. {
  385. ::SysFreeString( *pVal );
  386. }
  387. *pVal = T2BSTR( szBuffer );
  388. if ( *pVal == NULL )
  389. {
  390. return E_OUTOFMEMORY;
  391. }
  392. }
  393. else
  394. {
  395. return E_POINTER;
  396. }
  397. return S_OK;
  398. }
  399. bool
  400. CNextLink::GetPage(
  401. CContext& cxt,
  402. String& strPage )
  403. {
  404. USES_CONVERSION;
  405. bool rc = false;
  406. if ( cxt.Request() != NULL )
  407. {
  408. CComPtr<IDispatch> piPathInfo;
  409. HRESULT hr = cxt.Request()->get_Item( L"PATH_INFO", &piPathInfo );
  410. if ( !FAILED(hr) )
  411. {
  412. CComVariant vt = piPathInfo;
  413. hr = vt.ChangeType( VT_BSTR );
  414. if ( !FAILED( hr ) )
  415. {
  416. strPage = OLE2T(vt.bstrVal);
  417. rc = true;
  418. }
  419. }
  420. }
  421. return rc;
  422. }
  423. CLinkFilePtr
  424. CNextLink::LinkFile(
  425. CContext& cxt,
  426. UINT errorID,
  427. BSTR bstrFile )
  428. {
  429. USES_CONVERSION;
  430. CLinkFilePtr pLinkFile;
  431. if ( cxt.Server() != NULL )
  432. {
  433. CComBSTR bstrPath;
  434. HRESULT hr = cxt.Server()->MapPath( bstrFile, &bstrPath );
  435. if ( !FAILED( hr ) )
  436. {
  437. String strFile = OLE2T(bstrPath);
  438. CLock l( s_linkFileMap );
  439. CLinkFilePtr& rpLinkFile = s_linkFileMap[strFile];
  440. if ( !rpLinkFile.IsValid() )
  441. {
  442. rpLinkFile = new CLinkFile( strFile );
  443. }
  444. else
  445. {
  446. // make sure the file is up to date
  447. rpLinkFile->Refresh();
  448. }
  449. if ( rpLinkFile->IsOkay() )
  450. {
  451. }
  452. else
  453. {
  454. rpLinkFile = NULL;
  455. }
  456. pLinkFile = rpLinkFile;
  457. }
  458. else
  459. {
  460. RaiseException( errorID );
  461. }
  462. }
  463. return pLinkFile;
  464. }
  465. CLinkFilePtr
  466. CNextLink::LinkFile(
  467. UINT errorID,
  468. BSTR bstrFile )
  469. {
  470. CLinkFilePtr pLinkFile;
  471. CContext cxt;
  472. HRESULT hr = cxt.Init( CContext::get_Server );
  473. if ( !FAILED(hr) )
  474. {
  475. pLinkFile = LinkFile( cxt, errorID, bstrFile );
  476. }
  477. else
  478. {
  479. RaiseException( IDS_ERROR_NOSVR );
  480. }
  481. return pLinkFile;
  482. }
  483. bool
  484. CNextLink::GetFileAndPage(
  485. UINT errorID,
  486. BSTR bstrFile,
  487. CLinkFilePtr& pLinkFile,
  488. String& strPage )
  489. {
  490. bool rc = false;
  491. CContext cxt;
  492. HRESULT hr = cxt.Init( CContext::get_Server | CContext::get_Request );
  493. if ( !FAILED( hr ) )
  494. {
  495. pLinkFile = LinkFile( cxt, errorID, bstrFile );
  496. if ( pLinkFile.IsValid() )
  497. {
  498. rc = GetPage( cxt, strPage );
  499. }
  500. }
  501. else
  502. {
  503. RaiseException( IDS_ERROR_NOSVR );
  504. }
  505. return rc;
  506. }
  507. void
  508. CNextLink::ClearLinkFiles()
  509. {
  510. CLock l(s_linkFileMap);
  511. s_linkFileMap.clear();
  512. }
  513. //---------------------------------------------------------------------------
  514. // RaiseException
  515. //
  516. // Raises an exception using the given source and description
  517. //---------------------------------------------------------------------------
  518. void
  519. CNextLink::RaiseException (
  520. LPOLESTR strDescr
  521. )
  522. {
  523. HRESULT hr;
  524. ICreateErrorInfo *pICreateErr;
  525. IErrorInfo *pIErr;
  526. LANGID langID = LANG_NEUTRAL;
  527. /*
  528. * Thread-safe exception handling means that we call
  529. * CreateErrorInfo which gives us an ICreateErrorInfo pointer
  530. * that we then use to set the error information (basically
  531. * to set the fields of an EXCEPINFO structure. We then
  532. * call SetErrorInfo to attach this error to the current
  533. * thread. ITypeInfo::Invoke will look for this when it
  534. * returns from whatever function was invokes by calling
  535. * GetErrorInfo.
  536. */
  537. _TCHAR tstrSource[MAX_RESSTRINGSIZE];
  538. if ( ::LoadString(
  539. _Module.GetResourceInstance(),
  540. IDS_ERROR_SOURCE,
  541. tstrSource,
  542. MAX_RESSTRINGSIZE ) > 0 )
  543. {
  544. USES_CONVERSION;
  545. LPOLESTR strSource = T2OLE(tstrSource);
  546. //Not much we can do if this fails.
  547. if (!FAILED(CreateErrorInfo(&pICreateErr)))
  548. {
  549. pICreateErr->SetGUID(CLSID_NextLink);
  550. pICreateErr->SetHelpFile(L"");
  551. pICreateErr->SetHelpContext(0L);
  552. pICreateErr->SetSource(strSource);
  553. pICreateErr->SetDescription(strDescr);
  554. hr = pICreateErr->QueryInterface(IID_IErrorInfo, (void**)&pIErr);
  555. if (SUCCEEDED(hr))
  556. {
  557. if(SUCCEEDED(SetErrorInfo(0L, pIErr)))
  558. {
  559. pIErr->Release();
  560. }
  561. }
  562. pICreateErr->Release();
  563. }
  564. }
  565. }
  566. void
  567. CNextLink::RaiseException(
  568. UINT DescrID
  569. )
  570. {
  571. _TCHAR tstrDescr[MAX_RESSTRINGSIZE];
  572. if ( ::LoadString(
  573. _Module.GetResourceInstance(),
  574. DescrID,
  575. tstrDescr,
  576. MAX_RESSTRINGSIZE) > 0 )
  577. {
  578. USES_CONVERSION;
  579. LPOLESTR strDescr = T2OLE(tstrDescr);
  580. RaiseException( strDescr );
  581. }
  582. }