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.

778 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000.
  5. //
  6. // File: ixsutil.cxx
  7. //
  8. // Contents: Utility SSO class
  9. //
  10. // History: 04 Apr 1997 Alanw Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "pch.cxx"
  14. #pragma hdrstop
  15. //-----------------------------------------------------------------------------
  16. // Include Files
  17. //-----------------------------------------------------------------------------
  18. // debugging macros
  19. #include "ssodebug.hxx"
  20. // class declaration
  21. #include "stdcf.hxx"
  22. #include "ixsso.hxx"
  23. #include "ixsutil.hxx"
  24. #include <string.hxx>
  25. #include <htmlchar.hxx>
  26. extern WCHAR * g_pwszProgIdUtil;
  27. #if CIDBG
  28. extern ULONG g_ulObjCount;
  29. extern LONG g_lUtlCount;
  30. #endif // CIDBG
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Member: CixssoUtil::CixssoUtil - public
  34. //
  35. // Synopsis: Constructor of CixssoUtil
  36. //
  37. // Arguments: [pitlb] - pointer to ITypeLib for ixsso
  38. //
  39. // History: 04 Apr 1997 Alanw Created
  40. //
  41. //-----------------------------------------------------------------------------
  42. CixssoUtil::CixssoUtil( ITypeLib * pitlb ) :
  43. _ptinfo( 0 ),
  44. _err( IID_IixssoUtil )
  45. {
  46. _cRef = 1;
  47. SCODE sc = pitlb->GetTypeInfoOfGuid( IID_IixssoUtil, &_ptinfo );
  48. if (FAILED(sc))
  49. {
  50. ixssoDebugOut(( DEB_ERROR, "Util - GetTypeInfoOfGuid failed (%x)\n", sc ));
  51. Win4Assert(SUCCEEDED(sc));
  52. THROW( CException(sc) );
  53. }
  54. INC_OBJECT_COUNT();
  55. ixssoDebugOut((DEB_REFCOUNTS, "[DLL]: Create util: refcounts: glob %d util %d\n",
  56. g_ulObjCount,
  57. g_lUtlCount ));
  58. } //CixssoUtil
  59. //-----------------------------------------------------------------------------
  60. //
  61. // Member: CixssoUtil::~CixssoUtil - public
  62. //
  63. // Synopsis: Destructor of CixssoUtil
  64. //
  65. // History: 04 Apr 1997 Alanw Created
  66. //
  67. //-----------------------------------------------------------------------------
  68. CixssoUtil::~CixssoUtil( )
  69. {
  70. if (_ptinfo)
  71. _ptinfo->Release();
  72. DEC_OBJECT_COUNT();
  73. #if CIDBG
  74. extern LONG g_lUtlCount;
  75. LONG l = InterlockedDecrement( &g_lUtlCount );
  76. Win4Assert( l >= 0 );
  77. #endif //CIDBG
  78. ixssoDebugOut((DEB_REFCOUNTS, "[DLL]: Delete util: refcounts: glob %d util %d\n",
  79. g_ulObjCount,
  80. g_lUtlCount ));
  81. } //~CixssoUtl
  82. #if 0 // NOTE: OnStartPage and OnEndPage are unneeded
  83. //
  84. // ASP Methods
  85. //
  86. #include <asp/asptlb.h>
  87. STDMETHODIMP CixssoUtil::OnStartPage (IUnknown* pUnk)
  88. {
  89. if ( 0 == pUnk )
  90. return E_INVALIDARG;
  91. SCODE sc = S_OK;
  92. CTranslateSystemExceptions translate;
  93. TRY
  94. {
  95. // reset the error structure
  96. _err.Reset();
  97. IScriptingContext *piContext;
  98. //Get IScriptingContext Interface
  99. sc = pUnk->QueryInterface(IID_IScriptingContext, (void**)&piContext);
  100. if (FAILED(sc))
  101. return E_FAIL;
  102. //Get Request Object Pointer
  103. IRequest* piRequest = NULL;
  104. sc = piContext->get_Request(&piRequest);
  105. //Get ServerVariables Pointer
  106. IRequestDictionary *piRequestDict = NULL;
  107. sc = piRequest->get_ServerVariables(&piRequestDict);
  108. VARIANT vtOut;
  109. VariantInit(&vtOut);
  110. //Get the HTTP_ACCEPT_LANGUAGE Item
  111. sc = piRequestDict->get_Item(g_vtAcceptLanguageHeader, &vtOut);
  112. //vtOut Contains an IDispatch Pointer. To fetch the value
  113. //for HTTP_ACCEPT_LANGUAGE you must get the Default Value for the
  114. //Object stored in vtOut using VariantChangeType.
  115. if (V_VT(&vtOut) != VT_BSTR)
  116. VariantChangeType(&vtOut, &vtOut, 0, VT_BSTR);
  117. if (V_VT(&vtOut) == VT_BSTR)
  118. {
  119. ixssoDebugOut((DEB_TRACE, "OnStartPage: HTTP_ACCEPT_LANGUAGE = %ws\n",
  120. V_BSTR(&vtOut) ));
  121. SetLocaleString(V_BSTR(&vtOut));
  122. }
  123. else
  124. {
  125. ixssoDebugOut(( DEB_TRACE,
  126. "OnStart: HTTP_ACCEPT_LANGAUGE was not set is ServerVariables; using lcid=0x%x\n",
  127. GetSystemDefaultLCID() ));
  128. put_LocaleID( GetSystemDefaultLCID() );
  129. }
  130. VariantClear(&vtOut);
  131. piRequestDict->Release();
  132. piRequest->Release();
  133. piContext->Release();
  134. }
  135. CATCH( CException, e )
  136. {
  137. sc = e.GetErrorCode();
  138. SetError( sc, OLESTR("OnStartPage"), eIxssoError );
  139. }
  140. END_CATCH
  141. return sc;
  142. }
  143. HRESULT CixssoUtil::OnEndPage(void)
  144. {
  145. return S_OK;
  146. }
  147. #endif // 0 NOTE: OnStartPage and OnEndPage are unneeded
  148. //-----------------------------------------------------------------------------
  149. // CixssoUtil IUnknown Methods
  150. //-----------------------------------------------------------------------------
  151. STDMETHODIMP
  152. CixssoUtil::QueryInterface(REFIID iid, void * * ppv)
  153. {
  154. *ppv = 0;
  155. if (iid == IID_IUnknown || iid == IID_IDispatch)
  156. *ppv = (IDispatch *)this;
  157. else if (iid == IID_ISupportErrorInfo )
  158. *ppv = (ISupportErrorInfo *) this;
  159. else if (iid == IID_IixssoUtil )
  160. *ppv = (IixssoUtil *) this;
  161. else
  162. return E_NOINTERFACE;
  163. AddRef();
  164. return S_OK;
  165. } //QueryInterface
  166. STDMETHODIMP_(ULONG)
  167. CixssoUtil::AddRef(void)
  168. {
  169. return InterlockedIncrement((long *)&_cRef);
  170. }
  171. STDMETHODIMP_(ULONG)
  172. CixssoUtil::Release(void)
  173. {
  174. ULONG uTmp = InterlockedDecrement((long *)&_cRef);
  175. if (uTmp == 0)
  176. {
  177. delete this;
  178. return 0;
  179. }
  180. return uTmp;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // CixssoUtil IDispatch Methods
  184. //-----------------------------------------------------------------------------
  185. STDMETHODIMP
  186. CixssoUtil::GetTypeInfoCount(UINT * pctinfo)
  187. {
  188. *pctinfo = 1;
  189. return S_OK;
  190. }
  191. STDMETHODIMP
  192. CixssoUtil::GetTypeInfo(
  193. UINT itinfo,
  194. LCID lcid,
  195. ITypeInfo * * pptinfo)
  196. {
  197. _ptinfo->AddRef();
  198. *pptinfo = _ptinfo;
  199. return S_OK;
  200. }
  201. STDMETHODIMP
  202. CixssoUtil::GetIDsOfNames(
  203. REFIID riid,
  204. OLECHAR * * rgszNames,
  205. UINT cNames,
  206. LCID lcid,
  207. DISPID * rgdispid)
  208. {
  209. return DispGetIDsOfNames(_ptinfo, rgszNames, cNames, rgdispid);
  210. }
  211. STDMETHODIMP
  212. CixssoUtil::Invoke(
  213. DISPID dispidMember,
  214. REFIID riid,
  215. LCID lcid,
  216. WORD wFlags,
  217. DISPPARAMS * pParams,
  218. VARIANT * pvarResult,
  219. EXCEPINFO * pexcepinfo,
  220. UINT * puArgErr)
  221. {
  222. ixssoDebugOut((DEB_IDISPATCH, "Util - Invoking method dispid=%d wFlags=%d\n",
  223. dispidMember, wFlags ));
  224. _err.Reset();
  225. SCODE sc = DispInvoke( this, _ptinfo,
  226. dispidMember, wFlags, pParams,
  227. pvarResult, pexcepinfo, puArgErr );
  228. if ( _err.IsError() )
  229. sc = DISP_E_EXCEPTION;
  230. return sc;
  231. }
  232. STDMETHODIMP
  233. CixssoUtil::InterfaceSupportsErrorInfo(
  234. REFIID riid)
  235. {
  236. if (riid == IID_IixssoUtil)
  237. return S_OK;
  238. else
  239. return S_FALSE;
  240. }
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Member: CixssoQuery::CopyWstrToBstr - private inline
  244. //
  245. // Synopsis: Copies a Unicode string to a BSTR
  246. //
  247. // Arguments: [pbstr] - destination BSTR
  248. // [pwstr] - string to be copied
  249. //
  250. // Returns: SCODE - status return
  251. //
  252. // History: 25 Oct 1996 Alanw Created
  253. //
  254. //----------------------------------------------------------------------------
  255. inline
  256. SCODE CixssoUtil::CopyWstrToBstr( BSTR * pbstr, WCHAR const * pwstr )
  257. {
  258. *pbstr = 0;
  259. if (pwstr)
  260. {
  261. *pbstr = SysAllocString( pwstr );
  262. if (0 == *pbstr)
  263. return E_OUTOFMEMORY;
  264. }
  265. return S_OK;
  266. }
  267. //-----------------------------------------------------------------------------
  268. // CixssoUtil Methods
  269. //-----------------------------------------------------------------------------
  270. //+---------------------------------------------------------------------------
  271. //
  272. // Member: CixssoUtil::ISOToLocaleID - public
  273. //
  274. // Synopsis: Parse the input string for a recognizable locale name
  275. //
  276. // Arguments: [bstrLocale] - input string
  277. // [pLcid] - pointer where corresponding LCID is returned
  278. //
  279. // Returns: SCODE - status return
  280. //
  281. // History: 04 Apr 1997 Alanw Created
  282. //
  283. //----------------------------------------------------------------------------
  284. STDMETHODIMP
  285. CixssoUtil::ISOToLocaleID(BSTR bstrLocale, LONG *pLcid)
  286. {
  287. _err.Reset();
  288. if ( 0 == pLcid )
  289. return E_INVALIDARG;
  290. *pLcid = GetLCIDFromString( bstrLocale );
  291. return S_OK;
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // Member: CixssoUtil::LocaleIDToISO - public
  296. //
  297. // Synopsis: Return the ISO locale name for an LCID
  298. //
  299. // Arguments: [Lcid] - input LCID
  300. // [pstr] - pointer where output string is returned
  301. //
  302. // Returns: SCODE - status return
  303. //
  304. // History: 04 Apr 1997 Alanw Created
  305. //
  306. //----------------------------------------------------------------------------
  307. STDMETHODIMP
  308. CixssoUtil::LocaleIDToISO(LONG lcid, BSTR * pstr)
  309. {
  310. _err.Reset();
  311. if ( 0 == pstr )
  312. return E_INVALIDARG;
  313. WCHAR awc[100];
  314. GetStringFromLCID( lcid, awc );
  315. return CopyWstrToBstr( pstr, awc );
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CixssoUtil::AddScopeToQuery - public
  320. //
  321. // Synopsis: Parse the input string for a recognizable locale name
  322. //
  323. // Arguments: [pDisp] - an IDispatch for the query object
  324. // [bstrScope] - input scope
  325. // [bstrDepth] - input depth (optional)
  326. //
  327. // Returns: SCODE - status return
  328. //
  329. // Notes: In the future, this will operate by modifying the query
  330. // property to include a scope restriction.
  331. // For now, it just adds the scope and depth via a private
  332. // interface.
  333. //
  334. // History: 04 Apr 1997 Alanw Created
  335. //
  336. //----------------------------------------------------------------------------
  337. STDMETHODIMP
  338. CixssoUtil::AddScopeToQuery( IDispatch * pDisp,
  339. BSTR bstrScope,
  340. BSTR bstrDepth)
  341. {
  342. _err.Reset();
  343. SCODE sc = S_OK;
  344. CTranslateSystemExceptions translate;
  345. TRY
  346. {
  347. if ( 0 == pDisp )
  348. THROW( CException( E_INVALIDARG ) );
  349. IixssoQueryPrivate * pIQueryPvt = 0;
  350. sc = pDisp->QueryInterface( IID_IixssoQueryPrivate, (void **)&pIQueryPvt );
  351. if (FAILED(sc))
  352. {
  353. THROW(CException(sc));
  354. }
  355. XInterface<IixssoQueryPrivate> pQry(pIQueryPvt);
  356. pQry->AddScopeToQuery( bstrScope, bstrDepth );
  357. }
  358. CATCH( CIxssoException, e )
  359. {
  360. sc = e.GetErrorCode();
  361. SetError( sc, OLESTR("AddScopeToQuery"), eIxssoError );
  362. }
  363. AND_CATCH( CException, e )
  364. {
  365. sc = e.GetErrorCode();
  366. SetError( sc, OLESTR("AddScopeToQuery") );
  367. }
  368. END_CATCH
  369. return sc;
  370. } //AddScopeToQuery
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Member: CixssoUtil::TruncateToWhitespace - public
  374. //
  375. // Synopsis: Truncate a string, preferably at a white space character.
  376. //
  377. // Arguments: [bstrIn] - input string
  378. // [maxLen] - maximum number of characters in output string
  379. // [pbstrOut] - pointer where output string is returned
  380. //
  381. // Returns: SCODE - status return
  382. //
  383. // Notes: The implementation does not take into account real word breaks.
  384. // This may not work too well on far eastern languages.
  385. //
  386. // History: 04 Apr 1997 Alanw Created
  387. //
  388. //----------------------------------------------------------------------------
  389. STDMETHODIMP
  390. CixssoUtil::TruncateToWhitespace(BSTR bstrIn, LONG maxLen, BSTR * pbstrOut)
  391. {
  392. _err.Reset();
  393. ULONG cchString = 0;
  394. if (maxLen <= 0)
  395. return E_INVALIDARG;
  396. if (0 != bstrIn)
  397. cchString = SysStringLen(bstrIn);
  398. if (cchString > (unsigned)maxLen)
  399. {
  400. cchString = maxLen;
  401. for (unsigned i=0; i <= (unsigned)maxLen; i++)
  402. {
  403. if (iswspace(bstrIn[i]))
  404. cchString = i;
  405. }
  406. }
  407. *pbstrOut = SysAllocStringLen( bstrIn, cchString );
  408. if (0 == *pbstrOut)
  409. return E_OUTOFMEMORY;
  410. return S_OK;
  411. } //TruncateToWhitespace
  412. class XVariant
  413. {
  414. public:
  415. XVariant() : _pVar( 0 ) {}
  416. XVariant( VARIANT & var ) : _pVar( &var ) {}
  417. ~XVariant() { if ( 0 != _pVar ) VariantClear( _pVar ); }
  418. void Set( VARIANT & var ) { Win4Assert( 0 == _pVar ); _pVar = &var; }
  419. private:
  420. VARIANT * _pVar;
  421. };
  422. //+---------------------------------------------------------------------------
  423. //
  424. // Member: CixssoUtil::GetArrayElement - public
  425. //
  426. // Synopsis: Returns an element in an array as a variant
  427. //
  428. // Arguments: [pVarIn] - The input array (IDispatch or VT_ARRAY)
  429. // [iElement] - The element to retrieve
  430. // [pVarOut] - Where the array element result is written
  431. //
  432. // Returns: SCODE - status return
  433. //
  434. // History: 10 Sep 1997 dlee Created
  435. // 18 Jan 2000 KLam DECIMAL needs to fit into a VARIANT
  436. // on Win64 VARIANT is bigger than DECIMAL
  437. //
  438. //----------------------------------------------------------------------------
  439. STDMETHODIMP CixssoUtil::GetArrayElement(
  440. VARIANT * pVarIn,
  441. LONG iElement,
  442. VARIANT * pVarOut )
  443. {
  444. _err.Reset();
  445. //
  446. // Validate the variant arguments.
  447. //
  448. if ( ( 0 == pVarIn ) || ( 0 == pVarOut ) )
  449. return SetError( E_INVALIDARG, OLESTR( "GetArrayElement" ) );
  450. //
  451. // Get the source array, either from the IDispatch or just copy it.
  452. //
  453. XVariant xvar;
  454. VARIANT varArray;
  455. VariantInit( &varArray );
  456. if ( VT_DISPATCH == pVarIn->vt )
  457. {
  458. //
  459. // The first argument is an IDispatch, not the array value, so we
  460. // have to invoke it to get the value out.
  461. //
  462. if ( 0 == pVarIn->pdispVal )
  463. return SetError( E_INVALIDARG, OLESTR( "GetArrayElement" ) );
  464. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  465. SCODE sc = pVarIn->pdispVal->Invoke( DISPID_VALUE,
  466. IID_NULL,
  467. GetSystemDefaultLCID(),
  468. DISPATCH_PROPERTYGET,
  469. &dispparamsNoArgs,
  470. &varArray,
  471. 0,
  472. 0 );
  473. ixssoDebugOut(( DEB_ITRACE, "result of invoke: 0x%x\n", sc ));
  474. if ( FAILED( sc ) )
  475. return SetError( sc, OLESTR( "GetArrayElement" ) );
  476. xvar.Set( varArray );
  477. }
  478. else
  479. {
  480. varArray = *pVarIn;
  481. }
  482. ixssoDebugOut(( DEB_ITRACE, "value vt: 0x%x\n", varArray.vt ));
  483. //
  484. // Check for a valid variant array argument.
  485. //
  486. if ( ( 0 == ( VT_ARRAY & varArray.vt ) ) ||
  487. ( 0 == varArray.parray ) )
  488. return SetError( E_INVALIDARG, OLESTR( "GetArrayElement" ) );
  489. SAFEARRAY *psa = varArray.parray;
  490. //
  491. // This function only deals with 1-dimensional safearrays.
  492. //
  493. if ( 1 != SafeArrayGetDim( psa ) )
  494. return SetError( E_INVALIDARG, OLESTR( "GetArrayElement" ) );
  495. //
  496. // Make sure iElement is in the bounds of the array.
  497. //
  498. long lLowBound;
  499. SCODE sc = SafeArrayGetLBound( psa, 1, &lLowBound );
  500. if ( FAILED( sc ) )
  501. return SetError( sc, OLESTR( "GetArrayElement" ) );
  502. long lUpBound;
  503. sc = SafeArrayGetUBound( psa, 1, &lUpBound );
  504. if ( FAILED( sc ) )
  505. return SetError( sc, OLESTR( "GetArrayElement" ) );
  506. if ( ( iElement < lLowBound ) || ( iElement > lUpBound ) )
  507. return SetError( E_INVALIDARG, OLESTR( "GetArrayElement" ) );
  508. //
  509. // Get a pointer to the element.
  510. //
  511. void * pvData;
  512. sc = SafeArrayPtrOfIndex( psa, &iElement, &pvData );
  513. if ( FAILED( sc ) )
  514. return SetError( sc, OLESTR( "GetArrayElement" ) );
  515. //
  516. // Put the element in a local variant so it can be copied.
  517. //
  518. VARIANT var;
  519. VariantInit( &var );
  520. var.vt = varArray.vt & (~VT_ARRAY);
  521. unsigned cbElem = SafeArrayGetElemsize( psa );
  522. if ( VT_VARIANT == var.vt )
  523. {
  524. Win4Assert( sizeof( VARIANT ) == cbElem );
  525. RtlCopyMemory( &var, pvData, cbElem );
  526. }
  527. else if ( VT_DECIMAL == var.vt )
  528. {
  529. Win4Assert( sizeof( VARIANT ) >= cbElem &&
  530. sizeof( DECIMAL ) == cbElem );
  531. RtlCopyMemory( &var, pvData, cbElem );
  532. var.vt = VT_DECIMAL;
  533. }
  534. else
  535. {
  536. Win4Assert( cbElem <= 8 );
  537. RtlCopyMemory( &var.lVal, pvData, cbElem );
  538. }
  539. //
  540. // Make a copy of the value into another local variant.
  541. //
  542. VARIANT varCopy;
  543. VariantInit( &varCopy );
  544. sc = VariantCopy( &varCopy, &var );
  545. if ( FAILED( sc ) )
  546. return SetError( sc, OLESTR( "GetArrayElement" ) );
  547. //
  548. // Free anything still allocated in the output variant, and transfer
  549. // the value to the output variant.
  550. //
  551. VariantClear( pVarOut );
  552. *pVarOut = varCopy;
  553. return S_OK;
  554. } //GetArrayElement
  555. //+---------------------------------------------------------------------------
  556. //
  557. // Member: CixssoUtil::HTMLEncode - public
  558. //
  559. // Synopsis: Encode a string for use in HTML. Take the output code page
  560. // into account so that unicode characters not representable in
  561. // the code page are output as HTML numeric entities.
  562. //
  563. // Arguments: [bstrIn] - input string
  564. // [codepage] - code page for output string
  565. // [pbstrOut] - pointer where output string is returned
  566. //
  567. // Returns: SCODE - status return
  568. //
  569. // History: 04 Apr 1997 Alanw Created
  570. //
  571. //----------------------------------------------------------------------------
  572. STDMETHODIMP
  573. CixssoUtil::HTMLEncode(BSTR bstrIn, LONG codepage, BSTR * pbstrOut)
  574. {
  575. _err.Reset();
  576. SCODE sc = S_OK;
  577. CTranslateSystemExceptions translate;
  578. TRY
  579. {
  580. if ( ( codepage < 0 ) || ( 0 == pbstrOut ) )
  581. THROW( CException( E_INVALIDARG ) );
  582. CVirtualString vString( 512 );
  583. if ( 0 != bstrIn )
  584. HTMLEscapeW( bstrIn, vString, codepage );
  585. BSTR bstr = SysAllocStringLen( vString.GetPointer(), vString.StrLen() );
  586. if ( 0 == bstr )
  587. THROW( CException( E_OUTOFMEMORY ) );
  588. *pbstrOut = bstr;
  589. }
  590. CATCH( CException, e )
  591. {
  592. sc = e.GetErrorCode();
  593. SetError( sc, OLESTR("HTMLEncode"), eIxssoError );
  594. }
  595. END_CATCH;
  596. return sc;
  597. } //HTMLEncode
  598. //+---------------------------------------------------------------------------
  599. //
  600. // Member: CixssoUtil::URLEncode - public
  601. //
  602. // Synopsis: Encode a string for use in a URL. Take the output code page
  603. // into account so that unicode characters not representable in
  604. // the code page are output as %uxxxx escapes.
  605. //
  606. // Arguments: [bstrIn] - input string
  607. // [codepage] - code page for output string
  608. // [pbstrOut] - pointer where output string is returned
  609. //
  610. // Returns: SCODE - status return
  611. //
  612. // History: 04 Apr 1997 Alanw Created
  613. //
  614. //----------------------------------------------------------------------------
  615. STDMETHODIMP
  616. CixssoUtil::URLEncode(BSTR bstrIn, LONG codepage, BSTR * pbstrOut)
  617. {
  618. _err.Reset();
  619. SCODE sc = S_OK;
  620. CTranslateSystemExceptions translate;
  621. TRY
  622. {
  623. if ( ( codepage < 0 ) || ( 0 == pbstrOut ) )
  624. THROW( CException( E_INVALIDARG ) );
  625. CVirtualString vString( 512 );
  626. if ( 0 != bstrIn )
  627. URLEscapeW( bstrIn, vString, codepage, FALSE );
  628. BSTR bstr = SysAllocStringLen( vString.GetPointer(), vString.StrLen() );
  629. if ( 0 == bstr )
  630. THROW( CException( E_OUTOFMEMORY ) );
  631. *pbstrOut = bstr;
  632. }
  633. CATCH( CException, e )
  634. {
  635. sc = e.GetErrorCode();
  636. SetError( sc, OLESTR("URLEncode"), eIxssoError );
  637. }
  638. END_CATCH;
  639. return sc;
  640. } //URLEncode