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.

3420 lines
93 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2003 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ScriptResource.cpp
  7. //
  8. // Description:
  9. // CScriptResource class implementation.
  10. //
  11. // Maintained By:
  12. // Ozan Ozhan (OzanO) 22-MAR-2002
  13. // David Potter (DavidP) 14-JUN-2001
  14. // Geoff Pease (GPease) 14-DEC-1999
  15. //
  16. //////////////////////////////////////////////////////////////////////////////
  17. #include "Pch.h"
  18. #include "ActiveScriptSite.h"
  19. #include "ScriptResource.h"
  20. #include "SpinLock.h"
  21. DEFINE_THISCLASS("CScriptResource")
  22. //
  23. // We need this to log to the system event log
  24. //
  25. #define LOG_CURRENT_MODULE LOG_MODULE_GENSCRIPT
  26. //
  27. // KB: gpease 08-FEB-2000
  28. //
  29. // The Generic Scripting Resource uses a separate working thread to do all
  30. // calls into the Script. This is because the Scripting Host Engines require
  31. // only the creating thread to call them (remember, scripting is designed
  32. // to be used in a user mode application where usually the UI thread runs
  33. // the script). To make this possible, we serialize the threads entering the
  34. // the script using a user-mode spinlock (m_lockSerialize). We then use two events
  35. // to signal the "worker thread" (m_EventWait) and to signal when the "worker
  36. // thread" has completed the task (m_EventDone).
  37. //
  38. // LooksAlive is implemented by returning the last result of a LooksAlive. It
  39. // will start the "worker thread" doing the LooksAlive, but not wait for the
  40. // thread to return the result. Because of this, all the other threads must
  41. // make sure that the "Done Event" (m_EventDone) is signalled before writing
  42. // into the common buffers (m_msg and m_hr).
  43. //
  44. //////////////////////////////////////////////////////////////////////////////
  45. //
  46. // CScriptResource_CreateInstance
  47. //
  48. // Description:
  49. // Creates an intialized instance of CScriptResource.
  50. //
  51. // Arguments:
  52. // None.
  53. //
  54. // Return Values:
  55. // NULL - Failure to create or initialize.
  56. // valid pointer to a CScriptResource.
  57. //
  58. //////////////////////////////////////////////////////////////////////////////
  59. CScriptResource *
  60. CScriptResource_CreateInstance(
  61. LPCWSTR pszNameIn,
  62. HKEY hkeyIn,
  63. RESOURCE_HANDLE hResourceIn
  64. )
  65. {
  66. TraceFunc( "" );
  67. CScriptResource * lpcc = new CScriptResource();
  68. if ( lpcc != NULL )
  69. {
  70. HRESULT hr = THR( lpcc->HrInit( pszNameIn, hkeyIn, hResourceIn ) );
  71. if ( SUCCEEDED( hr ) )
  72. {
  73. RETURN( lpcc );
  74. } // if: success
  75. delete lpcc;
  76. } // if: got object
  77. RETURN(NULL);
  78. } //*** CScriptResource_CreateInstance
  79. //////////////////////////////////////////////////////////////////////////////
  80. //
  81. // Constructor
  82. //
  83. //////////////////////////////////////////////////////////////////////////////
  84. CScriptResource::CScriptResource( void ) :
  85. m_dispidOpen(DISPID_UNKNOWN),
  86. m_dispidClose(DISPID_UNKNOWN),
  87. m_dispidOnline(DISPID_UNKNOWN),
  88. m_dispidOffline(DISPID_UNKNOWN),
  89. m_dispidTerminate(DISPID_UNKNOWN),
  90. m_dispidLooksAlive(DISPID_UNKNOWN),
  91. m_dispidIsAlive(DISPID_UNKNOWN),
  92. m_pszScriptFilePath( NULL ),
  93. m_pszHangEntryPoint( NULL ),
  94. m_hScriptFile( INVALID_HANDLE_VALUE ),
  95. m_fHangDetected( FALSE ),
  96. m_fPendingTimeoutChanged( TRUE ),
  97. m_dwPendingTimeout( CLUSTER_RESOURCE_DEFAULT_PENDING_TIMEOUT ),
  98. m_msgLastExecuted( msgUNKNOWN ),
  99. m_pProps( NULL )
  100. {
  101. TraceFunc1( "%s", __THISCLASS__ );
  102. Assert( m_cRef == 0 );
  103. Assert( m_pass == NULL );
  104. Assert( m_pasp == NULL );
  105. Assert( m_pas == NULL );
  106. Assert( m_pidm == NULL );
  107. TraceFuncExit();
  108. } //*** constructor
  109. //////////////////////////////////////////////////////////////////////////////
  110. //
  111. // Destructor
  112. //
  113. //////////////////////////////////////////////////////////////////////////////
  114. CScriptResource::~CScriptResource( void )
  115. {
  116. TraceFunc( "" );
  117. HRESULT hr;
  118. CSpinLock SpinLock( &m_lockSerialize, INFINITE );
  119. //
  120. // Make sure no one else has this lock.... else why are we going away?
  121. //
  122. hr = SpinLock.AcquireLock();
  123. Assert( hr == S_OK );
  124. //
  125. // Kill the worker thread.
  126. //
  127. if ( m_hThread != NULL )
  128. {
  129. // Tell it to DIE
  130. m_msg = msgDIE;
  131. // Signal the event.
  132. SetEvent( m_hEventWait );
  133. // Wait for it to happen. This shouldn't take long at all.
  134. WaitForSingleObject( m_hThread, 30000 ); // 30 seconds
  135. // Cleanup the handle.
  136. CloseHandle( m_hThread );
  137. }
  138. if ( m_hEventDone != NULL )
  139. {
  140. CloseHandle( m_hEventDone );
  141. }
  142. if ( m_hEventWait != NULL )
  143. {
  144. CloseHandle( m_hEventWait );
  145. }
  146. LocalFree( m_pszScriptFilePath );
  147. TraceFree( m_pszName );
  148. delete [] m_pszHangEntryPoint;
  149. if ( m_hkeyParams != NULL )
  150. {
  151. ClusterRegCloseKey( m_hkeyResource );
  152. } // if: m_hkeyResource
  153. if ( m_hkeyParams != NULL )
  154. {
  155. ClusterRegCloseKey( m_hkeyParams );
  156. } // if: m_hkeyParams
  157. #if defined(DEBUG)
  158. //
  159. // Make the debug build happy. Not needed in RETAIL.
  160. //
  161. SpinLock.ReleaseLock();
  162. #endif // defined(DEBUG)
  163. TraceFuncExit();
  164. } //*** destructor
  165. //////////////////////////////////////////////////////////////////////////////
  166. //
  167. // CScriptResource::Init
  168. //
  169. // Description:
  170. // Initializes the class.
  171. //
  172. // Arguments:
  173. // pszNameIn - Name of resource instance.
  174. // hkeyIn - The cluster key root for this resource instance.
  175. // hResourceIn - The hResource for this instance.
  176. //
  177. // Return Value:
  178. // S_OK -
  179. // Success.
  180. // HRESULT_FROM_WIN32() error -
  181. // if Win32 call failed.
  182. // E_OUTOFMEMORY -
  183. // Out of memory.
  184. // other HRESULT errors.
  185. //
  186. //////////////////////////////////////////////////////////////////////////////
  187. HRESULT
  188. CScriptResource::HrInit(
  189. LPCWSTR pszNameIn,
  190. HKEY hkeyIn,
  191. RESOURCE_HANDLE hResourceIn
  192. )
  193. {
  194. TraceFunc1( "pszNameIn = '%ws'", pszNameIn );
  195. HRESULT hr = S_OK;
  196. DWORD scErr;
  197. // IUnknown
  198. AddRef();
  199. // Other
  200. m_hResource = hResourceIn;
  201. Assert( m_pszName == NULL );
  202. Assert( m_pszScriptFilePath == NULL );
  203. Assert( m_pszScriptEngine == NULL );
  204. Assert( m_hEventWait == NULL );
  205. Assert( m_hEventDone == NULL );
  206. Assert( m_lockSerialize == FALSE );
  207. //
  208. // Create some event to wait on.
  209. //
  210. // Scripting engine thread wait event
  211. m_hEventWait = CreateEvent( NULL, TRUE, FALSE, NULL );
  212. if ( m_hEventWait == NULL )
  213. {
  214. scErr = TW32( GetLastError() );
  215. hr = HRESULT_FROM_WIN32( scErr );
  216. goto Error;
  217. }
  218. // Task completion event
  219. m_hEventDone = CreateEvent( NULL, TRUE, FALSE, NULL );
  220. if ( m_hEventDone == NULL )
  221. {
  222. scErr = TW32( GetLastError() );
  223. hr = HRESULT_FROM_WIN32( scErr );
  224. goto Error;
  225. }
  226. //
  227. // Copy the resource name.
  228. //
  229. m_pszName = TraceStrDup( pszNameIn );
  230. if ( m_pszName == NULL )
  231. {
  232. hr = THR( E_OUTOFMEMORY );
  233. goto Cleanup;
  234. }
  235. //
  236. // Save the registry key for this resource in m_kheyResource.
  237. //
  238. scErr = TW32( ClusterRegOpenKey( hkeyIn, L"", KEY_ALL_ACCESS, &m_hkeyResource ) );
  239. if ( scErr != ERROR_SUCCESS )
  240. {
  241. hr = HRESULT_FROM_WIN32( scErr );
  242. goto Error;
  243. } // if: failed
  244. //
  245. // Open the parameters key.
  246. //
  247. scErr = TW32( ClusterRegOpenKey( hkeyIn, L"Parameters", KEY_ALL_ACCESS, &m_hkeyParams ) );
  248. if ( scErr != ERROR_SUCCESS )
  249. {
  250. hr = HRESULT_FROM_WIN32( scErr );
  251. goto Error;
  252. } // if: failed
  253. //
  254. // Create the scripting engine thread.
  255. //
  256. m_hThread = CreateThread( NULL,
  257. 0,
  258. &S_ThreadProc,
  259. this,
  260. 0,
  261. &m_dwThreadId
  262. );
  263. if ( m_hThread == NULL )
  264. {
  265. scErr = TW32( GetLastError() );
  266. hr = HRESULT_FROM_WIN32( scErr );
  267. goto Error;
  268. }
  269. Cleanup:
  270. //
  271. // All class variable clean up should be done in the destructor.
  272. //
  273. HRETURN( hr );
  274. Error:
  275. LogError( hr, L"HrInit() failed." );
  276. goto Cleanup;
  277. } //*** CScriptResource::Init
  278. //****************************************************************************
  279. //
  280. // IUnknown
  281. //
  282. //****************************************************************************
  283. //////////////////////////////////////////////////////////////////////////////
  284. //++
  285. //
  286. // CScriptResource::QueryInterface
  287. //
  288. // Description:
  289. // Query this object for the passed in interface.
  290. //
  291. // Arguments:
  292. // riidIn
  293. // Id of interface requested.
  294. //
  295. // ppvOut
  296. // Pointer to the requested interface.
  297. //
  298. // Return Value:
  299. // S_OK
  300. // If the interface is available on this object.
  301. //
  302. // E_NOINTERFACE
  303. // If the interface is not available.
  304. //
  305. // E_POINTER
  306. // ppvOut was NULL.
  307. //
  308. // Remarks:
  309. // None.
  310. //
  311. //--
  312. //////////////////////////////////////////////////////////////////////////////
  313. STDMETHODIMP
  314. CScriptResource::QueryInterface(
  315. REFIID riidIn
  316. , LPVOID * ppvOut
  317. )
  318. {
  319. TraceQIFunc( riidIn, ppvOut );
  320. HRESULT hr = S_OK;
  321. //
  322. // Validate arguments.
  323. //
  324. Assert( ppvOut != NULL );
  325. if ( ppvOut == NULL )
  326. {
  327. hr = THR( E_POINTER );
  328. goto Cleanup;
  329. }
  330. //
  331. // Handle known interfaces.
  332. //
  333. if ( IsEqualIID( riidIn, IID_IUnknown ) )
  334. {
  335. *ppvOut = TraceInterface( __THISCLASS__, IUnknown, static_cast< IUnknown * >( this ), 0 );
  336. } // if: IUnknown
  337. else
  338. {
  339. *ppvOut = NULL;
  340. hr = THR( E_NOINTERFACE );
  341. } // else
  342. //
  343. // Add a reference to the interface if successful.
  344. //
  345. if ( SUCCEEDED( hr ) )
  346. {
  347. ((IUnknown *) *ppvOut)->AddRef();
  348. } // if: success
  349. Cleanup:
  350. QIRETURN( hr, riidIn );
  351. } //*** CScriptResource::QueryInterface
  352. //////////////////////////////////////////////////////////////////////////////
  353. //
  354. // STDMETHODIMP_( ULONG )
  355. // CScriptResource::[IUnknown] AddRef( void )
  356. //
  357. //////////////////////////////////////////////////////////////////////////////
  358. STDMETHODIMP_( ULONG )
  359. CScriptResource::AddRef( void )
  360. {
  361. TraceFunc( "[IUnknown]" );
  362. LONG cRef = InterlockedIncrement( &m_cRef );
  363. RETURN( cRef );
  364. } //*** CScriptResource::AddRef
  365. //////////////////////////////////////////////////////////////////////////////
  366. //
  367. // STDMETHODIMP_( ULONG )
  368. // CScriptResource::[IUnknown] Release( void )
  369. //
  370. //////////////////////////////////////////////////////////////////////////////
  371. STDMETHODIMP_( ULONG )
  372. CScriptResource::Release( void )
  373. {
  374. TraceFunc( "[IUnknown]" );
  375. LONG cRef = InterlockedDecrement( &m_cRef );
  376. if ( cRef == 0 )
  377. {
  378. TraceDo( delete this );
  379. } // if: reference count decremented to zero
  380. RETURN( cRef );
  381. } //*** CScriptResource::Release
  382. //****************************************************************************
  383. //
  384. // Publics
  385. //
  386. //****************************************************************************
  387. //////////////////////////////////////////////////////////////////////////////
  388. //++
  389. //
  390. // CScriptResource::Open
  391. //
  392. //--
  393. //////////////////////////////////////////////////////////////////////////////
  394. STDMETHODIMP
  395. CScriptResource::Open( void )
  396. {
  397. TraceFunc( "" );
  398. HRESULT hr;
  399. hr = THR( WaitForMessageToComplete( msgOPEN ) );
  400. // CMCM:+ 19-Dec-2000 commented this out to make the DBG PRINT quiet since we now return ERROR_RETRY
  401. // HRETURN( hr );
  402. // DavidP 27-MAR-2002 Reverting the above change. DBG PRINTs are okay.
  403. // Besides, it needs to balance out the TraceFunc above.
  404. // return hr;
  405. HRETURN( hr );
  406. } //*** CScriptResource::Open
  407. //////////////////////////////////////////////////////////////////////////////
  408. //++
  409. //
  410. // CScriptResource::Close
  411. //
  412. //--
  413. //////////////////////////////////////////////////////////////////////////////
  414. STDMETHODIMP
  415. CScriptResource::Close( void )
  416. {
  417. TraceFunc( "" );
  418. HRESULT hr;
  419. hr = THR( WaitForMessageToComplete( msgCLOSE ) );
  420. HRETURN( hr );
  421. } //*** CScriptResource::Close
  422. //////////////////////////////////////////////////////////////////////////////
  423. //++
  424. //
  425. // CScriptResource::Online
  426. //
  427. //--
  428. //////////////////////////////////////////////////////////////////////////////
  429. STDMETHODIMP
  430. CScriptResource::Online( void )
  431. {
  432. TraceFunc( "" );
  433. HRESULT hr;
  434. hr = THR( WaitForMessageToComplete( msgONLINE ) );
  435. HRETURN( hr );
  436. } //*** CScriptResource::Online
  437. //////////////////////////////////////////////////////////////////////////////
  438. //++
  439. //
  440. // CScriptResource::Offline
  441. //
  442. //--
  443. //////////////////////////////////////////////////////////////////////////////
  444. STDMETHODIMP
  445. CScriptResource::Offline( void )
  446. {
  447. TraceFunc( "" );
  448. HRESULT hr;
  449. hr = THR( WaitForMessageToComplete( msgOFFLINE ) );
  450. HRETURN( hr );
  451. } //*** CScriptResource::Offline
  452. //////////////////////////////////////////////////////////////////////////////
  453. //++
  454. //
  455. // CScriptResource::Terminate
  456. //
  457. //--
  458. //////////////////////////////////////////////////////////////////////////////
  459. STDMETHODIMP
  460. CScriptResource::Terminate( void )
  461. {
  462. TraceFunc( "" );
  463. HRESULT hr;
  464. hr = THR( WaitForMessageToComplete( msgTERMINATE ) );
  465. HRETURN( hr );
  466. } //*** CScriptResource::Terminate
  467. //////////////////////////////////////////////////////////////////////////////
  468. //++
  469. //
  470. // CScriptResource::LooksAlive
  471. //
  472. //--
  473. //////////////////////////////////////////////////////////////////////////////
  474. STDMETHODIMP
  475. CScriptResource::LooksAlive( void )
  476. {
  477. TraceFunc( "" );
  478. HRESULT hr;
  479. BOOL fSuccess;
  480. DWORD dw;
  481. DWORD scErr;
  482. CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
  483. //
  484. // A potential hang has already been detected in this script. Therefore we
  485. // will not process any other calls to this script.
  486. //
  487. if ( m_fHangDetected == TRUE )
  488. {
  489. LogHangMode( msgLOOKSALIVE );
  490. scErr = TW32( ERROR_TIMEOUT );
  491. hr = HRESULT_FROM_WIN32( scErr );
  492. goto Cleanup;
  493. } // if: ( m_fHangDetected == TRUE )
  494. if ( m_fPendingTimeoutChanged == TRUE )
  495. {
  496. //
  497. // Read the new pending timeout from the cluster hive.
  498. //
  499. m_dwPendingTimeout = DwGetResourcePendingTimeout();
  500. m_fPendingTimeoutChanged = FALSE;
  501. } // if: pending timeout has changed.
  502. //
  503. // Acquire the serialization lock.
  504. //
  505. hr = THR( SerializeLock.AcquireLock() );
  506. if ( FAILED( hr ) )
  507. {
  508. //
  509. // Can't "goto Error" because we didn't acquire the lock.
  510. //
  511. LogError( hr, L"LooksAlive() failed to acquire the serialization lock." );
  512. goto Cleanup;
  513. }
  514. //
  515. // Wait for the script thread to be "done."
  516. //
  517. dw = WaitForSingleObject( m_hEventDone, m_dwPendingTimeout );
  518. if ( dw == WAIT_TIMEOUT )
  519. {
  520. m_fHangDetected = TRUE;
  521. hr = HrSetHangEntryPoint();
  522. if ( FAILED( hr ) )
  523. {
  524. goto Error;
  525. }
  526. scErr = TW32( ERROR_TIMEOUT );
  527. hr = HRESULT_FROM_WIN32( scErr );
  528. goto Error;
  529. } // if: ( dw == WAIT_TIMEOUT )
  530. else if ( dw != WAIT_OBJECT_0 )
  531. {
  532. scErr = TW32( GetLastError() );
  533. hr = HRESULT_FROM_WIN32( scErr );
  534. goto Error;
  535. } // else if: ( dw != WAIT_OBJECT_0 )
  536. //
  537. // Reset the done event to indicate that the thread is not busy.
  538. //
  539. fSuccess = ResetEvent( m_hEventDone );
  540. if ( fSuccess == FALSE )
  541. {
  542. scErr = TW32( GetLastError() );
  543. hr = HRESULT_FROM_WIN32( scErr );
  544. goto Error;
  545. }
  546. //
  547. // Store the message in the common memory buffer.
  548. //
  549. m_msg = msgLOOKSALIVE;
  550. //
  551. // Signal the script thread to process the message, but don't wait for
  552. // it to complete.
  553. //
  554. dw = SetEvent( m_hEventWait );
  555. if ( m_fLastLooksAlive )
  556. {
  557. hr = S_OK;
  558. }
  559. else
  560. {
  561. hr = S_FALSE;
  562. }
  563. ReleaseLockAndCleanup:
  564. SerializeLock.ReleaseLock();
  565. Cleanup:
  566. HRETURN( hr );
  567. Error:
  568. LogError( hr, L"LooksAlive() failed." );
  569. goto ReleaseLockAndCleanup;
  570. } //*** CScriptResource::LooksAlive
  571. //////////////////////////////////////////////////////////////////////////////
  572. //++
  573. //
  574. // CScriptResource::IsAlive
  575. //
  576. //--
  577. //////////////////////////////////////////////////////////////////////////////
  578. STDMETHODIMP
  579. CScriptResource::IsAlive( void )
  580. {
  581. TraceFunc( "" );
  582. HRESULT hr;
  583. hr = THR( WaitForMessageToComplete( msgISALIVE ) );
  584. HRETURN( hr );
  585. } //*** CScriptResource::IsAlive
  586. //////////////////////////////////////////////////////////////////////////////
  587. //++
  588. //
  589. // CScriptResource::SetPrivateProperties
  590. //
  591. // Description:
  592. // Handle the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control code.
  593. //
  594. // Arguments:
  595. // pProps
  596. //
  597. // Return Values:
  598. //
  599. //--
  600. //////////////////////////////////////////////////////////////////////////////
  601. DWORD
  602. CScriptResource::SetPrivateProperties(
  603. PGENSCRIPT_PROPS pProps
  604. )
  605. {
  606. TraceFunc( "" );
  607. HRESULT hr = S_OK;
  608. DWORD sc = ERROR_SUCCESS;
  609. hr = STHR( WaitForMessageToComplete(
  610. msgSETPRIVATEPROPERTIES
  611. , pProps
  612. ) );
  613. sc = STATUS_TO_RETURN( hr );
  614. W32RETURN( sc );
  615. } //*** CScriptResource::SetPrivateProperties
  616. //****************************************************************************
  617. //
  618. // Privates
  619. //
  620. //****************************************************************************
  621. //////////////////////////////////////////////////////////////////////////////
  622. //++
  623. //
  624. // CScriptResource::DwGetResourcePendingTimeout
  625. //
  626. // Description:
  627. // Returns the resource pending timeout from the cluster hive. If it can
  628. // not read this value for some reason, it returns the default resource
  629. // pending timeout.
  630. //
  631. // Return Values:
  632. // Resource pending timeout.
  633. //
  634. //--
  635. //////////////////////////////////////////////////////////////////////////////
  636. DWORD
  637. CScriptResource::DwGetResourcePendingTimeout( void )
  638. {
  639. DWORD scErr = ERROR_SUCCESS;
  640. DWORD dwType;
  641. DWORD dwValue = CLUSTER_RESOURCE_DEFAULT_PENDING_TIMEOUT;
  642. DWORD cbSize= sizeof( DWORD );
  643. scErr = ClusterRegQueryValue( m_hkeyResource, CLUSREG_NAME_RES_PENDING_TIMEOUT, &dwType, (LPBYTE) &dwValue, &cbSize );
  644. if ( scErr != ERROR_SUCCESS )
  645. {
  646. if ( scErr != ERROR_FILE_NOT_FOUND )
  647. {
  648. //
  649. // Log an error to the cluster log.
  650. //
  651. (ClusResLogEvent)(
  652. m_hResource
  653. , LOG_ERROR
  654. , L"DwGetResourcePendingTimeout: Failed to query the cluster hive for the resource pending time out. SCODE: 0x%1!08x! \n"
  655. , scErr
  656. );
  657. }
  658. dwValue = CLUSTER_RESOURCE_DEFAULT_PENDING_TIMEOUT;
  659. goto Cleanup;
  660. } //if: ( scErr != ERROR_SUCCESS )
  661. Assert( dwType == REG_DWORD );
  662. Cleanup:
  663. return dwValue;
  664. } //*** CScriptResource::DwGetResourcePendingTimeout
  665. //////////////////////////////////////////////////////////////////////////////
  666. //++
  667. //
  668. // CScriptResource::LogHangMode
  669. //
  670. // Description:
  671. // Log an error that informs that the incoming request will not be
  672. // proccessed due to a hang mode.
  673. //
  674. // Arguments:
  675. // msgIn - Incoming request message.
  676. //
  677. //--
  678. //////////////////////////////////////////////////////////////////////////////
  679. void
  680. CScriptResource::LogHangMode( EMESSAGE msgIn )
  681. {
  682. //
  683. // If the msgIn request is a known user request, let's log an entry to
  684. // the system event log.
  685. //
  686. if ( ( msgIn > msgUNKNOWN ) && ( msgIn < msgDIE ) )
  687. {
  688. //
  689. // Cluster logging infrastructure can display upto LOGENTRY_BUFFER_SIZE
  690. // characters. Since our error message text is too long, we'll cut it into two
  691. // and display it as two error messages.
  692. //
  693. //
  694. // Log an error to the cluster log.
  695. //
  696. (ClusResLogEvent)(
  697. m_hResource
  698. , LOG_ERROR
  699. , L"Request to perform the %1 operation will not be processed. This is because of a previous failed attempt to execute "
  700. L"the %2 entry point in a timely fashion. Please review the script code for this entry point to make sure there is no infinite "
  701. L"loop or a hang in it, and then consider increasing the resource pending timeout value if necessary.\n"
  702. , g_rgpszScriptEntryPointNames[ msgIn ]
  703. , m_pszHangEntryPoint == NULL ? L"<unknown>" : m_pszHangEntryPoint
  704. );
  705. //
  706. // Log an error to the cluster log.
  707. //
  708. (ClusResLogEvent)(
  709. m_hResource
  710. , LOG_ERROR
  711. , L"In a command shell, run \"cluster res \"%1\" /prop PersistentState=0\" to disable this resource, and then run \"net stop clussvc\" "
  712. L"to stop the cluster service. Ensure that any problem in the script code is fixed. Then run \"net start clussvc\" to start the cluster "
  713. L"service. If necessary, ensure that the pending time out is increased before bringing the resource online again.\n"
  714. , m_pszName
  715. );
  716. //
  717. // Log an error to the system event log.
  718. //
  719. ClusterLogEvent3(
  720. LOG_CRITICAL
  721. , LOG_CURRENT_MODULE
  722. , __FILE__
  723. , __LINE__
  724. , RES_GENSCRIPT_HANGMODE
  725. , 0
  726. , NULL
  727. , m_pszName
  728. , g_rgpszScriptEntryPointNames[ msgIn ]
  729. , m_pszHangEntryPoint == NULL ? L"<unknown>" : m_pszHangEntryPoint
  730. );
  731. } // if: ( pszEntryPoint != NULL )
  732. } //*** CScriptResource::LogHangMode
  733. //////////////////////////////////////////////////////////////////////////////
  734. //++
  735. //
  736. // CScriptResource::HrSetHangEntryPoint
  737. //
  738. // Description:
  739. // Allocates memory and sets m_pszHangEntryPoint and logs an error
  740. //
  741. // Return Values:
  742. // S_OK on success
  743. //
  744. //--
  745. //////////////////////////////////////////////////////////////////////////////
  746. HRESULT
  747. CScriptResource::HrSetHangEntryPoint( void )
  748. {
  749. TraceFunc( "" );
  750. HRESULT hr = S_OK;
  751. size_t cch = 0;
  752. //
  753. // m_msgLastExecuted is initially set to msgUNKNOWN in the constructor.
  754. //
  755. if ( m_msgLastExecuted != msgUNKNOWN )
  756. {
  757. delete [] m_pszHangEntryPoint;
  758. cch = wcslen( g_rgpszScriptEntryPointNames[ m_msgLastExecuted ] ) + 1;
  759. m_pszHangEntryPoint = new WCHAR[ cch ];
  760. if ( m_pszHangEntryPoint == NULL )
  761. {
  762. hr = THR( E_OUTOFMEMORY );
  763. goto Cleanup;
  764. } // if: ( m_pszHangEntryPoint == NULL )
  765. hr = THR( StringCchCopyW( m_pszHangEntryPoint, cch, g_rgpszScriptEntryPointNames[ m_msgLastExecuted ] ) );
  766. if ( FAILED( hr ) )
  767. {
  768. goto Cleanup;
  769. } // if: ( FAILED( hr ) )
  770. //
  771. // Cluster logging infrastructure can display upto LOGENTRY_BUFFER_SIZE
  772. // characters. Since our error message text is too long, we'll cut it into two
  773. // and display it as two error messages.
  774. //
  775. //
  776. // Log an error to the cluster log.
  777. //
  778. (ClusResLogEvent)(
  779. m_hResource
  780. , LOG_ERROR
  781. , L"%1 entry point did not complete execution in a timely manner. "
  782. L"This could be due to an infinite loop or a hang in this entry point, or the pending timeout may be too short for this resource. "
  783. L"Please review the script code for this entry point to make sure there is no infinite loop or a hang in it, and then consider "
  784. L"increasing the resource pending timeout value if necessary.\n"
  785. , m_pszHangEntryPoint
  786. );
  787. //
  788. // Log an error to the cluster log.
  789. //
  790. (ClusResLogEvent)(
  791. m_hResource
  792. , LOG_ERROR
  793. , L"In a command shell, run \"cluster res \"%1\" /prop PersistentState=0\" "
  794. L"to disable this resource, and then run \"net stop clussvc\" to stop the cluster service. Ensure that any problem in the script code is fixed. "
  795. L"Then run \"net start clussvc\" to start the cluster service. If necessary, ensure that the pending time out is increased before bringing the "
  796. L"resource online again.\n"
  797. , m_pszName
  798. );
  799. //
  800. // Log an error to the system event log.
  801. //
  802. ClusterLogEvent2(
  803. LOG_CRITICAL
  804. , LOG_CURRENT_MODULE
  805. , __FILE__
  806. , __LINE__
  807. , RES_GENSCRIPT_TIMEOUT
  808. , 0
  809. , NULL
  810. , m_pszName
  811. , m_pszHangEntryPoint
  812. );
  813. } // if: ( m_msgLastExecuted != msgUNKNOWN )
  814. else
  815. {
  816. (ClusResLogEvent)(
  817. m_hResource
  818. , LOG_ERROR
  819. , L"HrSetHangEntryPoint: Unsupported entry point. \n"
  820. );
  821. } // else:
  822. Cleanup:
  823. HRETURN( hr );
  824. } //*** CScriptResource::HrSetHangEntryPoint
  825. //////////////////////////////////////////////////////////////////////////////
  826. //++
  827. //
  828. // CScriptResource::WaitForMessageToComplete
  829. //
  830. // Description:
  831. // Send a message to the script thread and wait for it to complete.
  832. //
  833. // Arguments:
  834. // msgIn
  835. // pProps
  836. //
  837. // Return Values:
  838. //
  839. //--
  840. //////////////////////////////////////////////////////////////////////////////
  841. HRESULT
  842. CScriptResource::WaitForMessageToComplete(
  843. EMESSAGE msgIn
  844. , PGENSCRIPT_PROPS pProps
  845. )
  846. {
  847. TraceFunc( "" );
  848. HRESULT hr;
  849. BOOL fSuccess;
  850. DWORD dw;
  851. DWORD scErr;
  852. CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
  853. //
  854. // A potential hang has already been detected in this script. Therefore we
  855. // will not process any other calls to this script.
  856. //
  857. if ( m_fHangDetected == TRUE )
  858. {
  859. LogHangMode( msgIn );
  860. scErr = TW32( ERROR_TIMEOUT );
  861. hr = HRESULT_FROM_WIN32( scErr );
  862. goto Cleanup;
  863. } // if: ( m_fHangDetected == TRUE )
  864. if ( m_fPendingTimeoutChanged == TRUE )
  865. {
  866. //
  867. // Read the new pending timeout from the cluster hive.
  868. //
  869. m_dwPendingTimeout = DwGetResourcePendingTimeout();
  870. m_fPendingTimeoutChanged = FALSE;
  871. } // if: pending timeout has changed.
  872. //
  873. // Acquire the serialization lock.
  874. //
  875. hr = THR( SerializeLock.AcquireLock() );
  876. if ( FAILED( hr ) )
  877. {
  878. //
  879. // Can't "goto Error" because we didn't acquire the lock.
  880. //
  881. LogError( hr, L"WaitForMessageToComplete() failed to acquire the serialization lock." );
  882. goto Cleanup;
  883. }
  884. //
  885. // Wait for the script thread to be "done."
  886. //
  887. dw = WaitForSingleObject( m_hEventDone, m_dwPendingTimeout );
  888. if ( dw == WAIT_TIMEOUT )
  889. {
  890. m_fHangDetected = TRUE;
  891. hr = HrSetHangEntryPoint();
  892. if ( FAILED( hr ) )
  893. {
  894. goto Error;
  895. }
  896. scErr = TW32( ERROR_TIMEOUT );
  897. hr = HRESULT_FROM_WIN32( scErr );
  898. goto Error;
  899. } // if: ( dw == WAIT_TIMEOUT )
  900. else if ( dw != WAIT_OBJECT_0 )
  901. {
  902. scErr = TW32( GetLastError() );
  903. hr = HRESULT_FROM_WIN32( scErr );
  904. goto Error;
  905. } // else if: ( dw != WAIT_OBJECT_0 )
  906. //
  907. // Reset the done event to indicate that the thread is not busy.
  908. //
  909. fSuccess = ResetEvent( m_hEventDone );
  910. if ( fSuccess == FALSE )
  911. {
  912. scErr = TW32( GetLastError() );
  913. hr = HRESULT_FROM_WIN32( scErr );
  914. goto Error;
  915. }
  916. //
  917. // Store the message in the common memory buffer.
  918. //
  919. m_msg = msgIn;
  920. m_pProps = pProps;
  921. //
  922. // Signal the script thread to process the message.
  923. //
  924. fSuccess = SetEvent( m_hEventWait );
  925. if ( fSuccess == FALSE )
  926. {
  927. scErr = TW32( GetLastError() );
  928. hr = HRESULT_FROM_WIN32( scErr );
  929. goto Error;
  930. }
  931. //
  932. // Wait for the thread to complete.
  933. //
  934. dw = WaitForSingleObject( m_hEventDone, m_dwPendingTimeout );
  935. if ( dw == WAIT_TIMEOUT )
  936. {
  937. m_fHangDetected = TRUE;
  938. hr = HrSetHangEntryPoint();
  939. if ( FAILED( hr ) )
  940. {
  941. goto Error;
  942. }
  943. scErr = TW32( ERROR_TIMEOUT );
  944. hr = HRESULT_FROM_WIN32( scErr );
  945. goto Error;
  946. } // if: ( dw == WAIT_TIMEOUT )
  947. else if ( dw != WAIT_OBJECT_0 )
  948. {
  949. scErr = TW32( GetLastError() );
  950. hr = HRESULT_FROM_WIN32( scErr );
  951. goto Error;
  952. } // else if: ( dw != WAIT_OBJECT_0 )
  953. //
  954. // Get the result of the task from the common buffer.
  955. //
  956. hr = m_hr;
  957. ReleaseLockAndCleanup:
  958. SerializeLock.ReleaseLock();
  959. Cleanup:
  960. m_pProps = NULL;
  961. HRETURN( hr );
  962. Error:
  963. LogError( hr, L"WaitForMessageToComplete() failed.\n" );
  964. goto ReleaseLockAndCleanup;
  965. } //*** CScriptResource::WaitForMessageToComplete
  966. //////////////////////////////////////////////////////////////////////////////
  967. //++
  968. //
  969. // CScriptResource::LogError
  970. //
  971. //--
  972. //////////////////////////////////////////////////////////////////////////////
  973. STDMETHODIMP
  974. CScriptResource::LogError(
  975. HRESULT hrIn
  976. , LPCWSTR pszPrefixIn
  977. )
  978. {
  979. TraceFunc1( "hrIn = 0x%08x", hrIn );
  980. Assert( pszPrefixIn != NULL );
  981. static WCHAR s_szFormat[] = L"HRESULT: 0x%1!08x!\n";
  982. LPWSTR pszFormat = NULL;
  983. size_t cchAlloc;
  984. HRESULT hr = S_OK;
  985. TraceMsg( mtfCALLS, "%ws failed. HRESULT: 0x%08x\n", m_pszName, hrIn );
  986. cchAlloc = RTL_NUMBER_OF( s_szFormat ) + wcslen( pszPrefixIn );
  987. pszFormat = new WCHAR[ cchAlloc ];
  988. if ( pszFormat == NULL )
  989. {
  990. THR( E_OUTOFMEMORY );
  991. goto Cleanup;
  992. }
  993. hr = THR( StringCchPrintfW( pszFormat, cchAlloc, L"%ws %ws", pszPrefixIn, s_szFormat ) );
  994. if ( FAILED( hr ) )
  995. {
  996. goto Cleanup;
  997. } // if: StringCchPrintfW failed.
  998. (ClusResLogEvent)( m_hResource, LOG_ERROR, pszFormat, hrIn );
  999. Cleanup:
  1000. delete [] pszFormat;
  1001. HRETURN( hr );
  1002. } //*** CScriptResource::LogError
  1003. //////////////////////////////////////////////////////////////////////////////
  1004. //++
  1005. //
  1006. // CScriptResource::LogScriptError
  1007. //
  1008. //--
  1009. //////////////////////////////////////////////////////////////////////////////
  1010. STDMETHODIMP
  1011. CScriptResource::LogScriptError(
  1012. EXCEPINFO ei
  1013. )
  1014. {
  1015. TraceFunc( "" );
  1016. HRESULT hr;
  1017. if ( ei.pfnDeferredFillIn != NULL )
  1018. {
  1019. hr = THR( ei.pfnDeferredFillIn( &ei ) );
  1020. }
  1021. TraceMsg( mtfCALLS, "%ws failed.\nError: %u\nSource: %ws\nDescription: %ws\n",
  1022. m_pszName,
  1023. ( ei.wCode == 0 ? ei.scode : ei.wCode ),
  1024. ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource ),
  1025. ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription )
  1026. );
  1027. (ClusResLogEvent)( m_hResource,
  1028. LOG_ERROR,
  1029. L"Error: %1!u! (0x%1!08.8x!) - Description: %2!ws! (Source: %3!ws!)\n",
  1030. ( ei.wCode == 0 ? ei.scode : ei.wCode ),
  1031. ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription ),
  1032. ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource )
  1033. );
  1034. HRETURN( S_OK );
  1035. } //*** CScriptResource::LogScriptError
  1036. //////////////////////////////////////////////////////////////////////////////
  1037. //++
  1038. //
  1039. // CScriptResource::HrGetDispIDs
  1040. //
  1041. // Description:
  1042. // Get the DISPIDs for the entry points in the script.
  1043. //
  1044. // Arguments:
  1045. // None.
  1046. //
  1047. // Return Values:
  1048. // S_OK Operation succeeded.
  1049. // Other HRESULTs.
  1050. //--
  1051. //////////////////////////////////////////////////////////////////////////////
  1052. HRESULT
  1053. CScriptResource::HrGetDispIDs( void )
  1054. {
  1055. TraceFunc( "" );
  1056. HRESULT hr;
  1057. LPWSTR pszCommand;
  1058. Assert( m_pidm != NULL );
  1059. //
  1060. // Get DISPIDs for each method we will call.
  1061. //
  1062. pszCommand = L"Open";
  1063. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1064. &pszCommand,
  1065. 1,
  1066. LOCALE_USER_DEFAULT,
  1067. &m_dispidOpen
  1068. ) );
  1069. if ( hr == DISP_E_UNKNOWNNAME )
  1070. {
  1071. m_dispidOpen = DISPID_UNKNOWN;
  1072. }
  1073. else if ( FAILED( hr ) )
  1074. {
  1075. goto Cleanup;
  1076. }
  1077. pszCommand = L"Close";
  1078. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1079. &pszCommand,
  1080. 1,
  1081. LOCALE_USER_DEFAULT,
  1082. &m_dispidClose
  1083. ) );
  1084. if ( hr == DISP_E_UNKNOWNNAME )
  1085. {
  1086. m_dispidClose = DISPID_UNKNOWN;
  1087. }
  1088. else if ( FAILED( hr ) )
  1089. {
  1090. goto Cleanup;
  1091. }
  1092. pszCommand = L"Online";
  1093. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1094. &pszCommand,
  1095. 1,
  1096. LOCALE_USER_DEFAULT,
  1097. &m_dispidOnline
  1098. ) );
  1099. if ( hr == DISP_E_UNKNOWNNAME )
  1100. {
  1101. m_dispidOnline = DISPID_UNKNOWN;
  1102. }
  1103. else if ( FAILED( hr ) )
  1104. {
  1105. goto Cleanup;
  1106. }
  1107. pszCommand = L"Offline";
  1108. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1109. &pszCommand,
  1110. 1,
  1111. LOCALE_USER_DEFAULT,
  1112. &m_dispidOffline
  1113. ) );
  1114. if ( hr == DISP_E_UNKNOWNNAME )
  1115. {
  1116. m_dispidOffline = DISPID_UNKNOWN;
  1117. }
  1118. else if ( FAILED( hr ) )
  1119. {
  1120. goto Cleanup;
  1121. }
  1122. pszCommand = L"Terminate";
  1123. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1124. &pszCommand,
  1125. 1,
  1126. LOCALE_USER_DEFAULT,
  1127. &m_dispidTerminate
  1128. ) );
  1129. if ( hr == DISP_E_UNKNOWNNAME )
  1130. {
  1131. m_dispidTerminate = DISPID_UNKNOWN;
  1132. }
  1133. else if ( FAILED( hr ) )
  1134. {
  1135. goto Cleanup;
  1136. }
  1137. pszCommand = L"LooksAlive";
  1138. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1139. &pszCommand,
  1140. 1,
  1141. LOCALE_USER_DEFAULT,
  1142. &m_dispidLooksAlive
  1143. ) );
  1144. if ( FAILED( hr ) )
  1145. {
  1146. //
  1147. // If there's no LooksAlive entry point in the script.
  1148. //
  1149. if ( hr == DISP_E_UNKNOWNNAME )
  1150. {
  1151. m_dispidLooksAlive = DISPID_UNKNOWN;
  1152. hr = DISP_E_MEMBERNOTFOUND;
  1153. (ClusResLogEvent)(
  1154. m_hResource
  1155. , LOG_ERROR
  1156. , L"%1 did not implement LooksAlive() script entry point. This is a required script entry point.\n"
  1157. , m_pszName
  1158. );
  1159. }
  1160. goto Cleanup;
  1161. }
  1162. pszCommand = L"IsAlive";
  1163. hr = THR( m_pidm->GetIDsOfNames( IID_NULL,
  1164. &pszCommand,
  1165. 1,
  1166. LOCALE_USER_DEFAULT,
  1167. &m_dispidIsAlive
  1168. ) );
  1169. if ( FAILED( hr ) )
  1170. {
  1171. //
  1172. // If there's no IsAlive entry point in the script.
  1173. //
  1174. if ( hr == DISP_E_UNKNOWNNAME )
  1175. {
  1176. m_dispidIsAlive = DISPID_UNKNOWN;
  1177. hr = DISP_E_MEMBERNOTFOUND;
  1178. (ClusResLogEvent)(
  1179. m_hResource
  1180. , LOG_ERROR
  1181. , L"%1 did not implement IsAlive() script entry point. This is a required script entry point.\n"
  1182. , m_pszName
  1183. );
  1184. }
  1185. goto Cleanup;
  1186. }
  1187. //
  1188. // Don't return DISP_E_UNKNOWNNAME to caller.
  1189. //
  1190. hr = S_OK;
  1191. Cleanup:
  1192. HRETURN( hr );
  1193. } //*** CScriptResource::HrGetDispIDs
  1194. //////////////////////////////////////////////////////////////////////////////
  1195. //
  1196. // CScriptResource::HrLoadScriptFile
  1197. //
  1198. //////////////////////////////////////////////////////////////////////////////
  1199. HRESULT
  1200. CScriptResource::HrLoadScriptFile( void )
  1201. {
  1202. TraceFunc( "" );
  1203. HRESULT hr;
  1204. DWORD scErr;
  1205. DWORD dwLow;
  1206. DWORD dwRead;
  1207. VARIANT varResult;
  1208. EXCEPINFO ei;
  1209. BOOL fSuccess;
  1210. HANDLE hFile = INVALID_HANDLE_VALUE;
  1211. LPSTR paszText = NULL;
  1212. LPWSTR pszScriptText = NULL;
  1213. Assert( m_hScriptFile == INVALID_HANDLE_VALUE );
  1214. //
  1215. // Open the script file.
  1216. //
  1217. hFile = CreateFile(
  1218. m_pszScriptFilePath
  1219. , GENERIC_READ
  1220. , FILE_SHARE_READ
  1221. , NULL
  1222. , OPEN_EXISTING
  1223. , 0
  1224. , NULL
  1225. );
  1226. if ( hFile == INVALID_HANDLE_VALUE )
  1227. {
  1228. scErr = TW32( GetLastError() );
  1229. hr = HRESULT_FROM_WIN32( scErr );
  1230. goto Error;
  1231. } // if: failed to open
  1232. //
  1233. // Figure out its size.
  1234. //
  1235. dwLow = GetFileSize( hFile, NULL );
  1236. if ( dwLow == -1 )
  1237. {
  1238. scErr = TW32( GetLastError() );
  1239. hr = THR( HRESULT_FROM_WIN32( scErr ) );
  1240. goto Error;
  1241. } // if: failed to figure out size
  1242. else if ( dwLow == -2 )
  1243. {
  1244. hr = THR( E_OUTOFMEMORY );
  1245. goto Error;
  1246. }
  1247. //
  1248. // Make a buffer big enough to hold it.
  1249. //
  1250. dwLow++; // add one for trailing NULL.
  1251. paszText = reinterpret_cast<LPSTR>( TraceAlloc( LMEM_FIXED, dwLow ) );
  1252. if ( paszText == NULL )
  1253. {
  1254. hr = THR( E_OUTOFMEMORY );
  1255. goto Error;
  1256. }
  1257. //
  1258. // Read the script into memory.
  1259. //
  1260. fSuccess = ReadFile( hFile, paszText, dwLow - 1, &dwRead, NULL );
  1261. if ( fSuccess == FALSE )
  1262. {
  1263. scErr = TW32( GetLastError() );
  1264. hr = THR( HRESULT_FROM_WIN32( scErr ) );
  1265. goto Error;
  1266. } // if: failed
  1267. if ( dwRead == - 1 )
  1268. {
  1269. hr = THR( E_OUTOFMEMORY );
  1270. goto Error;
  1271. }
  1272. if ( dwLow - 1 != dwRead )
  1273. {
  1274. hr = THR( E_OUTOFMEMORY ); // TODO: figure out a better error code.
  1275. goto Error;
  1276. }
  1277. //
  1278. // Make sure it is terminated.
  1279. //
  1280. paszText[ dwRead ] = '\0';
  1281. //
  1282. // Make a buffer to convert the text into UNICODE.
  1283. //
  1284. dwRead++;
  1285. pszScriptText = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, dwRead * sizeof(WCHAR) ) );
  1286. if ( pszScriptText == NULL )
  1287. {
  1288. hr = THR( E_OUTOFMEMORY );
  1289. goto Error;
  1290. }
  1291. //
  1292. // Convert it to UNICODE.
  1293. //
  1294. Assert( lstrlenA( paszText ) + 1 == (signed)dwRead );
  1295. int cchWideFormat = MultiByteToWideChar(
  1296. CP_ACP
  1297. , 0
  1298. , paszText
  1299. , -1
  1300. , pszScriptText
  1301. , dwRead
  1302. );
  1303. if ( cchWideFormat == 0 )
  1304. {
  1305. scErr = TW32( GetLastError() );
  1306. hr = THR( HRESULT_FROM_WIN32( scErr ) );
  1307. goto Error;
  1308. }
  1309. //
  1310. // Load the script into the engine for pre-parsing.
  1311. //
  1312. hr = THR( m_pasp->ParseScriptText( pszScriptText,
  1313. NULL,
  1314. NULL,
  1315. NULL,
  1316. 0,
  1317. 0,
  1318. 0,
  1319. &varResult,
  1320. &ei
  1321. ) );
  1322. if ( hr == DISP_E_EXCEPTION )
  1323. {
  1324. LogScriptError( ei );
  1325. goto Error;
  1326. }
  1327. else if ( FAILED( hr ) )
  1328. {
  1329. goto Error;
  1330. }
  1331. //
  1332. // Get DISPIDs for each method in the script that we will call.
  1333. //
  1334. hr = THR( HrGetDispIDs() );
  1335. if ( FAILED( hr ) )
  1336. {
  1337. goto Error;
  1338. }
  1339. //
  1340. // Save the file handle to keep it open while we are using it.
  1341. // Set hFile so that the file won't be closed below.
  1342. //
  1343. m_hScriptFile = hFile;
  1344. hFile = INVALID_HANDLE_VALUE;
  1345. (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"Loaded script '%1!ws!' successfully.\n", m_pszScriptFilePath );
  1346. Cleanup:
  1347. VariantClear( &varResult );
  1348. if ( paszText != NULL )
  1349. {
  1350. TraceFree( paszText );
  1351. } // if: paszText
  1352. if ( pszScriptText != NULL )
  1353. {
  1354. TraceFree( pszScriptText );
  1355. } // if: pszScriptText;
  1356. if ( hFile != INVALID_HANDLE_VALUE )
  1357. {
  1358. CloseHandle( hFile );
  1359. } // if: hFile
  1360. HRETURN( hr );
  1361. Error:
  1362. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"Error loading script '%1!ws!'. HRESULT: 0x%2!08x!\n", m_pszScriptFilePath, hr );
  1363. goto Cleanup;
  1364. } //*** CScriptResource::HrLoadScriptFile
  1365. /////////////////////////////////////////////////////////////////////////////
  1366. //++
  1367. //
  1368. // CScriptResource::UnLoadScriptFile
  1369. //
  1370. // Description:
  1371. // Unload the script file and close the file.
  1372. //
  1373. // Arguments:
  1374. // None.
  1375. //
  1376. // Return Values:
  1377. // None.
  1378. //
  1379. //--
  1380. /////////////////////////////////////////////////////////////////////////////
  1381. void
  1382. CScriptResource::UnloadScriptFile( void )
  1383. {
  1384. TraceFunc( "" );
  1385. m_dispidOpen = DISPID_UNKNOWN;
  1386. m_dispidClose = DISPID_UNKNOWN;
  1387. m_dispidOnline = DISPID_UNKNOWN;
  1388. m_dispidOffline = DISPID_UNKNOWN;
  1389. m_dispidTerminate = DISPID_UNKNOWN;
  1390. m_dispidLooksAlive = DISPID_UNKNOWN;
  1391. m_dispidIsAlive = DISPID_UNKNOWN;
  1392. if ( m_hScriptFile != INVALID_HANDLE_VALUE )
  1393. {
  1394. CloseHandle( m_hScriptFile );
  1395. m_hScriptFile = INVALID_HANDLE_VALUE;
  1396. (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"Unloaded script '%1!ws!' successfully.\n", m_pszScriptFilePath );
  1397. } // if: file is open
  1398. TraceFuncExit();
  1399. } //*** CScriptResource::UnloadScriptFile
  1400. /////////////////////////////////////////////////////////////////////////////
  1401. //++
  1402. //
  1403. // CScriptResource::S_ThreadProc
  1404. //
  1405. //--
  1406. /////////////////////////////////////////////////////////////////////////////
  1407. DWORD
  1408. WINAPI
  1409. CScriptResource::S_ThreadProc(
  1410. LPVOID pParam
  1411. )
  1412. {
  1413. TraceFunc( "" );
  1414. HRESULT hr;
  1415. DWORD dw;
  1416. DWORD scErr;
  1417. BOOL fSuccess;
  1418. CScriptResource * pscript = reinterpret_cast< CScriptResource * >( pParam );
  1419. Assert( pscript != NULL );
  1420. //
  1421. // Initialize COM.
  1422. //
  1423. hr = THR( CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE ) );
  1424. if ( FAILED( hr ) )
  1425. {
  1426. goto Error;
  1427. }
  1428. for( ;; ) // ever
  1429. {
  1430. //
  1431. // Indicate that we are ready to do something.
  1432. //
  1433. fSuccess = SetEvent( pscript->m_hEventDone );
  1434. if ( fSuccess == FALSE )
  1435. {
  1436. scErr = TW32( GetLastError() );
  1437. hr = HRESULT_FROM_WIN32( scErr );
  1438. goto Error;
  1439. }
  1440. //
  1441. // Wait for someone to need something.
  1442. //
  1443. dw = WaitForSingleObject( pscript->m_hEventWait, INFINITE );
  1444. if ( dw != WAIT_OBJECT_0 )
  1445. {
  1446. hr = HRESULT_FROM_WIN32( dw );
  1447. goto Error;
  1448. }
  1449. //
  1450. // Reset the event.
  1451. //
  1452. fSuccess = ResetEvent( pscript->m_hEventWait );
  1453. if ( fSuccess == FALSE )
  1454. {
  1455. scErr = TW32( GetLastError() );
  1456. hr = HRESULT_FROM_WIN32( scErr );
  1457. goto Error;
  1458. }
  1459. //
  1460. // Do what they ask.
  1461. //
  1462. switch ( pscript->m_msg )
  1463. {
  1464. case msgOPEN:
  1465. pscript->m_hr = THR( pscript->OnOpen() );
  1466. break;
  1467. case msgCLOSE:
  1468. pscript->m_hr = THR( pscript->OnClose() );
  1469. break;
  1470. case msgONLINE:
  1471. pscript->m_hr = THR( pscript->OnOnline() );
  1472. break;
  1473. case msgOFFLINE:
  1474. pscript->m_hr = THR( pscript->OnOffline() );
  1475. break;
  1476. case msgTERMINATE:
  1477. pscript->m_hr = THR( pscript->OnTerminate() );
  1478. break;
  1479. case msgLOOKSALIVE:
  1480. pscript->m_hr = STHR( pscript->OnLooksAlive() );
  1481. break;
  1482. case msgISALIVE:
  1483. pscript->m_hr = STHR( pscript->OnIsAlive() );
  1484. break;
  1485. case msgSETPRIVATEPROPERTIES:
  1486. pscript->m_hr = STHR( pscript->OnSetPrivateProperties( pscript->m_pProps ) );
  1487. break;
  1488. case msgDIE:
  1489. //
  1490. // This means the resource is being released.
  1491. //
  1492. goto Cleanup;
  1493. } // switch: on message
  1494. } // spin forever
  1495. Cleanup:
  1496. CoUninitialize();
  1497. HRETURN( hr );
  1498. Error:
  1499. pscript->LogError( hr, L"S_ThreadProc() failed." );
  1500. goto Cleanup;
  1501. } //*** CScriptResource::S_ThreadProc
  1502. //////////////////////////////////////////////////////////////////////////////
  1503. //++
  1504. //
  1505. // CScriptResource::HrInvoke
  1506. //
  1507. // Description:
  1508. // Invoke a script method.
  1509. //
  1510. // Arguments:
  1511. // dispidIn - ID of the method to call.
  1512. // msgIn - Used in figuring out which entry point is being executed.
  1513. // pvarInout - Variant in which to return the results of the call.
  1514. // fRequiredIn - TRUE = method must exist, FALSE = method doesn't have to exist.
  1515. //
  1516. // Return Values:
  1517. // S_OK - Operation completed successfully.
  1518. // DISP_E_MEMBERNOTFOUND -Method not implemented by the script.
  1519. // Other HRESULTs.
  1520. //
  1521. //--
  1522. //////////////////////////////////////////////////////////////////////////////
  1523. HRESULT
  1524. CScriptResource::HrInvoke(
  1525. DISPID dispidIn
  1526. , EMESSAGE msgIn
  1527. , VARIANT * pvarInout // = NULL
  1528. , BOOL fRequiredIn // = FALSE
  1529. )
  1530. {
  1531. TraceFunc( "" );
  1532. HRESULT hr = S_OK;
  1533. EXCEPINFO ei;
  1534. VARIANT varResult;
  1535. VARIANT * pvarResult = pvarInout;
  1536. DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
  1537. Assert( m_pidm != NULL );
  1538. VariantInit( &varResult );
  1539. if ( pvarInout == NULL )
  1540. {
  1541. pvarResult = &varResult;
  1542. }
  1543. if ( dispidIn != DISPID_UNKNOWN )
  1544. {
  1545. m_msgLastExecuted = msgIn;
  1546. hr = m_pidm->Invoke(
  1547. dispidIn
  1548. , IID_NULL
  1549. , LOCALE_USER_DEFAULT
  1550. , DISPATCH_METHOD
  1551. , &dispparamsNoArgs
  1552. , pvarResult
  1553. , &ei
  1554. , NULL
  1555. );
  1556. if ( hr == DISP_E_EXCEPTION )
  1557. {
  1558. THR( hr );
  1559. LogScriptError( ei );
  1560. }
  1561. else if ( FAILED( hr ) )
  1562. {
  1563. LogError( hr, L"Failed to invoke a method in the script." );
  1564. }
  1565. } // if: entry point is known
  1566. else
  1567. {
  1568. //
  1569. // If this is a required method in the script.
  1570. //
  1571. if ( fRequiredIn == TRUE )
  1572. {
  1573. (ClusResLogEvent)(
  1574. m_hResource
  1575. , LOG_ERROR
  1576. , L"%1 entry point is not implemented in the script. This is a required entry point.\n"
  1577. , g_rgpszScriptEntryPointNames[ msgIn ]
  1578. );
  1579. hr = DISP_E_MEMBERNOTFOUND;
  1580. } // Log an error message if this is a required entry point, and fail.
  1581. else
  1582. {
  1583. (ClusResLogEvent)(
  1584. m_hResource
  1585. , LOG_INFORMATION
  1586. , L"%1 entry point is not implemented in the script. It is not required but recommended to have this entry point.\n"
  1587. , g_rgpszScriptEntryPointNames[ msgIn ]
  1588. );
  1589. hr = S_OK;
  1590. } // Log an information message if the method is not required but missing in the script.
  1591. } // if: method does not exist in the script
  1592. VariantClear( &varResult );
  1593. HRETURN( hr );
  1594. } //*** CScriptResource::HrInvoke
  1595. //////////////////////////////////////////////////////////////////////////////
  1596. //++
  1597. //
  1598. // CScriptResource::ScTranslateVariantReturnValue
  1599. //
  1600. // Description:
  1601. // Translates a numeric variant value to a status code.
  1602. //
  1603. // Arguments:
  1604. // varResultIn - Variant that holds the return value of a script entry point.
  1605. // vTypeIn - Type of the variant.
  1606. //
  1607. // Return Values:
  1608. // DWORD value of the variant.
  1609. //
  1610. //--
  1611. //////////////////////////////////////////////////////////////////////////////
  1612. DWORD
  1613. CScriptResource::ScTranslateVariantReturnValue(
  1614. VARIANT varResultIn
  1615. , VARTYPE vTypeIn
  1616. )
  1617. {
  1618. DWORD sc = ERROR_SUCCESS;
  1619. switch ( vTypeIn )
  1620. {
  1621. case VT_I1 :
  1622. sc = (DWORD) V_I1( &varResultIn );
  1623. break;
  1624. case VT_I2 :
  1625. sc = (DWORD) V_I2( &varResultIn );
  1626. break;
  1627. case VT_I4 :
  1628. sc = (DWORD) V_I4( &varResultIn );
  1629. break;
  1630. case VT_I8 :
  1631. sc = (DWORD) V_I8( &varResultIn );
  1632. break;
  1633. case VT_UI1 :
  1634. sc = (DWORD) V_UI1( &varResultIn );
  1635. break;
  1636. case VT_UI2 :
  1637. sc = (DWORD) V_UI2( &varResultIn );
  1638. break;
  1639. case VT_UI4 :
  1640. sc = (DWORD) V_UI4( &varResultIn );
  1641. break;
  1642. case VT_UI8 :
  1643. sc = (DWORD) V_UI8( &varResultIn );
  1644. break;
  1645. case VT_INT :
  1646. sc = (DWORD) V_INT( &varResultIn );
  1647. break;
  1648. case VT_UINT :
  1649. sc = (DWORD) V_UINT( &varResultIn );
  1650. break;
  1651. case VT_R4 :
  1652. sc = (DWORD) V_R4( &varResultIn );
  1653. break;
  1654. case VT_R8 :
  1655. sc = (DWORD) V_R8( &varResultIn );
  1656. break;
  1657. } // switch( vTypeIn )
  1658. return sc;
  1659. } //*** CScriptResource::ScTranslateVariantReturnValue
  1660. //////////////////////////////////////////////////////////////////////////////
  1661. //++
  1662. //
  1663. // CScriptResource::HrProcessResult
  1664. //
  1665. // Description:
  1666. // Processes and logs the return value that is stored in varResultIn and
  1667. // generates an HRESULT from the return value.
  1668. //
  1669. // Arguments:
  1670. // varResultIn - Variant that holds the return value of a script entry point.
  1671. // msgIn - Used in figuring out which entry point that was executed.
  1672. //
  1673. // Return Values:
  1674. // S_OK - Script entry point (i.e. Online) was executed successfully.
  1675. // S_FALSE - Script entry point returned an error.
  1676. // Other HRESULTs - Script entry point returned an error.
  1677. //
  1678. //--
  1679. //////////////////////////////////////////////////////////////////////////////
  1680. HRESULT
  1681. CScriptResource::HrProcessResult( VARIANT varResultIn, EMESSAGE msgIn )
  1682. {
  1683. TraceFunc( "" );
  1684. HRESULT hr = S_OK;
  1685. DWORD dwReturnValue = 0;
  1686. VARTYPE vType = V_VT( &varResultIn );
  1687. //
  1688. // Get the return value from varResultIn.
  1689. //
  1690. switch ( vType )
  1691. {
  1692. case VT_BOOL :
  1693. if ( V_BOOL( &varResultIn ) == VARIANT_FALSE ) // FALSE was returned
  1694. {
  1695. //
  1696. // Are we processing an IsAlive/LooksAlive return value?
  1697. //
  1698. if ( ( msgIn == msgISALIVE ) || ( msgIn == msgLOOKSALIVE ) )
  1699. {
  1700. hr = S_FALSE;
  1701. } // if: processing IsAlive/LooksAlive
  1702. else
  1703. {
  1704. hr = HRESULT_FROM_WIN32( TW32( ERROR_RESOURCE_FAILED ) );
  1705. } // else: processing IsAlive/LooksAlive
  1706. //
  1707. // Log the FALSE return value.
  1708. //
  1709. (ClusResLogEvent)(
  1710. m_hResource
  1711. , LOG_ERROR
  1712. , L"'%1!ws!' script entry point returned FALSE.'\n"
  1713. , g_rgpszScriptEntryPointNames[ msgIn ]
  1714. );
  1715. } // if: Return value is FALSE
  1716. break;
  1717. case VT_I1 :
  1718. case VT_I2 :
  1719. case VT_I4 :
  1720. case VT_I8 :
  1721. case VT_UI1 :
  1722. case VT_UI2 :
  1723. case VT_UI4 :
  1724. case VT_UI8 :
  1725. case VT_INT :
  1726. case VT_UINT :
  1727. case VT_R4 :
  1728. case VT_R8 :
  1729. dwReturnValue = TW32( ScTranslateVariantReturnValue( varResultIn, vType ) );
  1730. //
  1731. // Log the return value on failure.
  1732. //
  1733. if ( dwReturnValue != 0 )
  1734. {
  1735. (ClusResLogEvent)(
  1736. m_hResource
  1737. , LOG_ERROR
  1738. , L"'%1!ws!' script entry point returned '%2!d!'.\n"
  1739. , g_rgpszScriptEntryPointNames[ msgIn ]
  1740. , dwReturnValue
  1741. );
  1742. }
  1743. hr = HRESULT_FROM_WIN32( dwReturnValue );
  1744. break;
  1745. case VT_BSTR : // A string was returned, so let's just log it.
  1746. (ClusResLogEvent)(
  1747. m_hResource
  1748. , LOG_INFORMATION
  1749. , L"'%1!ws!' script entry point returned '%2!ws!'.\n"
  1750. , g_rgpszScriptEntryPointNames[ msgIn ]
  1751. , V_BSTR( &varResultIn )
  1752. );
  1753. break;
  1754. case VT_NULL : // NULL was returned, will not treat this as an error
  1755. (ClusResLogEvent)(
  1756. m_hResource
  1757. , LOG_INFORMATION
  1758. , L"'%1!ws!' script entry point returned NULL.'\n"
  1759. , g_rgpszScriptEntryPointNames[ msgIn ]
  1760. );
  1761. break;
  1762. case VT_EMPTY : // No return value.
  1763. (ClusResLogEvent)(
  1764. m_hResource
  1765. , LOG_INFORMATION
  1766. , L"'%1!ws!' script entry point did not return a value.'\n"
  1767. , g_rgpszScriptEntryPointNames[ msgIn ]
  1768. );
  1769. break;
  1770. default: // Unsupported return type.
  1771. (ClusResLogEvent)(
  1772. m_hResource
  1773. , LOG_INFORMATION
  1774. , L"'%1!ws!' script entry point returned a value type is not supported. The return value will be ignored.'\n"
  1775. , g_rgpszScriptEntryPointNames[ msgIn ]
  1776. );
  1777. break;
  1778. } // switch ( V_VT( &varResultIn ) )
  1779. if ( FAILED( hr ) )
  1780. {
  1781. (ClusResLogEvent)(
  1782. m_hResource
  1783. , LOG_ERROR
  1784. , L"Return value of '%1!ws!' script entry point caused HRESULT to be set to 0x%2!08x!.\n"
  1785. , g_rgpszScriptEntryPointNames[ msgIn ]
  1786. , hr
  1787. );
  1788. } // if: ( FAILED( hr ) )
  1789. else if ( hr != S_OK )
  1790. {
  1791. (ClusResLogEvent)(
  1792. m_hResource
  1793. , LOG_INFORMATION
  1794. , L"Return value of '%1!ws!' script entry point caused HRESULT to be set to 0x%2!08x!.\n"
  1795. , g_rgpszScriptEntryPointNames[ msgIn ]
  1796. , hr
  1797. );
  1798. } // else: ( FAILED( hr ) )
  1799. HRETURN( hr );
  1800. } //*** CScriptResource::HrProcessResult
  1801. //////////////////////////////////////////////////////////////////////////////
  1802. //++
  1803. //
  1804. // CScriptResource::OnOpen
  1805. //
  1806. //--
  1807. //////////////////////////////////////////////////////////////////////////////
  1808. HRESULT
  1809. CScriptResource::OnOpen( void )
  1810. {
  1811. TraceFunc( "" );
  1812. HRESULT hr = S_OK;
  1813. HRESULT hrOpen = S_OK;
  1814. HRESULT hrClose = S_OK;
  1815. VARIANT varResultOpen;
  1816. VARIANT varResultClose;
  1817. VariantInit( &varResultOpen );
  1818. VariantInit( &varResultClose );
  1819. //
  1820. // Get the script file path from the cluster database if we don't already have it.
  1821. //
  1822. if ( m_pszScriptFilePath == NULL )
  1823. {
  1824. hr = HrGetScriptFilePath();
  1825. if ( FAILED( hr ) )
  1826. {
  1827. if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) || ( hr == HRESULT_FROM_WIN32( ERROR_KEY_DELETED ) ) )
  1828. {
  1829. // This can happen when the resource is first created since the
  1830. // ScriptFilePath property has not been specified yet.
  1831. hr = S_OK;
  1832. }
  1833. THR( hr );
  1834. goto Cleanup;
  1835. }
  1836. } // if: no script file path
  1837. //
  1838. // If the script file path is set.
  1839. //
  1840. if ( m_pszScriptFilePath != NULL )
  1841. {
  1842. //
  1843. // Load the script engine for the specified script.
  1844. //
  1845. hr = THR( HrLoadScriptEngine() );
  1846. if ( FAILED( hr ) )
  1847. {
  1848. goto Cleanup;
  1849. }
  1850. //
  1851. // Open the script file and parse it
  1852. //
  1853. hr = THR( HrLoadScriptFile() );
  1854. if ( FAILED( hr ) )
  1855. {
  1856. goto Cleanup;
  1857. }
  1858. //
  1859. // Call the Open routine of the script if there's one.
  1860. // Call the Close routine as well since we are going to be unloading the script.
  1861. //
  1862. hrOpen = THR( HrInvoke( m_dispidOpen, msgOPEN, &varResultOpen, FALSE /* fRequiredIn */ ) );
  1863. hrClose = THR( HrInvoke( m_dispidClose, msgCLOSE, &varResultClose, FALSE /* fRequiredIn */ ) );
  1864. if ( FAILED( hrOpen ) )
  1865. {
  1866. hr = hrOpen;
  1867. goto Cleanup;
  1868. } // if: ( FAILED( hrOpen ) )
  1869. else if ( FAILED( hrClose ) )
  1870. {
  1871. hr = hrClose;
  1872. goto Cleanup;
  1873. } // elseif: ( FAILED( hrClose ) )
  1874. //
  1875. // We only care about the return value of Open.
  1876. // We don't care about the return value of Close,
  1877. // however processing the return value of Close
  1878. // might log an entry to the log file.
  1879. //
  1880. hr = HrProcessResult( varResultOpen, msgOPEN );
  1881. hrClose = HrProcessResult( varResultClose, msgCLOSE );
  1882. if ( FAILED( hr ) )
  1883. {
  1884. goto Cleanup;
  1885. } // if: FAILED( hr )
  1886. } // if: script file path is set
  1887. Cleanup:
  1888. //
  1889. // Unload the script and the script engine. Note they may not be loaded
  1890. // but these routines are safe to call either way.
  1891. //
  1892. UnloadScriptFile();
  1893. UnloadScriptEngine();
  1894. VariantClear( &varResultOpen );
  1895. VariantClear( &varResultClose );
  1896. HRETURN( hr );
  1897. } //*** CScriptResource::OnOpen
  1898. //////////////////////////////////////////////////////////////////////////////
  1899. //
  1900. // HRESULT
  1901. // CScriptResource::OnClose
  1902. //
  1903. //////////////////////////////////////////////////////////////////////////////
  1904. HRESULT
  1905. CScriptResource::OnClose( void )
  1906. {
  1907. TraceFunc( "" );
  1908. HRESULT hr = S_OK;
  1909. HRESULT hrOpen = S_OK;
  1910. HRESULT hrClose = S_OK;
  1911. BOOL fCallOpen = FALSE;
  1912. VARIANT varResultOpen;
  1913. VARIANT varResultClose;
  1914. VariantInit( &varResultOpen );
  1915. VariantInit( &varResultClose );
  1916. //
  1917. // If m_pidm is NULL call HrLoadScriptEngine to have it set.
  1918. //
  1919. if ( m_pidm == NULL )
  1920. {
  1921. //
  1922. // Get the script file path if we don't already have it.
  1923. //
  1924. if ( m_pszScriptFilePath == NULL )
  1925. {
  1926. hr = HrGetScriptFilePath();
  1927. if ( FAILED( hr ) )
  1928. {
  1929. if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) || ( hr == HRESULT_FROM_WIN32( ERROR_KEY_DELETED ) ) )
  1930. {
  1931. // This can happen when the resource is cancelled before the
  1932. // ScriptFilePath property has not been specified.
  1933. hr = S_OK;
  1934. }
  1935. THR( hr );
  1936. goto Cleanup;
  1937. }
  1938. } // if: no script file path
  1939. //
  1940. // Load the script engine based on the script file path.
  1941. //
  1942. hr = HrLoadScriptEngine();
  1943. if ( FAILED( hr ) )
  1944. {
  1945. goto Cleanup;
  1946. }
  1947. //
  1948. // We need to call open since we loaded the script.
  1949. //
  1950. fCallOpen = TRUE;
  1951. } // if: script and script engine is not loaded
  1952. if ( m_dispidClose == DISPID_UNKNOWN )
  1953. {
  1954. //
  1955. // Open the script file and parse it
  1956. //
  1957. hr = THR( HrLoadScriptFile() );
  1958. if ( FAILED( hr ) )
  1959. {
  1960. goto Cleanup;
  1961. }
  1962. } // if: DISPID for Close not loaded
  1963. //
  1964. // If we loaded the script, then we need to call the script's Open method.
  1965. //
  1966. if ( fCallOpen )
  1967. {
  1968. hrOpen = THR( HrInvoke( m_dispidOpen, msgOPEN, &varResultOpen, FALSE /* fRequiredIn */ ) );
  1969. }
  1970. //
  1971. // Call the script's Close method.
  1972. //
  1973. hrClose = THR( HrInvoke( m_dispidClose, msgCLOSE, &varResultClose, FALSE /* fRequiredIn */ ) );
  1974. if ( FAILED( hrClose ) )
  1975. {
  1976. hr = hrClose;
  1977. goto Cleanup;
  1978. } // if: ( FAILED( hrClose ) )
  1979. else if ( FAILED( hrOpen ) )
  1980. {
  1981. hr = hrOpen;
  1982. goto Cleanup;
  1983. } // else if: ( FAILED( hrOpen ) )
  1984. //
  1985. // We don't care about the return values of Open
  1986. // and Close script entry points in here, however processing the
  1987. // return values below might log an entry to the log file.
  1988. //
  1989. hr = HrProcessResult( varResultOpen, msgOPEN );
  1990. hr = HrProcessResult( varResultClose, msgCLOSE );
  1991. hr = S_OK;
  1992. Cleanup:
  1993. //
  1994. // Unload the script and the script engine. Note they may not be loaded
  1995. // but these routines are safe to call either way.
  1996. //
  1997. UnloadScriptFile();
  1998. UnloadScriptEngine();
  1999. VariantClear( &varResultOpen );
  2000. VariantClear( &varResultClose );
  2001. HRETURN( hr );
  2002. } //*** CScriptResource::OnClose
  2003. //////////////////////////////////////////////////////////////////////////////
  2004. //++
  2005. //
  2006. // HRESULT
  2007. // CScriptResource::OnOnline
  2008. //
  2009. //--
  2010. //////////////////////////////////////////////////////////////////////////////
  2011. HRESULT
  2012. CScriptResource::OnOnline( void )
  2013. {
  2014. TraceFunc( "" );
  2015. HRESULT hr = S_OK;
  2016. HRESULT hrOpen = S_OK;
  2017. HRESULT hrOnline = S_OK;
  2018. VARIANT varResultOpen;
  2019. VARIANT varResultOnline;
  2020. VariantInit( &varResultOpen );
  2021. VariantInit( &varResultOnline );
  2022. //
  2023. // Get the ScriptFilePath property.
  2024. //
  2025. hr = HrGetScriptFilePath();
  2026. if ( FAILED( hr ) )
  2027. {
  2028. goto Cleanup;
  2029. }
  2030. //
  2031. // Load the script engine based on the script file path.
  2032. //
  2033. hr = HrLoadScriptEngine();
  2034. if ( FAILED( hr ) )
  2035. {
  2036. goto Cleanup;
  2037. }
  2038. //
  2039. // Load the script file.
  2040. //
  2041. hr = THR( HrLoadScriptFile() );
  2042. if ( FAILED( hr ) )
  2043. {
  2044. goto Cleanup;
  2045. }
  2046. //
  2047. // Call the script's Open method since we just loaded the script.
  2048. //
  2049. hrOpen = THR( HrInvoke( m_dispidOpen, msgOPEN, &varResultOpen, FALSE /* fRequiredIn */ ) );
  2050. if ( FAILED( hrOpen ) )
  2051. {
  2052. hr = hrOpen;
  2053. goto Cleanup;
  2054. } // if: FAILED( hrOpen )
  2055. //
  2056. // Call the script's Online method.
  2057. //
  2058. hrOnline = THR( HrInvoke( m_dispidOnline, msgONLINE, &varResultOnline, FALSE /* fRequiredIn */ ) );
  2059. if ( FAILED( hrOnline ) )
  2060. {
  2061. hr = hrOnline;
  2062. goto Cleanup;
  2063. } // if: FAILED( hrOnline )
  2064. //
  2065. // We only care about the return value of Online.
  2066. // We don't care about the return value of Open,
  2067. // however processing the return value of Open
  2068. // might log an entry to the log file.
  2069. //
  2070. hr = HrProcessResult( varResultOpen, msgOPEN );
  2071. hr = HrProcessResult( varResultOnline, msgONLINE );
  2072. if ( FAILED( hr ) )
  2073. {
  2074. goto Cleanup;
  2075. } // if: FAILED( hr )
  2076. //
  2077. // Assume the resource LooksAlive...
  2078. //
  2079. m_fLastLooksAlive = TRUE;
  2080. Cleanup:
  2081. VariantClear( &varResultOpen );
  2082. VariantClear( &varResultOnline );
  2083. HRETURN( hr );
  2084. } //*** CScriptResource::OnOnline
  2085. //////////////////////////////////////////////////////////////////////////////
  2086. //++
  2087. //
  2088. // HRESULT
  2089. // CScriptResource::OnOffline
  2090. //
  2091. //--
  2092. //////////////////////////////////////////////////////////////////////////////
  2093. HRESULT
  2094. CScriptResource::OnOffline( void )
  2095. {
  2096. TraceFunc( "" );
  2097. HRESULT hr = S_OK;
  2098. HRESULT hrOffline = S_OK;
  2099. HRESULT hrClose = S_OK;
  2100. VARIANT varResultOffline;
  2101. VARIANT varResultClose;
  2102. VariantInit( &varResultOffline );
  2103. VariantInit( &varResultClose );
  2104. //
  2105. // Call the script's Offline method.
  2106. //
  2107. hrOffline = THR( HrInvoke( m_dispidOffline, msgOFFLINE, &varResultOffline, FALSE /* fRequiredIn */ ) );
  2108. //
  2109. // Call the script's Close method since we are going to unload the script.
  2110. //
  2111. hrClose = THR( HrInvoke( m_dispidClose, msgCLOSE, &varResultClose, FALSE /* fRequiredIn */ ) );
  2112. if ( FAILED( hrOffline ) )
  2113. {
  2114. hr = hrOffline;
  2115. goto Cleanup;
  2116. } // if: ( FAILED( hrOffline ) )
  2117. else if ( FAILED( hrClose ) )
  2118. {
  2119. hr = hrClose;
  2120. goto Cleanup;
  2121. } // else if: ( FAILED( hrClose ) )
  2122. //
  2123. // We only care about the return value of Offline.
  2124. // We don't care about the return value of Close,
  2125. // however processing the return value of Close
  2126. // might log an entry to the log file.
  2127. //
  2128. hr = HrProcessResult( varResultOffline, msgOFFLINE );
  2129. hrClose = HrProcessResult( varResultClose, msgCLOSE );
  2130. if ( FAILED( hr ) )
  2131. {
  2132. goto Cleanup;
  2133. } //if: FAILED( hr )
  2134. Cleanup:
  2135. //
  2136. // Unload the script and the script engine.
  2137. //
  2138. UnloadScriptFile();
  2139. UnloadScriptEngine();
  2140. VariantClear( &varResultOffline );
  2141. VariantClear( &varResultClose );
  2142. HRETURN( hr );
  2143. } //*** CScriptResource::OnOffline
  2144. //////////////////////////////////////////////////////////////////////////////
  2145. //
  2146. // HRESULT
  2147. // CScriptResource::OnTerminate
  2148. //
  2149. //////////////////////////////////////////////////////////////////////////////
  2150. HRESULT
  2151. CScriptResource::OnTerminate( void )
  2152. {
  2153. TraceFunc( "" );
  2154. HRESULT hr = S_OK;
  2155. HRESULT hrOpen = S_OK;
  2156. HRESULT hrTerminate = S_OK;
  2157. HRESULT hrClose = S_OK;
  2158. VARIANT varResultOpen;
  2159. VARIANT varResultTerminate;
  2160. VARIANT varResultClose;
  2161. VariantInit( &varResultOpen );
  2162. VariantInit( &varResultTerminate );
  2163. VariantInit( &varResultClose );
  2164. //
  2165. // If the script engine is not loaded yet, load it now.
  2166. //
  2167. if ( m_pidm == NULL )
  2168. {
  2169. //
  2170. // Get the script file path if we don't already have it.
  2171. //
  2172. if ( m_pszScriptFilePath == NULL )
  2173. {
  2174. hr = THR( HrGetScriptFilePath() );
  2175. if ( FAILED( hr ) )
  2176. {
  2177. goto Cleanup;
  2178. }
  2179. } // if: no script file path
  2180. //
  2181. // Load the script engine based on the script file path.
  2182. //
  2183. hr = HrLoadScriptEngine();
  2184. if ( FAILED( hr ) )
  2185. {
  2186. goto Cleanup;
  2187. }
  2188. //
  2189. // Open the script file and parse it
  2190. //
  2191. hr = THR( HrLoadScriptFile() );
  2192. if ( FAILED( hr ) )
  2193. {
  2194. goto Cleanup;
  2195. }
  2196. //
  2197. // We need to call open since we loaded the script.
  2198. //
  2199. hrOpen = THR( HrInvoke( m_dispidOpen, msgOPEN, &varResultOpen, FALSE /* fRequiredIn */ ) );
  2200. if ( FAILED( hrOpen ) )
  2201. {
  2202. hr = hrOpen;
  2203. goto Cleanup;
  2204. } // if: FAILED( hrOpen )
  2205. //
  2206. // We don't care about the return value of Open
  2207. // however processing the return value below might
  2208. // log an entry to the log file.
  2209. //
  2210. hrOpen = HrProcessResult( varResultOpen, msgOPEN );
  2211. } // if: script and script engine is not loaded
  2212. //
  2213. // Call the script's Terminate method.
  2214. //
  2215. hrTerminate = THR( HrInvoke( m_dispidTerminate, msgTERMINATE, &varResultTerminate, FALSE /* fRequiredIn */ ) );
  2216. if ( FAILED( hrTerminate ) )
  2217. {
  2218. hr = hrTerminate;
  2219. goto Cleanup;
  2220. } // if: ( FAILED( hrTerminate ) )
  2221. //
  2222. // Call the script's Close method since we are unloading the script.
  2223. //
  2224. hrClose = THR( HrInvoke( m_dispidClose, msgCLOSE, &varResultClose, FALSE /* fRequiredIn */ ) );
  2225. if ( FAILED( hrClose ) )
  2226. {
  2227. hr = hrClose;
  2228. goto Cleanup;
  2229. } // if: ( FAILED( hrClose ) )
  2230. //
  2231. // We don't care about the return values of Terminate
  2232. // and Close script entry points in here, however processing the
  2233. // return values below might log an entry to the log file.
  2234. //
  2235. hrTerminate = HrProcessResult( varResultTerminate, msgTERMINATE );
  2236. hrClose = HrProcessResult( varResultClose, msgCLOSE );
  2237. hr = S_OK;
  2238. Cleanup:
  2239. //
  2240. // Unload the script and the script engine.
  2241. //
  2242. UnloadScriptFile();
  2243. UnloadScriptEngine();
  2244. VariantClear( &varResultOpen );
  2245. VariantClear( &varResultTerminate );
  2246. VariantClear( &varResultClose );
  2247. HRETURN( hr );
  2248. } //*** CScriptResource::OnTerminate
  2249. //////////////////////////////////////////////////////////////////////////////
  2250. //
  2251. // HRESULT
  2252. // CScriptResource::OnLooksAlive
  2253. //
  2254. //////////////////////////////////////////////////////////////////////////////
  2255. HRESULT
  2256. CScriptResource::OnLooksAlive( void )
  2257. {
  2258. TraceFunc( "" );
  2259. HRESULT hr = S_OK;
  2260. VARIANT varResult;
  2261. VariantInit( &varResult );
  2262. //
  2263. // Call the script's LooksAlive method.
  2264. //
  2265. hr = THR( HrInvoke( m_dispidLooksAlive, msgLOOKSALIVE, &varResult, TRUE /* fRequiredIn */ ) );
  2266. if ( FAILED( hr ) )
  2267. {
  2268. goto Cleanup;
  2269. }
  2270. //
  2271. // Get the result of the LooksAlive call
  2272. // and process it.
  2273. //
  2274. hr = HrProcessResult( varResult, msgLOOKSALIVE );
  2275. if ( FAILED( hr ) )
  2276. {
  2277. goto Cleanup;
  2278. } //if: FAILED( hr )
  2279. Cleanup:
  2280. VariantClear( &varResult );
  2281. //
  2282. // Only if the result of this script entry point is S_OK is the resource
  2283. // considered alive.
  2284. //
  2285. if ( hr == S_OK )
  2286. {
  2287. m_fLastLooksAlive = TRUE;
  2288. } // if: S_OK
  2289. else
  2290. {
  2291. m_fLastLooksAlive = FALSE;
  2292. } // else: failed
  2293. HRETURN( hr );
  2294. } //*** CScriptResource::OnLooksAlive
  2295. //////////////////////////////////////////////////////////////////////////////
  2296. //
  2297. // HRESULT
  2298. // CScriptResource::OnIsAlive
  2299. //
  2300. //////////////////////////////////////////////////////////////////////////////
  2301. HRESULT
  2302. CScriptResource::OnIsAlive( void )
  2303. {
  2304. TraceFunc( "" );
  2305. HRESULT hr = S_OK;
  2306. VARIANT varResult;
  2307. VariantInit( &varResult );
  2308. //
  2309. // Call the script's IsAlive method.
  2310. //
  2311. hr = THR( HrInvoke( m_dispidIsAlive, msgISALIVE, &varResult, TRUE /* fRequiredIn */ ) );
  2312. if ( FAILED( hr ) )
  2313. {
  2314. goto Cleanup;
  2315. }
  2316. //
  2317. // Get the result of the IsAlive call
  2318. // and process it.
  2319. //
  2320. hr = HrProcessResult( varResult, msgISALIVE );
  2321. if ( FAILED( hr ) )
  2322. {
  2323. goto Cleanup;
  2324. } //if: FAILED( hr )
  2325. Cleanup:
  2326. VariantClear( &varResult );
  2327. HRETURN( hr );
  2328. } //*** CScriptResource::OnIsAlive
  2329. //////////////////////////////////////////////////////////////////////////////
  2330. //++
  2331. //
  2332. // CScriptResource::OnSetPrivateProperties
  2333. //
  2334. // Description:
  2335. // Handle the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control code in
  2336. // the script thread.
  2337. //
  2338. // Arguments:
  2339. //
  2340. // Return Values:
  2341. //
  2342. //--
  2343. //////////////////////////////////////////////////////////////////////////////
  2344. DWORD
  2345. CScriptResource::OnSetPrivateProperties(
  2346. PGENSCRIPT_PROPS pProps
  2347. )
  2348. {
  2349. TraceFunc( "" );
  2350. DWORD sc = ERROR_SUCCESS;
  2351. HRESULT hr = S_OK;
  2352. LPWSTR pszFilePath = NULL;
  2353. //
  2354. // Search the property list for the properties we know about.
  2355. //
  2356. if ( pProps != NULL )
  2357. {
  2358. //
  2359. // If the resource is online, we can't allow the user to set the ScriptFilePath
  2360. // out from under us, so return an error.
  2361. //
  2362. if ( m_pidm != NULL )
  2363. {
  2364. sc = ERROR_RESOURCE_ONLINE;
  2365. goto Cleanup;
  2366. } // if: script engine is loaded
  2367. //
  2368. // Expand the new script file path.
  2369. //
  2370. pszFilePath = ClRtlExpandEnvironmentStrings( pProps->pszScriptFilePath );
  2371. if ( pszFilePath == NULL )
  2372. {
  2373. sc = TW32( ERROR_OUTOFMEMORY );
  2374. goto Cleanup;
  2375. } // if: ( pszFilePath == NULL )
  2376. LocalFree( m_pszScriptFilePath );
  2377. m_pszScriptFilePath = pszFilePath;
  2378. if ( m_pszScriptFilePath == NULL )
  2379. {
  2380. sc = TW32( GetLastError() );
  2381. goto Cleanup;
  2382. }
  2383. //
  2384. // Since the script is being set, we need to load it again and call Open and Close on it.
  2385. //
  2386. hr = THR( OnOpen() );
  2387. if ( FAILED( hr ) )
  2388. {
  2389. sc = STATUS_TO_RETURN( hr );
  2390. goto Cleanup;
  2391. }
  2392. } // if: a property list was specified
  2393. Cleanup:
  2394. if ( sc == ERROR_SUCCESS )
  2395. {
  2396. //
  2397. // To allow the Resource Monitor to save the properties in the property list
  2398. // (especially unknown properties) to the cluster database, we will return
  2399. // ERROR_INVALID_FUNCTION.
  2400. //
  2401. sc = ERROR_INVALID_FUNCTION;
  2402. }
  2403. W32RETURN( sc );
  2404. } //*** CScriptResource::OnSetPrivateProperties
  2405. //////////////////////////////////////////////////////////////////////////////
  2406. //
  2407. // CScriptResource::HrMakeScriptEngineAssociation
  2408. //
  2409. // Description:
  2410. // Using the filename, this method splits off the extension then
  2411. // queries the registry to obtain the association and finally queries
  2412. // the ScriptingEngine key under that association and allocates a
  2413. // buffer containing the engine name. This engine name is suitable
  2414. // for input into CLSIDFromProgID.
  2415. //
  2416. // Return Values:
  2417. // S_OK - Success
  2418. // Other HRESULTs
  2419. //
  2420. //////////////////////////////////////////////////////////////////////////////
  2421. #define SCRIPTENGINE_KEY_STRING L"\\ScriptEngine"
  2422. HRESULT
  2423. CScriptResource::HrMakeScriptEngineAssociation( void )
  2424. {
  2425. TraceFunc( "" );
  2426. LPWSTR pszAssociation = NULL;
  2427. LPWSTR pszEngineName = NULL;
  2428. HKEY hKey = NULL;
  2429. WCHAR szExtension[ _MAX_EXT ];
  2430. DWORD scErr = ERROR_SUCCESS;
  2431. DWORD dwType;
  2432. DWORD cbAssociationSize;
  2433. DWORD cbEngineNameSize;
  2434. DWORD dwNumChars;
  2435. size_t cchBufSize;
  2436. HRESULT hr = S_OK;
  2437. TraceFree( m_pszScriptEngine );
  2438. m_pszScriptEngine = NULL;
  2439. //
  2440. // First split the path to get the extension.
  2441. //
  2442. _wsplitpath( m_pszScriptFilePath, NULL, NULL, NULL, szExtension );
  2443. if ( szExtension[ 0 ] == L'\0' )
  2444. {
  2445. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2446. goto Cleanup;
  2447. }
  2448. //
  2449. // Go to the HKEY_CLASSES_ROOT\szExtenstion registry key.
  2450. //
  2451. scErr = TW32( RegOpenKeyExW(
  2452. HKEY_CLASSES_ROOT // handle to open key
  2453. , szExtension // subkey name
  2454. , 0 // reserved
  2455. , KEY_READ // security access desired.
  2456. , &hKey // key handle returned
  2457. ) );
  2458. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2459. {
  2460. hr = THR( MK_E_INVALIDEXTENSION );
  2461. goto Cleanup;
  2462. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2463. else if ( scErr != ERROR_SUCCESS )
  2464. {
  2465. goto MakeHr;
  2466. }
  2467. //
  2468. // Query the value to get the size of the buffer to allocate.
  2469. // NB cbSize contains the size including the '\0'
  2470. //
  2471. scErr = TW32( RegQueryValueExW(
  2472. hKey // handle to key
  2473. , NULL // value name
  2474. , 0 // reserved
  2475. , &dwType // type buffer
  2476. , NULL // data buffer
  2477. , &cbAssociationSize // size of data buffer
  2478. ) );
  2479. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2480. {
  2481. hr = THR( MK_E_INVALIDEXTENSION );
  2482. goto Cleanup;
  2483. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2484. else if ( scErr != ERROR_SUCCESS )
  2485. {
  2486. goto MakeHr;
  2487. }
  2488. if ( dwType != REG_SZ )
  2489. {
  2490. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2491. goto Cleanup;
  2492. }
  2493. dwNumChars = cbAssociationSize / sizeof( WCHAR );
  2494. cchBufSize = static_cast<size_t> ( cbAssociationSize ) + sizeof( SCRIPTENGINE_KEY_STRING );
  2495. pszAssociation = (LPWSTR) TraceAlloc( GPTR, static_cast<DWORD> ( cchBufSize ) );
  2496. if ( pszAssociation == NULL )
  2497. {
  2498. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_ENOUGH_MEMORY ) );
  2499. goto Cleanup;
  2500. }
  2501. //
  2502. // Get the value for real.
  2503. //
  2504. scErr = TW32( RegQueryValueExW(
  2505. hKey // handle to key
  2506. , NULL // value name
  2507. , 0 // reserved
  2508. , &dwType // type buffer
  2509. , (LPBYTE) pszAssociation // data buffer
  2510. , &cbAssociationSize // size of data buffer
  2511. ) );
  2512. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2513. {
  2514. hr = THR( MK_E_INVALIDEXTENSION );
  2515. goto Cleanup;
  2516. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2517. else if ( scErr != ERROR_SUCCESS )
  2518. {
  2519. goto MakeHr;
  2520. }
  2521. if ( dwType != REG_SZ )
  2522. {
  2523. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2524. goto Cleanup;
  2525. }
  2526. scErr = TW32( RegCloseKey( hKey ) );
  2527. if ( scErr != ERROR_SUCCESS )
  2528. {
  2529. goto MakeHr;
  2530. }
  2531. hKey = NULL;
  2532. //
  2533. // Take the data and make a key with \ScriptEngine on the end. If
  2534. // we find this then we can use the file.
  2535. //
  2536. hr = THR( StringCchPrintfW( &pszAssociation[ dwNumChars - 1 ], cchBufSize - ( dwNumChars - 1 ), SCRIPTENGINE_KEY_STRING ) );
  2537. if ( FAILED( hr ) )
  2538. {
  2539. goto Cleanup;
  2540. } // if: FAILED( hr )
  2541. scErr = TW32( RegOpenKeyExW(
  2542. HKEY_CLASSES_ROOT // handle to open key
  2543. , pszAssociation // subkey name
  2544. , 0 // reserved
  2545. , KEY_READ // security access
  2546. , &hKey // key handle
  2547. ) );
  2548. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2549. {
  2550. hr = THR( MK_E_INVALIDEXTENSION );
  2551. goto Cleanup;
  2552. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2553. else if ( scErr != ERROR_SUCCESS )
  2554. {
  2555. goto MakeHr;
  2556. } // else if: ( scErr != ERROR_SUCCESS )
  2557. scErr = TW32( RegQueryValueExW(
  2558. hKey // handle to key
  2559. , NULL // value name
  2560. , 0 // reserved
  2561. , &dwType // type buffer
  2562. , NULL // data buffer
  2563. , &cbEngineNameSize // size of data buffer
  2564. ) );
  2565. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2566. {
  2567. hr = THR( MK_E_INVALIDEXTENSION );
  2568. goto Cleanup;
  2569. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2570. else if ( scErr != ERROR_SUCCESS )
  2571. {
  2572. goto MakeHr;
  2573. }
  2574. if ( dwType != REG_SZ )
  2575. {
  2576. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2577. goto Cleanup;
  2578. }
  2579. dwNumChars = cbEngineNameSize / sizeof( WCHAR );
  2580. pszEngineName = (LPWSTR) TraceAlloc( GPTR, cbEngineNameSize );
  2581. if ( NULL == pszEngineName )
  2582. {
  2583. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_ENOUGH_MEMORY ) );
  2584. goto Cleanup;
  2585. }
  2586. pszEngineName[ dwNumChars - 1 ] = L'\0';
  2587. //
  2588. // Get the value for real.
  2589. //
  2590. scErr = TW32( RegQueryValueExW(
  2591. hKey // handle to key
  2592. , NULL // value name
  2593. , 0 // reserved
  2594. , &dwType // type buffer
  2595. , (LPBYTE) pszEngineName // data buffer
  2596. , &cbEngineNameSize // size of data buffer
  2597. ) );
  2598. if ( scErr == ERROR_FILE_NOT_FOUND ) // The fix for bug 737013 in windows database.
  2599. {
  2600. hr = THR( MK_E_INVALIDEXTENSION );
  2601. goto Cleanup;
  2602. } // if: ( scErr == ERROR_FILE_NOT_FOUND )
  2603. else if ( scErr != ERROR_SUCCESS )
  2604. {
  2605. goto MakeHr;
  2606. }
  2607. if ( dwType != REG_SZ )
  2608. {
  2609. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2610. goto Cleanup;
  2611. }
  2612. scErr = RegCloseKey( hKey );
  2613. if ( scErr != ERROR_SUCCESS )
  2614. {
  2615. goto MakeHr;
  2616. }
  2617. hKey = NULL;
  2618. goto Cleanup;
  2619. MakeHr:
  2620. hr = HRESULT_FROM_WIN32( TW32( scErr ) );
  2621. goto Cleanup;
  2622. Cleanup:
  2623. if ( FAILED( hr ) )
  2624. {
  2625. TraceFree( pszEngineName );
  2626. pszEngineName = NULL;
  2627. }
  2628. else
  2629. {
  2630. m_pszScriptEngine = pszEngineName;
  2631. }
  2632. if ( hKey != NULL )
  2633. {
  2634. (void) RegCloseKey( hKey );
  2635. }
  2636. TraceFree( pszAssociation );
  2637. HRETURN( hr );
  2638. } //*** CScriptResource::MakeScriptEngineAssociation
  2639. #undef SCRIPTENGINE_KEY_STRING
  2640. //////////////////////////////////////////////////////////////////////////////
  2641. //++
  2642. //
  2643. // CScriptResource::HrGetScriptFilePath
  2644. //
  2645. // Description:
  2646. // Reads the registry, extracts the script file path and sets m_pszScriptFilePath.
  2647. //
  2648. // Arguments:
  2649. // None
  2650. //
  2651. // Return Values:
  2652. // S_OK - Script file path retrieved successfully.
  2653. // ERROR_FILE_NOT_FOUND - Script file path not set yet.
  2654. // Other HRESULTs.
  2655. //
  2656. //--
  2657. //////////////////////////////////////////////////////////////////////////////
  2658. HRESULT
  2659. CScriptResource::HrGetScriptFilePath( void )
  2660. {
  2661. TraceFunc( "" );
  2662. HRESULT hr = S_OK;
  2663. DWORD scErr;
  2664. DWORD cbSize;
  2665. DWORD dwType;
  2666. LPWSTR pszScriptFilePathTmp = NULL;
  2667. //
  2668. // Figure out how big the filepath is.
  2669. //
  2670. scErr = ClusterRegQueryValue( m_hkeyParams, CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH, NULL, NULL, &cbSize );
  2671. if ( scErr != ERROR_SUCCESS )
  2672. {
  2673. hr = HRESULT_FROM_WIN32( scErr );
  2674. if ( ( scErr == ERROR_FILE_NOT_FOUND ) || ( scErr == ERROR_KEY_DELETED ) )
  2675. {
  2676. goto Cleanup; // We don't want to log this error, goto Cleanup.
  2677. }
  2678. else
  2679. {
  2680. TW32( scErr );
  2681. goto Error;
  2682. }
  2683. } // if: failed
  2684. //
  2685. // Make a buffer big enough.
  2686. //
  2687. cbSize += sizeof( L'\0' );
  2688. pszScriptFilePathTmp = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, cbSize ) );
  2689. if ( pszScriptFilePathTmp == NULL )
  2690. {
  2691. hr = THR( E_OUTOFMEMORY );
  2692. goto Error;
  2693. }
  2694. //
  2695. // Grab it for real this time,
  2696. //
  2697. scErr = TW32( ClusterRegQueryValue(
  2698. m_hkeyParams
  2699. , CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH
  2700. , &dwType
  2701. , reinterpret_cast<LPBYTE>( pszScriptFilePathTmp )
  2702. , &cbSize
  2703. ) );
  2704. if ( scErr != ERROR_SUCCESS )
  2705. {
  2706. hr = HRESULT_FROM_WIN32( scErr );
  2707. goto Error;
  2708. }
  2709. Assert( ( dwType == REG_SZ ) || ( dwType == REG_EXPAND_SZ ) );
  2710. //
  2711. // If we have some old data from before then free this first.
  2712. //
  2713. LocalFree( m_pszScriptFilePath );
  2714. m_pszScriptFilePath = ClRtlExpandEnvironmentStrings( pszScriptFilePathTmp );
  2715. if ( m_pszScriptFilePath == NULL )
  2716. {
  2717. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  2718. goto Error;
  2719. }
  2720. Cleanup:
  2721. if ( pszScriptFilePathTmp != NULL )
  2722. {
  2723. TraceFree( pszScriptFilePathTmp );
  2724. } // if: pszScriptFilePathTmp
  2725. HRETURN( hr );
  2726. Error:
  2727. LogError( hr, L"Error getting the script file path property from the cluster database." );
  2728. goto Cleanup;
  2729. } //*** CScriptResource::HrGetScriptFilePath
  2730. //////////////////////////////////////////////////////////////////////////////
  2731. //++
  2732. //
  2733. // CScriptResource::HrLoadScriptEngine
  2734. //
  2735. // Description:
  2736. // Connects to the script engine associated with the script passed in.
  2737. //
  2738. // Arguments:
  2739. // None.
  2740. //
  2741. // Return Values:
  2742. // S_OK - connected OK.
  2743. // Failure status - local cleanup performed.
  2744. //
  2745. //--
  2746. //////////////////////////////////////////////////////////////////////////////
  2747. HRESULT
  2748. CScriptResource::HrLoadScriptEngine( void )
  2749. {
  2750. TraceFunc( "" );
  2751. HRESULT hr = S_OK;
  2752. CLSID clsidScriptEngine;
  2753. CActiveScriptSite * psite = NULL;
  2754. Assert( m_pszScriptFilePath != NULL );
  2755. Assert( m_pass == NULL );
  2756. Assert( m_pasp == NULL );
  2757. Assert( m_pas == NULL );
  2758. Assert( m_pidm == NULL );
  2759. //
  2760. // Create the scripting site.
  2761. //
  2762. psite = new CActiveScriptSite( m_hResource, ClusResLogEvent, m_hkeyParams, m_pszName );
  2763. if ( psite == NULL )
  2764. {
  2765. hr = THR( E_OUTOFMEMORY );
  2766. LogError( hr, L"Error allocating memory for the active script site object instance." );
  2767. goto Cleanup;
  2768. }
  2769. hr = THR( psite->QueryInterface( IID_IActiveScriptSite, reinterpret_cast< void ** >( &m_pass ) ) );
  2770. if ( FAILED( hr ) )
  2771. {
  2772. LogError( hr, L"Error getting the active script site interface." );
  2773. goto Cleanup;
  2774. }
  2775. //
  2776. // Find the Active Engine.
  2777. //
  2778. if ( m_pszScriptFilePath == NULL )
  2779. {
  2780. (ClusResLogEvent)( m_hResource, LOG_ERROR, L"HrLoadScriptEngine: No script file path set\n" );
  2781. hr = HRESULT_FROM_WIN32( TW32( ERROR_FILE_NOT_FOUND ) );
  2782. goto Cleanup;
  2783. } // if: no script file path specified
  2784. else
  2785. {
  2786. //
  2787. // Find the program associated with the extension.
  2788. //
  2789. hr = HrMakeScriptEngineAssociation();
  2790. if ( FAILED( hr ) )
  2791. {
  2792. LogError( hr, L"Error getting script engine." );
  2793. goto Cleanup;
  2794. }
  2795. hr = THR( CLSIDFromProgID( m_pszScriptEngine, &clsidScriptEngine ) );
  2796. if ( FAILED( hr ) )
  2797. {
  2798. LogError( hr, L"Error getting the ProgID for the script engine." );
  2799. goto Cleanup;
  2800. }
  2801. } // else: script file path specified
  2802. //
  2803. // Create an instance of it.
  2804. //
  2805. TraceDo( hr = THR( CoCreateInstance(
  2806. clsidScriptEngine
  2807. , NULL
  2808. , ( CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER )
  2809. , IID_IActiveScriptParse
  2810. , reinterpret_cast< void ** >( &m_pasp )
  2811. ) ) );
  2812. if ( FAILED( hr ) )
  2813. {
  2814. LogError( hr, L"Error creating the script engine object instance." );
  2815. goto Cleanup;
  2816. }
  2817. m_pasp = TraceInterface( L"Active Script Engine", IActiveScriptParse, m_pasp, 1 );
  2818. TraceDo( hr = THR( m_pasp->QueryInterface( IID_IActiveScript, reinterpret_cast<void**> ( &m_pas ) ) ) );
  2819. if ( FAILED( hr ) )
  2820. {
  2821. LogError( hr, L"Error getting the active script interface from the script parse object." );
  2822. goto Cleanup;
  2823. }
  2824. m_pas = TraceInterface( L"Active Script Engine", IActiveScript, m_pas, 1 );
  2825. //
  2826. // Initialize it.
  2827. //
  2828. TraceDo( hr = THR( m_pasp->InitNew() ) );
  2829. if ( FAILED( hr ) )
  2830. {
  2831. LogError( hr, L"Error initializing the script site parser object." );
  2832. goto Cleanup;
  2833. }
  2834. #if defined(DEBUG)
  2835. //
  2836. // Set our site. We'll give out a new tracking interface to track this separately.
  2837. //
  2838. {
  2839. IActiveScriptSite * psiteDbg;
  2840. hr = THR( m_pass->TypeSafeQI( IActiveScriptSite, &psiteDbg ) );
  2841. Assert( hr == S_OK );
  2842. TraceDo( hr = THR( m_pas->SetScriptSite( psiteDbg ) ) );
  2843. psiteDbg->Release(); // release promptly
  2844. psiteDbg = NULL;
  2845. if ( FAILED( hr ) )
  2846. {
  2847. LogError( hr, L"Error setting the script site on the script engine." );
  2848. goto Cleanup;
  2849. }
  2850. }
  2851. #else
  2852. TraceDo( hr = THR( m_pas->SetScriptSite( m_pass ) ) );
  2853. if ( FAILED( hr ) )
  2854. {
  2855. LogError( hr, L"Error setting the script site on the script engine." );
  2856. goto Cleanup;
  2857. }
  2858. #endif
  2859. //
  2860. // Add Document to the global members.
  2861. //
  2862. TraceDo( hr = THR( m_pas->AddNamedItem( L"Resource", SCRIPTITEM_ISVISIBLE ) ) );
  2863. if ( FAILED( hr ) )
  2864. {
  2865. LogError( hr, L"Error adding the 'Resource' named item to the script object." );
  2866. goto Cleanup;
  2867. }
  2868. //
  2869. // Connect the script.
  2870. //
  2871. TraceDo( hr = THR( m_pas->SetScriptState( SCRIPTSTATE_CONNECTED ) ) );
  2872. if ( FAILED( hr ) )
  2873. {
  2874. LogError( hr, L"Error setting the script state on the script engine." );
  2875. goto Cleanup;
  2876. }
  2877. //
  2878. // Get the dispatch inteface to the script.
  2879. //
  2880. TraceDo( hr = THR( m_pas->GetScriptDispatch( NULL, &m_pidm ) ) );
  2881. if ( FAILED( hr) )
  2882. {
  2883. LogError( hr, L"Error getting the script dispatch table." );
  2884. goto Cleanup;
  2885. }
  2886. m_pidm = TraceInterface( L"Active Script", IDispatch, m_pidm, 1 );
  2887. hr = S_OK;
  2888. (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"Loaded script engine '%1!ws!' successfully.\n", m_pszScriptEngine );
  2889. Cleanup:
  2890. if ( psite != NULL )
  2891. {
  2892. psite->Release();
  2893. psite = NULL;
  2894. }
  2895. HRETURN( hr );
  2896. } //*** CScriptResource::HrLoadScriptEngine
  2897. //////////////////////////////////////////////////////////////////////////////
  2898. //
  2899. // CScriptResource::UnloadScriptEngine
  2900. //
  2901. // Description:
  2902. // Disconnects from any currently connected script engine.
  2903. //
  2904. // Arguments:
  2905. // None.
  2906. //
  2907. // Return Values:
  2908. // None.
  2909. //
  2910. //////////////////////////////////////////////////////////////////////////////
  2911. void
  2912. CScriptResource::UnloadScriptEngine( void )
  2913. {
  2914. TraceFunc( "" );
  2915. //
  2916. // Cleanup the scripting engine.
  2917. //
  2918. if ( m_pszScriptEngine != NULL )
  2919. {
  2920. (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"Unloaded script engine '%1!ws!' successfully.\n", m_pszScriptEngine );
  2921. TraceFree( m_pszScriptEngine );
  2922. m_pszScriptEngine = NULL;
  2923. }
  2924. if ( m_pidm != NULL )
  2925. {
  2926. TraceDo( m_pidm->Release() );
  2927. m_pidm = NULL;
  2928. } // if: m_pidm
  2929. if ( m_pasp != NULL )
  2930. {
  2931. TraceDo( m_pasp->Release() );
  2932. m_pasp = NULL;
  2933. } // if: m_pasp
  2934. if ( m_pas != NULL )
  2935. {
  2936. TraceDo( m_pas->Close() );
  2937. TraceDo( m_pas->Release() );
  2938. m_pas = NULL;
  2939. } // if: m_pas
  2940. if ( m_pass != NULL )
  2941. {
  2942. TraceDo( m_pass->Release() );
  2943. m_pass = NULL;
  2944. } // if: m_pass
  2945. TraceFuncExit();
  2946. } //*** CScriptResource::UnloadScriptEngine