I would be happy to but it's not that simple... Oh, well...
Here are two
basic routines that run within the scope of the problem:
(see additional comments below)
//
// List attachments
//
// m_spMessage is declared as CComPtr<IMessage> m_spMessage
//
HRESULT CBrMAPIMessage::GetAttachments( CBrMAPIAttachmentList& aList )
{
ASSERT(IsMessageInitialized());
if( !IsMessageInitialized() ) return OLE_E_BLANK;
CComPtr<IMAPITable> spAttachmentTable;
ULONG nAttachments = 0;
HRESULT hr = m_spMessage -> GetAttachmentTable( 0,
&spAttachmentTable );
ASSERT(spAttachmentTable.p!=NULL);
if( spAttachmentTable.p == NULL ) return FAILURE(hr);
hr = spAttachmentTable -> GetRowCount( 0, &nAttachments);
ASSERT(hr==S_OK);
if( FAILED(hr) ) return hr;
if( !nAttachments ) return S_OK;
//
// Make sure that table is positioned at the begining
//
hr = spAttachmentTable -> SeekRow( BOOKMARK_BEGINNING, 0, NULL);
ASSERT(hr==S_OK);
if( FAILED(hr) ) return hr;
//
// Enum
//
while( nAttachments && SUCCEEDED(hr) )
{
LPSRowSet pRows = NULL;
//
// Try to get all of them at once
//
hr = spAttachmentTable -> QueryRows( nAttachments, 0, &pRows);
ASSERT(hr==S_OK);
ASSERT(pRows!=NULL);
if( FAILED(hr) ) return hr;
if( pRows == NULL ) return FAILURE(hr);
ASSERT(pRows -> cRows!=0);
if( !pRows -> cRows )
{
MAPIFreeBuffer(pRows);
break;
}
for( ULONG nAtt = 0; nAtt < pRows -> cRows; nAtt++ )
{
//
// We will be looking for our PR_ATTACH_NUM property that
// allows us to open attachment object
//
SRow* pRow = pRows -> aRow + nAtt;
LPSPropValue pProps = pRow -> lpProps;
ASSERT(pProps!=NULL);
if( pProps == NULL ) continue;
ASSERT(pRow -> cValues!=0);
for( ULONG nProp = 0; nProp < pRow -> cValues; nProp++ )
{
//
// Look for PR_ATTACH_NUM
//
if( pProps[nProp].ulPropTag != PR_ATTACH_NUM )
continue;
//
// Try to open it
//
CComPtr<IAttach> spAttachment;
HRESULT hrc = m_spMessage -> OpenAttach(
(ULONG)pProps[nProp].Value.l, &IID_IAttachment, 0/*MAPI_BEST_ACCESS*/,
&spAttachment);
REPORTHR(hrc);
ASSERT(spAttachment.p!=NULL);
if( spAttachment.p == NULL ) continue;
//
// Instantiate object and add it to the list
// What gets added here is just attachment info, not
IAttach. All references to IAttach
// will be released as soon as we step out of that
loop...
//
CBrMAPIAttachment* pAttach = NULL;
try
{
CBrMAPIAttachmentObject aObj(spAttachment.p);
pAttach = new CBrMAPIAttachment( &aObj );
aList.push_back(pAttach);
}
catch( ... )
{
DBGREPORTEXCEPTION();
}
break;
}
MAPIFreeBuffer(pProps);
}
nAttachments -= pRows -> cRows;
MAPIFreeBuffer(pRows);
}
return S_OK;
}
//
// Delete an attachment
//
HRESULT CBrMAPIMessage:
eleteAttachment( ULONG nAttachNum )
{
ASSERT(IsMessageInitialized());
if( !IsMessageInitialized() ) return OLE_E_BLANK;
HRESULT hr = m_spMessage -> DeleteAttach( nAttachNum, 0, NULL, 0);
if( SUCCEEDED(hr) )
{
Save();
}
else
{
CBrMAPIMessage aWrk;
if( InitializeCopy( aWrk ) == S_OK )
{
hr = aWrk.m_spMessage -> DeleteAttach( nAttachNum, 0,
NULL, 0);
if( SUCCEEDED(hr) )
{
aWrk.Save();
}
}
}
return hr;
}
So, all together they work like this. First I call GetAttachments to enum
all the attachments for an item.
This works just fine. Then I select some attachments to delete and call
DeleteAttachment passing "number" that
I got from PR_ATTACH_NUM property when enumerating. And that fails.
Everything is going on within the same
instance of CBrMAPIMessage (thus, the same instance of IMessage that this
object holds). Now, the code (in Delete
routine) related to aWrk is my recent experiment. What I've done is I've
created a completely new instance of
IMessage (by getting my message EntryID and opening new item via
IMAPISession:OpenEntry) and (surprise, surprise!)
deleting attachment using that "copy" instance succeeds! But... Although
"DeleteAttach" succeeds, attachment is still
remains in the attachment table.
I'm so completely lost here that "Blair Witch Project" seems just as
innocent as "Cinderella"