Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

579 lines
18 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Script Manager
  6. File: ScrptMgr.h
  7. Owner: AndrewS
  8. This file contains the declarations for the Script Manager, ie. siting an
  9. ActiveX Scripting engine (in our case VBScript) for Denali.
  10. ===================================================================*/
  11. #ifndef __ScrptMgr_h
  12. #define __ScrptMgr_h
  13. #include <dispex.h>
  14. #include "activscp.h"
  15. #include "activdbg.h"
  16. #include "hostinfo.h"
  17. #include "util.h"
  18. #include "HitObj.h"
  19. #include "hashing.h"
  20. #include "memcls.h"
  21. #include "scrpteng.h"
  22. typedef SCRIPTSTATE ENGINESTATE; // Uninited, Loaded, etc
  23. typedef CLSID PROGLANG_ID;
  24. const CBPROGLANG_ID = sizeof(PROGLANG_ID);
  25. class CActiveScriptSite;
  26. class CActiveScriptEngine;
  27. class CASEElem;
  28. class CScriptingNamespace;
  29. class CAppln;
  30. // SMHash depends on stuff in this include file which must be defined first.
  31. #include "SMHash.h"
  32. /*
  33. *
  34. *
  35. * C S c r i p t M a n a g e r
  36. *
  37. *
  38. * Manages script engines, potentially caching them for future use,
  39. * hands script engines to callers for use.
  40. *
  41. */
  42. class CScriptManager
  43. {
  44. private:
  45. // private data members
  46. BOOLB m_fInited; // Are we initialized?
  47. /*
  48. * Script Engines that are not in use can be reused and
  49. * go on the Free Script Queue. It is a queue so we can
  50. * discard the oldest if we need to.
  51. *
  52. * Engines that are in use cant be reused. When an engine
  53. * is handed out to be used, it is removed from the FSQ. When a thread
  54. * is done using an engine, it calls ReturnEngineToCache to put it back on
  55. * the FSQ. If the Queue is at max length, the oldest engine on the queue is
  56. * freed at that point. The one returned is put on the front of the queue.
  57. *
  58. * We also maintain a Running Script List. This is needed so that if we
  59. * are told to flush a given script from our cache, we can "zombify" any
  60. * running scripts that have that script in them (so they will be discarded
  61. * when they are done running.)
  62. *
  63. * Additional note: Though we cant have multiple users of the *same* runing engine
  64. * we can "clone" a running engine. If we get two simulanteous requests for Foo.ASP
  65. * we expect that it will be faster to clone the second one from the first one than
  66. * to create a second engine for the second request. Thus, the RSL will be searched
  67. * for a given engine to clone if no suitable engine is found on the FSQ.
  68. *
  69. * DEBUGGING NOTE:
  70. * Once the debugger asks a script engine for a code context cookie, we cannot
  71. * ever let go of the script engine until the debugger detaches. Therefore, we
  72. * don't cache scripts in the FSQ if debugging is active. Instead, the scripts
  73. * are placed in the template when execution is finished, there to be doled back
  74. * out when that engine is needed by the debugging engine.
  75. *
  76. * CONSIDER:
  77. * We could be smarter about this, and cache scripts UNTIL the debugger either
  78. * a. Asks for a code context from a document context, or
  79. * b. Calls GetDocumentContextFromPosition, in which case, the debugger
  80. * got a code context "behind our virtual backs".
  81. *
  82. * If we don't do this, we could, at the very least, only implement this
  83. * debugging behavior when a debugger attaches to our application.
  84. * (i.e. stop caching on attach, then on detach, resume caching, and also
  85. * free scripts that the template objects are holding onto.)
  86. */
  87. CSMHash m_htFSQ; // Free Script Queue
  88. CRITICAL_SECTION m_csFSQ; // Serialize access to FSQ
  89. CSMHash m_htRSL; // Running Script List
  90. CRITICAL_SECTION m_csRSL; // Serialize access to RSL
  91. CHashTable m_hTPLL; // Hash table of language engine classid's
  92. CRITICAL_SECTION m_cSPLL; // Serialize access to PLL
  93. DWORD m_idScriptKiller; // Script killer sched workitem id
  94. DWORD m_msecScriptKillerTimeout;// Current script killer timeout
  95. // private methods
  96. HRESULT UnInitASEElems();
  97. HRESULT UnInitPLL();
  98. HRESULT AddProgLangToPLL(CHAR *szProgLangName, PROGLANG_ID progLangId);
  99. // script killer
  100. static VOID WINAPI ScriptKillerSchedulerCallback(VOID *pv);
  101. public:
  102. // public methods
  103. CScriptManager();
  104. ~CScriptManager();
  105. HRESULT Init();
  106. HRESULT UnInit();
  107. // Resolves a language name into a prog lang id, adding to engine list (m_hTPLL) if not already there
  108. HRESULT ProgLangIdOfLangName(LPCSTR szProgLang, PROGLANG_ID *pProgLangId);
  109. // Return an engine, preferably filled with the script for the given template/language
  110. HRESULT GetEngine( LCID lcid, // The system language to use
  111. PROGLANG_ID& progLangId, // prog lang id of the script
  112. LPCTSTR szTemplateName, // Template we want an engine for
  113. CHitObj *pHitObj, // Hit obj to use in this engine
  114. CScriptEngine **ppSE, // Returned script engine
  115. ENGINESTATE *pdwState, // Current state of the engine
  116. CTemplate *pTemplate, // template (debug document)
  117. DWORD dwSourceContext); // script engine index
  118. HRESULT ReturnEngineToCache(CScriptEngine **, CAppln *, IASPObjectContextCustom *);
  119. // Throw out any cached engines containing a given template
  120. // (presumably the script changed on disk so the cache is obsolete.)
  121. HRESULT FlushCache(LPCTSTR szTemplateName); // Template to throw out of the cache
  122. HRESULT FlushAll(); // Clear the entire FSQ
  123. HRESULT KillOldEngines(BOOLB fKillNow = FALSE); // Kill expired scripting engines
  124. // Bug 1140: Called prior to shutting down script manager to make sure RSL is empty
  125. HRESULT EmptyRunningScriptList();
  126. // Adjust (shorten) script killer timeout
  127. HRESULT AdjustScriptKillerTimeout(DWORD msecNewTimeout);
  128. // Find running script that corresponds to a template (in one of its script blocks)
  129. IActiveScriptDebug *GetDebugScript(CTemplate *pTemplate, DWORD dwSourceContext);
  130. private:
  131. HRESULT FindEngineInList(LPCTSTR szTemplateName, PROGLANG_ID progLangId, DWORD dwInstanceID, BOOL fFSQ, CASEElem **ppASEElem);
  132. HRESULT FindASEElemInList(CActiveScriptEngine *pASE, BOOL fFSQ, CASEElem **ppASEElem);
  133. // For threading a FIFO queue through the hash table
  134. HRESULT AddToFSQ(CASEElem *pASEElem);
  135. HRESULT CheckFSQLRU();
  136. #ifdef DBG
  137. virtual void AssertValid() const;
  138. #else
  139. virtual void AssertValid() const {}
  140. #endif
  141. };
  142. extern CScriptManager g_ScriptManager;
  143. /*
  144. *
  145. *
  146. * C A c t i v e S c r i p t E n g i n e
  147. *
  148. * Object defining methods required to host an ActiveXScripting engine &
  149. * service requests to that engine.
  150. *
  151. */
  152. class CActiveScriptEngine :
  153. public CScriptEngine,
  154. public IActiveScriptSite,
  155. public IActiveScriptSiteDebug,
  156. public IHostInfoProvider
  157. {
  158. private:
  159. // private data members
  160. UINT m_cRef; // Reference count
  161. IDispatch *m_pDisp; // IDispatch interface on script
  162. CHitObj *m_pHitObj; // The hit object contains a list of objects for this run
  163. LPTSTR m_szTemplateName; // The name of the template this engine has loaded
  164. DWORD m_dwInstanceID; // server instance ID of template this engine has loaded
  165. TCHAR m_szTemplateNameBuf[64]; // Buffer for short templates to fit to avoid allocs
  166. PROGLANG_ID m_proglang_id; // What programming language?
  167. LCID m_lcid; // what system language
  168. IActiveScript *m_pAS; // The script object sited here
  169. IActiveScriptParse *m_pASP; // The script object parser
  170. IHostInfoUpdate *m_pHIUpdate;// Interface for advising the script that we have new host info
  171. time_t m_timeStarted; // Time when the script engine was handed out last.
  172. CTemplate *m_pTemplate; // template that acts as debugging document
  173. DWORD m_dwSourceContext; // "Cookie" value which is really script engine
  174. DWORD m_fInited : 1; // Have we been inited?
  175. DWORD m_fZombie : 1; // Do we need to be deleted on last use
  176. DWORD m_fScriptLoaded : 1; // Have we been called with script to load yet? (Used for clone)
  177. DWORD m_fObjectsLoaded : 1; // Have we been called with a set of objects yet? (Used for clone)
  178. DWORD m_fBeingDebugged : 1; // Is this script being debugged now?
  179. DWORD m_fTemplateNameAllocated : 1; // Is name allocated? (need to free?)
  180. /*
  181. * NOTE: ActiveXScripting:
  182. * ActiveXScripting had an undone such that the excepinfo filled in in InteruptScript
  183. * was not passed to OnScriptError. We would have liked to use that mechanism to cause
  184. * correct error loging (or suppression) if we interrupt a script. However,
  185. * since ActiveXScripting wasnt passing the info, we didnt know. We wrote this code to
  186. * handle it ourselves. They have now fixed it, but the mechanism we implemented works very
  187. * well, so we are not going to change it.
  188. */
  189. DWORD m_fScriptAborted : 1; // The script did a Response.End
  190. DWORD m_fScriptTimedOut : 1; // We killed the script on timeout
  191. DWORD m_fScriptHadError : 1; // The script had an error while running. Transacted script should autoabort
  192. /*
  193. * BUG 1225: If there is a GPF running a script, we shouldnt reuse the engine
  194. */
  195. DWORD m_fCorrupted : 1; // Might the engine be "unsafe" for reuse?
  196. // handle GetItemInfo() failure
  197. void HandleItemNotFound(LPCOLESTR pcszName);
  198. HRESULT StoreTemplateName(LPCTSTR szTemplateName);
  199. public:
  200. CActiveScriptEngine();
  201. ~CActiveScriptEngine();
  202. HRESULT Init(
  203. PROGLANG_ID proglang_id,
  204. LPCTSTR szTemplateName,
  205. LCID lcid,
  206. CHitObj *pHitObj,
  207. CTemplate *pTemplate,
  208. DWORD dwSourceContext);
  209. HRESULT MakeClone(
  210. PROGLANG_ID proglang_id,
  211. LPCTSTR szTemplateName,
  212. LCID lcid,
  213. CHitObj *pHitObj,
  214. CTemplate *pTemplate,
  215. DWORD dwSourceContext,
  216. DWORD dwInstanceID,
  217. IActiveScript *pAS); // The cloned script engine
  218. HRESULT ReuseEngine(
  219. CHitObj *pHitObj,
  220. CTemplate *pTemplate,
  221. DWORD dwSourceContext,
  222. DWORD dwInstanceID
  223. );
  224. time_t TimeStarted();
  225. VOID SetTimeStarted(time_t timeStarted);
  226. BOOL FBeingDebugged(); // Is the script being debugged?
  227. VOID IsBeingDebugged(); // Notify script that it is being debugged
  228. HRESULT ResetToUninitialized(IASPObjectContextCustom *);
  229. HRESULT GetASP();
  230. HRESULT GetIDisp();
  231. HRESULT GetIHostInfoUpdate();
  232. IActiveScript *GetActiveScript();
  233. LPTSTR SzTemplateName();
  234. BOOL FIsZombie();
  235. BOOL FIsCorrupted();
  236. PROGLANG_ID ProgLang_Id();
  237. DWORD DWInstanceID();
  238. BOOL FFullyLoaded();
  239. long GetTimeout();
  240. BOOL FScriptTimedOut();
  241. BOOL FScriptHadError();
  242. void GetDebugDocument(CTemplate **ppTemplate, DWORD *pdwSourceContext);
  243. /*
  244. * C S c r i p t E n g i n e M e t h o d s
  245. */
  246. HRESULT AddScriptlet(LPCOLESTR wstrScript);
  247. HRESULT AddObjects(BOOL fPersistNames = TRUE);
  248. HRESULT AddAdditionalObject(LPWSTR strObjName, BOOL fPersistNames = TRUE);
  249. HRESULT AddScriptingNamespace();
  250. HRESULT Call(LPCOLESTR strEntryPoint);
  251. HRESULT CheckEntryPoint(LPCOLESTR strEntryPoint);
  252. HRESULT MakeEngineRunnable() { return(Call(NULL)); };
  253. HRESULT ResetScript() { return m_pAS? m_pAS->SetScriptState(SCRIPTSTATE_UNINITIALIZED) : E_FAIL; }
  254. VOID Zombify();
  255. HRESULT InterruptScript(BOOL fAbnormal = TRUE);
  256. HRESULT UpdateLocaleInfo(hostinfo hi);
  257. HRESULT TryCall(LPCOLESTR strEntryPoint);
  258. ULONG FinalRelease();
  259. /*
  260. * I U n k n o w n M e t h o d s
  261. */
  262. STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
  263. STDMETHOD_(ULONG, AddRef)(VOID);
  264. STDMETHOD_(ULONG, Release)(VOID);
  265. /*
  266. * C A c t i v e S c r i p t S i t e M e t h o d s
  267. */
  268. STDMETHOD(GetLCID)(LCID *plcid);
  269. STDMETHOD(GetItemInfo)(LPCOLESTR pcszName,
  270. DWORD dwReturnMask,
  271. IUnknown **ppiunkItem,
  272. ITypeInfo **ppti);
  273. STDMETHOD(GetDocVersionString)(BSTR *pszVersion);
  274. STDMETHOD(RequestItems)(BOOL fPersistNames = TRUE);
  275. STDMETHOD(RequestTypeLibs)(VOID);
  276. STDMETHOD(OnScriptTerminate)(const VARIANT *pvarResult,
  277. const EXCEPINFO *pexcepinfo);
  278. STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState);
  279. STDMETHOD(OnScriptError)(IActiveScriptError __RPC_FAR *pscripterror);
  280. STDMETHOD(OnEnterScript)(VOID);
  281. STDMETHOD(OnLeaveScript)(VOID);
  282. /*
  283. * C A c t i v e S c r i p t S i t e D e b u g M e t h o d s
  284. */
  285. STDMETHOD(GetDocumentContextFromPosition)(
  286. /* [in] */ DWORD_PTR dwSourceContext,
  287. /* [in] */ ULONG uCharacterOffset,
  288. /* [in] */ ULONG uNumChars,
  289. /* [out] */ IDebugDocumentContext **ppsc);
  290. STDMETHOD(GetApplication)(/* [out] */ IDebugApplication **ppda);
  291. STDMETHOD(GetRootApplicationNode)(/* [out] */ IDebugApplicationNode **);
  292. STDMETHOD(OnScriptErrorDebug)(
  293. /* [in] */ IActiveScriptErrorDebug *pErrorDebug,
  294. /* [out] */ BOOL *pfEnterDebugger,
  295. /* [out] */ BOOL *pfCallOnScriptErrorWhenContinuing);
  296. /*
  297. * IHostInfoProvider methods
  298. */
  299. STDMETHOD(GetHostInfo)(hostinfo hostinfoRequest, void **ppvInfo);
  300. public:
  301. #ifdef DBG
  302. virtual void AssertValid() const;
  303. #else
  304. virtual void AssertValid() const {}
  305. #endif
  306. // Cache on per-class basis
  307. ACACHE_INCLASS_DEFINITIONS()
  308. };
  309. inline VOID CActiveScriptEngine::Zombify() { m_fZombie = TRUE; }
  310. inline BOOL CActiveScriptEngine::FFullyLoaded() { return(m_fScriptLoaded && m_fObjectsLoaded); }
  311. inline BOOL CActiveScriptEngine::FIsZombie() { return(m_fZombie); }
  312. inline BOOL CActiveScriptEngine::FIsCorrupted() { return(m_fCorrupted); }
  313. inline time_t CActiveScriptEngine::TimeStarted() { return(m_timeStarted); }
  314. inline VOID CActiveScriptEngine::SetTimeStarted(time_t timeStarted) { m_timeStarted = timeStarted; }
  315. inline IActiveScript *CActiveScriptEngine::GetActiveScript() { return(m_pAS); }
  316. inline LPTSTR CActiveScriptEngine::SzTemplateName() { return(m_szTemplateName); }
  317. inline PROGLANG_ID CActiveScriptEngine::ProgLang_Id() { return(m_proglang_id); }
  318. inline DWORD CActiveScriptEngine::DWInstanceID() { return(m_dwInstanceID); }
  319. inline BOOL CActiveScriptEngine::FBeingDebugged() { return(m_fBeingDebugged); } // Is the script being debugged?
  320. inline VOID CActiveScriptEngine::IsBeingDebugged() { m_fBeingDebugged = TRUE; }
  321. inline BOOL CActiveScriptEngine::FScriptTimedOut() { return m_fScriptTimedOut; }
  322. inline BOOL CActiveScriptEngine::FScriptHadError() { return m_fScriptHadError; }
  323. inline long CActiveScriptEngine::GetTimeout() { return m_fBeingDebugged? LONG_MAX : m_pHitObj->GetScriptTimeout(); }
  324. inline void CActiveScriptEngine::GetDebugDocument(CTemplate **ppTemplate, DWORD *pdwSourceContext)
  325. {
  326. if (ppTemplate) *ppTemplate = m_pTemplate;
  327. if (pdwSourceContext) *pdwSourceContext = m_dwSourceContext;
  328. }
  329. /*
  330. *
  331. *
  332. * C A S E E l e m
  333. *
  334. * Script element. For keeping lists and queues of script engines
  335. *
  336. */
  337. class CASEElem : public CLruLinkElem
  338. {
  339. private:
  340. CActiveScriptEngine *m_pASE;
  341. public:
  342. CASEElem() : m_pASE(NULL) {}
  343. ~CASEElem();
  344. HRESULT Init(CActiveScriptEngine *pASE);
  345. CActiveScriptEngine *PASE();
  346. // Cache on per-class basis
  347. ACACHE_INCLASS_DEFINITIONS()
  348. };
  349. inline CActiveScriptEngine *CASEElem::PASE() { return(m_pASE); }
  350. /*
  351. *
  352. *
  353. * C P L L E l e m
  354. *
  355. * Hash table list element for a Programming Language List.
  356. *
  357. */
  358. class CPLLElem : public CLinkElem
  359. {
  360. private:
  361. PROGLANG_ID m_ProgLangId; // clsid for the language
  362. public:
  363. CPLLElem() : m_ProgLangId(CLSID_NULL) {};
  364. ~CPLLElem();
  365. HRESULT Init(CHAR *szProgLangName, PROGLANG_ID progLangId);
  366. PROGLANG_ID ProgLangId();
  367. };
  368. inline PROGLANG_ID CPLLElem::ProgLangId() { return(m_ProgLangId); }
  369. /*
  370. *
  371. *
  372. * C S c r i p t i n g N a m e s p a c e
  373. *
  374. * We need to keep track of all of the names which different engines (and typeinfos)
  375. * contribute to the namespace. All of these names go into this object
  376. * which we give to each engine with the SCRIPTITEM_GLOBALMEMBERS flag. When
  377. * ActiveXScripting calls us back on GetIdsOfNames, we will call the engines
  378. * we have cached until we find the name. When AXS calls us with Invoke,
  379. * we will map the id to the appropriate engine and pass on the invoke
  380. *
  381. * Data structure note:
  382. * We implement the ScriptingNamespace with a linked list of arrays.
  383. * This gives reasonable access time and should minimize heap
  384. * fragmentation. In debug mode, the number of buckets is small to
  385. * excersize the resize code.
  386. *
  387. * NOTE: "ENGDISPMAX" should be a power of two - this will allow the optimizer
  388. * to optimize the integer divide and modulus operations with bit-ands and
  389. * shifts. However, the code does not assume that "ENGDISPMAX" is a power
  390. * of two.
  391. */
  392. #ifdef DBG
  393. #define ENGDISPMAX 2
  394. #else
  395. #define ENGDISPMAX 32
  396. #endif
  397. typedef struct _engdisp
  398. {
  399. DISPID dispid; // the dispid that the engine really uses
  400. IDispatch *pDisp; // the engine to call for this dispid
  401. IDispatchEx *pDispEx; // the engine to call for this dispid
  402. } ENGDISP;
  403. typedef struct _engdispbucket : CDblLink
  404. {
  405. ENGDISP rgEngDisp[ENGDISPMAX+1];
  406. } ENGDISPBUCKET;
  407. class CEngineDispElem : public CDblLink
  408. {
  409. public:
  410. IDispatch *m_pDisp;
  411. IDispatchEx *m_pDispEx;
  412. // Cache on per-class basis
  413. ACACHE_INCLASS_DEFINITIONS()
  414. };
  415. class CScriptingNamespace : public IDispatchEx
  416. {
  417. private:
  418. ULONG m_cRef; // Reference count
  419. BOOLB m_fInited;
  420. CDblLink m_listSE; // List of scripting engines (list of CSEElem's)
  421. UINT m_cEngDispMac;
  422. CDblLink m_listEngDisp;
  423. HRESULT CacheDispID(CEngineDispElem *pEngine, DISPID dispidEngine, DISPID *pdispidCached);
  424. HRESULT FetchDispID(DISPID dispid, ENGDISP **ppEngDisp);
  425. public:
  426. // public methods
  427. CScriptingNamespace();
  428. ~CScriptingNamespace();
  429. HRESULT Init();
  430. HRESULT UnInit();
  431. HRESULT ReInit();
  432. HRESULT AddEngineToNamespace(CActiveScriptEngine *pASE);
  433. // IUnknown
  434. STDMETHODIMP QueryInterface(REFIID, void **);
  435. STDMETHODIMP_(ULONG) AddRef(void);
  436. STDMETHODIMP_(ULONG) Release(void);
  437. // IDispatch
  438. STDMETHODIMP GetTypeInfoCount(UINT *);
  439. STDMETHODIMP GetTypeInfo(UINT, LCID, ITypeInfo **);
  440. STDMETHODIMP GetIDsOfNames(REFIID, OLECHAR **, UINT, LCID, DISPID *);
  441. STDMETHODIMP Invoke(DISPID, REFIID, LCID, WORD,
  442. DISPPARAMS *, VARIANT *, EXCEPINFO *, UINT *);
  443. // IDispatchEx
  444. STDMETHODIMP DeleteMemberByDispID(DISPID id);
  445. STDMETHODIMP DeleteMemberByName(BSTR bstrName, DWORD grfdex);
  446. STDMETHODIMP GetMemberName(DISPID id, BSTR *pbstrName);
  447. STDMETHODIMP GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
  448. STDMETHODIMP GetNameSpaceParent(IUnknown **ppunk);
  449. STDMETHODIMP GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid);
  450. STDMETHODIMP GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid);
  451. STDMETHODIMP InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
  452. VARIANT *pVarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
  453. public:
  454. #ifdef DBG
  455. VOID AssertValid() const;
  456. #else
  457. VOID AssertValid() const {}
  458. #endif
  459. // Cache on per-class basis
  460. ACACHE_INCLASS_DEFINITIONS()
  461. };
  462. /*
  463. *
  464. *
  465. * U t i l i t i e s
  466. *
  467. * General utility functions
  468. *
  469. */
  470. HRESULT WrapTypeLibs(ITypeLib **prgpTypeLib, UINT cTypeLibs, IDispatch **ppDisp);
  471. #endif // __ScrptMgr_h