Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1452 lines
38 KiB

/*
* a d d r o b j . h
*
*
* Purpose:
* implements an Address object. An ole object representation for
* a resolved email address. Wraps a CAddress object
* also implements an IDataObj for drag-drop
*
* Copyright (C) Microsoft Corp. 1993, 1994.
*
* Owner: brettm
*
*/
#include <pch.hxx>
#include <resource.h>
#include <addrobj.h>
#include <ourguid.h> //addr object guid
#include <dragdrop.h>
#include <menuutil.h>
#include <wells.h>
#include <ipab.h>
#include <fonts.h>
#include <oleutil.h>
#include "menures.h"
#include "header.h"
#include "shlwapip.h"
#include "demand.h"
ASSERTDATA
/*
* c o n s t a n t s
*/
enum
{
iverbProperties=0, //OLEIVERB_PRIMARY
iverbAddToWAB=1,
iverbFind=2,
iverbBlockSender=3,
iverbMax
};
#define CF_ADDROBJ "Outlook Express Recipients"
/*
* t y p e d e f s
*/
/*
* m a c r o s
*/
/*
* g l o b a l d a t a
*/
#pragma BEGIN_CODESPACE_DATA
static char szClipFormatAddrObj[] = CF_ADDROBJ;
#pragma END_CODESPACE_DATA
static FORMATETC rgformatetcADDROBJ[] =
{
{ 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
};
enum
{
iFormatAddrObj=0,
iFormatText,
iFormatUnicode,
cformatetcADDROBJ
};
static BOOL g_fInited=FALSE;
/*
* p r o t o t y p e s
*/
HRESULT HrBuildSelectionWabal(HWND hwndRE, CHARRANGE *pchrg, LPWABAL *lplpWabal);
HRESULT HrBuildOneSelWabal(LPADRINFO lpAdrInfo, LPWABAL *lplpWabal);
/*
* f u n c t i o n s
*/
BOOL FInitAddrObj(BOOL fInit)
{
if(fInit&&g_fInited)
return TRUE;
if(!fInit)
{
//de-init stuff
return TRUE;
}
// Register our clipboard formats
rgformatetcADDROBJ[iFormatAddrObj].cfFormat =
(CLIPFORMAT) RegisterClipboardFormat(szClipFormatAddrObj);
rgformatetcADDROBJ[iFormatText].cfFormat = CF_TEXT;
rgformatetcADDROBJ[iFormatUnicode].cfFormat = CF_UNICODETEXT;
return g_fInited=TRUE;
}
HRESULT CAddrObj::QueryInterface(REFIID riid, void **ppvObject)
{
*ppvObject = NULL; // set to NULL, in case we fail.
if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = (void*)this;
else if (IsEqualIID(riid, IID_IOleObject))
*ppvObject = (void*)(IOleObject*)this;
else if (IsEqualIID(riid, IID_IViewObject))
*ppvObject = (void*)(IViewObject*)this;
else if (IsEqualIID(riid, IID_IPersist))
*ppvObject = (void*)(IPersist*)this;
else if (IsEqualIID(riid, IID_IOleCommandTarget))
*ppvObject = (void *)(IOleCommandTarget *)this;
else
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
ULONG CAddrObj::AddRef(void)
{
return ++m_cRef;
}
ULONG CAddrObj::Release(void)
{
if (--m_cRef==0)
{
delete this;
return 0;
}
return m_cRef;
}
// IOleObject methods:
HRESULT CAddrObj::SetClientSite(LPOLECLIENTSITE pClientSite)
{
CAddrWellCB *pawcb=0;
IRichEditOleCallback *prole=0;
IOleInPlaceSite *pIPS;
m_hwndEdit = NULL;
ReleaseObj(m_lpoleclientsite);
m_lpoleclientsite=0;
if (!pClientSite)
return NOERROR;
// we do this so when we d-d between notes, read/send etc. the triple inherits the
// properies of it's callbacks pab and underlining.
if(!pClientSite->QueryInterface(IID_IRichEditOleCallback, (LPVOID *)&prole))
{
pawcb=(CAddrWellCB *)prole;
m_fUnderline=pawcb->m_fUnderline;
ReleaseObj(prole);
}
if(!pClientSite->QueryInterface(IID_IOleInPlaceSite, (LPVOID *)&pIPS))
{
pIPS->GetWindow(&m_hwndEdit);
pIPS->Release();
}
pClientSite->AddRef();
m_lpoleclientsite = pClientSite;
return NOERROR;
}
HRESULT CAddrObj::GetClientSite(LPOLECLIENTSITE * ppClientSite)
{
*ppClientSite = m_lpoleclientsite;
if(m_lpoleclientsite)
m_lpoleclientsite->AddRef();
return NOERROR;
}
HRESULT CAddrObj::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
{
return NOERROR;
}
HRESULT CAddrObj::Close(DWORD dwSaveOption)
{
return NOERROR;
}
HRESULT CAddrObj::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER * ppmk)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::InitFromData(LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::GetClipboardData(DWORD dwReserved, LPDATAOBJECT * ppDataObject)
{
HRESULT hr;
CAddrObjData *pAddrObjData=0;
LPWABAL lpWabal=0;
Assert(m_lpAdrInfo);
hr=HrBuildOneSelWabal(m_lpAdrInfo, &lpWabal);
if(FAILED(hr))
goto cleanup;
if(!(pAddrObjData = new CAddrObjData(lpWabal)))
{
hr=E_OUTOFMEMORY;
goto cleanup;
}
hr=pAddrObjData->QueryInterface(IID_IDataObject, (LPVOID *)ppDataObject);
cleanup:
ReleaseObj(lpWabal);
ReleaseObj(pAddrObjData);
return hr;
}
HRESULT CAddrObj::DoVerb(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
{
HRESULT hr=0;
HWND hwndUI=GetParent(hwndParent);
LPWAB lpWab=0;
int idsErr=0;
Assert(m_lpAdrInfo);
hr=HrCreateWabObject(&lpWab);
if(FAILED(hr))
goto error;
switch(iVerb)
{
case iverbBlockSender:
// hack. send the wm_command to the note to avoid dupe-code, also the note knows
// if it's news or mail so the correct block sender verb can be applied
SendMessage(GetTopMostParent(hwndUI), WM_COMMAND, MAKELONG(ID_BLOCK_SENDER, 0), 0);
break;
case iverbProperties:
hr=lpWab->HrDetails(hwndUI, &m_lpAdrInfo);
if(FAILED(hr) && hr!=MAPI_E_USER_CANCEL)
idsErr=idsErrAddrProps;
m_padvisesink->OnViewChange(DVASPECT_CONTENT, -1);
break;
case iverbAddToWAB:
if (m_lpAdrInfo->fDistList)
{
// $bug: 12298. don't try and add dist-lists
idsErr=idsErrAddrDupe;
hr = MAPI_E_COLLISION;
}
else
{
hr=lpWab->HrAddToWAB(hwndUI, m_lpAdrInfo);
if(FAILED(hr) && hr!=MAPI_E_USER_CANCEL)
{
if(hr==MAPI_E_COLLISION)
idsErr=idsErrAddrDupe;
else
idsErr=idsErrAddToWAB;
}
}
break;
case iverbFind:
hr = lpWab->HrFind(hwndUI, m_lpAdrInfo->lpwszAddress);
if(FAILED(hr))
idsErr = idsErrFindWAB;
break;
default:
hr=OLEOBJ_S_INVALIDVERB;
break;
}
if(idsErr)
AthMessageBoxW(hwndUI, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsErr), NULL, MB_OK);
error:
ReleaseObj(lpWab);
return hr;
}
HRESULT CAddrObj::EnumVerbs(LPENUMOLEVERB * ppEnumOleVerb)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::Update()
{
return E_NOTIMPL;
}
HRESULT CAddrObj::IsUpToDate()
{
return E_NOTIMPL;
}
HRESULT CAddrObj::GetUserClassID(CLSID * pClsid)
{
*pClsid = CLSID_AddrObject;
return NOERROR;
}
HRESULT CAddrObj::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
{
WCHAR szWT[CCHMAX_STRINGRES];
if (AthLoadStringW((dwFormOfType == USERCLASSTYPE_APPNAME ? idsAthena : idsRecipient),szWT, CCHMAX_STRINGRES))
{
*pszUserType = PszDupW(szWT);
}
else
{
*pszUserType = NULL;
}
return(NOERROR);
}
HRESULT CAddrObj::SetExtent(DWORD dwDrawAspect, LPSIZEL psizel)
{
// The object's size is fixed
return E_FAIL;
}
HFONT CAddrObj::_GetFont()
{
HFONT hFont=NULL;
// try and get the message-font from the header, if this fails, fall back to the normal font
if (m_hwndEdit)
hFont = (HFONT)SendMessage(GetParent(m_hwndEdit), WM_HEADER_GETFONT, m_lpAdrInfo->fDistList, 0);
if (!hFont)
hFont = HGetSystemFont(m_lpAdrInfo->fDistList?FNT_SYS_ICON_BOLD:FNT_SYS_ICON);
return hFont;
}
HRESULT CAddrObj::OnFontChange()
{
IAdviseSink *pAS;
if (m_lpoleclientsite &&
m_lpoleclientsite->QueryInterface(IID_IAdviseSink, (LPVOID *)&pAS)==S_OK)
{
pAS->OnViewChange(DVASPECT_CONTENT, -1);
pAS->Release();
}
return S_OK;
}
HRESULT CAddrObj::GetExtent(DWORD dwDrawAspect, LPSIZEL psizel)
{
HFONT hfontOld=NULL;
HDC hdc;
TEXTMETRIC tm;
LPWSTR pwszName;
SIZE size;
SIZEL sizel;
DWORD cch, i;
int cx = 0, chcx;
if (m_hwndEdit)
hdc = GetWindowDC(m_hwndEdit);
else
hdc = GetWindowDC(NULL);
if(!hdc)
return E_OUTOFMEMORY;
Assert(m_lpAdrInfo);
hfontOld = SelectFont(hdc, _GetFont());
pwszName = m_lpAdrInfo->lpwszDisplay;
Assert(pwszName);
GetTextExtentPoint32AthW(hdc, pwszName, lstrlenW(pwszName), &size, DT_NOPREFIX);
GetTextMetrics(hdc, &tm);
sizel.cx = size.cx;
#ifndef DBCS
sizel.cy = size.cy - tm.tmDescent; // Same height as normal line (RAID11516 was +1)
#else
sizel.cy = tm.tmAscent + 2;
#endif
XformSizeInPixelsToHimetric(hdc, &sizel, psizel);
if (hfontOld)
SelectFont(hdc, hfontOld);
if (m_hwndEdit)
ReleaseDC(m_hwndEdit, hdc);
else
ReleaseDC(NULL, hdc);
return NOERROR;
}
HRESULT CAddrObj::Advise (LPADVISESINK pAdvSink, DWORD * pdwConnection)
{
if (m_poleadviseholder)
return m_poleadviseholder->Advise(pAdvSink, pdwConnection);
else
return OLE_E_ADVISENOTSUPPORTED;
}
HRESULT CAddrObj::Unadvise(DWORD dwConnection)
{
if (m_poleadviseholder)
return m_poleadviseholder->Unadvise(dwConnection);
else
return E_FAIL;
}
HRESULT CAddrObj::EnumAdvise(LPENUMSTATDATA * ppenumAdvise)
{
if(m_poleadviseholder)
return m_poleadviseholder->EnumAdvise(ppenumAdvise);
else
return OLE_E_ADVISENOTSUPPORTED;
}
HRESULT CAddrObj::GetMiscStatus(DWORD dwAspect, DWORD * pdwStatus)
{
*pdwStatus = 0;
return NOERROR;
}
HRESULT CAddrObj::SetColorScheme(LPLOGPALETTE lpLogpal)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pCmdText)
{
if (pguidCmdGroup == NULL)
return OLECMDERR_E_UNKNOWNGROUP;
if (IsEqualGUID(CMDSETID_OutlookExpress, *pguidCmdGroup))
{
for (ULONG ul = 0; ul < cCmds; ul++)
{
rgCmds[ul].cmdf = 0;
switch (rgCmds[ul].cmdID)
{
case ID_ADDROBJ_OLE_BLOCK_SENDER:
rgCmds[ul].cmdf = (m_lpAdrInfo->lRecipType == MAPI_ORIG) ? OLECMDF_ENABLED|OLECMDF_SUPPORTED : 0;
break;
case ID_ADDROBJ_OLE_PROPERTIES:
rgCmds[ul].cmdf = OLECMDF_ENABLED|OLECMDF_SUPPORTED;
break;
case ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK:
case ID_ADDROBJ_OLE_FIND:
rgCmds[ul].cmdf = OLECMDF_SUPPORTED;
if (m_lpAdrInfo->lpwszAddress)
rgCmds[ul].cmdf |= OLECMDF_ENABLED;
break;
}
}
return S_OK;
}
else
return OLECMDERR_E_UNKNOWNGROUP;
}
HRESULT CAddrObj::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
// we should use DoVerb for this
return E_NOTIMPL;
}
// IViewObject methods:
HRESULT CAddrObj::Draw(DWORD dwDrawAspect, LONG lindex, void * pvAspect,
DVTARGETDEVICE * ptd, HDC hicTargetDev, HDC hdcDraw,
LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
BOOL (CALLBACK * pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue)
{
HFONT hfontOld=NULL;
RECT rect;
LPWSTR pwszName;
TEXTMETRIC tm;
HPEN hPen,
hPenOld;
COLORREF hColor;
Assert(m_lpAdrInfo);
// Need to convert from RECTL to RECT
rect.left = (INT) lprcBounds->left;
rect.top = (INT) lprcBounds->top;
rect.right = (INT) lprcBounds->right;
rect.bottom = (INT) lprcBounds->bottom;
hColor = GetSysColor(COLOR_WINDOWTEXT);
if (m_fUnderline && m_lpAdrInfo->lpwszAddress == NULL && !m_lpAdrInfo->fDistList)
{
// if a compose-note, and there is no address then we show recipients with no email in red
hColor = RGB(0xFF, 0, 0);
if (GetSysColor(COLOR_WINDOW) == hColor) // if background is RED, use WHITE
hColor = RGB(0xFF, 0xFF, 0xFF);
}
hfontOld = SelectFont(hdcDraw, _GetFont());
pwszName = m_lpAdrInfo->lpwszDisplay;
SetTextAlign(hdcDraw, TA_BOTTOM);
SetTextColor(hdcDraw, hColor);
ExtTextOutWrapW(hdcDraw, rect.left, rect.bottom, 0, &rect, pwszName, lstrlenW(pwszName), NULL);
if (hfontOld)
SelectObject(hdcDraw, hfontOld);
GetTextMetrics(hdcDraw, &tm);
if (m_fUnderline)
{
// we want this underlined...
hPen=CreatePen(PS_SOLID, 0, hColor);
if(!hPen)
return E_OUTOFMEMORY;
hPenOld=(HPEN)SelectPen(hdcDraw, hPen);
MoveToEx(hdcDraw, rect.left, rect.bottom - tm.tmDescent + 1, NULL);
LineTo(hdcDraw, rect.right, rect.bottom - tm.tmDescent + 1);
SelectPen(hdcDraw, hPenOld);
DeleteObject(hPen);
}
return NOERROR;
}
HRESULT CAddrObj::GetColorSet(DWORD dwDrawAspect,
LONG lindex,
void *pvAspect,
DVTARGETDEVICE *ptd,
HDC hicTargetDev,
LPLOGPALETTE *ppColorSet)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::Freeze(DWORD dwDrawAspect, LONG lindex, void * pvAspect, DWORD * pdwFreeze)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::Unfreeze(DWORD dwFreeze)
{
return E_NOTIMPL;
}
HRESULT CAddrObj::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink * pAdvSnk)
{
if(m_padvisesink)
m_padvisesink->Release();
if(pAdvSnk)
pAdvSnk->AddRef();
m_padvisesink = pAdvSnk;
return NOERROR;
}
HRESULT CAddrObj::GetAdvise(DWORD * pAspects, DWORD * pAdvf, IAdviseSink ** ppAdvSnk)
{
return E_NOTIMPL;
}
// IPersit methods:
HRESULT CAddrObj::GetClassID(CLSID *pClsID)
{
*pClsID = CLSID_AddrObject;
return NOERROR;
}
CAddrObj::CAddrObj()
{
m_cRef=1;
m_fUnderline=TRUE;
m_lpoleclientsite = 0;
m_pstg = 0;
m_padvisesink = 0;
CreateOleAdviseHolder(&m_poleadviseholder);
// copy props
m_lpAdrInfo = NULL;
}
HRESULT CAddrObj::HrSetAdrInfo(LPADRINFO lpAdrInfo)
{
if(m_lpAdrInfo)
{
MemFree(m_lpAdrInfo);
m_lpAdrInfo=0;
}
// has to have a valid address, or else be a distlist...
Assert(lpAdrInfo->lpwszDisplay);
Assert(lpAdrInfo->lpbEID);
return HrDupeAddrInfo(lpAdrInfo, &m_lpAdrInfo);
}
HRESULT CAddrObj::HrGetAdrInfo(LPADRINFO *lplpAdrInfo)
{
Assert(lplpAdrInfo);
*lplpAdrInfo=m_lpAdrInfo;
return NOERROR;
};
CAddrObj::~CAddrObj()
{
ReleaseObj(m_lpoleclientsite);
ReleaseObj(m_pstg);
ReleaseObj(m_poleadviseholder);
ReleaseObj(m_padvisesink);
// this is our own copy, we must free it!
if(m_lpAdrInfo)
MemFree(m_lpAdrInfo);
}
/*
* I D a t a O b j e c t m e t h o d s:
*
*
*
*/
HRESULT CAddrObjData::GetData(FORMATETC * pformatetcIn, STGMEDIUM * pmedium)
{
return HrGetDataHereOrThere(pformatetcIn, pmedium);
}
HRESULT CAddrObjData::GetDataHere(FORMATETC * pformatetc, STGMEDIUM *pmedium)
{
return HrGetDataHereOrThere(pformatetc, pmedium);
}
HRESULT CAddrObjData::QueryGetData(FORMATETC * pformatetc )
{
LONG iformatetc;
LPFORMATETC pformatetcT = rgformatetcADDROBJ;
CLIPFORMAT cfFormat = pformatetc->cfFormat;
DWORD tymed = pformatetc->tymed;
for (iformatetc = 0; iformatetc < cformatetcADDROBJ;
++iformatetc, ++pformatetcT)
{
// Stop searching if we have compatible formats and mediums
if (pformatetcT->cfFormat == cfFormat &&
(pformatetcT->tymed & tymed))
return NOERROR;
}
return ResultFromScode(S_FALSE);
}
HRESULT CAddrObjData::GetCanonicalFormatEtc(FORMATETC * pformatetcIn, FORMATETC * pFormatetcOut)
{
return DATA_S_SAMEFORMATETC;
}
HRESULT CAddrObjData::SetData(FORMATETC * pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
{
return E_NOTIMPL;
}
HRESULT CAddrObjData::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatEtc )
{
return CreateEnumFormatEtc(this, cformatetcADDROBJ, NULL, rgformatetcADDROBJ, ppenumFormatEtc);
}
HRESULT CAddrObjData::DAdvise(FORMATETC * pformatetc, DWORD advf, IAdviseSink *pAdvSnk, DWORD * pdwConnection)
{
return E_NOTIMPL;
}
HRESULT CAddrObjData::DUnadvise(DWORD dwConnection)
{
return E_NOTIMPL;
}
HRESULT CAddrObjData::EnumDAdvise(IEnumSTATDATA ** ppenumAdvise )
{
return E_NOTIMPL;
}
HRESULT CAddrObjData::QueryInterface(REFIID riid, void **ppvObject)
{
*ppvObject = NULL; // set to NULL, in case we fail.
if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = (void*)this;
else if (IsEqualIID(riid, IID_IDataObject))
*ppvObject = (void*)(IDataObject*)this;
else
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
ULONG CAddrObjData::AddRef(void)
{
return ++m_cRef;
}
ULONG CAddrObjData::Release(void)
{
if (--m_cRef==0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT CAddrObjData::HrGetDataHereOrThere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
{
HRESULT hr=NOERROR;
BOOL fFound;
ADRINFO adrInfo;
ULONG cb=0;
LPBYTE pDst, pBeg;
int cch = 0;
Assert(m_lpWabal);
if (pformatetcIn->cfFormat == rgformatetcADDROBJ[iFormatAddrObj].cfFormat)
{
pmedium->tymed = TYMED_HGLOBAL;
pmedium->pUnkForRelease = NULL;
return m_lpWabal->HrBuildHGlobal(&pmedium->hGlobal);
}
else if ((pformatetcIn->cfFormat != rgformatetcADDROBJ[iFormatText].cfFormat) &&
(pformatetcIn->cfFormat != rgformatetcADDROBJ[iFormatUnicode].cfFormat))
{
return DATA_E_FORMATETC;
}
fFound=m_lpWabal->FGetFirst(&adrInfo);
while(fFound)
{
Assert(adrInfo.lpwszDisplay);
cb+=(lstrlenW(adrInfo.lpwszDisplay)+2)*sizeof(WCHAR); // +2 for '; '
if (adrInfo.lpwszAddress)
{
cb+=(lstrlenW(adrInfo.lpwszAddress)+3)*sizeof(WCHAR); // +3 for ' <>'
}
fFound=m_lpWabal->FGetNext(&adrInfo);
}
cb+=sizeof(WCHAR); // null term
if (pmedium->tymed == TYMED_NULL ||
(pmedium->tymed == TYMED_HGLOBAL && pmedium->hGlobal == NULL))
{
// This is easy, we can quit right after copying stuff
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, cb);
pmedium->pUnkForRelease = NULL;
}
else if (pmedium->tymed == TYMED_HGLOBAL && pmedium->hGlobal != NULL)
{
HGLOBAL hGlobal;
// Caller wants us to fill his hGlobal
// Realloc the destination to make sure there is enough room
if (!(hGlobal = GlobalReAlloc(pmedium->hGlobal, cb, 0)))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
pmedium->hGlobal = hGlobal;
}
else
goto Cleanup;
if (!pmedium->hGlobal)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
cch = (cb/sizeof(WCHAR));
pBeg = pDst = (LPBYTE)GlobalLock(pmedium->hGlobal);
fFound=m_lpWabal->FGetFirst(&adrInfo);
while(fFound)
{
ULONG cbItem = lstrlenW(adrInfo.lpwszDisplay) * sizeof(WCHAR);
if (adrInfo.lpwszAddress)
{
cbItem += (lstrlenW(adrInfo.lpwszAddress) + 3) * sizeof(WCHAR); //+3 " <>"
}
if (adrInfo.lpwszAddress)
{
wnsprintfW((LPWSTR)pDst, cch, L"%s <%s>", adrInfo.lpwszDisplay, adrInfo.lpwszAddress);
}
else
{
StrCpyNW((LPWSTR)pDst, adrInfo.lpwszDisplay, cch);
}
pDst+=cbItem;
cch -= (cbItem/sizeof(WCHAR));
fFound=m_lpWabal->FGetNext(&adrInfo);
if(fFound)
{
// if more, add a '; '
*((LPWSTR) pDst) = L';';
pDst += sizeof(WCHAR);
*((LPWSTR) pDst) = L' ';
pDst += sizeof(WCHAR);
*((LPWSTR) pDst) = L'\0';
cch -= 2;
}
}
//From MSDN:
// CF_TEXT Specifies the standard American National Standards Institute (ANSI) text format.
//The string needs to be ANSI...convert it.
if(pformatetcIn->cfFormat == CF_TEXT)
{
WCHAR *pwszDup;
int cCopied;
IF_NULLEXIT(pwszDup = StrDupW((LPWSTR)pBeg));
cCopied = WideCharToMultiByte(CP_ACP, 0, pwszDup, lstrlenW(pwszDup), (LPTSTR)pBeg, cb, NULL, NULL);
pBeg[cCopied] = '\0';
MemFree(pwszDup);
}
GlobalUnlock(pmedium->hGlobal);
exit:
Cleanup:
return hr;
}
CAddrObjData::CAddrObjData(LPWABAL lpWabal)
{
m_cRef=1;
Assert(lpWabal);
m_lpWabal=lpWabal;
if(lpWabal)
lpWabal->AddRef();
};
CAddrObjData::~CAddrObjData()
{
ReleaseObj(m_lpWabal);
};
CAddrWellCB::CAddrWellCB(BOOL fUnderline, BOOL fHasAddrObjs)
{
m_cRef=1;
m_hwndEdit = 0;
m_fUnderline = fUnderline;
m_fHasAddrObjs=fHasAddrObjs;
}
CAddrWellCB::~CAddrWellCB()
{
}
BOOL CAddrWellCB::FInit(HWND hwndEdit)
{
// make sure addrobj's DD guid's are registered
if(!FInitAddrObj(TRUE))
return FALSE;
if(!IsWindow(hwndEdit))
return FALSE;
m_hwndEdit = hwndEdit;
return TRUE;
}
HRESULT CAddrWellCB::QueryInterface(REFIID riid, LPVOID FAR * lplpObj)
{
*lplpObj = NULL; // set to NULL, in case we fail.
if (IsEqualIID(riid, IID_IUnknown))
*lplpObj = (void*)(IUnknown*)this;
else if (IsEqualIID(riid, IID_IRichEditOleCallback))
*lplpObj = (void*)(IRichEditOleCallback*)this;
else
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
ULONG CAddrWellCB::AddRef()
{
return ++m_cRef;
}
ULONG CAddrWellCB::Release()
{
if (--m_cRef==0)
{
delete this;
return 0;
}
else
return m_cRef;
}
HRESULT CAddrWellCB::GetNewStorage (LPSTORAGE FAR * ppstg)
{
if (*ppstg)
ppstg=NULL;
AssertSz(FALSE, "this code should not get hit for OE");
return E_NOTIMPL;
}
HRESULT CAddrWellCB::GetInPlaceContext( LPOLEINPLACEFRAME FAR * lplpFrame,
LPOLEINPLACEUIWINDOW FAR * lplpDoc,
LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
return E_NOTIMPL;
}
HRESULT CAddrWellCB::ShowContainerUI(BOOL fShow)
{
return E_NOTIMPL;
}
HRESULT CAddrWellCB::QueryInsertObject(LPCLSID lpclsid,
LPSTORAGE lpstg,
LONG cp)
{
if(!m_fHasAddrObjs)
return E_NOTIMPL;
if (IsEqualIID(*lpclsid, CLSID_AddrObject))
return NOERROR;
else
return E_FAIL;
}
HRESULT CAddrWellCB::DeleteObject(LPOLEOBJECT lpoleobj)
{
return NOERROR;
}
HRESULT CAddrWellCB::QueryAcceptData(LPDATAOBJECT pdataobj,
CLIPFORMAT FAR *pcfFormat,
DWORD reco,
BOOL fReally,
HGLOBAL hMetaPict)
{
HRESULT hr;
STGMEDIUM stgmedium;
LPWABAL lpWabal=0;
ADRINFO adrInfo;
if(!m_fHasAddrObjs)
{
// of we're a regular callback, take TEXTONLY
*pcfFormat=CF_TEXT;
return NOERROR;
}
if (!*pcfFormat)
{
// default to text
*pcfFormat = CF_TEXT;
// Cool, it's one of ours...
if(pdataobj->QueryGetData(&rgformatetcADDROBJ[iFormatAddrObj])==NOERROR)
*pcfFormat = rgformatetcADDROBJ[iFormatAddrObj].cfFormat;
}
else
{
if (*pcfFormat != rgformatetcADDROBJ[iFormatAddrObj].cfFormat
&& *pcfFormat != rgformatetcADDROBJ[iFormatText].cfFormat)
return DATA_E_FORMATETC;
}
if (*pcfFormat==CF_TEXT) // let the richedit take care of text
return NOERROR;
// If I'm read-only, return Success and Richedit won't do anything
if (GetWindowLong(m_hwndEdit, GWL_STYLE) & ES_READONLY)
return NOERROR;
if (!fReally) // return that we'll import it ourselves
return ResultFromScode(S_FALSE);
hr=pdataobj->GetData(&rgformatetcADDROBJ[iFormatAddrObj], &stgmedium);
if(FAILED(hr))
goto Cleanup;
hr=HrCreateWabalObjectFromHGlobal(stgmedium.hGlobal, &lpWabal);
if(FAILED(hr))
goto Cleanup;
if(lpWabal->FGetFirst(&adrInfo))
{
// don't add semi colon before first entry!
HrAddRecipientToWell(m_hwndEdit, (LPADRINFO)&adrInfo);
while(lpWabal->FGetNext(&adrInfo))
{
HdrSetRichEditText(m_hwndEdit, L"; ", TRUE);
HrAddRecipientToWell(m_hwndEdit, (LPADRINFO)&adrInfo);
}
}
// free the hglobal
GlobalFree(stgmedium.hGlobal);
ReleaseObj(lpWabal);
hr = ResultFromScode(S_FALSE);
Cleanup:
return hr;
}
HRESULT CAddrWellCB::ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}
HRESULT CAddrWellCB::GetClipboardData(CHARRANGE FAR * pchrg,
DWORD reco,
LPDATAOBJECT FAR * ppdataobj)
{
HRESULT hr;
CAddrObjData *lpAddrObjData=0;
LPWABAL lpWabal=0;
ULONG uSelType;
if(!m_fHasAddrObjs)
return E_NOTIMPL;
Assert(ppdataobj);
*ppdataobj=0;
// Need to prevent cut on read only
if (reco == RECO_CUT &&
(GetWindowStyle(m_hwndEdit)&ES_READONLY))
return E_NOTIMPL;
// if there is only text in the selection, let the richedit take care of it!
uSelType= (ULONG) SendMessage(m_hwndEdit, EM_SELECTIONTYPE, 0, 0);
if(!(uSelType&SEL_OBJECT))
return E_NOTIMPL;
hr=HrBuildSelectionWabal(m_hwndEdit, pchrg, &lpWabal);
if(FAILED(hr))
return E_FAIL;
// this will gobble up the pal so I don't want to free it
if(!(lpAddrObjData= new CAddrObjData(lpWabal)))
{
hr=E_OUTOFMEMORY;
goto error;
}
hr=lpAddrObjData->QueryInterface(IID_IDataObject, (LPVOID *)ppdataobj);
ReleaseObj(lpAddrObjData);
error:
ReleaseObj(lpWabal);
return hr;
}
HRESULT CAddrWellCB::GetDragDropEffect(BOOL fDrag,
DWORD grfKeyState,
LPDWORD pdwEffect)
{
if(!m_fHasAddrObjs)
return E_NOTIMPL;
if (fDrag) // use the default
return NOERROR;
if (GetWindowLong(m_hwndEdit, GWL_STYLE) & ES_READONLY)
*pdwEffect = DROPEFFECT_NONE;
else
{
if ((grfKeyState & MK_CONTROL) || !(*pdwEffect & DROPEFFECT_MOVE))
*pdwEffect = DROPEFFECT_COPY;
else
*pdwEffect = DROPEFFECT_MOVE;
}
return NOERROR;
}
HRESULT CAddrWellCB::GetContextMenu(WORD seltype,
LPOLEOBJECT pOleObject,
CHARRANGE FAR *pchrg,
HMENU FAR *phMenu)
{
HMENU hMenu=0;
DWORD dwFlags=0;
IOleCommandTarget *pCmdTarget;
OLECMD rgCmds[] = {
{ID_ADDROBJ_OLE_FIND, 0},
{ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, 0},
{ID_ADDROBJ_OLE_PROPERTIES, 0},
{ID_ADDROBJ_OLE_BLOCK_SENDER, 0}};
if (!(hMenu=LoadPopupMenu(IDR_ADDRESS_POPUP)))
return E_OUTOFMEMORY;
if (!m_fHasAddrObjs || pOleObject==NULL)
{
// if this RICHEDIT control does not care about ADDROBJECT or if there is
// no addr object selected, then just return a
// regular cut|copy|paste menu
RemoveMenu(hMenu, ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_ADDROBJ_OLE_FIND, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_ADDROBJ_OLE_BLOCK_SENDER, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_SEPARATOR_1, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_SEPARATOR_3, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_ADDROBJ_OLE_PROPERTIES, MF_BYCOMMAND);
}
else
{
// if we get this far, then we have an ole object, make sure it's one we know
// about if we're an addrobj well
#ifdef DEBUG
AssertValidAddrObject(pOleObject);
#endif
// try and see if the object can handle the commands
if (pOleObject->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget)==S_OK)
{
if (pCmdTarget->QueryStatus(&CMDSETID_OutlookExpress, ARRAYSIZE(rgCmds), rgCmds, NULL)==S_OK)
{
for(ULONG ul=0; ul<sizeof(rgCmds)/sizeof(OLECMD); ul++)
{
EnableMenuItem(hMenu, rgCmds[ul].cmdID, (rgCmds[ul].cmdf&OLECMDF_ENABLED ? MF_ENABLED: MF_GRAYED)|MF_BYCOMMAND);
if (!(rgCmds[ul].cmdf&OLECMDF_SUPPORTED))
RemoveMenu(hMenu, rgCmds[ul].cmdID, MF_BYCOMMAND);
}
}
pCmdTarget->Release();
}
// if an Object has focus, then we show the commands before the separator
// if there is an object in selction, remove SelectAll
RemoveMenu(hMenu, ID_SEPARATOR_2, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_SELECT_ALL, MF_BYCOMMAND);
if (SendMessage(m_hwndEdit, EM_SELECTIONTYPE, 0, 0) != SEL_OBJECT)
{
// multiple objects selected, let's grey out addrobj commands
EnableMenuItem(hMenu, ID_ADDROBJ_OLE_PROPERTIES, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(hMenu, ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(hMenu, ID_ADDROBJ_OLE_FIND, MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(hMenu, ID_ADDROBJ_OLE_BLOCK_SENDER, MF_GRAYED|MF_BYCOMMAND);
}
}
// if we are a readonly edit, then remove cut and paste
if (FReadOnlyEdit(m_hwndEdit))
{
// remove cut and past if readonly
RemoveMenu(hMenu, ID_CUT, MF_BYCOMMAND);
RemoveMenu(hMenu, ID_PASTE, MF_BYCOMMAND);
}
MenuUtil_SetPopupDefault(hMenu, ID_ADDROBJ_OLE_PROPERTIES);
GetEditDisableFlags(m_hwndEdit, &dwFlags);
EnableDisableEditMenu(hMenu, dwFlags);
*phMenu=hMenu;
return S_OK;
}
#ifdef DEBUG
void AssertValidAddrObject(LPUNKNOWN pUnk)
{
BOOL fValid=FALSE;
LPOLEOBJECT pOleObject;
CLSID clsid;
Assert(pUnk);
if(!pUnk->QueryInterface(IID_IOleObject, (LPVOID *)&pOleObject))
{
if((pOleObject->GetUserClassID(&clsid)==NOERROR) &&
IsEqualCLSID(clsid, CLSID_AddrObject))
fValid=TRUE;
ReleaseObj(pOleObject);
}
AssertSz(fValid, "WHOA! This is not an AddrObject!");
}
#endif
HRESULT HrBuildSelectionAddrInfoList(HWND hwndRE, CHARRANGE *pchrg, LPADRINFOLIST *lplpAdrInfoList)
{
return NOERROR;
}
HRESULT HrBuildOneSelWabal(LPADRINFO lpAdrInfo, LPWABAL *lplpWabal)
{
LPWABAL lpWabal=0;
HRESULT hr;
if(!lplpWabal)
return E_INVALIDARG;
hr=HrCreateWabalObject(&lpWabal);
if(FAILED(hr))
goto error;
hr=lpWabal->HrAddEntry(lpAdrInfo);
if(FAILED(hr))
goto error;
*lplpWabal=lpWabal;
lpWabal->AddRef();
error:
ReleaseObj(lpWabal);
return hr;
}
#define iswhite(_ch) (_ch==' ' || _ch=='\t' || _ch=='\n' || _ch=='\r')
/*
* ScBuildSelectionAdrlist
*
* Purpose:
* This function will add all the resolved and unresolved
* names from the selection in an edit control to an ADRLIST
*
* Parameters:
* ppal pointer to pointer to ADRLIST
* hwndEdit hwnd of the edit control
* pchrg CHARRANGE of the selection
*
* Returns:
* sc
*/
HRESULT HrBuildSelectionWabal(HWND hwndRE, CHARRANGE *pchrg, LPWABAL *lplpWabal)
{
ULONG iOb,
cOb,
cb,
cchBuf = 0,
cchSel;
LPRICHEDITOLE preole;
REOBJECT reobj = {0};
LPWABAL lpWabal = NULL;
HRESULT hr;
WCHAR rgch[cchUnresolvedMax];
LPWSTR pbStart = NULL,
pbSel;
BOOL fTruncated = FALSE;
PHCI phci;
Assert(pchrg);
cchSel = pchrg->cpMax-pchrg->cpMin;
// Add all the resolved names (stored as OLE objects) from
// hwndEdit to the ADRLIST
reobj.cbStruct = sizeof(REOBJECT);
if(!MemAlloc((LPVOID *)&pbStart, (cchSel+1)*sizeof(WCHAR)))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
pbSel = pbStart;
hr=HrCreateWabalObject(&lpWabal);
if(FAILED(hr))
goto Cleanup;
// if we're building a Wabal, there MUST be some object in the selection!
Assert((SendMessage(hwndRE, EM_SELECTIONTYPE, 0, 0)&SEL_OBJECT));
phci = (HCI*)GetWindowLongPtr(hwndRE, GWLP_USERDATA);
AssertSz(phci, "How did we get a richedit without a phci???");
preole = phci->preole;
AssertSz(preole, "How did we get a phci without a preole???");
// count up the number of objects in the selction, and the number of
// bytes in them...
cOb = preole->GetObjectCount();
for (iOb = 0; iOb < cOb; iOb++)
{
hr=preole->GetObject(iOb, &reobj, REO_GETOBJ_POLEOBJ);
if(FAILED(hr))
goto Cleanup;
if (reobj.cp >= pchrg->cpMax) // out of the selrange...
break;
if (reobj.cp >= pchrg->cpMin)
{
LPPERSIST ppersist = NULL;
LPADRINFO lpAdrInfo = 0;
if (FAILED(hr = reobj.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&ppersist)))
goto Cleanup;
hr = ((CAddrObj *)ppersist)->HrGetAdrInfo(&lpAdrInfo);
lpWabal->HrAddEntry(lpAdrInfo);
ReleaseObj(ppersist);
if(FAILED(hr))
goto Cleanup;
}
ReleaseObj(reobj.poleobj);
reobj.poleobj = NULL;
}
// walk the unresolved text, and parse it up into unresolved names...
cb = HdrGetRichEditText(hwndRE, pbSel, cchSel, TRUE) + 1;
//$ BUG - broken for Unicode
// The algorithm below will strip spaces off of the
// beginning and end of each name
while (cb--)
{
if (*pbSel == L'\t')
*pbSel = L' ';
if ((*pbSel == L'\0') || (*pbSel == L';') || (*pbSel == L'\r'))
{
if(cchBuf)
{
LPWSTR psz = rgch + cchBuf - 1;
while(cchBuf > 0)
{
// Exchange #10168.
if((*psz == L' ') || (*psz == L'\t'))
{
cchBuf--;
psz--;
}
else
break;
}
}
if (cchBuf)
{
rgch[cchBuf] = L'\0';
lpWabal->HrAddUnresolved(rgch, (ULONG)-1);
cchBuf = 0;
}
}
else
{
if (((*pbSel != L' ') && (*pbSel != L'\n') && (*pbSel != L'\r')) || cchBuf > 0)
{
if (cchBuf < cchUnresolvedMax - 1)
rgch[cchBuf++] = *pbSel;
else
fTruncated = TRUE;
}
}
++pbSel;
}
*lplpWabal=lpWabal;
lpWabal->AddRef();
Cleanup:
MemFree(pbStart);
ReleaseObj(lpWabal);
ReleaseObj(reobj.poleobj);
return hr;
}