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
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;
|
|
}
|
|
|