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.

489 lines
9.7 KiB

  1. #ifndef __EXTOBJ_H
  2. #define __EXTOBJ_H
  3. ////
  4. //
  5. // ExpandoObject header file
  6. //
  7. //
  8. //
  9. #include "IPServer.H"
  10. ////
  11. //
  12. // IDispatchEx
  13. //
  14. ////
  15. ////
  16. //
  17. // the GUID
  18. //
  19. // {A0AAC450-A77B-11cf-91D0-00AA00C14A7C}
  20. DEFINE_GUID(IID_IDispatchEx, 0xa0aac450, 0xa77b, 0x11cf, 0x91, 0xd0, 0x0, 0xaa, 0x0, 0xc1, 0x4a, 0x7c);
  21. ////
  22. //
  23. // IDispatchEx flags:
  24. //
  25. enum
  26. {
  27. fdexNil = 0x00, // empty
  28. fdexDontCreate = 0x01, // don't create slot if non-existant otherwise do
  29. fdexInitNull = 0x02, // init a new slot to VT_NULL as opposed to VT_EMPTY
  30. fdexCaseSensitive = 0x04, // match names as case sensitive
  31. };
  32. ////
  33. //
  34. // This is the interface for extensible IDispatch objects.
  35. //
  36. class IDispatchEx : public IDispatch
  37. {
  38. public:
  39. // Get dispID for names, with options
  40. virtual HRESULT STDMETHODCALLTYPE GetIDsOfNamesEx(
  41. REFIID riid,
  42. LPOLESTR *prgpsz,
  43. UINT cpsz,
  44. LCID lcid,
  45. DISPID *prgid,
  46. DWORD grfdex
  47. ) = 0;
  48. // Enumerate dispIDs and their associated "names".
  49. // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  50. // error code if the call fails.
  51. virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
  52. DISPID id,
  53. DISPID *pid,
  54. BSTR *pbstrName
  55. ) = 0;
  56. };
  57. ////
  58. //
  59. // Globals and definitions
  60. //
  61. ////
  62. #define NUM_EXPANDO_DISPIDS 250
  63. #define NUM_CORE_DISPIDS 250
  64. #define NUM_RESERVED_EXTENDER_DISPIDS (NUM_CORE_DISPIDS + NUM_EXPANDO_DISPIDS)
  65. #define EXTENDER_DISPID_BASE ((ULONG)(0x80010000))
  66. #define IS_EXTENDER_DISPID(x) ( ( (ULONG)(x) & 0xFFFF0000 ) == EXTENDER_DISPID_BASE )
  67. ////
  68. //
  69. // Slot: the state of a value slot
  70. //
  71. inline WCHAR ToUpper(WCHAR ch)
  72. {
  73. if (ch>='a' && ch <= 'z')
  74. return ch - 'a' + 'A';
  75. else
  76. return ch;
  77. }
  78. class CExpandoObjectSlot
  79. {
  80. public:
  81. ////
  82. //
  83. // Constructor/Destructor
  84. //
  85. // because these monsters are malloc'ed, we need a manual constructor and destructor methods
  86. void Construct()
  87. {
  88. m_name = NULL;
  89. m_next = -1;
  90. VariantInit(&m_value);
  91. // set hash and dispId to dummy values
  92. m_hash = 0;
  93. m_dispId = DISPID_UNKNOWN;
  94. }
  95. void Destruct()
  96. {
  97. if (m_name)
  98. SysFreeString(m_name);
  99. VariantClear(&m_value);
  100. }
  101. private:
  102. // the constructors and destructors are private because they should never be called ...
  103. // we could use in-place construction if we wanted to be clever ...
  104. CExpandoObjectSlot()
  105. {
  106. }
  107. ~CExpandoObjectSlot()
  108. {
  109. }
  110. public:
  111. ////
  112. //
  113. // Init the slot
  114. //
  115. HRESULT Init(LPOLESTR name, LCID lcid, DISPID dispId, VARIANT* value)
  116. {
  117. // allocate the string
  118. m_name = SysAllocString(name);
  119. if (m_name == NULL)
  120. return E_OUTOFMEMORY;
  121. // compute the hash: uses the standard OLE string hashing function
  122. // note that this function is case insensitive
  123. m_hash = LHashValOfName(lcid, name);
  124. // set the dispId
  125. m_dispId = dispId;
  126. // Copy the variant value
  127. return VariantCopy(&m_value, value);
  128. }
  129. ////
  130. //
  131. // Name information
  132. //
  133. // get the name
  134. BSTR Name()
  135. { return m_name; }
  136. // compare two names
  137. BOOL CompareName(LPOLESTR name, ULONG hash, BOOL caseSensitive)
  138. {
  139. // hash should be the same, length should be the same, and strings should compare
  140. // BUGBUG robwell 8May96 These functions are probably verboten.
  141. if (hash != m_hash)
  142. return FALSE;
  143. if (!name)
  144. return !m_name;
  145. WCHAR *c1 = name;
  146. WCHAR *c2 = m_name;
  147. // Travel down both strings until we reach a mismatched character
  148. // or the end of one (or both) of the strings
  149. if (caseSensitive)
  150. while (*c1 && *c2 && *c1++==*c2++);
  151. else
  152. while (*c1 && *c2 && ToUpper(*c1++)==ToUpper(*c2++));
  153. // The strings match if we reached the end of both without a mismatch
  154. return !*c1 && !*c2;
  155. }
  156. ////
  157. //
  158. // DispId information
  159. //
  160. // get the dispatch id
  161. DISPID DispId()
  162. { return m_dispId; }
  163. ////
  164. //
  165. // Get and set the property values
  166. //
  167. HRESULT Get(VARIANT* result)
  168. { return VariantCopy(result, &m_value); }
  169. HRESULT Set(VARIANT* value)
  170. { return VariantCopy(&m_value, value); }
  171. ////
  172. //
  173. // List management
  174. //
  175. CExpandoObjectSlot* Next(CExpandoObjectSlot* base)
  176. { return m_next == -1? NULL: &base[m_next]; }
  177. CExpandoObjectSlot* Insert(CExpandoObjectSlot* base, LONG& prev)
  178. {
  179. m_next = prev;
  180. prev = (LONG)(this - base);
  181. return this;
  182. }
  183. private:
  184. // the DispId
  185. DISPID m_dispId;
  186. // the name
  187. LPOLESTR m_name;
  188. // the name hash
  189. ULONG m_hash;
  190. // the property value
  191. VARIANT m_value;
  192. // the hash bucket link (index based)
  193. LONG m_next;
  194. };
  195. // NB: CExpandoObject implements a crippled version of aggegation.
  196. // It delegates all IUnknown calls to its controlling IUnknown, and has no
  197. // private IUnknown interface.
  198. // If you want the CExpandoObject to go away, simply call delete on it.
  199. class CExpandoObject: public IDispatchEx
  200. {
  201. public:
  202. ////
  203. //
  204. // Constructor/Destructor
  205. //
  206. CExpandoObject(IUnknown *punkOuter, IDispatch *pdisp, ULONG dispIdBase = EXTENDER_DISPID_BASE + NUM_CORE_DISPIDS)
  207. {
  208. // remember our controlling outer
  209. m_punkOuter = punkOuter;
  210. // remember the IDispatch to try first for IDispatch functionality
  211. m_pdisp = pdisp;
  212. // clear the name hash table
  213. ClearHashTable();
  214. // set the total slots and the table of slots to 0 and empty respectively)
  215. m_totalSlots = 0;
  216. m_slotTableSize = 0;
  217. m_slots = NULL;
  218. m_dispIdBase = dispIdBase;
  219. }
  220. STDMETHODIMP_(ULONG) AddRef()
  221. {
  222. return m_punkOuter->AddRef();
  223. }
  224. STDMETHODIMP_(ULONG)Release()
  225. {
  226. return m_punkOuter->Release();
  227. }
  228. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObjOut)
  229. {
  230. return m_punkOuter->QueryInterface(riid, ppvObjOut);
  231. }
  232. virtual ~CExpandoObject(void)
  233. {
  234. FreeAllSlots();
  235. }
  236. // Copy all of the properties from obj
  237. HRESULT CloneProperties(CExpandoObject& obj);
  238. ////
  239. //
  240. //
  241. // Utility functions
  242. //
  243. // free all slots
  244. void FreeAllSlots();
  245. // IDispatch methods
  246. virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
  247. virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
  248. UINT itinfo,
  249. LCID lcid,
  250. ITypeInfo **pptinfo
  251. );
  252. virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
  253. REFIID riid,
  254. LPOLESTR *prgpsz,
  255. UINT cpsz,
  256. LCID lcid,
  257. DISPID *prgdispID
  258. );
  259. virtual HRESULT STDMETHODCALLTYPE Invoke(
  260. DISPID dispID,
  261. REFIID riid,
  262. LCID lcid,
  263. WORD wFlags,
  264. DISPPARAMS *pdispparams,
  265. VARIANT *pvarRes,
  266. EXCEPINFO *pexcepinfo,
  267. UINT *puArgErr
  268. );
  269. // IDispatchEx methods
  270. // Get dispID for names, with options
  271. virtual HRESULT STDMETHODCALLTYPE GetIDsOfNamesEx(
  272. REFIID riid,
  273. LPOLESTR *prgpsz,
  274. UINT cpsz,
  275. LCID lcid,
  276. DISPID *prgid,
  277. DWORD grfdex
  278. );
  279. // Enumerate dispIDs and their associated "names".
  280. // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  281. // error code if the call fails.
  282. virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
  283. DISPID id,
  284. DISPID *pid,
  285. BSTR *pbstrName
  286. );
  287. private:
  288. ////
  289. //
  290. // Implementation constants
  291. //
  292. enum
  293. {
  294. kSlotHashTableSize = 10,
  295. kInitialSlotTableSize = 4,
  296. kMaxTotalSlots = NUM_EXPANDO_DISPIDS
  297. };
  298. ////
  299. //
  300. // Utility functions
  301. //
  302. //
  303. CExpandoObjectSlot* GetHashTableHead(UINT hashIndex)
  304. {
  305. LONG index;
  306. return (index = m_hashTable[hashIndex]) == -1? NULL: &m_slots[index];
  307. }
  308. // get the ID of from a slot name
  309. HRESULT GetIDOfName(LPOLESTR name, LCID lcid, BOOL caseSensitive, DISPID* id);
  310. // add a slot to the object
  311. HRESULT AddSlot(LPOLESTR name, LCID lcid, BOOL caseSensitive, VARIANT* initialValue, DISPID* id);
  312. // allocate a slot from the slot table
  313. CExpandoObjectSlot* AllocSlot();
  314. // clear the hash table
  315. void ClearHashTable()
  316. {
  317. UINT i;
  318. for (i=0; i<kSlotHashTableSize; ++i)
  319. m_hashTable[i] = -1;
  320. }
  321. ////
  322. //
  323. // Slot operations
  324. //
  325. // DISPIDS start at kInitialDispId so we need to offset them by that amount
  326. // in this code.
  327. //
  328. HRESULT GetSlot(DISPID id, VARIANT* result)
  329. {
  330. if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  331. return DISP_E_MEMBERNOTFOUND;
  332. return m_slots[id-m_dispIdBase].Get(result);
  333. }
  334. HRESULT SetSlot(DISPID id, VARIANT* result)
  335. {
  336. if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  337. return DISP_E_MEMBERNOTFOUND;
  338. return m_slots[id-m_dispIdBase].Set(result);
  339. }
  340. ////
  341. //
  342. // Iteration operations
  343. //
  344. UINT NumDispIds()
  345. { return m_totalSlots; }
  346. DISPID First()
  347. { return m_dispIdBase; }
  348. DISPID Last()
  349. { return m_totalSlots + m_dispIdBase - 1; }
  350. BOOL ValidDispId(DISPID id)
  351. { return id >= First() && id <= Last(); }
  352. HRESULT Next(DISPID key, CExpandoObjectSlot*& slot)
  353. {
  354. // zero restarts the enumerator
  355. if (key == 0)
  356. {
  357. // if there are no slots we are done
  358. if (NumDispIds() == 0)
  359. return S_FALSE;
  360. // return the first slot
  361. slot = &m_slots[0];
  362. return NOERROR;
  363. }
  364. else
  365. if (key == Last())
  366. {
  367. // the key was the last slot so we are done
  368. return S_FALSE;
  369. }
  370. else
  371. if (ValidDispId(key))
  372. {
  373. // return the next slot
  374. slot = &m_slots[key-m_dispIdBase+1];
  375. return NOERROR;
  376. }
  377. else
  378. // the key must be invalid
  379. return E_INVALIDARG;
  380. }
  381. ////
  382. //
  383. // The local state of the object
  384. //
  385. // the objects reference count
  386. ULONG m_ref;
  387. // the base of objectIds
  388. ULONG m_dispIdBase;
  389. // the hash table of slots - for fast GetIDSofNames lookup
  390. LONG m_hashTable[kSlotHashTableSize];
  391. // the number of slots (and the next dispId to allocate)
  392. UINT m_totalSlots;
  393. // the size of the allocated array of slots
  394. UINT m_slotTableSize;
  395. // a pointer to the allocated array of slots
  396. CExpandoObjectSlot* m_slots;
  397. // controlling unknown
  398. IUnknown *m_punkOuter;
  399. // controlling IDispatch
  400. IDispatch *m_pdisp;
  401. };
  402. #endif // __EXTOBJ_H