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

  1. /*
  2. * a d d r o b j . h
  3. *
  4. *
  5. * Purpose:
  6. * implements an Address object. An ole object representation for
  7. * a resolved email address. Wraps a CAddress object
  8. * also implements an IDataObj for drag-drop
  9. *
  10. * Copyright (C) Microsoft Corp. 1993, 1994.
  11. *
  12. * Owner: brettm
  13. *
  14. */
  15. #include <pch.hxx>
  16. #include <resource.h>
  17. #include <addrobj.h>
  18. #include <ourguid.h> //addr object guid
  19. #include <dragdrop.h>
  20. #include <menuutil.h>
  21. #include <wells.h>
  22. #include <ipab.h>
  23. #include <fonts.h>
  24. #include <oleutil.h>
  25. #include "menures.h"
  26. #include "header.h"
  27. #include "shlwapip.h"
  28. #include "demand.h"
  29. ASSERTDATA
  30. /*
  31. * c o n s t a n t s
  32. */
  33. enum
  34. {
  35. iverbProperties=0, //OLEIVERB_PRIMARY
  36. iverbAddToWAB=1,
  37. iverbFind=2,
  38. iverbBlockSender=3,
  39. iverbMax
  40. };
  41. #define CF_ADDROBJ "Outlook Express Recipients"
  42. /*
  43. * t y p e d e f s
  44. */
  45. /*
  46. * m a c r o s
  47. */
  48. /*
  49. * g l o b a l d a t a
  50. */
  51. #pragma BEGIN_CODESPACE_DATA
  52. static char szClipFormatAddrObj[] = CF_ADDROBJ;
  53. #pragma END_CODESPACE_DATA
  54. static FORMATETC rgformatetcADDROBJ[] =
  55. {
  56. { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  57. { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  58. { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
  59. };
  60. enum
  61. {
  62. iFormatAddrObj=0,
  63. iFormatText,
  64. iFormatUnicode,
  65. cformatetcADDROBJ
  66. };
  67. static BOOL g_fInited=FALSE;
  68. /*
  69. * p r o t o t y p e s
  70. */
  71. HRESULT HrBuildSelectionWabal(HWND hwndRE, CHARRANGE *pchrg, LPWABAL *lplpWabal);
  72. HRESULT HrBuildOneSelWabal(LPADRINFO lpAdrInfo, LPWABAL *lplpWabal);
  73. /*
  74. * f u n c t i o n s
  75. */
  76. BOOL FInitAddrObj(BOOL fInit)
  77. {
  78. if(fInit&&g_fInited)
  79. return TRUE;
  80. if(!fInit)
  81. {
  82. //de-init stuff
  83. return TRUE;
  84. }
  85. // Register our clipboard formats
  86. rgformatetcADDROBJ[iFormatAddrObj].cfFormat =
  87. (CLIPFORMAT) RegisterClipboardFormat(szClipFormatAddrObj);
  88. rgformatetcADDROBJ[iFormatText].cfFormat = CF_TEXT;
  89. rgformatetcADDROBJ[iFormatUnicode].cfFormat = CF_UNICODETEXT;
  90. return g_fInited=TRUE;
  91. }
  92. HRESULT CAddrObj::QueryInterface(REFIID riid, void **ppvObject)
  93. {
  94. *ppvObject = NULL; // set to NULL, in case we fail.
  95. if (IsEqualIID(riid, IID_IUnknown))
  96. *ppvObject = (void*)this;
  97. else if (IsEqualIID(riid, IID_IOleObject))
  98. *ppvObject = (void*)(IOleObject*)this;
  99. else if (IsEqualIID(riid, IID_IViewObject))
  100. *ppvObject = (void*)(IViewObject*)this;
  101. else if (IsEqualIID(riid, IID_IPersist))
  102. *ppvObject = (void*)(IPersist*)this;
  103. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  104. *ppvObject = (void *)(IOleCommandTarget *)this;
  105. else
  106. return E_NOINTERFACE;
  107. AddRef();
  108. return NOERROR;
  109. }
  110. ULONG CAddrObj::AddRef(void)
  111. {
  112. return ++m_cRef;
  113. }
  114. ULONG CAddrObj::Release(void)
  115. {
  116. if (--m_cRef==0)
  117. {
  118. delete this;
  119. return 0;
  120. }
  121. return m_cRef;
  122. }
  123. // IOleObject methods:
  124. HRESULT CAddrObj::SetClientSite(LPOLECLIENTSITE pClientSite)
  125. {
  126. CAddrWellCB *pawcb=0;
  127. IRichEditOleCallback *prole=0;
  128. IOleInPlaceSite *pIPS;
  129. m_hwndEdit = NULL;
  130. ReleaseObj(m_lpoleclientsite);
  131. m_lpoleclientsite=0;
  132. if (!pClientSite)
  133. return NOERROR;
  134. // we do this so when we d-d between notes, read/send etc. the triple inherits the
  135. // properies of it's callbacks pab and underlining.
  136. if(!pClientSite->QueryInterface(IID_IRichEditOleCallback, (LPVOID *)&prole))
  137. {
  138. pawcb=(CAddrWellCB *)prole;
  139. m_fUnderline=pawcb->m_fUnderline;
  140. ReleaseObj(prole);
  141. }
  142. if(!pClientSite->QueryInterface(IID_IOleInPlaceSite, (LPVOID *)&pIPS))
  143. {
  144. pIPS->GetWindow(&m_hwndEdit);
  145. pIPS->Release();
  146. }
  147. pClientSite->AddRef();
  148. m_lpoleclientsite = pClientSite;
  149. return NOERROR;
  150. }
  151. HRESULT CAddrObj::GetClientSite(LPOLECLIENTSITE * ppClientSite)
  152. {
  153. *ppClientSite = m_lpoleclientsite;
  154. if(m_lpoleclientsite)
  155. m_lpoleclientsite->AddRef();
  156. return NOERROR;
  157. }
  158. HRESULT CAddrObj::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
  159. {
  160. return NOERROR;
  161. }
  162. HRESULT CAddrObj::Close(DWORD dwSaveOption)
  163. {
  164. return NOERROR;
  165. }
  166. HRESULT CAddrObj::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
  167. {
  168. return E_NOTIMPL;
  169. }
  170. HRESULT CAddrObj::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER * ppmk)
  171. {
  172. return E_NOTIMPL;
  173. }
  174. HRESULT CAddrObj::InitFromData(LPDATAOBJECT pDataObject, BOOL fCreation, DWORD dwReserved)
  175. {
  176. return E_NOTIMPL;
  177. }
  178. HRESULT CAddrObj::GetClipboardData(DWORD dwReserved, LPDATAOBJECT * ppDataObject)
  179. {
  180. HRESULT hr;
  181. CAddrObjData *pAddrObjData=0;
  182. LPWABAL lpWabal=0;
  183. Assert(m_lpAdrInfo);
  184. hr=HrBuildOneSelWabal(m_lpAdrInfo, &lpWabal);
  185. if(FAILED(hr))
  186. goto cleanup;
  187. if(!(pAddrObjData = new CAddrObjData(lpWabal)))
  188. {
  189. hr=E_OUTOFMEMORY;
  190. goto cleanup;
  191. }
  192. hr=pAddrObjData->QueryInterface(IID_IDataObject, (LPVOID *)ppDataObject);
  193. cleanup:
  194. ReleaseObj(lpWabal);
  195. ReleaseObj(pAddrObjData);
  196. return hr;
  197. }
  198. HRESULT CAddrObj::DoVerb(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
  199. {
  200. HRESULT hr=0;
  201. HWND hwndUI=GetParent(hwndParent);
  202. LPWAB lpWab=0;
  203. int idsErr=0;
  204. Assert(m_lpAdrInfo);
  205. hr=HrCreateWabObject(&lpWab);
  206. if(FAILED(hr))
  207. goto error;
  208. switch(iVerb)
  209. {
  210. case iverbBlockSender:
  211. // hack. send the wm_command to the note to avoid dupe-code, also the note knows
  212. // if it's news or mail so the correct block sender verb can be applied
  213. SendMessage(GetTopMostParent(hwndUI), WM_COMMAND, MAKELONG(ID_BLOCK_SENDER, 0), 0);
  214. break;
  215. case iverbProperties:
  216. hr=lpWab->HrDetails(hwndUI, &m_lpAdrInfo);
  217. if(FAILED(hr) && hr!=MAPI_E_USER_CANCEL)
  218. idsErr=idsErrAddrProps;
  219. m_padvisesink->OnViewChange(DVASPECT_CONTENT, -1);
  220. break;
  221. case iverbAddToWAB:
  222. if (m_lpAdrInfo->fDistList)
  223. {
  224. // $bug: 12298. don't try and add dist-lists
  225. idsErr=idsErrAddrDupe;
  226. hr = MAPI_E_COLLISION;
  227. }
  228. else
  229. {
  230. hr=lpWab->HrAddToWAB(hwndUI, m_lpAdrInfo);
  231. if(FAILED(hr) && hr!=MAPI_E_USER_CANCEL)
  232. {
  233. if(hr==MAPI_E_COLLISION)
  234. idsErr=idsErrAddrDupe;
  235. else
  236. idsErr=idsErrAddToWAB;
  237. }
  238. }
  239. break;
  240. case iverbFind:
  241. hr = lpWab->HrFind(hwndUI, m_lpAdrInfo->lpwszAddress);
  242. if(FAILED(hr))
  243. idsErr = idsErrFindWAB;
  244. break;
  245. default:
  246. hr=OLEOBJ_S_INVALIDVERB;
  247. break;
  248. }
  249. if(idsErr)
  250. AthMessageBoxW(hwndUI, MAKEINTRESOURCEW(idsAthenaMail),
  251. MAKEINTRESOURCEW(idsErr), NULL, MB_OK);
  252. error:
  253. ReleaseObj(lpWab);
  254. return hr;
  255. }
  256. HRESULT CAddrObj::EnumVerbs(LPENUMOLEVERB * ppEnumOleVerb)
  257. {
  258. return E_NOTIMPL;
  259. }
  260. HRESULT CAddrObj::Update()
  261. {
  262. return E_NOTIMPL;
  263. }
  264. HRESULT CAddrObj::IsUpToDate()
  265. {
  266. return E_NOTIMPL;
  267. }
  268. HRESULT CAddrObj::GetUserClassID(CLSID * pClsid)
  269. {
  270. *pClsid = CLSID_AddrObject;
  271. return NOERROR;
  272. }
  273. HRESULT CAddrObj::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
  274. {
  275. WCHAR szWT[CCHMAX_STRINGRES];
  276. if (AthLoadStringW((dwFormOfType == USERCLASSTYPE_APPNAME ? idsAthena : idsRecipient),szWT, CCHMAX_STRINGRES))
  277. {
  278. *pszUserType = PszDupW(szWT);
  279. }
  280. else
  281. {
  282. *pszUserType = NULL;
  283. }
  284. return(NOERROR);
  285. }
  286. HRESULT CAddrObj::SetExtent(DWORD dwDrawAspect, LPSIZEL psizel)
  287. {
  288. // The object's size is fixed
  289. return E_FAIL;
  290. }
  291. HFONT CAddrObj::_GetFont()
  292. {
  293. HFONT hFont=NULL;
  294. // try and get the message-font from the header, if this fails, fall back to the normal font
  295. if (m_hwndEdit)
  296. hFont = (HFONT)SendMessage(GetParent(m_hwndEdit), WM_HEADER_GETFONT, m_lpAdrInfo->fDistList, 0);
  297. if (!hFont)
  298. hFont = HGetSystemFont(m_lpAdrInfo->fDistList?FNT_SYS_ICON_BOLD:FNT_SYS_ICON);
  299. return hFont;
  300. }
  301. HRESULT CAddrObj::OnFontChange()
  302. {
  303. IAdviseSink *pAS;
  304. if (m_lpoleclientsite &&
  305. m_lpoleclientsite->QueryInterface(IID_IAdviseSink, (LPVOID *)&pAS)==S_OK)
  306. {
  307. pAS->OnViewChange(DVASPECT_CONTENT, -1);
  308. pAS->Release();
  309. }
  310. return S_OK;
  311. }
  312. HRESULT CAddrObj::GetExtent(DWORD dwDrawAspect, LPSIZEL psizel)
  313. {
  314. HFONT hfontOld=NULL;
  315. HDC hdc;
  316. TEXTMETRIC tm;
  317. LPWSTR pwszName;
  318. SIZE size;
  319. SIZEL sizel;
  320. DWORD cch, i;
  321. int cx = 0, chcx;
  322. if (m_hwndEdit)
  323. hdc = GetWindowDC(m_hwndEdit);
  324. else
  325. hdc = GetWindowDC(NULL);
  326. if(!hdc)
  327. return E_OUTOFMEMORY;
  328. Assert(m_lpAdrInfo);
  329. hfontOld = SelectFont(hdc, _GetFont());
  330. pwszName = m_lpAdrInfo->lpwszDisplay;
  331. Assert(pwszName);
  332. GetTextExtentPoint32AthW(hdc, pwszName, lstrlenW(pwszName), &size, DT_NOPREFIX);
  333. GetTextMetrics(hdc, &tm);
  334. sizel.cx = size.cx;
  335. #ifndef DBCS
  336. sizel.cy = size.cy - tm.tmDescent; // Same height as normal line (RAID11516 was +1)
  337. #else
  338. sizel.cy = tm.tmAscent + 2;
  339. #endif
  340. XformSizeInPixelsToHimetric(hdc, &sizel, psizel);
  341. if (hfontOld)
  342. SelectFont(hdc, hfontOld);
  343. if (m_hwndEdit)
  344. ReleaseDC(m_hwndEdit, hdc);
  345. else
  346. ReleaseDC(NULL, hdc);
  347. return NOERROR;
  348. }
  349. HRESULT CAddrObj::Advise (LPADVISESINK pAdvSink, DWORD * pdwConnection)
  350. {
  351. if (m_poleadviseholder)
  352. return m_poleadviseholder->Advise(pAdvSink, pdwConnection);
  353. else
  354. return OLE_E_ADVISENOTSUPPORTED;
  355. }
  356. HRESULT CAddrObj::Unadvise(DWORD dwConnection)
  357. {
  358. if (m_poleadviseholder)
  359. return m_poleadviseholder->Unadvise(dwConnection);
  360. else
  361. return E_FAIL;
  362. }
  363. HRESULT CAddrObj::EnumAdvise(LPENUMSTATDATA * ppenumAdvise)
  364. {
  365. if(m_poleadviseholder)
  366. return m_poleadviseholder->EnumAdvise(ppenumAdvise);
  367. else
  368. return OLE_E_ADVISENOTSUPPORTED;
  369. }
  370. HRESULT CAddrObj::GetMiscStatus(DWORD dwAspect, DWORD * pdwStatus)
  371. {
  372. *pdwStatus = 0;
  373. return NOERROR;
  374. }
  375. HRESULT CAddrObj::SetColorScheme(LPLOGPALETTE lpLogpal)
  376. {
  377. return E_NOTIMPL;
  378. }
  379. HRESULT CAddrObj::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pCmdText)
  380. {
  381. if (pguidCmdGroup == NULL)
  382. return OLECMDERR_E_UNKNOWNGROUP;
  383. if (IsEqualGUID(CMDSETID_OutlookExpress, *pguidCmdGroup))
  384. {
  385. for (ULONG ul = 0; ul < cCmds; ul++)
  386. {
  387. rgCmds[ul].cmdf = 0;
  388. switch (rgCmds[ul].cmdID)
  389. {
  390. case ID_ADDROBJ_OLE_BLOCK_SENDER:
  391. rgCmds[ul].cmdf = (m_lpAdrInfo->lRecipType == MAPI_ORIG) ? OLECMDF_ENABLED|OLECMDF_SUPPORTED : 0;
  392. break;
  393. case ID_ADDROBJ_OLE_PROPERTIES:
  394. rgCmds[ul].cmdf = OLECMDF_ENABLED|OLECMDF_SUPPORTED;
  395. break;
  396. case ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK:
  397. case ID_ADDROBJ_OLE_FIND:
  398. rgCmds[ul].cmdf = OLECMDF_SUPPORTED;
  399. if (m_lpAdrInfo->lpwszAddress)
  400. rgCmds[ul].cmdf |= OLECMDF_ENABLED;
  401. break;
  402. }
  403. }
  404. return S_OK;
  405. }
  406. else
  407. return OLECMDERR_E_UNKNOWNGROUP;
  408. }
  409. HRESULT CAddrObj::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  410. {
  411. // we should use DoVerb for this
  412. return E_NOTIMPL;
  413. }
  414. // IViewObject methods:
  415. HRESULT CAddrObj::Draw(DWORD dwDrawAspect, LONG lindex, void * pvAspect,
  416. DVTARGETDEVICE * ptd, HDC hicTargetDev, HDC hdcDraw,
  417. LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
  418. BOOL (CALLBACK * pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue)
  419. {
  420. HFONT hfontOld=NULL;
  421. RECT rect;
  422. LPWSTR pwszName;
  423. TEXTMETRIC tm;
  424. HPEN hPen,
  425. hPenOld;
  426. COLORREF hColor;
  427. Assert(m_lpAdrInfo);
  428. // Need to convert from RECTL to RECT
  429. rect.left = (INT) lprcBounds->left;
  430. rect.top = (INT) lprcBounds->top;
  431. rect.right = (INT) lprcBounds->right;
  432. rect.bottom = (INT) lprcBounds->bottom;
  433. hColor = GetSysColor(COLOR_WINDOWTEXT);
  434. if (m_fUnderline && m_lpAdrInfo->lpwszAddress == NULL && !m_lpAdrInfo->fDistList)
  435. {
  436. // if a compose-note, and there is no address then we show recipients with no email in red
  437. hColor = RGB(0xFF, 0, 0);
  438. if (GetSysColor(COLOR_WINDOW) == hColor) // if background is RED, use WHITE
  439. hColor = RGB(0xFF, 0xFF, 0xFF);
  440. }
  441. hfontOld = SelectFont(hdcDraw, _GetFont());
  442. pwszName = m_lpAdrInfo->lpwszDisplay;
  443. SetTextAlign(hdcDraw, TA_BOTTOM);
  444. SetTextColor(hdcDraw, hColor);
  445. ExtTextOutWrapW(hdcDraw, rect.left, rect.bottom, 0, &rect, pwszName, lstrlenW(pwszName), NULL);
  446. if (hfontOld)
  447. SelectObject(hdcDraw, hfontOld);
  448. GetTextMetrics(hdcDraw, &tm);
  449. if (m_fUnderline)
  450. {
  451. // we want this underlined...
  452. hPen=CreatePen(PS_SOLID, 0, hColor);
  453. if(!hPen)
  454. return E_OUTOFMEMORY;
  455. hPenOld=(HPEN)SelectPen(hdcDraw, hPen);
  456. MoveToEx(hdcDraw, rect.left, rect.bottom - tm.tmDescent + 1, NULL);
  457. LineTo(hdcDraw, rect.right, rect.bottom - tm.tmDescent + 1);
  458. SelectPen(hdcDraw, hPenOld);
  459. DeleteObject(hPen);
  460. }
  461. return NOERROR;
  462. }
  463. HRESULT CAddrObj::GetColorSet(DWORD dwDrawAspect,
  464. LONG lindex,
  465. void *pvAspect,
  466. DVTARGETDEVICE *ptd,
  467. HDC hicTargetDev,
  468. LPLOGPALETTE *ppColorSet)
  469. {
  470. return E_NOTIMPL;
  471. }
  472. HRESULT CAddrObj::Freeze(DWORD dwDrawAspect, LONG lindex, void * pvAspect, DWORD * pdwFreeze)
  473. {
  474. return E_NOTIMPL;
  475. }
  476. HRESULT CAddrObj::Unfreeze(DWORD dwFreeze)
  477. {
  478. return E_NOTIMPL;
  479. }
  480. HRESULT CAddrObj::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink * pAdvSnk)
  481. {
  482. if(m_padvisesink)
  483. m_padvisesink->Release();
  484. if(pAdvSnk)
  485. pAdvSnk->AddRef();
  486. m_padvisesink = pAdvSnk;
  487. return NOERROR;
  488. }
  489. HRESULT CAddrObj::GetAdvise(DWORD * pAspects, DWORD * pAdvf, IAdviseSink ** ppAdvSnk)
  490. {
  491. return E_NOTIMPL;
  492. }
  493. // IPersit methods:
  494. HRESULT CAddrObj::GetClassID(CLSID *pClsID)
  495. {
  496. *pClsID = CLSID_AddrObject;
  497. return NOERROR;
  498. }
  499. CAddrObj::CAddrObj()
  500. {
  501. m_cRef=1;
  502. m_fUnderline=TRUE;
  503. m_lpoleclientsite = 0;
  504. m_pstg = 0;
  505. m_padvisesink = 0;
  506. CreateOleAdviseHolder(&m_poleadviseholder);
  507. // copy props
  508. m_lpAdrInfo = NULL;
  509. }
  510. HRESULT CAddrObj::HrSetAdrInfo(LPADRINFO lpAdrInfo)
  511. {
  512. if(m_lpAdrInfo)
  513. {
  514. MemFree(m_lpAdrInfo);
  515. m_lpAdrInfo=0;
  516. }
  517. // has to have a valid address, or else be a distlist...
  518. Assert(lpAdrInfo->lpwszDisplay);
  519. Assert(lpAdrInfo->lpbEID);
  520. return HrDupeAddrInfo(lpAdrInfo, &m_lpAdrInfo);
  521. }
  522. HRESULT CAddrObj::HrGetAdrInfo(LPADRINFO *lplpAdrInfo)
  523. {
  524. Assert(lplpAdrInfo);
  525. *lplpAdrInfo=m_lpAdrInfo;
  526. return NOERROR;
  527. };
  528. CAddrObj::~CAddrObj()
  529. {
  530. ReleaseObj(m_lpoleclientsite);
  531. ReleaseObj(m_pstg);
  532. ReleaseObj(m_poleadviseholder);
  533. ReleaseObj(m_padvisesink);
  534. // this is our own copy, we must free it!
  535. if(m_lpAdrInfo)
  536. MemFree(m_lpAdrInfo);
  537. }
  538. /*
  539. * I D a t a O b j e c t m e t h o d s:
  540. *
  541. *
  542. *
  543. */
  544. HRESULT CAddrObjData::GetData(FORMATETC * pformatetcIn, STGMEDIUM * pmedium)
  545. {
  546. return HrGetDataHereOrThere(pformatetcIn, pmedium);
  547. }
  548. HRESULT CAddrObjData::GetDataHere(FORMATETC * pformatetc, STGMEDIUM *pmedium)
  549. {
  550. return HrGetDataHereOrThere(pformatetc, pmedium);
  551. }
  552. HRESULT CAddrObjData::QueryGetData(FORMATETC * pformatetc )
  553. {
  554. LONG iformatetc;
  555. LPFORMATETC pformatetcT = rgformatetcADDROBJ;
  556. CLIPFORMAT cfFormat = pformatetc->cfFormat;
  557. DWORD tymed = pformatetc->tymed;
  558. for (iformatetc = 0; iformatetc < cformatetcADDROBJ;
  559. ++iformatetc, ++pformatetcT)
  560. {
  561. // Stop searching if we have compatible formats and mediums
  562. if (pformatetcT->cfFormat == cfFormat &&
  563. (pformatetcT->tymed & tymed))
  564. return NOERROR;
  565. }
  566. return ResultFromScode(S_FALSE);
  567. }
  568. HRESULT CAddrObjData::GetCanonicalFormatEtc(FORMATETC * pformatetcIn, FORMATETC * pFormatetcOut)
  569. {
  570. return DATA_S_SAMEFORMATETC;
  571. }
  572. HRESULT CAddrObjData::SetData(FORMATETC * pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
  573. {
  574. return E_NOTIMPL;
  575. }
  576. HRESULT CAddrObjData::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatEtc )
  577. {
  578. return CreateEnumFormatEtc(this, cformatetcADDROBJ, NULL, rgformatetcADDROBJ, ppenumFormatEtc);
  579. }
  580. HRESULT CAddrObjData::DAdvise(FORMATETC * pformatetc, DWORD advf, IAdviseSink *pAdvSnk, DWORD * pdwConnection)
  581. {
  582. return E_NOTIMPL;
  583. }
  584. HRESULT CAddrObjData::DUnadvise(DWORD dwConnection)
  585. {
  586. return E_NOTIMPL;
  587. }
  588. HRESULT CAddrObjData::EnumDAdvise(IEnumSTATDATA ** ppenumAdvise )
  589. {
  590. return E_NOTIMPL;
  591. }
  592. HRESULT CAddrObjData::QueryInterface(REFIID riid, void **ppvObject)
  593. {
  594. *ppvObject = NULL; // set to NULL, in case we fail.
  595. if (IsEqualIID(riid, IID_IUnknown))
  596. *ppvObject = (void*)this;
  597. else if (IsEqualIID(riid, IID_IDataObject))
  598. *ppvObject = (void*)(IDataObject*)this;
  599. else
  600. return E_NOINTERFACE;
  601. AddRef();
  602. return NOERROR;
  603. }
  604. ULONG CAddrObjData::AddRef(void)
  605. {
  606. return ++m_cRef;
  607. }
  608. ULONG CAddrObjData::Release(void)
  609. {
  610. if (--m_cRef==0)
  611. {
  612. delete this;
  613. return 0;
  614. }
  615. return m_cRef;
  616. }
  617. HRESULT CAddrObjData::HrGetDataHereOrThere(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
  618. {
  619. HRESULT hr=NOERROR;
  620. BOOL fFound;
  621. ADRINFO adrInfo;
  622. ULONG cb=0;
  623. LPBYTE pDst, pBeg;
  624. int cch = 0;
  625. Assert(m_lpWabal);
  626. if (pformatetcIn->cfFormat == rgformatetcADDROBJ[iFormatAddrObj].cfFormat)
  627. {
  628. pmedium->tymed = TYMED_HGLOBAL;
  629. pmedium->pUnkForRelease = NULL;
  630. return m_lpWabal->HrBuildHGlobal(&pmedium->hGlobal);
  631. }
  632. else if ((pformatetcIn->cfFormat != rgformatetcADDROBJ[iFormatText].cfFormat) &&
  633. (pformatetcIn->cfFormat != rgformatetcADDROBJ[iFormatUnicode].cfFormat))
  634. {
  635. return DATA_E_FORMATETC;
  636. }
  637. fFound=m_lpWabal->FGetFirst(&adrInfo);
  638. while(fFound)
  639. {
  640. Assert(adrInfo.lpwszDisplay);
  641. cb+=(lstrlenW(adrInfo.lpwszDisplay)+2)*sizeof(WCHAR); // +2 for '; '
  642. if (adrInfo.lpwszAddress)
  643. {
  644. cb+=(lstrlenW(adrInfo.lpwszAddress)+3)*sizeof(WCHAR); // +3 for ' <>'
  645. }
  646. fFound=m_lpWabal->FGetNext(&adrInfo);
  647. }
  648. cb+=sizeof(WCHAR); // null term
  649. if (pmedium->tymed == TYMED_NULL ||
  650. (pmedium->tymed == TYMED_HGLOBAL && pmedium->hGlobal == NULL))
  651. {
  652. // This is easy, we can quit right after copying stuff
  653. pmedium->tymed = TYMED_HGLOBAL;
  654. pmedium->hGlobal = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, cb);
  655. pmedium->pUnkForRelease = NULL;
  656. }
  657. else if (pmedium->tymed == TYMED_HGLOBAL && pmedium->hGlobal != NULL)
  658. {
  659. HGLOBAL hGlobal;
  660. // Caller wants us to fill his hGlobal
  661. // Realloc the destination to make sure there is enough room
  662. if (!(hGlobal = GlobalReAlloc(pmedium->hGlobal, cb, 0)))
  663. {
  664. hr = E_OUTOFMEMORY;
  665. goto Cleanup;
  666. }
  667. pmedium->hGlobal = hGlobal;
  668. }
  669. else
  670. goto Cleanup;
  671. if (!pmedium->hGlobal)
  672. {
  673. hr = E_OUTOFMEMORY;
  674. goto Cleanup;
  675. }
  676. cch = (cb/sizeof(WCHAR));
  677. pBeg = pDst = (LPBYTE)GlobalLock(pmedium->hGlobal);
  678. fFound=m_lpWabal->FGetFirst(&adrInfo);
  679. while(fFound)
  680. {
  681. ULONG cbItem = lstrlenW(adrInfo.lpwszDisplay) * sizeof(WCHAR);
  682. if (adrInfo.lpwszAddress)
  683. {
  684. cbItem += (lstrlenW(adrInfo.lpwszAddress) + 3) * sizeof(WCHAR); //+3 " <>"
  685. }
  686. if (adrInfo.lpwszAddress)
  687. {
  688. wnsprintfW((LPWSTR)pDst, cch, L"%s <%s>", adrInfo.lpwszDisplay, adrInfo.lpwszAddress);
  689. }
  690. else
  691. {
  692. StrCpyNW((LPWSTR)pDst, adrInfo.lpwszDisplay, cch);
  693. }
  694. pDst+=cbItem;
  695. cch -= (cbItem/sizeof(WCHAR));
  696. fFound=m_lpWabal->FGetNext(&adrInfo);
  697. if(fFound)
  698. {
  699. // if more, add a '; '
  700. *((LPWSTR) pDst) = L';';
  701. pDst += sizeof(WCHAR);
  702. *((LPWSTR) pDst) = L' ';
  703. pDst += sizeof(WCHAR);
  704. *((LPWSTR) pDst) = L'\0';
  705. cch -= 2;
  706. }
  707. }
  708. //From MSDN:
  709. // CF_TEXT Specifies the standard American National Standards Institute (ANSI) text format.
  710. //The string needs to be ANSI...convert it.
  711. if(pformatetcIn->cfFormat == CF_TEXT)
  712. {
  713. WCHAR *pwszDup;
  714. int cCopied;
  715. IF_NULLEXIT(pwszDup = StrDupW((LPWSTR)pBeg));
  716. cCopied = WideCharToMultiByte(CP_ACP, 0, pwszDup, lstrlenW(pwszDup), (LPTSTR)pBeg, cb, NULL, NULL);
  717. pBeg[cCopied] = '\0';
  718. MemFree(pwszDup);
  719. }
  720. GlobalUnlock(pmedium->hGlobal);
  721. exit:
  722. Cleanup:
  723. return hr;
  724. }
  725. CAddrObjData::CAddrObjData(LPWABAL lpWabal)
  726. {
  727. m_cRef=1;
  728. Assert(lpWabal);
  729. m_lpWabal=lpWabal;
  730. if(lpWabal)
  731. lpWabal->AddRef();
  732. };
  733. CAddrObjData::~CAddrObjData()
  734. {
  735. ReleaseObj(m_lpWabal);
  736. };
  737. CAddrWellCB::CAddrWellCB(BOOL fUnderline, BOOL fHasAddrObjs)
  738. {
  739. m_cRef=1;
  740. m_hwndEdit = 0;
  741. m_fUnderline = fUnderline;
  742. m_fHasAddrObjs=fHasAddrObjs;
  743. }
  744. CAddrWellCB::~CAddrWellCB()
  745. {
  746. }
  747. BOOL CAddrWellCB::FInit(HWND hwndEdit)
  748. {
  749. // make sure addrobj's DD guid's are registered
  750. if(!FInitAddrObj(TRUE))
  751. return FALSE;
  752. if(!IsWindow(hwndEdit))
  753. return FALSE;
  754. m_hwndEdit = hwndEdit;
  755. return TRUE;
  756. }
  757. HRESULT CAddrWellCB::QueryInterface(REFIID riid, LPVOID FAR * lplpObj)
  758. {
  759. *lplpObj = NULL; // set to NULL, in case we fail.
  760. if (IsEqualIID(riid, IID_IUnknown))
  761. *lplpObj = (void*)(IUnknown*)this;
  762. else if (IsEqualIID(riid, IID_IRichEditOleCallback))
  763. *lplpObj = (void*)(IRichEditOleCallback*)this;
  764. else
  765. return E_NOINTERFACE;
  766. AddRef();
  767. return NOERROR;
  768. }
  769. ULONG CAddrWellCB::AddRef()
  770. {
  771. return ++m_cRef;
  772. }
  773. ULONG CAddrWellCB::Release()
  774. {
  775. if (--m_cRef==0)
  776. {
  777. delete this;
  778. return 0;
  779. }
  780. else
  781. return m_cRef;
  782. }
  783. HRESULT CAddrWellCB::GetNewStorage (LPSTORAGE FAR * ppstg)
  784. {
  785. if (*ppstg)
  786. ppstg=NULL;
  787. AssertSz(FALSE, "this code should not get hit for OE");
  788. return E_NOTIMPL;
  789. }
  790. HRESULT CAddrWellCB::GetInPlaceContext( LPOLEINPLACEFRAME FAR * lplpFrame,
  791. LPOLEINPLACEUIWINDOW FAR * lplpDoc,
  792. LPOLEINPLACEFRAMEINFO lpFrameInfo)
  793. {
  794. return E_NOTIMPL;
  795. }
  796. HRESULT CAddrWellCB::ShowContainerUI(BOOL fShow)
  797. {
  798. return E_NOTIMPL;
  799. }
  800. HRESULT CAddrWellCB::QueryInsertObject(LPCLSID lpclsid,
  801. LPSTORAGE lpstg,
  802. LONG cp)
  803. {
  804. if(!m_fHasAddrObjs)
  805. return E_NOTIMPL;
  806. if (IsEqualIID(*lpclsid, CLSID_AddrObject))
  807. return NOERROR;
  808. else
  809. return E_FAIL;
  810. }
  811. HRESULT CAddrWellCB::DeleteObject(LPOLEOBJECT lpoleobj)
  812. {
  813. return NOERROR;
  814. }
  815. HRESULT CAddrWellCB::QueryAcceptData(LPDATAOBJECT pdataobj,
  816. CLIPFORMAT FAR *pcfFormat,
  817. DWORD reco,
  818. BOOL fReally,
  819. HGLOBAL hMetaPict)
  820. {
  821. HRESULT hr;
  822. STGMEDIUM stgmedium;
  823. LPWABAL lpWabal=0;
  824. ADRINFO adrInfo;
  825. if(!m_fHasAddrObjs)
  826. {
  827. // of we're a regular callback, take TEXTONLY
  828. *pcfFormat=CF_TEXT;
  829. return NOERROR;
  830. }
  831. if (!*pcfFormat)
  832. {
  833. // default to text
  834. *pcfFormat = CF_TEXT;
  835. // Cool, it's one of ours...
  836. if(pdataobj->QueryGetData(&rgformatetcADDROBJ[iFormatAddrObj])==NOERROR)
  837. *pcfFormat = rgformatetcADDROBJ[iFormatAddrObj].cfFormat;
  838. }
  839. else
  840. {
  841. if (*pcfFormat != rgformatetcADDROBJ[iFormatAddrObj].cfFormat
  842. && *pcfFormat != rgformatetcADDROBJ[iFormatText].cfFormat)
  843. return DATA_E_FORMATETC;
  844. }
  845. if (*pcfFormat==CF_TEXT) // let the richedit take care of text
  846. return NOERROR;
  847. // If I'm read-only, return Success and Richedit won't do anything
  848. if (GetWindowLong(m_hwndEdit, GWL_STYLE) & ES_READONLY)
  849. return NOERROR;
  850. if (!fReally) // return that we'll import it ourselves
  851. return ResultFromScode(S_FALSE);
  852. hr=pdataobj->GetData(&rgformatetcADDROBJ[iFormatAddrObj], &stgmedium);
  853. if(FAILED(hr))
  854. goto Cleanup;
  855. hr=HrCreateWabalObjectFromHGlobal(stgmedium.hGlobal, &lpWabal);
  856. if(FAILED(hr))
  857. goto Cleanup;
  858. if(lpWabal->FGetFirst(&adrInfo))
  859. {
  860. // don't add semi colon before first entry!
  861. HrAddRecipientToWell(m_hwndEdit, (LPADRINFO)&adrInfo);
  862. while(lpWabal->FGetNext(&adrInfo))
  863. {
  864. HdrSetRichEditText(m_hwndEdit, L"; ", TRUE);
  865. HrAddRecipientToWell(m_hwndEdit, (LPADRINFO)&adrInfo);
  866. }
  867. }
  868. // free the hglobal
  869. GlobalFree(stgmedium.hGlobal);
  870. ReleaseObj(lpWabal);
  871. hr = ResultFromScode(S_FALSE);
  872. Cleanup:
  873. return hr;
  874. }
  875. HRESULT CAddrWellCB::ContextSensitiveHelp(BOOL fEnterMode)
  876. {
  877. return E_NOTIMPL;
  878. }
  879. HRESULT CAddrWellCB::GetClipboardData(CHARRANGE FAR * pchrg,
  880. DWORD reco,
  881. LPDATAOBJECT FAR * ppdataobj)
  882. {
  883. HRESULT hr;
  884. CAddrObjData *lpAddrObjData=0;
  885. LPWABAL lpWabal=0;
  886. ULONG uSelType;
  887. if(!m_fHasAddrObjs)
  888. return E_NOTIMPL;
  889. Assert(ppdataobj);
  890. *ppdataobj=0;
  891. // Need to prevent cut on read only
  892. if (reco == RECO_CUT &&
  893. (GetWindowStyle(m_hwndEdit)&ES_READONLY))
  894. return E_NOTIMPL;
  895. // if there is only text in the selection, let the richedit take care of it!
  896. uSelType= (ULONG) SendMessage(m_hwndEdit, EM_SELECTIONTYPE, 0, 0);
  897. if(!(uSelType&SEL_OBJECT))
  898. return E_NOTIMPL;
  899. hr=HrBuildSelectionWabal(m_hwndEdit, pchrg, &lpWabal);
  900. if(FAILED(hr))
  901. return E_FAIL;
  902. // this will gobble up the pal so I don't want to free it
  903. if(!(lpAddrObjData= new CAddrObjData(lpWabal)))
  904. {
  905. hr=E_OUTOFMEMORY;
  906. goto error;
  907. }
  908. hr=lpAddrObjData->QueryInterface(IID_IDataObject, (LPVOID *)ppdataobj);
  909. ReleaseObj(lpAddrObjData);
  910. error:
  911. ReleaseObj(lpWabal);
  912. return hr;
  913. }
  914. HRESULT CAddrWellCB::GetDragDropEffect(BOOL fDrag,
  915. DWORD grfKeyState,
  916. LPDWORD pdwEffect)
  917. {
  918. if(!m_fHasAddrObjs)
  919. return E_NOTIMPL;
  920. if (fDrag) // use the default
  921. return NOERROR;
  922. if (GetWindowLong(m_hwndEdit, GWL_STYLE) & ES_READONLY)
  923. *pdwEffect = DROPEFFECT_NONE;
  924. else
  925. {
  926. if ((grfKeyState & MK_CONTROL) || !(*pdwEffect & DROPEFFECT_MOVE))
  927. *pdwEffect = DROPEFFECT_COPY;
  928. else
  929. *pdwEffect = DROPEFFECT_MOVE;
  930. }
  931. return NOERROR;
  932. }
  933. HRESULT CAddrWellCB::GetContextMenu(WORD seltype,
  934. LPOLEOBJECT pOleObject,
  935. CHARRANGE FAR *pchrg,
  936. HMENU FAR *phMenu)
  937. {
  938. HMENU hMenu=0;
  939. DWORD dwFlags=0;
  940. IOleCommandTarget *pCmdTarget;
  941. OLECMD rgCmds[] = {
  942. {ID_ADDROBJ_OLE_FIND, 0},
  943. {ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, 0},
  944. {ID_ADDROBJ_OLE_PROPERTIES, 0},
  945. {ID_ADDROBJ_OLE_BLOCK_SENDER, 0}};
  946. if (!(hMenu=LoadPopupMenu(IDR_ADDRESS_POPUP)))
  947. return E_OUTOFMEMORY;
  948. if (!m_fHasAddrObjs || pOleObject==NULL)
  949. {
  950. // if this RICHEDIT control does not care about ADDROBJECT or if there is
  951. // no addr object selected, then just return a
  952. // regular cut|copy|paste menu
  953. RemoveMenu(hMenu, ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, MF_BYCOMMAND);
  954. RemoveMenu(hMenu, ID_ADDROBJ_OLE_FIND, MF_BYCOMMAND);
  955. RemoveMenu(hMenu, ID_ADDROBJ_OLE_BLOCK_SENDER, MF_BYCOMMAND);
  956. RemoveMenu(hMenu, ID_SEPARATOR_1, MF_BYCOMMAND);
  957. RemoveMenu(hMenu, ID_SEPARATOR_3, MF_BYCOMMAND);
  958. RemoveMenu(hMenu, ID_ADDROBJ_OLE_PROPERTIES, MF_BYCOMMAND);
  959. }
  960. else
  961. {
  962. // if we get this far, then we have an ole object, make sure it's one we know
  963. // about if we're an addrobj well
  964. #ifdef DEBUG
  965. AssertValidAddrObject(pOleObject);
  966. #endif
  967. // try and see if the object can handle the commands
  968. if (pOleObject->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget)==S_OK)
  969. {
  970. if (pCmdTarget->QueryStatus(&CMDSETID_OutlookExpress, ARRAYSIZE(rgCmds), rgCmds, NULL)==S_OK)
  971. {
  972. for(ULONG ul=0; ul<sizeof(rgCmds)/sizeof(OLECMD); ul++)
  973. {
  974. EnableMenuItem(hMenu, rgCmds[ul].cmdID, (rgCmds[ul].cmdf&OLECMDF_ENABLED ? MF_ENABLED: MF_GRAYED)|MF_BYCOMMAND);
  975. if (!(rgCmds[ul].cmdf&OLECMDF_SUPPORTED))
  976. RemoveMenu(hMenu, rgCmds[ul].cmdID, MF_BYCOMMAND);
  977. }
  978. }
  979. pCmdTarget->Release();
  980. }
  981. // if an Object has focus, then we show the commands before the separator
  982. // if there is an object in selction, remove SelectAll
  983. RemoveMenu(hMenu, ID_SEPARATOR_2, MF_BYCOMMAND);
  984. RemoveMenu(hMenu, ID_SELECT_ALL, MF_BYCOMMAND);
  985. if (SendMessage(m_hwndEdit, EM_SELECTIONTYPE, 0, 0) != SEL_OBJECT)
  986. {
  987. // multiple objects selected, let's grey out addrobj commands
  988. EnableMenuItem(hMenu, ID_ADDROBJ_OLE_PROPERTIES, MF_GRAYED|MF_BYCOMMAND);
  989. EnableMenuItem(hMenu, ID_ADDROBJ_OLE_ADD_ADDRESS_BOOK, MF_GRAYED|MF_BYCOMMAND);
  990. EnableMenuItem(hMenu, ID_ADDROBJ_OLE_FIND, MF_GRAYED|MF_BYCOMMAND);
  991. EnableMenuItem(hMenu, ID_ADDROBJ_OLE_BLOCK_SENDER, MF_GRAYED|MF_BYCOMMAND);
  992. }
  993. }
  994. // if we are a readonly edit, then remove cut and paste
  995. if (FReadOnlyEdit(m_hwndEdit))
  996. {
  997. // remove cut and past if readonly
  998. RemoveMenu(hMenu, ID_CUT, MF_BYCOMMAND);
  999. RemoveMenu(hMenu, ID_PASTE, MF_BYCOMMAND);
  1000. }
  1001. MenuUtil_SetPopupDefault(hMenu, ID_ADDROBJ_OLE_PROPERTIES);
  1002. GetEditDisableFlags(m_hwndEdit, &dwFlags);
  1003. EnableDisableEditMenu(hMenu, dwFlags);
  1004. *phMenu=hMenu;
  1005. return S_OK;
  1006. }
  1007. #ifdef DEBUG
  1008. void AssertValidAddrObject(LPUNKNOWN pUnk)
  1009. {
  1010. BOOL fValid=FALSE;
  1011. LPOLEOBJECT pOleObject;
  1012. CLSID clsid;
  1013. Assert(pUnk);
  1014. if(!pUnk->QueryInterface(IID_IOleObject, (LPVOID *)&pOleObject))
  1015. {
  1016. if((pOleObject->GetUserClassID(&clsid)==NOERROR) &&
  1017. IsEqualCLSID(clsid, CLSID_AddrObject))
  1018. fValid=TRUE;
  1019. ReleaseObj(pOleObject);
  1020. }
  1021. AssertSz(fValid, "WHOA! This is not an AddrObject!");
  1022. }
  1023. #endif
  1024. HRESULT HrBuildSelectionAddrInfoList(HWND hwndRE, CHARRANGE *pchrg, LPADRINFOLIST *lplpAdrInfoList)
  1025. {
  1026. return NOERROR;
  1027. }
  1028. HRESULT HrBuildOneSelWabal(LPADRINFO lpAdrInfo, LPWABAL *lplpWabal)
  1029. {
  1030. LPWABAL lpWabal=0;
  1031. HRESULT hr;
  1032. if(!lplpWabal)
  1033. return E_INVALIDARG;
  1034. hr=HrCreateWabalObject(&lpWabal);
  1035. if(FAILED(hr))
  1036. goto error;
  1037. hr=lpWabal->HrAddEntry(lpAdrInfo);
  1038. if(FAILED(hr))
  1039. goto error;
  1040. *lplpWabal=lpWabal;
  1041. lpWabal->AddRef();
  1042. error:
  1043. ReleaseObj(lpWabal);
  1044. return hr;
  1045. }
  1046. #define iswhite(_ch) (_ch==' ' || _ch=='\t' || _ch=='\n' || _ch=='\r')
  1047. /*
  1048. * ScBuildSelectionAdrlist
  1049. *
  1050. * Purpose:
  1051. * This function will add all the resolved and unresolved
  1052. * names from the selection in an edit control to an ADRLIST
  1053. *
  1054. * Parameters:
  1055. * ppal pointer to pointer to ADRLIST
  1056. * hwndEdit hwnd of the edit control
  1057. * pchrg CHARRANGE of the selection
  1058. *
  1059. * Returns:
  1060. * sc
  1061. */
  1062. HRESULT HrBuildSelectionWabal(HWND hwndRE, CHARRANGE *pchrg, LPWABAL *lplpWabal)
  1063. {
  1064. ULONG iOb,
  1065. cOb,
  1066. cb,
  1067. cchBuf = 0,
  1068. cchSel;
  1069. LPRICHEDITOLE preole;
  1070. REOBJECT reobj = {0};
  1071. LPWABAL lpWabal = NULL;
  1072. HRESULT hr;
  1073. WCHAR rgch[cchUnresolvedMax];
  1074. LPWSTR pbStart = NULL,
  1075. pbSel;
  1076. BOOL fTruncated = FALSE;
  1077. PHCI phci;
  1078. Assert(pchrg);
  1079. cchSel = pchrg->cpMax-pchrg->cpMin;
  1080. // Add all the resolved names (stored as OLE objects) from
  1081. // hwndEdit to the ADRLIST
  1082. reobj.cbStruct = sizeof(REOBJECT);
  1083. if(!MemAlloc((LPVOID *)&pbStart, (cchSel+1)*sizeof(WCHAR)))
  1084. {
  1085. hr = E_OUTOFMEMORY;
  1086. goto Cleanup;
  1087. }
  1088. pbSel = pbStart;
  1089. hr=HrCreateWabalObject(&lpWabal);
  1090. if(FAILED(hr))
  1091. goto Cleanup;
  1092. // if we're building a Wabal, there MUST be some object in the selection!
  1093. Assert((SendMessage(hwndRE, EM_SELECTIONTYPE, 0, 0)&SEL_OBJECT));
  1094. phci = (HCI*)GetWindowLongPtr(hwndRE, GWLP_USERDATA);
  1095. AssertSz(phci, "How did we get a richedit without a phci???");
  1096. preole = phci->preole;
  1097. AssertSz(preole, "How did we get a phci without a preole???");
  1098. // count up the number of objects in the selction, and the number of
  1099. // bytes in them...
  1100. cOb = preole->GetObjectCount();
  1101. for (iOb = 0; iOb < cOb; iOb++)
  1102. {
  1103. hr=preole->GetObject(iOb, &reobj, REO_GETOBJ_POLEOBJ);
  1104. if(FAILED(hr))
  1105. goto Cleanup;
  1106. if (reobj.cp >= pchrg->cpMax) // out of the selrange...
  1107. break;
  1108. if (reobj.cp >= pchrg->cpMin)
  1109. {
  1110. LPPERSIST ppersist = NULL;
  1111. LPADRINFO lpAdrInfo = 0;
  1112. if (FAILED(hr = reobj.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&ppersist)))
  1113. goto Cleanup;
  1114. hr = ((CAddrObj *)ppersist)->HrGetAdrInfo(&lpAdrInfo);
  1115. lpWabal->HrAddEntry(lpAdrInfo);
  1116. ReleaseObj(ppersist);
  1117. if(FAILED(hr))
  1118. goto Cleanup;
  1119. }
  1120. ReleaseObj(reobj.poleobj);
  1121. reobj.poleobj = NULL;
  1122. }
  1123. // walk the unresolved text, and parse it up into unresolved names...
  1124. cb = HdrGetRichEditText(hwndRE, pbSel, cchSel, TRUE) + 1;
  1125. //$ BUG - broken for Unicode
  1126. // The algorithm below will strip spaces off of the
  1127. // beginning and end of each name
  1128. while (cb--)
  1129. {
  1130. if (*pbSel == L'\t')
  1131. *pbSel = L' ';
  1132. if ((*pbSel == L'\0') || (*pbSel == L';') || (*pbSel == L'\r'))
  1133. {
  1134. if(cchBuf)
  1135. {
  1136. LPWSTR psz = rgch + cchBuf - 1;
  1137. while(cchBuf > 0)
  1138. {
  1139. // Exchange #10168.
  1140. if((*psz == L' ') || (*psz == L'\t'))
  1141. {
  1142. cchBuf--;
  1143. psz--;
  1144. }
  1145. else
  1146. break;
  1147. }
  1148. }
  1149. if (cchBuf)
  1150. {
  1151. rgch[cchBuf] = L'\0';
  1152. lpWabal->HrAddUnresolved(rgch, (ULONG)-1);
  1153. cchBuf = 0;
  1154. }
  1155. }
  1156. else
  1157. {
  1158. if (((*pbSel != L' ') && (*pbSel != L'\n') && (*pbSel != L'\r')) || cchBuf > 0)
  1159. {
  1160. if (cchBuf < cchUnresolvedMax - 1)
  1161. rgch[cchBuf++] = *pbSel;
  1162. else
  1163. fTruncated = TRUE;
  1164. }
  1165. }
  1166. ++pbSel;
  1167. }
  1168. *lplpWabal=lpWabal;
  1169. lpWabal->AddRef();
  1170. Cleanup:
  1171. MemFree(pbStart);
  1172. ReleaseObj(lpWabal);
  1173. ReleaseObj(reobj.poleobj);
  1174. return hr;
  1175. }