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.

1481 lines
41 KiB

  1. /*************************************************************************
  2. * @doc SHROOM EXTERNAL API *
  3. * *
  4. * RSIMP.CPP *
  5. * *
  6. * Copyright (C) Microsoft Corporation 1997 *
  7. * All Rights reserved. *
  8. * *
  9. * This file contains the implementation of the result set object *
  10. * *
  11. * *
  12. **************************************************************************
  13. * *
  14. * Written By : Erin Foxford *
  15. * Current Owner: erinfox *
  16. * *
  17. **************************************************************************/
  18. #include <mvopsys.h>
  19. #ifdef _DEBUG
  20. static char s_aszModule[] = __FILE__; /* For error report */
  21. #endif
  22. #include <_mvutil.h>
  23. #include <atlinc.h> // Includes for ATL
  24. #include <itpropl.h>
  25. #include <itrs.h>
  26. #include <orkin.h>
  27. #include "rsimp.h"
  28. #include "prop.h"
  29. #include "plist.h"
  30. #define THEORETICAL_MAX_PROP 30 // This would be a lot of properties - Assert only
  31. const unsigned int CHUNK_SIZE = 512; // How many "chunks" of rows that can be allocated
  32. const unsigned int ROW_CHUNK = 1024; // Number of rows allocated per chunk
  33. const unsigned int ROW_CHUNK_LESS1 = ROW_CHUNK - 1; // Number of rows minus 1
  34. // optimization for Real % ROW_CHUNK
  35. #define RealToLogical(Real, Logical) (Logical = Real & ROW_CHUNK_LESS1)
  36. static unsigned int g_iAlloc = 0;
  37. static unsigned int g_iFreed = 0;
  38. CITResultSet::CITResultSet() : m_PageMap(NULL), m_hResultSet(NULL),
  39. m_AppendRow(0), m_cProp(0), m_NumberOfPages(0),
  40. m_fInit(FALSE), m_RowsReserved(0), m_Chunk(-1)
  41. {
  42. // Allocate memory for data pool - if allocation fails,
  43. // how do we notify user?
  44. m_pMemPool = BlockInitiate((DWORD)16384, 0, 0, 0);
  45. ITASSERT (NULL != m_pMemPool);
  46. // Allocate an array of DWORD pointers. These pointers will point to the virtual memory
  47. // space of the result set
  48. m_hResultSet = _GLOBALALLOC(GMEM_MOVEABLE | GMEM_ZEROINIT, CHUNK_SIZE*sizeof(DWORD*));
  49. ITASSERT (NULL != m_hResultSet);
  50. if (m_hResultSet)
  51. m_ResultSet = (DWORD_PTR**)_GLOBALLOCK(m_hResultSet);
  52. // The number of chunks allocated in one shot
  53. m_NumChunks = CHUNK_SIZE;
  54. }
  55. CITResultSet::~CITResultSet()
  56. {
  57. // Free up virtual memory
  58. Clear();
  59. // Free memory pool
  60. if (m_pMemPool)
  61. {
  62. BlockFree(m_pMemPool);
  63. m_pMemPool = NULL;
  64. }
  65. // Free result set array
  66. if (m_hResultSet)
  67. {
  68. _GLOBALUNLOCK(m_hResultSet);
  69. _GLOBALFREE(m_hResultSet);
  70. m_hResultSet = NULL;
  71. }
  72. }
  73. // We wrap VirtualAlloc(.... MEM_RESERVE) so in the future we can
  74. // make this nothing on the Mac
  75. //
  76. // NOTE: Uses #define PAGE_SIZE, which is defined in mvopsys.h.
  77. // Currently it's 8k for Alpha, 4k for everything else
  78. //
  79. HRESULT WINAPI CITResultSet::Reserve()
  80. {
  81. #ifdef _DEBUG
  82. SYSTEM_INFO si;
  83. GetSystemInfo(&si);
  84. ITASSERT(PAGE_SIZE == si.dwPageSize);
  85. #endif
  86. m_Chunk++;
  87. // we have to realloc...
  88. if (m_Chunk == m_NumChunks)
  89. {
  90. // We're allocating a BUNCH of memory here. If we hit this code often, we need
  91. // to redesign our allocation scheme.
  92. ITASSERT(0);
  93. _GLOBALUNLOCK(m_hResultSet);
  94. m_NumChunks += CHUNK_SIZE;
  95. m_hResultSet = _GLOBALREALLOC(m_hResultSet, m_NumChunks*sizeof(DWORD*), GMEM_MOVEABLE | GMEM_ZEROINIT);
  96. if (m_hResultSet)
  97. {
  98. m_ResultSet = (DWORD_PTR**) _GLOBALLOCK(m_hResultSet);
  99. }
  100. else
  101. return SetErrReturn(E_OUTOFMEMORY);
  102. }
  103. // Calculate some info we'll need later on
  104. if (!m_fInit)
  105. {
  106. // how many rows fit into a page of memory?
  107. m_RowsPerPage = PAGE_SIZE/(m_cProp* sizeof(DWORD *));
  108. // the number of pages in a chunk of rows
  109. m_NumberOfPages = (m_cProp * ROW_CHUNK * sizeof(DWORD *))/PAGE_SIZE + 1;
  110. // allocation size in bytes.
  111. m_BytesReserved = m_NumberOfPages*PAGE_SIZE;
  112. if (NULL == (m_PageMap = new BOOL[m_NumberOfPages]))
  113. return SetErrReturn(E_OUTOFMEMORY);
  114. m_fInit = TRUE;
  115. }
  116. // set page map to 0 - this keeps track of which pages are allocated
  117. MEMSET(m_PageMap, 0, m_NumberOfPages*sizeof(BOOL));
  118. // reserve memory for an entire chunk - this call shouldn't happen very frequently.
  119. if (NULL == (m_ResultSet[m_Chunk] = (DWORD_PTR *) VirtualAlloc(NULL, m_BytesReserved,
  120. MEM_RESERVE, PAGE_READWRITE)))
  121. {
  122. #ifdef _DEBUG
  123. int Error = GetLastError( );
  124. DPF1("CITResultSet::Reserve: MEM_RESERVE faild: %u", Error);
  125. #endif // _DEBUG
  126. return SetErrReturn(E_OUTOFMEMORY);
  127. }
  128. #ifdef _DEBUG
  129. MEMORY_BASIC_INFORMATION MemInfo;
  130. VirtualQuery(m_ResultSet[m_Chunk], &MemInfo, sizeof(MEMORY_BASIC_INFORMATION));
  131. #endif // _DEBUG
  132. m_RowsReserved += ROW_CHUNK;
  133. return S_OK;
  134. }
  135. // Wrapper for VirtualAlloc(... MEM_COMMIT...)
  136. // One possible optimization: replace w/ SEH instead
  137. // of maintaining a page map
  138. HRESULT WINAPI CITResultSet::Commit(LONG RowNum)
  139. {
  140. LONG LogicalRowNum;
  141. LONG PageNum;
  142. RealToLogical(RowNum, LogicalRowNum);
  143. PageNum = LogicalRowNum/m_RowsPerPage;
  144. // Only allocate if page hasn't been committed before
  145. // Note that allocated memory gets zero'd
  146. if (FALSE == m_PageMap[PageNum])
  147. {
  148. // this will allocate a full page
  149. if (NULL == VirtualAlloc(&m_ResultSet[m_Chunk][ROW_CHUNK * PageNum], PAGE_SIZE,
  150. MEM_COMMIT, PAGE_READWRITE) )
  151. {
  152. // TODO: map relevant Win32 error to HRESULT... for now I'm assuming
  153. // we ran out of memory
  154. #ifdef _DEBUG
  155. int Error = GetLastError( );
  156. DPF1("CITResultSet::Reserve: MEM_COMMIT faild: %u", Error);
  157. #endif // _DEBUG
  158. return SetErrReturn(E_OUTOFMEMORY);
  159. }
  160. g_iAlloc++;
  161. m_PageMap[PageNum] = TRUE;
  162. }
  163. return S_OK;
  164. }
  165. /********************************************************************
  166. * @method STDMETHODIMP | IITResultSet | Add |
  167. * Adds columns to result set, given a header containing pairs
  168. * of property ID followed by property type
  169. *
  170. * @parm LPVOID | lpvHdr | Buffer containing property ID/property pairs
  171. *
  172. * @rvalue S_OK | The columns were successfully added
  173. *
  174. * @xcomm
  175. * The format of lpvHdr is identical to the output format of
  176. * PorpertyList::SaveHeader. If PL:SaveHeader changes we
  177. * may need to modify this code to maintain compatability.
  178. *
  179. ********************************************************************/
  180. STDMETHODIMP CITResultSet::Add(LPVOID lpvHdr)
  181. {
  182. LPBYTE pCurHdr = (LPBYTE) lpvHdr;
  183. DWORD dwPropID;
  184. DWORD dwType;
  185. DWORD dwProps;
  186. DWORD dwMax;
  187. DWORD iProp; // loop index
  188. m_cs.Lock();
  189. // Number of properties in header
  190. MEMCPY(&dwProps, pCurHdr, sizeof(DWORD));
  191. pCurHdr += sizeof(DWORD);
  192. dwMax = m_cProp + dwProps;
  193. if (dwMax >= MAX_COLUMNS)
  194. {
  195. m_cs.Unlock();
  196. return (SetErrReturn(E_TOOMANYCOLUMNS));
  197. }
  198. // For each property in header, create a column
  199. for (iProp = m_cProp; iProp < dwMax; iProp++)
  200. {
  201. // clear header
  202. MEMSET(&m_Header[iProp], NULL, sizeof(CHeader));
  203. MEMCPY(&dwPropID, pCurHdr, sizeof(DWORD));
  204. pCurHdr += sizeof(DWORD);
  205. MEMCPY(&dwType, pCurHdr, sizeof(DWORD));
  206. pCurHdr += sizeof(DWORD);
  207. m_Header[iProp].dwPropID = dwPropID;
  208. m_Header[iProp].lpvData = NULL;
  209. m_Header[iProp].dwType = dwType;
  210. m_Header[iProp].Priority = PRIORITY_NORMAL; // default priority
  211. } // end for over properties in header
  212. m_cProp += dwProps;
  213. m_cs.Unlock();
  214. return S_OK;
  215. }
  216. /********************************************************************
  217. * @method STDMETHODIMP | IITResultSet | Add |
  218. * Adds a column to the result set
  219. *
  220. * @parm PROPID | PropID | Property ID associated with column
  221. * @parm DWORD | dwDefautData | Default data value
  222. * @parm PRIORITY | Priority | Download priority of column (PRIORITY_LOW, PRIORITY_NORMAL,
  223. * or PRIORITY_HIGH)
  224. *
  225. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  226. * @rvalue S_OK | The column was successfully added
  227. *
  228. * @comm This method is used to add a column for numerical properties.
  229. ********************************************************************/
  230. STDMETHODIMP CITResultSet::Add(PROPID PropID, DWORD dwDefaultData, PRIORITY Priority)
  231. {
  232. if (m_cProp >= MAX_COLUMNS)
  233. return (SetErrReturn(E_TOOMANYCOLUMNS));
  234. m_cs.Lock();
  235. // clear header
  236. MEMSET(&m_Header[m_cProp], NULL, sizeof(CHeader));
  237. // copy data
  238. m_Header[m_cProp].dwPropID = PropID;
  239. m_Header[m_cProp].dwValue = dwDefaultData;
  240. m_Header[m_cProp].dwType = TYPE_VALUE;
  241. m_Header[m_cProp].Priority = Priority; // default priority
  242. m_cProp++;
  243. // Wow! This is a lot of properties!
  244. ITASSERT (m_cProp < THEORETICAL_MAX_PROP);
  245. m_cs.Unlock();
  246. return S_OK;
  247. }
  248. /********************************************************************
  249. * @method STDMETHODIMP | IITResultSet | Add |
  250. * Adds a column to the result set
  251. *
  252. * @parm PROPID | PropID | Property ID associated with column
  253. * @parm LPCWSTR | lpDefaultData | Default value of string
  254. * @parm PRIORITY | Priority | Download priority of column (PRIORITY_LOW, PRIORITY_NORMAL,
  255. * or PRIORITY_HIGH)
  256. *
  257. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  258. * @rvalue S_OK | The column was successfully added
  259. *
  260. * @comm This method is used to add a column for string properties.
  261. ********************************************************************/
  262. STDMETHODIMP CITResultSet::Add(PROPID PropID, LPCWSTR lpszwDefault, PRIORITY Priority)
  263. {
  264. if (m_cProp >= MAX_COLUMNS)
  265. return (SetErrReturn(E_TOOMANYCOLUMNS));
  266. m_cs.Lock();
  267. // clear header
  268. MEMSET(&m_Header[m_cProp], NULL, sizeof(CHeader));
  269. // copy data
  270. if (lpszwDefault)
  271. {
  272. LPBYTE pBuffer;
  273. DWORD cbData = (DWORD)(WSTRLEN(lpszwDefault) + 1) * sizeof(WCHAR);
  274. if (NULL == (pBuffer = (LPBYTE) BlockCopy(m_pMemPool, NULL, cbData + 4, 0)))
  275. {
  276. m_cs.Unlock();
  277. return SetErrReturn(E_OUTOFMEMORY);
  278. }
  279. MEMCPY(pBuffer + sizeof (DWORD), lpszwDefault, cbData);
  280. *(LPDWORD)pBuffer = cbData;
  281. m_Header[m_cProp].lpvData = pBuffer;
  282. }
  283. else
  284. m_Header[m_cProp].lpvData = NULL;
  285. m_Header[m_cProp].dwPropID = PropID;
  286. m_Header[m_cProp].dwType = TYPE_STRING;
  287. m_Header[m_cProp].Priority = Priority; // default priority
  288. m_cProp++;
  289. // Wow! This is a lot of properties!
  290. ITASSERT (m_cProp < THEORETICAL_MAX_PROP);
  291. m_cs.Unlock();
  292. return S_OK;
  293. }
  294. /********************************************************************
  295. * @method STDMETHODIMP | IITResultSet | Add |
  296. * Adds a column to the result set
  297. *
  298. * @parm PROPID | PropID | Property ID associated with column
  299. * @parm LPVOID | lpvDefaultData | Buffer containing default value of data
  300. * @parm DWORD | cbData | Size of buffer
  301. * @parm PRIORITY | Priority | Download priority of column (PRIORITY_LOW, PRIORITY_NORMAL,
  302. * or PRIORITY_HIGH)
  303. *
  304. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  305. * @rvalue S_OK | The column was successfully added
  306. *
  307. * @comm This method is used to add a column for pointer properties.
  308. ********************************************************************/
  309. STDMETHODIMP CITResultSet::Add(PROPID PropID, LPVOID lpvDefaultData, DWORD cbData, PRIORITY Priority)
  310. {
  311. if (m_cProp >= MAX_COLUMNS)
  312. return (SetErrReturn(E_TOOMANYCOLUMNS));
  313. m_cs.Lock();
  314. // clear header
  315. MEMSET(&m_Header[m_cProp], NULL, sizeof(CHeader));
  316. // copy data
  317. if (lpvDefaultData)
  318. {
  319. LPBYTE pBuffer;
  320. if (NULL == (pBuffer = (LPBYTE) BlockCopy(m_pMemPool, NULL, cbData + 4, 0)))
  321. {
  322. m_cs.Unlock();
  323. return SetErrReturn(E_OUTOFMEMORY);
  324. }
  325. MEMCPY(pBuffer + 4, lpvDefaultData, cbData);
  326. *(LPDWORD)pBuffer = cbData;
  327. m_Header[m_cProp].lpvData = pBuffer;
  328. }
  329. else
  330. m_Header[m_cProp].lpvData = NULL;
  331. m_Header[m_cProp].dwPropID = PropID;
  332. m_Header[m_cProp].dwType = TYPE_POINTER;
  333. m_Header[m_cProp].Priority = Priority; // default priority
  334. m_cProp++;
  335. // Wow! This is a lot of properties!
  336. ITASSERT (m_cProp < THEORETICAL_MAX_PROP);
  337. m_cs.Unlock();
  338. return S_OK;
  339. }
  340. /********************************************************************
  341. * @method STDMETHODIMP | IITResultSet | SetColumnPriority |
  342. * Sets the download priority for the given column in the result set
  343. *
  344. * @parm LONG | lColumnIndex | Index of column to set
  345. * @parm PRIORITY | Priority | Priority, which can be one of the following:
  346. *
  347. * @flag PRIORITY_LOW | Low priority
  348. * @flag PRIORITY_NORMAL | Normal priority
  349. * @flag PRIORITY_HIGH | High priority
  350. *
  351. * @rvalue E_NOTEXIST | Column does not exist
  352. * @rvalue S_OK | The priority was successfully set
  353. ********************************************************************/
  354. STDMETHODIMP CITResultSet::SetColumnPriority(LONG lColumnIndex, PRIORITY ColumnPriority)
  355. {
  356. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  357. return SetErrReturn(E_NOTEXIST);
  358. m_cs.Lock();
  359. m_Header[lColumnIndex].Priority = ColumnPriority;
  360. m_cs.Unlock();
  361. return S_OK;
  362. }
  363. /********************************************************************
  364. * @method STDMETHODIMP | IITResultSet | SetColumnHeap |
  365. * Sets the heap which DWORD values in this column point into.
  366. *
  367. * @parm LONG | lColumnIndex | Index of column to set
  368. * @parm LPVOID | lpvHeap | Pointer to the heap.
  369. * @parm PFNCOLHEAPFREE | pfnColHeapFree |
  370. * Pointer to a function which can be called to free the heap
  371. * when the result set is cleared or freed.
  372. *
  373. *
  374. * @rvalue E_NOTEXIST | Column does not exist
  375. * @rvalue S_OK | The heap was successfully set
  376. ********************************************************************/
  377. STDMETHODIMP CITResultSet::SetColumnHeap(LONG lColumnIndex, LPVOID lpvHeap,
  378. PFNCOLHEAPFREE pfnColHeapFree)
  379. {
  380. HRESULT hr = S_OK;
  381. if (lColumnIndex < 0)
  382. return SetErrReturn(E_INVALIDARG);
  383. m_cs.Lock();
  384. if (lColumnIndex >= m_cProp)
  385. hr = E_NOTEXIST;
  386. else
  387. if (m_Header[lColumnIndex].lpvHeap != NULL)
  388. hr = E_ALREADYINIT;
  389. if (SUCCEEDED(hr))
  390. {
  391. m_Header[lColumnIndex].lpvHeap = lpvHeap;
  392. m_Header[lColumnIndex].pfnHeapFree = pfnColHeapFree;
  393. }
  394. m_cs.Unlock();
  395. return (hr);
  396. }
  397. /********************************************************************
  398. * @method STDMETHODIMP | IITResultSet | GetColumnPriority |
  399. * Gets the download priority for the given column in the result set
  400. *
  401. * @parm LONG | lColumnIndex | Index of column to get
  402. * @parm PRIORITY& | Priority | Priority, which can be one of the following:
  403. *
  404. * @flag PRIORITY_LOW | Low priority
  405. * @flag PRIORITY_NORMAL | Normal priority
  406. * @flag PRIORITY_HIGH | High priority
  407. *
  408. * @rvalue E_NOTEXIST | Column does not exist
  409. * @rvalue S_OK | The priority was successfully retrieved
  410. ********************************************************************/
  411. STDMETHODIMP CITResultSet::GetColumnPriority(LONG lColumnIndex, PRIORITY& ColumnPriority)
  412. {
  413. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  414. return SetErrReturn(E_NOTEXIST);
  415. ColumnPriority = m_Header[lColumnIndex].Priority;
  416. return S_OK;
  417. }
  418. /********************************************************************
  419. * @method STDMETHODIMP | IITResultSet | SetKeyProp |
  420. * Sets the property to be used as the key.
  421. *
  422. * @parm PROPID | KeyPropID | Property ID
  423. *
  424. * @rvalue S_OK | The key property was successfully set
  425. *
  426. ********************************************************************/
  427. inline STDMETHODIMP CITResultSet::SetKeyProp(PROPID KeyPropID)
  428. {
  429. m_cs.Lock();
  430. m_dwKeyProp = KeyPropID;
  431. m_cs.Unlock();
  432. return S_OK;
  433. }
  434. /********************************************************************
  435. * @method STDMETHODIMP | IITResultSet | GetKeyProp |
  436. * Retrieves the property used as the key
  437. *
  438. * @parm PROPID | KeyPropID | Property ID
  439. *
  440. * @rvalue S_OK | The key property was successfully retrieved
  441. *
  442. ********************************************************************/
  443. inline STDMETHODIMP CITResultSet::GetKeyProp(PROPID& KeyPropID)
  444. {
  445. KeyPropID = m_dwKeyProp;
  446. return S_OK;
  447. }
  448. /********************************************************************
  449. * @method STDMETHODIMP | IITResultSet | Append |
  450. * Given header (prop ID and type) and data, this function forms a
  451. * row and appends it to the current result set
  452. *
  453. * @parm LPVOID | lpvHdr | Pointer to buffer containing header
  454. * @parm LPVOID | lpvData | Pointer to buffer containing data
  455. *
  456. * @rvalue E_INVALIDARG | Exceeded maximum number of rows
  457. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  458. * @rvalue S_FALSE | No columns were found to set, but no failure occurred
  459. * @rvalue S_OK | The row was successfully filled in
  460. *
  461. * @xcomm
  462. * The format of lpvHdr is identical to the output format of
  463. * PorpertyList::SaveData. If PL:Savedata changes we may
  464. * need to modify this code to maintain compatability.
  465. *
  466. ********************************************************************/
  467. STDMETHODIMP CITResultSet::Append(LPVOID lpvHdr, LPVOID lpvData)
  468. {
  469. return Set(m_AppendRow, lpvHdr, lpvData);
  470. }
  471. /********************************************************************
  472. * @method STDMETHODIMP | IITResultSet | Set |
  473. * Given header (prop ID and type) and data, this function puts
  474. * the information into the specified row in the result set
  475. *
  476. * @parm LONG | lRowIndex | Index of row in result set
  477. * @parm LPVOID | lpvHdr | Pointer to buffer containing header
  478. * @parm LPVOID | lpvData | Pointer to buffer containing data
  479. *
  480. * @rvalue E_INVALIDARG | Exceeded maximum number of rows
  481. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  482. * @rvalue S_FALSE | No columns were found to set, but no failure occurred
  483. * @rvalue S_OK | The row was successfully filled in
  484. *
  485. * @xcomm
  486. * The format of lpvHdr is identical to the output format of
  487. * PorpertyList::SaveData. If PL:Savedata changes we may
  488. * need to modify this code to maintain compatability.
  489. *
  490. ********************************************************************/
  491. STDMETHODIMP CITResultSet::Set(LONG lRowIndex, LPVOID lpvHdr, LPVOID lpvData)
  492. {
  493. LPBYTE pCurHdr = (LPBYTE) lpvHdr;
  494. LPBYTE pCurData = (LPBYTE) lpvData;
  495. LPBYTE pBitField = (LPBYTE) lpvData;
  496. DWORD dwProps;
  497. DWORD dwPropID;
  498. DWORD dwType;
  499. LPBYTE pBuffer;
  500. DWORD cbSize;
  501. LONG lColumn;
  502. HRESULT hr = S_FALSE;
  503. m_cs.Lock();
  504. // Reserve memory if necessary
  505. if (lRowIndex >= m_RowsReserved)
  506. {
  507. if ( FAILED(Reserve()) )
  508. {
  509. m_cs.Unlock();
  510. return SetErrReturn(E_OUTOFMEMORY);
  511. }
  512. }
  513. // Commit memory
  514. if ( FAILED(Commit(lRowIndex)) )
  515. {
  516. m_cs.Unlock();
  517. return SetErrReturn(E_OUTOFMEMORY);
  518. }
  519. LONG LogicalRow;
  520. RealToLogical(lRowIndex, LogicalRow);
  521. LONG nRow = LogicalRow * m_cProp;
  522. LONG nChunk = lRowIndex/ROW_CHUNK;
  523. // Number of properties in header
  524. MEMCPY(&dwProps, pCurHdr, sizeof(DWORD));
  525. pCurHdr += sizeof(DWORD);
  526. // Shift pCurData up to leave room for the property bit field
  527. pCurData += (dwProps/8 + 1);
  528. // For each property in header, look for matching result set column
  529. for (DWORD iProp = 0; iProp < dwProps; iProp++)
  530. {
  531. MEMCPY(&dwPropID, pCurHdr, sizeof(DWORD));
  532. pCurHdr += sizeof(DWORD);
  533. MEMCPY(&dwType, pCurHdr, sizeof(DWORD));
  534. pCurHdr += sizeof(DWORD);
  535. // UNDONE: Figure out an optimization. If columns match up w/ header,
  536. // then by the time we get to the end of the header, we'll have to loop
  537. // over ALL the columns just to find which the column that matches the
  538. // property ID. The problem is, it's not guaranteed that the columns
  539. // match up exactly; the user could set them in any order.
  540. // Is there data for this property?
  541. BYTE WhichBit = (0x80 >> (iProp % 8));
  542. int BitSet = pBitField[iProp/8] & WhichBit;
  543. HRESULT hrFound = GetColumnFromPropID(dwPropID, lColumn);
  544. if (SUCCEEDED(hrFound))
  545. hr = S_OK; // found at least one column
  546. if (BitSet)
  547. {
  548. if (TYPE_VALUE == dwType)
  549. {
  550. // copy data value
  551. if (SUCCEEDED(hrFound))
  552. m_ResultSet[nChunk][nRow + lColumn] = *(LPDWORD) pCurData;
  553. // if user didn't specify column, we still need to skip the data for
  554. // this property
  555. pCurData += sizeof(DWORD);
  556. }
  557. else
  558. {
  559. // get size
  560. MEMCPY(&cbSize, pCurData, sizeof(DWORD));
  561. pCurData += sizeof(DWORD);
  562. if (SUCCEEDED(hrFound))
  563. {
  564. if (NULL == (pBuffer = (LPBYTE) BlockCopy(m_pMemPool, NULL, cbSize + 4, 0)))
  565. {
  566. m_cs.Unlock();
  567. return SetErrReturn(E_OUTOFMEMORY);
  568. }
  569. // append size to data
  570. MEMCPY(pBuffer + 4, pCurData, cbSize);
  571. *(LPDWORD)pBuffer = cbSize;
  572. m_ResultSet[nChunk][nRow + lColumn] = (DWORD_PTR) pBuffer;
  573. }
  574. pCurData += cbSize;
  575. }
  576. }
  577. else
  578. {
  579. // No, so use default
  580. if (SUCCEEDED(hrFound))
  581. m_ResultSet[nChunk][nRow + lColumn] = (DWORD_PTR) m_Header[lColumn].lpvData;
  582. }
  583. } // end for over properties in header
  584. // Always maintain one past the last row as the append row
  585. // unless we didn't put anything in the result set
  586. if ( (lRowIndex >= m_AppendRow) && (S_OK == hr))
  587. m_AppendRow = lRowIndex + 1;
  588. m_cs.Unlock();
  589. return hr;
  590. }
  591. /********************************************************************
  592. * @method STDMETHODIMP | IITResultSet | Set |
  593. * Sets the property in the specified row to the property value.
  594. *
  595. * @parm LONG | lRowIndex | Row in which property belongs
  596. * @parm LONG | lColumnIndex | Column in which property belongs
  597. * @parm DWORD | dwData | Data to set
  598. *
  599. * @rvalue E_INVALIDARG | Exceed maximum row count
  600. * @rvalue E_NOTEXIST | Column does not exist
  601. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  602. * @rvalue S_OK | The row was successfully set
  603. ********************************************************************/
  604. STDMETHODIMP CITResultSet::Set(LONG lRowIndex, LONG lColumnIndex, DWORD dwData)
  605. {
  606. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  607. return SetErrReturn(E_NOTEXIST);
  608. m_cs.Lock();
  609. // Reserve memory if necessary
  610. if (lRowIndex >= m_RowsReserved)
  611. {
  612. if ( FAILED(Reserve()) )
  613. {
  614. m_cs.Unlock();
  615. return SetErrReturn(E_OUTOFMEMORY);
  616. }
  617. }
  618. // Commit memory
  619. if ( FAILED(Commit(lRowIndex)) )
  620. {
  621. m_cs.Unlock();
  622. return SetErrReturn(E_OUTOFMEMORY);
  623. }
  624. LONG LogicalRow;
  625. RealToLogical(lRowIndex, LogicalRow);
  626. LONG nRow = LogicalRow * m_cProp;
  627. LONG nChunk = lRowIndex/ROW_CHUNK;
  628. m_ResultSet[nChunk][nRow + lColumnIndex] = dwData;
  629. // always maintain one past the last row as the append row
  630. if (lRowIndex >= m_AppendRow)
  631. m_AppendRow = lRowIndex + 1;
  632. m_cs.Unlock();
  633. return S_OK;
  634. }
  635. /********************************************************************
  636. * @method STDMETHODIMP | IITResultSet | Set |
  637. * Sets the property in the specified row to the property value.
  638. *
  639. * @parm LONG | lRowIndex | Row in which property belongs
  640. * @parm LONG | lColumnIndex | Column in which property belongs
  641. * @parm DWORD | dwData | Data to set
  642. *
  643. * @rvalue E_INVALIDARG | Exceed maximum row count
  644. * @rvalue E_NOTEXIST | Column does not exist
  645. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  646. * @rvalue S_OK | The row was successfully set
  647. ********************************************************************/
  648. STDMETHODIMP CITResultSet::Set(LONG lRowIndex, LONG lColumnIndex, DWORD_PTR dwData)
  649. {
  650. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  651. return SetErrReturn(E_NOTEXIST);
  652. m_cs.Lock();
  653. // Reserve memory if necessary
  654. if (lRowIndex >= m_RowsReserved)
  655. {
  656. if ( FAILED(Reserve()) )
  657. {
  658. m_cs.Unlock();
  659. return SetErrReturn(E_OUTOFMEMORY);
  660. }
  661. }
  662. // Commit memory
  663. if ( FAILED(Commit(lRowIndex)) )
  664. {
  665. m_cs.Unlock();
  666. return SetErrReturn(E_OUTOFMEMORY);
  667. }
  668. LONG LogicalRow;
  669. RealToLogical(lRowIndex, LogicalRow);
  670. LONG nRow = LogicalRow * m_cProp;
  671. LONG nChunk = lRowIndex/ROW_CHUNK;
  672. m_ResultSet[nChunk][nRow + lColumnIndex] = dwData;
  673. // always maintain one past the last row as the append row
  674. if (lRowIndex >= m_AppendRow)
  675. m_AppendRow = lRowIndex + 1;
  676. m_cs.Unlock();
  677. return S_OK;
  678. }
  679. /********************************************************************
  680. * @method STDMETHODIMP | IITResultSet | Set |
  681. * Sets the property in the specified row to the property value.
  682. *
  683. * @parm LONG | lRowIndex | Row in which property belongs
  684. * @parm LPCWSTR | lpszString | Data to set
  685. *
  686. * @rvalue E_INVALIDARG | Exceed maximum row count
  687. * @rvalue E_NOTEXIST | Column does not exist
  688. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  689. * @rvalue S_OK | The row was successfully set
  690. ********************************************************************/
  691. STDMETHODIMP CITResultSet::Set(LONG lRowIndex, LONG lColumnIndex, LPCWSTR lpszString)
  692. {
  693. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  694. return SetErrReturn(E_NOTEXIST);
  695. m_cs.Lock();
  696. // Reserve memory if necessary
  697. if (lRowIndex >= m_RowsReserved)
  698. {
  699. if ( FAILED(Reserve()) )
  700. {
  701. m_cs.Unlock();
  702. return SetErrReturn(E_OUTOFMEMORY);
  703. }
  704. }
  705. // Commit memory
  706. if ( FAILED(Commit(lRowIndex)) )
  707. {
  708. m_cs.Unlock();
  709. return SetErrReturn(E_OUTOFMEMORY);
  710. }
  711. LONG LogicalRow;
  712. RealToLogical(lRowIndex, LogicalRow);
  713. LONG nRow = LogicalRow * m_cProp;
  714. LONG nChunk = lRowIndex/ROW_CHUNK;
  715. DWORD cbData = 0;
  716. if (lpszString)
  717. cbData = (DWORD) (2*(WSTRLEN(lpszString) + 1));
  718. LPBYTE pBuffer = (LPBYTE) BlockCopy(m_pMemPool, NULL, cbData + sizeof (DWORD), 0);
  719. if (NULL == pBuffer)
  720. {
  721. m_cs.Unlock();
  722. return SetErrReturn(E_OUTOFMEMORY);
  723. }
  724. MEMCPY(pBuffer + 4, lpszString, cbData);
  725. *(LPDWORD)pBuffer = cbData;
  726. m_ResultSet[nChunk][nRow + lColumnIndex] = (DWORD_PTR) pBuffer;
  727. // always maintain one past the last row as the append row
  728. if (lRowIndex >= m_AppendRow)
  729. m_AppendRow = lRowIndex + 1;
  730. m_cs.Unlock();
  731. return S_OK;
  732. }
  733. /********************************************************************
  734. * @method STDMETHODIMP | IITResultSet | Set |
  735. * Sets the property in the specified row to the property value.
  736. *
  737. * @parm LONG | lRowIndex | Row in which property belongs
  738. * @parm DWORD | dwData | Data to set
  739. *
  740. * @rvalue E_INVALIDARG | Exceed maximum row count
  741. * @rvalue E_NOTEXIST | Column does not exist
  742. * @rvalue E_OUTOFMEMORY | Memory allocation failed
  743. * @rvalue S_OK | The row was successfully set
  744. ********************************************************************/
  745. STDMETHODIMP CITResultSet::Set(LONG lRowIndex, LONG lColumnIndex, LPVOID lpvData, DWORD cbData)
  746. {
  747. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  748. return SetErrReturn(E_NOTEXIST);
  749. m_cs.Lock();
  750. // Reserve memory if necessary
  751. if (lRowIndex >= m_RowsReserved)
  752. {
  753. if ( FAILED(Reserve()) )
  754. {
  755. m_cs.Unlock();
  756. return SetErrReturn(E_OUTOFMEMORY);
  757. }
  758. }
  759. // Commit memory
  760. if ( FAILED(Commit(lRowIndex)) )
  761. {
  762. m_cs.Unlock();
  763. return SetErrReturn(E_OUTOFMEMORY);
  764. }
  765. LONG LogicalRow;
  766. RealToLogical(lRowIndex, LogicalRow);
  767. LONG nRow = LogicalRow * m_cProp;
  768. LONG nChunk = lRowIndex/ROW_CHUNK;
  769. LPBYTE pBuffer = (LPBYTE) BlockCopy(m_pMemPool, NULL, cbData + sizeof (DWORD), 0);
  770. if (NULL == pBuffer)
  771. {
  772. m_cs.Unlock();
  773. return SetErrReturn(E_OUTOFMEMORY);
  774. }
  775. *(LPDWORD)pBuffer = cbData;
  776. MEMCPY(pBuffer + sizeof (DWORD), lpvData, cbData);
  777. m_ResultSet[nChunk][nRow + lColumnIndex] = (DWORD_PTR) pBuffer;
  778. // always maintain one past the last row as the append row
  779. if (lRowIndex >= m_AppendRow)
  780. m_AppendRow = lRowIndex + 1;
  781. m_cs.Unlock();
  782. return S_OK;
  783. }
  784. /********************************************************************
  785. * @method STDMETHODIMP | IITResultSet | Get |
  786. * Gets the property in the specified row and column and fills the given
  787. * property object.
  788. *
  789. * @parm LONG | lRowIndex | Row in which property belongs
  790. * @parm LONG | lColumnIndex | Column in which property belongs
  791. * @parm CProperty& | Prop | Property object to fill
  792. *
  793. * @rvalue E_NOTEXIST | The row or column does not exist in the row set
  794. * @rvalue S_OK | The row was successfully retrieved
  795. *
  796. ********************************************************************/
  797. STDMETHODIMP CITResultSet::Get(LONG lRowIndex, LONG lColumnIndex, CProperty& Prop)
  798. {
  799. if (lRowIndex >= m_AppendRow || lColumnIndex >= m_cProp)
  800. return SetErrReturn(E_NOTEXIST);
  801. LONG LogicalRow;
  802. RealToLogical(lRowIndex, LogicalRow);
  803. LONG nRow = LogicalRow * m_cProp;
  804. LONG nChunk = lRowIndex/ROW_CHUNK;
  805. Prop.dwPropID = m_Header[lColumnIndex].dwPropID;
  806. if (TYPE_VALUE == (Prop.dwType = m_Header[lColumnIndex].dwType))
  807. {
  808. // For data types, we have no way of knowing how to return
  809. // the default, so we just return 0 if this cell was never filled in
  810. Prop.lpvData = (LPVOID) m_ResultSet[nChunk][nRow+lColumnIndex];
  811. Prop.dwValue = (DWORD) m_ResultSet[nChunk][nRow+lColumnIndex];
  812. Prop.cbData = sizeof(DWORD);
  813. }
  814. else
  815. {
  816. LPBYTE pBuffer = (LPBYTE) m_ResultSet[nChunk][nRow+lColumnIndex];
  817. if (pBuffer)
  818. {
  819. Prop.cbData = *(LPDWORD)pBuffer;
  820. Prop.lpvData = pBuffer + sizeof (DWORD);
  821. }
  822. else
  823. {
  824. // there's nothing there, so return default
  825. if (m_Header[lColumnIndex].lpvData)
  826. {
  827. Prop.cbData = *(LPDWORD) m_Header[lColumnIndex].lpvData;
  828. Prop.lpvData = (LPDWORD)(m_Header[lColumnIndex].lpvData) + 1;
  829. }
  830. else
  831. {
  832. // default was specified as NULL, so we make sure we
  833. // return that
  834. Prop.cbData = 0;
  835. Prop.lpvData = NULL;
  836. }
  837. }
  838. }
  839. return S_OK;
  840. }
  841. /********************************************************************
  842. * @method STDMETHODIMP | IITResultSet | GetColumnCount |
  843. * Gets number of columns in result set
  844. *
  845. * @parm LONG& | lNumberOfColumns | Number of columns
  846. *
  847. * @rvalue S_OK | The number of columns was successfully retrieved
  848. *
  849. ********************************************************************/
  850. inline STDMETHODIMP CITResultSet::GetColumnCount(LONG& lNumberOfColumns)
  851. {
  852. lNumberOfColumns = m_cProp;
  853. return S_OK;
  854. }
  855. /********************************************************************
  856. * @method STDMETHODIMP | IITResultSet | GetRowCount |
  857. * Gets number of rows in result set
  858. *
  859. * @parm LONG& | lNumberOfRows | Number of rows
  860. *
  861. * @rvalue S_OK | The number of rows was successfully retrieved
  862. *
  863. ********************************************************************/
  864. inline STDMETHODIMP CITResultSet::GetRowCount(LONG& lNumberOfRows)
  865. {
  866. lNumberOfRows = m_AppendRow;
  867. return S_OK;
  868. }
  869. /********************************************************************
  870. * @method STDMETHODIMP | IITResultSet | GetColumn|
  871. * Gets property ID and default value associated with a column.
  872. *
  873. * @parm LONG | lColumnIndex | Column number
  874. * @parm PROPID | PropID | Property ID
  875. * @parm DWORD | dwType | Property Type (TYPE_VALUE, TYPE_POINTER, TYPE_STRING)
  876. * @parm LPVOID& | lpvDefaultValue | Default value
  877. * @parm DWORD& | cbSize |Length of data (in bytes)
  878. * @parm PRIORITY& | Priority | Column priority
  879. *
  880. * @rvalue E_NOTEXIST | Column does not exist
  881. * @rvalue S_OK | The column was successfully retrieved
  882. *
  883. ********************************************************************/
  884. STDMETHODIMP CITResultSet::GetColumn(LONG lColumnIndex, PROPID& PropID, DWORD& dwType, LPVOID& lpvDefaultValue,
  885. DWORD& cbSize, PRIORITY& Priority)
  886. {
  887. // check against invalid lColumnIndex
  888. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  889. return SetErrReturn(E_NOTEXIST);
  890. PropID = m_Header[lColumnIndex].dwPropID;
  891. dwType = m_Header[lColumnIndex].dwType;
  892. // it could be NULL
  893. if (m_Header[lColumnIndex].lpvData)
  894. {
  895. lpvDefaultValue = (LPBYTE) m_Header[lColumnIndex].lpvData + sizeof (DWORD);
  896. if (TYPE_VALUE == dwType)
  897. cbSize = sizeof(DWORD);
  898. else
  899. cbSize = *((LPDWORD)m_Header[lColumnIndex].lpvData);
  900. }
  901. else
  902. {
  903. lpvDefaultValue = NULL;
  904. cbSize = 0;
  905. }
  906. Priority = m_Header[lColumnIndex].Priority;
  907. return S_OK;
  908. }
  909. /********************************************************************
  910. * @method STDMETHODIMP | IITResultSet | GetColumn|
  911. * Gets property ID for a given column index.
  912. *
  913. * @parm LONG | lColumnIndex | Column number
  914. * @parm PROPID | PropID | Property ID
  915. *
  916. * @rvalue E_NOTEXIST | Column does not exist
  917. * @rvalue S_OK | The column was successfully retrieved
  918. *
  919. ********************************************************************/
  920. STDMETHODIMP CITResultSet::GetColumn(LONG lColumnIndex, PROPID& PropID)
  921. {
  922. // check against invalid lColumnIndex
  923. if (lColumnIndex >= m_cProp || lColumnIndex < 0)
  924. return SetErrReturn(E_NOTEXIST);
  925. PropID = m_Header[lColumnIndex].dwPropID;
  926. return S_OK;
  927. }
  928. /********************************************************************
  929. * @method STDMETHODIMP | IITResultSet | GetColumnFromPropID |
  930. * Gets column index for which a property ID is associated
  931. *
  932. * @parm PROPID | PropID | Property ID
  933. * @parm LONG& | lColumnIndex | Column index
  934. *
  935. * @rvalue E_NOTEXIST | The column does not exist
  936. * @rvalue S_OK | The column index was successfully returned
  937. *
  938. ********************************************************************/
  939. STDMETHODIMP CITResultSet::GetColumnFromPropID(PROPID PropID, LONG& lColumnIndex)
  940. {
  941. // Loop over all columns, looking for match
  942. for (LONG iIndex = 0; iIndex < m_cProp; iIndex++)
  943. {
  944. if (PropID == m_Header[iIndex].dwPropID)
  945. {
  946. // Found it
  947. lColumnIndex = iIndex;
  948. return S_OK;
  949. }
  950. }
  951. return SetErrReturn(E_NOTEXIST);
  952. }
  953. /********************************************************************
  954. * @method STDMETHODIMP | IITResultSet | AppendRows|
  955. * Appends rows from the given source resultset
  956. *
  957. * @parm IITResultSet* | pResSrc | Source resultset
  958. * @parm LONG | lRowSrcFirst | Source row number to start the copy
  959. * @parm LONG | cSrcRows | Number of rows to append
  960. * @parm LONG& | lRowFirstDest | First destination row number appended
  961. *
  962. * @rvalue E_OUTOFMEMORY | Not enough memory to append to the destination
  963. * @rvalue S_OK | All rows were successfully appended
  964. *
  965. ********************************************************************/
  966. // UNDONE: this is terribly inefficient. We need to fix resultsets so that rows can
  967. // be copied more easily
  968. STDMETHODIMP CITResultSet::AppendRows(IITResultSet* pResSrc, LONG lRowSrcFirst, LONG cSrcRows,
  969. LONG& lRowDestFirst)
  970. {
  971. LONG lColumn;
  972. HRESULT hr = E_NOTEXIST;
  973. PROPID PropID;
  974. LONG lDestColumn;
  975. CProperty Prop;
  976. lRowDestFirst = m_AppendRow;
  977. m_cs.Lock();
  978. pResSrc->GetColumnCount(lColumn);
  979. // Loop over columns in source result set
  980. for (LONG iProp = 0; iProp < lColumn; iProp++)
  981. {
  982. // get column in dest result set
  983. pResSrc->GetColumn(iProp, PropID);
  984. if (FAILED(GetColumnFromPropID(PropID, lDestColumn)))
  985. continue;
  986. hr = S_OK; // there's at least one matching column
  987. // Loop over rows in input result set
  988. LONG iRow; // loop index
  989. switch( m_Header[lDestColumn].dwType )
  990. {
  991. case TYPE_VALUE:
  992. for (iRow = 0; iRow < cSrcRows; iRow++)
  993. {
  994. pResSrc->Get(lRowSrcFirst + iRow, iProp, Prop);
  995. Set(lRowDestFirst + iRow, lDestColumn, Prop.dwValue);
  996. }
  997. break;
  998. case TYPE_STRING:
  999. for (iRow = 0; iRow < cSrcRows; iRow++)
  1000. {
  1001. pResSrc->Get(lRowSrcFirst + iRow, iProp, Prop);
  1002. Set(lRowDestFirst + iRow, lDestColumn, Prop.lpszwData);
  1003. }
  1004. break;
  1005. case TYPE_POINTER:
  1006. for (iRow = 0; iRow < cSrcRows; iRow++)
  1007. {
  1008. pResSrc->Get(lRowSrcFirst + iRow, iProp, Prop);
  1009. Set(lRowDestFirst + iRow, lDestColumn, Prop.lpvData, Prop.cbData);
  1010. }
  1011. break;
  1012. }
  1013. }
  1014. m_cs.Unlock();
  1015. return hr;
  1016. }
  1017. /********************************************************************
  1018. * @method STDMETHODIMP | IITResultSet | Copy |
  1019. * Copies the rows associated with the columns set in the
  1020. * given result set. This method can be used to take a larger result
  1021. * set and reduce it Passing an empty resultset will cause all columns
  1022. * and rows to be added and copied from the source resultset.
  1023. *
  1024. * @parm IITResultSet* | pRSCopy | Result set object containing copied
  1025. * rows.
  1026. *
  1027. * @rvalue E_NOTEXIST | No columns match the input result set
  1028. *
  1029. * @rvalue S_OK | The rows were successfully copied.
  1030. *
  1031. ********************************************************************/
  1032. STDMETHODIMP CITResultSet::Copy(IITResultSet* pRSCopy)
  1033. {
  1034. LONG lColumn;
  1035. HRESULT hr;
  1036. pRSCopy->GetColumnCount(lColumn);
  1037. if (0L == lColumn)
  1038. {
  1039. LONG cCols;
  1040. LONG iCol;
  1041. // add all columns from the source to the dest
  1042. GetColumnCount(cCols);
  1043. for (iCol = 0; iCol < cCols; iCol++)
  1044. {
  1045. PROPID pid;
  1046. DWORD dwType;
  1047. LPVOID lpv;
  1048. DWORD cbSize;
  1049. PRIORITY pri;
  1050. // UNDONE: get rid of this dwType stuff
  1051. // UNDONE: simpler place to put column info (i.e. struct/class)
  1052. GetColumn(iCol, pid, dwType, lpv, cbSize, pri);
  1053. if (dwType == TYPE_VALUE)
  1054. {
  1055. if (FAILED(hr = pRSCopy->Add(pid, (DWORD)0, PRIORITY_NORMAL)))
  1056. return hr;
  1057. }
  1058. else
  1059. {
  1060. if (FAILED(hr= pRSCopy->Add(pid, (LPWSTR)0, PRIORITY_NORMAL)))
  1061. return hr;
  1062. }
  1063. }
  1064. lColumn = cCols;
  1065. }
  1066. PROPID PropID;
  1067. LONG lInputColumn;
  1068. CProperty Prop;
  1069. m_cs.Lock();
  1070. hr = E_NOTEXIST;
  1071. // Loop over columns in output result set
  1072. for (LONG iProp = 0; iProp < lColumn; iProp++)
  1073. {
  1074. // get column in input result set
  1075. pRSCopy->GetColumn(iProp, PropID);
  1076. if (FAILED(GetColumnFromPropID(PropID, lInputColumn)))
  1077. continue;
  1078. hr = S_OK; // there's at least one matching column
  1079. // Loop over rows in input result set
  1080. LONG iRow; // loop index
  1081. switch( m_Header[lInputColumn].dwType )
  1082. {
  1083. case TYPE_VALUE:
  1084. for (iRow = 0; iRow < m_AppendRow; iRow++)
  1085. {
  1086. Get(iRow, lInputColumn, Prop);
  1087. pRSCopy->Set(iRow, iProp, Prop.dwValue);
  1088. }
  1089. break;
  1090. case TYPE_STRING:
  1091. for (iRow = 0; iRow < m_AppendRow; iRow++)
  1092. {
  1093. Get(iRow, lInputColumn, Prop);
  1094. pRSCopy->Set(iRow, iProp, Prop.lpszwData);
  1095. }
  1096. break;
  1097. case TYPE_POINTER:
  1098. for (iRow = 0; iRow < m_AppendRow; iRow++)
  1099. {
  1100. Get(iRow, lInputColumn, Prop);
  1101. pRSCopy->Set(iRow, iProp, Prop.lpvData, Prop.cbData);
  1102. }
  1103. break;
  1104. }
  1105. }
  1106. m_cs.Unlock();
  1107. return hr;
  1108. }
  1109. /********************************************************************
  1110. * @method STDMETHODIMP | IITResultSet | Clear |
  1111. * Frees all memory associated with a result set
  1112. *
  1113. * @rvalue S_OK | The result set was successfully cleared
  1114. *
  1115. * @comm This method can be called to clear a result set without
  1116. * requiring the set to be destroyed before being used again.
  1117. ********************************************************************/
  1118. STDMETHODIMP CITResultSet::Clear()
  1119. {
  1120. LONG iProp;
  1121. m_cs.Lock();
  1122. // Free any column heaps which may have been set.
  1123. for (iProp = 0; iProp < m_cProp; iProp++)
  1124. {
  1125. LPVOID lpvHeap;
  1126. PFNCOLHEAPFREE pfnHeapFree;
  1127. if ((lpvHeap = m_Header[iProp].lpvHeap) != NULL &&
  1128. (pfnHeapFree = m_Header[iProp].pfnHeapFree) != NULL)
  1129. {
  1130. (*pfnHeapFree)(lpvHeap);
  1131. }
  1132. }
  1133. ClearRows();
  1134. m_cProp = 0;
  1135. m_cs.Unlock();
  1136. return S_OK;
  1137. }
  1138. /********************************************************************
  1139. * @method STDMETHODIMP | IITResultSet | ClearRows |
  1140. * Frees all memory associated with a result set, without
  1141. * resetting column information
  1142. *
  1143. * @rvalue S_OK | The result set was successfully cleared
  1144. *
  1145. * @comm This method can be called to clear a result set without
  1146. * requiring the set to be destroyed before being used again.
  1147. ********************************************************************/
  1148. STDMETHODIMP CITResultSet::ClearRows()
  1149. {
  1150. m_cs.Lock();
  1151. // Free page map
  1152. if (m_PageMap)
  1153. {
  1154. delete m_PageMap;
  1155. m_PageMap = NULL;
  1156. }
  1157. // Decommit and release virtual memory
  1158. FreeMem();
  1159. // Reset memory pool
  1160. if (m_pMemPool)
  1161. BlockReset(m_pMemPool);
  1162. // Reset member data
  1163. m_NumberOfPages = 0;
  1164. m_fInit = FALSE;
  1165. m_RowsReserved = 0;
  1166. m_AppendRow = 0;
  1167. m_Chunk = -1;
  1168. m_cs.Unlock();
  1169. return S_OK;
  1170. }
  1171. // Wrapper for VirtualFree(MEM_DECOMMIT) and VirtualFree(MEM_RELEASE)
  1172. HRESULT WINAPI CITResultSet::FreeMem()
  1173. {
  1174. BOOL fRet;
  1175. int iLoop;
  1176. // Decommit result set - remember that it's an array of chunks (of rows)
  1177. // so we have to loop over all the chunks
  1178. // erinfox: bug fix, iLoop <= m_Chunk because m_Chunk is numbered from 0!
  1179. for (iLoop = 0; iLoop <= m_Chunk; iLoop++)
  1180. {
  1181. g_iFreed++;
  1182. fRet = VirtualFree(m_ResultSet[iLoop], m_BytesReserved, MEM_DECOMMIT);
  1183. ITASSERT(TRUE == fRet);
  1184. }
  1185. // Then release it
  1186. for (iLoop = 0; iLoop <= m_Chunk; iLoop++)
  1187. {
  1188. fRet = VirtualFree(m_ResultSet[iLoop], 0, MEM_RELEASE);
  1189. ITASSERT(TRUE == fRet);
  1190. }
  1191. return S_OK;
  1192. }
  1193. STDMETHODIMP CITResultSet::Free()
  1194. {
  1195. return E_NOTIMPL;
  1196. }
  1197. //////////////////////// Asynchronous //////////////////////////////////////
  1198. STDMETHODIMP CITResultSet::IsCompleted()
  1199. {
  1200. return E_NOTIMPL;
  1201. }
  1202. STDMETHODIMP CITResultSet::Cancel()
  1203. {
  1204. return E_NOTIMPL;
  1205. }
  1206. STDMETHODIMP CITResultSet::Pause(BOOL fPause)
  1207. {
  1208. return E_NOTIMPL;
  1209. }
  1210. STDMETHODIMP CITResultSet::GetRowStatus(LONG lRowFirst, LONG cRows, LPROWSTATUS lpRowStatus)
  1211. {
  1212. return E_NOTIMPL;
  1213. }
  1214. STDMETHODIMP CITResultSet::GetColumnStatus(LPCOLUMNSTATUS lpColStatus)
  1215. {
  1216. return E_NOTIMPL;
  1217. }