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.

490 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. unsigned int strLen;
  140. // hash should be the same, length should be the same, and strings should compare
  141. // BUGBUG robwell 8May96 These functions are probably verboten.
  142. if (hash != m_hash)
  143. return FALSE;
  144. if (!name)
  145. return !m_name;
  146. WCHAR *c1 = name;
  147. WCHAR *c2 = m_name;
  148. // Travel down both strings until we reach a mismatched character
  149. // or the end of one (or both) of the strings
  150. if (caseSensitive)
  151. while (*c1 && *c2 && *c1++==*c2++);
  152. else
  153. while (*c1 && *c2 && ToUpper(*c1++)==ToUpper(*c2++));
  154. // The strings match if we reached the end of both without a mismatch
  155. return !*c1 && !*c2;
  156. }
  157. ////
  158. //
  159. // DispId information
  160. //
  161. // get the dispatch id
  162. DISPID DispId()
  163. { return m_dispId; }
  164. ////
  165. //
  166. // Get and set the property values
  167. //
  168. HRESULT Get(VARIANT* result)
  169. { return VariantCopy(result, &m_value); }
  170. HRESULT Set(VARIANT* value)
  171. { return VariantCopy(&m_value, value); }
  172. ////
  173. //
  174. // List management
  175. //
  176. CExpandoObjectSlot* Next(CExpandoObjectSlot* base)
  177. { return m_next == -1? NULL: &base[m_next]; }
  178. CExpandoObjectSlot* Insert(CExpandoObjectSlot* base, LONG& prev)
  179. {
  180. m_next = prev;
  181. prev = (LONG)(this - base);
  182. return this;
  183. }
  184. private:
  185. // the DispId
  186. DISPID m_dispId;
  187. // the name
  188. LPOLESTR m_name;
  189. // the name hash
  190. ULONG m_hash;
  191. // the property value
  192. VARIANT m_value;
  193. // the hash bucket link (index based)
  194. LONG m_next;
  195. };
  196. // NB: CExpandoObject implements a crippled version of aggegation.
  197. // It delegates all IUnknown calls to its controlling IUnknown, and has no
  198. // private IUnknown interface.
  199. // If you want the CExpandoObject to go away, simply call delete on it.
  200. class CExpandoObject: public IDispatchEx
  201. {
  202. public:
  203. ////
  204. //
  205. // Constructor/Destructor
  206. //
  207. CExpandoObject(IUnknown *punkOuter, IDispatch *pdisp, ULONG dispIdBase = EXTENDER_DISPID_BASE + NUM_CORE_DISPIDS)
  208. {
  209. // remember our controlling outer
  210. m_punkOuter = punkOuter;
  211. // remember the IDispatch to try first for IDispatch functionality
  212. m_pdisp = pdisp;
  213. // clear the name hash table
  214. ClearHashTable();
  215. // set the total slots and the table of slots to 0 and empty respectively)
  216. m_totalSlots = 0;
  217. m_slotTableSize = 0;
  218. m_slots = NULL;
  219. m_dispIdBase = dispIdBase;
  220. }
  221. STDMETHODIMP_(ULONG) AddRef()
  222. {
  223. return m_punkOuter->AddRef();
  224. }
  225. STDMETHODIMP_(ULONG)Release()
  226. {
  227. return m_punkOuter->Release();
  228. }
  229. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObjOut)
  230. {
  231. return m_punkOuter->QueryInterface(riid, ppvObjOut);
  232. }
  233. virtual ~CExpandoObject(void)
  234. {
  235. FreeAllSlots();
  236. }
  237. // Copy all of the properties from obj
  238. HRESULT CloneProperties(CExpandoObject& obj);
  239. ////
  240. //
  241. //
  242. // Utility functions
  243. //
  244. // free all slots
  245. void FreeAllSlots();
  246. // IDispatch methods
  247. virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
  248. virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
  249. UINT itinfo,
  250. LCID lcid,
  251. ITypeInfo **pptinfo
  252. );
  253. virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
  254. REFIID riid,
  255. LPOLESTR *prgpsz,
  256. UINT cpsz,
  257. LCID lcid,
  258. DISPID *prgdispID
  259. );
  260. virtual HRESULT STDMETHODCALLTYPE Invoke(
  261. DISPID dispID,
  262. REFIID riid,
  263. LCID lcid,
  264. WORD wFlags,
  265. DISPPARAMS *pdispparams,
  266. VARIANT *pvarRes,
  267. EXCEPINFO *pexcepinfo,
  268. UINT *puArgErr
  269. );
  270. // IDispatchEx methods
  271. // Get dispID for names, with options
  272. virtual HRESULT STDMETHODCALLTYPE GetIDsOfNamesEx(
  273. REFIID riid,
  274. LPOLESTR *prgpsz,
  275. UINT cpsz,
  276. LCID lcid,
  277. DISPID *prgid,
  278. DWORD grfdex
  279. );
  280. // Enumerate dispIDs and their associated "names".
  281. // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  282. // error code if the call fails.
  283. virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
  284. DISPID id,
  285. DISPID *pid,
  286. BSTR *pbstrName
  287. );
  288. private:
  289. ////
  290. //
  291. // Implementation constants
  292. //
  293. enum
  294. {
  295. kSlotHashTableSize = 10,
  296. kInitialSlotTableSize = 4,
  297. kMaxTotalSlots = NUM_EXPANDO_DISPIDS
  298. };
  299. ////
  300. //
  301. // Utility functions
  302. //
  303. //
  304. CExpandoObjectSlot* GetHashTableHead(UINT hashIndex)
  305. {
  306. LONG index;
  307. return (index = m_hashTable[hashIndex]) == -1? NULL: &m_slots[index];
  308. }
  309. // get the ID of from a slot name
  310. HRESULT GetIDOfName(LPOLESTR name, LCID lcid, BOOL caseSensitive, DISPID* id);
  311. // add a slot to the object
  312. HRESULT AddSlot(LPOLESTR name, LCID lcid, BOOL caseSensitive, VARIANT* initialValue, DISPID* id);
  313. // allocate a slot from the slot table
  314. CExpandoObjectSlot* AllocSlot();
  315. // clear the hash table
  316. void ClearHashTable()
  317. {
  318. UINT i;
  319. for (i=0; i<kSlotHashTableSize; ++i)
  320. m_hashTable[i] = -1;
  321. }
  322. ////
  323. //
  324. // Slot operations
  325. //
  326. // DISPIDS start at kInitialDispId so we need to offset them by that amount
  327. // in this code.
  328. //
  329. HRESULT GetSlot(DISPID id, VARIANT* result)
  330. {
  331. if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  332. return DISP_E_MEMBERNOTFOUND;
  333. return m_slots[id-m_dispIdBase].Get(result);
  334. }
  335. HRESULT SetSlot(DISPID id, VARIANT* result)
  336. {
  337. if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  338. return DISP_E_MEMBERNOTFOUND;
  339. return m_slots[id-m_dispIdBase].Set(result);
  340. }
  341. ////
  342. //
  343. // Iteration operations
  344. //
  345. UINT NumDispIds()
  346. { return m_totalSlots; }
  347. DISPID First()
  348. { return m_dispIdBase; }
  349. DISPID Last()
  350. { return m_totalSlots + m_dispIdBase - 1; }
  351. BOOL ValidDispId(DISPID id)
  352. { return id >= First() && id <= Last(); }
  353. HRESULT Next(DISPID key, CExpandoObjectSlot*& slot)
  354. {
  355. // zero restarts the enumerator
  356. if (key == 0)
  357. {
  358. // if there are no slots we are done
  359. if (NumDispIds() == 0)
  360. return S_FALSE;
  361. // return the first slot
  362. slot = &m_slots[0];
  363. return NOERROR;
  364. }
  365. else
  366. if (key == Last())
  367. {
  368. // the key was the last slot so we are done
  369. return S_FALSE;
  370. }
  371. else
  372. if (ValidDispId(key))
  373. {
  374. // return the next slot
  375. slot = &m_slots[key-m_dispIdBase+1];
  376. return NOERROR;
  377. }
  378. else
  379. // the key must be invalid
  380. return E_INVALIDARG;
  381. }
  382. ////
  383. //
  384. // The local state of the object
  385. //
  386. // the objects reference count
  387. ULONG m_ref;
  388. // the base of objectIds
  389. ULONG m_dispIdBase;
  390. // the hash table of slots - for fast GetIDSofNames lookup
  391. LONG m_hashTable[kSlotHashTableSize];
  392. // the number of slots (and the next dispId to allocate)
  393. UINT m_totalSlots;
  394. // the size of the allocated array of slots
  395. UINT m_slotTableSize;
  396. // a pointer to the allocated array of slots
  397. CExpandoObjectSlot* m_slots;
  398. // controlling unknown
  399. IUnknown *m_punkOuter;
  400. // controlling IDispatch
  401. IDispatch *m_pdisp;
  402. };
  403. #endif // __EXTOBJ_H