TCStrings.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /////////////////////////////////////////////////////////////////////////////
  2. // TCStrings.cpp | Implementation of the CTCStrings class.
  3. //
  4. #include "pch.h"
  5. #include "TCStrings.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. // CTCStrings
  8. TC_OBJECT_EXTERN_IMPL(CTCStrings)
  9. /////////////////////////////////////////////////////////////////////////////
  10. // Construction / Destruction
  11. CTCStrings::CTCStrings()
  12. {
  13. }
  14. /////////////////////////////////////////////////////////////////////////////
  15. // ITCCollection Interface Methods
  16. STDMETHODIMP CTCStrings::get_Count(long* pnCount)
  17. {
  18. // Lock the object
  19. CLock lock(this);
  20. // Copy the size of the vector to the specified [out] parameter
  21. CLEAROUT(pnCount, (long)m_vecStrings.size());
  22. // Indicate success
  23. return S_OK;
  24. }
  25. STDMETHODIMP CTCStrings::get__NewEnum(IUnknown** ppunkEnum)
  26. {
  27. // Clear the [out] parameter
  28. CLEAROUT(ppunkEnum, (IUnknown*)NULL);
  29. // Create a new CComEnum enumerator object
  30. typedef CComObject<CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
  31. _Copy<VARIANT> > > CEnum;
  32. CEnum* pEnum = new CEnum;
  33. assert(NULL != pEnum);
  34. // Lock the object
  35. CLock lock(this);
  36. // Copy the elements of stored vector to a temporary CComVariant vector
  37. std::vector<CComVariant> vecTemp(m_vecStrings.size(), CComVariant());
  38. for (int i = 0; i < m_vecStrings.size(); ++i)
  39. vecTemp[i] = m_vecStrings[i];
  40. // Initialize enumerator object with the temporary CComVariant vector
  41. HRESULT hr = pEnum->Init(vecTemp.begin(), vecTemp.end(), NULL, AtlFlagCopy);
  42. if (SUCCEEDED(hr))
  43. hr = pEnum->QueryInterface(IID_IEnumVARIANT, (void**)ppunkEnum);
  44. if (FAILED(hr))
  45. delete pEnum;
  46. // Return the last result
  47. return hr;
  48. }
  49. /////////////////////////////////////////////////////////////////////////////
  50. // ITCStrings Interface Methods
  51. STDMETHODIMP CTCStrings::get_Item(VARIANT* pvIndex, BSTR* pbstr)
  52. {
  53. // Initialize the [out] parameter
  54. CLEAROUT(pbstr, (BSTR)NULL);
  55. // Attempt to convert the specified VARIANT to a long
  56. CComVariant var;
  57. HRESULT hr = VariantChangeType(&var, pvIndex, 0, VT_I4);
  58. if (FAILED(hr))
  59. return hr;
  60. // Lock the object
  61. CLock lock(this);
  62. // Ensure that the specified index is in range
  63. if (V_I4(&var) < 0 || V_I4(&var) >= m_vecStrings.size())
  64. return E_INVALIDARG;
  65. // Copy the item at the specified index into the vector
  66. *pbstr = m_vecStrings[V_I4(&var)].Copy();
  67. // Indicate success
  68. return S_OK;
  69. }
  70. STDMETHODIMP CTCStrings::Add(BSTR bstr)
  71. {
  72. // Lock the object
  73. CLock lock(this);
  74. // Add the string to the vector
  75. m_vecStrings.push_back(bstr);
  76. // Indicate success
  77. return S_OK;
  78. }
  79. STDMETHODIMP CTCStrings::Remove(VARIANT* pvIndex)
  80. {
  81. // Attempt to convert the specified VARIANT to a long
  82. CComVariant var;
  83. RETURN_FAILED(VariantChangeType(&var, pvIndex, 0, VT_I4));
  84. // Lock the object
  85. CLock lock(this);
  86. // Ensure that the specified index is in range
  87. if (V_I4(&var) < 0 || V_I4(&var) >= m_vecStrings.size())
  88. return E_INVALIDARG;
  89. // Use the long as an index into the vector
  90. m_vecStrings.erase(m_vecStrings.begin() + V_I4(&var));
  91. // Indicate success
  92. return S_OK;
  93. }
  94. STDMETHODIMP CTCStrings::RemoveAll()
  95. {
  96. // Lock the object
  97. CLock lock(this);
  98. // Clear the vector
  99. m_vecStrings.clear();
  100. // Indicate success
  101. return S_OK;
  102. }
  103. STDMETHODIMP CTCStrings::AddDelimited(BSTR bstrDelimiter, BSTR bstrStrings)
  104. {
  105. // Get the character length of the specified delimiter
  106. UINT cchDelim = SysStringLen(bstrDelimiter);
  107. // Ensure that the bstrDelimiter parameter is not an empty string
  108. if (!cchDelim)
  109. return E_INVALIDARG;
  110. // Get a pointer to the specified strings
  111. LPCOLESTR psz = bstrStrings;
  112. while (psz)
  113. {
  114. // Find the delimiter in the specified string
  115. LPCOLESTR pszFound = wcsstr(psz, bstrDelimiter);
  116. if (pszFound)
  117. {
  118. m_vecStrings.push_back(CComBSTR(pszFound - psz, psz));
  119. psz = pszFound + cchDelim;
  120. }
  121. else
  122. {
  123. m_vecStrings.push_back(CComBSTR(psz));
  124. psz = NULL;
  125. }
  126. };
  127. // Indicate success
  128. return S_OK;
  129. }
  130. STDMETHODIMP CTCStrings::get_DelimitedItems(BSTR bstrDelimiter,
  131. BSTR* pbstrStrings)
  132. {
  133. // Initialize the [out] parameter
  134. CLEAROUT(pbstrStrings, (BSTR)NULL);
  135. // Get the character length of the specified delimiter
  136. UINT cchDelim = SysStringLen(bstrDelimiter);
  137. // Ensure that the bstrDelimiter parameter is not an empty string
  138. if (!cchDelim)
  139. return E_INVALIDARG;
  140. // Loop thru the collection and calculate the total number of characters
  141. UINT cchTotal = 1;
  142. UINT nCount = m_vecStrings.size();
  143. for (UINT i = 0; i < nCount; ++i)
  144. {
  145. if (i)
  146. cchTotal += cchDelim;
  147. cchTotal += m_vecStrings[i].Length();
  148. }
  149. // Allocate a buffer for the entire array
  150. LPOLESTR psz = new OLECHAR[cchTotal];
  151. *psz = OLESTR('\0');
  152. // Loop thru the collection and concatenate the strings
  153. for (i = 0; i < nCount; ++i)
  154. {
  155. if (i)
  156. wcscat(psz, bstrDelimiter);
  157. if (m_vecStrings[i].Length())
  158. wcscat(psz, m_vecStrings[i]);
  159. }
  160. // Allocate a BSTR and assign it to the [out] parameter
  161. *pbstrStrings = SysAllocStringLen(psz, cchTotal - 1);
  162. // Delete the temporary string
  163. delete [] psz;
  164. // Indicate success
  165. return S_OK;
  166. }
  167. STDMETHODIMP CTCStrings::AddStrings(ITCStrings* pStrings)
  168. {
  169. // Lock the object
  170. Lock();
  171. HRESULT hr = S_OK;
  172. BSTR bstr = NULL;
  173. __try
  174. {
  175. // Loop thru the strings of the specified collection
  176. long nCount = 0;
  177. if (!pStrings || FAILED(hr = pStrings->get_Count(&nCount)))
  178. {
  179. VARIANT v;
  180. VariantInit(&v);
  181. V_VT(&v) = VT_I4;
  182. V_I4(&v) = 0;
  183. for (; V_I4(&v) < nCount; ++V_I4(&v))
  184. {
  185. if (FAILED(hr = pStrings->get_Item(&v, &bstr)))
  186. break;
  187. if (FAILED(hr = Add(bstr)))
  188. break;
  189. }
  190. }
  191. }
  192. __except(1)
  193. {
  194. hr = E_POINTER;
  195. }
  196. // Unlock the object
  197. Unlock();
  198. // Free the BSTR
  199. if (bstr)
  200. SysFreeString(bstr);
  201. // Return the last result
  202. return hr;
  203. }
  204. /////////////////////////////////////////////////////////////////////////////
  205. // ITCCollectionPersistHelper Interface Methods
  206. STDMETHODIMP CTCStrings::put_Collection1(VARIANT* pvarSafeArray)
  207. {
  208. // Lock the object
  209. CLock lock(this);
  210. // Validate the specified VARIANT
  211. VARTYPE vt = V_VT(pvarSafeArray);
  212. if ((VT_BSTR | VT_ARRAY) != vt)
  213. {
  214. m_vecStrings.clear();
  215. return E_INVALIDARG;
  216. }
  217. // Get the array pointer and check dimensions of the array
  218. SAFEARRAY* psa = V_ARRAY(pvarSafeArray);
  219. if (1 != SafeArrayGetDim(psa))
  220. {
  221. m_vecStrings.clear();
  222. return E_INVALIDARG;
  223. }
  224. // Get array bounds.
  225. LONG cElements, lLBound, lUBound;
  226. HRESULT hr = SafeArrayGetLBound(psa, 1, &lLBound);
  227. if (SUCCEEDED(hr))
  228. hr = SafeArrayGetUBound(psa, 1, &lUBound);
  229. if (FAILED(hr))
  230. {
  231. m_vecStrings.clear();
  232. return hr;
  233. }
  234. cElements = lUBound - lLBound + 1;
  235. // Get a pointer to the elements of the array.
  236. BSTR* pbstr = NULL;
  237. hr = SafeArrayAccessData(psa, (void **)&pbstr);
  238. if (FAILED(hr))
  239. {
  240. m_vecStrings.clear();
  241. return hr;
  242. }
  243. // This object will call SafeArrayUnaccessData when it is destructed
  244. TCSafeArrayAccess saa(psa);
  245. // Erase the current contents of the vector
  246. m_vecStrings.clear();
  247. // Add each BSTR to the vector
  248. m_vecStrings.resize(cElements);
  249. for (long i = 0; i < cElements; i++)
  250. m_vecStrings[i] = pbstr[i];
  251. // Indicate success
  252. return S_OK;
  253. }
  254. STDMETHODIMP CTCStrings::get_Collection1(VARIANT* pvarSafeArray)
  255. {
  256. // Initialize the specified VARIANT
  257. __try
  258. {
  259. VariantInit(pvarSafeArray);
  260. }
  261. __except(1)
  262. {
  263. return E_POINTER;
  264. }
  265. // Lock the object
  266. Lock();
  267. HRESULT hr = S_OK;
  268. __try
  269. {
  270. // Create a safe array to copy the BSTRs into
  271. long nCount = m_vecStrings.size();
  272. SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, nCount);
  273. if (!psa)
  274. hr = E_OUTOFMEMORY;
  275. else
  276. {
  277. // Attach the new safe array to the VARIANT
  278. V_VT(pvarSafeArray) = VT_ARRAY | VT_BSTR;
  279. V_ARRAY(pvarSafeArray) = psa;
  280. // Copy each BSTR to the safe array
  281. for (long i = 0; i < nCount; ++i)
  282. SafeArrayPutElement(psa, &i, m_vecStrings[i].Copy());
  283. }
  284. }
  285. __except(1)
  286. {
  287. hr = RPC_E_SERVERFAULT;
  288. }
  289. // Unlock the object
  290. Unlock();
  291. // Clear the [out] variant if an error occurred
  292. if (FAILED(hr))
  293. VariantClear(pvarSafeArray);
  294. // Return the last result
  295. return hr;
  296. }