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.

1062 lines
27 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. SAFEARRY.CPP
  5. Abstract:
  6. CSafeArray implementation.
  7. Notes:
  8. (1) Support only for arrays with origin at 0 or 1.
  9. Can VB deal with a SAFEARRAY of origin zero?
  10. (2) Support only for the following OA types:
  11. VT_BSTR, VT_VARIANT,
  12. VT_UI1, VT_I2, VT_I4, VT_R8
  13. History:
  14. 08-Apr-96 a-raymcc Created.
  15. 18-Mar-99 a-dcrews Added out-of-memory exception handling
  16. --*/
  17. #include "precomp.h"
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <safearry.h>
  22. #include <arrtempl.h>
  23. #include <olewrap.h>
  24. typedef struct
  25. {
  26. DWORD m_nMaxElementUsed;
  27. DWORD m_nFlags;
  28. DWORD m_nGrowBy;
  29. DWORD m_nStatus;
  30. DWORD m_nVarType;
  31. SAFEARRAYBOUND m_bound;
  32. } PersistHeaderBlock;
  33. //***************************************************************************
  34. //
  35. // CSafeArray::CheckType
  36. //
  37. // Verifies that the constructor is being invoked with a supported type.
  38. //
  39. // PARAMETERS:
  40. // nTest
  41. // One of the supported OLE VT_ constants.
  42. //
  43. //***************************************************************************
  44. void CSafeArray::CheckType(int nTest)
  45. {
  46. if (nTest != VT_BSTR &&
  47. nTest != VT_VARIANT &&
  48. nTest != VT_UI1 &&
  49. nTest != VT_I2 &&
  50. nTest != VT_I4 &&
  51. nTest != VT_R4 &&
  52. nTest != VT_R8 &&
  53. nTest != VT_BOOL &&
  54. nTest != VT_DISPATCH &&
  55. nTest != VT_UNKNOWN
  56. )
  57. Fatal("Caller attempted to use unsupported OLE Automation Type (VT_*)");
  58. }
  59. //***************************************************************************
  60. //
  61. // CSafeArray::CSafeArray
  62. //
  63. // Constructor which creates a new SAFEARRAY.
  64. //
  65. // PARAMETERS:
  66. // vt
  67. // An OLE VT_ type indicator, indicating the element type.
  68. // nFlags
  69. // The destruct policy, either <no_delete> or <auto_delete>. With
  70. // <no_delete>, the underlying SAFEARRAY is not deallocated, whereas
  71. // with <auto_delete> the destructor destroys the SAFEARRAY.
  72. // nSize
  73. // The initial size of the SAFEARRAY.
  74. // nGrowBy
  75. // The amount the SAFEARRAY should grow by when the user attempts to
  76. // add elements to a full array.
  77. //
  78. //***************************************************************************
  79. CSafeArray::CSafeArray(
  80. IN int vt,
  81. IN int nFlags,
  82. IN int nSize,
  83. IN int nGrowBy
  84. )
  85. {
  86. CheckType(vt);
  87. m_nMaxElementUsed = -1;
  88. m_nFlags = nFlags;
  89. m_nGrowBy = nGrowBy;
  90. m_nVarType = vt;
  91. // Allocate the array.
  92. // ===================
  93. m_bound.cElements = nSize;
  94. m_bound.lLbound = 0;
  95. m_pArray = COleAuto::_SafeArrayCreate((VARENUM) vt, 1, &m_bound);
  96. if (m_pArray == 0)
  97. m_nStatus = failed;
  98. else
  99. m_nStatus = no_error;
  100. m_nElementSize = SafeArrayGetElemsize( m_pArray );
  101. }
  102. //***************************************************************************
  103. //
  104. // CSafeArray::CSafeArray
  105. //
  106. // Constructor based on an existing SAFEARRAY.
  107. //
  108. // PARAMETERS:
  109. // pSrc
  110. // A pointer to an existing SAFEARRAY which is used as a source
  111. // during object construction.
  112. // nType
  113. // One of the OLE VT_ type indicators.
  114. // nFlags
  115. // OR'ed Bit flags indicating the bind vs. copy, and the
  116. // object destruct policy.
  117. //
  118. // The destruct policy is either <no_delete> or <auto_delete>. With
  119. // <no_delete>, the underlying SAFEARRAY is not deallocated, whereas
  120. // with <auto_delete> the destructor destroys the SAFEARRAY.
  121. //
  122. // Binding is indicated by <bind>, in which case the SAFEARRAY
  123. // pointed to by <pSrc> becomes the internal SAFEARRAY of the
  124. // object. Otherwise, this constructor makes a new copy of the
  125. // SAFEARRAY for internal use.
  126. // nGrowBy
  127. // How much to grow the array by when it fills and the user attempts
  128. // to add more elements. This allows the array to grow in chunks
  129. // so that continuous Add() operations do not operate slowly on
  130. // large arrays.
  131. //
  132. //***************************************************************************
  133. CSafeArray::CSafeArray(
  134. IN SAFEARRAY *pSrcCopy,
  135. IN int nType,
  136. IN int nFlags,
  137. IN int nGrowBy
  138. )
  139. {
  140. m_nStatus = no_error;
  141. CheckType(nType);
  142. // Verify that this is only a 1-dimensional array.
  143. // ===============================================
  144. if (1 != COleAuto::_SafeArrayGetDim(pSrcCopy))
  145. m_nStatus = failed;
  146. // Now copy the source or 'bind' the incoming array.
  147. // ====================================================
  148. if (nFlags & bind)
  149. m_pArray = pSrcCopy;
  150. else if (COleAuto::_SafeArrayCopy(pSrcCopy, &m_pArray) != S_OK)
  151. m_nStatus = failed;
  152. // Get bound information.
  153. // ======================
  154. LONG uBound = 0;
  155. if (S_OK != COleAuto::_SafeArrayGetUBound(m_pArray, 1, &uBound))
  156. m_nStatus = failed;
  157. // Correct the Upper Bound into a size.
  158. // ====================================
  159. m_bound.cElements = uBound + 1;
  160. m_bound.lLbound = 0;
  161. m_nMaxElementUsed = uBound;
  162. m_nVarType = nType;
  163. m_nGrowBy = nGrowBy;
  164. m_nFlags = nFlags & 3; // Mask out the acquire & copy bits.
  165. m_nElementSize = SafeArrayGetElemsize( m_pArray );
  166. }
  167. //***************************************************************************
  168. //
  169. // CSafeArray::GetScalarAt
  170. //
  171. // For class internal use. This function returns the element at
  172. // the specified index.
  173. //
  174. // PARAMETERS:
  175. // nIndex
  176. // The index at which to retrieve the scalar.
  177. //
  178. // RETURN VALUE:
  179. // The scalar at the specified the location.
  180. //
  181. //***************************************************************************
  182. SA_ArrayScalar CSafeArray::GetScalarAt(IN int nIndex)
  183. {
  184. SA_ArrayScalar retval = {0};
  185. // Check for out-of-range condition.
  186. // =================================
  187. if (nIndex > m_nMaxElementUsed + 1)
  188. return retval;
  189. COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &retval);
  190. return retval;
  191. }
  192. //***************************************************************************
  193. //
  194. // CSafeArray assignment operator.
  195. //
  196. //***************************************************************************
  197. CSafeArray& CSafeArray::operator =(IN CSafeArray &Src)
  198. {
  199. Empty();
  200. m_nMaxElementUsed = Src.m_nMaxElementUsed;
  201. m_nFlags = Src.m_nFlags;
  202. m_nGrowBy = Src.m_nGrowBy;
  203. m_nStatus = Src.m_nStatus;
  204. m_nVarType = Src.m_nVarType;
  205. m_bound = Src.m_bound;
  206. m_nElementSize = Src.m_nElementSize;
  207. if (COleAuto::_SafeArrayCopy(Src.m_pArray, &m_pArray) != S_OK)
  208. m_nStatus = failed;
  209. return *this;
  210. }
  211. //***************************************************************************
  212. //
  213. // Copy constructor.
  214. //
  215. // This is implemented primarily via the assignment operator.
  216. //
  217. //***************************************************************************
  218. CSafeArray::CSafeArray(CSafeArray &Src)
  219. {
  220. m_nMaxElementUsed = 0;
  221. m_nFlags = 0;
  222. m_nGrowBy = 0;
  223. m_nStatus = no_error;
  224. m_nVarType = VT_NULL;
  225. m_pArray = 0;
  226. m_bound.cElements = 0;
  227. m_bound.lLbound = 0;
  228. *this = Src;
  229. }
  230. //***************************************************************************
  231. //
  232. // CSafeArray::Add
  233. //
  234. // Adds the BSTR to the array, growing the array if required.
  235. //
  236. // PARAMETERS:
  237. // Src
  238. // The source BSTR to add to the array. If NULL, then a
  239. // blank string is added by the underlying SAFEARRAY implementation.
  240. // (there is no way to prevent this). This can point to
  241. // an LPWSTR as well.
  242. //
  243. // RETURN VALUE:
  244. // <no_error> or <failed>.
  245. //
  246. //***************************************************************************
  247. int CSafeArray::AddBSTR(IN BSTR Src)
  248. {
  249. // If there is no more room in the array, then expand it.
  250. // ======================================================
  251. if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
  252. if (m_nGrowBy == 0)
  253. return range_error;
  254. m_bound.cElements += m_nGrowBy;
  255. if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound))
  256. m_nStatus = failed;
  257. }
  258. m_nMaxElementUsed++;
  259. BSTR Copy = COleAuto::_SysAllocString(Src);
  260. CSysFreeMe auto1(Copy);
  261. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, Copy) != S_OK) {
  262. m_nStatus = failed;
  263. return failed;
  264. }
  265. return no_error;
  266. }
  267. //***************************************************************************
  268. //
  269. // CSafeArray::AddVariant
  270. //
  271. // Adds the specified VARIANT to the array.
  272. //
  273. // PARAMETERS:
  274. // pSrc
  275. // A pointer to the source VARIANT, which is copied.
  276. //
  277. // RETURN VALUE:
  278. // range_error, failed, no_error
  279. //
  280. //***************************************************************************
  281. int CSafeArray::AddVariant(IN VARIANT *pSrc)
  282. {
  283. // If there is no more room in the array, then expand it.
  284. // ======================================================
  285. if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
  286. if (m_nGrowBy == 0)
  287. return range_error;
  288. m_bound.cElements += m_nGrowBy;
  289. if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound))
  290. m_nStatus = failed;
  291. }
  292. m_nMaxElementUsed++;
  293. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pSrc) != S_OK) {
  294. m_nStatus = failed;
  295. return failed;
  296. }
  297. return no_error;
  298. }
  299. //***************************************************************************
  300. //
  301. // CSafeArray::AddDispatch
  302. //
  303. // Adds the specified IDispatch* to the array.
  304. //
  305. // PARAMETERS:
  306. // pSrc
  307. // A pointer to the source IDispatch*, which is AddRefed.
  308. //
  309. // RETURN VALUE:
  310. // range_error, failed, no_error
  311. //
  312. //***************************************************************************
  313. int CSafeArray::AddDispatch(IN IDispatch *pDisp)
  314. {
  315. // If there is no more room in the array, then expand it.
  316. // ======================================================
  317. if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
  318. if (m_nGrowBy == 0)
  319. return range_error;
  320. m_bound.cElements += m_nGrowBy;
  321. if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound))
  322. m_nStatus = failed;
  323. }
  324. m_nMaxElementUsed++;
  325. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pDisp) != S_OK) {
  326. m_nStatus = failed;
  327. return failed;
  328. }
  329. return no_error;
  330. }
  331. //***************************************************************************
  332. //
  333. // CSafeArray::AddUnknown
  334. //
  335. // Adds the specified IUnknown* to the array.
  336. //
  337. // PARAMETERS:
  338. // pSrc
  339. // A pointer to the source IUnknown*, which is AddRefed.
  340. //
  341. // RETURN VALUE:
  342. // range_error, failed, no_error
  343. //
  344. //***************************************************************************
  345. int CSafeArray::AddUnknown(IN IUnknown *pUnk)
  346. {
  347. // If there is no more room in the array, then expand it.
  348. // ======================================================
  349. if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
  350. if (m_nGrowBy == 0)
  351. return range_error;
  352. m_bound.cElements += m_nGrowBy;
  353. if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound))
  354. m_nStatus = failed;
  355. }
  356. m_nMaxElementUsed++;
  357. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, pUnk) != S_OK) {
  358. m_nStatus = failed;
  359. return failed;
  360. }
  361. return no_error;
  362. }
  363. //***************************************************************************
  364. //
  365. // CSafeArray::GetBSTRAt
  366. //
  367. // If the array type is VT_BSTR, this returns the string at the specified
  368. // index.
  369. //
  370. // PARAMETERS:
  371. // nIndex
  372. // The array index for which the string is requried.
  373. //
  374. // RETURN VALUE:
  375. // A dynamically allocated BSTR which must be freed with SysFreeString.
  376. // NULL is returned on error. If NULL was originally added at this
  377. // location, a string with zero length will be returned, which still
  378. // must be freed with SysFreeString.
  379. //
  380. //***************************************************************************
  381. BSTR CSafeArray::GetBSTRAt(int nIndex)
  382. {
  383. BSTR StrPtr = 0;
  384. if (nIndex >= (int) m_bound.cElements)
  385. return NULL;
  386. if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &StrPtr))
  387. return NULL;
  388. return StrPtr;
  389. }
  390. BSTR CSafeArray::GetBSTRAtThrow(int nIndex)
  391. {
  392. BSTR StrPtr = 0;
  393. if (nIndex >= (int) m_bound.cElements)
  394. throw CX_MemoryException();
  395. if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &StrPtr))
  396. throw CX_MemoryException();
  397. return StrPtr;
  398. }
  399. //***************************************************************************
  400. //
  401. // CSafeArray::GetVariantAt
  402. //
  403. // PARAMETERS:
  404. // nIndex
  405. // The array index from which to retrieve the VARIANT.
  406. //
  407. // RETURN VALUE:
  408. // Returns a new VARIANT at the specified location. The receiver must
  409. // call VariantClear() on this VARIANT when it is no longer used.
  410. //
  411. //***************************************************************************
  412. VARIANT CSafeArray::GetVariantAt(int nIndex)
  413. {
  414. VARIANT Var;
  415. COleAuto::_VariantInit(&Var);
  416. if (nIndex >= (int) m_bound.cElements)
  417. return Var;
  418. if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &Var))
  419. return Var;
  420. return Var;
  421. }
  422. //***************************************************************************
  423. //
  424. // CSafeArray::GetDispatchAt
  425. //
  426. // PARAMETERS:
  427. // nIndex
  428. // The array index from which to retrieve the IDispatch*.
  429. //
  430. // RETURN VALUE:
  431. // Returns the IDispatch* at the specified location. The receiver must
  432. // call Release on this pointer (if not NULL) when it is no longer used.
  433. //
  434. //***************************************************************************
  435. IDispatch* CSafeArray::GetDispatchAt(int nIndex)
  436. {
  437. IDispatch* pDisp;
  438. if (nIndex >= (int) m_bound.cElements)
  439. return NULL;
  440. if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &pDisp))
  441. return NULL;
  442. return pDisp;
  443. }
  444. //***************************************************************************
  445. //
  446. // CSafeArray::GetUnknownAt
  447. //
  448. // PARAMETERS:
  449. // nIndex
  450. // The array index from which to retrieve the IUnknown*.
  451. //
  452. // RETURN VALUE:
  453. // Returns the IUnknown* at the specified location. The receiver must
  454. // call Release on this pointer (if not NULL) when it is no longer used.
  455. //
  456. //***************************************************************************
  457. IUnknown* CSafeArray::GetUnknownAt(int nIndex)
  458. {
  459. IUnknown* pUnk;
  460. if (nIndex >= (int) m_bound.cElements)
  461. return NULL;
  462. if (S_OK != COleAuto::_SafeArrayGetElement(m_pArray, (long *) &nIndex, &pUnk))
  463. return NULL;
  464. return pUnk;
  465. }
  466. //***************************************************************************
  467. //
  468. // CSafeArray::SetAt
  469. //
  470. // Replaces the BSTR value at the specified array index. The original
  471. // BSTR value is automatically deallocated and replaced by the new value.
  472. // You can only call this to replace an existing element or to add a
  473. // new element to the end (one position past the last element). If the
  474. // array size is 10, you can call this with 0..10, but not 11 or higher.
  475. //
  476. // PARAMETERS:
  477. // nIndex
  478. // The position at which to replace the element.
  479. // Str
  480. // The new string.
  481. // nFlags
  482. // If <acquire> this function acquires ownership of the string and
  483. // can delete it. Otherwise, the caller retains ownership of the
  484. // string.
  485. //
  486. // RETURN VALUE:
  487. // no_error
  488. // range_error
  489. // failed
  490. //
  491. //***************************************************************************
  492. int CSafeArray::SetBSTRAt(
  493. IN int nIndex,
  494. IN BSTR Str
  495. )
  496. {
  497. // Check for out-of-range condition.
  498. // =================================
  499. if (nIndex > m_nMaxElementUsed + 1)
  500. return range_error;
  501. // Check to see if we are adding a new element.
  502. // ============================================
  503. if (nIndex == m_nMaxElementUsed + 1)
  504. return AddBSTR(Str);
  505. BSTR Copy = COleAuto::_SysAllocString(Str);
  506. CSysFreeMe auto1(Copy);
  507. // If here, we are replacing an element.
  508. // =====================================
  509. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, Copy) != S_OK) {
  510. m_nStatus = failed;
  511. return failed;
  512. }
  513. return no_error;
  514. }
  515. //***************************************************************************
  516. //
  517. // CSafeArray::SetVariantAt
  518. //
  519. // Sets the VARIANT at the specified index.
  520. //
  521. // PARAMETERS:
  522. // nIndex
  523. // The index at which to set the VARIANT. The original contents
  524. // at this location are automatically deallocated and replaced.
  525. // pVal
  526. // Used as the source of the new value. This is treated as read-only.
  527. //
  528. // RETURN VALUE:
  529. // no_error, failed, range_error
  530. //
  531. //***************************************************************************
  532. int CSafeArray::SetVariantAt(
  533. IN int nIndex,
  534. IN VARIANT *pVal
  535. )
  536. {
  537. // Check for out-of-range condition.
  538. // =================================
  539. if (nIndex > m_nMaxElementUsed + 1)
  540. return range_error;
  541. // Check to see if we are adding a new element.
  542. // ============================================
  543. if (nIndex == m_nMaxElementUsed + 1)
  544. return AddVariant(pVal);
  545. // If here, we are replacing an element.
  546. // =====================================
  547. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pVal) != S_OK) {
  548. m_nStatus = failed;
  549. return failed;
  550. }
  551. return no_error;
  552. }
  553. //***************************************************************************
  554. //
  555. // CSafeArray::SetDispatchAt
  556. //
  557. // Sets the IDispatch* at the specified index.
  558. //
  559. // PARAMETERS:
  560. // nIndex
  561. // The index at which to set the IDispatch*. The original contents
  562. // at this location are automatically Released and replaced.
  563. // pVal
  564. // Used as the source of the new value. This is treated as read-only.
  565. //
  566. // RETURN VALUE:
  567. // no_error, failed, range_error
  568. //
  569. //***************************************************************************
  570. int CSafeArray::SetDispatchAt(
  571. IN int nIndex,
  572. IN IDispatch *pDisp
  573. )
  574. {
  575. // Check for out-of-range condition.
  576. // =================================
  577. if (nIndex > m_nMaxElementUsed + 1)
  578. return range_error;
  579. // Check to see if we are adding a new element.
  580. // ============================================
  581. if (nIndex == m_nMaxElementUsed + 1)
  582. return AddDispatch(pDisp);
  583. // If here, we are replacing an element.
  584. // =====================================
  585. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pDisp) != S_OK) {
  586. m_nStatus = failed;
  587. return failed;
  588. }
  589. return no_error;
  590. }
  591. //***************************************************************************
  592. //
  593. // CSafeArray::SetUnknownAt
  594. //
  595. // Sets the IUnknown* at the specified index.
  596. //
  597. // PARAMETERS:
  598. // nIndex
  599. // The index at which to set the IUnknown*. The original contents
  600. // at this location are automatically Released and replaced.
  601. // pVal
  602. // Used as the source of the new value. This is treated as read-only.
  603. //
  604. // RETURN VALUE:
  605. // no_error, failed, range_error
  606. //
  607. //***************************************************************************
  608. int CSafeArray::SetUnknownAt(
  609. IN int nIndex,
  610. IN IUnknown *pUnk
  611. )
  612. {
  613. // Check for out-of-range condition.
  614. // =================================
  615. if (nIndex > m_nMaxElementUsed + 1)
  616. return range_error;
  617. // Check to see if we are adding a new element.
  618. // ============================================
  619. if (nIndex == m_nMaxElementUsed + 1)
  620. return AddUnknown(pUnk);
  621. // If here, we are replacing an element.
  622. // =====================================
  623. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, pUnk) != S_OK) {
  624. m_nStatus = failed;
  625. return failed;
  626. }
  627. return no_error;
  628. }
  629. //***************************************************************************
  630. //
  631. // CSafeArray::RemoveAt
  632. //
  633. // Removes the element at the specified index. After a series of these
  634. // operations, the caller should call the Trim() function.
  635. //
  636. // PARAMETERS:
  637. // nIndex
  638. // The target index for element removal.
  639. //
  640. // RETURN VALUE:
  641. // no_error, range_error
  642. //
  643. //***************************************************************************
  644. int CSafeArray::RemoveAt(IN int nIndex)
  645. {
  646. // Check for out-of-range condition.
  647. // =================================
  648. if (nIndex > m_nMaxElementUsed + 1)
  649. return range_error;
  650. // Copy element n+1 into n.
  651. // ========================
  652. BSTR strVal;
  653. VARIANT v;
  654. SA_ArrayScalar scalar;
  655. IDispatch* pDisp;
  656. IUnknown* pUnk;
  657. for (long i = nIndex; i < m_nMaxElementUsed; i++) {
  658. long nNext = i + 1;
  659. if (m_nVarType == VT_BSTR) {
  660. COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &strVal);
  661. COleAuto::_SafeArrayPutElement(m_pArray, &i, strVal);
  662. COleAuto::_SysFreeString(strVal);
  663. }
  664. else if (m_nVarType == VT_VARIANT) {
  665. COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &v);
  666. COleAuto::_SafeArrayPutElement(m_pArray, &i, &v);
  667. COleAuto::_VariantClear(&v);
  668. }
  669. else if (m_nVarType == VT_DISPATCH) {
  670. COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &pDisp);
  671. COleAuto::_SafeArrayPutElement(m_pArray, &i, pDisp);
  672. if(pDisp) pDisp->Release();
  673. }
  674. else if (m_nVarType == VT_UNKNOWN) {
  675. COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &pUnk);
  676. COleAuto::_SafeArrayPutElement(m_pArray, &i, pUnk);
  677. if(pUnk) pUnk->Release();
  678. }
  679. else {
  680. COleAuto::_SafeArrayGetElement(m_pArray, &nNext, &scalar);
  681. COleAuto::_SafeArrayPutElement(m_pArray, &i, &scalar);
  682. }
  683. }
  684. m_nMaxElementUsed--;
  685. return no_error;
  686. }
  687. //***************************************************************************
  688. //
  689. // CSafeArray::SetScalarAt
  690. //
  691. // For class internal use. Sets the scalar type at the specified index.
  692. //
  693. // PARAMETERS:
  694. // nIndex
  695. // The target index.
  696. // val
  697. // The new value.
  698. //
  699. // RETURN VALUES:
  700. // range_error, failed, no_error
  701. //
  702. //***************************************************************************
  703. int CSafeArray::SetScalarAt(IN int nIndex, IN SA_ArrayScalar val)
  704. {
  705. // Check for out-of-range condition.
  706. // =================================
  707. if (nIndex > m_nMaxElementUsed + 1)
  708. return range_error;
  709. // Check to see if we are adding a new element.
  710. // ============================================
  711. if (nIndex == m_nMaxElementUsed + 1)
  712. return AddScalar(val);
  713. // If here, we are replacing an element.
  714. // =====================================
  715. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &nIndex, &val) != S_OK) {
  716. m_nStatus = failed;
  717. return failed;
  718. }
  719. return no_error;
  720. }
  721. //***************************************************************************
  722. //
  723. // CSafeArray::AddScalar
  724. //
  725. // For class internal use only.
  726. //
  727. // Adds a new scalar to the 'end' of the array, growing it if required
  728. // and if possible.
  729. //
  730. // PARAMETERS:
  731. // val
  732. // The new value.
  733. //
  734. // RETURN VALUE:
  735. // no_error, range_error, failed
  736. //
  737. //***************************************************************************
  738. int CSafeArray::AddScalar(IN SA_ArrayScalar val)
  739. {
  740. // If there is no more room in the array, then expand it.
  741. // ======================================================
  742. if (m_nMaxElementUsed == (int) m_bound.cElements - 1) {
  743. if (m_nGrowBy == 0)
  744. return range_error;
  745. m_bound.cElements += m_nGrowBy;
  746. if (S_OK != COleAuto::_SafeArrayRedim(m_pArray, &m_bound))
  747. m_nStatus = failed;
  748. }
  749. m_nMaxElementUsed++;
  750. if (COleAuto::_SafeArrayPutElement(m_pArray, (long *) &m_nMaxElementUsed, &val) != S_OK) {
  751. m_nStatus = failed;
  752. return failed;
  753. }
  754. return no_error;
  755. }
  756. //***************************************************************************
  757. //
  758. // CSafeArray::Empty
  759. //
  760. // Empties the SAFEARRAY.
  761. //
  762. //***************************************************************************
  763. void CSafeArray::Empty()
  764. {
  765. m_nMaxElementUsed = 0;
  766. m_nFlags = 0;
  767. m_nGrowBy = 0;
  768. m_nStatus = no_error;
  769. m_nVarType = VT_NULL;
  770. if (m_pArray)
  771. COleAuto::_SafeArrayDestroy(m_pArray);
  772. m_pArray = 0;
  773. m_bound.cElements = 0;
  774. m_bound.lLbound = 0;
  775. m_nElementSize = 0L;
  776. }
  777. //***************************************************************************
  778. //
  779. // CSafeArray::GetArrayCopy
  780. //
  781. // RETURN VALUE:
  782. // A copy of the internal SAFEARRAY or NULL on error.
  783. //
  784. //***************************************************************************
  785. SAFEARRAY *CSafeArray::GetArrayCopy()
  786. {
  787. SAFEARRAY *pCopy = 0;
  788. if (COleAuto::_SafeArrayCopy(m_pArray, &pCopy) != S_OK)
  789. return 0;
  790. return pCopy;
  791. }
  792. //***************************************************************************
  793. //
  794. // CSafeArray destructor.
  795. //
  796. // If the internal flags are set to auto_delete, then the internal
  797. // SAFEARRAY is destroyed during destruction.
  798. //
  799. //***************************************************************************
  800. CSafeArray::~CSafeArray()
  801. {
  802. if (m_nFlags == auto_delete)
  803. COleAuto::_SafeArrayDestroy(m_pArray);
  804. }
  805. //***************************************************************************
  806. //
  807. // CSafeArray::Trim
  808. //
  809. //***************************************************************************
  810. int CSafeArray::Trim()
  811. {
  812. m_bound.cElements = m_nMaxElementUsed + 1;
  813. // HACK for NT 3.51: may not redimention to size 0
  814. // ===============================================
  815. if(m_bound.cElements == 0)
  816. {
  817. COleAuto::_SafeArrayDestroy(m_pArray);
  818. m_pArray = COleAuto::_SafeArrayCreate((VARENUM) m_nVarType, 1, &m_bound);
  819. }
  820. else
  821. {
  822. COleAuto::_SafeArrayRedim(m_pArray, &m_bound);
  823. }
  824. return no_error;
  825. }
  826. //***************************************************************************
  827. //
  828. //***************************************************************************
  829. void CSafeArray::Fatal(const char *pszMsg)
  830. {
  831. // MessageBox(0, pszMsg, "CSafeArray FATAL Error",
  832. // MB_OK | MB_SYSTEMMODAL | MB_ICONEXCLAMATION);
  833. }
  834. int CSafeArray::GetActualVarType( VARTYPE* pvt )
  835. {
  836. if ( FAILED( SafeArrayGetVartype( m_pArray, pvt ) ) )
  837. return failed;
  838. return no_error;
  839. }
  840. int CSafeArray::SetRawData( void* pvSource, int nNumElements, int nElementSize )
  841. {
  842. // If the number of elements we are setting is > than the number we are allocated
  843. // for, or element size does not match we fail the operation
  844. if ( nNumElements > m_bound.cElements || nElementSize != m_nElementSize )
  845. {
  846. return failed;
  847. }
  848. LPVOID pvDest = NULL;
  849. HRESULT hr = Access( &pvDest );
  850. if ( SUCCEEDED( hr ) )
  851. {
  852. CopyMemory( pvDest, pvSource, nElementSize * nNumElements );
  853. m_nMaxElementUsed = nNumElements - 1;
  854. Unaccess();
  855. }
  856. return ( SUCCEEDED( hr ) ? no_error : failed );
  857. }
  858. int CSafeArray::GetRawData( void* pvDest, int nBuffSize )
  859. {
  860. // If the number of elements we will copy will exceed the destination
  861. // buffer, don't do it!
  862. if ( ( ( m_nMaxElementUsed + 1 ) * m_nElementSize ) > nBuffSize )
  863. {
  864. return failed;
  865. }
  866. LPVOID pvSource = NULL;
  867. HRESULT hr = Access( &pvSource );
  868. if ( SUCCEEDED( hr ) )
  869. {
  870. CopyMemory( pvDest, pvSource, ( m_nMaxElementUsed + 1) * m_nElementSize );
  871. Unaccess();
  872. }
  873. return ( SUCCEEDED( hr ) ? no_error : failed );
  874. }