Source code of Windows XP (NT5)
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.

265 lines
6.6 KiB

  1. ////////////////////////////////////////////////
  2. // SAFEARRAY.H - SafeArray wrappers and other COM helpers
  3. ////////////////////////////////////////////////
  4. #pragma once
  5. #include <comdef.h>
  6. #pragma warning (disable: 4786) // exceeds 255 chars in browser info
  7. // Macro to make code constantly checking for HRESULTS
  8. // more readable
  9. //
  10. #define CHECK_ERROR(expression) \
  11. { HRESULT hResultCheck = (expression); \
  12. TCHAR l_buf[1024];\
  13. if (FAILED(hResultCheck)) \
  14. { \
  15. wsprintf(l_buf,\
  16. L"%S(%d) : error %d (0x%X) [%s] while performing this action:\n %s\n====\n", \
  17. __FILE__, __LINE__, hResultCheck, hResultCheck, \
  18. _com_error(hResultCheck).ErrorMessage(), #expression); \
  19. OutputDebugString(l_buf);\
  20. ASSERT (FALSE); \
  21. if (hResultCheck != WBEM_E_ACCESS_DENIED) \
  22. return hResultCheck; \
  23. } \
  24. }
  25. // quick class to generate a GUID and a string equivalent
  26. class CGuidString
  27. {
  28. WCHAR m_szGUID[39]; // enough space to fit a GUID in Unicode
  29. GUID m_guid; // enough space to fit a GUID in Unicode
  30. public:
  31. CGuidString()
  32. {
  33. Regen();
  34. }
  35. HRESULT GetBSTR (_bstr_t& str)
  36. {
  37. try {
  38. str = m_szGUID;
  39. }
  40. catch (_com_error e) {
  41. return e.Error();
  42. }
  43. return S_OK;
  44. }
  45. operator LPCWSTR() {return m_szGUID;}
  46. HRESULT Regen()
  47. {
  48. ::ZeroMemory(m_szGUID, sizeof(m_szGUID));
  49. HRESULT hr = CoCreateGuid(&m_guid);
  50. StringFromGUID2 (m_guid, m_szGUID, sizeof(m_szGUID) / sizeof (WCHAR));
  51. return hr;
  52. }
  53. };
  54. //
  55. // template function to suppress exceptions generated from an
  56. // assignment and turn them into HRESULTS. Note that this only works
  57. // with _com_error exceptions!
  58. //
  59. template<class T1, class T2> inline HRESULT SafeAssign(T1& dest, T2& src)
  60. {
  61. try
  62. {
  63. dest = src;
  64. }
  65. catch (_com_error e)
  66. {
  67. return e.Error();
  68. }
  69. catch (...)
  70. {
  71. ASSERT (FALSE); // invalid type of exception!!!!
  72. return TYPE_E_TYPEMISMATCH;
  73. }
  74. return S_OK;
  75. }
  76. //
  77. // Dependency-free SAFEARRAY wrapper class
  78. // Adapted from MFC's COleSafeArray
  79. // Allows type-safe access to safearrays of any type
  80. //
  81. template <class T, VARTYPE t_vt> class CSafeArrayOneDim : public tagVARIANT
  82. {
  83. public:
  84. enum {INITIAL_ALLOC = 200};
  85. CSafeArrayOneDim()
  86. {
  87. // Validate the VARTYPE for SafeArrayCreate call
  88. ASSERT(!(t_vt & VT_ARRAY));
  89. ASSERT(!(t_vt & VT_BYREF));
  90. ASSERT(!(t_vt & VT_VECTOR));
  91. ASSERT(t_vt != VT_EMPTY);
  92. ASSERT(t_vt != VT_NULL);
  93. ::ZeroMemory(this, sizeof(*this));
  94. vt = VT_EMPTY;
  95. }
  96. ~CSafeArrayOneDim()
  97. { Clear(); }
  98. operator VARIANT*()
  99. { return this; }
  100. operator const VARIANT*() const
  101. { return this; }
  102. // operations
  103. HRESULT Create(
  104. DWORD nElements = INITIAL_ALLOC,
  105. T* pvSrcData = NULL)
  106. {
  107. ASSERT(nElements > 0);
  108. // Free up old safe array if necessary
  109. Clear();
  110. // Allocate and fill proxy array of bounds (with lower bound of zero)
  111. SAFEARRAYBOUND saBounds;
  112. saBounds.lLbound = 0;
  113. saBounds.cElements = nElements;
  114. parray = ::SafeArrayCreate(t_vt, 1, &saBounds);
  115. if (parray == NULL)
  116. return E_OUTOFMEMORY;
  117. // set the correct variant type for us
  118. vt = unsigned short(t_vt | VT_ARRAY);
  119. // Copy over the data if neccessary
  120. if (pvSrcData != NULL)
  121. {
  122. T* pvDestData;
  123. CHECK_ERROR(AccessData(&pvDestData));
  124. memcpy(pvDestData,
  125. pvSrcData,
  126. ::SafeArrayGetElemsize(parray) * nElements);
  127. CHECK_ERROR(UnaccessData());
  128. }
  129. return S_OK;
  130. }
  131. DWORD GetSize()
  132. {
  133. long nUBound;
  134. GetUBound(&nUBound);
  135. return nUBound + 1;
  136. }
  137. HRESULT Resize(DWORD dwElements)
  138. {
  139. SAFEARRAYBOUND rgsabound;
  140. rgsabound.cElements = dwElements;
  141. rgsabound.lLbound = 0;
  142. CHECK_ERROR(::SafeArrayRedim(parray, &rgsabound));
  143. return S_OK;
  144. }
  145. HRESULT Copy(LPSAFEARRAY* ppsa)
  146. {
  147. ASSERT (::SafeArrayGetDim(ppsa) == 1);
  148. CHECK_ERROR(::SafeArrayCopy(parray, ppsa));
  149. return S_OK;
  150. }
  151. // store an entry in the array-- resize if needed
  152. HRESULT SafePutElement(long nIndex, const T& pvData)
  153. {
  154. long nUBound;
  155. CHECK_ERROR (GetUBound(&nUBound));
  156. if (nUBound < 1)
  157. {
  158. ASSERT (FALSE);
  159. return E_INVALIDARG;
  160. }
  161. // do we need to expand?
  162. if (nUBound < nIndex)
  163. {
  164. // figure out the right new size
  165. while (nUBound < nIndex)
  166. {
  167. nUBound = nUBound * 2;
  168. }
  169. CHECK_ERROR (Resize(nUBound));
  170. }
  171. CHECK_ERROR(::SafeArrayPutElement(parray, &nIndex, pvData));
  172. return S_OK;
  173. }
  174. // Operations
  175. HRESULT Attach(VARIANT& varSrc)
  176. {
  177. if (!IsValid())
  178. CHECK_ERROR (E_INVALIDARG);
  179. // Free up previous safe array if necessary
  180. CHECK_ERROR(Clear());
  181. // give control of data to CSafeArrayOneDim
  182. memcpy(this, &varSrc, sizeof(varSrc));
  183. varSrc.vt = VT_EMPTY; // take it from the source variant
  184. return S_OK;
  185. }
  186. static bool IsValid(const VARIANT& Other)
  187. {
  188. if ((Other.vt & VT_ARRAY) == 0)
  189. return false; // must be an array
  190. if (Other.vt != unsigned short(t_vt | VT_ARRAY))
  191. return false; // must be same type as us
  192. if (::SafeArrayGetDim(Other.parray) != 1)
  193. return false; // make sure no multi-dim arrays
  194. long nLBound = -1;
  195. ::SafeArrayGetLBound(Other.parray, 1, &nLBound);
  196. if (nLBound != 0)
  197. return false; // lower bound must be zero
  198. // all looks good
  199. return true;
  200. }
  201. VARIANT Detach()
  202. {
  203. VARIANT varResult = *this;
  204. vt = VT_EMPTY;
  205. return varResult;
  206. }
  207. // trivial COM API wrappers
  208. HRESULT Clear()
  209. { return ::VariantClear(this); }
  210. HRESULT AccessData(T** ppvData)
  211. { CHECK_ERROR(::SafeArrayAccessData(parray, (void**) ppvData)); return S_OK; }
  212. HRESULT UnaccessData()
  213. { CHECK_ERROR(::SafeArrayUnaccessData(parray)); return S_OK; }
  214. HRESULT AllocData()
  215. { CHECK_ERROR(::SafeArrayAllocData(parray)); return S_OK; }
  216. HRESULT AllocDescriptor()
  217. { CHECK_ERROR(::SafeArrayAllocDescriptor(1, &parray)); return S_OK; }
  218. HRESULT GetUBound(long* pUbound)
  219. { CHECK_ERROR(::SafeArrayGetUBound(parray, 1, pUbound)); return S_OK; }
  220. HRESULT Lock()
  221. { CHECK_ERROR(::SafeArrayLock(parray)); return S_OK; }
  222. HRESULT Unlock()
  223. { CHECK_ERROR(::SafeArrayUnlock(parray)); return S_OK;}
  224. HRESULT Destroy()
  225. { CHECK_ERROR(::SafeArrayDestroy(parray)); return S_OK; }
  226. HRESULT DestroyData()
  227. { CHECK_ERROR(::SafeArrayDestroyData(parray)); return S_OK; }
  228. HRESULT DestroyDescriptor()
  229. { CHECK_ERROR(::SafeArrayDestroyDescriptor(parray)); return S_OK; }
  230. HRESULT GetElement(long nIndex, T* pvData)
  231. { CHECK_ERROR(::SafeArrayGetElement(parray, &nIndex, pvData)); return S_OK; }
  232. HRESULT PtrOfIndex(long* rgIndices, T** ppvData)
  233. { CHECK_ERROR(::SafeArrayPtrOfIndex(parray, rgIndices, ppvData)); return S_OK; }
  234. HRESULT PutElement(long* rgIndices, T* pvData)
  235. { CHECK_ERROR(::SafeArrayPutElement(parray, rgIndices, pvData)); return S_OK; }
  236. };
  237. // typdefs for common classes
  238. typedef CSafeArrayOneDim<VARIANT, VT_VARIANT> SafeArrayOneDimVariant;
  239. typedef CSafeArrayOneDim<IWbemClassObject*, VT_UNKNOWN> SafeArrayOneDimWbemClassObject;
  240. typedef CSafeArrayOneDim<BSTR, VT_BSTR> SafeArrayOneDimBSTR;