123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <new>
- #include <kopano/platform.h>
- #include <kopano/lockhelper.hpp>
- #include <kopano/ECInterfaceDefs.h>
- #include <mapicode.h>
- #include <mapidefs.h>
- #include <mapitags.h>
- #include <mapiguid.h>
- #include <mapiutil.h>
- #include "Mem.h"
- #include "ECMAPITable.h"
- #include <edkguid.h>
- #include <kopano/ECGuid.h>
- #include <kopano/Util.h>
- #include <kopano/ECDebug.h>
- #include <kopano/ECInterfaceDefs.h>
- ECMAPITable::ECMAPITable(std::string strName, ECNotifyClient *lpNotifyClient, ULONG ulFlags) : ECUnknown("IMAPITable")
- {
- TRACE_MAPI(TRACE_ENTRY, "ECMAPITable::ECMAPITable","");
- this->lpNotifyClient = lpNotifyClient;
-
- if(this->lpNotifyClient)
- this->lpNotifyClient->AddRef();
- this->lpsSortOrderSet = NULL;
- this->lpsPropTags = NULL;
- this->ulFlags = ulFlags;
- this->lpTableOps = NULL;
-
- m_lpSetColumns = NULL;
- m_lpRestrict = NULL;
- m_lpSortTable = NULL;
- m_ulRowCount = 0;
- m_ulFlags = 0;
- m_ulDeferredFlags = 0;
- m_strName = strName;
- }
- HRESULT ECMAPITable::FlushDeferred(LPSRowSet *lppRowSet)
- {
- HRESULT hr;
-
- hr = lpTableOps->HrOpenTable();
- if(hr != hrSuccess)
- return hr;
- // No deferred calls -> nothing to do
- if (!IsDeferred())
- return hr;
-
- hr = lpTableOps->HrMulti(m_ulDeferredFlags, m_lpSetColumns, m_lpRestrict, m_lpSortTable, m_ulRowCount, m_ulFlags, lppRowSet);
- // Reset deferred items
- MAPIFreeBuffer(m_lpSetColumns);
- m_lpSetColumns = NULL;
- MAPIFreeBuffer(m_lpRestrict);
- m_lpRestrict = NULL;
- MAPIFreeBuffer(m_lpSortTable);
- m_lpSortTable = NULL;
- m_ulRowCount = 0;
- m_ulFlags = 0;
- m_ulDeferredFlags = 0;
- return hr;
- }
- BOOL ECMAPITable::IsDeferred()
- {
- return m_lpSetColumns != NULL || m_lpRestrict != NULL ||
- m_lpSortTable != NULL || m_ulRowCount != 0 ||
- m_ulFlags != 0 || m_ulDeferredFlags != 0;
- }
- ECMAPITable::~ECMAPITable()
- {
- TRACE_MAPI(TRACE_ENTRY, "ECMAPITable::~ECMAPITable","");
- // Remove all advises
- auto iterMapInt = m_ulConnectionList.cbegin();
- while (iterMapInt != m_ulConnectionList.cend()) {
- auto iterMapIntDel = iterMapInt;
- ++iterMapInt;
- Unadvise(*iterMapIntDel);
- }
- delete[] this->lpsPropTags;
- MAPIFreeBuffer(m_lpRestrict);
- MAPIFreeBuffer(m_lpSetColumns);
- MAPIFreeBuffer(m_lpSortTable);
- if(lpNotifyClient)
- lpNotifyClient->Release();
- if(lpTableOps)
- lpTableOps->Release(); // closes the table on the server too
- delete[] lpsSortOrderSet;
- }
- HRESULT ECMAPITable::Create(std::string strName, ECNotifyClient *lpNotifyClient, ULONG ulFlags, ECMAPITable **lppECMAPITable)
- {
- auto lpMAPITable = new(std::nothrow) ECMAPITable(strName, lpNotifyClient, ulFlags);
- if (lpMAPITable == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- auto ret = lpMAPITable->QueryInterface(IID_ECMAPITable,
- reinterpret_cast<void **>(lppECMAPITable));
- if (ret != hrSuccess)
- delete lpMAPITable;
- return ret;
- }
- HRESULT ECMAPITable::QueryInterface(REFIID refiid, void **lppInterface)
- {
- REGISTER_INTERFACE2(ECMAPITable, this);
- REGISTER_INTERFACE2(ECUnknown, this);
- REGISTER_INTERFACE2(IMAPITable, &this->m_xMAPITable);
- REGISTER_INTERFACE2(IUnknown, &this->m_xMAPITable);
- REGISTER_INTERFACE3(ISelectUnicode, IUnknown, &this->m_xUnknown);
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- }
- HRESULT ECMAPITable::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError)
- {
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT ECMAPITable::Advise(ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG * lpulConnection)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- if (lpNotifyClient == NULL)
- return MAPI_E_NO_SUPPORT;
- if (lpulConnection == NULL)
- return MAPI_E_INVALID_PARAMETER;
- // FIXME: if a reconnection happens in another thread during the following call, the ulTableId sent here will be incorrect. The reconnection
- // 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
- // table.
- hr = lpNotifyClient->Advise(4, (BYTE *)&lpTableOps->ulTableId, ulEventMask, lpAdviseSink, lpulConnection);
- if(hr != hrSuccess)
- return hr;
- // We lock the connection list separately
- scoped_rlock l_conn(m_hMutexConnectionList);
- m_ulConnectionList.insert(*lpulConnection);
- return hrSuccess;
- }
- HRESULT ECMAPITable::Unadvise(ULONG ulConnection)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- if (lpNotifyClient == NULL)
- return MAPI_E_NO_SUPPORT;
- ulock_rec l_conn(m_hMutexConnectionList);
- m_ulConnectionList.erase(ulConnection);
- l_conn.unlock();
- lpNotifyClient->Unadvise(ulConnection);
- return hr;
- }
- // @fixme Do we need to lock here or just update the status?
- HRESULT ECMAPITable::GetStatus(ULONG *lpulTableStatus, ULONG *lpulTableType)
- {
- HRESULT hr = hrSuccess;
- *lpulTableStatus = TBLSTAT_COMPLETE;
- *lpulTableType = TBLTYPE_DYNAMIC;
- return hr;
- }
- HRESULT ECMAPITable::SetColumns(const SPropTagArray *lpPropTagArray,
- ULONG ulFlags)
- {
- if(lpPropTagArray == NULL || lpPropTagArray->cValues == 0)
- return MAPI_E_INVALID_PARAMETER;
- scoped_rlock lock(m_hLock);
- delete[] this->lpsPropTags;
- lpsPropTags = (LPSPropTagArray) new BYTE[CbNewSPropTagArray(lpPropTagArray->cValues)];
- lpsPropTags->cValues = lpPropTagArray->cValues;
- memcpy(&lpsPropTags->aulPropTag, &lpPropTagArray->aulPropTag, lpPropTagArray->cValues * sizeof(ULONG));
- MAPIFreeBuffer(m_lpSetColumns);
- m_lpSetColumns = NULL;
- HRESULT hr = MAPIAllocateBuffer(CbNewSPropTagArray(lpPropTagArray->cValues), (void **)&m_lpSetColumns);
- if (hr != hrSuccess)
- return hr;
-
- m_lpSetColumns->cValues = lpPropTagArray->cValues;
- memcpy(&m_lpSetColumns->aulPropTag, &lpPropTagArray->aulPropTag, lpPropTagArray->cValues * sizeof(ULONG));
- if (!(ulFlags & TBL_BATCH))
- hr = FlushDeferred();
- return hr;
- }
- HRESULT ECMAPITable::QueryColumns(ULONG ulFlags, LPSPropTagArray *lppPropTagArray)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- // FIXME if the client has done SetColumns, we can handle this
- // call locally instead of querying the server (unless TBL_ALL_COLUMNS has been
- // specified)
- return this->lpTableOps->HrQueryColumns(ulFlags, lppPropTagArray);
- }
- HRESULT ECMAPITable::GetRowCount(ULONG ulFlags, ULONG *lpulCount)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- ULONG ulRow = 0; // discarded
- return this->lpTableOps->HrGetRowCount(lpulCount, &ulRow);
- }
- HRESULT ECMAPITable::SeekRow(BOOKMARK bkOrigin, LONG lRowCount, LONG *lplRowsSought)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if (hr != hrSuccess)
- return hr;
- return this->lpTableOps->HrSeekRow(bkOrigin, lRowCount, lplRowsSought);
- }
- HRESULT ECMAPITable::SeekRowApprox(ULONG ulNumerator, ULONG ulDenominator)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- ULONG ulRows = 0;
- ULONG ulCurrent = 0;
- hr = lpTableOps->HrGetRowCount(&ulRows, &ulCurrent);
- if(hr != hrSuccess)
- return hr;
- return SeekRow(BOOKMARK_BEGINNING, static_cast<ULONG>(static_cast<double>(ulRows) * (static_cast<double>(ulNumerator) / ulDenominator)), NULL);
- }
- HRESULT ECMAPITable::QueryPosition(ULONG *lpulRow, ULONG *lpulNumerator, ULONG *lpulDenominator)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- ULONG ulRows = 0;
- ULONG ulCurrentRow = 0;
- hr = lpTableOps->HrGetRowCount(&ulRows, &ulCurrentRow);
- if(hr != hrSuccess)
- return hr;
- *lpulRow = ulCurrentRow;
- *lpulNumerator = ulCurrentRow;
- *lpulDenominator = (ulRows == 0)?1:ulRows;
- return hr;
- }
- HRESULT ECMAPITable::FindRow(LPSRestriction lpRestriction, BOOKMARK bkOrigin, ULONG ulFlags)
- {
- if (lpRestriction == NULL)
- return MAPI_E_INVALID_PARAMETER;
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return this->lpTableOps->HrFindRow(lpRestriction, bkOrigin, ulFlags);
- }
- HRESULT ECMAPITable::Restrict(LPSRestriction lpRestriction, ULONG ulFlags)
- {
- HRESULT hr = hrSuccess;
- scoped_rlock lock(m_hLock);
- MAPIFreeBuffer(m_lpRestrict);
- if(lpRestriction) {
- if ((hr = MAPIAllocateBuffer(sizeof(SRestriction), (void **)&m_lpRestrict)) != hrSuccess)
- return hr;
-
- hr = Util::HrCopySRestriction(m_lpRestrict, lpRestriction, m_lpRestrict);
- m_ulDeferredFlags &= ~TABLE_MULTI_CLEAR_RESTRICTION;
- } else {
- // setting the restriction to NULL is not the same as not setting the restriction at all
- m_ulDeferredFlags |= TABLE_MULTI_CLEAR_RESTRICTION;
- m_lpRestrict = NULL;
- }
- if (!(ulFlags & TBL_BATCH))
- hr = FlushDeferred();
- return hr;
- }
- HRESULT ECMAPITable::CreateBookmark(BOOKMARK* lpbkPosition)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return this->lpTableOps->CreateBookmark(lpbkPosition);
- }
- HRESULT ECMAPITable::FreeBookmark(BOOKMARK bkPosition)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return this->lpTableOps->FreeBookmark(bkPosition);
- }
- HRESULT ECMAPITable::SortTable(const SSortOrderSet *lpSortCriteria,
- ULONG ulFlags)
- {
- if (lpSortCriteria == NULL)
- return MAPI_E_INVALID_PARAMETER;
- scoped_rlock lock(m_hLock);
- delete[] lpsSortOrderSet;
- lpsSortOrderSet = (LPSSortOrderSet) new BYTE[CbSSortOrderSet(lpSortCriteria)];
- memcpy(lpsSortOrderSet, lpSortCriteria, CbSSortOrderSet(lpSortCriteria));
- MAPIFreeBuffer(m_lpSortTable);
- HRESULT hr = MAPIAllocateBuffer(CbSSortOrderSet(lpSortCriteria),
- reinterpret_cast<void **>(&m_lpSortTable));
- if (hr != hrSuccess)
- return hr;
- memcpy(m_lpSortTable, lpSortCriteria, CbSSortOrderSet(lpSortCriteria));
- if (!(ulFlags & TBL_BATCH))
- hr = FlushDeferred();
- return hr;
- }
- HRESULT ECMAPITable::QuerySortOrder(LPSSortOrderSet *lppSortCriteria)
- {
- LPSSortOrderSet lpSortCriteria = NULL;
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- if(lpsSortOrderSet)
- hr = ECAllocateBuffer(CbSSortOrderSet(lpsSortOrderSet), (void **) &lpSortCriteria);
- else
- hr = ECAllocateBuffer(CbNewSSortOrderSet(0), (void **) &lpSortCriteria);
- if(hr != hrSuccess)
- return hr;
- if(lpsSortOrderSet)
- memcpy(lpSortCriteria, lpsSortOrderSet, CbSSortOrderSet(lpsSortOrderSet));
- else
- memset(lpSortCriteria, 0, CbNewSSortOrderSet(0));
- *lppSortCriteria = lpSortCriteria;
- return hr;
- }
- HRESULT ECMAPITable::Abort()
- {
- scoped_rlock biglock(m_hLock);
- FlushDeferred();
- /*
- * Fixme: sent this call to the server, and breaks the search!
- * OLK 2007 request.
- */
- return S_OK;
- }
- HRESULT ECMAPITable::ExpandRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulRowCount, ULONG ulFlags, LPSRowSet * lppRows, ULONG *lpulMoreRows)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return lpTableOps->HrExpandRow(cbInstanceKey, pbInstanceKey,
- ulRowCount, ulFlags, lppRows, lpulMoreRows);
- }
- HRESULT ECMAPITable::CollapseRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulFlags, ULONG *lpulRowCount)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return lpTableOps->HrCollapseRow(cbInstanceKey, pbInstanceKey, ulFlags,
- lpulRowCount);
- }
- // @todo do we need lock here, currently we do. maybe we must return MAPI_E_TIMEOUT
- HRESULT ECMAPITable::WaitForCompletion(ULONG ulFlags, ULONG ulTimeout, ULONG *lpulTableStatus)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- if(lpulTableStatus)
- *lpulTableStatus = S_OK;
- return hrSuccess;
- }
- HRESULT ECMAPITable::GetCollapseState(ULONG ulFlags, ULONG cbInstanceKey, LPBYTE lpbInstanceKey, ULONG *lpcbCollapseState, LPBYTE *lppbCollapseState)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- return lpTableOps->HrGetCollapseState(lppbCollapseState,
- lpcbCollapseState, lpbInstanceKey, cbInstanceKey);
- }
- HRESULT ECMAPITable::SetCollapseState(ULONG ulFlags, ULONG cbCollapseState, LPBYTE pbCollapseState, BOOKMARK *lpbkLocation)
- {
- scoped_rlock lock(m_hLock);
- HRESULT hr = FlushDeferred();
- if(hr != hrSuccess)
- return hr;
- hr = lpTableOps->HrSetCollapseState(pbCollapseState, cbCollapseState, lpbkLocation);
- if(lpbkLocation)
- *lpbkLocation = BOOKMARK_BEGINNING;
- return hr;
- }
- HRESULT ECMAPITable::HrSetTableOps(WSTableView *lpTableOps, bool fLoad)
- {
- HRESULT hr;
- this->lpTableOps = lpTableOps;
- lpTableOps->AddRef();
- // Open the table on the server, ready for reading ..
- if(fLoad) {
- hr = lpTableOps->HrOpenTable();
- if (hr != hrSuccess)
- return hr;
- }
- lpTableOps->SetReloadCallback(Reload, this);
- return hrSuccess;
- }
- HRESULT ECMAPITable::QueryRows(LONG lRowCount, ULONG ulFlags, LPSRowSet *lppRows)
- {
- HRESULT hr = hrSuccess;
- scoped_rlock lock(m_hLock);
- if(IsDeferred()) {
- m_ulRowCount = lRowCount;
- m_ulFlags = ulFlags;
-
- hr = FlushDeferred(lppRows);
- } else {
-
- // Send the request to the TableOps object, which will send the request to the server.
- hr = this->lpTableOps->HrQueryRows(lRowCount, ulFlags, lppRows);
- }
- return hr;
- }
- HRESULT ECMAPITable::Reload(void *lpParam)
- {
- auto lpThis = static_cast<ECMAPITable *>(lpParam);
- // Locking m_hLock is not allowed here since when we are called, the SOAP transport in lpTableOps
- // will be locked. Since normally m_hLock is locked before SOAP, locking m_hLock *after* SOAP here
- // would be a lock-order violation causing deadlocks.
- scoped_rlock lock(lpThis->m_hMutexConnectionList);
- // The underlying data has been reloaded, therefore we must re-register the advises. This is called
- // after the transport has re-established its state
- for (auto conn_id : lpThis->m_ulConnectionList) {
- HRESULT hr = lpThis->lpNotifyClient->Reregister(conn_id, 4,
- reinterpret_cast<BYTE *>(&lpThis->lpTableOps->ulTableId));
- if(hr != hrSuccess)
- return hr;
- }
- return hrSuccess;
- }
- DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPITable, MAPITable, AddRef, (void))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPITable, MAPITable, Release, (void))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryInterface, (REFIID, refiid), (void **, lppInterface))
- 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))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Unadvise, (ULONG, ulConnection))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetStatus, (ULONG *, lpulTableStatus), (ULONG *, lpulTableType))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QueryColumns, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), GetRowCount, (ULONG, ulFlags), (ULONG *, lpulCount))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), SeekRowApprox, (ULONG, ulNumerator), (ULONG, ulDenominator))
- 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))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Restrict, (LPSRestriction, lpRestriction), (ULONG, ulFlags))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), CreateBookmark, (BOOKMARK *, lpbkPosition))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), FreeBookmark, (BOOKMARK, bkPosition))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), QuerySortOrder, (LPSSortOrderSet *, lppSortCriteria))
- 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))
- DEF_HRMETHOD_EX2(TRACE_MAPI, ECMAPITable, MAPITable, "table=%d name=%s", pThis->lpTableOps->ulTableId, pThis->m_strName.c_str(), Abort, (void))
- 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))
- 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))
- 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))
- 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))
- 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))
|