Leaked source code of windows server 2003
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.

395 lines
10 KiB

  1. //--------------------------------------------------------------------------
  2. // EnumFold.cpp
  3. //--------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "enumfold.h"
  6. //--------------------------------------------------------------------------
  7. // CFOLDER_FETCH
  8. //--------------------------------------------------------------------------
  9. #define CFOLDER_FETCH_MIN 5
  10. #define CFOLDER_FETCH_MID 30
  11. #define CFOLDER_FETCH_MAX 200
  12. //--------------------------------------------------------------------------
  13. // CEnumerateFolders::CEnumerateFolders
  14. //--------------------------------------------------------------------------
  15. CEnumerateFolders::CEnumerateFolders(void)
  16. {
  17. TraceCall("CEnumerateFolders::CEnumerateFolders");
  18. m_cRef = 1;
  19. m_pDB = NULL;
  20. m_fSubscribed = FALSE;
  21. m_idParent = FOLDERID_INVALID;
  22. m_pStream = NULL;
  23. m_cFolders = 0;
  24. m_iFolder = 0;
  25. }
  26. //--------------------------------------------------------------------------
  27. // CEnumerateFolders::~CEnumerateFolders
  28. //--------------------------------------------------------------------------
  29. CEnumerateFolders::~CEnumerateFolders(void)
  30. {
  31. TraceCall("CEnumerateFolders::~CEnumerateFolders");
  32. _FreeFolderArray();
  33. SafeRelease(m_pDB);
  34. }
  35. //--------------------------------------------------------------------------
  36. // CEnumerateFolders::QueryInterface
  37. //--------------------------------------------------------------------------
  38. STDMETHODIMP CEnumerateFolders::QueryInterface(REFIID riid, LPVOID *ppv)
  39. {
  40. // Locals
  41. HRESULT hr=S_OK;
  42. // Stack
  43. TraceCall("CEnumerateFolders::QueryInterface");
  44. // Find IID
  45. if (IID_IUnknown == riid)
  46. *ppv = (IUnknown *)this;
  47. else if (IID_IEnumerateFolders == riid)
  48. *ppv = (IEnumerateFolders *)this;
  49. else
  50. {
  51. *ppv = NULL;
  52. hr = TraceResult(E_NOINTERFACE);
  53. goto exit;
  54. }
  55. // AddRef It
  56. ((IUnknown *)*ppv)->AddRef();
  57. exit:
  58. // Done
  59. return(hr);
  60. }
  61. //--------------------------------------------------------------------------
  62. // CEnumerateFolders::AddRef
  63. //--------------------------------------------------------------------------
  64. STDMETHODIMP_(ULONG) CEnumerateFolders::AddRef(void)
  65. {
  66. TraceCall("CEnumerateFolders::AddRef");
  67. return InterlockedIncrement(&m_cRef);
  68. }
  69. //--------------------------------------------------------------------------
  70. // CEnumerateFolders::Release
  71. //--------------------------------------------------------------------------
  72. STDMETHODIMP_(ULONG) CEnumerateFolders::Release(void)
  73. {
  74. TraceCall("CEnumerateFolders::Release");
  75. LONG cRef = InterlockedDecrement(&m_cRef);
  76. if (0 == cRef)
  77. delete this;
  78. return (ULONG)cRef;
  79. }
  80. //--------------------------------------------------------------------------
  81. // CEnumerateFolders::_FreeFolderArray
  82. //--------------------------------------------------------------------------
  83. HRESULT CEnumerateFolders::_FreeFolderArray(void)
  84. {
  85. // Locals
  86. HRESULT hr=S_OK;
  87. FOLDERINFO Folder;
  88. DWORD cbRead;
  89. DWORD cbSeek;
  90. // Trace
  91. TraceCall("CEnumerateFolders::_FreeFolderArray");
  92. // If we have a stream
  93. if (NULL == m_pStream)
  94. return(S_OK);
  95. // Seek to next folder that should be read
  96. cbSeek = (m_iFolder * sizeof(FOLDERINFO));
  97. // Seek
  98. IF_FAILEXIT(hr = HrStreamSeekSet(m_pStream, cbSeek));
  99. // Read Folder Infos
  100. while (S_OK == m_pStream->Read(&Folder, sizeof(FOLDERINFO), &cbRead) && cbRead)
  101. {
  102. // Free Folder Info
  103. m_pDB->FreeRecord(&Folder);
  104. }
  105. exit:
  106. // Reset
  107. m_cFolders = m_iFolder = 0;
  108. // Free
  109. SafeRelease(m_pStream);
  110. // Done
  111. return(hr);
  112. }
  113. //--------------------------------------------------------------------------
  114. // CEnumerateFolders::Initialize
  115. //--------------------------------------------------------------------------
  116. HRESULT CEnumerateFolders::Initialize(IDatabase *pDB, BOOL fSubscribed,
  117. FOLDERID idParent)
  118. {
  119. // Locals
  120. HRESULT hr=S_OK;
  121. ROWORDINAL iFirstRow;
  122. HLOCK hLock=NULL;
  123. HROWSET hRowset=NULL;
  124. FOLDERINFO Child={0};
  125. FOLDERINFO rgFolder[CFOLDER_FETCH_MAX];
  126. DWORD cWanted=CFOLDER_FETCH_MIN;
  127. DWORD cFetched=0;
  128. DWORD i;
  129. INDEXORDINAL iIndex;
  130. // Trace
  131. TraceCall("CEnumerateFolders::Initialize");
  132. // Invalid Args
  133. Assert(pDB);
  134. // Release Current m_pDB
  135. SafeRelease(m_pDB);
  136. m_pDB = pDB;
  137. m_pDB->AddRef();
  138. // Unlock
  139. IF_FAILEXIT(hr = pDB->Lock(&hLock));
  140. // Free Folder Array
  141. _FreeFolderArray();
  142. // Save Subscribed
  143. m_fSubscribed = fSubscribed;
  144. // Subscribed Stuff
  145. iIndex = (fSubscribed ? IINDEX_SUBSCRIBED : IINDEX_ALL);
  146. // Save parent
  147. m_idParent = idParent;
  148. // Set idParent
  149. Child.idParent = idParent;
  150. // Locate where the first record with idParent
  151. IF_FAILEXIT(hr = m_pDB->FindRecord(iIndex, 1, &Child, &iFirstRow));
  152. // Not Found
  153. if (DB_S_NOTFOUND == hr)
  154. {
  155. hr = S_OK;
  156. goto exit;
  157. }
  158. // Create a Stream
  159. IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&m_pStream));
  160. // Write the Folder....
  161. IF_FAILEXIT(hr = m_pStream->Write(&Child, sizeof(FOLDERINFO), NULL));
  162. // One Folder
  163. m_cFolders++;
  164. // Don't Free Child
  165. Child.pAllocated = NULL;
  166. // Create a Rowset
  167. IF_FAILEXIT(hr = m_pDB->CreateRowset(iIndex, NOFLAGS, &hRowset));
  168. // Seek the rowset to the first row
  169. if (FAILED(m_pDB->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, iFirstRow, NULL)))
  170. {
  171. hr = S_OK;
  172. goto exit;
  173. }
  174. // Loop and fetch all folders...
  175. while (SUCCEEDED(m_pDB->QueryRowset(hRowset, cWanted, (LPVOID *)rgFolder, &cFetched)) && cFetched > 0)
  176. {
  177. // Write the Folder....
  178. IF_FAILEXIT(hr = m_pStream->Write(rgFolder, sizeof(FOLDERINFO) * cFetched, NULL));
  179. // Loop through cFetched
  180. for (i=0; i<cFetched; i++)
  181. {
  182. // Done ?
  183. if (rgFolder[i].idParent != m_idParent)
  184. goto exit;
  185. // Increment Folder Count
  186. m_cFolders++;
  187. }
  188. // Adjust cWanted for Perf.
  189. if (cWanted < CFOLDER_FETCH_MID && m_cFolders >= CFOLDER_FETCH_MID)
  190. cWanted = CFOLDER_FETCH_MID;
  191. if (cWanted < CFOLDER_FETCH_MAX && m_cFolders >= CFOLDER_FETCH_MAX)
  192. cWanted = CFOLDER_FETCH_MAX;
  193. }
  194. exit:
  195. // Commit
  196. if (m_pStream)
  197. {
  198. // Commit
  199. m_pStream->Commit(STGC_DEFAULT);
  200. // Rewind
  201. HrRewindStream(m_pStream);
  202. }
  203. // Close the Rowset
  204. m_pDB->FreeRecord(&Child);
  205. // Close the Rowset
  206. m_pDB->CloseRowset(&hRowset);
  207. // Unlock
  208. m_pDB->Unlock(&hLock);
  209. // Done
  210. return(hr);
  211. }
  212. //--------------------------------------------------------------------------
  213. // CEnumerateFolders::Next
  214. //--------------------------------------------------------------------------
  215. STDMETHODIMP CEnumerateFolders::Next(ULONG cWanted, LPFOLDERINFO prgInfo, ULONG *pcFetched)
  216. {
  217. // Locals
  218. HRESULT hr=S_OK;
  219. DWORD cFetched=0;
  220. DWORD cbRead;
  221. // Trace
  222. TraceCall("CEnumerateFolders::Next");
  223. // Initialize
  224. if (pcFetched)
  225. *pcFetched = 0;
  226. // Get some Records
  227. while (cFetched < cWanted && m_iFolder < m_cFolders)
  228. {
  229. // Read a Folder
  230. IF_FAILEXIT(hr = m_pStream->Read(&prgInfo[cFetched], sizeof(FOLDERINFO), &cbRead));
  231. // Validate
  232. Assert(sizeof(FOLDERINFO) == cbRead && prgInfo[cFetched].idParent == m_idParent);
  233. // Increment m_iFolder
  234. m_iFolder++;
  235. // Increment iFetch
  236. cFetched++;
  237. }
  238. // Initialize
  239. if (pcFetched)
  240. *pcFetched = cFetched;
  241. exit:
  242. // Done
  243. return(cFetched == cWanted) ? S_OK : S_FALSE;
  244. }
  245. //--------------------------------------------------------------------------
  246. // CEnumerateFolders::Skip
  247. //--------------------------------------------------------------------------
  248. STDMETHODIMP CEnumerateFolders::Skip(ULONG cItems)
  249. {
  250. // Locals
  251. HRESULT hr=S_OK;
  252. DWORD i;
  253. FOLDERINFO Folder;
  254. // Trace
  255. TraceCall("CEnumerateFolders::Skip");
  256. // Loop...
  257. for (i=0; i<cItems; i++)
  258. {
  259. // Next
  260. IF_FAILEXIT(hr = Next(1, &Folder, NULL));
  261. // Done
  262. if (S_OK != hr)
  263. break;
  264. }
  265. exit:
  266. // Done
  267. return(hr);
  268. }
  269. //--------------------------------------------------------------------------
  270. // CEnumerateFolders::Reset
  271. //--------------------------------------------------------------------------
  272. STDMETHODIMP CEnumerateFolders::Reset(void)
  273. {
  274. // Locals
  275. HRESULT hr=S_OK;
  276. // Trace
  277. TraceCall("CEnumerateFolders::Reset");
  278. // Initialize MySelf
  279. IF_FAILEXIT(hr = Initialize(m_pDB, m_fSubscribed, m_idParent));
  280. exit:
  281. // Done
  282. return(hr);
  283. }
  284. //--------------------------------------------------------------------------
  285. // CEnumerateFolders::Clone
  286. //--------------------------------------------------------------------------
  287. STDMETHODIMP CEnumerateFolders::Clone(IEnumerateFolders **ppEnum)
  288. {
  289. // Locals
  290. HRESULT hr=S_OK;
  291. CEnumerateFolders *pEnum=NULL;
  292. // Trace
  293. TraceCall("CEnumerateFolders::Clone");
  294. // Allocate a New Enumerator
  295. IF_NULLEXIT(pEnum = new CEnumerateFolders);
  296. // Initialzie
  297. IF_FAILEXIT(hr = pEnum->Initialize(m_pDB, m_fSubscribed, m_idParent));
  298. // Return It
  299. *ppEnum = (IEnumerateFolders *)pEnum;
  300. // Don't Release It
  301. pEnum = NULL;
  302. exit:
  303. // Cleanup
  304. SafeRelease(pEnum);
  305. // Done
  306. return(hr);
  307. }
  308. //--------------------------------------------------------------------------
  309. // CEnumerateFolders::Release
  310. //--------------------------------------------------------------------------
  311. STDMETHODIMP CEnumerateFolders::Count(ULONG *pcItems)
  312. {
  313. // Trace
  314. TraceCall("CEnumerateFolders::Next");
  315. // Return Folder count
  316. *pcItems = m_cFolders;
  317. // Done
  318. return(S_OK);
  319. }