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.

450 lines
11 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Implementation of EngineDispatch.
  4. //
  5. #include "stdinc.h"
  6. #include "enginc.h"
  7. #include "engdisp.h"
  8. #include "limits"
  9. #include "oleaut.h"
  10. //////////////////////////////////////////////////////////////////////
  11. // Global constants
  12. const DISPID g_dispidFirstRoutine = 1;
  13. const DISPID g_dispidFirstGlobal = 1000001;
  14. //////////////////////////////////////////////////////////////////////
  15. // ASCII comparison of WCHAR and char strings
  16. bool wcsstrimatch(const WCHAR *pwsz, const char *pasz)
  17. {
  18. for (;;)
  19. {
  20. if (*pwsz > std::numeric_limits<char>::max())
  21. return false;
  22. char ch1 = (char)tolower((char)*pwsz++); // �� make sure tolower is the right kind of function
  23. char ch2 = (char)tolower((char)*pasz++);
  24. if (ch1 != ch2)
  25. return false;
  26. if (!ch1)
  27. return true;
  28. }
  29. }
  30. //////////////////////////////////////////////////////////////////////
  31. // Creation
  32. EngineDispatch::EngineDispatch(IUnknown *punkParent, Script &script, IDispatch *pGlobalDispatch)
  33. : m_cRef(1),
  34. m_scomParent(punkParent),
  35. m_script(script),
  36. m_exec(script, pGlobalDispatch)
  37. {
  38. punkParent->AddRef();
  39. }
  40. //////////////////////////////////////////////////////////////////////
  41. // IUnknown
  42. STDMETHODIMP
  43. EngineDispatch::QueryInterface(const IID &iid, void **ppv)
  44. {
  45. V_INAME(EngineDispatch::QueryInterface);
  46. V_PTRPTR_WRITE(ppv);
  47. V_REFGUID(iid);
  48. if (iid == IID_IUnknown || iid == IID_IDispatch)
  49. {
  50. *ppv = static_cast<IDispatch*>(this);
  51. }
  52. else
  53. {
  54. *ppv = NULL;
  55. return E_NOINTERFACE;
  56. }
  57. reinterpret_cast<IUnknown*>(this)->AddRef();
  58. return S_OK;
  59. }
  60. STDMETHODIMP_(ULONG)
  61. EngineDispatch::AddRef()
  62. {
  63. return InterlockedIncrement(&m_cRef);
  64. }
  65. STDMETHODIMP_(ULONG)
  66. EngineDispatch::Release()
  67. {
  68. if (!InterlockedDecrement(&m_cRef))
  69. {
  70. delete this;
  71. return 0;
  72. }
  73. return m_cRef;
  74. }
  75. //////////////////////////////////////////////////////////////////////
  76. // IDispatch
  77. STDMETHODIMP
  78. EngineDispatch::GetTypeInfoCount(UINT *pctinfo)
  79. {
  80. V_INAME(EngineDispatch::GetTypeInfoCount);
  81. V_PTR_WRITE(pctinfo, *pctinfo);
  82. *pctinfo = 1;
  83. return S_OK;
  84. }
  85. STDMETHODIMP
  86. EngineDispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
  87. {
  88. V_INAME(EngineDispatch::GetTypeInfo);
  89. V_PTR_WRITE(ppTInfo, *ppTInfo);
  90. if (iTInfo != 0)
  91. return DISP_E_BADINDEX;
  92. *ppTInfo = static_cast<ITypeInfo *>(this);
  93. this->AddRef();
  94. return S_OK;
  95. }
  96. STDMETHODIMP
  97. EngineDispatch::GetIDsOfNames(
  98. REFIID riid,
  99. LPOLESTR *rgszNames,
  100. UINT cNames,
  101. LCID lcid,
  102. DISPID *rgDispId)
  103. {
  104. V_INAME(EngineDispatch::GetIDsOfNames);
  105. V_BUFPTR_READ(rgszNames, sizeof(LPOLESTR) * cNames);
  106. V_BUFPTR_WRITE(rgDispId, sizeof(DISPID) * cNames);
  107. if (riid != IID_NULL)
  108. return DISP_E_UNKNOWNINTERFACE;
  109. if (cNames == 0)
  110. return S_OK;
  111. // Clear out dispid's
  112. for (UINT c = 0; c < cNames; ++c)
  113. {
  114. rgDispId[c] = DISPID_UNKNOWN;
  115. }
  116. // �� Possible optimization: sort the routines/globals so that we can bsearch for names.
  117. // See if we have a routine with the first name
  118. Routines::index irtnLast = m_script.routines.Next();
  119. for (Routines::index irtn = 0; irtn < irtnLast; ++irtn)
  120. {
  121. if (wcsstrimatch(rgszNames[0], m_script.strings[m_script.routines[irtn].istrIdentifier]))
  122. {
  123. rgDispId[0] = g_dispidFirstRoutine + irtn;
  124. break;
  125. }
  126. }
  127. if (rgDispId[0] == DISPID_UNKNOWN)
  128. {
  129. // See if we have a global variable with the first name
  130. Variables::index ivarLast = m_script.globals.Next();
  131. for (Variables::index ivar = g_cBuiltInConstants; ivar < ivarLast; ++ivar)
  132. {
  133. Variable &variable = m_script.globals[ivar];
  134. if (variable.dispid == DISPID_UNKNOWN && // variable must be in script (not member of global dispatch)
  135. wcsstrimatch(rgszNames[0], m_script.strings[variable.istrIdentifier]))
  136. {
  137. rgDispId[0] = g_dispidFirstGlobal + ivar;
  138. break;
  139. }
  140. }
  141. }
  142. // Additional names requested (cNames > 1) are named parameters to the method,
  143. // which isn't something we support.
  144. // Return DISP_E_UNKNOWNNAME in this case, and in the case that we didn't match
  145. // the first name.
  146. if (rgDispId[0] == DISPID_UNKNOWN || cNames > 1)
  147. return DISP_E_UNKNOWNNAME;
  148. return S_OK;
  149. }
  150. STDMETHODIMP
  151. EngineDispatch::Invoke(
  152. DISPID dispIdMember,
  153. REFIID riid,
  154. LCID lcid,
  155. WORD wFlags,
  156. DISPPARAMS *pDispParams,
  157. VARIANT *pVarResult,
  158. EXCEPINFO *pExcepInfo,
  159. UINT *puArgErr)
  160. {
  161. V_INAME(EngineDispatch::Invoke);
  162. V_PTR_READ(pDispParams, DISPPARAMS);
  163. V_PTR_WRITE_OPT(pVarResult, VARIANT);
  164. V_PTR_WRITE_OPT(puArgErr, UINT);
  165. // Additional parameter validation
  166. bool fReturnValueUsingOleAut = g_fUseOleAut || riid != g_guidInvokeWithoutOleaut;
  167. // This is true unless g_fUseOleAut is false (script engine is set to always use oleaut32.dll
  168. // and riid is g_guidInvokeWithoutOleaut (caller expects this not to return values allocated with
  169. // oleaut32.dll. See oleaut.h for more info.
  170. if (fReturnValueUsingOleAut && riid != IID_NULL)
  171. {
  172. return DISP_E_UNKNOWNINTERFACE;
  173. }
  174. // Zero the out params
  175. if (puArgErr)
  176. *puArgErr = 0;
  177. HRESULT hr = S_OK;
  178. if (dispIdMember < g_dispidFirstGlobal)
  179. {
  180. // it's a routine
  181. if (!(wFlags & DISPATCH_METHOD))
  182. return DISP_E_MEMBERNOTFOUND;
  183. Routines::index irtn = dispIdMember - g_dispidFirstRoutine;
  184. if (irtn >= m_script.routines.Next())
  185. return DISP_E_MEMBERNOTFOUND;
  186. if (pDispParams->cArgs > 0)
  187. return DISP_E_BADPARAMCOUNT;
  188. if (pDispParams->cNamedArgs > 0)
  189. return DISP_E_NONAMEDARGS;
  190. if (pVarResult)
  191. {
  192. assert(false);
  193. return E_UNEXPECTED;
  194. }
  195. hr = m_exec.ExecRoutine(irtn, pExcepInfo);
  196. }
  197. else
  198. {
  199. // it's a global variable
  200. Variables::index ivar = dispIdMember - g_dispidFirstGlobal;
  201. if (ivar >= m_script.globals.Next())
  202. return DISP_E_MEMBERNOTFOUND;
  203. if (wFlags & DISPATCH_PROPERTYGET)
  204. {
  205. if (pDispParams->cArgs > 0)
  206. return DISP_E_BADPARAMCOUNT;
  207. if (pDispParams->cNamedArgs > 0)
  208. return DISP_E_NONAMEDARGS;
  209. if (pVarResult)
  210. {
  211. DMS_VariantInit(fReturnValueUsingOleAut, pVarResult);
  212. DMS_VariantCopy(fReturnValueUsingOleAut, pVarResult, &m_exec.GetGlobal(ivar));
  213. }
  214. return S_OK;
  215. }
  216. else
  217. {
  218. if (!(wFlags & (DISPATCH_PROPERTYPUTREF | DISPATCH_PROPERTYPUT)))
  219. return DISP_E_MEMBERNOTFOUND;
  220. bool fPutRef = !!(wFlags & DISPATCH_PROPERTYPUTREF);
  221. assert(fPutRef || wFlags & DISPATCH_PROPERTYPUT);
  222. if (pDispParams->cArgs != 1)
  223. return DISP_E_BADPARAMCOUNT;
  224. if (pDispParams->cNamedArgs != 1)
  225. return DISP_E_BADPARAMCOUNT;
  226. if (*pDispParams->rgdispidNamedArgs != DISPID_PROPERTYPUT)
  227. return DISP_E_PARAMNOTFOUND;
  228. if (pVarResult)
  229. return E_INVALIDARG;
  230. hr = m_exec.SetGlobal(ivar, pDispParams->rgvarg[0], fPutRef, pExcepInfo);
  231. }
  232. }
  233. // If an exception occurred, we need to convert the error strings into our own kind of BSTR.
  234. if (hr == DISP_E_EXCEPTION)
  235. ConvertOleAutExceptionBSTRs(false, fReturnValueUsingOleAut, pExcepInfo);
  236. return hr;
  237. }
  238. //////////////////////////////////////////////////////////////////////
  239. // ITypeInfo
  240. HRESULT STDMETHODCALLTYPE
  241. EngineDispatch::GetTypeAttr(
  242. /* [out] */ TYPEATTR **ppTypeAttr)
  243. {
  244. V_INAME(EngineDispatch::GetTypeAttr);
  245. V_PTR_WRITE(ppTypeAttr, *ppTypeAttr);
  246. *ppTypeAttr = new TYPEATTR;
  247. if (!*ppTypeAttr)
  248. return E_OUTOFMEMORY;
  249. Zero(*ppTypeAttr);
  250. (*ppTypeAttr)->cFuncs = (unsigned short)m_script.routines.Next();
  251. // Count the global variables -- necessary because some are on the global dispatch
  252. // and we don't want to report them.
  253. int cVars = 0;
  254. Variables::index iLastGlobal = m_script.globals.Next();
  255. for (Variables::index iGlobal = g_cBuiltInConstants; iGlobal < iLastGlobal; ++iGlobal)
  256. {
  257. if (m_script.globals[iGlobal].dispid == DISPID_UNKNOWN)
  258. ++cVars;
  259. }
  260. (*ppTypeAttr)->cVars = (unsigned short)cVars;
  261. return S_OK;
  262. }
  263. void STDMETHODCALLTYPE
  264. EngineDispatch::ReleaseTypeAttr(
  265. /* [in] */ TYPEATTR *pTypeAttr)
  266. {
  267. assert(!IsBadReadPtr(pTypeAttr, sizeof(*pTypeAttr)));
  268. delete pTypeAttr;
  269. }
  270. HRESULT STDMETHODCALLTYPE
  271. EngineDispatch::GetFuncDesc(
  272. /* [in] */ UINT index,
  273. /* [out] */ FUNCDESC **ppFuncDesc)
  274. {
  275. V_INAME(EngineDispatch::GetFuncDesc);
  276. V_PTR_WRITE(ppFuncDesc, *ppFuncDesc);
  277. if (index >= m_script.routines.Next())
  278. return E_INVALIDARG;
  279. *ppFuncDesc = new FUNCDESC;
  280. if (!*ppFuncDesc)
  281. return E_OUTOFMEMORY;
  282. Zero(*ppFuncDesc);
  283. (*ppFuncDesc)->funckind = FUNC_DISPATCH;
  284. (*ppFuncDesc)->invkind = INVOKE_FUNC;
  285. (*ppFuncDesc)->cParams = 0;
  286. (*ppFuncDesc)->memid = index + g_dispidFirstRoutine;
  287. return S_OK;
  288. }
  289. void STDMETHODCALLTYPE
  290. EngineDispatch::ReleaseFuncDesc(
  291. /* [in] */ FUNCDESC *pFuncDesc)
  292. {
  293. assert(!IsBadReadPtr(pFuncDesc, sizeof(*pFuncDesc)));
  294. delete pFuncDesc;
  295. }
  296. HRESULT STDMETHODCALLTYPE
  297. EngineDispatch::GetVarDesc(
  298. /* [in] */ UINT index,
  299. /* [out] */ VARDESC **ppVarDesc)
  300. {
  301. V_INAME(EngineDispatch::GetVarDesc);
  302. V_PTR_WRITE(ppVarDesc, *ppVarDesc);
  303. // Count until we find the global (non-dispatch-based) variable at the index position.
  304. UINT cFuncs = 0;
  305. Variables::index iLastGlobal = m_script.globals.Next();
  306. for (Variables::index iGlobal = g_cBuiltInConstants; iGlobal < iLastGlobal; ++iGlobal)
  307. {
  308. if (m_script.globals[iGlobal].dispid == DISPID_UNKNOWN)
  309. {
  310. if (cFuncs == index)
  311. break;
  312. else
  313. ++cFuncs;
  314. }
  315. }
  316. if (cFuncs < index)
  317. {
  318. // there aren't that many variables
  319. return E_INVALIDARG;
  320. }
  321. *ppVarDesc = new VARDESC;
  322. if (!*ppVarDesc)
  323. return E_OUTOFMEMORY;
  324. Zero(*ppVarDesc);
  325. (*ppVarDesc)->varkind = VAR_DISPATCH;
  326. (*ppVarDesc)->memid = iGlobal + g_dispidFirstGlobal;
  327. return S_OK;
  328. }
  329. void STDMETHODCALLTYPE
  330. EngineDispatch::ReleaseVarDesc(
  331. /* [in] */ VARDESC *pVarDesc)
  332. {
  333. assert(!IsBadReadPtr(pVarDesc, sizeof(*pVarDesc)));
  334. delete pVarDesc;
  335. }
  336. HRESULT STDMETHODCALLTYPE
  337. EngineDispatch::GetNames(
  338. /* [in] */ MEMBERID memid,
  339. /* [length_is][size_is][out] */ BSTR *rgBstrNames,
  340. /* [in] */ UINT cMaxNames,
  341. /* [out] */ UINT *pcNames)
  342. {
  343. V_INAME(EngineDispatch::GetNames);
  344. if (memid < g_dispidFirstRoutine)
  345. return E_INVALIDARG;
  346. V_PTR_WRITE(rgBstrNames, *rgBstrNames);
  347. if (cMaxNames != 1)
  348. return E_INVALIDARG;
  349. V_PTR_WRITE(pcNames, *pcNames);
  350. assert(g_dispidFirstRoutine < g_dispidFirstGlobal);
  351. Strings::index iStr = 0;
  352. if (memid < g_dispidFirstGlobal)
  353. {
  354. const int iSlot = memid - g_dispidFirstRoutine;
  355. if (iSlot >= m_script.routines.Next())
  356. return E_INVALIDARG;
  357. iStr = m_script.routines[iSlot].istrIdentifier;
  358. }
  359. else
  360. {
  361. const int iSlot = memid - g_dispidFirstGlobal;
  362. if (iSlot >= m_script.globals.Next())
  363. return E_INVALIDARG;
  364. iStr = m_script.globals[iSlot].istrIdentifier;
  365. }
  366. SmartRef::WString wstrName = m_script.strings[iStr];
  367. if (!wstrName)
  368. return E_OUTOFMEMORY;
  369. *rgBstrNames = DMS_SysAllocString(g_fUseOleAut, wstrName);
  370. if (!*rgBstrNames)
  371. return E_OUTOFMEMORY;
  372. *pcNames = 1;
  373. return S_OK;
  374. }