ECMAPITable.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <new>
  18. #include <kopano/platform.h>
  19. #include <kopano/lockhelper.hpp>
  20. #include <kopano/ECInterfaceDefs.h>
  21. #include <mapicode.h>
  22. #include <mapidefs.h>
  23. #include <mapitags.h>
  24. #include <mapiguid.h>
  25. #include <mapiutil.h>
  26. #include "Mem.h"
  27. #include "ECMAPITable.h"
  28. #include <edkguid.h>
  29. #include <kopano/ECGuid.h>
  30. #include <kopano/Util.h>
  31. #include <kopano/ECDebug.h>
  32. #include <kopano/ECInterfaceDefs.h>
  33. ECMAPITable::ECMAPITable(std::string strName, ECNotifyClient *lpNotifyClient, ULONG ulFlags) : ECUnknown("IMAPITable")
  34. {
  35. TRACE_MAPI(TRACE_ENTRY, "ECMAPITable::ECMAPITable","");
  36. this->lpNotifyClient = lpNotifyClient;
  37. if(this->lpNotifyClient)
  38. this->lpNotifyClient->AddRef();
  39. this->lpsSortOrderSet = NULL;
  40. this->lpsPropTags = NULL;
  41. this->ulFlags = ulFlags;
  42. this->lpTableOps = NULL;
  43. m_lpSetColumns = NULL;
  44. m_lpRestrict = NULL;
  45. m_lpSortTable = NULL;
  46. m_ulRowCount = 0;
  47. m_ulFlags = 0;
  48. m_ulDeferredFlags = 0;
  49. m_strName = strName;
  50. }
  51. HRESULT ECMAPITable::FlushDeferred(LPSRowSet *lppRowSet)
  52. {
  53. HRESULT hr;
  54. hr = lpTableOps->HrOpenTable();
  55. if(hr != hrSuccess)
  56. return hr;
  57. // No deferred calls -> nothing to do
  58. if (!IsDeferred())
  59. return hr;
  60. hr = lpTableOps->HrMulti(m_ulDeferredFlags, m_lpSetColumns, m_lpRestrict, m_lpSortTable, m_ulRowCount, m_ulFlags, lppRowSet);
  61. // Reset deferred items
  62. MAPIFreeBuffer(m_lpSetColumns);
  63. m_lpSetColumns = NULL;
  64. MAPIFreeBuffer(m_lpRestrict);
  65. m_lpRestrict = NULL;
  66. MAPIFreeBuffer(m_lpSortTable);
  67. m_lpSortTable = NULL;
  68. m_ulRowCount = 0;
  69. m_ulFlags = 0;
  70. m_ulDeferredFlags = 0;
  71. return hr;
  72. }
  73. BOOL ECMAPITable::IsDeferred()
  74. {
  75. return m_lpSetColumns != NULL || m_lpRestrict != NULL ||
  76. m_lpSortTable != NULL || m_ulRowCount != 0 ||
  77. m_ulFlags != 0 || m_ulDeferredFlags != 0;
  78. }
  79. ECMAPITable::~ECMAPITable()
  80. {
  81. TRACE_MAPI(TRACE_ENTRY, "ECMAPITable::~ECMAPITable","");
  82. // Remove all advises
  83. auto iterMapInt = m_ulConnectionList.cbegin();
  84. while (iterMapInt != m_ulConnectionList.cend()) {
  85. auto iterMapIntDel = iterMapInt;
  86. ++iterMapInt;
  87. Unadvise(*iterMapIntDel);
  88. }
  89. delete[] this->lpsPropTags;
  90. MAPIFreeBuffer(m_lpRestrict);
  91. MAPIFreeBuffer(m_lpSetColumns);
  92. MAPIFreeBuffer(m_lpSortTable);
  93. if(lpNotifyClient)
  94. lpNotifyClient->Release();
  95. if(lpTableOps)
  96. lpTableOps->Release(); // closes the table on the server too
  97. delete[] lpsSortOrderSet;
  98. }
  99. HRESULT ECMAPITable::Create(std::string strName, ECNotifyClient *lpNotifyClient, ULONG ulFlags, ECMAPITable **lppECMAPITable)
  100. {
  101. auto lpMAPITable = new(std::nothrow) ECMAPITable(strName, lpNotifyClient, ulFlags);
  102. if (lpMAPITable == nullptr)
  103. return MAPI_E_NOT_ENOUGH_MEMORY;
  104. auto ret = lpMAPITable->QueryInterface(IID_ECMAPITable,
  105. reinterpret_cast<void **>(lppECMAPITable));
  106. if (ret != hrSuccess)
  107. delete lpMAPITable;
  108. return ret;
  109. }
  110. HRESULT ECMAPITable::QueryInterface(REFIID refiid, void **lppInterface)
  111. {
  112. REGISTER_INTERFACE2(ECMAPITable, this);
  113. REGISTER_INTERFACE2(ECUnknown, this);
  114. REGISTER_INTERFACE2(IMAPITable, &this->m_xMAPITable);
  115. REGISTER_INTERFACE2(IUnknown, &this->m_xMAPITable);
  116. REGISTER_INTERFACE3(ISelectUnicode, IUnknown, &this->m_xUnknown);
  117. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  118. }
  119. HRESULT ECMAPITable::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError)
  120. {
  121. return MAPI_E_NO_SUPPORT;
  122. }
  123. HRESULT ECMAPITable::Advise(ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG * lpulConnection)
  124. {
  125. scoped_rlock lock(m_hLock);
  126. HRESULT hr = FlushDeferred();
  127. if(hr != hrSuccess)
  128. return hr;
  129. if (lpNotifyClient == NULL)
  130. return MAPI_E_NO_SUPPORT;
  131. if (lpulConnection == NULL)
  132. return MAPI_E_INVALID_PARAMETER;
  133. // FIXME: if a reconnection happens in another thread during the following call, the ulTableId sent here will be incorrect. The reconnection
  134. // code will not yet know about this connection since we don't insert it until later, so you may end up getting an Advise() on completely the wrong
  135. // table.
  136. hr = lpNotifyClient->Advise(4, (BYTE *)&lpTableOps->ulTableId, ulEventMask, lpAdviseSink, lpulConnection);
  137. if(hr != hrSuccess)
  138. return hr;
  139. // We lock the connection list separately
  140. scoped_rlock l_conn(m_hMutexConnectionList);
  141. m_ulConnectionList.insert(*lpulConnection);
  142. return hrSuccess;
  143. }
  144. HRESULT ECMAPITable::Unadvise(ULONG ulConnection)
  145. {
  146. scoped_rlock lock(m_hLock);
  147. HRESULT hr = FlushDeferred();
  148. if(hr != hrSuccess)
  149. return hr;
  150. if (lpNotifyClient == NULL)
  151. return MAPI_E_NO_SUPPORT;
  152. ulock_rec l_conn(m_hMutexConnectionList);
  153. m_ulConnectionList.erase(ulConnection);
  154. l_conn.unlock();
  155. lpNotifyClient->Unadvise(ulConnection);
  156. return hr;
  157. }
  158. // @fixme Do we need to lock here or just update the status?
  159. HRESULT ECMAPITable::GetStatus(ULONG *lpulTableStatus, ULONG *lpulTableType)
  160. {
  161. HRESULT hr = hrSuccess;
  162. *lpulTableStatus = TBLSTAT_COMPLETE;
  163. *lpulTableType = TBLTYPE_DYNAMIC;
  164. return hr;
  165. }
  166. HRESULT ECMAPITable::SetColumns(const SPropTagArray *lpPropTagArray,
  167. ULONG ulFlags)
  168. {
  169. if(lpPropTagArray == NULL || lpPropTagArray->cValues == 0)
  170. return MAPI_E_INVALID_PARAMETER;
  171. scoped_rlock lock(m_hLock);
  172. delete[] this->lpsPropTags;
  173. lpsPropTags = (LPSPropTagArray) new BYTE[CbNewSPropTagArray(lpPropTagArray->cValues)];
  174. lpsPropTags->cValues = lpPropTagArray->cValues;
  175. memcpy(&lpsPropTags->aulPropTag, &lpPropTagArray->aulPropTag, lpPropTagArray->cValues * sizeof(ULONG));
  176. MAPIFreeBuffer(m_lpSetColumns);
  177. m_lpSetColumns = NULL;
  178. HRESULT hr = MAPIAllocateBuffer(CbNewSPropTagArray(lpPropTagArray->cValues), (void **)&m_lpSetColumns);
  179. if (hr != hrSuccess)
  180. return hr;
  181. m_lpSetColumns->cValues = lpPropTagArray->cValues;
  182. memcpy(&m_lpSetColumns->aulPropTag, &lpPropTagArray->aulPropTag, lpPropTagArray->cValues * sizeof(ULONG));
  183. if (!(ulFlags & TBL_BATCH))
  184. hr = FlushDeferred();
  185. return hr;
  186. }
  187. HRESULT ECMAPITable::QueryColumns(ULONG ulFlags, LPSPropTagArray *lppPropTagArray)
  188. {
  189. scoped_rlock lock(m_hLock);
  190. HRESULT hr = FlushDeferred();
  191. if(hr != hrSuccess)
  192. return hr;
  193. // FIXME if the client has done SetColumns, we can handle this
  194. // call locally instead of querying the server (unless TBL_ALL_COLUMNS has been
  195. // specified)
  196. return this->lpTableOps->HrQueryColumns(ulFlags, lppPropTagArray);
  197. }
  198. HRESULT ECMAPITable::GetRowCount(ULONG ulFlags, ULONG *lpulCount)
  199. {
  200. scoped_rlock lock(m_hLock);
  201. HRESULT hr = FlushDeferred();
  202. if(hr != hrSuccess)
  203. return hr;
  204. ULONG ulRow = 0; // discarded
  205. return this->lpTableOps->HrGetRowCount(lpulCount, &ulRow);
  206. }
  207. HRESULT ECMAPITable::SeekRow(BOOKMARK bkOrigin, LONG lRowCount, LONG *lplRowsSought)
  208. {
  209. scoped_rlock lock(m_hLock);
  210. HRESULT hr = FlushDeferred();
  211. if (hr != hrSuccess)
  212. return hr;
  213. return this->lpTableOps->HrSeekRow(bkOrigin, lRowCount, lplRowsSought);
  214. }
  215. HRESULT ECMAPITable::SeekRowApprox(ULONG ulNumerator, ULONG ulDenominator)
  216. {
  217. scoped_rlock lock(m_hLock);
  218. HRESULT hr = FlushDeferred();
  219. if(hr != hrSuccess)
  220. return hr;
  221. ULONG ulRows = 0;
  222. ULONG ulCurrent = 0;
  223. hr = lpTableOps->HrGetRowCount(&ulRows, &ulCurrent);
  224. if(hr != hrSuccess)
  225. return hr;
  226. return SeekRow(BOOKMARK_BEGINNING, static_cast<ULONG>(static_cast<double>(ulRows) * (static_cast<double>(ulNumerator) / ulDenominator)), NULL);
  227. }
  228. HRESULT ECMAPITable::QueryPosition(ULONG *lpulRow, ULONG *lpulNumerator, ULONG *lpulDenominator)
  229. {
  230. scoped_rlock lock(m_hLock);
  231. HRESULT hr = FlushDeferred();
  232. if(hr != hrSuccess)
  233. return hr;
  234. ULONG ulRows = 0;
  235. ULONG ulCurrentRow = 0;
  236. hr = lpTableOps->HrGetRowCount(&ulRows, &ulCurrentRow);
  237. if(hr != hrSuccess)
  238. return hr;
  239. *lpulRow = ulCurrentRow;
  240. *lpulNumerator = ulCurrentRow;
  241. *lpulDenominator = (ulRows == 0)?1:ulRows;
  242. return hr;
  243. }
  244. HRESULT ECMAPITable::FindRow(LPSRestriction lpRestriction, BOOKMARK bkOrigin, ULONG ulFlags)
  245. {
  246. if (lpRestriction == NULL)
  247. return MAPI_E_INVALID_PARAMETER;
  248. scoped_rlock lock(m_hLock);
  249. HRESULT hr = FlushDeferred();
  250. if(hr != hrSuccess)
  251. return hr;
  252. return this->lpTableOps->HrFindRow(lpRestriction, bkOrigin, ulFlags);
  253. }
  254. HRESULT ECMAPITable::Restrict(LPSRestriction lpRestriction, ULONG ulFlags)
  255. {
  256. HRESULT hr = hrSuccess;
  257. scoped_rlock lock(m_hLock);
  258. MAPIFreeBuffer(m_lpRestrict);
  259. if(lpRestriction) {
  260. if ((hr = MAPIAllocateBuffer(sizeof(SRestriction), (void **)&m_lpRestrict)) != hrSuccess)
  261. return hr;
  262. hr = Util::HrCopySRestriction(m_lpRestrict, lpRestriction, m_lpRestrict);
  263. m_ulDeferredFlags &= ~TABLE_MULTI_CLEAR_RESTRICTION;
  264. } else {
  265. // setting the restriction to NULL is not the same as not setting the restriction at all
  266. m_ulDeferredFlags |= TABLE_MULTI_CLEAR_RESTRICTION;
  267. m_lpRestrict = NULL;
  268. }
  269. if (!(ulFlags & TBL_BATCH))
  270. hr = FlushDeferred();
  271. return hr;
  272. }
  273. HRESULT ECMAPITable::CreateBookmark(BOOKMARK* lpbkPosition)
  274. {
  275. scoped_rlock lock(m_hLock);
  276. HRESULT hr = FlushDeferred();
  277. if(hr != hrSuccess)
  278. return hr;
  279. return this->lpTableOps->CreateBookmark(lpbkPosition);
  280. }
  281. HRESULT ECMAPITable::FreeBookmark(BOOKMARK bkPosition)
  282. {
  283. scoped_rlock lock(m_hLock);
  284. HRESULT hr = FlushDeferred();
  285. if(hr != hrSuccess)
  286. return hr;
  287. return this->lpTableOps->FreeBookmark(bkPosition);
  288. }
  289. HRESULT ECMAPITable::SortTable(const SSortOrderSet *lpSortCriteria,
  290. ULONG ulFlags)
  291. {
  292. if (lpSortCriteria == NULL)
  293. return MAPI_E_INVALID_PARAMETER;
  294. scoped_rlock lock(m_hLock);
  295. delete[] lpsSortOrderSet;
  296. lpsSortOrderSet = (LPSSortOrderSet) new BYTE[CbSSortOrderSet(lpSortCriteria)];
  297. memcpy(lpsSortOrderSet, lpSortCriteria, CbSSortOrderSet(lpSortCriteria));
  298. MAPIFreeBuffer(m_lpSortTable);
  299. HRESULT hr = MAPIAllocateBuffer(CbSSortOrderSet(lpSortCriteria),
  300. reinterpret_cast<void **>(&m_lpSortTable));
  301. if (hr != hrSuccess)
  302. return hr;
  303. memcpy(m_lpSortTable, lpSortCriteria, CbSSortOrderSet(lpSortCriteria));
  304. if (!(ulFlags & TBL_BATCH))
  305. hr = FlushDeferred();
  306. return hr;
  307. }
  308. HRESULT ECMAPITable::QuerySortOrder(LPSSortOrderSet *lppSortCriteria)
  309. {
  310. LPSSortOrderSet lpSortCriteria = NULL;
  311. scoped_rlock lock(m_hLock);
  312. HRESULT hr = FlushDeferred();
  313. if(hr != hrSuccess)
  314. return hr;
  315. if(lpsSortOrderSet)
  316. hr = ECAllocateBuffer(CbSSortOrderSet(lpsSortOrderSet), (void **) &lpSortCriteria);
  317. else
  318. hr = ECAllocateBuffer(CbNewSSortOrderSet(0), (void **) &lpSortCriteria);
  319. if(hr != hrSuccess)
  320. return hr;
  321. if(lpsSortOrderSet)
  322. memcpy(lpSortCriteria, lpsSortOrderSet, CbSSortOrderSet(lpsSortOrderSet));
  323. else
  324. memset(lpSortCriteria, 0, CbNewSSortOrderSet(0));
  325. *lppSortCriteria = lpSortCriteria;
  326. return hr;
  327. }
  328. HRESULT ECMAPITable::Abort()
  329. {
  330. scoped_rlock biglock(m_hLock);
  331. FlushDeferred();
  332. /*
  333. * Fixme: sent this call to the server, and breaks the search!
  334. * OLK 2007 request.
  335. */
  336. return S_OK;
  337. }
  338. HRESULT ECMAPITable::ExpandRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulRowCount, ULONG ulFlags, LPSRowSet * lppRows, ULONG *lpulMoreRows)
  339. {
  340. scoped_rlock lock(m_hLock);
  341. HRESULT hr = FlushDeferred();
  342. if(hr != hrSuccess)
  343. return hr;
  344. return lpTableOps->HrExpandRow(cbInstanceKey, pbInstanceKey,
  345. ulRowCount, ulFlags, lppRows, lpulMoreRows);
  346. }
  347. HRESULT ECMAPITable::CollapseRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulFlags, ULONG *lpulRowCount)
  348. {
  349. scoped_rlock lock(m_hLock);
  350. HRESULT hr = FlushDeferred();
  351. if(hr != hrSuccess)
  352. return hr;
  353. return lpTableOps->HrCollapseRow(cbInstanceKey, pbInstanceKey, ulFlags,
  354. lpulRowCount);
  355. }
  356. // @todo do we need lock here, currently we do. maybe we must return MAPI_E_TIMEOUT
  357. HRESULT ECMAPITable::WaitForCompletion(ULONG ulFlags, ULONG ulTimeout, ULONG *lpulTableStatus)
  358. {
  359. scoped_rlock lock(m_hLock);
  360. HRESULT hr = FlushDeferred();
  361. if(hr != hrSuccess)
  362. return hr;
  363. if(lpulTableStatus)
  364. *lpulTableStatus = S_OK;
  365. return hrSuccess;
  366. }
  367. HRESULT ECMAPITable::GetCollapseState(ULONG ulFlags, ULONG cbInstanceKey, LPBYTE lpbInstanceKey, ULONG *lpcbCollapseState, LPBYTE *lppbCollapseState)
  368. {
  369. scoped_rlock lock(m_hLock);
  370. HRESULT hr = FlushDeferred();
  371. if(hr != hrSuccess)
  372. return hr;
  373. return lpTableOps->HrGetCollapseState(lppbCollapseState,
  374. lpcbCollapseState, lpbInstanceKey, cbInstanceKey);
  375. }
  376. HRESULT ECMAPITable::SetCollapseState(ULONG ulFlags, ULONG cbCollapseState, LPBYTE pbCollapseState, BOOKMARK *lpbkLocation)
  377. {
  378. scoped_rlock lock(m_hLock);
  379. HRESULT hr = FlushDeferred();
  380. if(hr != hrSuccess)
  381. return hr;
  382. hr = lpTableOps->HrSetCollapseState(pbCollapseState, cbCollapseState, lpbkLocation);
  383. if(lpbkLocation)
  384. *lpbkLocation = BOOKMARK_BEGINNING;
  385. return hr;
  386. }
  387. HRESULT ECMAPITable::HrSetTableOps(WSTableView *lpTableOps, bool fLoad)
  388. {
  389. HRESULT hr;
  390. this->lpTableOps = lpTableOps;
  391. lpTableOps->AddRef();
  392. // Open the table on the server, ready for reading ..
  393. if(fLoad) {
  394. hr = lpTableOps->HrOpenTable();
  395. if (hr != hrSuccess)
  396. return hr;
  397. }
  398. lpTableOps->SetReloadCallback(Reload, this);
  399. return hrSuccess;
  400. }
  401. HRESULT ECMAPITable::QueryRows(LONG lRowCount, ULONG ulFlags, LPSRowSet *lppRows)
  402. {
  403. HRESULT hr = hrSuccess;
  404. scoped_rlock lock(m_hLock);
  405. if(IsDeferred()) {
  406. m_ulRowCount = lRowCount;
  407. m_ulFlags = ulFlags;
  408. hr = FlushDeferred(lppRows);
  409. } else {
  410. // Send the request to the TableOps object, which will send the request to the server.
  411. hr = this->lpTableOps->HrQueryRows(lRowCount, ulFlags, lppRows);
  412. }
  413. return hr;
  414. }
  415. HRESULT ECMAPITable::Reload(void *lpParam)
  416. {
  417. auto lpThis = static_cast<ECMAPITable *>(lpParam);
  418. // Locking m_hLock is not allowed here since when we are called, the SOAP transport in lpTableOps
  419. // will be locked. Since normally m_hLock is locked before SOAP, locking m_hLock *after* SOAP here
  420. // would be a lock-order violation causing deadlocks.
  421. scoped_rlock lock(lpThis->m_hMutexConnectionList);
  422. // The underlying data has been reloaded, therefore we must re-register the advises. This is called
  423. // after the transport has re-established its state
  424. for (auto conn_id : lpThis->m_ulConnectionList) {
  425. HRESULT hr = lpThis->lpNotifyClient->Reregister(conn_id, 4,
  426. reinterpret_cast<BYTE *>(&lpThis->lpTableOps->ulTableId));
  427. if(hr != hrSuccess)
  428. return hr;
  429. }
  430. return hrSuccess;
  431. }
  432. DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPITable, MAPITable, AddRef, (void))
  433. DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPITable, MAPITable, Release, (void))
  434. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryInterface, (REFIID, refiid), (void **, lppInterface))
  435. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetLastError, (HRESULT, hResult), (ULONG, ulFlags), (LPMAPIERROR *, lppMAPIError))
  436. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Advise, (ULONG, ulEventMask), (LPMAPIADVISESINK, lpAdviseSink), (ULONG *, lpulConnection))
  437. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Unadvise, (ULONG, ulConnection))
  438. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetStatus, (ULONG *, lpulTableStatus), (ULONG *, lpulTableType))
  439. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SetColumns, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags))
  440. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryColumns, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
  441. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetRowCount, (ULONG, ulFlags), (ULONG *, lpulCount))
  442. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SeekRow, (BOOKMARK, bkOrigin), (LONG, lRowCount), (LONG *, lplRowsSought))
  443. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SeekRowApprox, (ULONG, ulNumerator), (ULONG, ulDenominator))
  444. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryPosition, (ULONG *, lpulRow), (ULONG *, lpulNumerator), (ULONG *, lpulDenominator))
  445. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), FindRow, (LPSRestriction, lpRestriction), (BOOKMARK, bkOrigin), (ULONG, ulFlags))
  446. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Restrict, (LPSRestriction, lpRestriction), (ULONG, ulFlags))
  447. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), CreateBookmark, (BOOKMARK *, lpbkPosition))
  448. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), FreeBookmark, (BOOKMARK, bkPosition))
  449. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SortTable, (const SSortOrderSet *, lpSortCriteria), (ULONG, ulFlags))
  450. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QuerySortOrder, (LPSSortOrderSet *, lppSortCriteria))
  451. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryRows, (LONG, lRowCount), (ULONG, ulFlags), (LPSRowSet *, lppRows))
  452. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Abort, (void))
  453. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), ExpandRow, (ULONG, cbInstanceKey), (LPBYTE, pbInstanceKey), (ULONG, ulRowCount), (ULONG, ulFlags), (LPSRowSet *, lppRows), (ULONG *, lpulMoreRows))
  454. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), CollapseRow, (ULONG, cbInstanceKey), (LPBYTE, pbInstanceKey), (ULONG, ulFlags), (ULONG *, lpulRowCount))
  455. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), WaitForCompletion, (ULONG, ulFlags), (ULONG, ulTimeout), (ULONG *, lpulTableStatus))
  456. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetCollapseState, (ULONG, ulFlags), (ULONG, cbInstanceKey), (LPBYTE, lpbInstanceKey), (ULONG *, lpcbCollapseState), (LPBYTE *, lppbCollapseState))
  457. DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SetCollapseState, (ULONG, ulFlags), (ULONG, cbCollapseState), (LPBYTE, pbCollapseState), (BOOKMARK *, lpbkLocation))