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.

501 lines
10 KiB

  1. ////
  2. //
  3. // CExpandoObject
  4. //
  5. // Notes:
  6. // 1) If the LCID passed to this object changes from call to call we are in trouble. This is hard to
  7. // create an ASSERT for because it would require memoizing the LCID at some point.
  8. // 2) There is a maximum on the number of slots allowed (this is currently 2048)
  9. // 3) This is not a thread safe structure.
  10. // 4) I'm currently using malloc -- this is probably wrong for IE.
  11. //
  12. // for ASSERT and FAIL
  13. //
  14. #include "IPServer.H"
  15. #include "LocalSrv.H"
  16. #include "Globals.H"
  17. #include "extobj.h"
  18. #include "Util.H"
  19. #define GTR_MALLOC(size) CoTaskMemAlloc(size)
  20. #define GTR_FREE(pv) CoTaskMemFree(pv)
  21. SZTHISFILE
  22. ////
  23. //
  24. // Private Utility Functions
  25. //
  26. ////
  27. ////
  28. //
  29. // Get the ID of a Name
  30. //
  31. HRESULT CExpandoObject::GetIDOfName(LPOLESTR name, LCID lcid, BOOL caseSensitive, DISPID* id)
  32. {
  33. HRESULT hr = NOERROR;
  34. ULONG hash = LHashValOfName(lcid, name);
  35. UINT hashIndex = hash % kSlotHashTableSize;
  36. CExpandoObjectSlot* slot;
  37. for (slot=GetHashTableHead(hashIndex); slot!=NULL; slot=slot->Next(m_slots))
  38. {
  39. if (slot->CompareName(name, hash, caseSensitive))
  40. {
  41. *id = slot->DispId();
  42. goto Exit;
  43. }
  44. }
  45. // not found
  46. hr = DISP_E_UNKNOWNNAME;
  47. *id = DISPID_UNKNOWN;
  48. Exit:
  49. return hr;
  50. }
  51. ////
  52. //
  53. // Add a new slot to the object
  54. //
  55. HRESULT CExpandoObject::AddSlot(LPOLESTR name, LCID lcid, BOOL caseSensitive, VARIANT* initialValue, DISPID* id)
  56. {
  57. HRESULT hr = NOERROR;
  58. ULONG hash = LHashValOfName(lcid, name);
  59. UINT hashIndex = hash % kSlotHashTableSize;
  60. CExpandoObjectSlot* slot;
  61. DISPID dispId;
  62. // first check if the slot exists
  63. for (slot=GetHashTableHead(hashIndex); slot!=NULL; slot=slot->Next(m_slots))
  64. {
  65. // bail if the name matches
  66. if (slot->CompareName(name, hash, caseSensitive))
  67. {
  68. hr = E_INVALIDARG;
  69. goto Exit;
  70. }
  71. }
  72. // allocate a slot
  73. dispId = (DISPID) m_totalSlots;
  74. slot = AllocSlot();
  75. if (slot == NULL)
  76. {
  77. hr = E_OUTOFMEMORY;
  78. goto Exit;
  79. }
  80. // Initialize it
  81. // BUGBUG robwell 8May96 If this fails and the initialValue is not VT_EMTPY or VT_NULL
  82. // there in no cleanup code.
  83. hr = slot->Init(name, lcid, dispId + m_dispIdBase, initialValue);
  84. if (FAILED(hr))
  85. {
  86. // free the slot and dispId
  87. m_totalSlots -= 1;
  88. goto Exit;
  89. }
  90. // intern the slot into the proper hash table
  91. slot->Insert(m_slots, m_hashTable[hashIndex]);
  92. // set the DISPID return value
  93. *id = slot->DispId();
  94. Exit:
  95. return hr;
  96. }
  97. ////
  98. //
  99. // Slot allocation
  100. //
  101. // Because slots are never freed there is no free method
  102. //
  103. CExpandoObjectSlot* CExpandoObject::AllocSlot()
  104. {
  105. // limit on the number of slots
  106. if (m_totalSlots >= kMaxTotalSlots)
  107. return NULL;
  108. // do we need to realloc the array?
  109. if (m_totalSlots == m_slotTableSize)
  110. {
  111. UINT i;
  112. UINT newSize;
  113. CExpandoObjectSlot* newSlots;
  114. // allocate twice as many slots unless first time around
  115. if (m_slotTableSize == 0)
  116. newSize = kInitialSlotTableSize;
  117. else
  118. newSize = m_slotTableSize * 2;
  119. // allocate the space for the slots
  120. newSlots = (CExpandoObjectSlot*) GTR_MALLOC(sizeof(CExpandoObjectSlot)*newSize);
  121. if (newSlots == NULL)
  122. return NULL;
  123. // copy the old values if the old m_slots is not NULL
  124. if (m_slots)
  125. {
  126. // copy the slots
  127. memcpy(newSlots, m_slots, sizeof(CExpandoObjectSlot)*m_totalSlots);
  128. // free the old values
  129. GTR_FREE(m_slots);
  130. }
  131. // construct all of the unused slots
  132. for (i=m_totalSlots; i<newSize; ++i)
  133. newSlots[i].Construct();
  134. // make the new array the new table and fix the total size
  135. m_slots = newSlots;
  136. m_slotTableSize = newSize;
  137. }
  138. // return a pointer to the slot and bump the totalSlots count
  139. return &m_slots[m_totalSlots++];
  140. }
  141. ////
  142. //
  143. // Free all of the slots
  144. //
  145. void CExpandoObject::FreeAllSlots()
  146. {
  147. UINT i;
  148. UINT initedSlotCount;
  149. CExpandoObjectSlot* slots;
  150. // first clear the hash table
  151. ClearHashTable();
  152. // detach the slots
  153. slots = m_slots;
  154. initedSlotCount = m_totalSlots;
  155. // clear the object info
  156. m_totalSlots = 0;
  157. m_slotTableSize = 0;
  158. m_slots = NULL;
  159. // only need to destruct those slots in use
  160. for (i=0; i<initedSlotCount; ++i)
  161. slots[i].Destruct();
  162. // free the storage
  163. if (slots)
  164. GTR_FREE(slots);
  165. }
  166. ////
  167. //
  168. // IDispatch Methods
  169. //
  170. ////
  171. HRESULT CExpandoObject::GetTypeInfoCount(UINT *pctinfo)
  172. {
  173. *pctinfo = 0;
  174. return NOERROR;
  175. }
  176. HRESULT CExpandoObject::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  177. {
  178. *pptinfo = NULL;
  179. return E_NOTIMPL;
  180. }
  181. HRESULT CExpandoObject::GetIDsOfNames(
  182. REFIID riid,
  183. LPOLESTR *prgpsz,
  184. UINT cpsz,
  185. LCID lcid,
  186. DISPID *prgdispid
  187. )
  188. {
  189. HRESULT hr;
  190. if (IID_NULL != riid)
  191. return DISP_E_UNKNOWNINTERFACE;
  192. // First see if the outer object knows about the name
  193. if (m_pdisp)
  194. {
  195. hr = m_pdisp->GetIDsOfNames(
  196. riid,
  197. prgpsz,
  198. cpsz,
  199. lcid,
  200. prgdispid);
  201. // if so, just return
  202. if (SUCCEEDED(hr))
  203. return hr;
  204. }
  205. // Otherwise look on our expanded properties
  206. if (cpsz == 0)
  207. return NOERROR;
  208. // get the ids for the name
  209. hr = GetIDOfName(prgpsz[0], lcid, FALSE, &prgdispid[0]);
  210. // clear the rest of the array
  211. for (unsigned int i = 1; i < cpsz; i++)
  212. {
  213. if (SUCCEEDED(hr))
  214. hr = DISP_E_UNKNOWNNAME;
  215. prgdispid[i] = DISPID_UNKNOWN;
  216. }
  217. return hr;
  218. }
  219. HRESULT CExpandoObject::Invoke(
  220. DISPID dispID,
  221. REFIID riid,
  222. LCID lcid,
  223. WORD wFlags,
  224. DISPPARAMS *pdispparams,
  225. VARIANT *pvarRes,
  226. EXCEPINFO *pexcepinfo,
  227. UINT *puArgErr
  228. )
  229. {
  230. if (IID_NULL != riid)
  231. return DISP_E_UNKNOWNINTERFACE;
  232. HRESULT hr;
  233. // First try the outer object's invoke
  234. if (m_pdisp)
  235. {
  236. hr = m_pdisp->Invoke(
  237. dispID,
  238. riid,
  239. lcid,
  240. wFlags,
  241. pdispparams,
  242. pvarRes,
  243. pexcepinfo,
  244. puArgErr
  245. );
  246. // If that succeeded, we're done
  247. if (SUCCEEDED(hr))
  248. return hr;
  249. }
  250. // Otherwise, try the expando object's invoke
  251. if (NULL != puArgErr)
  252. *puArgErr = 0;
  253. if (wFlags & DISPATCH_PROPERTYGET)
  254. {
  255. if (NULL == pvarRes)
  256. return NOERROR;
  257. if (NULL != pdispparams && 0 != pdispparams->cArgs)
  258. return E_INVALIDARG;
  259. // clear the result slot
  260. pvarRes->vt = VT_EMPTY;
  261. return GetSlot(dispID, pvarRes);
  262. }
  263. if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
  264. {
  265. if (NULL == pdispparams
  266. || 1 != pdispparams->cArgs
  267. || 1 != pdispparams->cNamedArgs
  268. || DISPID_PROPERTYPUT != pdispparams->rgdispidNamedArgs[0]
  269. )
  270. return DISP_E_PARAMNOTOPTIONAL;
  271. return SetSlot(dispID, &pdispparams->rgvarg[0]);
  272. }
  273. return DISP_E_MEMBERNOTFOUND;
  274. }
  275. ////
  276. //
  277. // IDispatchEx methods
  278. //
  279. ////
  280. // Get dispID for names, with options
  281. HRESULT STDMETHODCALLTYPE CExpandoObject::GetIDsOfNamesEx(
  282. REFIID riid,
  283. LPOLESTR *prgpsz,
  284. UINT cpsz,
  285. LCID lcid,
  286. DISPID *prgid,
  287. DWORD grfdex
  288. )
  289. {
  290. HRESULT hr;
  291. BOOL caseSensitive = ((grfdex & fdexCaseSensitive) != 0);
  292. // First see if the outer object knows about the name
  293. if (m_pdisp)
  294. {
  295. hr = m_pdisp->GetIDsOfNames(
  296. riid,
  297. prgpsz,
  298. cpsz,
  299. lcid,
  300. prgid);
  301. // if so, just return
  302. if (SUCCEEDED(hr))
  303. return hr;
  304. }
  305. if (IID_NULL != riid)
  306. return DISP_E_UNKNOWNINTERFACE;
  307. if (cpsz == 0)
  308. return NOERROR;
  309. // check the array arguments
  310. if (prgpsz == NULL || prgid == NULL)
  311. return E_INVALIDARG;
  312. // get the id from the name
  313. hr = GetIDOfName(prgpsz[0], lcid, caseSensitive, &prgid[0]);
  314. // create the slot?
  315. if (hr == DISP_E_UNKNOWNNAME && (grfdex & fdexDontCreate) == 0)
  316. {
  317. VARIANT initialValue;
  318. if (grfdex & fdexInitNull)
  319. initialValue.vt = VT_NULL;
  320. else
  321. initialValue.vt = VT_EMPTY;
  322. hr = AddSlot(prgpsz[0], lcid, caseSensitive, &initialValue, &prgid[0]);
  323. }
  324. // clear the rest of the array
  325. for (unsigned int i = 1; i < cpsz; i++)
  326. {
  327. hr = DISP_E_UNKNOWNNAME;
  328. prgid[i] = DISPID_UNKNOWN;
  329. }
  330. return hr;
  331. }
  332. // Enumerate dispIDs and their associated "names".
  333. // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  334. // error code if the call fails.
  335. HRESULT STDMETHODCALLTYPE CExpandoObject::GetNextDispID(
  336. DISPID id,
  337. DISPID *pid,
  338. BSTR *pbstrName
  339. )
  340. {
  341. HRESULT hr;
  342. CExpandoObjectSlot* slot;
  343. // check the outgoing parameters
  344. if (pid == NULL || pbstrName == NULL)
  345. return E_INVALIDARG;
  346. // set to the default failure case
  347. *pid = DISPID_UNKNOWN;
  348. *pbstrName = NULL;
  349. // get the next slot
  350. hr = Next(id, slot);
  351. if (hr == NOERROR)
  352. {
  353. BSTR name;
  354. // allocate the result string
  355. name = SysAllocString(slot->Name());
  356. if (name == NULL)
  357. return E_OUTOFMEMORY;
  358. // fill in the outgoing parameters
  359. *pid = slot->DispId();
  360. *pbstrName = name;
  361. }
  362. return hr;
  363. }
  364. // Copy all of the expando-object properties from obj
  365. HRESULT
  366. CExpandoObject::CloneProperties(CExpandoObject& obj)
  367. {
  368. // BUGBUG PhilBo
  369. // The initialization code below is copied from the default constructor.
  370. // This should be factored out into a shared method.
  371. // Copy each of the properties from the original object
  372. HRESULT hr = S_OK;
  373. DISPID dispid = 0;
  374. BSTR bstrName = NULL;
  375. while (obj.GetNextDispID(dispid, &dispid, &bstrName) == S_OK)
  376. {
  377. // Get the value of the property from the original object
  378. VARIANT varResult;
  379. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  380. VariantInit(&varResult);
  381. hr = obj.Invoke(
  382. dispid,
  383. IID_NULL,
  384. LOCALE_SYSTEM_DEFAULT,
  385. DISPATCH_PROPERTYGET,
  386. &dispparamsNoArgs, &varResult, NULL, NULL);
  387. ASSERT(SUCCEEDED(hr), "");
  388. if (FAILED(hr))
  389. continue;
  390. // Set the property on the new object
  391. DISPID dispidNew = 0;
  392. hr = GetIDsOfNamesEx(IID_NULL, &bstrName, 1, LOCALE_SYSTEM_DEFAULT,
  393. &dispidNew, 0);
  394. ASSERT(SUCCEEDED(hr), "");
  395. if (FAILED(hr))
  396. continue;
  397. DISPPARAMS dispparams;
  398. dispparams.rgvarg = &varResult;
  399. DISPID rgdispid[] = {DISPID_PROPERTYPUT};
  400. dispparams.rgdispidNamedArgs = rgdispid;
  401. dispparams.cArgs = 1;
  402. dispparams.cNamedArgs = 1;
  403. hr = Invoke(
  404. dispidNew,
  405. IID_NULL,
  406. LOCALE_SYSTEM_DEFAULT,
  407. DISPATCH_PROPERTYPUT,
  408. &dispparams, NULL, NULL, NULL);
  409. }
  410. return hr;
  411. }