Group:  Microsoft Outlook ยป microsoft.public.outlook.thirdpartyutil
Thread: Bad bug when writing RTF directy to an Outlook Item

DotNetBag
.NET Development Newsgroups

HTVi
TV Discussion Newsgroups

Our Hot Pick: Rising Antivirus 2006 - Certified by TUV & Checkmark! Get 10% discount by entering this coupon code: ONDISCOUNT10
Rising Antivirus 2006

Bad bug when writing RTF directy to an Outlook Item
"clc" <crownlog[ at ]comcast.net> 30.05.2006 16:18:23
This is a multi-part message in MIME format.

------=_NextPart_000_0009_01C683E3.254AED00
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Setting:
Outlook 2003 (SP2)
Windows XP (SP2)
VS2005 C++
Outlook Object Modal 11
MAPI

Problem:
Whenever I save RTF directly to the JournalItem using the code below it =
is as if the item is left open and not saved. Two symptoms:
1) Opening and changing the item again using only Outlook Object Model I =
get the error "0xfbc40109 - The operation cannot be performed because =
the message has been changed."
2) Even if no errors occur, the JournalItem is not updated. It is as if =
the items is updated with the new data, but not saved or committed. The =
message still appears to be opened.=20

Please help!
Ben

Code:

If I create an intem in outlook like this (code shortened for =
readability)

// Create the Journalitem in our example and set no other properties =
because we just want a valid EntryID.
_JournalItemPtr pItem pItem =3D (_JournalItemPtr) =
m_pStore->polApp->CreateItem( olJournalItem );
pItem->Save();
pItem->Close(olSave);
pItem =3D NULL;

// Now we use our own routine to get a ptr to the item from Outlook and =
fill in the details of the Item
pItem =3D pFolder->FindItem( pEntry ); // UPDATE
pItem->Start =3D ...mydate
pItem->Subject =3D ...mysubject
pitem->Save()
pItem->Close(olSave)

// We use MAPI to save our RTF code to the same message zbBody is a =
stream to a raw RTF code
hr =3D m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(), =
zbBody);


HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )=20
{
HRESULT hr =3D NOERROR;
BOOL bUpdated =3D false;
LPBYTE lpbMsgID =3D NULL;
LPMESSAGE lppMsg =3D NULL;
LPSTREAM lpRTFCompressed =3D NULL;
LPSTREAM lpRTFStream =3D NULL;
LPSPropValue pPropSuppMask =3D NULL;
ULONG cbWritten =3D 0;
ULONG cbMsgID =3D 0;
ULONG uType =3D 0;
if (!IsHexEntryIDValid(CW2A(szEID)))
return ResultFromScode(E_INVALIDARG);

cbMsgID =3D (ULONG) _tcslen(szEID) / 2;

hr =3D MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
if (FAILED(hr)) return hr;

if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
{
hr =3D ResultFromScode(E_INVALIDARG);
goto Quit;
}
hr =3D m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL, =
MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
if( FAILED(hr) )
goto Quit;

// Call the message's IMAPIProp::OpenProperty method to open the =
PR_RTF_COMPRESSED property,=20
// specifying IID_IStream as the interface identifier and setting =
the MAPI_CREATE flag.
hr =3D lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0, =
MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
if (FAILED(hr))
goto Quit;

hr =3D HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
if (FAILED(hr))
goto Quit;

// Call the WrapCompressedRTFStream function, passing the =
STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF=20
// bit is set in the message store's PR_STORE_SUPPORT_MASK property =
and get IStream pointer for uncompressed RTF,=20
// to which we will write
hr =3D WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY | =
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);

// Call either IStream::Write or IStream::CopyTo to write the =
message text to the stream returned=20
// from WrapCompressedRTFStream. Write the text that was passed to =
the uncompressed RTF strea
hr =3D lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
if (FAILED(hr))
goto Quit;

// Call the Commit and Release methods on the stream returned from =
the OpenProperty method=20
hr =3D lpRTFStream->Commit(STGC_OVERWRITE);
if (FAILED(hr))
goto Quit;

// Sync the RTF and plain text properties of the Message
hr =3D RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
if (FAILED(hr))
goto Quit;

// If the message was updated, save changes to the message
if (bUpdated)
{
hr =3D lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
if( hr =3D=3D MAPI_E_OBJECT_CHANGED )
hr =3D lppMsg->SaveChanges(FORCE_SAVE);
lppMsg->SubmitMessage(0);
}

Quit:
if( pPropSuppMask)=20
MAPIFreeBuffer(pPropSuppMask);

UlRelease(lppMsg);
UlRelease(lpRTFStream);
UlRelease(lpRTFCompressed);
MAPIFreeBuffer(lpbMsgID);

return hr;=20
}



------=_NextPart_000_0009_01C683E3.254AED00
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2900.2873" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY>
<DIV><FONT face=3DArial size=3D2><STRONG>Setting:</STRONG></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Outlook 2003 (SP2)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Windows XP (SP2)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>VS2005 C++</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Outlook Object Modal 11</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>MAPI</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2><STRONG>Problem:</STRONG></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Whenever I save RTF directly to the =
JournalItem=20
using the code below it is as if the item is left open and not saved. =
Two=20
symptoms:</FONT></DIV>
<DIV><FONT size=3D2><FONT face=3DArial>1) Opening and changing the item =
again using=20
only Outlook Object Model I get the error "</FONT><FONT face=3DAri=20
color=3D#ff0000>0xfbc40109 - The operation cannot be performed because =
the message=20
has been changed.<FONT face=3DArial =
color=3D#000000>"</FONT></FONT></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>2) Even if no errors occur, the =
JournalItem is not=20
updated. It is as if the items is updated with the new data, but not =
saved or=20
committed. The message still appears to be opened. </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>Please help!</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>Ben</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT><FONT face=3DArial =
size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2><STRONG>Code:</STRONG></FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>If I create an intem in outlook like =
this (code=20
shortened for readability)</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial color=3D#008000 size=3D2>// Create the =
Journalitem in our=20
example and set no other properties because we just want a valid=20
EntryID.</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2>_JournalItemPtr pItem </FONT><FONT =
face=3DCourier=20
size=3D2>pItem =3D (_JournalItemPtr) m_pStore->polApp->CreateItem( =

olJournalItem );<BR></FONT><FONT face=3DCourier=20
size=3D2>pItem->Save();<BR></FONT><FONT face=3DCourier=20
size=3D2>pItem->Close(olSave);<BR></FONT><FONT face=3DCourier =
size=3D2>pItem =3D=20
NULL;</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2></FONT> </DIV>
<DIV><FONT face=3DCourier size=3D2><FONT face=3DArial color=3D#008000>// =
Now we use our=20
own routine to get a ptr to the item from Outlook and fill in the =
details of the=20
Item</FONT></DIV>
<DIV></FONT><FONT face=3DCourier size=3D2>pItem =3D =
pFolder->FindItem( pEntry ); //=20
UPDATE</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2>pItem->Start =3D =
....mydate</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2>pItem->Subject =3D =
....mysubject</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2>pitem->Save()</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2>pItem->Close(olSave)</FONT></DIV>
<DIV><FONT face=3DCourier size=3D2></FONT> </DIV><FONT =
face=3DCourier size=3D2>
<DIV><FONT face=3DCourier size=3D2><FONT face=3DArial color=3D#008000>// =
We use MAPI to=20
save our RTF code to the same message zbBody is a stream to a raw RTF=20
code<BR></FONT><FONT size=3D2>hr =3D m_pStore->SetMapiItemRTFBody( =
(LPTSTR)=20
pItem->GetEntryID(), zbBody);</DIV>
<DIV></FONT></FONT></FONT><FONT face=3DCourier =
size=3D2></FONT> </DIV>
<DIV><FONT face=3Dcour size=3D2></FONT> </DIV>
<DIV><FONT face=3DCourier size=3D2>HRESULT =
CStore::SetMapiItemRTFBody(LPCTSTR szEID,=20
<FONT color=3D#0000ff>const</FONT> ZBlob& zb ) <BR></FONT><FONT =
face=3DCourier=20
size=3D2>{<BR>    </FONT><FONT face=3DCourier =
size=3D2>HRESULT hr =3D=20
NOERROR;<BR>    </FONT><FONT face=3DCourier size=3D2>BOOL =
bUpdated =3D=20
<FONT color=3D#0000ff>false</FONT>;<BR>    </FONT><FONT=20
face=3DCourier size=3D2>LPBYTE lpbMsgID =3D NULL;<BR>    =
</FONT><FONT=20
face=3DCourier size=3D2>LPMESSAGE lppMsg =3D NULL;<BR>    =
</FONT><FONT=20
face=3DCourier size=3D2>LPSTREAM lpRTFCompressed =3D =
NULL;<BR>   =20
</FONT><FONT face=3DCourier size=3D2>LPSTREAM lpRTFStream =3D=20
NULL;<BR>    </FONT><FONT face=3DCourier =
size=3D2>LPSPropValue=20
pPropSuppMask =3D NULL;<BR>    </FONT><FONT =
face=3DCourier=20
size=3D2>ULONG cbWritten =3D 0;<BR>    ULONG cbMsgID =3D=20
0;<BR>    </FONT><FONT face=3DCourier size=3D2>ULONG =
uType =3D=20
0;</FONT></DIV>
<DIV>
<P><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>   =20
if</FONT> (!IsHexEntryIDValid(CW2A(szEID)))<BR>   =20
    </FONT></FONT><FONT size=3D2><FONT =
face=3DCourier><FONT=20
color=3D#0000ff>return</FONT> =
ResultFromScode(E_INVALIDARG);</FONT></FONT></P>
<P><FONT face=3DCourier size=3D2>    cbMsgID =3D (ULONG) =
_tcslen(szEID)=20
/ 2;</FONT></P>
<P><FONT face=3DCourier size=3D2>    hr =3D =
MAPIAllocateBuffer(=20
cbMsgID, (<FONT color=3D#0000ff>void</FONT> **) &lpbMsgID=20
);<BR>    </FONT><FONT size=3D2><FONT =
face=3DCourier><FONT=20
color=3D#0000ff>if</FONT> (FAILED(hr)) </FONT></FONT><FONT =
size=3D2><FONT=20
face=3DCourier><FONT color=3D#0000ff>return</FONT> hr;</FONT></FONT></P>
<P><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>   =20
if</FONT>( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID)=20
)<BR>    </FONT></FONT><FONT face=3DCourier=20
size=3D2>{<BR>        </FONT><FONT =
face=3DCourier=20
size=3D2>hr =3D ResultFromScode(E_INVALIDARG);<BR>   =20
    </FONT><FONT size=3D2><FONT face=3DCourier><FONT=20
color=3D#0000ff>goto</FONT> Quit;<BR>    =
</FONT></FONT><FONT=20
face=3DCourier size=3D2>}<BR>    </FONT><FONT =
face=3DCourier size=3D2>hr=20
=3D m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,=20
MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *)=20
&lppMsg);<BR>    </FONT><FONT size=3D2><FONT =
face=3DCourier><FONT=20
color=3D#0000ff>if</FONT>( FAILED(hr) )<BR>    =
   =20
</FONT></FONT><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>goto</FONT>=20
Quit;</FONT></FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // Call the=20
message's IMAPIProp::OpenProperty method to open the PR_RTF_COMPRESSED =
property,=20
<BR></FONT></FONT><FONT color=3D#008000><FONT face=3DCourier=20
size=3D2>    // specifying IID_IStream as the interface =
identifier=20
and setting the MAPI_CREATE flag.<BR>    =
</FONT></FONT><FONT=20
face=3DCourier size=3D2>hr =3D =
lppMsg->OpenProperty(PR_RTF_COMPRESSED,=20
&IID_IStream, 0, MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *)=20
&lpRTFCompressed);<BR>    </FONT><FONT size=3D2><FONT =

face=3DCourier><FONT color=3D#0000ff>if</FONT> =
(FAILED(hr))<BR>   =20
    </FONT></FONT><FONT size=3D2><FONT =
face=3DCourier><FONT=20
color=3D#0000ff>goto</FONT> Quit;</FONT></FONT></P>
<P><FONT face=3DCourier size=3D2>    hr =3D =
HrGetOneProp(lppMsg,=20
PR_STORE_SUPPORT_MASK, &pPropSuppMask);<BR>    =
</FONT><FONT=20
size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>if</FONT>=20
(FAILED(hr))<BR>        =
</FONT></FONT><FONT=20
size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>goto</FONT>=20
Quit;</FONT></FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // Call the=20
WrapCompressedRTFStream function, passing the STORE_UNCOMPRESSED_RTF =
flag if the=20
STORE_UNCOMPRESSED_RTF <BR>    </FONT></FONT><FONT=20
color=3D#008000><FONT face=3DCourier size=3D2>// bit is set in the =
message store's=20
PR_STORE_SUPPORT_MASK property and get IStream pointer for uncompressed =
RTF,=20
<BR>    </FONT></FONT><FONT color=3D#008000><FONT =
face=3DCourier=20
size=3D2>// to which we will write<BR>    =
</FONT></FONT><FONT=20
face=3DCourier size=3D2>hr =3D WrapCompressedRTFStream(lpRTFCompressed, =
MAPI_MODIFY |=20
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF),=20
&lpRTFStream);</FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // Call=20
either IStream::Write or IStream::CopyTo to write the message text to =
the stream=20
returned <BR>    </FONT></FONT><FONT =
color=3D#008000><FONT=20
face=3DCourier size=3D2>// from WrapCompressedRTFStream. Write the text =
that was=20
passed to the uncompressed RTF=20
strea<BR>    </FONT></FONT><FONT face=3DCourier =
size=3D2>hr =3D=20
lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten=20
);<BR>    </FONT><FONT size=3D2><FONT =
face=3DCourier><FONT=20
color=3D#0000ff>if</FONT> (FAILED(hr))<BR>    =
   =20
</FONT></FONT><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>goto</FONT>=20
Quit;</FONT></FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // Call the=20
Commit and Release methods on the stream returned from the OpenProperty =
method=20
<BR>    </FONT></FONT><FONT face=3DCourier size=3D2>hr =
=3D=20
lpRTFStream->Commit(STGC_OVERWRITE);<BR>    =
</FONT><FONT=20
size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>if</FONT>=20
(FAILED(hr))<BR>        =
</FONT></FONT><FONT=20
size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>goto</FONT>=20
Quit;</FONT></FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // Sync the=20
RTF and plain text properties of the Message<BR>   =20
</FONT></FONT><FONT face=3DCourier size=3D2>hr =3D RTFSync(lppMsg,=20
RTF_SYNC_RTF_CHANGED, &bUpdated);<BR>    </FONT><FONT =

size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>if</FONT>=20
(FAILED(hr))<BR>        =
</FONT></FONT><FONT=20
size=3D2><FONT face=3DCourier><FONT color=3D#0000ff>goto</FONT>=20
Quit;</FONT></FONT></P>
<P><FONT color=3D#008000><FONT face=3DCourier =
size=3D2>    // If the=20
message was updated, save changes to the message<BR>   =20
</FONT></FONT><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>if</FONT>=20
(bUpdated)<BR>    </FONT></FONT><FONT face=3DCourier=20
size=3D2>{<BR></FONT><FONT size=3D2><FONT=20
face=3DCourier>        hr =3D=20
lppMsg->SaveChanges(0); <FONT color=3D#008000>//=20
KEEP_OPEN_READWRITE);<BR>       =20
</FONT></FONT></FONT><FONT size=3D2><FONT face=3DCourier><FONT=20
color=3D#0000ff>if</FONT>( hr =3D=3D MAPI_E_OBJECT_CHANGED =
)<BR>   =20
        </FONT></FONT><FONT face=3DCourier =
size=3D2>hr=20
=3D=20
lppMsg->SaveChanges(FORCE_SAVE);<BR>     &nbs=
p;  </FONT><FONT=20
face=3DCourier =
size=3D2>lppMsg->SubmitMessage(0);<BR>   =20
</FONT><FONT face=3DCourier size=3D2>}</FONT></P>
<P><FONT face=3DCourier size=3D2>Quit:<BR></FONT><FONT size=3D2><FONT=20
face=3DCourier><FONT color=3D#0000ff>    if</FONT>( =
pPropSuppMask)=20
<BR>        </FONT></FONT><FONT =
face=3DCourier=20
size=3D2>MAPIFreeBuffer(pPropSuppMask);</FONT></P>
<P><FONT face=3DCourier size=3D2>   =20
UlRelease(lppMsg);<BR></FONT><FONT face=3DCourier =
size=3D2>   =20
UlRelease(lpRTFStream);<BR>    </FONT><FONT =
face=3DCourier=20
size=3D2>UlRelease(lpRTFCompressed);<BR>    </FONT><FONT=20
face=3DCourier size=3D2>MAPIFreeBuffer(lpbMsgID);</FONT></P>
<P><FONT size=3D2><FONT face=3DCourier><FONT =
color=3D#0000ff>   =20
return</FONT> hr; <BR></FONT></FONT><FONT face=3DCourier =
size=3D2>}</FONT></P>
<P><FONT face=3DCourier size=3D2></FONT> </P></DIV></BODY></HTML>

------=_NextPart_000_0009_01C683E3.254AED00--

Re: Bad bug when writing RTF directy to an Outlook Item
"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> 30.05.2006 18:50:06
Do not reopen the message using IMsgStore::OpenEntry. You can retrieve
IMessage from the Outlook Object Model using the JournalItem.MAPIOBJECT
property.
Why do you call IMessage::SubmitMessage()?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

"clc" <crownlog[ at ]comcast.net> wrote in message
news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
Setting:
Outlook 2003 (SP2)
Windows XP (SP2)
VS2005 C++
Outlook Object Modal 11
MAPI

Problem:
Whenever I save RTF directly to the JournalItem using the code below it is
as if the item is left open and not saved. Two symptoms:
1) Opening and changing the item again using only Outlook Object Model I get
the error "0xfbc40109 - The operation cannot be performed because the
message has been changed."
2) Even if no errors occur, the JournalItem is not updated. It is as if the
items is updated with the new data, but not saved or committed. The message
still appears to be opened.

Please help!
Ben

Code:

If I create an intem in outlook like this (code shortened for readability)

// Create the Journalitem in our example and set no other properties because
we just want a valid EntryID.
_JournalItemPtr pItem pItem = (_JournalItemPtr)
m_pStore->polApp->CreateItem( olJournalItem );
pItem->Save();
pItem->Close(olSave);
pItem = NULL;

// Now we use our own routine to get a ptr to the item from Outlook and fill
in the details of the Item
pItem = pFolder->FindItem( pEntry ); // UPDATE
pItem->Start = ...mydate
pItem->Subject = ...mysubject
pitem->Save()
pItem->Close(olSave)

// We use MAPI to save our RTF code to the same message zbBody is a stream
to a raw RTF code
hr = m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(), zbBody);


HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
{
HRESULT hr = NOERROR;
BOOL bUpdated = false;
LPBYTE lpbMsgID = NULL;
LPMESSAGE lppMsg = NULL;
LPSTREAM lpRTFCompressed = NULL;
LPSTREAM lpRTFStream = NULL;
LPSPropValue pPropSuppMask = NULL;
ULONG cbWritten = 0;
ULONG cbMsgID = 0;
ULONG uType = 0;
if (!IsHexEntryIDValid(CW2A(szEID)))
return ResultFromScode(E_INVALIDARG);
cbMsgID = (ULONG) _tcslen(szEID) / 2;
hr = MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
if (FAILED(hr)) return hr;
if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
{
hr = ResultFromScode(E_INVALIDARG);
goto Quit;
}
hr = m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,
MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
if( FAILED(hr) )
goto Quit;
// Call the message's IMAPIProp::OpenProperty method to open the
PR_RTF_COMPRESSED property,
// specifying IID_IStream as the interface identifier and setting the
MAPI_CREATE flag.
hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
if (FAILED(hr))
goto Quit;
hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
if (FAILED(hr))
goto Quit;
// Call the WrapCompressedRTFStream function, passing the
STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
// bit is set in the message store's PR_STORE_SUPPORT_MASK property and
get IStream pointer for uncompressed RTF,
// to which we will write
hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
// Call either IStream::Write or IStream::CopyTo to write the message
text to the stream returned
// from WrapCompressedRTFStream. Write the text that was passed to the
uncompressed RTF strea
hr = lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
if (FAILED(hr))
goto Quit;
// Call the Commit and Release methods on the stream returned from the
OpenProperty method
hr = lpRTFStream->Commit(STGC_OVERWRITE);
if (FAILED(hr))
goto Quit;
// Sync the RTF and plain text properties of the Message
hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
if (FAILED(hr))
goto Quit;
// If the message was updated, save changes to the message
if (bUpdated)
{
hr = lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
if( hr == MAPI_E_OBJECT_CHANGED )
hr = lppMsg->SaveChanges(FORCE_SAVE);
lppMsg->SubmitMessage(0);
}
Quit:
if( pPropSuppMask)
MAPIFreeBuffer(pPropSuppMask);
UlRelease(lppMsg);
UlRelease(lpRTFStream);
UlRelease(lpRTFCompressed);
MAPIFreeBuffer(lpbMsgID);
return hr;
}


Re: Bad bug when writing RTF directy to an Outlook Item
"clc" <crownlog[ at ]comcast.net> 31.05.2006 16:43:47
This is a multi-part message in MIME format.

------=_NextPart_000_000A_01C684AF.DDE31D70
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Dmitry,=20

It didn't even occur to me to use the MAPIOBJECT and it DID solve part =
of the problem.=20

Now the message body is updated correctly with raw RTF text as expected =
and it correctly shows up in the Journal within outlook both in =
Autopreview mode and in the reading pane. But the changes are not =
reflected when I open the actual message which is really weird. I've =
modified the my code to the following shortened version.=20

// Create the Journalitem in our example and set no other properties =
because we just want a valid EntryID.
_JournalItemPtr pItem pItem =3D (_JournalItemPtr)=20
m_pStore->polApp->CreateItem( olJournalItem );
pItem->Save();
pItem->Close(olSave);
pItem =3D NULL;
=20
// Now we use our own routine to get a ptr to the item from Outlook and =
fill in the details of the Item
pItem =3D pFolder->FindItem( pEntry ); // UPDATE

pItem->Start =3D ...mydate

pItem->Subject =3D ...mysubject

// Write RTF body
BOOL bUpdated =3D false;
LPMESSAGE lppMsg =3D NULL;
LPSTREAM lpRTFCompressed =3D NULL;
LPSTREAM lpRTFStream =3D NULL;
LPSPropValue pPropSuppMask =3D NULL;
ULONG cbWritten =3D 0;
ULONG uType =3D 0;

IUnknown* pUnk =3D pItem->GetMAPIOBJECT();
hr =3D pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);

// Call the message's IMAPIProp::OpenProperty method to open the =
PR_RTF_COMPRESSED property,=20
// specifying IID_IStream as the interface identifier and setting =
the MAPI_CREATE flag.
hr =3D lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0, =
MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
if (FAILED(hr))
goto Quit;

hr =3D HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
if (FAILED(hr))
goto Quit;

// Call the WrapCompressedRTFStream function, passing the =
STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF=20
// bit is set in the message store's PR_STORE_SUPPORT_MASK property =
and get IStream pointer for uncompressed RTF,=20
// to which we will write
hr =3D WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY | =
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);

// Call either IStream::Write or IStream::CopyTo to write the =
message text to the stream returned=20
// from WrapCompressedRTFStream. Write the text that was passed to =
the uncompressed RTF strea
hr =3D lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(), =
&cbWritten );
if (FAILED(hr))
goto Quit;

// Call the Commit and Release methods on the stream returned from =
the OpenProperty method=20
hr =3D lpRTFStream->Commit(STGC_OVERWRITE);
if (FAILED(hr))
goto Quit;

// Sync the RTF and plain text properties of the Message
hr =3D RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
if (FAILED(hr))
goto Quit;

// If the message was updated, save changes to the message
if (bUpdated)
hr =3D lppMsg->SaveChanges(KEEP_OPEN_READWRITE);

Quit:
if( pPropSuppMask)=20
MAPIFreeBuffer(pPropSuppMask);
UlRelease(lppMsg);
UlRelease(lpRTFStream);
UlRelease(lpRTFCompressed);
UlRelease(pUnk);
// Done writing RTF body

pitem->Save();
pItem->Close(olSave);
pItem =3D NULL


"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message =
news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text]
> Do not reopen the message using IMsgStore::OpenEntry. You can retrieve =

> IMessage from the Outlook Object Model using the =
JournalItem.MAPIOBJECT=20
> property.
> Why do you call IMessage::SubmitMessage()?
>=20
> Dmitry Streblechenko (MVP)
> http://www.dimastr.com/
> OutlookSpy - Outlook, CDO
> and MAPI Developer Tool
>=20
> "clc" <crownlog[ at ]comcast.net> wrote in message=20
> news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
> Setting:
> Outlook 2003 (SP2)
> Windows XP (SP2)
> VS2005 C++
> Outlook Object Modal 11
> MAPI
>=20
> Problem:
> Whenever I save RTF directly to the JournalItem using the code below =
it is=20
> as if the item is left open and not saved. Two symptoms:
> 1) Opening and changing the item again using only Outlook Object Model =
I get=20
> the error "0xfbc40109 - The operation cannot be performed because the=20
> message has been changed."
> 2) Even if no errors occur, the JournalItem is not updated. It is as =
if the=20
> items is updated with the new data, but not saved or committed. The =
message=20
> still appears to be opened.
>=20
> Please help!
> Ben
>=20
> Code:
>=20
> If I create an intem in outlook like this (code shortened for =
readability)
>=20
> // Create the Journalitem in our example and set no other properties =
because=20
> we just want a valid EntryID.
> _JournalItemPtr pItem pItem =3D (_JournalItemPtr)=20
> m_pStore->polApp->CreateItem( olJournalItem );
> pItem->Save();
> pItem->Close(olSave);
> pItem =3D NULL;
>=20
> // Now we use our own routine to get a ptr to the item from Outlook =
and fill=20
> in the details of the Item
> pItem =3D pFolder->FindItem( pEntry ); // UPDATE
> pItem->Start =3D ...mydate
> pItem->Subject =3D ...mysubject
> pitem->Save()
> pItem->Close(olSave)
>=20
> // We use MAPI to save our RTF code to the same message zbBody is a =
stream=20
> to a raw RTF code
> hr =3D m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(), =
zbBody);
>=20
>=20
> HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
> {
> HRESULT hr =3D NOERROR;
> BOOL bUpdated =3D false;
> LPBYTE lpbMsgID =3D NULL;
> LPMESSAGE lppMsg =3D NULL;
> LPSTREAM lpRTFCompressed =3D NULL;
> LPSTREAM lpRTFStream =3D NULL;
> LPSPropValue pPropSuppMask =3D NULL;
> ULONG cbWritten =3D 0;
> ULONG cbMsgID =3D 0;
> ULONG uType =3D 0;
> if (!IsHexEntryIDValid(CW2A(szEID)))
> return ResultFromScode(E_INVALIDARG);
> cbMsgID =3D (ULONG) _tcslen(szEID) / 2;
> hr =3D MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
> if (FAILED(hr)) return hr;
> if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
> {
> hr =3D ResultFromScode(E_INVALIDARG);
> goto Quit;
> }
> hr =3D m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL, =

> MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
> if( FAILED(hr) )
> goto Quit;
> // Call the message's IMAPIProp::OpenProperty method to open the=20
> PR_RTF_COMPRESSED property,
> // specifying IID_IStream as the interface identifier and setting =
the=20
> MAPI_CREATE flag.
> hr =3D lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,=20
> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
> if (FAILED(hr))
> goto Quit;
> hr =3D HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
> if (FAILED(hr))
> goto Quit;
> // Call the WrapCompressedRTFStream function, passing the=20
> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
> // bit is set in the message store's PR_STORE_SUPPORT_MASK property =
and=20
> get IStream pointer for uncompressed RTF,
> // to which we will write
> hr =3D WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |=20
> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
> // Call either IStream::Write or IStream::CopyTo to write the =
message=20
> text to the stream returned
> // from WrapCompressedRTFStream. Write the text that was passed to =
the=20
> uncompressed RTF strea
> hr =3D lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
> if (FAILED(hr))
> goto Quit;
> // Call the Commit and Release methods on the stream returned from =
the=20
> OpenProperty method
> hr =3D lpRTFStream->Commit(STGC_OVERWRITE);
> if (FAILED(hr))
> goto Quit;
> // Sync the RTF and plain text properties of the Message
> hr =3D RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
> if (FAILED(hr))
> goto Quit;
> // If the message was updated, save changes to the message
> if (bUpdated)
> {
> hr =3D lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
> if( hr =3D=3D MAPI_E_OBJECT_CHANGED )
> hr =3D lppMsg->SaveChanges(FORCE_SAVE);
> lppMsg->SubmitMessage(0);
> }
> Quit:
> if( pPropSuppMask)
> MAPIFreeBuffer(pPropSuppMask);
> UlRelease(lppMsg);
> UlRelease(lpRTFStream);
> UlRelease(lpRTFCompressed);
> MAPIFreeBuffer(lpbMsgID);
> return hr;
> }=20
>=20
>
------=_NextPart_000_000A_01C684AF.DDE31D70
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2900.2873" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY>
<DIV><FONT face=3DArial size=3D2>Dmitry, </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>It didn't even occur to me to use the =
MAPIOBJECT=20
and it DID solve part of the problem. </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>Now the message body is updated =
correctly with raw=20
RTF text as expected and it correctly shows up in the Journal within =
outlook=20
both in Autopreview mode and in the reading pane. But the changes are =
not=20
reflected when I open the actual message which is really weird. I've =
modified=20
the my code to the following shortened version. </FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>// Create the Journalitem in our =
example and set no=20
other properties because we just want a valid =
EntryID.<BR>_JournalItemPtr pItem=20
pItem =3D (_JournalItemPtr) <BR>m_pStore->polApp->CreateItem( =
olJournalItem=20
);<BR>pItem->Save();<BR>pItem->Close(olSave);<BR>pItem =3D=20
NULL;<BR> <BR>// Now we use our own routine to get a ptr to the =
item from=20
Outlook and fill  in the details of the Item<BR>pItem =3D=20
pFolder->FindItem( pEntry ); // UPDATE<BR></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>pItem->Start =3D =
....mydate<BR></FONT></DIV>
<DIV><FONT face=3DArial size=3D2>pItem->Subject =3D =
....mysubject</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial color=3D#0000ff size=3D2>// Write RTF =
body</FONT></DIV>
<DIV>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    BOOL =
bUpdated =3D=20
false;<BR>    </FONT><FONT face=3DArial color=3D#0000ff=20
size=3D2>LPMESSAGE lppMsg =3D NULL;<BR>    </FONT><FONT =
face=3DArial=20
color=3D#0000ff size=3D2>LPSTREAM lpRTFCompressed =3D =
NULL;<BR>   =20
</FONT><FONT face=3DArial color=3D#0000ff size=3D2>LPSTREAM lpRTFStream =
=3D=20
NULL;<BR>    </FONT><FONT face=3DArial color=3D#0000ff=20
size=3D2>LPSPropValue pPropSuppMask =3D NULL;<BR>    =
</FONT><FONT=20
color=3D#0000ff><FONT face=3DArial size=3D2>ULONG cbWritten =3D =
0;<BR>   =20
</FONT><FONT face=3DArial size=3D2>ULONG uType =3D 0;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    =
</FONT><FONT=20
color=3D#0000ff><FONT face=3DArial size=3D2>IUnknown* pUnk =3D=20
pItem->GetMAPIOBJECT();<BR>    </FONT><FONT =
face=3DArial=20
size=3D2>hr =3D pUnk->QueryInterface(IID_IMessage, (void**)=20
&lppMsg);</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    =
</FONT><FONT=20
face=3DArial color=3D#0000ff size=3D2>// Call the message's =
IMAPIProp::OpenProperty=20
method to open the PR_RTF_COMPRESSED property, <BR>   =20
</FONT><FONT face=3DArial color=3D#0000ff size=3D2>// specifying =
IID_IStream as the=20
interface identifier and setting the MAPI_CREATE =
flag.<BR>   =20
</FONT><FONT face=3DArial color=3D#0000ff size=3D2>hr =3D=20
lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0, =
MAPI_MODIFY |=20
MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);<BR>   =20
</FONT><FONT color=3D#0000ff><FONT face=3DArial size=3D2>if=20
(FAILED(hr))<BR>        </FONT><FONT =
face=3DArial=20
size=3D2>goto Quit;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    hr =3D =

HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK,=20
&pPropSuppMask);<BR>    </FONT><FONT =
color=3D#0000ff><FONT=20
face=3DArial size=3D2>if (FAILED(hr))<BR>    =
   =20
</FONT><FONT face=3DArial size=3D2>goto Quit;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    // =
Call the=20
WrapCompressedRTFStream function, passing the STORE_UNCOMPRESSED_RTF =
flag if the=20
STORE_UNCOMPRESSED_RTF <BR>    </FONT><FONT face=3DArial=20
color=3D#0000ff size=3D2>// bit is set in the message store's =
PR_STORE_SUPPORT_MASK=20
property and get IStream pointer for uncompressed RTF, =
<BR>   =20
</FONT><FONT color=3D#0000ff><FONT face=3DArial size=3D2>// to which we =
will=20
write<BR>    </FONT><FONT face=3DArial size=3D2>hr =3D=20
WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |=20
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF),=20
&lpRTFStream);</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    // =
Call either=20
IStream::Write or IStream::CopyTo to write the message text to the =
stream=20
returned <BR>    </FONT><FONT face=3DArial =
color=3D#0000ff size=3D2>//=20
from WrapCompressedRTFStream. Write the text that was passed to the =
uncompressed=20
RTF strea<BR>    </FONT><FONT face=3DArial =
color=3D#0000ff size=3D2>hr=20
=3D lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(), =
&cbWritten=20
);<BR>    </FONT><FONT color=3D#0000ff><FONT face=3DArial =
size=3D2>if=20
(FAILED(hr))<BR>        </FONT><FONT =
face=3DArial=20
size=3D2>goto Quit;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    // =
Call the Commit=20
and Release methods on the stream returned from the OpenProperty method=20
<BR>    </FONT><FONT face=3DArial color=3D#0000ff =
size=3D2>hr =3D=20
lpRTFStream->Commit(STGC_OVERWRITE);<BR>    =
</FONT><FONT=20
color=3D#0000ff><FONT face=3DArial size=3D2>if =
(FAILED(hr))<BR>   =20
    </FONT><FONT face=3DArial size=3D2>goto =
Quit;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    // =
Sync the RTF and=20
plain text properties of the Message<BR>    </FONT><FONT=20
face=3DArial color=3D#0000ff size=3D2>hr =3D RTFSync(lppMsg, =
RTF_SYNC_RTF_CHANGED,=20
&bUpdated);<BR>    </FONT><FONT color=3D#0000ff><FONT =

face=3DArial size=3D2>if (FAILED(hr))<BR>    =
   =20
</FONT><FONT face=3DArial size=3D2>goto Quit;</FONT></FONT></P>
<P><FONT face=3DArial color=3D#0000ff size=3D2>    // If =
the message=20
was updated, save changes to the message<BR>    =
</FONT><FONT=20
face=3DArial color=3D#0000ff size=3D2>if =
(bUpdated)<BR>   =20
    </FONT><FONT face=3DArial color=3D#0000ff size=3D2>hr =
=3D=20
lppMsg->SaveChanges(KEEP_OPEN_READWRITE);<BR><BR>   =20
</FONT><FONT face=3DArial color=3D#0000ff =
size=3D2>Quit:<BR>   =20
    </FONT><FONT face=3DArial color=3D#0000ff =
size=3D2>if(=20
pPropSuppMask) <BR>        =
   =20
</FONT><FONT face=3DArial color=3D#0000ff=20
size=3D2>MAPIFreeBuffer(pPropSuppMask);<BR>    =
   =20
</FONT><FONT face=3DArial color=3D#0000ff=20
size=3D2>UlRelease(lppMsg);<BR>        =
</FONT><FONT=20
face=3DArial color=3D#0000ff =
size=3D2>UlRelease(lpRTFStream);<BR>   =20
    </FONT><FONT face=3DArial color=3D#0000ff=20
size=3D2>UlRelease(lpRTFCompressed);<BR>    =
   =20
</FONT><FONT color=3D#0000ff><FONT face=3DArial=20
size=3D2>UlRelease(pUnk);<BR></FONT><FONT face=3DArial size=3D2>// Done =
writing RTF=20
body</FONT></FONT></P></DIV>
<DIV><FONT face=3DArial=20
size=3D2>pitem->Save();<BR>pItem->Close(olSave);</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>pItem =3D NULL<BR></DIV></FONT>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>"Dmitry Streblechenko" <</FONT><A=20
href=3D"mailto:dmitry[ at ]dimastr.com"><FONT face=3DArial=20
size=3D2>dmitry[ at ]dimastr.com</FONT></A><FONT face=3DArial size=3D2>> =
wrote in=20
message </FONT><A =
href=3D"news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl"><FONT=20
face=3DArial =
size=3D2>news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl</FONT></A><FONT=20
face=3DArial size=3D2>...</FONT></DIV><FONT face=3DArial size=3D2>> =
Do not reopen the=20
message using IMsgStore::OpenEntry. You can retrieve <BR>> IMessage =
from the=20
Outlook Object Model using the JournalItem.MAPIOBJECT <BR>> =
property.<BR>>=20
Why do you call IMessage::SubmitMessage()?<BR>> <BR>> Dmitry =
Streblechenko=20
(MVP)<BR>> </FONT><A href=3D"http://www.dimastr.com/"><FONT =
face=3DArial=20
size=3D2>http://www.dimastr.com/</FONT></A><BR><FONT face=3DArial =
size=3D2>>=20
OutlookSpy  - Outlook, CDO<BR>> and MAPI Developer Tool<BR>> =
<BR>>=20
"clc" <</FONT><A href=3D"mailto:crownlog[ at ]comcast.net"><FONT =
face=3DArial=20
size=3D2>crownlog[ at ]comcast.net</FONT></A><FONT face=3DArial size=3D2>> =
wrote in=20
message <BR>> </FONT><A=20
href=3D"news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl"><FONT face=3DArial=20
size=3D2>news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl</FONT></A><FONT =
face=3DArial=20
size=3D2>...<BR>> Setting:<BR>> Outlook 2003 (SP2)<BR>> Windows =
XP=20
(SP2)<BR>> VS2005 C++<BR>> Outlook Object Modal 11<BR>> =
MAPI<BR>>=20
<BR>> Problem:<BR>> Whenever I save RTF directly to the =
JournalItem using=20
the code below it is <BR>> as if the item is left open and not saved. =
Two=20
symptoms:<BR>> 1) Opening and changing the item again using only =
Outlook=20
Object Model I get <BR>> the error "0xfbc40109 - The operation cannot =
be=20
performed because the <BR>> message has been changed."<BR>> 2) =
Even if no=20
errors occur, the JournalItem is not updated. It is as if the <BR>> =
items is=20
updated with the new data, but not saved or committed. The message =
<BR>>=20
still appears to be opened.<BR>> <BR>> Please help!<BR>> =
Ben<BR>>=20
<BR>> Code:<BR>> <BR>> If I create an intem in outlook like =
this (code=20
shortened for readability)<BR>> <BR>> // Create the Journalitem in =
our=20
example and set no other properties because <BR>> we just want a =
valid=20
EntryID.<BR>> _JournalItemPtr pItem pItem =3D (_JournalItemPtr) =
<BR>>=20
m_pStore->polApp->CreateItem( olJournalItem );<BR>>=20
pItem->Save();<BR>> pItem->Close(olSave);<BR>> pItem =3D =
NULL;<BR>>=20
<BR>> // Now we use our own routine to get a ptr to the item from =
Outlook and=20
fill <BR>> in the details of the Item<BR>> pItem =3D =
pFolder->FindItem(=20
pEntry ); // UPDATE<BR>> pItem->Start =3D ...mydate<BR>>=20
pItem->Subject =3D ...mysubject<BR>> pitem->Save()<BR>>=20
pItem->Close(olSave)<BR>> <BR>> // We use MAPI to save our RTF =
code to=20
the same message zbBody is a stream <BR>> to a raw RTF code<BR>> =
hr =3D=20
m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(),=20
zbBody);<BR>> <BR>> <BR>> HRESULT =
CStore::SetMapiItemRTFBody(LPCTSTR=20
szEID, const ZBlob& zb )<BR>> {<BR>>    HRESULT =
hr =3D=20
NOERROR;<BR>>    BOOL bUpdated =3D=20
false;<BR>>    LPBYTE lpbMsgID =3D=20
NULL;<BR>>    LPMESSAGE lppMsg =3D=20
NULL;<BR>>    LPSTREAM lpRTFCompressed =3D=20
NULL;<BR>>    LPSTREAM lpRTFStream =3D=20
NULL;<BR>>    LPSPropValue pPropSuppMask =3D=20
NULL;<BR>>    ULONG cbWritten =3D =
0;<BR>>   =20
ULONG cbMsgID =3D 0;<BR>>    ULONG uType =3D=20
0;<BR>>    if=20
(!IsHexEntryIDValid(CW2A(szEID)))<BR>>     &n=
bsp; =20
return ResultFromScode(E_INVALIDARG);<BR>>    cbMsgID =
=3D=20
(ULONG) _tcslen(szEID) / 2;<BR>>    hr =3D =
MAPIAllocateBuffer(=20
cbMsgID, (void **) &lpbMsgID );<BR>>    if =
(FAILED(hr))=20
return hr;<BR>>    if( !FBinFromHex((LPTSTR) (LPSTR)=20
CW2A(szEID), lpbMsgID) )<BR>>   =20
{<BR>>        hr =3D=20
ResultFromScode(E_INVALIDARG);<BR>>      =
; =20
goto Quit;<BR>>    }<BR>>    hr =3D=20
m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL, <BR>> =

MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *)=20
&lppMsg);<BR>>    if( FAILED(hr)=20
)<BR>>        goto=20
Quit;<BR>>    // Call the message's =
IMAPIProp::OpenProperty=20
method to open the <BR>> PR_RTF_COMPRESSED=20
property,<BR>>    // specifying IID_IStream as the =
interface=20
identifier and setting the <BR>> MAPI_CREATE =
flag.<BR>>   =20
hr =3D lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0, =
<BR>>=20
MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *)=20
&lpRTFCompressed);<BR>>    if=20
(FAILED(hr))<BR>>        goto=20
Quit;<BR>>    hr =3D HrGetOneProp(lppMsg, =
PR_STORE_SUPPORT_MASK,=20
&pPropSuppMask);<BR>>    if=20
(FAILED(hr))<BR>>        goto=20
Quit;<BR>>    // Call the WrapCompressedRTFStream =
function,=20
passing the <BR>> STORE_UNCOMPRESSED_RTF flag if the=20
STORE_UNCOMPRESSED_RTF<BR>>    // bit is set in the =
message=20
store's PR_STORE_SUPPORT_MASK property and <BR>> get IStream pointer =
for=20
uncompressed RTF,<BR>>    // to which we will=20
write<BR>>    hr =3D =
WrapCompressedRTFStream(lpRTFCompressed,=20
MAPI_MODIFY | <BR>> (pPropSuppMask->Value.l & =
STORE_UNCOMPRESSED_RTF),=20
&lpRTFStream);<BR>>    // Call either =
IStream::Write or=20
IStream::CopyTo to write the message <BR>> text to the stream=20
returned<BR>>    // from WrapCompressedRTFStream. =
Write the=20
text that was passed to the <BR>> uncompressed RTF=20
strea<BR>>    hr =3D lpRTFStream->Write( =
zb.GetPtr(),=20
zb.GetSize(), &cbWritten );<BR>>    if=20
(FAILED(hr))<BR>>        goto=20
Quit;<BR>>    // Call the Commit and Release methods =
on the=20
stream returned from the <BR>> OpenProperty =
method<BR>>   =20
hr =3D lpRTFStream->Commit(STGC_OVERWRITE);<BR>>    =
if=20
(FAILED(hr))<BR>>        goto=20
Quit;<BR>>    // Sync the RTF and plain text =
properties of the=20
Message<BR>>    hr =3D RTFSync(lppMsg, =
RTF_SYNC_RTF_CHANGED,=20
&bUpdated);<BR>>    if=20
(FAILED(hr))<BR>>        goto=20
Quit;<BR>>    // If the message was updated, save =
changes to=20
the message<BR>>    if =
(bUpdated)<BR>>   =20
{<BR>>        hr =3D=20
lppMsg->SaveChanges(0); //=20
KEEP_OPEN_READWRITE);<BR>>        =
if( hr=20
=3D=3D MAPI_E_OBJECT_CHANGED=20
)<BR>>          &nbs=
p; hr =3D=20
lppMsg->SaveChanges(FORCE_SAVE);<BR>>     =
  =20
lppMsg->SubmitMessage(0);<BR>>    }<BR>>=20
Quit:<BR>>    if(=20
pPropSuppMask)<BR>>       =20
MAPIFreeBuffer(pPropSuppMask);<BR>>   =20
UlRelease(lppMsg);<BR>>   =20
UlRelease(lpRTFStream);<BR>>   =20
UlRelease(lpRTFCompressed);<BR>>   =20
MAPIFreeBuffer(lpbMsgID);<BR>>    return hr;<BR>> } =

<BR>> <BR>></FONT></BODY></HTML>

------=_NextPart_000_000A_01C684AF.DDE31D70--

Re: Bad bug when writing RTF directy to an Outlook Item
"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> 31.05.2006 17:50:07
That means that Outlook is still holding a reference to the item. It will
see the changes when thee item is completely dereferenced.
Can you see the changes after you restart Outlook?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

"clc" <crownlog[ at ]comcast.net> wrote in message
news:OJI0nFNhGHA.4044[ at ]TK2MSFTNGP03.phx.gbl...
Dmitry,

It didn't even occur to me to use the MAPIOBJECT and it DID solve part of
the problem.

Now the message body is updated correctly with raw RTF text as expected and
it correctly shows up in the Journal within outlook both in Autopreview mode
and in the reading pane. But the changes are not reflected when I open the
actual message which is really weird. I've modified the my code to the
following shortened version.

// Create the Journalitem in our example and set no other properties because
we just want a valid EntryID.
_JournalItemPtr pItem pItem = (_JournalItemPtr)
m_pStore->polApp->CreateItem( olJournalItem );
pItem->Save();
pItem->Close(olSave);
pItem = NULL;

// Now we use our own routine to get a ptr to the item from Outlook and fill
in the details of the Item
pItem = pFolder->FindItem( pEntry ); // UPDATE

pItem->Start = ...mydate

pItem->Subject = ...mysubject

// Write RTF body
BOOL bUpdated = false;
LPMESSAGE lppMsg = NULL;
LPSTREAM lpRTFCompressed = NULL;
LPSTREAM lpRTFStream = NULL;
LPSPropValue pPropSuppMask = NULL;
ULONG cbWritten = 0;
ULONG uType = 0;
IUnknown* pUnk = pItem->GetMAPIOBJECT();
hr = pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);
// Call the message's IMAPIProp::OpenProperty method to open the
PR_RTF_COMPRESSED property,
// specifying IID_IStream as the interface identifier and setting the
MAPI_CREATE flag.
hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
if (FAILED(hr))
goto Quit;
hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
if (FAILED(hr))
goto Quit;
// Call the WrapCompressedRTFStream function, passing the
STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
// bit is set in the message store's PR_STORE_SUPPORT_MASK property and
get IStream pointer for uncompressed RTF,
// to which we will write
hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
(pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
// Call either IStream::Write or IStream::CopyTo to write the message
text to the stream returned
// from WrapCompressedRTFStream. Write the text that was passed to the
uncompressed RTF strea
hr = lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(),
&cbWritten );
if (FAILED(hr))
goto Quit;
// Call the Commit and Release methods on the stream returned from the
OpenProperty method
hr = lpRTFStream->Commit(STGC_OVERWRITE);
if (FAILED(hr))
goto Quit;
// Sync the RTF and plain text properties of the Message
hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
if (FAILED(hr))
goto Quit;
// If the message was updated, save changes to the message
if (bUpdated)
hr = lppMsg->SaveChanges(KEEP_OPEN_READWRITE);

Quit:
if( pPropSuppMask)
MAPIFreeBuffer(pPropSuppMask);
UlRelease(lppMsg);
UlRelease(lpRTFStream);
UlRelease(lpRTFCompressed);
UlRelease(pUnk);
// Done writing RTF body
pitem->Save();
pItem->Close(olSave);
pItem = NULL


"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text]
> Do not reopen the message using IMsgStore::OpenEntry. You can retrieve
> IMessage from the Outlook Object Model using the JournalItem.MAPIOBJECT
> property.
> Why do you call IMessage::SubmitMessage()?
>
> Dmitry Streblechenko (MVP)
> http://www.dimastr.com/
> OutlookSpy - Outlook, CDO
> and MAPI Developer Tool
>
> "clc" <crownlog[ at ]comcast.net> wrote in message
> news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
> Setting:
> Outlook 2003 (SP2)
> Windows XP (SP2)
> VS2005 C++
> Outlook Object Modal 11
> MAPI
>
> Problem:
> Whenever I save RTF directly to the JournalItem using the code below it is
> as if the item is left open and not saved. Two symptoms:
> 1) Opening and changing the item again using only Outlook Object Model I
> get
> the error "0xfbc40109 - The operation cannot be performed because the
> message has been changed."
> 2) Even if no errors occur, the JournalItem is not updated. It is as if
> the
> items is updated with the new data, but not saved or committed. The
> message
> still appears to be opened.
>
> Please help!
> Ben
>
> Code:
>
> If I create an intem in outlook like this (code shortened for readability)
>
> // Create the Journalitem in our example and set no other properties
> because
> we just want a valid EntryID.
> _JournalItemPtr pItem pItem = (_JournalItemPtr)
> m_pStore->polApp->CreateItem( olJournalItem );
> pItem->Save();
> pItem->Close(olSave);
> pItem = NULL;
>
> // Now we use our own routine to get a ptr to the item from Outlook and
> fill
> in the details of the Item
> pItem = pFolder->FindItem( pEntry ); // UPDATE
> pItem->Start = ...mydate
> pItem->Subject = ...mysubject
> pitem->Save()
> pItem->Close(olSave)
>
> // We use MAPI to save our RTF code to the same message zbBody is a stream
> to a raw RTF code
> hr = m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(), zbBody);
>
>
> HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
> {
> HRESULT hr = NOERROR;
> BOOL bUpdated = false;
> LPBYTE lpbMsgID = NULL;
> LPMESSAGE lppMsg = NULL;
> LPSTREAM lpRTFCompressed = NULL;
> LPSTREAM lpRTFStream = NULL;
> LPSPropValue pPropSuppMask = NULL;
> ULONG cbWritten = 0;
> ULONG cbMsgID = 0;
> ULONG uType = 0;
> if (!IsHexEntryIDValid(CW2A(szEID)))
> return ResultFromScode(E_INVALIDARG);
> cbMsgID = (ULONG) _tcslen(szEID) / 2;
> hr = MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
> if (FAILED(hr)) return hr;
> if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
> {
> hr = ResultFromScode(E_INVALIDARG);
> goto Quit;
> }
> hr = m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,
> MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
> if( FAILED(hr) )
> goto Quit;
> // Call the message's IMAPIProp::OpenProperty method to open the
> PR_RTF_COMPRESSED property,
> // specifying IID_IStream as the interface identifier and setting the
> MAPI_CREATE flag.
> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
> if (FAILED(hr))
> goto Quit;
> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
> if (FAILED(hr))
> goto Quit;
> // Call the WrapCompressedRTFStream function, passing the
> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
> // bit is set in the message store's PR_STORE_SUPPORT_MASK property and
> get IStream pointer for uncompressed RTF,
> // to which we will write
> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
> // Call either IStream::Write or IStream::CopyTo to write the message
> text to the stream returned
> // from WrapCompressedRTFStream. Write the text that was passed to the
> uncompressed RTF strea
> hr = lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
> if (FAILED(hr))
> goto Quit;
> // Call the Commit and Release methods on the stream returned from the
> OpenProperty method
> hr = lpRTFStream->Commit(STGC_OVERWRITE);
> if (FAILED(hr))
> goto Quit;
> // Sync the RTF and plain text properties of the Message
> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
> if (FAILED(hr))
> goto Quit;
> // If the message was updated, save changes to the message
> if (bUpdated)
> {
> hr = lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
> if( hr == MAPI_E_OBJECT_CHANGED )
> hr = lppMsg->SaveChanges(FORCE_SAVE);
> lppMsg->SubmitMessage(0);
> }
> Quit:
> if( pPropSuppMask)
> MAPIFreeBuffer(pPropSuppMask);
> UlRelease(lppMsg);
> UlRelease(lpRTFStream);
> UlRelease(lpRTFCompressed);
> MAPIFreeBuffer(lpbMsgID);
> return hr;
> }
>
>

Re: Bad bug when writing RTF directy to an Outlook Item
"clc" <crownlog[ at ]comcast.net> 31.05.2006 19:10:13
You're on to something. It does show up correctly if I restart outlook. I
mean kill it from within task manager and then restart it. That does the
trick. So you are suggesting that outlook is holding on a reference to it
someplace? I would think that when I clear the smart pointer _JournalItemPtr
by reseting it to NULL after I am done with it, it should be released... In
essence I am doing this

_JournalItemPtr pItem = Getmypointer(EntryID)...
// Update my data
pItem->Subject = "My new subject"
pItem->body = "my rtf code"
pItem->save() // this alone should save and release the
item
pItem->Close(olSave) // I go one step further and close it again
pItem = NULL // This should release all of my references to
the item so why and where would
// outlook hold on to the reference
to my message?

Thanks
Ben


"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
news:%23LxfRpNhGHA.5096[ at ]TK2MSFTNGP02.phx.gbl...
[Quoted Text]
> That means that Outlook is still holding a reference to the item. It will
> see the changes when thee item is completely dereferenced.
> Can you see the changes after you restart Outlook?
>
> Dmitry Streblechenko (MVP)
> http://www.dimastr.com/
> OutlookSpy - Outlook, CDO
> and MAPI Developer Tool
>
> "clc" <crownlog[ at ]comcast.net> wrote in message
> news:OJI0nFNhGHA.4044[ at ]TK2MSFTNGP03.phx.gbl...
> Dmitry,
>
> It didn't even occur to me to use the MAPIOBJECT and it DID solve part of
> the problem.
>
> Now the message body is updated correctly with raw RTF text as expected
> and it correctly shows up in the Journal within outlook both in
> Autopreview mode and in the reading pane. But the changes are not
> reflected when I open the actual message which is really weird. I've
> modified the my code to the following shortened version.
>
> // Create the Journalitem in our example and set no other properties
> because we just want a valid EntryID.
> _JournalItemPtr pItem pItem = (_JournalItemPtr)
> m_pStore->polApp->CreateItem( olJournalItem );
> pItem->Save();
> pItem->Close(olSave);
> pItem = NULL;
>
> // Now we use our own routine to get a ptr to the item from Outlook and
> fill in the details of the Item
> pItem = pFolder->FindItem( pEntry ); // UPDATE
>
> pItem->Start = ...mydate
>
> pItem->Subject = ...mysubject
>
> // Write RTF body
> BOOL bUpdated = false;
> LPMESSAGE lppMsg = NULL;
> LPSTREAM lpRTFCompressed = NULL;
> LPSTREAM lpRTFStream = NULL;
> LPSPropValue pPropSuppMask = NULL;
> ULONG cbWritten = 0;
> ULONG uType = 0;
> IUnknown* pUnk = pItem->GetMAPIOBJECT();
> hr = pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);
> // Call the message's IMAPIProp::OpenProperty method to open the
> PR_RTF_COMPRESSED property,
> // specifying IID_IStream as the interface identifier and setting the
> MAPI_CREATE flag.
> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
> if (FAILED(hr))
> goto Quit;
> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
> if (FAILED(hr))
> goto Quit;
> // Call the WrapCompressedRTFStream function, passing the
> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
> // bit is set in the message store's PR_STORE_SUPPORT_MASK property and
> get IStream pointer for uncompressed RTF,
> // to which we will write
> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
> // Call either IStream::Write or IStream::CopyTo to write the message
> text to the stream returned
> // from WrapCompressedRTFStream. Write the text that was passed to the
> uncompressed RTF strea
> hr = lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(),
> &cbWritten );
> if (FAILED(hr))
> goto Quit;
> // Call the Commit and Release methods on the stream returned from the
> OpenProperty method
> hr = lpRTFStream->Commit(STGC_OVERWRITE);
> if (FAILED(hr))
> goto Quit;
> // Sync the RTF and plain text properties of the Message
> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
> if (FAILED(hr))
> goto Quit;
> // If the message was updated, save changes to the message
> if (bUpdated)
> hr = lppMsg->SaveChanges(KEEP_OPEN_READWRITE);
>
> Quit:
> if( pPropSuppMask)
> MAPIFreeBuffer(pPropSuppMask);
> UlRelease(lppMsg);
> UlRelease(lpRTFStream);
> UlRelease(lpRTFCompressed);
> UlRelease(pUnk);
> // Done writing RTF body
> pitem->Save();
> pItem->Close(olSave);
> pItem = NULL
>
>
> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
> news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl...
>> Do not reopen the message using IMsgStore::OpenEntry. You can retrieve
>> IMessage from the Outlook Object Model using the JournalItem.MAPIOBJECT
>> property.
>> Why do you call IMessage::SubmitMessage()?
>>
>> Dmitry Streblechenko (MVP)
>> http://www.dimastr.com/
>> OutlookSpy - Outlook, CDO
>> and MAPI Developer Tool
>>
>> "clc" <crownlog[ at ]comcast.net> wrote in message
>> news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
>> Setting:
>> Outlook 2003 (SP2)
>> Windows XP (SP2)
>> VS2005 C++
>> Outlook Object Modal 11
>> MAPI
>>
>> Problem:
>> Whenever I save RTF directly to the JournalItem using the code below it
>> is
>> as if the item is left open and not saved. Two symptoms:
>> 1) Opening and changing the item again using only Outlook Object Model I
>> get
>> the error "0xfbc40109 - The operation cannot be performed because the
>> message has been changed."
>> 2) Even if no errors occur, the JournalItem is not updated. It is as if
>> the
>> items is updated with the new data, but not saved or committed. The
>> message
>> still appears to be opened.
>>
>> Please help!
>> Ben
>>
>> Code:
>>
>> If I create an intem in outlook like this (code shortened for
>> readability)
>>
>> // Create the Journalitem in our example and set no other properties
>> because
>> we just want a valid EntryID.
>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>> m_pStore->polApp->CreateItem( olJournalItem );
>> pItem->Save();
>> pItem->Close(olSave);
>> pItem = NULL;
>>
>> // Now we use our own routine to get a ptr to the item from Outlook and
>> fill
>> in the details of the Item
>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>> pItem->Start = ...mydate
>> pItem->Subject = ...mysubject
>> pitem->Save()
>> pItem->Close(olSave)
>>
>> // We use MAPI to save our RTF code to the same message zbBody is a
>> stream
>> to a raw RTF code
>> hr = m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(), zbBody);
>>
>>
>> HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
>> {
>> HRESULT hr = NOERROR;
>> BOOL bUpdated = false;
>> LPBYTE lpbMsgID = NULL;
>> LPMESSAGE lppMsg = NULL;
>> LPSTREAM lpRTFCompressed = NULL;
>> LPSTREAM lpRTFStream = NULL;
>> LPSPropValue pPropSuppMask = NULL;
>> ULONG cbWritten = 0;
>> ULONG cbMsgID = 0;
>> ULONG uType = 0;
>> if (!IsHexEntryIDValid(CW2A(szEID)))
>> return ResultFromScode(E_INVALIDARG);
>> cbMsgID = (ULONG) _tcslen(szEID) / 2;
>> hr = MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
>> if (FAILED(hr)) return hr;
>> if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
>> {
>> hr = ResultFromScode(E_INVALIDARG);
>> goto Quit;
>> }
>> hr = m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,
>> MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
>> if( FAILED(hr) )
>> goto Quit;
>> // Call the message's IMAPIProp::OpenProperty method to open the
>> PR_RTF_COMPRESSED property,
>> // specifying IID_IStream as the interface identifier and setting the
>> MAPI_CREATE flag.
>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>> if (FAILED(hr))
>> goto Quit;
>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>> if (FAILED(hr))
>> goto Quit;
>> // Call the WrapCompressedRTFStream function, passing the
>> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
>> // bit is set in the message store's PR_STORE_SUPPORT_MASK property
>> and
>> get IStream pointer for uncompressed RTF,
>> // to which we will write
>> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
>> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
>> // Call either IStream::Write or IStream::CopyTo to write the message
>> text to the stream returned
>> // from WrapCompressedRTFStream. Write the text that was passed to the
>> uncompressed RTF strea
>> hr = lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
>> if (FAILED(hr))
>> goto Quit;
>> // Call the Commit and Release methods on the stream returned from the
>> OpenProperty method
>> hr = lpRTFStream->Commit(STGC_OVERWRITE);
>> if (FAILED(hr))
>> goto Quit;
>> // Sync the RTF and plain text properties of the Message
>> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
>> if (FAILED(hr))
>> goto Quit;
>> // If the message was updated, save changes to the message
>> if (bUpdated)
>> {
>> hr = lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
>> if( hr == MAPI_E_OBJECT_CHANGED )
>> hr = lppMsg->SaveChanges(FORCE_SAVE);
>> lppMsg->SubmitMessage(0);
>> }
>> Quit:
>> if( pPropSuppMask)
>> MAPIFreeBuffer(pPropSuppMask);
>> UlRelease(lppMsg);
>> UlRelease(lpRTFStream);
>> UlRelease(lpRTFCompressed);
>> MAPIFreeBuffer(lpbMsgID);
>> return hr;
>> }
>>
>>
>


Re: Bad bug when writing RTF directy to an Outlook Item
"clc" <crownlog[ at ]comcast.net> 31.05.2006 19:44:30
Dmitry,

This seems to have fixed it but I don't like it. I don't think it is right
and it might cause other problems down the road. Same example, but by
placing an extral pItem->close(olSave) after pitem->save() seems to have
solved it.

_JournalItemPtr pItem = Getmypointer(EntryID)...
// Update my data
pItem->Subject = "My new subject"
if( there is a body )
{
pItem->body = "my rtf code"
pItem->save() // works but should be unnecessary
pItem->Close(olSave) // go figure!
}
pItem->save() // this alone should save and release the
item
pItem->Close(olSave) // I go one step further and close it again
pItem = NULL // This should release all of my references to
the item so why and where would
// outlook hold on to the reference
to my message?

Thanks
Ben


"clc" <crownlog[ at ]comcast.net> wrote in message
news:uUc8cXOhGHA.1324[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text]
> You're on to something. It does show up correctly if I restart outlook. I
> mean kill it from within task manager and then restart it. That does the
> trick. So you are suggesting that outlook is holding on a reference to it
> someplace? I would think that when I clear the smart pointer
> _JournalItemPtr by reseting it to NULL after I am done with it, it should
> be released... In essence I am doing this
>
> _JournalItemPtr pItem = Getmypointer(EntryID)...
> // Update my data
> pItem->Subject = "My new subject"
> pItem->body = "my rtf code"
> pItem->save() // this alone should save and release the
> item
> pItem->Close(olSave) // I go one step further and close it again
> pItem = NULL // This should release all of my references
> to the item so why and where would
> // outlook hold on to the reference
> to my message?
>
> Thanks
> Ben
>
>
> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
> news:%23LxfRpNhGHA.5096[ at ]TK2MSFTNGP02.phx.gbl...
>> That means that Outlook is still holding a reference to the item. It will
>> see the changes when thee item is completely dereferenced.
>> Can you see the changes after you restart Outlook?
>>
>> Dmitry Streblechenko (MVP)
>> http://www.dimastr.com/
>> OutlookSpy - Outlook, CDO
>> and MAPI Developer Tool
>>
>> "clc" <crownlog[ at ]comcast.net> wrote in message
>> news:OJI0nFNhGHA.4044[ at ]TK2MSFTNGP03.phx.gbl...
>> Dmitry,
>>
>> It didn't even occur to me to use the MAPIOBJECT and it DID solve part of
>> the problem.
>>
>> Now the message body is updated correctly with raw RTF text as expected
>> and it correctly shows up in the Journal within outlook both in
>> Autopreview mode and in the reading pane. But the changes are not
>> reflected when I open the actual message which is really weird. I've
>> modified the my code to the following shortened version.
>>
>> // Create the Journalitem in our example and set no other properties
>> because we just want a valid EntryID.
>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>> m_pStore->polApp->CreateItem( olJournalItem );
>> pItem->Save();
>> pItem->Close(olSave);
>> pItem = NULL;
>>
>> // Now we use our own routine to get a ptr to the item from Outlook and
>> fill in the details of the Item
>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>>
>> pItem->Start = ...mydate
>>
>> pItem->Subject = ...mysubject
>>
>> // Write RTF body
>> BOOL bUpdated = false;
>> LPMESSAGE lppMsg = NULL;
>> LPSTREAM lpRTFCompressed = NULL;
>> LPSTREAM lpRTFStream = NULL;
>> LPSPropValue pPropSuppMask = NULL;
>> ULONG cbWritten = 0;
>> ULONG uType = 0;
>> IUnknown* pUnk = pItem->GetMAPIOBJECT();
>> hr = pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);
>> // Call the message's IMAPIProp::OpenProperty method to open the
>> PR_RTF_COMPRESSED property,
>> // specifying IID_IStream as the interface identifier and setting the
>> MAPI_CREATE flag.
>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>> if (FAILED(hr))
>> goto Quit;
>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>> if (FAILED(hr))
>> goto Quit;
>> // Call the WrapCompressedRTFStream function, passing the
>> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
>> // bit is set in the message store's PR_STORE_SUPPORT_MASK property
>> and get IStream pointer for uncompressed RTF,
>> // to which we will write
>> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
>> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
>> // Call either IStream::Write or IStream::CopyTo to write the message
>> text to the stream returned
>> // from WrapCompressedRTFStream. Write the text that was passed to the
>> uncompressed RTF strea
>> hr = lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(),
>> &cbWritten );
>> if (FAILED(hr))
>> goto Quit;
>> // Call the Commit and Release methods on the stream returned from the
>> OpenProperty method
>> hr = lpRTFStream->Commit(STGC_OVERWRITE);
>> if (FAILED(hr))
>> goto Quit;
>> // Sync the RTF and plain text properties of the Message
>> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
>> if (FAILED(hr))
>> goto Quit;
>> // If the message was updated, save changes to the message
>> if (bUpdated)
>> hr = lppMsg->SaveChanges(KEEP_OPEN_READWRITE);
>>
>> Quit:
>> if( pPropSuppMask)
>> MAPIFreeBuffer(pPropSuppMask);
>> UlRelease(lppMsg);
>> UlRelease(lpRTFStream);
>> UlRelease(lpRTFCompressed);
>> UlRelease(pUnk);
>> // Done writing RTF body
>> pitem->Save();
>> pItem->Close(olSave);
>> pItem = NULL
>>
>>
>> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
>> news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl...
>>> Do not reopen the message using IMsgStore::OpenEntry. You can retrieve
>>> IMessage from the Outlook Object Model using the JournalItem.MAPIOBJECT
>>> property.
>>> Why do you call IMessage::SubmitMessage()?
>>>
>>> Dmitry Streblechenko (MVP)
>>> http://www.dimastr.com/
>>> OutlookSpy - Outlook, CDO
>>> and MAPI Developer Tool
>>>
>>> "clc" <crownlog[ at ]comcast.net> wrote in message
>>> news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
>>> Setting:
>>> Outlook 2003 (SP2)
>>> Windows XP (SP2)
>>> VS2005 C++
>>> Outlook Object Modal 11
>>> MAPI
>>>
>>> Problem:
>>> Whenever I save RTF directly to the JournalItem using the code below it
>>> is
>>> as if the item is left open and not saved. Two symptoms:
>>> 1) Opening and changing the item again using only Outlook Object Model I
>>> get
>>> the error "0xfbc40109 - The operation cannot be performed because the
>>> message has been changed."
>>> 2) Even if no errors occur, the JournalItem is not updated. It is as if
>>> the
>>> items is updated with the new data, but not saved or committed. The
>>> message
>>> still appears to be opened.
>>>
>>> Please help!
>>> Ben
>>>
>>> Code:
>>>
>>> If I create an intem in outlook like this (code shortened for
>>> readability)
>>>
>>> // Create the Journalitem in our example and set no other properties
>>> because
>>> we just want a valid EntryID.
>>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>>> m_pStore->polApp->CreateItem( olJournalItem );
>>> pItem->Save();
>>> pItem->Close(olSave);
>>> pItem = NULL;
>>>
>>> // Now we use our own routine to get a ptr to the item from Outlook and
>>> fill
>>> in the details of the Item
>>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>>> pItem->Start = ...mydate
>>> pItem->Subject = ...mysubject
>>> pitem->Save()
>>> pItem->Close(olSave)
>>>
>>> // We use MAPI to save our RTF code to the same message zbBody is a
>>> stream
>>> to a raw RTF code
>>> hr = m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(),
>>> zbBody);
>>>
>>>
>>> HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
>>> {
>>> HRESULT hr = NOERROR;
>>> BOOL bUpdated = false;
>>> LPBYTE lpbMsgID = NULL;
>>> LPMESSAGE lppMsg = NULL;
>>> LPSTREAM lpRTFCompressed = NULL;
>>> LPSTREAM lpRTFStream = NULL;
>>> LPSPropValue pPropSuppMask = NULL;
>>> ULONG cbWritten = 0;
>>> ULONG cbMsgID = 0;
>>> ULONG uType = 0;
>>> if (!IsHexEntryIDValid(CW2A(szEID)))
>>> return ResultFromScode(E_INVALIDARG);
>>> cbMsgID = (ULONG) _tcslen(szEID) / 2;
>>> hr = MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
>>> if (FAILED(hr)) return hr;
>>> if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
>>> {
>>> hr = ResultFromScode(E_INVALIDARG);
>>> goto Quit;
>>> }
>>> hr = m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,
>>> MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
>>> if( FAILED(hr) )
>>> goto Quit;
>>> // Call the message's IMAPIProp::OpenProperty method to open the
>>> PR_RTF_COMPRESSED property,
>>> // specifying IID_IStream as the interface identifier and setting the
>>> MAPI_CREATE flag.
>>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>>> if (FAILED(hr))
>>> goto Quit;
>>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Call the WrapCompressedRTFStream function, passing the
>>> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
>>> // bit is set in the message store's PR_STORE_SUPPORT_MASK property
>>> and
>>> get IStream pointer for uncompressed RTF,
>>> // to which we will write
>>> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
>>> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
>>> // Call either IStream::Write or IStream::CopyTo to write the message
>>> text to the stream returned
>>> // from WrapCompressedRTFStream. Write the text that was passed to
>>> the
>>> uncompressed RTF strea
>>> hr = lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Call the Commit and Release methods on the stream returned from
>>> the
>>> OpenProperty method
>>> hr = lpRTFStream->Commit(STGC_OVERWRITE);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Sync the RTF and plain text properties of the Message
>>> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // If the message was updated, save changes to the message
>>> if (bUpdated)
>>> {
>>> hr = lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
>>> if( hr == MAPI_E_OBJECT_CHANGED )
>>> hr = lppMsg->SaveChanges(FORCE_SAVE);
>>> lppMsg->SubmitMessage(0);
>>> }
>>> Quit:
>>> if( pPropSuppMask)
>>> MAPIFreeBuffer(pPropSuppMask);
>>> UlRelease(lppMsg);
>>> UlRelease(lpRTFStream);
>>> UlRelease(lpRTFCompressed);
>>> MAPIFreeBuffer(lpbMsgID);
>>> return hr;
>>> }
>>>
>>>
>>
>
>


Re: Bad bug when writing RTF directy to an Outlook Item
"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> 31.05.2006 20:46:12
Is that item selected at the time your code is executed?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

"clc" <crownlog[ at ]comcast.net> wrote in message
news:OYm$kqOhGHA.4712[ at ]TK2MSFTNGP05.phx.gbl...
[Quoted Text]
> Dmitry,
>
> This seems to have fixed it but I don't like it. I don't think it is right
> and it might cause other problems down the road. Same example, but by
> placing an extral pItem->close(olSave) after pitem->save() seems to have
> solved it.
>
> _JournalItemPtr pItem = Getmypointer(EntryID)...
> // Update my data
> pItem->Subject = "My new subject"
> if( there is a body )
> {
> pItem->body = "my rtf code"
> pItem->save() // works but should be unnecessary
> pItem->Close(olSave) // go figure!
> }
> pItem->save() // this alone should save and release the
> item
> pItem->Close(olSave) // I go one step further and close it again
> pItem = NULL // This should release all of my references
> to the item so why and where would
> // outlook hold on to the reference
> to my message?
>
> Thanks
> Ben
>
>
> "clc" <crownlog[ at ]comcast.net> wrote in message
> news:uUc8cXOhGHA.1324[ at ]TK2MSFTNGP04.phx.gbl...
>> You're on to something. It does show up correctly if I restart outlook. I
>> mean kill it from within task manager and then restart it. That does the
>> trick. So you are suggesting that outlook is holding on a reference to it
>> someplace? I would think that when I clear the smart pointer
>> _JournalItemPtr by reseting it to NULL after I am done with it, it should
>> be released... In essence I am doing this
>>
>> _JournalItemPtr pItem = Getmypointer(EntryID)...
>> // Update my data
>> pItem->Subject = "My new subject"
>> pItem->body = "my rtf code"
>> pItem->save() // this alone should save and release the
>> item
>> pItem->Close(olSave) // I go one step further and close it again
>> pItem = NULL // This should release all of my references
>> to the item so why and where would
>> // outlook hold on to the
>> reference to my message?
>>
>> Thanks
>> Ben
>>
>>
>> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
>> news:%23LxfRpNhGHA.5096[ at ]TK2MSFTNGP02.phx.gbl...
>>> That means that Outlook is still holding a reference to the item. It
>>> will see the changes when thee item is completely dereferenced.
>>> Can you see the changes after you restart Outlook?
>>>
>>> Dmitry Streblechenko (MVP)
>>> http://www.dimastr.com/
>>> OutlookSpy - Outlook, CDO
>>> and MAPI Developer Tool
>>>
>>> "clc" <crownlog[ at ]comcast.net> wrote in message
>>> news:OJI0nFNhGHA.4044[ at ]TK2MSFTNGP03.phx.gbl...
>>> Dmitry,
>>>
>>> It didn't even occur to me to use the MAPIOBJECT and it DID solve part
>>> of the problem.
>>>
>>> Now the message body is updated correctly with raw RTF text as expected
>>> and it correctly shows up in the Journal within outlook both in
>>> Autopreview mode and in the reading pane. But the changes are not
>>> reflected when I open the actual message which is really weird. I've
>>> modified the my code to the following shortened version.
>>>
>>> // Create the Journalitem in our example and set no other properties
>>> because we just want a valid EntryID.
>>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>>> m_pStore->polApp->CreateItem( olJournalItem );
>>> pItem->Save();
>>> pItem->Close(olSave);
>>> pItem = NULL;
>>>
>>> // Now we use our own routine to get a ptr to the item from Outlook and
>>> fill in the details of the Item
>>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>>>
>>> pItem->Start = ...mydate
>>>
>>> pItem->Subject = ...mysubject
>>>
>>> // Write RTF body
>>> BOOL bUpdated = false;
>>> LPMESSAGE lppMsg = NULL;
>>> LPSTREAM lpRTFCompressed = NULL;
>>> LPSTREAM lpRTFStream = NULL;
>>> LPSPropValue pPropSuppMask = NULL;
>>> ULONG cbWritten = 0;
>>> ULONG uType = 0;
>>> IUnknown* pUnk = pItem->GetMAPIOBJECT();
>>> hr = pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);
>>> // Call the message's IMAPIProp::OpenProperty method to open the
>>> PR_RTF_COMPRESSED property,
>>> // specifying IID_IStream as the interface identifier and setting the
>>> MAPI_CREATE flag.
>>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>>> if (FAILED(hr))
>>> goto Quit;
>>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Call the WrapCompressedRTFStream function, passing the
>>> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
>>> // bit is set in the message store's PR_STORE_SUPPORT_MASK property
>>> and get IStream pointer for uncompressed RTF,
>>> // to which we will write
>>> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
>>> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
>>> // Call either IStream::Write or IStream::CopyTo to write the message
>>> text to the stream returned
>>> // from WrapCompressedRTFStream. Write the text that was passed to
>>> the uncompressed RTF strea
>>> hr = lpRTFStream->Write( zbBody.GetPtr(), zbBody.GetSize(),
>>> &cbWritten );
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Call the Commit and Release methods on the stream returned from
>>> the OpenProperty method
>>> hr = lpRTFStream->Commit(STGC_OVERWRITE);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // Sync the RTF and plain text properties of the Message
>>> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
>>> if (FAILED(hr))
>>> goto Quit;
>>> // If the message was updated, save changes to the message
>>> if (bUpdated)
>>> hr = lppMsg->SaveChanges(KEEP_OPEN_READWRITE);
>>>
>>> Quit:
>>> if( pPropSuppMask)
>>> MAPIFreeBuffer(pPropSuppMask);
>>> UlRelease(lppMsg);
>>> UlRelease(lpRTFStream);
>>> UlRelease(lpRTFCompressed);
>>> UlRelease(pUnk);
>>> // Done writing RTF body
>>> pitem->Save();
>>> pItem->Close(olSave);
>>> pItem = NULL
>>>
>>>
>>> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
>>> news:%23Q$qImBhGHA.3916[ at ]TK2MSFTNGP04.phx.gbl...
>>>> Do not reopen the message using IMsgStore::OpenEntry. You can retrieve
>>>> IMessage from the Outlook Object Model using the JournalItem.MAPIOBJECT
>>>> property.
>>>> Why do you call IMessage::SubmitMessage()?
>>>>
>>>> Dmitry Streblechenko (MVP)
>>>> http://www.dimastr.com/
>>>> OutlookSpy - Outlook, CDO
>>>> and MAPI Developer Tool
>>>>
>>>> "clc" <crownlog[ at ]comcast.net> wrote in message
>>>> news:e4s6uSAhGHA.4848[ at ]TK2MSFTNGP04.phx.gbl...
>>>> Setting:
>>>> Outlook 2003 (SP2)
>>>> Windows XP (SP2)
>>>> VS2005 C++
>>>> Outlook Object Modal 11
>>>> MAPI
>>>>
>>>> Problem:
>>>> Whenever I save RTF directly to the JournalItem using the code below it
>>>> is
>>>> as if the item is left open and not saved. Two symptoms:
>>>> 1) Opening and changing the item again using only Outlook Object Model
>>>> I get
>>>> the error "0xfbc40109 - The operation cannot be performed because the
>>>> message has been changed."
>>>> 2) Even if no errors occur, the JournalItem is not updated. It is as if
>>>> the
>>>> items is updated with the new data, but not saved or committed. The
>>>> message
>>>> still appears to be opened.
>>>>
>>>> Please help!
>>>> Ben
>>>>
>>>> Code:
>>>>
>>>> If I create an intem in outlook like this (code shortened for
>>>> readability)
>>>>
>>>> // Create the Journalitem in our example and set no other properties
>>>> because
>>>> we just want a valid EntryID.
>>>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>>>> m_pStore->polApp->CreateItem( olJournalItem );
>>>> pItem->Save();
>>>> pItem->Close(olSave);
>>>> pItem = NULL;
>>>>
>>>> // Now we use our own routine to get a ptr to the item from Outlook and
>>>> fill
>>>> in the details of the Item
>>>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>>>> pItem->Start = ...mydate
>>>> pItem->Subject = ...mysubject
>>>> pitem->Save()
>>>> pItem->Close(olSave)
>>>>
>>>> // We use MAPI to save our RTF code to the same message zbBody is a
>>>> stream
>>>> to a raw RTF code
>>>> hr = m_pStore->SetMapiItemRTFBody( (LPTSTR) pItem->GetEntryID(),
>>>> zbBody);
>>>>
>>>>
>>>> HRESULT CStore::SetMapiItemRTFBody(LPCTSTR szEID, const ZBlob& zb )
>>>> {
>>>> HRESULT hr = NOERROR;
>>>> BOOL bUpdated = false;
>>>> LPBYTE lpbMsgID = NULL;
>>>> LPMESSAGE lppMsg = NULL;
>>>> LPSTREAM lpRTFCompressed = NULL;
>>>> LPSTREAM lpRTFStream = NULL;
>>>> LPSPropValue pPropSuppMask = NULL;
>>>> ULONG cbWritten = 0;
>>>> ULONG cbMsgID = 0;
>>>> ULONG uType = 0;
>>>> if (!IsHexEntryIDValid(CW2A(szEID)))
>>>> return ResultFromScode(E_INVALIDARG);
>>>> cbMsgID = (ULONG) _tcslen(szEID) / 2;
>>>> hr = MAPIAllocateBuffer( cbMsgID, (void **) &lpbMsgID );
>>>> if (FAILED(hr)) return hr;
>>>> if( !FBinFromHex((LPTSTR) (LPSTR) CW2A(szEID), lpbMsgID) )
>>>> {
>>>> hr = ResultFromScode(E_INVALIDARG);
>>>> goto Quit;
>>>> }
>>>> hr = m_pMapiStore->OpenEntry(cbMsgID, (LPENTRYID) lpbMsgID, NULL,
>>>> MAPI_BEST_ACCESS | MAPI_NO_CACHE, &uType, (LPUNKNOWN *) &lppMsg);
>>>> if( FAILED(hr) )
>>>> goto Quit;
>>>> // Call the message's IMAPIProp::OpenProperty method to open the
>>>> PR_RTF_COMPRESSED property,
>>>> // specifying IID_IStream as the interface identifier and setting
>>>> the
>>>> MAPI_CREATE flag.
>>>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>>>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> // Call the WrapCompressedRTFStream function, passing the
>>>> STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF
>>>> // bit is set in the message store's PR_STORE_SUPPORT_MASK property
>>>> and
>>>> get IStream pointer for uncompressed RTF,
>>>> // to which we will write
>>>> hr = WrapCompressedRTFStream(lpRTFCompressed, MAPI_MODIFY |
>>>> (pPropSuppMask->Value.l & STORE_UNCOMPRESSED_RTF), &lpRTFStream);
>>>> // Call either IStream::Write or IStream::CopyTo to write the
>>>> message
>>>> text to the stream returned
>>>> // from WrapCompressedRTFStream. Write the text that was passed to
>>>> the
>>>> uncompressed RTF strea
>>>> hr = lpRTFStream->Write( zb.GetPtr(), zb.GetSize(), &cbWritten );
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> // Call the Commit and Release methods on the stream returned from
>>>> the
>>>> OpenProperty method
>>>> hr = lpRTFStream->Commit(STGC_OVERWRITE);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> // Sync the RTF and plain text properties of the Message
>>>> hr = RTFSync(lppMsg, RTF_SYNC_RTF_CHANGED, &bUpdated);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> // If the message was updated, save changes to the message
>>>> if (bUpdated)
>>>> {
>>>> hr = lppMsg->SaveChanges(0); // KEEP_OPEN_READWRITE);
>>>> if( hr == MAPI_E_OBJECT_CHANGED )
>>>> hr = lppMsg->SaveChanges(FORCE_SAVE);
>>>> lppMsg->SubmitMessage(0);
>>>> }
>>>> Quit:
>>>> if( pPropSuppMask)
>>>> MAPIFreeBuffer(pPropSuppMask);
>>>> UlRelease(lppMsg);
>>>> UlRelease(lpRTFStream);
>>>> UlRelease(lpRTFCompressed);
>>>> MAPIFreeBuffer(lpbMsgID);
>>>> return hr;
>>>> }
>>>>
>>>>
>>>
>>
>>
>
>


Re: Bad bug when writing RTF directy to an Outlook Item
"clc" <crownlog[ at ]comcast.net> 01.06.2006 18:47:51
When it is selected it appears to work fine. When it is not, it does not
work fine. But calling Save and Close(olSave) twice in concession seams to
fix the problem all together. Like I said, I don't like it but it works. I
hope to find the real cause for the problem and fix it right.


"Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
news:%23WaZrLPhGHA.1508[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text]
> Is that item selected at the time your code is executed?
>
> Dmitry Streblechenko (MVP)
> http://www.dimastr.com/
> OutlookSpy - Outlook, CDO
> and MAPI Developer Tool
>
> "clc" <crownlog[ at ]comcast.net> wrote in message
> news:OYm$kqOhGHA.4712[ at ]TK2MSFTNGP05.phx.gbl...
>> Dmitry,
>>
>> This seems to have fixed it but I don't like it. I don't think it is
>> right and it might cause other problems down the road. Same example, but
>> by placing an extral pItem->close(olSave) after pitem->save() seems to
>> have solved it.
>>
>> _JournalItemPtr pItem = Getmypointer(EntryID)...
>> // Update my data
>> pItem->Subject = "My new subject"
>> if( there is a body )
>> {
>> pItem->body = "my rtf code"
>> pItem->save() // works but should be unnecessary
>> pItem->Close(olSave) // go figure!
>> }
>> pItem->save() // this alone should save and release the
>> item
>> pItem->Close(olSave) // I go one step further and close it again
>> pItem = NULL // This should release all of my references
>> to the item so why and where would
>> // outlook hold on to the
>> reference to my message?
>>
>> Thanks
>> Ben
>>
>>
>> "clc" <crownlog[ at ]comcast.net> wrote in message
>> news:uUc8cXOhGHA.1324[ at ]TK2MSFTNGP04.phx.gbl...
>>> You're on to something. It does show up correctly if I restart outlook.
>>> I mean kill it from within task manager and then restart it. That does
>>> the trick. So you are suggesting that outlook is holding on a reference
>>> to it someplace? I would think that when I clear the smart pointer
>>> _JournalItemPtr by reseting it to NULL after I am done with it, it
>>> should be released... In essence I am doing this
>>>
>>> _JournalItemPtr pItem = Getmypointer(EntryID)...
>>> // Update my data
>>> pItem->Subject = "My new subject"
>>> pItem->body = "my rtf code"
>>> pItem->save() // this alone should save and release the
>>> item
>>> pItem->Close(olSave) // I go one step further and close it again
>>> pItem = NULL // This should release all of my references
>>> to the item so why and where would
>>> // outlook hold on to the
>>> reference to my message?
>>>
>>> Thanks
>>> Ben
>>>
>>>
>>> "Dmitry Streblechenko" <dmitry[ at ]dimastr.com> wrote in message
>>> news:%23LxfRpNhGHA.5096[ at ]TK2MSFTNGP02.phx.gbl...
>>>> That means that Outlook is still holding a reference to the item. It
>>>> will see the changes when thee item is completely dereferenced.
>>>> Can you see the changes after you restart Outlook?
>>>>
>>>> Dmitry Streblechenko (MVP)
>>>> http://www.dimastr.com/
>>>> OutlookSpy - Outlook, CDO
>>>> and MAPI Developer Tool
>>>>
>>>> "clc" <crownlog[ at ]comcast.net> wrote in message
>>>> news:OJI0nFNhGHA.4044[ at ]TK2MSFTNGP03.phx.gbl...
>>>> Dmitry,
>>>>
>>>> It didn't even occur to me to use the MAPIOBJECT and it DID solve part
>>>> of the problem.
>>>>
>>>> Now the message body is updated correctly with raw RTF text as expected
>>>> and it correctly shows up in the Journal within outlook both in
>>>> Autopreview mode and in the reading pane. But the changes are not
>>>> reflected when I open the actual message which is really weird. I've
>>>> modified the my code to the following shortened version.
>>>>
>>>> // Create the Journalitem in our example and set no other properties
>>>> because we just want a valid EntryID.
>>>> _JournalItemPtr pItem pItem = (_JournalItemPtr)
>>>> m_pStore->polApp->CreateItem( olJournalItem );
>>>> pItem->Save();
>>>> pItem->Close(olSave);
>>>> pItem = NULL;
>>>>
>>>> // Now we use our own routine to get a ptr to the item from Outlook and
>>>> fill in the details of the Item
>>>> pItem = pFolder->FindItem( pEntry ); // UPDATE
>>>>
>>>> pItem->Start = ...mydate
>>>>
>>>> pItem->Subject = ...mysubject
>>>>
>>>> // Write RTF body
>>>> BOOL bUpdated = false;
>>>> LPMESSAGE lppMsg = NULL;
>>>> LPSTREAM lpRTFCompressed = NULL;
>>>> LPSTREAM lpRTFStream = NULL;
>>>> LPSPropValue pPropSuppMask = NULL;
>>>> ULONG cbWritten = 0;
>>>> ULONG uType = 0;
>>>> IUnknown* pUnk = pItem->GetMAPIOBJECT();
>>>> hr = pUnk->QueryInterface(IID_IMessage, (void**) &lppMsg);
>>>> // Call the message's IMAPIProp::OpenProperty method to open the
>>>> PR_RTF_COMPRESSED property,
>>>> // specifying IID_IStream as the interface identifier and setting
>>>> the MAPI_CREATE flag.
>>>> hr = lppMsg->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream, 0,
>>>> MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN *) &lpRTFCompressed);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> hr = HrGetOneProp(lppMsg, PR_STORE_SUPPORT_MASK, &pPropSuppMask);
>>>> if (FAILED(hr))
>>>> goto Quit;
>>>> // Call the WrapCompressedRTFStream function, passing the
>