V
Vladimir Werskov
Hello,
i am facing a strange problem with an Exchange Client Extension. Under
Windows XP (SP2) and Outlook 2002 (without SP, SP1, SP2, SP3) the extension
is behaving differently than on other configurations.
The extension implements the IExchExt, IExchExtMessageEvents interfaces and
the only events i am using are the OnSubmit and OnWriteComplete. Here i need
to access the message which is to be sent. Everything works perfectly until
the user uses the "Send To - Mail Recipient" (either from desktop, Windows
Explorer or any other shell application). If the user sends the message, the
explorer (or the process which has started the Send To function) hangs (does
not respond anymore).
I have narrowed down the problem to one method call, which causes the
problem. Actually when the message is requested using the
lpExchangeCallback->GetObject, the explorer hangs. If i uncomment this call,
everything is working perfect. If i explicitly release the returned pointers
(lpMessage, lpMdb), then also everything is working.
I haven't found any example code or documentation which requires explicit
release on those pointers! And i even do not know whether i should call it or
what are the side effects? Is Outlook 2002 calling an additional AddRef, but
Outlook 2003 not? What can be the difference.
To demonstrate the problem i have modified the sample code from
http://support.microsoft.com/kb/285999
I have added the IExchExtMessageEvents interface to it.
Here is the source code:
// SimplestExt.cpp : Defines the entry point for the DLL application.
//
#include <STDIO.h>
#include <WINDOWS.H>
#include <COMMCTRL.H>
#include <MAPIX.H>
#include <MAPIUTIL.H>
#include <MAPIFORM.H>
#include <INITGUID.h>
#include <EXCHEXT.H>
#include "stdafx.h"
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved)
{
return TRUE;
}
//Declarations
class CMyExtublic IExchExt, IExchExtMessageEvents
{
public:
CMyExt() { refcount = 0; };
~CMyExt() {};
//Methods of IUnknown
inline STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj)
{
*ppvObj = NULL;
IUnknown* punk = NULL;
if ((IID_IUnknown == riid) || (IID_IExchExt == riid))
{
punk = (IExchExt*) this;
}
else if (riid == IID_IExchExtMessageEvents)
{
punk = (IExchExtMessageEvents*)this;
}
else
return E_NOINTERFACE;
if (NULL != punk)
{
*ppvObj = punk;
AddRef();
}
return S_OK;
}
inline STDMETHODIMP_(ULONG) AddRef()
{
refcount++;
return refcount;
}
inline STDMETHODIMP_(ULONG) Release()
{
ULONG ulCount = refcount--;
if (!ulCount)
{
delete this;
}
return ulCount;
}
//This is one method of IExchExt.
STDMETHODIMP Install(IExchExtCallback *pmecb, ULONG mcontext, ULONG ulFlags);
STDMETHODIMP OnRead(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnReadComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags);
STDMETHODIMP OnWrite(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnWriteComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags);
STDMETHODIMP OnCheckNames(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnCheckNamesComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags);
STDMETHODIMP OnSubmit(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP_(VOID) OnSubmitComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags);
private:
ULONG refcount;
};
extern "C" _declspec(dllexport) LPEXCHEXT CALLBACK ExchEntryPoint(void);
LPEXCHEXT CALLBACK ExchEntryPoint()
{
return new CMyExt;
}
STDMETHODIMP CMyExt::Install(
IExchExtCallback *pmecb,
ULONG mcontext,
ULONG ulFlags)
{
return S_OK;
}
STDMETHODIMP CMyExt::OnRead(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnReadComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnWrite(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
/////////////////////////////////////////////////////////
// When we get called here, MAPI has finished writing all the
// properties to the message, but the message has not been submitted yet.
/////////////////////////////////////////////////////////
STDMETHODIMP CMyExt::OnWriteComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags)
{
LPMESSAGE lpMessage = NULL;
LPMDB lpMdb = NULL;
MessageBox(NULL, "Open message", "Test Extension", MB_OK);
if ((SUCCEEDED(lpExchangeCallback->GetObject(&lpMdb, (LPMAPIPROP
*)&lpMessage)))&& (lpMessage))
{
if (lpMessage != NULL)
{
lpMessage->Release();
lpMessage = NULL;
}
if (lpMdb != NULL)
{
lpMdb->Release();
lpMdb = NULL;
}
}
MessageBox(NULL, "Finished", "Test Extension", MB_OK);
return S_FALSE;
}
STDMETHODIMP CMyExt::OnCheckNames(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnCheckNamesComplete(IExchExtCallback
*lpExchangeCallback, ULONG ulFlags)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnSubmit(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
VOID CMyExt::OnSubmitComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags)
{
}
Thank you for any advice.
Vladimir Werskov
i am facing a strange problem with an Exchange Client Extension. Under
Windows XP (SP2) and Outlook 2002 (without SP, SP1, SP2, SP3) the extension
is behaving differently than on other configurations.
The extension implements the IExchExt, IExchExtMessageEvents interfaces and
the only events i am using are the OnSubmit and OnWriteComplete. Here i need
to access the message which is to be sent. Everything works perfectly until
the user uses the "Send To - Mail Recipient" (either from desktop, Windows
Explorer or any other shell application). If the user sends the message, the
explorer (or the process which has started the Send To function) hangs (does
not respond anymore).
I have narrowed down the problem to one method call, which causes the
problem. Actually when the message is requested using the
lpExchangeCallback->GetObject, the explorer hangs. If i uncomment this call,
everything is working perfect. If i explicitly release the returned pointers
(lpMessage, lpMdb), then also everything is working.
I haven't found any example code or documentation which requires explicit
release on those pointers! And i even do not know whether i should call it or
what are the side effects? Is Outlook 2002 calling an additional AddRef, but
Outlook 2003 not? What can be the difference.
To demonstrate the problem i have modified the sample code from
http://support.microsoft.com/kb/285999
I have added the IExchExtMessageEvents interface to it.
Here is the source code:
// SimplestExt.cpp : Defines the entry point for the DLL application.
//
#include <STDIO.h>
#include <WINDOWS.H>
#include <COMMCTRL.H>
#include <MAPIX.H>
#include <MAPIUTIL.H>
#include <MAPIFORM.H>
#include <INITGUID.h>
#include <EXCHEXT.H>
#include "stdafx.h"
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved)
{
return TRUE;
}
//Declarations
class CMyExtublic IExchExt, IExchExtMessageEvents
{
public:
CMyExt() { refcount = 0; };
~CMyExt() {};
//Methods of IUnknown
inline STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj)
{
*ppvObj = NULL;
IUnknown* punk = NULL;
if ((IID_IUnknown == riid) || (IID_IExchExt == riid))
{
punk = (IExchExt*) this;
}
else if (riid == IID_IExchExtMessageEvents)
{
punk = (IExchExtMessageEvents*)this;
}
else
return E_NOINTERFACE;
if (NULL != punk)
{
*ppvObj = punk;
AddRef();
}
return S_OK;
}
inline STDMETHODIMP_(ULONG) AddRef()
{
refcount++;
return refcount;
}
inline STDMETHODIMP_(ULONG) Release()
{
ULONG ulCount = refcount--;
if (!ulCount)
{
delete this;
}
return ulCount;
}
//This is one method of IExchExt.
STDMETHODIMP Install(IExchExtCallback *pmecb, ULONG mcontext, ULONG ulFlags);
STDMETHODIMP OnRead(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnReadComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags);
STDMETHODIMP OnWrite(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnWriteComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags);
STDMETHODIMP OnCheckNames(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP OnCheckNamesComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags);
STDMETHODIMP OnSubmit(IExchExtCallback *lpExchangeCallback);
STDMETHODIMP_(VOID) OnSubmitComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags);
private:
ULONG refcount;
};
extern "C" _declspec(dllexport) LPEXCHEXT CALLBACK ExchEntryPoint(void);
LPEXCHEXT CALLBACK ExchEntryPoint()
{
return new CMyExt;
}
STDMETHODIMP CMyExt::Install(
IExchExtCallback *pmecb,
ULONG mcontext,
ULONG ulFlags)
{
return S_OK;
}
STDMETHODIMP CMyExt::OnRead(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnReadComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnWrite(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
/////////////////////////////////////////////////////////
// When we get called here, MAPI has finished writing all the
// properties to the message, but the message has not been submitted yet.
/////////////////////////////////////////////////////////
STDMETHODIMP CMyExt::OnWriteComplete(IExchExtCallback *lpExchangeCallback,
ULONG ulFlags)
{
LPMESSAGE lpMessage = NULL;
LPMDB lpMdb = NULL;
MessageBox(NULL, "Open message", "Test Extension", MB_OK);
if ((SUCCEEDED(lpExchangeCallback->GetObject(&lpMdb, (LPMAPIPROP
*)&lpMessage)))&& (lpMessage))
{
if (lpMessage != NULL)
{
lpMessage->Release();
lpMessage = NULL;
}
if (lpMdb != NULL)
{
lpMdb->Release();
lpMdb = NULL;
}
}
MessageBox(NULL, "Finished", "Test Extension", MB_OK);
return S_FALSE;
}
STDMETHODIMP CMyExt::OnCheckNames(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnCheckNamesComplete(IExchExtCallback
*lpExchangeCallback, ULONG ulFlags)
{
return S_FALSE;
}
STDMETHODIMP CMyExt::OnSubmit(IExchExtCallback *lpExchangeCallback)
{
return S_FALSE;
}
VOID CMyExt::OnSubmitComplete(IExchExtCallback *lpExchangeCallback, ULONG
ulFlags)
{
}
Thank you for any advice.
Vladimir Werskov