IAGCRangesImpl.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. #ifndef __IAGCRangesImpl_h__
  2. #define __IAGCRangesImpl_h__
  3. /////////////////////////////////////////////////////////////////////////////
  4. // IAGCRangesImpl.h : Declaration of the IAGCRangesImpl class template.
  5. //
  6. #include <AGC.h>
  7. #include <..\TCLib\RangeSet.h>
  8. #include <..\TCLib\ObjectLock.h>
  9. /////////////////////////////////////////////////////////////////////////////
  10. // Interface Map Macro
  11. //
  12. // Classes derived from IAGCRangesImpl should include this macro in their
  13. // interface maps.
  14. //
  15. #define COM_INTERFACE_ENTRIES_IAGCRangesImpl() \
  16. COM_INTERFACE_ENTRY(IAGCRangesPrivate) \
  17. COM_INTERFACE_ENTRY(IDispatch) \
  18. COM_INTERFACE_ENTRY(ISupportErrorInfo) \
  19. COM_INTERFACE_ENTRY(IPersistStreamInit) \
  20. COM_INTERFACE_ENTRY(IPersistPropertyBag) \
  21. COM_INTERFACE_ENTRY2(IPersistStream, IPersistStreamInit) \
  22. COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) \
  23. COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_IMarshal, m_punkMBV.p, \
  24. CLSID_TCMarshalByValue)
  25. /////////////////////////////////////////////////////////////////////////////
  26. // IAGCRangesImpl
  27. //
  28. template <class T, class RT, class ITF, class RTITF, const GUID* plibid>
  29. class ATL_NO_VTABLE IAGCRangesImpl :
  30. public IDispatchImpl<ITF, &__uuidof(ITF), plibid>,
  31. public IAGCRangesPrivate,
  32. public ISupportErrorInfo,
  33. public IPersistStreamInit,
  34. public IPersistPropertyBag
  35. {
  36. // Types
  37. public:
  38. typedef TCObjectLock<T> XLock;
  39. typedef range<RT> XRange;
  40. typedef rangeset<XRange> XRangeSet;
  41. typedef XRangeSet::iterator XRangeIt;
  42. typedef XRangeSet::reverse_iterator XRangeRevIt;
  43. typedef IDispatchImpl<ITF, &__uuidof(ITF), plibid> IAGCRangesImplBase;
  44. // Construction
  45. public:
  46. IAGCRangesImpl()
  47. {
  48. // Create a range COM object to be reused multiple times
  49. ZSucceeded(T::CreateRange(RT(), RT(), &m_spRange));
  50. m_spPrivate = m_spRange;
  51. assert(NULL != m_spPrivate);
  52. m_spPersist = m_spRange;
  53. if (NULL == m_spPersist)
  54. {
  55. ZSucceeded(m_spRange->QueryInterface(IID_IPersistStreamInit,
  56. (void**)&m_spPersist));
  57. }
  58. }
  59. // Overrides
  60. public:
  61. static HRESULT CreateRange(const RT& value1, const RT& value2,
  62. RTITF** ppRange);
  63. // IAGC<*>Ranges Interface Methods
  64. public:
  65. STDMETHODIMP get_Count(long* pnCount)
  66. {
  67. XLock lock(static_cast<T*>(this));
  68. CLEAROUT(pnCount, static_cast<long>(m_ranges.size()));
  69. return S_OK;
  70. }
  71. STDMETHODIMP get__NewEnum(IUnknown** ppunkEnum)
  72. {
  73. // Create a new CComEnum enumerator object
  74. typedef CComObject<CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
  75. _Copy<VARIANT> > > CEnum;
  76. CEnum* pEnum = new CEnum;
  77. assert(NULL != pEnum);
  78. IUnknownPtr spEnum(pEnum);
  79. // Get the number of items in the collection
  80. XLock lock(static_cast<T*>(this));
  81. long cTotal = m_ranges.size();
  82. // Create a temporary array of variants
  83. std::vector<CComVariant> vecTemp(cTotal);
  84. // Populate the temporary array of variants
  85. long i = 0;
  86. RT value1, value2;
  87. for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
  88. {
  89. value1 = it->lower();
  90. value2 = it->upper();
  91. CComPtr<RTITF> spRange;
  92. RETURN_FAILED(T::CreateRange(value1, value2, &spRange));
  93. vecTemp[i++] = (IDispatch*)spRange;
  94. }
  95. // Initialize enumerator object with the temporary CComVariant vector
  96. RETURN_FAILED(pEnum->Init(vecTemp.begin(), vecTemp.end(), NULL, AtlFlagCopy));
  97. // Copy the new object to the [out] parameter
  98. RETURN_FAILED(spEnum->QueryInterface(IID_IEnumVARIANT, (void**)ppunkEnum));
  99. // Indicate success
  100. return S_OK;
  101. }
  102. STDMETHODIMP get_Item(VARIANT* pvIndex, RTITF** ppRange)
  103. {
  104. // Initialize the [out] parameter
  105. CLEAROUT(ppRange, (RTITF*)NULL);
  106. // Coerce the specified index to a long
  107. CComVariant varIndex;
  108. RETURN_FAILED(VariantChangeType(&varIndex, pvIndex, 0, VT_I4));
  109. long nIndex = V_I4(&varIndex);
  110. XLock lock(static_cast<T*>(this));
  111. // Validate the specified index
  112. if (0 > nIndex || nIndex >= m_ranges.size())
  113. return E_INVALIDARG;
  114. // Loop from beginning or end, depending on which is closest
  115. RT value1, value2;
  116. if (nIndex < (m_ranges.size() / 2))
  117. {
  118. for (XRangeIt it = m_ranges.begin(); nIndex; ++it)
  119. --nIndex;
  120. value1 = it->lower();
  121. value2 = it->upper();
  122. }
  123. else
  124. {
  125. for (XRangeRevIt it = m_ranges.rbegin(); nIndex; ++it)
  126. --nIndex;
  127. value1 = it->lower();
  128. value2 = it->upper();
  129. }
  130. lock.Unlock();
  131. // Allow the most-derived class to create the range COM object
  132. return T::CreateRange(value1, value2, ppRange);
  133. }
  134. STDMETHODIMP put_DisplayString(BSTR bstr)
  135. {
  136. // Initialize the object
  137. RETURN_FAILED(InitNew());
  138. // Do nothing more if string is empty
  139. UINT cch = BSTRLen(bstr);
  140. if (!cch)
  141. return S_OK;
  142. // Create a string collection to help with the parsing
  143. ITCStringsPtr spStrings;
  144. RETURN_FAILED(spStrings.CreateInstance("TCObj.Strings"));
  145. // Add the specified string as a list of delimited items
  146. RETURN_FAILED(spStrings->AddDelimited(CComBSTR(L";"), bstr));
  147. // Iterate through each string of the set
  148. long cItems;
  149. RETURN_FAILED(spStrings->get_Count(&cItems));
  150. for (CComVariant v(0L); V_I4(&v) < cItems; ++V_I4(&v))
  151. {
  152. // Get the next string
  153. CComBSTR bstrItem;
  154. RETURN_FAILED(spStrings->get_Item(&v, &bstrItem));
  155. // Load the string into the helper range object
  156. RETURN_FAILED(m_spRange->put_DisplayString(bstrItem));
  157. // Insert the range into the set
  158. XRangeSet::key_type range;
  159. RETURN_FAILED(m_spPrivate->CopyRangeTo(&range));
  160. m_ranges.insert(range);
  161. }
  162. // Indicate success
  163. return S_OK;
  164. }
  165. STDMETHODIMP get_DisplayString(BSTR* pbstr)
  166. {
  167. // Create a string collection to help with the parsing
  168. ITCStringsPtr spStrings;
  169. RETURN_FAILED(spStrings.CreateInstance("TCObj.Strings"));
  170. // Create a persistent string for each item in the set
  171. XLock lock(static_cast<T*>(this));
  172. for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
  173. {
  174. RETURN_FAILED(m_spPrivate->InitFromRange(&(*it)));
  175. CComBSTR bstrItem;
  176. RETURN_FAILED(m_spRange->get_DisplayString(&bstrItem));
  177. if (bstrItem.Length())
  178. spStrings->Add(bstrItem);
  179. }
  180. // Create a string delimited by semi-colons (;)
  181. return spStrings->get_DelimitedItems(CComBSTR(L";"), pbstr);
  182. }
  183. STDMETHODIMP AddByValues(RT value1, RT value2)
  184. {
  185. XLock lock(static_cast<T*>(this));
  186. m_ranges.insert(value1, value2);
  187. return S_OK;
  188. }
  189. STDMETHODIMP Add(RTITF* pRange)
  190. {
  191. RT value1, value2;
  192. RETURN_FAILED(pRange->get_Lower(&value1));
  193. RETURN_FAILED(pRange->get_Upper(&value2));
  194. return AddByValues(value1, value2);
  195. }
  196. STDMETHODIMP RemoveByValues(RT value1, RT value2)
  197. {
  198. XLock lock(static_cast<T*>(this));
  199. m_ranges.erase(value1, value2);
  200. return S_OK;
  201. }
  202. STDMETHODIMP Remove(RTITF* pRange)
  203. {
  204. RT value1, value2;
  205. RETURN_FAILED(pRange->get_Lower(&value1));
  206. RETURN_FAILED(pRange->get_Upper(&value2));
  207. return RemoveByValues(value1, value2);
  208. }
  209. STDMETHODIMP RemoveAll()
  210. {
  211. XLock lock(static_cast<T*>(this));
  212. m_ranges.clear();
  213. return S_OK;
  214. }
  215. STDMETHODIMP get_IntersectsWithValue(RT value,
  216. VARIANT_BOOL* pbIntersects)
  217. {
  218. XLock lock(static_cast<T*>(this));
  219. bool bIntr = m_ranges.find(make_range(value, value)) != m_ranges.end();
  220. CLEAROUT(pbIntersects, VARBOOL(bIntr));
  221. return S_OK;
  222. }
  223. STDMETHODIMP get_IntersectsWithRangeValues(RT value1, RT value2,
  224. VARIANT_BOOL* pbIntersects)
  225. {
  226. XLock lock(static_cast<T*>(this));
  227. bool bIntr = m_ranges.find(make_range(value1, value2)) != m_ranges.end();
  228. CLEAROUT(pbIntersects, VARBOOL(bIntr));
  229. return S_OK;
  230. }
  231. STDMETHODIMP get_IntersectsWithRange(RTITF* pRange,
  232. VARIANT_BOOL* pbIntersects)
  233. {
  234. RT value1, value2;
  235. RETURN_FAILED(pRange->get_Lower(&value1));
  236. RETURN_FAILED(pRange->get_Upper(&value2));
  237. return get_IntersectsWithRangeValues(value1, value2, pbIntersects);
  238. }
  239. // IAGCRangesPrivate Interface Methods
  240. public:
  241. STDMETHODIMP InitFromRanges(const void* pvRanges)
  242. {
  243. const XRangeSet* pRanges = reinterpret_cast<const XRangeSet*>(pvRanges);
  244. XLock lock(static_cast<T*>(this));
  245. if (pRanges)
  246. m_ranges = *pRanges;
  247. else
  248. m_ranges.clear();
  249. return S_OK;
  250. }
  251. STDMETHODIMP CopyRangesTo(void* pvRanges)
  252. {
  253. XRangeSet* pRanges = reinterpret_cast<XRangeSet*>(pvRanges);
  254. XLock lock(static_cast<T*>(this));
  255. *pRanges = m_ranges;
  256. return S_OK;
  257. }
  258. // ISupportErrorInfo Interface Methods
  259. public:
  260. STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
  261. {
  262. static const IID* arr[] =
  263. {
  264. &__uuidof(ITF),
  265. };
  266. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  267. {
  268. if (InlineIsEqualGUID(*arr[i],riid))
  269. return S_OK;
  270. }
  271. return S_FALSE;
  272. }
  273. // IPersist Interface Methods
  274. public:
  275. STDMETHODIMP GetClassID(CLSID* pClassID)
  276. {
  277. __try
  278. {
  279. *pClassID = T::GetObjectCLSID();
  280. }
  281. __except(1)
  282. {
  283. return E_POINTER;
  284. }
  285. return S_OK;
  286. }
  287. // IPersistStreamInit Interface Methods
  288. public:
  289. STDMETHODIMP IsDirty()
  290. {
  291. // We don't maintain a dirty flag
  292. return S_OK;
  293. }
  294. STDMETHODIMP Load(LPSTREAM pStm)
  295. {
  296. // Read the number of range items to follow
  297. DWORD cItems;
  298. RETURN_FAILED(pStm->Read(&cItems, sizeof(cItems), NULL));
  299. // Clear the set
  300. XLock lock(static_cast<T*>(this));
  301. m_ranges.clear();
  302. // Read each range item
  303. assert(NULL != m_spPrivate);
  304. assert(NULL != m_spPersist);
  305. for (DWORD i = 0; i < cItems; ++i)
  306. {
  307. RETURN_FAILED(m_spPersist->Load(pStm));
  308. XRangeSet::key_type range;
  309. RETURN_FAILED(m_spPrivate->CopyRangeTo(&range));
  310. m_ranges.insert(range);
  311. }
  312. // Indicate success
  313. return S_OK;
  314. }
  315. STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty)
  316. {
  317. UNUSED_ALWAYS(fClearDirty);
  318. // Write out the number of range items to follow
  319. XLock lock(static_cast<T*>(this));
  320. DWORD cItems = m_ranges.size();
  321. RETURN_FAILED(pStm->Write(&cItems, sizeof(cItems), NULL));
  322. // Write each range to the stream
  323. assert(NULL != m_spPrivate);
  324. assert(NULL != m_spPersist);
  325. for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
  326. {
  327. RETURN_FAILED(m_spPrivate->InitFromRange(&(*it)));
  328. RETURN_FAILED(m_spPersist->Save(pStm, fClearDirty));
  329. }
  330. // Indicate success
  331. return S_OK;
  332. }
  333. STDMETHODIMP GetSizeMax(ULARGE_INTEGER* pCbSize)
  334. {
  335. XLock lock(static_cast<T*>(this));
  336. ULARGE_INTEGER uli;
  337. assert(NULL != m_spPersist);
  338. RETURN_FAILED(m_spPersist->GetSizeMax(&uli));
  339. pCbSize->HighPart = 0;
  340. pCbSize->LowPart = sizeof(DWORD) + m_ranges.size() * uli.LowPart;
  341. return S_OK;
  342. }
  343. STDMETHODIMP InitNew()
  344. {
  345. XLock lock(static_cast<T*>(this));
  346. m_ranges.clear();
  347. return S_OK;
  348. }
  349. // IPersistPropertyBag Interface Methods
  350. public:
  351. STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog)
  352. {
  353. // Load the persistent string value of the range set
  354. CComVariant var(BSTR(NULL));
  355. RETURN_FAILED(pPropBag->Read(L"Value", &var, pErrorLog));
  356. // Load the string into the object
  357. return put_DisplayString(V_BSTR(&var));
  358. }
  359. STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty,
  360. BOOL fSaveAllProperties)
  361. {
  362. UNUSED_ALWAYS(fClearDirty);
  363. UNUSED_ALWAYS(fSaveAllProperties);
  364. // Create a display string of the items in the set
  365. CComBSTR bstr;
  366. RETURN_FAILED(get_DisplayString(&bstr));
  367. // Save the persistent string value of the range set
  368. return pPropBag->Write(L"Value", &CComVariant(bstr));
  369. }
  370. // Data Members
  371. protected:
  372. XRangeSet m_ranges;
  373. CComPtr<RTITF> m_spRange;
  374. IAGCRangePrivatePtr m_spPrivate;
  375. IPersistStreamPtr m_spPersist;
  376. // Data Members
  377. public:
  378. CComPtr<IUnknown> m_punkMBV;
  379. };
  380. /////////////////////////////////////////////////////////////////////////////
  381. #endif //__IAGCRangesImpl_h__