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.

2035 lines
51 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ScriptResource.cpp
  7. //
  8. // Description:
  9. // CScriptResource class implementation.
  10. //
  11. // Maintained By:
  12. // gpease 14-DEC-1999
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. #include "pch.h"
  16. #include <clusudef.h>
  17. #include "ActiveScriptSite.h"
  18. #include "ScriptResource.h"
  19. #include "SpinLock.h"
  20. #include "clusrtl.h"
  21. DEFINE_THISCLASS("CScriptResource")
  22. //
  23. // KB: gpease 08-FEB-2000
  24. //
  25. // The Generic Scripting Resource uses a separate working thread to do all
  26. // calls into the Script. This is because the Scripting Host Engines require
  27. // only the creating thread to call them (remember, scripting is designed
  28. // to be used in a user mode application where usually the UI thread runs
  29. // the script). To make this possible, we serialize the threads entering the
  30. // the script using a user-mode spinlock (m_lockSerialize). We then use two events
  31. // to signal the "worker thread" (m_EventWait) and to signal when the "worker
  32. // thread" has completed the task (m_EventDone).
  33. //
  34. // LooksAlive is implemented by returning the last result of a LooksAlive. It
  35. // will start the "worker thread" doing the LooksAlive, but not wait for the
  36. // thread to return the result. Because of this, all the other threads must
  37. // make sure that the "Done Event" (m_EventDone) is signalled before writing
  38. // into the common buffers (m_msg and m_hr).
  39. //
  40. //////////////////////////////////////////////////////////////////////////////
  41. //
  42. // LPUNKNOWN
  43. // CScriptResource_CreateInstance( void )
  44. //
  45. // Description:
  46. // Creates an intialized instance of CScriptResource.
  47. //
  48. // Arguments:
  49. // None.
  50. //
  51. // Return Values:
  52. // NULL - Failure to create or initialize.
  53. // valid pointer to a CScriptResource.
  54. //
  55. //////////////////////////////////////////////////////////////////////////////
  56. CScriptResource *
  57. CScriptResource_CreateInstance(
  58. LPCWSTR pszNameIn,
  59. HKEY hkeyIn,
  60. RESOURCE_HANDLE hResourceIn
  61. )
  62. {
  63. TraceFunc( "CScriptResource_CreateInstance( )\n" );
  64. CScriptResource * lpcc = new CScriptResource( );
  65. if ( lpcc != NULL )
  66. {
  67. HRESULT hr = THR( lpcc->Init( pszNameIn, hkeyIn, hResourceIn ) );
  68. if ( SUCCEEDED( hr ) )
  69. {
  70. RETURN( lpcc );
  71. } // if: success
  72. delete lpcc;
  73. } // if: got object
  74. RETURN(NULL);
  75. } //*** CScriptResource_CreateInstance( )
  76. //////////////////////////////////////////////////////////////////////////////
  77. //
  78. // Constructor
  79. //
  80. //////////////////////////////////////////////////////////////////////////////
  81. CScriptResource::CScriptResource( ) :
  82. m_dispidOpen(DISPID_UNKNOWN),
  83. m_dispidClose(DISPID_UNKNOWN),
  84. m_dispidOnline(DISPID_UNKNOWN),
  85. m_dispidOffline(DISPID_UNKNOWN),
  86. m_dispidTerminate(DISPID_UNKNOWN),
  87. m_dispidLooksAlive(DISPID_UNKNOWN),
  88. m_dispidIsAlive(DISPID_UNKNOWN)
  89. {
  90. TraceClsFunc1( "%s( )\n", __THISCLASS__ );
  91. Assert( m_cRef == 0 );
  92. TraceFuncExit( );
  93. } //*** constructor
  94. //////////////////////////////////////////////////////////////////////////////
  95. //
  96. // Destructor
  97. //
  98. //////////////////////////////////////////////////////////////////////////////
  99. CScriptResource::~CScriptResource( )
  100. {
  101. TraceClsFunc1( "~%s( )\n", __THISCLASS__ );
  102. HRESULT hr;
  103. CSpinLock SpinLock( &m_lockSerialize, INFINITE );
  104. //
  105. // Make sure no one else has this lock.... else why are we going away?
  106. //
  107. hr = SpinLock.AcquireLock( );
  108. Assert( hr == S_OK );
  109. //
  110. // Kill the worker thread.
  111. //
  112. if ( m_hThread != NULL )
  113. {
  114. // Tell it to DIE
  115. m_msg = msgDIE;
  116. // Signal the event.
  117. SetEvent( m_hEventWait );
  118. // Wait for it to happen. This shouldn't take long at all.
  119. WaitForSingleObject( m_hThread, 30000 ); // 30 seconds
  120. // Cleanup the handle.
  121. CloseHandle( m_hThread );
  122. }
  123. if ( m_hEventDone != NULL )
  124. {
  125. CloseHandle( m_hEventDone );
  126. }
  127. if ( m_hEventWait != NULL )
  128. {
  129. CloseHandle( m_hEventWait );
  130. }
  131. if ( m_pszName != NULL )
  132. {
  133. TraceFree( m_pszName );
  134. } // if: m_pszName
  135. if ( m_hkeyParams != NULL )
  136. {
  137. ClusterRegCloseKey( m_hkeyParams );
  138. } // if: m_hkeyParams
  139. #if defined(DEBUG)
  140. //
  141. // Make the debug build happy. Not needed in RETAIL.
  142. //
  143. SpinLock.ReleaseLock( );
  144. #endif // defined(DEBUG)
  145. TraceFuncExit( );
  146. } //*** destructor
  147. //////////////////////////////////////////////////////////////////////////////
  148. //
  149. // HRESULT
  150. // CScriptResource::Init(
  151. // LPCWSTR pszNameIn,
  152. // HKEY hkeyIn,
  153. // RESOURCE_HANDLE hResourceIn
  154. // )
  155. //
  156. // Description:
  157. // Initializes the class.
  158. //
  159. // Arguments:
  160. // pszNameIn - Name of resource instance.
  161. // hkeyIn - The cluster key root for this resource instance.
  162. // hResourceIn - The hResource for this instance.
  163. //
  164. // Return Value:
  165. // S_OK -
  166. // Success.
  167. // HRESULT_FROM_WIN32( ) error -
  168. // if Win32 call failed.
  169. // E_OUTOFMEMORY -
  170. // Out of memory.
  171. // other HRESULT errors.
  172. //
  173. //////////////////////////////////////////////////////////////////////////////
  174. HRESULT
  175. CScriptResource::Init(
  176. LPCWSTR pszNameIn,
  177. HKEY hkeyIn,
  178. RESOURCE_HANDLE hResourceIn
  179. )
  180. {
  181. TraceClsFunc1( "Init( pszNameIn = '%s' )\n", pszNameIn );
  182. DWORD dwErr;
  183. HRESULT hr = S_OK;
  184. // IUnknown
  185. AddRef( );
  186. // Other
  187. m_hResource = hResourceIn;
  188. Assert( m_pszName == NULL );
  189. Assert( m_pszScriptFilePath == NULL );
  190. Assert( m_pszScriptEngine == NULL );
  191. Assert( m_hEventWait == NULL );
  192. Assert( m_hEventDone == NULL );
  193. Assert( m_lockSerialize == FALSE );
  194. //
  195. // Create some event to wait on.
  196. //
  197. // scripting engine thread wait event
  198. m_hEventWait = CreateEvent( NULL, TRUE, FALSE, NULL );
  199. if ( m_hEventWait == NULL )
  200. goto Win32Error;
  201. // task completion event
  202. m_hEventDone = CreateEvent( NULL, TRUE, FALSE, NULL );
  203. if ( m_hEventDone == NULL )
  204. goto Win32Error;
  205. //
  206. // Copy the resource name.
  207. //
  208. m_pszName = TraceStrDup( pszNameIn );
  209. if ( m_pszName == NULL )
  210. goto OutOfMemory;
  211. //
  212. // Open the parameters key.
  213. //
  214. dwErr = ClusterRegOpenKey( hkeyIn, L"Parameters", KEY_ALL_ACCESS, &m_hkeyParams );
  215. if ( dwErr != ERROR_SUCCESS )
  216. {
  217. TW32( dwErr );
  218. hr = HRESULT_FROM_WIN32( dwErr );
  219. goto Error;
  220. } // if: failed
  221. //
  222. // Create the scripting engine thread.
  223. //
  224. m_hThread = CreateThread( NULL,
  225. 0,
  226. &S_ThreadProc,
  227. this,
  228. 0,
  229. &m_dwThreadId
  230. );
  231. if ( m_hThread == NULL )
  232. goto Win32Error;
  233. Cleanup:
  234. //
  235. // All class variable clean up should be done in the destructor.
  236. //
  237. HRETURN( hr );
  238. Error:
  239. LogError( hr );
  240. goto Cleanup;
  241. OutOfMemory:
  242. hr = E_OUTOFMEMORY;
  243. goto Error;
  244. Win32Error:
  245. dwErr = GetLastError( );
  246. TW32( dwErr );
  247. hr = HRESULT_FROM_WIN32( dwErr );
  248. goto Error;
  249. } //*** Init( )
  250. //****************************************************************************
  251. //
  252. // IUnknown
  253. //
  254. //****************************************************************************
  255. //////////////////////////////////////////////////////////////////////////////
  256. //
  257. // STDMETHODIMP
  258. // CScriptResource::[IUnknown] QueryInterface(
  259. // REFIID riid,
  260. // LPVOID * ppv
  261. // )
  262. //
  263. //////////////////////////////////////////////////////////////////////////////
  264. STDMETHODIMP
  265. CScriptResource::QueryInterface(
  266. REFIID riid,
  267. LPVOID * ppv
  268. )
  269. {
  270. TraceClsFunc1( "[IUnknown] QueryInterface( riid, ppv = 0x%08x )\n",
  271. ppv
  272. );
  273. HRESULT hr = E_NOINTERFACE;
  274. if ( IsEqualIID( riid, IID_IUnknown ) )
  275. {
  276. *ppv = TraceInterface( __THISCLASS__, IUnknown, static_cast< IUnknown* >( this ), 0 );
  277. hr = S_OK;
  278. } // if: IUnknown
  279. if ( SUCCEEDED( hr ) )
  280. {
  281. ((IUnknown *) *ppv)->AddRef( );
  282. } // if: success
  283. QIRETURN( hr, riid );
  284. } //*** QueryInterface( )
  285. //////////////////////////////////////////////////////////////////////////////
  286. //
  287. // STDMETHODIMP_( ULONG )
  288. // CScriptResource::[IUnknown] AddRef( void )
  289. //
  290. //////////////////////////////////////////////////////////////////////////////
  291. STDMETHODIMP_( ULONG )
  292. CScriptResource::AddRef( void )
  293. {
  294. TraceClsFunc( "[IUnknown] AddRef( )\n" );
  295. LONG cRef = InterlockedIncrement( &m_cRef );
  296. RETURN( cRef );
  297. } //*** AddRef( )
  298. //////////////////////////////////////////////////////////////////////////////
  299. //
  300. // STDMETHODIMP_( ULONG )
  301. // CScriptResource::[IUnknown] Release( void )
  302. //
  303. //////////////////////////////////////////////////////////////////////////////
  304. STDMETHODIMP_( ULONG )
  305. CScriptResource::Release( void )
  306. {
  307. TraceClsFunc( "[IUnknown] Release( )\n" );
  308. LONG cRef = InterlockedDecrement( &m_cRef );
  309. if ( cRef == 0 )
  310. {
  311. TraceDo( delete this );
  312. } // if: reference count decremented to zero
  313. RETURN( cRef );
  314. } //*** Release( )
  315. //****************************************************************************
  316. //
  317. // Publics
  318. //
  319. //****************************************************************************
  320. //////////////////////////////////////////////////////////////////////////////
  321. //
  322. // STDMETHODIMP
  323. // CScriptResource::Close(
  324. // )
  325. //
  326. //////////////////////////////////////////////////////////////////////////////
  327. STDMETHODIMP
  328. CScriptResource::Close(
  329. )
  330. {
  331. TraceClsFunc( "Close( )\n" );
  332. HRESULT hr;
  333. hr = THR( WaitForMessageToComplete( msgCLOSE ) );
  334. HRETURN( hr );
  335. } //*** Close( )
  336. //////////////////////////////////////////////////////////////////////////////
  337. //
  338. // STDMETHODIMP
  339. // CScriptResource::Open(
  340. // )
  341. //
  342. //////////////////////////////////////////////////////////////////////////////
  343. STDMETHODIMP
  344. CScriptResource::Open(
  345. )
  346. {
  347. TraceClsFunc( "Open( )\n" );
  348. HRESULT hr;
  349. hr = THR( WaitForMessageToComplete( msgOPEN ) );
  350. // CMCM:+ 19-Dec-2000 commented this out to make the DBG PRINT quiet since we now return ERROR_RETRY
  351. // HRETURN( hr );
  352. return hr;
  353. } //*** Open( )
  354. //////////////////////////////////////////////////////////////////////////////
  355. //
  356. // STDMETHODIMP
  357. // CScriptResource::Online(
  358. // )
  359. //
  360. //////////////////////////////////////////////////////////////////////////////
  361. STDMETHODIMP
  362. CScriptResource::Online(
  363. )
  364. {
  365. TraceClsFunc( "Online( )\n" );
  366. HRESULT hr;
  367. hr = THR( WaitForMessageToComplete( msgONLINE ) );
  368. HRETURN( hr );
  369. } //*** Online( )
  370. //////////////////////////////////////////////////////////////////////////////
  371. //
  372. // STDMETHODIMP
  373. // CScriptResource::Offline(
  374. // )
  375. //
  376. //////////////////////////////////////////////////////////////////////////////
  377. STDMETHODIMP
  378. CScriptResource::Offline(
  379. )
  380. {
  381. TraceClsFunc( "Offline( )\n" );
  382. HRESULT hr;
  383. hr = THR( WaitForMessageToComplete( msgOFFLINE ) );
  384. HRETURN( hr );
  385. } //*** Offline( )
  386. //////////////////////////////////////////////////////////////////////////////
  387. //
  388. // STDMETHODIMP
  389. // CScriptResource::Terminate(
  390. // )
  391. //
  392. //////////////////////////////////////////////////////////////////////////////
  393. STDMETHODIMP
  394. CScriptResource::Terminate(
  395. )
  396. {
  397. TraceClsFunc( "Terminate( )\n" );
  398. HRESULT hr;
  399. hr = THR( WaitForMessageToComplete( msgTERMINATE ) );
  400. HRETURN( hr );
  401. } //*** Terminate( )
  402. //////////////////////////////////////////////////////////////////////////////
  403. //
  404. // STDMETHODIMP
  405. // CScriptResource::LooksAlive(
  406. // )
  407. //
  408. //////////////////////////////////////////////////////////////////////////////
  409. STDMETHODIMP
  410. CScriptResource::LooksAlive(
  411. )
  412. {
  413. TraceClsFunc( "LooksAlive( )\n" );
  414. HRESULT hr;
  415. BOOL b;
  416. DWORD dw;
  417. CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
  418. //
  419. // Acquire the serialization lock.
  420. //
  421. hr = THR( SerializeLock.AcquireLock( ) );
  422. if ( FAILED( hr ) )
  423. {
  424. //
  425. // Can't "goto Error" because we didn't acquire the lock.
  426. //
  427. LogError( hr );
  428. goto Cleanup;
  429. }
  430. //
  431. // Wait for the script thread to be "done."
  432. //
  433. dw = WaitForSingleObject( m_hEventDone, INFINITE );
  434. if ( dw != WAIT_OBJECT_0 )
  435. goto Win32Error;
  436. //
  437. // Reset the done event to indicate that the thread is not busy.
  438. //
  439. b = ResetEvent( m_hEventDone );
  440. if ( !b )
  441. goto Win32Error;
  442. //
  443. // Store the message in the common memory buffer.
  444. //
  445. m_msg = msgLOOKSALIVE;
  446. //
  447. // Signal the script thread to process the message, but don't wait for
  448. // it to complete.
  449. //
  450. dw = SetEvent( m_hEventWait );
  451. if ( m_fLastLooksAlive )
  452. {
  453. hr = S_OK;
  454. }
  455. else
  456. {
  457. hr = S_FALSE;
  458. }
  459. ReleaseLockAndCleanup:
  460. SerializeLock.ReleaseLock( );
  461. Cleanup:
  462. HRETURN( hr );
  463. Error:
  464. LogError( hr );
  465. goto ReleaseLockAndCleanup;
  466. Win32Error:
  467. hr = HRESULT_FROM_WIN32( GetLastError( ) );
  468. goto Error;
  469. } //*** LooksAlive( )
  470. //////////////////////////////////////////////////////////////////////////////
  471. //
  472. // STDMETHODIMP
  473. // CScriptResource::IsAlive(
  474. // )
  475. //
  476. //////////////////////////////////////////////////////////////////////////////
  477. STDMETHODIMP
  478. CScriptResource::IsAlive(
  479. )
  480. {
  481. TraceClsFunc( "IsAlive( )\n" );
  482. HRESULT hr;
  483. hr = THR( WaitForMessageToComplete( msgISALIVE ) );
  484. HRETURN( hr );
  485. } //*** IsAlive( )
  486. //****************************************************************************
  487. //
  488. // Privates
  489. //
  490. //****************************************************************************
  491. //////////////////////////////////////////////////////////////////////////////
  492. //
  493. // HRESULT
  494. // CScriptResource::WaitForMessageToComplete(
  495. // SMESSAGE msgIn
  496. // )
  497. //
  498. //////////////////////////////////////////////////////////////////////////////
  499. HRESULT
  500. CScriptResource::WaitForMessageToComplete(
  501. EMESSAGE msgIn
  502. )
  503. {
  504. TraceClsFunc( "WaitForMessageToComplete( )\n" );
  505. HRESULT hr;
  506. BOOL b;
  507. DWORD dw;
  508. CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
  509. //
  510. // Acquire the serialization lock.
  511. //
  512. hr = THR( SerializeLock.AcquireLock( ) );
  513. if ( FAILED( hr ) )
  514. {
  515. //
  516. // Can't "goto Error" because we didn't acquire the lock.
  517. //
  518. LogError( hr );
  519. goto Cleanup;
  520. }
  521. //
  522. // Wait for the script thread to be "done."
  523. //
  524. dw = WaitForSingleObject( m_hEventDone, INFINITE );
  525. if ( dw != WAIT_OBJECT_0 )
  526. goto Win32Error;
  527. //
  528. // Reset the done event to indicate that the thread is not busy.
  529. //
  530. b = ResetEvent( m_hEventDone );
  531. if ( !b )
  532. goto Win32Error;
  533. //
  534. // Store the message in the common memory buffer.
  535. //
  536. m_msg = msgIn;
  537. //
  538. // Signal the script thread to process the message.
  539. //
  540. b = SetEvent( m_hEventWait );
  541. if ( !b )
  542. goto Win32Error;
  543. //
  544. // Wait for the thread to complete.
  545. //
  546. dw = WaitForSingleObject( m_hEventDone, INFINITE );
  547. if ( dw != WAIT_OBJECT_0 )
  548. goto Win32Error;
  549. //
  550. // Get the result of the task from the common buffer.
  551. //
  552. hr = m_hr;
  553. ReleaseLockAndCleanup:
  554. SerializeLock.ReleaseLock( );
  555. Cleanup:
  556. HRETURN( hr );
  557. Error:
  558. LogError( hr );
  559. goto ReleaseLockAndCleanup;
  560. Win32Error:
  561. hr = HRESULT_FROM_WIN32( GetLastError( ) );
  562. goto Error;
  563. } //*** WaitForMessageToComplete( )
  564. //////////////////////////////////////////////////////////////////////////////
  565. //
  566. // STDMETHODIMP
  567. // CScriptResource::LogError(
  568. // HRESULT hrIn
  569. // )
  570. //
  571. //////////////////////////////////////////////////////////////////////////////
  572. STDMETHODIMP
  573. CScriptResource::LogError(
  574. HRESULT hrIn
  575. )
  576. {
  577. TraceClsFunc1( "LogError( hrIn = 0x%08x )\n", hrIn );
  578. TraceMsg( mtfCALLS, "%s failed. HRESULT: 0x%08x\n", m_pszName, hrIn );
  579. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"HRESULT: 0x%1!08x!\n", hrIn );
  580. HRETURN( S_OK );
  581. } //*** LogError( )
  582. //////////////////////////////////////////////////////////////////////////////
  583. //
  584. // STDMETHODIMP
  585. // CScriptResource::LogScriptError(
  586. // EXCEPINFO ei
  587. // )
  588. //
  589. //////////////////////////////////////////////////////////////////////////////
  590. STDMETHODIMP
  591. CScriptResource::LogScriptError(
  592. EXCEPINFO ei
  593. )
  594. {
  595. TraceClsFunc( "LogScriptError( ... )\n" );
  596. HRESULT hr;
  597. if ( ei.pfnDeferredFillIn != NULL )
  598. {
  599. hr = THR( ei.pfnDeferredFillIn( &ei ) );
  600. }
  601. TraceMsg( mtfCALLS, "%s failed.\nError: %u\nSource: %s\nDescription: %s\n",
  602. m_pszName,
  603. ( ei.wCode == 0 ? ei.scode : ei.wCode ),
  604. ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource ),
  605. ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription )
  606. );
  607. (ClusResLogEvent)( m_hResource,
  608. LOG_ERROR,
  609. L"Error: %1!u! - Description: %2 (Source: %3)\n",
  610. ( ei.wCode == 0 ? ei.scode : ei.wCode ),
  611. ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription ),
  612. ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource )
  613. );
  614. HRETURN( S_OK );
  615. } //*** LogScriptError( )
  616. //////////////////////////////////////////////////////////////////////////////
  617. //
  618. // HRESULT
  619. // CScriptResource::OnOpen(
  620. // )
  621. //
  622. //////////////////////////////////////////////////////////////////////////////
  623. HRESULT
  624. CScriptResource::OnOpen(
  625. )
  626. {
  627. TraceClsFunc( "OnOpen( ... )\n" );
  628. HRESULT hr = S_OK;
  629. hr = HRESULT_FROM_WIN32( ERROR_RETRY );
  630. (ClusResLogEvent)( m_hResource,
  631. LOG_INFORMATION,
  632. L"Leave OnOpen without calling connect. Fail call so we don't try to use it.\n");
  633. return hr;
  634. } //*** OnOpen( )
  635. //////////////////////////////////////////////////////////////////////////////
  636. //
  637. // HRESULT
  638. // CScriptResource::OnClose(
  639. // )
  640. //
  641. //////////////////////////////////////////////////////////////////////////////
  642. HRESULT
  643. CScriptResource::OnClose(
  644. )
  645. {
  646. TraceClsFunc( "OnClose( )\n" );
  647. HRESULT hr;
  648. EXCEPINFO ei;
  649. VARIANT varResult;
  650. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  651. VariantInit( &varResult );
  652. // Assert( m_pidm != NULL );
  653. if ( m_pidm != NULL
  654. && m_dispidClose != DISPID_UNKNOWN
  655. )
  656. {
  657. hr = THR( m_pidm->Invoke( m_dispidClose,
  658. IID_NULL,
  659. LOCALE_USER_DEFAULT,
  660. DISPATCH_METHOD,
  661. &dispparamsNoArgs,
  662. &varResult,
  663. &ei,
  664. NULL
  665. ) );
  666. }
  667. else
  668. {
  669. hr = S_OK;
  670. }
  671. if ( hr == DISP_E_EXCEPTION )
  672. {
  673. LogScriptError( ei );
  674. }
  675. else if ( hr == DISP_E_MEMBERNOTFOUND )
  676. {
  677. //
  678. // No-op
  679. //
  680. hr = S_OK;
  681. }
  682. else if ( FAILED( hr ) )
  683. {
  684. LogError( hr );
  685. }
  686. VariantClear( &varResult );
  687. //
  688. // Disconnect script engine. Note that it may not be connected
  689. // but DoDisconnect is safe to call either way.
  690. //
  691. DoDisconnect( );
  692. HRETURN( hr );
  693. } //*** OnClose( )
  694. //////////////////////////////////////////////////////////////////////////////
  695. //
  696. // HRESULT
  697. // CScriptResource::OnOnline(
  698. // )
  699. //
  700. //////////////////////////////////////////////////////////////////////////////
  701. HRESULT
  702. CScriptResource::OnOnline(
  703. )
  704. {
  705. TraceClsFunc( "OnOnline( ... )\n" );
  706. HRESULT hr;
  707. DWORD dwErr;
  708. DWORD cbSize;
  709. DWORD dwLow;
  710. DWORD dwRead;
  711. LPWSTR pszCommand;
  712. EXCEPINFO ei;
  713. LPWSTR pszScriptFilePathTmp = NULL;
  714. BOOL b;
  715. BOOL bDoneConnect = FALSE;
  716. VARIANT varResult;
  717. HANDLE hFile = INVALID_HANDLE_VALUE;
  718. LPWSTR pszScriptName = NULL;
  719. LPSTR paszText = NULL;
  720. LPWSTR pszScriptText = NULL;
  721. VariantInit( &varResult );
  722. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  723. //
  724. // Figure out how big the filepath is.
  725. //
  726. dwErr = TW32( ClusterRegQueryValue( m_hkeyParams, CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH, NULL, NULL, &cbSize ) );
  727. if ( dwErr != ERROR_SUCCESS )
  728. {
  729. hr = HRESULT_FROM_WIN32( dwErr );
  730. goto Error;
  731. } // if: failed
  732. //
  733. // Make a buffer big enough.
  734. //
  735. cbSize += sizeof(L"");
  736. pszScriptFilePathTmp = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, cbSize ) );
  737. if ( pszScriptFilePathTmp == NULL )
  738. goto OutOfMemory;
  739. //
  740. // Grab it for real this time,
  741. //
  742. dwErr = TW32( ClusterRegQueryValue( m_hkeyParams, CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH, NULL, reinterpret_cast<LPBYTE>( pszScriptFilePathTmp ), &cbSize ) );
  743. if ( dwErr != ERROR_SUCCESS )
  744. {
  745. hr = HRESULT_FROM_WIN32( dwErr );
  746. goto Error;
  747. }
  748. //
  749. // If we have some old data from before then free this first.
  750. //
  751. if ( m_pszScriptFilePath != NULL )
  752. {
  753. LocalFree( m_pszScriptFilePath );
  754. }
  755. m_pszScriptFilePath = ClRtlExpandEnvironmentStrings( pszScriptFilePathTmp );
  756. if ( m_pszScriptFilePath == NULL )
  757. {
  758. hr = HRESULT_FROM_WIN32( GetLastError( ) );
  759. goto Error;
  760. }
  761. hr = DoConnect (m_pszScriptFilePath);
  762. if ( FAILED( hr ) )
  763. {
  764. goto Error;
  765. }
  766. bDoneConnect = TRUE;
  767. //
  768. // Open the script file.
  769. //
  770. hFile = CreateFile( m_pszScriptFilePath,
  771. GENERIC_READ,
  772. FILE_SHARE_READ,
  773. NULL,
  774. OPEN_EXISTING,
  775. 0,
  776. NULL
  777. );
  778. if ( hFile == INVALID_HANDLE_VALUE )
  779. {
  780. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  781. goto Error;
  782. } // if: failed to open
  783. //
  784. // Figure out its size.
  785. //
  786. dwLow = GetFileSize( hFile, NULL );
  787. if ( dwLow == -1 )
  788. {
  789. hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) );
  790. goto Error;
  791. } // if: failed to figure out size
  792. else if ( dwLow == -2 )
  793. goto OutOfMemory;
  794. //
  795. // Make a buffer big enough to hold it.
  796. //
  797. dwLow++; // add one for trailing NULL.
  798. paszText = reinterpret_cast<LPSTR>( TraceAlloc( LMEM_FIXED, dwLow ) );
  799. if ( paszText == NULL )
  800. goto OutOfMemory;
  801. //
  802. // Read the script into memory.
  803. //
  804. b = ReadFile( hFile, paszText, dwLow - 1, &dwRead, NULL );
  805. if ( !b )
  806. {
  807. hr = HRESULT_FROM_WIN32( TW32( GetLastError( ) ) );
  808. goto Error;
  809. } // if: failed
  810. if ( dwRead == - 1 )
  811. goto OutOfMemory;
  812. if ( dwLow - 1 != dwRead )
  813. goto OutOfMemory; // TODO: figure out a better error code.
  814. //
  815. // Make sure it is terminated.
  816. //
  817. paszText[ dwRead ] = L'\0';
  818. //
  819. // Make a buffer to convert the text into UNICODE.
  820. //
  821. dwRead++;
  822. pszScriptText = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, dwRead * sizeof(WCHAR) ) );
  823. if ( pszScriptText == NULL )
  824. goto OutOfMemory;
  825. //
  826. // Convert it to UNICODE.
  827. //
  828. Assert( lstrlenA( paszText ) + 1 == (signed)dwRead );
  829. mbstowcs( pszScriptText, paszText, dwRead );
  830. //
  831. // Load the script into the engine for pre-parsing.
  832. //
  833. hr = THR( m_pasp->ParseScriptText( pszScriptText,
  834. NULL,
  835. NULL,
  836. NULL,
  837. 0,
  838. 0,
  839. 0,
  840. &varResult,
  841. &ei
  842. ) );
  843. if ( hr == DISP_E_EXCEPTION )
  844. goto ErrorWithExcepInfo;
  845. else if ( FAILED( hr ) )
  846. goto Error;
  847. VariantClear( &varResult );
  848. Assert( m_pidm != NULL );
  849. //
  850. // Get DISPIDs for each method we will call.
  851. //
  852. pszCommand = L"Online";
  853. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  854. &pszCommand,
  855. 1,
  856. LOCALE_USER_DEFAULT,
  857. &m_dispidOnline
  858. ) );
  859. if ( hr == DISP_E_UNKNOWNNAME )
  860. {
  861. m_dispidOnline = DISPID_UNKNOWN;
  862. }
  863. else if ( FAILED( hr ) )
  864. {
  865. goto Error;
  866. }
  867. pszCommand = L"Close";
  868. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  869. &pszCommand,
  870. 1,
  871. LOCALE_USER_DEFAULT,
  872. &m_dispidClose
  873. ) );
  874. if ( hr == DISP_E_UNKNOWNNAME )
  875. {
  876. m_dispidClose = DISPID_UNKNOWN;
  877. }
  878. else if ( FAILED( hr ) )
  879. {
  880. goto Error;
  881. }
  882. pszCommand = L"Offline";
  883. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  884. &pszCommand,
  885. 1,
  886. LOCALE_USER_DEFAULT,
  887. &m_dispidOffline
  888. ) );
  889. if ( hr == DISP_E_UNKNOWNNAME )
  890. {
  891. m_dispidOffline = DISPID_UNKNOWN;
  892. }
  893. else if ( FAILED( hr ) )
  894. {
  895. goto Error;
  896. }
  897. pszCommand = L"Terminate";
  898. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  899. &pszCommand,
  900. 1,
  901. LOCALE_USER_DEFAULT,
  902. &m_dispidTerminate
  903. ) );
  904. if ( hr == DISP_E_UNKNOWNNAME )
  905. {
  906. m_dispidTerminate = DISPID_UNKNOWN;
  907. }
  908. else if ( FAILED( hr ) )
  909. {
  910. goto Error;
  911. }
  912. pszCommand = L"LooksAlive";
  913. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  914. &pszCommand,
  915. 1,
  916. LOCALE_USER_DEFAULT,
  917. &m_dispidLooksAlive
  918. ) );
  919. if ( hr == DISP_E_UNKNOWNNAME )
  920. {
  921. m_dispidLooksAlive = DISPID_UNKNOWN;
  922. }
  923. else if ( FAILED( hr ) )
  924. {
  925. goto Error;
  926. }
  927. pszCommand = L"IsAlive";
  928. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  929. &pszCommand,
  930. 1,
  931. LOCALE_USER_DEFAULT,
  932. &m_dispidIsAlive
  933. ) );
  934. if ( hr == DISP_E_UNKNOWNNAME )
  935. {
  936. m_dispidIsAlive = DISPID_UNKNOWN;
  937. }
  938. else if ( FAILED( hr ) )
  939. {
  940. goto Error;
  941. }
  942. //
  943. // Invoke the Online function.
  944. //
  945. if ( m_dispidOnline != DISPID_UNKNOWN )
  946. {
  947. hr = THR( m_pidm->Invoke( m_dispidOnline,
  948. IID_NULL,
  949. LOCALE_USER_DEFAULT,
  950. DISPATCH_METHOD,
  951. &dispparamsNoArgs,
  952. &varResult,
  953. &ei,
  954. NULL
  955. ) );
  956. if ( hr == DISP_E_EXCEPTION )
  957. {
  958. LogScriptError( ei );
  959. }
  960. else if ( hr == DISP_E_MEMBERNOTFOUND )
  961. {
  962. //
  963. // No-op
  964. //
  965. hr = S_OK;
  966. }
  967. else if ( FAILED( hr ) )
  968. {
  969. LogError( hr );
  970. }
  971. }
  972. //
  973. // Assume the resource LooksAlive...
  974. //
  975. m_fLastLooksAlive = TRUE;
  976. //
  977. // TODO: gpease 16-DEC-1999
  978. // Record and process the result of the Online call.
  979. //
  980. Cleanup:
  981. VariantClear( &varResult );
  982. if ( pszScriptFilePathTmp )
  983. {
  984. TraceFree( pszScriptFilePathTmp );
  985. } // if: pszScriptFilePathTmp
  986. if ( paszText != NULL )
  987. {
  988. TraceFree( paszText );
  989. } // if: paszText
  990. if ( pszScriptText != NULL )
  991. {
  992. TraceFree( pszScriptText );
  993. } // if: pszScriptText;
  994. if ( hFile != INVALID_HANDLE_VALUE )
  995. {
  996. CloseHandle( hFile );
  997. } // if: hFile
  998. HRETURN( hr );
  999. Error:
  1000. LogError( hr );
  1001. if ( bDoneConnect == TRUE )
  1002. {
  1003. DoDisconnect( );
  1004. }
  1005. goto Cleanup;
  1006. ErrorWithExcepInfo:
  1007. LogScriptError( ei );
  1008. goto Cleanup;
  1009. OutOfMemory:
  1010. hr = E_OUTOFMEMORY;
  1011. goto Cleanup;
  1012. } //*** OnOnline( )
  1013. //////////////////////////////////////////////////////////////////////////////
  1014. //
  1015. // HRESULT
  1016. // CScriptResource::OnOffline(
  1017. // )
  1018. //
  1019. //////////////////////////////////////////////////////////////////////////////
  1020. HRESULT
  1021. CScriptResource::OnOffline(
  1022. )
  1023. {
  1024. TraceClsFunc( "OnOffline( ... )\n" );
  1025. HRESULT hr;
  1026. EXCEPINFO ei;
  1027. VARIANT varResult;
  1028. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  1029. VariantInit( &varResult );
  1030. Assert( m_pidm != NULL );
  1031. if ( m_pidm != NULL
  1032. && m_dispidOffline != DISPID_UNKNOWN
  1033. )
  1034. {
  1035. hr = THR( m_pidm->Invoke( m_dispidOffline,
  1036. IID_NULL,
  1037. LOCALE_USER_DEFAULT,
  1038. DISPATCH_METHOD,
  1039. &dispparamsNoArgs,
  1040. &varResult,
  1041. &ei,
  1042. NULL
  1043. ) );
  1044. }
  1045. else
  1046. {
  1047. hr = S_OK;
  1048. }
  1049. if ( hr == DISP_E_EXCEPTION )
  1050. {
  1051. LogScriptError( ei );
  1052. }
  1053. else if ( hr == DISP_E_MEMBERNOTFOUND )
  1054. {
  1055. //
  1056. // No-op
  1057. //
  1058. hr = S_OK;
  1059. }
  1060. else if ( FAILED( hr ) )
  1061. {
  1062. LogError( hr );
  1063. }
  1064. VariantClear( &varResult );
  1065. //
  1066. // Tear down the scripting engine association as it is recreated in OnOnline.
  1067. //
  1068. DoDisconnect( );
  1069. HRETURN( hr );
  1070. } //*** OnOffline( )
  1071. //////////////////////////////////////////////////////////////////////////////
  1072. //
  1073. // HRESULT
  1074. // CScriptResource::OnTerminate(
  1075. // )
  1076. //
  1077. //////////////////////////////////////////////////////////////////////////////
  1078. HRESULT
  1079. CScriptResource::OnTerminate(
  1080. )
  1081. {
  1082. TraceClsFunc( "OnTerminate( ... )\n" );
  1083. HRESULT hr;
  1084. EXCEPINFO ei;
  1085. VARIANT varResult;
  1086. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  1087. VariantInit( &varResult );
  1088. // Assert( m_pidm != NULL );
  1089. if ( m_pidm != NULL
  1090. && m_dispidTerminate != DISPID_UNKNOWN
  1091. )
  1092. {
  1093. hr = THR( m_pidm->Invoke( m_dispidTerminate,
  1094. IID_NULL,
  1095. LOCALE_USER_DEFAULT,
  1096. DISPATCH_METHOD,
  1097. &dispparamsNoArgs,
  1098. &varResult,
  1099. &ei,
  1100. NULL
  1101. ) );
  1102. }
  1103. else
  1104. {
  1105. hr = S_OK;
  1106. }
  1107. if ( hr == DISP_E_EXCEPTION )
  1108. {
  1109. LogScriptError( ei );
  1110. }
  1111. else if ( hr == DISP_E_MEMBERNOTFOUND )
  1112. {
  1113. //
  1114. // No-op
  1115. //
  1116. hr = S_OK;
  1117. }
  1118. else if ( FAILED( hr ) )
  1119. {
  1120. LogError( hr );
  1121. }
  1122. HRETURN( hr );
  1123. } //*** OnTerminate( )
  1124. //////////////////////////////////////////////////////////////////////////////
  1125. //
  1126. // HRESULT
  1127. // CScriptResource::OnLooksAlive(
  1128. // )
  1129. //
  1130. //////////////////////////////////////////////////////////////////////////////
  1131. HRESULT
  1132. CScriptResource::OnLooksAlive(
  1133. )
  1134. {
  1135. TraceClsFunc( "OnLooksAlive( ... )\n" );
  1136. HRESULT hr;
  1137. EXCEPINFO ei;
  1138. VARIANT varResult;
  1139. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  1140. VariantInit( &varResult );
  1141. Assert( m_pidm != NULL );
  1142. if ( m_pidm != NULL
  1143. && m_dispidLooksAlive != DISPID_UNKNOWN
  1144. )
  1145. {
  1146. hr = THR( m_pidm->Invoke( m_dispidLooksAlive,
  1147. IID_NULL,
  1148. LOCALE_USER_DEFAULT,
  1149. DISPATCH_METHOD,
  1150. &dispparamsNoArgs,
  1151. &varResult,
  1152. &ei,
  1153. NULL
  1154. ) );
  1155. }
  1156. else
  1157. {
  1158. (ClusResLogEvent)( m_hResource,
  1159. LOG_ERROR,
  1160. L"%1 did not implement Function LooksAlive( ). This is a required function.\n",
  1161. m_pszName
  1162. );
  1163. hr = DISP_E_MEMBERNOTFOUND;
  1164. goto Cleanup;
  1165. }
  1166. if ( hr == DISP_E_EXCEPTION )
  1167. {
  1168. LogScriptError( ei );
  1169. goto Cleanup;
  1170. }
  1171. else if ( FAILED( hr ) )
  1172. {
  1173. LogError( hr );
  1174. goto Cleanup;
  1175. }
  1176. if ( V_VT( &varResult ) == VT_BOOL )
  1177. {
  1178. if ( !V_BOOL( &varResult ) )
  1179. {
  1180. hr = S_FALSE;
  1181. } // if: not alive
  1182. } // if: correct type returned
  1183. else
  1184. {
  1185. hr = THR( E_INVALIDARG );
  1186. LogError( hr );
  1187. } // else: failed
  1188. Cleanup:
  1189. VariantClear( &varResult );
  1190. //
  1191. // Only if the result of this function is S_OK is the resource
  1192. // considered alive.
  1193. //
  1194. if ( hr == S_OK )
  1195. {
  1196. m_fLastLooksAlive = TRUE;
  1197. } // if: S_OK
  1198. else
  1199. {
  1200. m_fLastLooksAlive = FALSE;
  1201. } // else: failed
  1202. HRETURN( hr );
  1203. } //*** OnLooksAlive( )
  1204. //////////////////////////////////////////////////////////////////////////////
  1205. //
  1206. // HRESULT
  1207. // CScriptResource::OnIsAlive(
  1208. // )
  1209. //
  1210. //////////////////////////////////////////////////////////////////////////////
  1211. HRESULT
  1212. CScriptResource::OnIsAlive(
  1213. )
  1214. {
  1215. TraceClsFunc( "IsAlive( ... )\n" );
  1216. HRESULT hr;
  1217. EXCEPINFO ei;
  1218. VARIANT varResult;
  1219. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  1220. VariantInit( &varResult );
  1221. if ( m_pidm != NULL
  1222. && m_dispidIsAlive != DISPID_UNKNOWN
  1223. )
  1224. {
  1225. hr = THR( m_pidm->Invoke( m_dispidIsAlive,
  1226. IID_NULL,
  1227. LOCALE_USER_DEFAULT,
  1228. DISPATCH_METHOD,
  1229. &dispparamsNoArgs,
  1230. &varResult,
  1231. &ei,
  1232. NULL
  1233. ) );
  1234. }
  1235. else
  1236. {
  1237. (ClusResLogEvent)( m_hResource,
  1238. LOG_ERROR,
  1239. L"%1 did not implement Function IsAlive( ). This is a required function.\n",
  1240. m_pszName
  1241. );
  1242. hr = DISP_E_MEMBERNOTFOUND;
  1243. goto Cleanup;
  1244. }
  1245. if ( hr == DISP_E_EXCEPTION )
  1246. {
  1247. LogScriptError( ei );
  1248. goto Cleanup;
  1249. }
  1250. else if ( FAILED( hr ) )
  1251. {
  1252. LogError( hr );
  1253. goto Cleanup;
  1254. }
  1255. if ( V_VT( &varResult ) == VT_BOOL )
  1256. {
  1257. if ( !V_BOOL( &varResult ) )
  1258. {
  1259. hr = S_FALSE;
  1260. } // if: not alive
  1261. } // if: correct type returned
  1262. else
  1263. {
  1264. hr = THR( E_INVALIDARG );
  1265. LogError( hr );
  1266. } // else: failed
  1267. Cleanup:
  1268. VariantClear( &varResult );
  1269. HRETURN( hr );
  1270. } //*** OnIsAlive( )
  1271. /////////////////////////////////////////////////////////////////////////////
  1272. //
  1273. // DWORD
  1274. // WINAPI
  1275. // CScriptResource::S_ThreadProc(
  1276. // LPVOID pParam
  1277. // )
  1278. //
  1279. /////////////////////////////////////////////////////////////////////////////
  1280. DWORD
  1281. WINAPI
  1282. CScriptResource::S_ThreadProc(
  1283. LPVOID pParam
  1284. )
  1285. {
  1286. MSG msg;
  1287. HRESULT hr;
  1288. DWORD dw;
  1289. BOOL b;
  1290. CScriptResource * pscript = reinterpret_cast< CScriptResource * >( pParam );
  1291. Assert( pscript != NULL );
  1292. //
  1293. // Initialize COM.
  1294. //
  1295. hr = THR( CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE ) );
  1296. if ( FAILED( hr ) )
  1297. goto Error;
  1298. for( ;; ) // ever
  1299. {
  1300. //
  1301. // Indicate that we are ready to do something.
  1302. //
  1303. b = SetEvent( pscript->m_hEventDone );
  1304. if ( !b )
  1305. goto Win32Error;
  1306. //
  1307. // Wait for someone to need something.
  1308. //
  1309. dw = WaitForSingleObject( pscript->m_hEventWait, INFINITE );
  1310. if ( dw != WAIT_OBJECT_0 )
  1311. {
  1312. hr = HRESULT_FROM_WIN32( dw );
  1313. goto Error;
  1314. }
  1315. //
  1316. // Reset the event.
  1317. //
  1318. b = ResetEvent( pscript->m_hEventWait );
  1319. if ( !b )
  1320. goto Win32Error;
  1321. //
  1322. // Do what they ask.
  1323. //
  1324. switch ( pscript->m_msg )
  1325. {
  1326. case msgOPEN:
  1327. pscript->m_hr = THR( pscript->OnOpen( ) );
  1328. break;
  1329. case msgCLOSE:
  1330. pscript->m_hr = THR( pscript->OnClose( ) );
  1331. break;
  1332. case msgONLINE:
  1333. pscript->m_hr = THR( pscript->OnOnline( ) );
  1334. break;
  1335. case msgOFFLINE:
  1336. pscript->m_hr = THR( pscript->OnOffline( ) );
  1337. break;
  1338. case msgTERMINATE:
  1339. pscript->m_hr = THR( pscript->OnTerminate( ) );
  1340. break;
  1341. case msgLOOKSALIVE:
  1342. pscript->m_hr = STHR( pscript->OnLooksAlive( ) );
  1343. break;
  1344. case msgISALIVE:
  1345. pscript->m_hr = STHR( pscript->OnIsAlive( ) );
  1346. break;
  1347. case msgDIE:
  1348. //
  1349. // This means the resource is being released.
  1350. //
  1351. goto Cleanup;
  1352. }
  1353. } // spin forever
  1354. Cleanup:
  1355. CoUninitialize( );
  1356. return hr;
  1357. Error:
  1358. pscript->LogError( hr );
  1359. goto Cleanup;
  1360. Win32Error:
  1361. hr = HRESULT_FROM_WIN32( GetLastError( ) );
  1362. goto Error;
  1363. } //*** S_ThreadProc( )
  1364. //////////////////////////////////////////////////////////////////////////////
  1365. //
  1366. // DWORD
  1367. // CScriptResource::MakeScriptEngineAssociation( pszScriptFileName )
  1368. //
  1369. // Description:
  1370. // Takes the filename and splits off the extension then queries
  1371. // the registry to obtain the association and finally queries the
  1372. // ScriptingEngine key under that association and allocates and
  1373. // returns a buffer containing the engine name. This engine name
  1374. // is suitable for input into CLSIDFromProgID.
  1375. //
  1376. // Arguments:
  1377. // pszScriptFileName - Pointer to null terminated script file name (full path with environment expanded).
  1378. //
  1379. // Return Values:
  1380. // NULL - Failure to read engine for this key, consult GetLastError() for details.
  1381. // Valid pointer to string buffer containing engine prog id.
  1382. //
  1383. //////////////////////////////////////////////////////////////////////////////
  1384. #define SCRIPTENGINE_KEY_STRING L"\\ScriptEngine"
  1385. LPWSTR
  1386. CScriptResource::MakeScriptEngineAssociation(
  1387. IN LPCWSTR pszScriptFileName
  1388. )
  1389. {
  1390. LPWSTR pszAssociation = NULL;
  1391. LPWSTR pszEngineName = NULL;
  1392. LONG lRegStatus = ERROR_SUCCESS;
  1393. HKEY hKey = NULL;
  1394. WCHAR szExtension[_MAX_EXT];
  1395. DWORD dwType, cbAssociationSize, cbEngineNameSize, dwNumChars;
  1396. //
  1397. // First split the path to get the extension.
  1398. //
  1399. _wsplitpath (pszScriptFileName, NULL, NULL, NULL, szExtension);
  1400. if (szExtension[0] == L'\0') {
  1401. SetLastError (ERROR_FILE_NOT_FOUND);
  1402. goto Cleanup;
  1403. }
  1404. //
  1405. // Pre-parse to patch up .scr association!
  1406. //
  1407. if (_wcsicmp (szExtension, L".scr") == 0)
  1408. {
  1409. LPWSTR pszSCREngine=NULL;
  1410. pszSCREngine = (LPWSTR) TraceAlloc( GPTR, sizeof( L"VBScript" ) );
  1411. if ( pszSCREngine == NULL )
  1412. goto ErrorOutOfMemory;
  1413. else
  1414. {
  1415. wcscpy (pszSCREngine, L"VBScript");
  1416. return pszSCREngine;
  1417. }
  1418. }
  1419. //
  1420. // If the pre-parse didn't get it then go to the registry to do
  1421. // the right thing.
  1422. //
  1423. lRegStatus = RegOpenKeyExW( HKEY_CLASSES_ROOT, // handle to open key
  1424. szExtension, // subkey name
  1425. 0, // reserved
  1426. KEY_READ, // security access desired.
  1427. &hKey); // key handle returned
  1428. if (lRegStatus != ERROR_SUCCESS)
  1429. goto Error;
  1430. //
  1431. // Query the value to get the size of the buffer to allocate.
  1432. // NB cbSize contains the size including the '\0'
  1433. //
  1434. lRegStatus = RegQueryValueExW( hKey, // handle to key
  1435. NULL, // value name
  1436. 0, // reserved
  1437. &dwType, // type buffer
  1438. NULL, // data buffer
  1439. &cbAssociationSize); // size of data buffer
  1440. if ( lRegStatus != ERROR_SUCCESS )
  1441. goto Error;
  1442. if ( dwType != REG_SZ )
  1443. goto ErrorBadType;
  1444. dwNumChars = cbAssociationSize / sizeof (WCHAR);
  1445. pszAssociation = (LPWSTR) TraceAlloc( GPTR, cbAssociationSize + sizeof (SCRIPTENGINE_KEY_STRING) );
  1446. if ( pszAssociation == NULL )
  1447. goto ErrorOutOfMemory;
  1448. // Get the value for real.
  1449. //
  1450. lRegStatus = RegQueryValueExW( hKey, // handle to key
  1451. NULL, // value name
  1452. 0, // reserved
  1453. &dwType, // type buffer
  1454. (LPBYTE) pszAssociation, // data buffer
  1455. &cbAssociationSize ); // size of data buffer
  1456. if ( lRegStatus != ERROR_SUCCESS )
  1457. goto Error;
  1458. if ( dwType != REG_SZ )
  1459. goto ErrorBadType;
  1460. lRegStatus = RegCloseKey( hKey );
  1461. if ( lRegStatus != ERROR_SUCCESS )
  1462. goto Error;
  1463. hKey = NULL;
  1464. //
  1465. // Take the data and make a key with \ScriptEngine on the end. If
  1466. // we find this then we can use the file.
  1467. //
  1468. swprintf( &pszAssociation[ dwNumChars - 1 ], SCRIPTENGINE_KEY_STRING );
  1469. pszAssociation[ dwNumChars + (sizeof( SCRIPTENGINE_KEY_STRING ) / sizeof ( WCHAR ) ) - 1 ] = L'\0';
  1470. lRegStatus = RegOpenKeyExW( HKEY_CLASSES_ROOT, // handle to open key
  1471. pszAssociation, // subkey name
  1472. 0, // reserved
  1473. KEY_READ, // security access
  1474. &hKey ); // key handle
  1475. lRegStatus = RegQueryValueExW( hKey, // handle to key
  1476. NULL, // value name
  1477. 0, // reserved
  1478. &dwType, // type buffer
  1479. NULL, // data buffer
  1480. &cbEngineNameSize); // size of data buffer
  1481. if ( lRegStatus != ERROR_SUCCESS )
  1482. goto Error;
  1483. if ( dwType != REG_SZ )
  1484. goto ErrorBadType;
  1485. dwNumChars = cbEngineNameSize / sizeof (WCHAR);
  1486. pszEngineName = (LPWSTR) TraceAlloc( GPTR, cbEngineNameSize );
  1487. if ( NULL == pszEngineName )
  1488. {
  1489. goto ErrorOutOfMemory;
  1490. }
  1491. pszEngineName[ dwNumChars - 1 ] = '\0';
  1492. //
  1493. // Get the value for real.
  1494. //
  1495. lRegStatus = RegQueryValueExW( hKey, // handle to key
  1496. NULL, // value name
  1497. 0, // reserved
  1498. &dwType, // type buffer
  1499. (LPBYTE) pszEngineName, // data buffer
  1500. &cbEngineNameSize); // size of data buffer
  1501. if ( lRegStatus != ERROR_SUCCESS )
  1502. goto Error;
  1503. if ( dwType != REG_SZ )
  1504. goto ErrorBadType;
  1505. lRegStatus = RegCloseKey( hKey );
  1506. if ( lRegStatus != ERROR_SUCCESS )
  1507. goto Error;
  1508. hKey = NULL;
  1509. goto Cleanup;
  1510. Error:
  1511. SetLastError (lRegStatus);
  1512. goto ErrorCleanup;
  1513. ErrorBadType:
  1514. SetLastError (ERROR_FILE_NOT_FOUND);
  1515. goto ErrorCleanup;
  1516. ErrorOutOfMemory:
  1517. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  1518. goto ErrorCleanup;
  1519. ErrorCleanup:
  1520. if (pszEngineName)
  1521. {
  1522. TraceFree (pszEngineName);
  1523. pszEngineName = NULL;
  1524. }
  1525. Cleanup:
  1526. if (pszAssociation)
  1527. TraceFree (pszAssociation);
  1528. if (hKey)
  1529. (void) RegCloseKey (hKey);
  1530. return pszEngineName;
  1531. }
  1532. #undef SCRIPTENGINE_KEY_STRING
  1533. //////////////////////////////////////////////////////////////////////////////
  1534. //
  1535. // HRESULT
  1536. // CScriptResource::DoConnect( szScriptFilePath )
  1537. //
  1538. // Description:
  1539. // Connects to the script engine associated with the script passed in.
  1540. //
  1541. // Arguments:
  1542. // pszScriptFileName - Pointer to null terminated script file name (full path with environment expanded).
  1543. //
  1544. // Return Values:
  1545. // S_OK - connected OK.
  1546. // Failure status - local cleanup performed.
  1547. //
  1548. //////////////////////////////////////////////////////////////////////////////
  1549. HRESULT
  1550. CScriptResource::DoConnect(
  1551. IN LPWSTR szScriptFilePath
  1552. )
  1553. {
  1554. HRESULT hr = S_OK;
  1555. DWORD cbSize;
  1556. DWORD dwErr;
  1557. CLSID clsidScriptEngine;
  1558. CActiveScriptSite * psite;
  1559. //
  1560. // Create the scripting site.
  1561. //
  1562. psite = new CActiveScriptSite( m_hResource, ClusResLogEvent, m_hkeyParams, m_pszName );
  1563. if ( psite == NULL )
  1564. goto OutOfMemory;
  1565. hr = THR( psite->QueryInterface( IID_IActiveScriptSite, reinterpret_cast<void**>( &m_pass ) ) );
  1566. psite->Release( ); // release promptly
  1567. if ( FAILED( hr ) )
  1568. goto Error;
  1569. //
  1570. // Find the Active Engine.
  1571. //
  1572. if (szScriptFilePath == NULL)
  1573. {
  1574. (ClusResLogEvent)( m_hResource,
  1575. LOG_INFORMATION, L"DoConnect: Default to VBScript\n");
  1576. hr = THR( CLSIDFromProgID( L"VBScript", &clsidScriptEngine ) );
  1577. if ( FAILED( hr ) )
  1578. goto Error;
  1579. }
  1580. else
  1581. {
  1582. (ClusResLogEvent)( m_hResource,
  1583. LOG_INFORMATION, L"DoConnect: Got path: %1\n", szScriptFilePath);
  1584. //
  1585. // Find the program associated with the extension.
  1586. //
  1587. if ( m_pszScriptEngine != NULL )
  1588. {
  1589. TraceFree( m_pszScriptEngine );
  1590. }
  1591. m_pszScriptEngine = MakeScriptEngineAssociation( szScriptFilePath );
  1592. if ( m_pszScriptEngine == NULL)
  1593. {
  1594. (ClusResLogEvent)( m_hResource,
  1595. LOG_ERROR, L"Error getting engine\n");
  1596. hr = HRESULT_FROM_WIN32( GetLastError( ) );
  1597. goto Error;
  1598. }
  1599. (ClusResLogEvent)( m_hResource,
  1600. LOG_ERROR, L"Got engine %1\n", m_pszScriptEngine);
  1601. hr = THR( CLSIDFromProgID( m_pszScriptEngine, &clsidScriptEngine ) );
  1602. if ( FAILED( hr ) )
  1603. {
  1604. (ClusResLogEvent)( m_hResource,
  1605. LOG_ERROR, L"Error getting prog ID\n");
  1606. goto Error;
  1607. }
  1608. }
  1609. //
  1610. // Create an instance of it.
  1611. //
  1612. TraceDo( hr = THR( CoCreateInstance( clsidScriptEngine,
  1613. NULL,
  1614. CLSCTX_SERVER,
  1615. IID_IActiveScriptParse,
  1616. reinterpret_cast<void**>( &m_pasp )
  1617. ) )
  1618. );
  1619. if ( FAILED( hr ) ) {
  1620. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to create instance of CLSID\n");
  1621. goto Error;
  1622. }
  1623. m_pasp = TraceInterface( L"Active Script Engine", IActiveScriptParse, m_pasp, 1 );
  1624. TraceDo( hr = THR( m_pasp->QueryInterface( IID_IActiveScript, (void**) &m_pas ) ) );
  1625. if ( FAILED( hr ) )
  1626. goto Error;
  1627. m_pas = TraceInterface( L"Active Script Engine", IActiveScript, m_pas, 1 );
  1628. //
  1629. // Initialize it.
  1630. //
  1631. TraceDo( hr = THR( m_pasp->InitNew( ) ) );
  1632. if ( FAILED( hr ) )
  1633. {
  1634. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to InitNew\n");
  1635. goto Error;
  1636. }
  1637. #if defined(DEBUG)
  1638. //
  1639. // Set our site. We'll give out a new tracking interface to track this separately.
  1640. //
  1641. {
  1642. IActiveScriptSite * psite;
  1643. hr = THR( m_pass->TypeSafeQI( IActiveScriptSite, &psite ) );
  1644. Assert( hr == S_OK );
  1645. TraceDo( hr = THR( m_pas->SetScriptSite( psite ) ) );
  1646. psite->Release( ); // release promptly
  1647. if ( FAILED( hr ) )
  1648. goto Error;
  1649. }
  1650. #else
  1651. TraceDo( hr = THR( m_pas->SetScriptSite( m_pass ) ) );
  1652. if ( FAILED( hr ) )
  1653. {
  1654. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to SetScriptSite\n");
  1655. goto Error;
  1656. }
  1657. #endif
  1658. //
  1659. // Add Document to the global members.
  1660. //
  1661. TraceDo( hr = THR( m_pas->AddNamedItem( L"Resource", SCRIPTITEM_ISVISIBLE ) ) );
  1662. if ( FAILED( hr ) )
  1663. goto Error;
  1664. //
  1665. // Connect the script.
  1666. //
  1667. TraceDo( hr = THR( m_pas->SetScriptState( SCRIPTSTATE_CONNECTED ) ) );
  1668. if ( FAILED( hr ) ) {
  1669. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to SetScriptState\n");
  1670. goto Error;
  1671. }
  1672. //
  1673. // Get the dispatch inteface to the script.
  1674. //
  1675. TraceDo( hr = THR( m_pas->GetScriptDispatch( NULL, &m_pidm ) ) );
  1676. if ( FAILED( hr) ) {
  1677. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to GetScriptDispatch\n");
  1678. goto Error;
  1679. }
  1680. m_pidm = TraceInterface( L"Active Script", IDispatch, m_pidm, 1 );
  1681. hr = S_OK;
  1682. Cleanup:
  1683. HRETURN( hr );
  1684. Error:
  1685. LogError( hr );
  1686. goto Cleanup;
  1687. OutOfMemory:
  1688. hr = E_OUTOFMEMORY;
  1689. goto Cleanup;
  1690. }
  1691. //////////////////////////////////////////////////////////////////////////////
  1692. //
  1693. // void
  1694. // CScriptResource::DoDisconnect( )
  1695. //
  1696. // Description:
  1697. // Disconnects from any currently connected script engine.
  1698. //
  1699. // Arguments:
  1700. // none.
  1701. //
  1702. // Return Values:
  1703. // none.
  1704. //
  1705. //////////////////////////////////////////////////////////////////////////////
  1706. void
  1707. CScriptResource::DoDisconnect( )
  1708. {
  1709. //
  1710. // Cleanup the scripting engine.
  1711. //
  1712. if ( m_pszScriptFilePath != NULL )
  1713. {
  1714. LocalFree( m_pszScriptFilePath );
  1715. m_pszScriptFilePath = NULL;
  1716. } // if: m_pszScriptFilePath
  1717. if ( m_pszScriptEngine != NULL )
  1718. {
  1719. TraceFree( m_pszScriptEngine );
  1720. m_pszScriptEngine = NULL;
  1721. } // if: m_pszScriptEngine
  1722. if ( m_pidm != NULL )
  1723. {
  1724. TraceDo( m_pidm->Release( ) );
  1725. m_pidm = NULL;
  1726. } // if: m_pidm
  1727. if ( m_pasp != NULL )
  1728. {
  1729. TraceDo( m_pasp->Release( ) );
  1730. m_pasp = NULL;
  1731. } // if: m_pasp
  1732. if ( m_pas != NULL )
  1733. {
  1734. TraceDo( m_pas->Close( ) );
  1735. TraceDo( m_pas->Release( ) );
  1736. m_pas = NULL;
  1737. } // if: m_pas
  1738. if ( m_pass != NULL )
  1739. {
  1740. TraceDo( m_pass->Release( ) );
  1741. m_pass = NULL;
  1742. } // if: m_pass
  1743. }