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.

2198 lines
62 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: outbar.cpp
  5. //
  6. // PURPOSE: Implements the Outlook Bar
  7. //
  8. #include "pch.hxx"
  9. #include "resource.h"
  10. #include "outbar.h"
  11. #include "goptions.h"
  12. #include "ourguid.h"
  13. #include <inpobj.h>
  14. #include <browser.h>
  15. #include <notify.h>
  16. #include <strconst.h>
  17. #include <thormsgs.h>
  18. #include <shlwapi.h>
  19. #include "shlwapip.h"
  20. #include "storutil.h"
  21. #include "menures.h"
  22. #include "menuutil.h"
  23. #include "dragdrop.h"
  24. #include "newfldr.h"
  25. #include "finder.h"
  26. #include "instance.h"
  27. ASSERTDATA
  28. #define IDC_FRAME 100
  29. #define IDC_PAGER 101
  30. #define IDC_TOOLBAR 102
  31. #define HT_ENTER 1
  32. #define HT_OVER 2
  33. #define HT_LEAVE 3
  34. // Special HitTest results
  35. #define IBHT_SOURCE (-32768)
  36. #define IBHT_BACKGROUND (-32767)
  37. #define IBHT_PAGER (-32766)
  38. ////////////////////////////////////////////////////////////////////////
  39. //
  40. // Prototypes
  41. //
  42. ////////////////////////////////////////////////////////////////////////
  43. HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist);
  44. HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData);
  45. extern DWORD CUnread(FOLDERINFO *pfi);
  46. ////////////////////////////////////////////////////////////////////////
  47. //
  48. // Module Data
  49. //
  50. ////////////////////////////////////////////////////////////////////////
  51. static const TCHAR s_szOutBarWndClass[] = TEXT("Outlook Express Outlook Bar");
  52. static const TCHAR s_szOutBarFrameClass[] = TEXT("Outlook Express Outlook Bar Frame");
  53. static const TCHAR c_szOutBarNotifyName[] = TEXT("Outlook Express Outlook Bar Notify");
  54. ////////////////////////////////////////////////////////////////////////
  55. //
  56. // Constructors, Destructors, and other initialization stuff
  57. //
  58. ////////////////////////////////////////////////////////////////////////
  59. COutBar::COutBar()
  60. {
  61. m_cRef = 1;
  62. m_hwndParent = NULL;
  63. m_hwnd = NULL;
  64. m_hwndFrame = NULL;
  65. m_hwndPager = NULL;
  66. m_hwndTools = NULL;
  67. m_ptbSite = NULL;
  68. m_fShow = FALSE;
  69. m_pBrowser = NULL;
  70. m_pStNotify = NULL;
  71. m_idCommand = 0;
  72. m_fResizing = FALSE;
  73. m_idSel = -1;
  74. // load the width from resource
  75. m_cxWidth = 70;
  76. TCHAR szBuffer[64];
  77. if (AthLoadString(idsMaxOutbarBtnWidth, szBuffer, ARRAYSIZE(szBuffer)))
  78. {
  79. m_cxWidth = StrToInt(szBuffer);
  80. if (m_cxWidth == 0)
  81. m_cxWidth = 70;
  82. }
  83. m_fLarge = TRUE;
  84. m_himlLarge = NULL;
  85. m_himlSmall = NULL;
  86. m_pOutBarNotify = NULL;
  87. m_pDataObject = NULL;
  88. m_grfKeyState = 0;
  89. m_dwEffectCur = DROPEFFECT_NONE;
  90. m_idCur = -1;
  91. m_pTargetCur = NULL;
  92. m_idDropHilite = 0;
  93. m_fInsertMark = FALSE;
  94. m_fOnce = TRUE;
  95. }
  96. COutBar::~COutBar()
  97. {
  98. Assert(NULL == m_pStNotify);
  99. if (m_hwnd)
  100. DestroyWindow(m_hwnd);
  101. if (m_himlLarge)
  102. ImageList_Destroy(m_himlLarge);
  103. if (m_himlSmall)
  104. ImageList_Destroy(m_himlSmall);
  105. SafeRelease(m_pDataObject);
  106. }
  107. HRESULT COutBar::HrInit(LPSHELLFOLDER psf, IAthenaBrowser *psb)
  108. {
  109. HRESULT hr;
  110. m_pBrowser = psb;
  111. hr = CreateNotify(&m_pStNotify);
  112. if (FAILED(hr))
  113. return(hr);
  114. return m_pStNotify->Initialize((TCHAR *)c_szMailFolderNotify);
  115. }
  116. ////////////////////////////////////////////////////////////////////////
  117. //
  118. // IUnknown
  119. //
  120. ////////////////////////////////////////////////////////////////////////
  121. HRESULT COutBar::QueryInterface(REFIID riid, LPVOID * ppvObj)
  122. {
  123. if (IsEqualIID(riid, IID_IUnknown) ||
  124. IsEqualIID(riid, IID_IOleWindow) ||
  125. IsEqualIID(riid, IID_IDockingWindow) ||
  126. IsEqualIID(riid, IID_IDatabaseNotify))
  127. {
  128. *ppvObj = (void*)(IDockingWindow*)this;
  129. }
  130. else if (IsEqualIID(riid, IID_IObjectWithSite))
  131. {
  132. *ppvObj = (void*)(IObjectWithSite*)this;
  133. }
  134. else
  135. {
  136. *ppvObj = NULL;
  137. return E_NOINTERFACE;
  138. }
  139. AddRef();
  140. return S_OK;
  141. }
  142. ULONG COutBar::AddRef()
  143. {
  144. return ++m_cRef;
  145. }
  146. ULONG COutBar::Release()
  147. {
  148. if (--m_cRef == 0)
  149. {
  150. delete this;
  151. return 0;
  152. }
  153. return m_cRef;
  154. }
  155. ////////////////////////////////////////////////////////////////////////
  156. //
  157. // IOleWindow
  158. //
  159. ////////////////////////////////////////////////////////////////////////
  160. HRESULT COutBar::GetWindow(HWND * lphwnd)
  161. {
  162. *lphwnd = m_hwnd;
  163. return (*lphwnd ? S_OK : E_FAIL);
  164. }
  165. HRESULT COutBar::ContextSensitiveHelp(BOOL fEnterMode)
  166. {
  167. return E_NOTIMPL;
  168. }
  169. //
  170. // FUNCTION: COutBar::ShowDW()
  171. //
  172. // PURPOSE: Causes the bar to be displayed. If it has not yet been
  173. // created, we do that here too.
  174. //
  175. // PARAMETERS:
  176. // [in] fShow - TRUE to make the bar visible, FALSE to hide.
  177. //
  178. // RETURN VALUE:
  179. // HRESULT
  180. //
  181. HRESULT COutBar::ShowDW(BOOL fShow)
  182. {
  183. // Make sure we have a site pointer first
  184. if (!m_ptbSite)
  185. {
  186. AssertSz(0, _T("COutBar::ShowDW() - Can't show without calling SetSite() first."));
  187. return E_FAIL;
  188. }
  189. // Decide if we need to create a new window or show a currently existing
  190. // window
  191. if (!m_hwnd)
  192. {
  193. WNDCLASSEX wc;
  194. wc.cbSize = sizeof(WNDCLASSEX);
  195. if (!GetClassInfoEx(g_hInst, s_szOutBarWndClass, &wc))
  196. {
  197. // We need to register the outlook bar class
  198. wc.style = 0;
  199. wc.lpfnWndProc = COutBar::OutBarWndProc;
  200. wc.cbClsExtra = 0;
  201. wc.cbWndExtra = 0;
  202. wc.hInstance = g_hInst;
  203. wc.hCursor = LoadCursor(NULL, IDC_SIZEWE);
  204. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
  205. wc.lpszMenuName = NULL;
  206. wc.lpszClassName = s_szOutBarWndClass;
  207. wc.hIcon = NULL;
  208. wc.hIconSm = NULL;
  209. if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
  210. return E_FAIL;
  211. // Also need to register the frame class
  212. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  213. wc.lpfnWndProc = COutBar::ExtFrameWndProc;
  214. wc.lpszClassName = s_szOutBarFrameClass;
  215. wc.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1);
  216. if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
  217. return E_FAIL;
  218. }
  219. // Get the handle of the parent window
  220. if (FAILED(m_ptbSite->GetWindow(&m_hwndParent)))
  221. return E_FAIL;
  222. // Create the window
  223. m_hwnd = CreateWindowEx(0, s_szOutBarWndClass, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  224. 0, 0, 0, 0, m_hwndParent, NULL, g_hInst, (LPVOID) this);
  225. if (!m_hwnd)
  226. {
  227. AssertSz(0, _T("COutBar::ShowDW() - Failed to create window."));
  228. return E_FAIL;
  229. }
  230. if (FAILED(_CreateToolbar()))
  231. return E_FAIL;
  232. }
  233. // Show or hide the window and resize the parent windows accordingly
  234. m_fShow = fShow;
  235. ResizeBorderDW(NULL, NULL, FALSE);
  236. ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
  237. // Do notifications
  238. if (SUCCEEDED(CreateNotify(&m_pOutBarNotify)))
  239. {
  240. if (SUCCEEDED(m_pOutBarNotify->Initialize(c_szOutBarNotifyName)))
  241. {
  242. m_pOutBarNotify->Register(m_hwnd, g_hwndInit, FALSE);
  243. }
  244. }
  245. // Drag Drop
  246. RegisterDragDrop(m_hwndTools, this);
  247. g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, 0, (IDatabaseNotify *)this);
  248. return S_OK;
  249. }
  250. //
  251. // FUNCTION: COutBar::CloseDW()
  252. //
  253. // PURPOSE: Destroys the bar and cleans up.
  254. //
  255. HRESULT COutBar::CloseDW(DWORD dwReserved)
  256. {
  257. // Save our settings
  258. _SaveSettings();
  259. RevokeDragDrop(m_hwndTools);
  260. g_pStore->UnregisterNotify((IDatabaseNotify *) this);
  261. // Release
  262. if (m_pOutBarNotify != NULL)
  263. {
  264. if (m_hwnd != NULL)
  265. m_pOutBarNotify->Unregister(m_hwnd);
  266. m_pOutBarNotify->Release();
  267. m_pOutBarNotify = NULL;
  268. }
  269. // Release our notification interface
  270. if (m_pStNotify != NULL)
  271. {
  272. if (m_hwnd != NULL)
  273. m_pStNotify->Unregister(m_hwnd);
  274. m_pStNotify->Release();
  275. m_pStNotify = NULL;
  276. }
  277. // Clean up the toolbar and other child windows
  278. if (m_hwnd)
  279. {
  280. if (m_hwndTools)
  281. _EmptyToolbar(FALSE);
  282. DestroyWindow(m_hwnd);
  283. m_hwnd = NULL;
  284. }
  285. return S_OK;
  286. }
  287. //
  288. // FUNCTION: COutBar::ResizeBorderDW()
  289. //
  290. // PURPOSE:
  291. //
  292. // PARAMETERS:
  293. // LPCRECT prcBorder
  294. // IUnknown *punkToolbarSite
  295. // BOOL fReserved
  296. //
  297. // RETURN VALUE:
  298. // HRESULT
  299. //
  300. HRESULT COutBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
  301. {
  302. RECT rcRequest = { 0, 0, 0, 0 };
  303. RECT rcFrame;
  304. if (!m_ptbSite)
  305. {
  306. AssertSz(0, _T("COutBar::ResizeBorderDW() - Can't resize without calling SetSite() first."));
  307. return E_FAIL;
  308. }
  309. if (m_fShow)
  310. {
  311. RECT rcBorder;
  312. if (!prcBorder)
  313. {
  314. // Find out how big our parent's border space is
  315. m_ptbSite->GetBorderDW((IDockingWindow*) this, &rcBorder);
  316. prcBorder = &rcBorder;
  317. }
  318. // Figure out how much border space to ask the site for
  319. GetWindowRect(m_hwndFrame, &rcFrame);
  320. rcFrame.right = min(m_cxWidth - GetSystemMetrics(SM_CXFRAME) + 1,
  321. prcBorder->right - prcBorder->left);
  322. rcRequest.left = min(m_cxWidth, prcBorder->right - prcBorder->left - 32);
  323. // Set our new window position
  324. SetWindowPos(m_hwndFrame, NULL, 0, 0,
  325. rcFrame.right, prcBorder->bottom - prcBorder->top,
  326. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  327. SetWindowPos(m_hwnd, NULL, prcBorder->left, prcBorder->top,
  328. rcRequest.left, prcBorder->bottom - prcBorder->top,
  329. SWP_NOACTIVATE | SWP_NOZORDER);
  330. }
  331. m_ptbSite->SetBorderSpaceDW((IDockingWindow*) this, &rcRequest);
  332. return S_OK;
  333. }
  334. //
  335. // FUNCTION: COutBar::SetSite()
  336. //
  337. // PURPOSE: Set's a site pointer for the class
  338. //
  339. HRESULT COutBar::SetSite(IUnknown* punkSite)
  340. {
  341. // If we already have a site pointer, release it now
  342. if (m_ptbSite)
  343. {
  344. m_ptbSite->Release();
  345. m_ptbSite = NULL;
  346. }
  347. // If the caller provided a new site interface, get the IDockingWindowSite
  348. // and keep a pointer to it.
  349. if (punkSite)
  350. {
  351. if (FAILED(punkSite->QueryInterface(IID_IDockingWindowSite, (void **)&m_ptbSite)))
  352. return E_FAIL;
  353. }
  354. return S_OK;
  355. }
  356. HRESULT COutBar::GetSite(REFIID riid, LPVOID *ppvSite)
  357. {
  358. return E_NOTIMPL;
  359. }
  360. //
  361. // FUNCTION: COutBar::DragEnter()
  362. //
  363. // PURPOSE: This get's called when the user starts dragging an object
  364. // over our target area.
  365. //
  366. // PARAMETERS:
  367. // <in> pDataObject - Pointer to the data object being dragged
  368. // <in> grfKeyState - Pointer to the current key states
  369. // <in> pt - Point in screen coordinates of the mouse
  370. // <out> pdwEffect - Where we return whether this is a valid place for
  371. // pDataObject to be dropped and if so what type of
  372. // drop.
  373. //
  374. // RETURN VALUE:
  375. // S_OK - The function succeeded.
  376. //
  377. HRESULT STDMETHODCALLTYPE COutBar::DragEnter(IDataObject* pDataObject,
  378. DWORD grfKeyState,
  379. POINTL pt, DWORD* pdwEffect)
  380. {
  381. FORMATETC fe;
  382. POINT ptTemp = {pt.x, pt.y};
  383. // Initialize our state
  384. SafeRelease(m_pDataObject);
  385. // Hold on to this new object
  386. m_pDataObject = pDataObject;
  387. m_pDataObject->AddRef();
  388. // The big question here is whether or not this data object is an OE folder
  389. // or is it something else.
  390. SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
  391. m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe));
  392. if (!m_fDropShortcut)
  393. {
  394. SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL);
  395. m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe));
  396. }
  397. if (m_fDropShortcut)
  398. {
  399. m_fDropShortcut = _IsTempNewsgroup(m_pDataObject);
  400. }
  401. DOUTL(32, "COutBar::DragEnter() - Data is %s shortcut", m_fDropShortcut ? "a" : "not a");
  402. // Hang on to this little gem
  403. m_grfKeyState = grfKeyState;
  404. // Initialize some other stuff
  405. m_idCur = -1;
  406. Assert(m_pTargetCur == NULL);
  407. m_tbim.iButton = -1;
  408. m_tbim.dwFlags = 0;
  409. // Set the default return value here
  410. m_dwEffectCur = *pdwEffect = DROPEFFECT_NONE;
  411. // Update the highlight point
  412. _UpdateDragDropHilite(&ptTemp);
  413. return (S_OK);
  414. }
  415. int COutBar::_GetItemFromPoint(POINT pt)
  416. {
  417. int iPos;
  418. TBBUTTON tb;
  419. // Figure out which button this is over
  420. ScreenToClient(m_hwndTools, &pt);
  421. iPos = ToolBar_HitTest(m_hwndTools, &pt);
  422. // If this is over a button, convert that button position to a command
  423. if (iPos >= 0)
  424. {
  425. ToolBar_GetButton(m_hwndTools, iPos, &tb);
  426. return (tb.idCommand);
  427. }
  428. return (-1);
  429. }
  430. void COutBar::_UpdateDragDropHilite(LPPOINT ppt)
  431. {
  432. TBINSERTMARK tbim;
  433. int iPos;
  434. // If this is a shortcut we do one thing, if it's anything else we do another
  435. if (m_fDropShortcut)
  436. {
  437. if (m_fInsertMark)
  438. {
  439. tbim.iButton = -1;
  440. tbim.dwFlags = 0;
  441. ToolBar_SetInsertMark(m_hwndTools, &tbim);
  442. m_fInsertMark = FALSE;
  443. }
  444. if (ppt)
  445. {
  446. ScreenToClient(m_hwndTools, ppt);
  447. ToolBar_InsertMarkHitTest(m_hwndTools, ppt, &tbim);
  448. ToolBar_SetInsertMark(m_hwndTools, &tbim);
  449. m_fInsertMark = TRUE;
  450. }
  451. }
  452. else
  453. {
  454. // Remove any previous marks
  455. if (m_idDropHilite)
  456. {
  457. ToolBar_MarkButton(m_hwndTools, m_idDropHilite, FALSE);
  458. m_idDropHilite = 0;
  459. }
  460. // Hilite the new button
  461. if (ppt)
  462. {
  463. // First check to see if we're over a button or in between
  464. m_idDropHilite = _GetItemFromPoint(*ppt);
  465. ToolBar_MarkButton(m_hwndTools, m_idDropHilite, TRUE);
  466. #ifdef DEBUG
  467. FOLDERINFO rInfo;
  468. FOLDERID idFolder;
  469. idFolder = _FolderIdFromCmd(m_idDropHilite);
  470. if (SUCCEEDED(g_pStore->GetFolderInfo(idFolder, &rInfo)))
  471. {
  472. DOUTL(32, "COutBar::_UpdateDragDropHilite() - Hiliting %s", rInfo.pszName);
  473. g_pStore->FreeRecord(&rInfo);
  474. }
  475. #endif
  476. }
  477. }
  478. }
  479. FOLDERID COutBar::_FolderIdFromCmd(int idCmd)
  480. {
  481. TBBUTTON tbb;
  482. int iPos;
  483. iPos = (int) SendMessage(m_hwndTools, TB_COMMANDTOINDEX, idCmd, 0);
  484. ToolBar_GetButton(m_hwndTools, iPos, &tbb);
  485. return ((FOLDERID) tbb.dwData);
  486. }
  487. //
  488. // FUNCTION: COutBar::DragOver()
  489. //
  490. // PURPOSE: This is called as the user drags an object over our target.
  491. // If we allow this object to be dropped on us, then we will have
  492. // a pointer in m_pDataObject.
  493. //
  494. // PARAMETERS:
  495. // <in> grfKeyState - Pointer to the current key states
  496. // <in> pt - Point in screen coordinates of the mouse
  497. // <out> pdwEffect - Where we return whether this is a valid place for
  498. // pDataObject to be dropped and if so what type of
  499. // drop.
  500. //
  501. // RETURN VALUE:
  502. // S_OK - The function succeeded.
  503. //
  504. HRESULT STDMETHODCALLTYPE COutBar::DragOver(DWORD grfKeyState, POINTL pt,
  505. DWORD* pdwEffect)
  506. {
  507. DWORD idCur;
  508. HRESULT hr = E_FAIL;
  509. // If we don't have a data object from DragEnter, bail
  510. if (NULL == m_pDataObject)
  511. return (S_OK);
  512. // If this is a shortcut we do one thing, if it's anything else we do another
  513. if (m_fDropShortcut)
  514. {
  515. TBINSERTMARK tbim;
  516. POINT ptTemp = {pt.x, pt.y};
  517. ScreenToClient(m_hwndTools, &ptTemp);
  518. ToolBar_InsertMarkHitTest(m_hwndTools, &ptTemp, &tbim);
  519. if (tbim.iButton != m_tbim.iButton || tbim.dwFlags != m_tbim.dwFlags)
  520. {
  521. m_tbim = tbim;
  522. ptTemp.x = pt.x;
  523. ptTemp.y = pt.y;
  524. _UpdateDragDropHilite(&ptTemp);
  525. }
  526. if (DROPEFFECT_LINK & *pdwEffect)
  527. *pdwEffect = DROPEFFECT_LINK;
  528. else
  529. *pdwEffect = DROPEFFECT_MOVE;
  530. return (S_OK);
  531. }
  532. else
  533. {
  534. // Figure out which item we're over
  535. POINT ptTemp = {pt.x, pt.y};
  536. if (-1 == (idCur = _GetItemFromPoint(ptTemp)))
  537. {
  538. DOUTL(32, "COutBar::DragOver() - _GetItemFromPoint() returns -1.");
  539. }
  540. DOUTL(32, "COutBar::DragOver() - m_idCur = %d, id = %d", m_idCur, idCur);
  541. // If we're over a new button, then get the drop target for that button
  542. if (m_idCur != idCur)
  543. {
  544. // Release any previous drop target, if any.
  545. SafeRelease(m_pTargetCur);
  546. // Update our current object marker
  547. m_idCur = idCur;
  548. // Assume error
  549. m_dwEffectCur = DROPEFFECT_NONE;
  550. // Update the UI
  551. _UpdateDragDropHilite(&ptTemp);
  552. // If we're over a button
  553. if (m_idCur != -1)
  554. {
  555. FOLDERID id = _FolderIdFromCmd(m_idCur);
  556. // Create the drop target object
  557. m_pTargetCur = new CDropTarget();
  558. if (m_pTargetCur)
  559. {
  560. hr = m_pTargetCur->Initialize(m_hwnd, id);
  561. }
  562. // If we have an initialized drop target, call DragEnter()
  563. if (SUCCEEDED(hr) && m_pTargetCur)
  564. {
  565. hr = m_pTargetCur->DragEnter(m_pDataObject, grfKeyState, pt, pdwEffect);
  566. m_dwEffectCur = *pdwEffect;
  567. }
  568. }
  569. else
  570. {
  571. m_dwEffectCur = DROPEFFECT_NONE;
  572. }
  573. }
  574. else
  575. {
  576. // No target change, but did the key state change?
  577. if ((m_grfKeyState != grfKeyState) && m_pTargetCur)
  578. {
  579. m_dwEffectCur = *pdwEffect;
  580. hr = m_pTargetCur->DragOver(grfKeyState, pt, &m_dwEffectCur);
  581. }
  582. else
  583. {
  584. hr = S_OK;
  585. }
  586. }
  587. *pdwEffect = m_dwEffectCur;
  588. m_grfKeyState = grfKeyState;
  589. }
  590. return (hr);
  591. }
  592. //
  593. // FUNCTION: COutBar::DragLeave()
  594. //
  595. // PURPOSE: Allows us to release any stored data we have from a successful
  596. // DragEnter()
  597. //
  598. // RETURN VALUE:
  599. // S_OK - Everything is groovy
  600. //
  601. HRESULT STDMETHODCALLTYPE COutBar::DragLeave(void)
  602. {
  603. SafeRelease(m_pDataObject);
  604. SafeRelease(m_pTargetCur);
  605. _UpdateDragDropHilite(NULL);
  606. return (S_OK);
  607. }
  608. //
  609. // FUNCTION: COutBar::Drop()
  610. //
  611. // PURPOSE: The user has let go of the object over our target. If we
  612. // can accept this object we will already have the pDataObject
  613. // stored in m_pDataObject. If this is a copy or move, then
  614. // we go ahead and update the store. Otherwise, we bring up
  615. // a send note with the object attached.
  616. //
  617. // PARAMETERS:
  618. // <in> pDataObject - Pointer to the data object being dragged
  619. // <in> grfKeyState - Pointer to the current key states
  620. // <in> pt - Point in screen coordinates of the mouse
  621. // <out> pdwEffect - Where we return whether this is a valid place for
  622. // pDataObject to be dropped and if so what type of
  623. // drop.
  624. //
  625. // RETURN VALUE:
  626. // S_OK - Everything worked OK
  627. //
  628. HRESULT STDMETHODCALLTYPE COutBar::Drop(IDataObject* pDataObject,
  629. DWORD grfKeyState, POINTL pt,
  630. DWORD* pdwEffect)
  631. {
  632. HRESULT hr = E_FAIL;
  633. Assert(m_pDataObject == pDataObject);
  634. if (m_fDropShortcut)
  635. {
  636. hr = _AddShortcut(pDataObject);
  637. }
  638. else
  639. {
  640. if (m_pTargetCur)
  641. {
  642. hr = m_pTargetCur->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  643. }
  644. else
  645. {
  646. *pdwEffect = DROPEFFECT_NONE;
  647. hr = S_OK;
  648. }
  649. }
  650. _UpdateDragDropHilite(NULL);
  651. SafeRelease(m_pTargetCur);
  652. SafeRelease(m_pDataObject);
  653. return (hr);
  654. }
  655. HRESULT COutBar::_AddShortcut(IDataObject *pObject)
  656. {
  657. FORMATETC fe;
  658. STGMEDIUM stm;
  659. FOLDERID *pidFolder;
  660. HRESULT hr = E_UNEXPECTED;
  661. TBINSERTMARK tbim;
  662. if (!pObject)
  663. return (E_INVALIDARG);
  664. // Get the data from the data object
  665. SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
  666. if (SUCCEEDED(pObject->GetData(&fe, &stm)))
  667. {
  668. pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal);
  669. ToolBar_GetInsertMark(m_hwndTools, &tbim);
  670. _InsertButton(tbim.iButton + tbim.dwFlags, *pidFolder);
  671. _SaveSettings();
  672. _EmptyToolbar(TRUE);
  673. _FillToolbar();
  674. m_pOutBarNotify->Lock(m_hwnd);
  675. m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
  676. m_pOutBarNotify->Unlock();
  677. GlobalUnlock(stm.hGlobal);
  678. ReleaseStgMedium(&stm);
  679. }
  680. else
  681. {
  682. SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL);
  683. if (SUCCEEDED(pObject->GetData(&fe, &stm)))
  684. {
  685. UINT *piPosOld = (UINT *) GlobalLock(stm.hGlobal);
  686. UINT iPosNew;
  687. ToolBar_GetInsertMark(m_hwndTools, &tbim);
  688. iPosNew = tbim.iButton;
  689. if (tbim.dwFlags & TBIMHT_AFTER)
  690. iPosNew++;
  691. TBBUTTON tbb;
  692. ToolBar_GetButton(m_hwndTools, *piPosOld, &tbb);
  693. SendMessage(m_hwndTools, TB_INSERTBUTTON, iPosNew, (LPARAM)&tbb);
  694. if (iPosNew < *piPosOld)
  695. (*piPosOld)++;
  696. SendMessage(m_hwndTools, TB_DELETEBUTTON, *piPosOld, 0);
  697. _SaveSettings();
  698. _EmptyToolbar(TRUE);
  699. _FillToolbar();
  700. m_pOutBarNotify->Lock(m_hwnd);
  701. m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
  702. m_pOutBarNotify->Unlock();
  703. GlobalUnlock(stm.hGlobal);
  704. ReleaseStgMedium(&stm);
  705. }
  706. }
  707. return (hr);
  708. }
  709. HRESULT STDMETHODCALLTYPE COutBar::QueryContinueDrag(BOOL fEscapePressed,
  710. DWORD grfKeyState)
  711. {
  712. if (fEscapePressed)
  713. return (DRAGDROP_S_CANCEL);
  714. if (grfKeyState & MK_RBUTTON)
  715. return (DRAGDROP_S_CANCEL);
  716. if (!(grfKeyState & MK_LBUTTON))
  717. return (DRAGDROP_S_DROP);
  718. return (S_OK);
  719. }
  720. HRESULT STDMETHODCALLTYPE COutBar::GiveFeedback(DWORD dwEffect)
  721. {
  722. return (DRAGDROP_S_USEDEFAULTCURSORS);
  723. }
  724. LRESULT CALLBACK COutBar::OutBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  725. {
  726. COutBar *pThis;
  727. if (uMsg == WM_NCCREATE)
  728. {
  729. pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams;
  730. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
  731. }
  732. else
  733. {
  734. pThis = (COutBar *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  735. }
  736. Assert(pThis);
  737. return pThis->WndProc(hwnd, uMsg, wParam, lParam);
  738. }
  739. LRESULT CALLBACK COutBar::ExtFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  740. {
  741. COutBar *pThis;
  742. if (uMsg == WM_NCCREATE)
  743. {
  744. pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams;
  745. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
  746. }
  747. else
  748. {
  749. pThis = (COutBar *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  750. }
  751. Assert(pThis);
  752. return pThis->FrameWndProc(hwnd, uMsg, wParam, lParam);
  753. }
  754. LRESULT COutBar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  755. {
  756. switch (msg)
  757. {
  758. HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove);
  759. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown);
  760. HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp);
  761. case WM_SYSCOLORCHANGE:
  762. case WM_WININICHANGE:
  763. case WM_FONTCHANGE:
  764. {
  765. SendMessage(m_hwndPager, msg, wParam, lParam);
  766. SendMessage(m_hwndTools, msg, wParam, lParam);
  767. ResizeBorderDW(NULL, NULL, FALSE);
  768. return (0);
  769. }
  770. case WM_RELOADSHORTCUTS:
  771. {
  772. _EmptyToolbar(TRUE);
  773. _FillToolbar();
  774. return (0);
  775. }
  776. }
  777. return DefWindowProc(hwnd, msg, wParam, lParam);
  778. }
  779. LRESULT COutBar::FrameWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  780. {
  781. switch (msg)
  782. {
  783. HANDLE_MSG(hwnd, WM_NOTIFY, Frame_OnNotify);
  784. HANDLE_MSG(hwnd, WM_SIZE, Frame_OnSize);
  785. HANDLE_MSG(hwnd, WM_COMMAND, Frame_OnCommand);
  786. HANDLE_MSG(hwnd, WM_NCDESTROY, Frame_OnNCDestroy);
  787. }
  788. return DefWindowProc(hwnd, msg, wParam, lParam);
  789. }
  790. void COutBar::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  791. {
  792. if (!m_fResizing)
  793. {
  794. SetCapture(hwnd);
  795. m_fResizing = TRUE;
  796. }
  797. }
  798. void COutBar::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  799. {
  800. POINT pt = { x, y };
  801. RECT rcClient;
  802. if (m_fResizing)
  803. {
  804. if (pt.x > 32)
  805. {
  806. GetClientRect(m_hwndParent, &rcClient);
  807. m_cxWidth = min(pt.x, rcClient.right - 32);
  808. ResizeBorderDW(0, 0, FALSE);
  809. }
  810. }
  811. }
  812. void COutBar::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  813. {
  814. if (m_fResizing)
  815. {
  816. ReleaseCapture();
  817. m_fResizing = FALSE;
  818. }
  819. }
  820. void COutBar::Frame_OnNCDestroy(HWND hwnd)
  821. {
  822. SetWindowLong(hwnd, GWLP_USERDATA, NULL);
  823. m_hwndFrame = m_hwndPager = m_hwndTools = NULL;
  824. }
  825. void COutBar::Frame_OnSize(HWND hwnd, UINT state, int cx, int cy)
  826. {
  827. // When we get resized, we resize our children and update the toolbar button width
  828. if (m_hwndPager)
  829. {
  830. SetWindowPos(m_hwndPager, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  831. SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(cx, cx));
  832. }
  833. }
  834. void COutBar::Frame_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  835. {
  836. int iPos;
  837. TBBUTTONINFO tbbi;
  838. if (id < ID_FIRST)
  839. {
  840. tbbi.cbSize = sizeof(tbbi);
  841. tbbi.dwMask = TBIF_LPARAM;
  842. iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) id, (LPARAM)&tbbi);
  843. if (iPos >= 0)
  844. m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0);
  845. }
  846. }
  847. LRESULT COutBar::Frame_OnNotify(HWND hwnd, int idFrom, NMHDR *pnmhdr)
  848. {
  849. if (pnmhdr->code <= PGN_FIRST && pnmhdr->code >= PGN_LAST)
  850. return SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) pnmhdr);
  851. switch (pnmhdr->code)
  852. {
  853. case NM_CUSTOMDRAW:
  854. {
  855. NMCUSTOMDRAW *pnmcd = (NMCUSTOMDRAW*) pnmhdr;
  856. if (pnmcd->dwDrawStage == CDDS_PREPAINT)
  857. return CDRF_NOTIFYITEMDRAW;
  858. if (pnmcd->dwDrawStage == CDDS_ITEMPREPAINT)
  859. {
  860. NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd;
  861. ptbcd->clrText = GetSysColor(COLOR_WINDOW);
  862. return CDRF_NEWFONT;
  863. }
  864. }
  865. break;
  866. case NM_RCLICK:
  867. {
  868. if (pnmhdr->hwndFrom == m_hwndTools)
  869. {
  870. DWORD dwPos = GetMessagePos();
  871. _OnContextMenu(GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos));
  872. return 1;
  873. }
  874. }
  875. case TBN_DRAGOUT:
  876. {
  877. NMTOOLBAR *pnmtb = (NMTOOLBAR *) pnmhdr;
  878. DWORD dwEffect = DROPEFFECT_NONE;
  879. UINT id = ToolBar_CommandToIndex(m_hwndTools, pnmtb->iItem);
  880. // Create a new data object
  881. CShortcutDataObject *pDataObj = new CShortcutDataObject(id);
  882. if (pDataObj)
  883. {
  884. DoDragDrop(pDataObj, (IDropSource *) this, DROPEFFECT_MOVE, &dwEffect);
  885. pDataObj->Release();
  886. }
  887. return 0;
  888. }
  889. }
  890. return (FALSE);
  891. }
  892. HRESULT COutBar::_CreateToolbar()
  893. {
  894. HIMAGELIST himl, himlOld;
  895. LRESULT lButtonSize;
  896. RECT rc;
  897. int iButtonWidth = 70;
  898. TCHAR szName[CCHMAX_STRINGRES];
  899. // Create the frame window
  900. m_hwndFrame = CreateWindowEx(WS_EX_CLIENTEDGE, s_szOutBarFrameClass, NULL,
  901. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  902. 0, 0, 0, 0, m_hwnd, (HMENU) IDC_FRAME, g_hInst, this);
  903. if (!m_hwndFrame)
  904. return E_FAIL;
  905. // Create the pager
  906. m_hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL,
  907. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | PGS_VERT | PGS_DRAGNDROP,
  908. 0, 0, 0, 0, m_hwndFrame, (HMENU) IDC_PAGER, g_hInst, NULL);
  909. if (!m_hwndPager)
  910. return E_FAIL;
  911. ZeroMemory(szName, ARRAYSIZE(szName));
  912. LoadString(g_hLocRes, idsOutlookBar, szName, ARRAYSIZE(szName));
  913. // Create the toolbar
  914. m_hwndTools = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, szName,
  915. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  916. TBSTYLE_FLAT | TBSTYLE_TOOLTIPS |
  917. CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_VERT,
  918. 0, 0, 0, 0, m_hwndPager, (HMENU) IDC_TOOLBAR, g_hInst, NULL);
  919. if (!m_hwndTools)
  920. return E_FAIL;
  921. // This tells the toolbar what version we are
  922. SendMessage(m_hwndTools, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  923. _FillToolbar();
  924. _SetButtonStyle(!m_fLarge);
  925. SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(0, m_cxWidth));
  926. m_pStNotify->Register(m_hwnd, g_hwndInit, FALSE);
  927. SendMessage(m_hwndPager, PGM_SETCHILD, 0, (LPARAM)m_hwndTools);
  928. // Let's try this
  929. COLORSCHEME cs;
  930. cs.dwSize = sizeof(COLORSCHEME);
  931. cs.clrBtnHighlight = GetSysColor(COLOR_3DFACE);
  932. cs.clrBtnShadow = GetSysColor(COLOR_WINDOWFRAME);
  933. SendMessage(m_hwndTools, TB_SETCOLORSCHEME, 0, (LPARAM) &cs);
  934. return S_OK;
  935. }
  936. void COutBar::_FillToolbar()
  937. {
  938. if (FAILED(_LoadSettings()))
  939. _CreateDefaultButtons();
  940. SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
  941. }
  942. void COutBar::_EmptyToolbar(BOOL fDelete)
  943. {
  944. if (fDelete)
  945. while (SendMessage(m_hwndTools, TB_DELETEBUTTON, 0, 0))
  946. ;
  947. }
  948. BOOL COutBar::_FindButton(int *piBtn, LPITEMIDLIST pidl)
  949. {
  950. BOOL fFound = FALSE;
  951. #if 0
  952. int iBtn, cBtn, iCmp;
  953. TBBUTTON tbb;
  954. Assert(pidl);
  955. cBtn = (int)SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0L);
  956. // skip the root, so start at index 1
  957. for (iBtn = 1; iBtn < cBtn; iBtn++)
  958. {
  959. if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
  960. {
  961. Assert(tbb.dwData);
  962. iCmp = ShortFromResult(m_pShellFolder->CompareIDs(0, pidl, (LPITEMIDLIST)(tbb.dwData)));
  963. if (iCmp <= 0)
  964. {
  965. fFound = (iCmp == 0);
  966. break;
  967. }
  968. }
  969. }
  970. *piBtn = iBtn;
  971. #endif
  972. return fFound;
  973. }
  974. BOOL COutBar::_InsertButton(int index, FOLDERINFO *pInfo)
  975. {
  976. TBBUTTON tbb;
  977. TCHAR szName[2 * MAX_PATH];
  978. LPTSTR pszFree = NULL;
  979. BOOL fRet;
  980. tbb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
  981. tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_NOPREFIX;
  982. tbb.idCommand = m_idCommand++;
  983. tbb.dwData = (DWORD_PTR) pInfo->idFolder;
  984. tbb.iBitmap = GetFolderIcon(pInfo);
  985. tbb.iString = (INT_PTR) pInfo->pszName;
  986. if (pInfo->cUnread)
  987. {
  988. DWORD cchSize = ARRAYSIZE(szName);;
  989. if (lstrlen(pInfo->pszName) + 13 < ARRAYSIZE(szName))
  990. tbb.iString = (INT_PTR)szName;
  991. else
  992. {
  993. cchSize = (lstrlen(pInfo->pszName) + 14);
  994. if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR)))
  995. return FALSE;
  996. tbb.iString = (INT_PTR)pszFree;
  997. }
  998. wnsprintf((LPTSTR)tbb.iString, cchSize, "%s (%d)", pInfo->pszName, CUnread(pInfo));
  999. }
  1000. // Check to see if we're inserting at the end
  1001. if (index == -1)
  1002. {
  1003. index = ToolBar_ButtonCount(m_hwndTools);
  1004. }
  1005. // insert the root
  1006. fRet = (BOOL)SendMessage(m_hwndTools, TB_INSERTBUTTON, index, (LPARAM)&tbb);
  1007. SafeMemFree(pszFree);
  1008. return fRet;
  1009. }
  1010. BOOL COutBar::_InsertButton(int iIndex, FOLDERID id)
  1011. {
  1012. FOLDERINFO rInfo = {0};
  1013. if (SUCCEEDED(g_pStore->GetFolderInfo(id, &rInfo)))
  1014. {
  1015. _InsertButton(iIndex, &rInfo);
  1016. g_pStore->FreeRecord(&rInfo);
  1017. }
  1018. return (TRUE);
  1019. }
  1020. BOOL COutBar::_DeleteButton(int iBtn)
  1021. {
  1022. TBBUTTON tbb;
  1023. if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
  1024. {
  1025. if (SendMessage(m_hwndTools, TB_DELETEBUTTON, iBtn, 0L))
  1026. {
  1027. _SaveSettings();
  1028. m_pOutBarNotify->Lock(m_hwnd);
  1029. m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
  1030. m_pOutBarNotify->Unlock();
  1031. return (TRUE);
  1032. }
  1033. }
  1034. return FALSE;
  1035. }
  1036. BOOL COutBar::_UpdateButton(int iBtn, LPITEMIDLIST pidl)
  1037. {
  1038. #if 0
  1039. TBBUTTON tbb;
  1040. TBBUTTONINFO tbbi;
  1041. TCHAR szName[2 * MAX_PATH];
  1042. LPTSTR pszFree = NULL;
  1043. BOOL fRet = FALSE;
  1044. if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
  1045. {
  1046. tbbi.cbSize = sizeof(tbbi);
  1047. tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE | TBIF_LPARAM;
  1048. tbbi.iImage = FIDL_ICONID(pidl);
  1049. tbbi.lParam = (DWORD)pidl;
  1050. if (FIDL_UNREAD(pidl))
  1051. {
  1052. DWORD cchSize = ARRAYSIZE(szName);
  1053. if (lstrlen(FIDL_NAME(pidl)) + 13 < ARRAYSIZE(szName))
  1054. tbbi.pszText = szName;
  1055. else
  1056. {
  1057. cchSize = (lstrlen(FIDL_NAME(pidl)) + 14);
  1058. if (!MemAlloc((LPVOID*)&pszFree, (cchSize * sizeof(TCHAR))))
  1059. return FALSE;
  1060. tbbi.pszText = pszFree;
  1061. }
  1062. wnsprintf(tbbi.pszText, cchSize, "%s (%d)", FIDL_NAME(pidl), FIDL_UNREAD(pidl));
  1063. }
  1064. else
  1065. tbbi.pszText = FIDL_NAME(pidl);
  1066. fRet = SendMessage(m_hwndTools, TB_SETBUTTONINFO, (WPARAM)tbb.idCommand, (LPARAM)&tbbi);
  1067. if (tbb.dwData)
  1068. PidlFree((LPITEMIDLIST)(tbb.dwData));
  1069. if (pszFree)
  1070. MemFree(pszFree);
  1071. }
  1072. return fRet;
  1073. #endif
  1074. return 0;
  1075. }
  1076. #if 0
  1077. void COutBar::_OnFolderNotify(FOLDERNOTIFY *pnotify)
  1078. {
  1079. LPITEMIDLIST pidl;
  1080. int iBtn;
  1081. BOOL fRecalc = FALSE;
  1082. Assert(pnotify != NULL);
  1083. Assert(pnotify->pidlNew != NULL);
  1084. switch (pnotify->msg)
  1085. {
  1086. case NEW_FOLDER:
  1087. // only insert if it is a root level pidl
  1088. if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
  1089. {
  1090. // check for dups and figure out where to insert
  1091. if (!FindButton(&iBtn, pnotify->pidlNew))
  1092. {
  1093. if (pidl = PidlDupIdList(pnotify->pidlNew))
  1094. fRecalc = InsertButton(iBtn, pidl);
  1095. }
  1096. }
  1097. break ;
  1098. case DELETE_FOLDER:
  1099. // only look for it if it is a root level pidl
  1100. if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
  1101. {
  1102. if (FindButton(&iBtn, pnotify->pidlNew))
  1103. fRecalc = DeleteButton(iBtn);
  1104. }
  1105. break ;
  1106. case RENAME_FOLDER:
  1107. case MOVE_FOLDER:
  1108. // only look for it if it is a root level pidl
  1109. if (0 == NEXTID(pnotify->pidlOld)->mkid.cb)
  1110. {
  1111. if (FindButton(&iBtn, pnotify->pidlOld))
  1112. fRecalc = DeleteButton(iBtn);
  1113. }
  1114. // only insert if it is a root level pidl
  1115. if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
  1116. {
  1117. // check for dups and figure out where to insert
  1118. if (!FindButton(&iBtn, pnotify->pidlNew))
  1119. {
  1120. if (pidl = PidlDupIdList(pnotify->pidlNew))
  1121. fRecalc = InsertButton(iBtn, pidl);
  1122. }
  1123. }
  1124. break ;
  1125. case UNREAD_CHANGE:
  1126. case UPDATEFLAG_CHANGE:
  1127. // only look for it if it is a root level pidl
  1128. if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
  1129. {
  1130. // check for dups and figure out where to insert
  1131. if (FindButton(&iBtn, pnotify->pidlNew))
  1132. {
  1133. if (pidl = PidlDupIdList(pnotify->pidlNew))
  1134. UpdateButton(iBtn, pidl);
  1135. }
  1136. }
  1137. break ;
  1138. case IMAPFLAG_CHANGE:
  1139. // don't care
  1140. break ;
  1141. case FOLDER_PROPS_CHANGED:
  1142. //Don't care
  1143. break ;
  1144. default:
  1145. AssertSz(FALSE, "Unhandled CFolderCache notification!");
  1146. break;
  1147. }
  1148. if (fRecalc)
  1149. SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
  1150. }
  1151. #endif
  1152. //
  1153. // FUNCTION: COutBar::_OnContextMenu
  1154. //
  1155. // PURPOSE: If the WM_CONTEXTMENU message is generated from the keyboard
  1156. // then figure out a pos to invoke the menu. Then dispatch the
  1157. // request to the handler.
  1158. //
  1159. // PARAMETERS:
  1160. // hwnd - Handle of the view window.
  1161. // hwndClick - Handle of the window the user clicked in.
  1162. // x, y - Position of the mouse click in screen coordinates.
  1163. //
  1164. void COutBar::_OnContextMenu(int x, int y)
  1165. {
  1166. HRESULT hr;
  1167. HMENU hMenu;
  1168. int id = 0;
  1169. int i;
  1170. POINT pt = { x, y };
  1171. TBBUTTON tbb;
  1172. // Figure out where the click was
  1173. ScreenToClient(m_hwndTools, &pt);
  1174. i = ToolBar_HitTest(m_hwndTools, &pt);
  1175. // If the click was on a button, then bring up the item context menu
  1176. if (i >= 0)
  1177. {
  1178. // Get the button info
  1179. SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb);
  1180. // Load the context menu
  1181. hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_ITEM_POPUP);
  1182. if (!hMenu)
  1183. return;
  1184. // Mark the button
  1185. SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP | TBSTATE_MARKED));
  1186. m_idSel = tbb.idCommand;
  1187. // If this is the deleted items folder, add the "empty" menu item
  1188. TBBUTTONINFO tbbi;
  1189. tbbi.cbSize = sizeof(tbbi);
  1190. tbbi.dwMask = TBIF_LPARAM;
  1191. if (-1 != SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi))
  1192. {
  1193. FOLDERINFO rInfo;
  1194. if (SUCCEEDED(g_pStore->GetFolderInfo((FOLDERID) tbbi.lParam, &rInfo)))
  1195. {
  1196. if (rInfo.tySpecial != FOLDER_DELETED)
  1197. {
  1198. DeleteMenu(hMenu, ID_EMPTY_WASTEBASKET, MF_BYCOMMAND);
  1199. }
  1200. g_pStore->FreeRecord(&rInfo);
  1201. }
  1202. }
  1203. // Do the enable-disable thing
  1204. MenuUtil_EnablePopupMenu(hMenu, this);
  1205. // Display the context menu
  1206. id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
  1207. x, y, m_hwnd, NULL);
  1208. // Unmark the button
  1209. SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP));
  1210. // See if the user chose a menu item
  1211. if (id != 0)
  1212. {
  1213. Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  1214. }
  1215. m_idSel = -1;
  1216. // Clean this up
  1217. DestroyMenu(hMenu);
  1218. }
  1219. // Else if the click was in the empty space, show the bar context menu
  1220. else
  1221. {
  1222. // Load the context menu
  1223. hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_POPUP);
  1224. if (!hMenu)
  1225. return;
  1226. // Do the enable-disable thing
  1227. MenuUtil_EnablePopupMenu(hMenu, this);
  1228. // Display the context menu
  1229. id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
  1230. x, y, m_hwnd, NULL);
  1231. // See if the user chose a menu item
  1232. if (id != 0)
  1233. {
  1234. Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  1235. }
  1236. // Clean this up
  1237. DestroyMenu(hMenu);
  1238. }
  1239. }
  1240. HRESULT COutBar::_CreateDefaultButtons()
  1241. {
  1242. IEnumerateFolders *pEnum = NULL;
  1243. FOLDERINFO rFolder;
  1244. UINT iIndex = 0;
  1245. FOLDERID idFolderDefault;
  1246. // Figure out the default server first
  1247. if (FAILED(GetDefaultServerId(ACCT_MAIL, &idFolderDefault)))
  1248. idFolderDefault = FOLDERID_LOCAL_STORE;
  1249. if (!(g_dwAthenaMode & MODE_NEWSONLY))
  1250. {
  1251. // Inbox first
  1252. if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_INBOX, &rFolder)))
  1253. {
  1254. _InsertButton(iIndex++, &rFolder);
  1255. g_pStore->FreeRecord(&rFolder);
  1256. }
  1257. }
  1258. // Outbox
  1259. if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_OUTBOX, &rFolder)))
  1260. {
  1261. _InsertButton(iIndex++, &rFolder);
  1262. g_pStore->FreeRecord(&rFolder);
  1263. }
  1264. // Sent Items
  1265. if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_SENT, &rFolder)))
  1266. {
  1267. _InsertButton(iIndex++, &rFolder);
  1268. g_pStore->FreeRecord(&rFolder);
  1269. }
  1270. // Deleted
  1271. if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_DELETED, &rFolder)))
  1272. {
  1273. _InsertButton(iIndex++, &rFolder);
  1274. g_pStore->FreeRecord(&rFolder);
  1275. }
  1276. // Drafts
  1277. if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_DRAFT, &rFolder)))
  1278. {
  1279. _InsertButton(iIndex++, &rFolder);
  1280. g_pStore->FreeRecord(&rFolder);
  1281. }
  1282. // Save at this point so everyone will be in sync
  1283. _SaveSettings();
  1284. return (S_OK);
  1285. }
  1286. HRESULT COutBar::_LoadSettings(void)
  1287. {
  1288. BAR_PERSIST_INFO *pPersist = NULL;
  1289. HRESULT hr = E_FAIL;
  1290. DWORD iIndex = 0;
  1291. FOLDERINFO rInfo;
  1292. UINT i;
  1293. // Load the settings
  1294. if (FAILED(hr = OutlookBar_LoadSettings(&pPersist)))
  1295. goto exit;
  1296. // Load the bar from the saved folder ID's
  1297. for (i = 0; i < pPersist->cItems; i++)
  1298. {
  1299. // Get the folder info for this folder
  1300. if (SUCCEEDED(g_pStore->GetFolderInfo(pPersist->rgFolders[i], &rInfo)))
  1301. {
  1302. if (_InsertButton(iIndex, &rInfo))
  1303. iIndex++;
  1304. g_pStore->FreeRecord(&rInfo);
  1305. }
  1306. }
  1307. // If the bar is empty, and the user didn't save it empty, use the defaults
  1308. if (iIndex == 0 && pPersist->cItems)
  1309. hr = E_FAIL;
  1310. else
  1311. hr = S_OK;
  1312. // Also restore the width while we're at it
  1313. if (pPersist->cxWidth >= 28)
  1314. {
  1315. m_cxWidth = pPersist->cxWidth;
  1316. }
  1317. if (m_fOnce)
  1318. {
  1319. m_fLarge = !pPersist->fSmall;
  1320. m_fOnce = FALSE;
  1321. }
  1322. exit:
  1323. SafeMemFree(pPersist);
  1324. return (hr);
  1325. }
  1326. HRESULT COutBar::_SaveSettings(void)
  1327. {
  1328. BAR_PERSIST_INFO *pPersist = NULL;
  1329. DWORD cbData;
  1330. DWORD iIndex = 0;
  1331. FOLDERINFO rInfo;
  1332. UINT i;
  1333. DWORD cButtons;
  1334. TBBUTTON tbb;
  1335. RECT rcClient;
  1336. // Get the count of buttons from the outlook bar
  1337. cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0);
  1338. // Allocate a persist info struct big enough for everything
  1339. cbData = sizeof(BAR_PERSIST_INFO) + ((cButtons - 1) * sizeof(FOLDERID));
  1340. if (!MemAlloc((LPVOID *) &pPersist, cbData))
  1341. return (E_OUTOFMEMORY);
  1342. // Fill in the persist info
  1343. pPersist->dwVersion = GetOutlookBarVersion();
  1344. pPersist->cItems = cButtons;
  1345. pPersist->fSmall = !m_fLarge;
  1346. pPersist->ftSaved.dwHighDateTime = 0;
  1347. pPersist->ftSaved.dwLowDateTime = 0;
  1348. GetClientRect(m_hwnd, &rcClient);
  1349. pPersist->cxWidth = rcClient.right;
  1350. // Loop through the buttons on the toolbar and get the info from each
  1351. for (i = 0; i < cButtons; i++)
  1352. {
  1353. SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb);
  1354. pPersist->rgFolders[i] = (FOLDERID) tbb.dwData;
  1355. }
  1356. // Now open the registry and save the blob
  1357. AthUserSetValue(NULL, GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData);
  1358. // Free up the struct
  1359. SafeMemFree(pPersist);
  1360. return (S_OK);
  1361. }
  1362. HRESULT COutBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  1363. {
  1364. BOOL fSpecial = FALSE;
  1365. BOOL fServer = FALSE;
  1366. BOOL fRoot = FALSE;
  1367. BOOL fNews = FALSE;
  1368. BOOL fIMAP = FALSE;
  1369. FOLDERINFO rFolder = {0};
  1370. FOLDERID idFolder = FOLDERID_INVALID;
  1371. if (m_idSel != -1)
  1372. {
  1373. // Get the ID of the folder that is selected
  1374. TBBUTTONINFO tbbi;
  1375. tbbi.cbSize = sizeof(tbbi);
  1376. tbbi.dwMask = TBIF_LPARAM;
  1377. if (-1 == SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi))
  1378. return (E_UNEXPECTED);
  1379. // Get the Folder Info
  1380. idFolder = (FOLDERID) tbbi.lParam;
  1381. if (FAILED(g_pStore->GetFolderInfo(idFolder, &rFolder)))
  1382. return (E_UNEXPECTED);
  1383. // Break some of this down for readability
  1384. fSpecial = rFolder.tySpecial != FOLDER_NOTSPECIAL;
  1385. fServer = rFolder.dwFlags & FOLDER_SERVER;
  1386. fRoot = FOLDERID_ROOT == idFolder;
  1387. fNews = rFolder.tyFolder == FOLDER_NEWS;
  1388. fIMAP = rFolder.tyFolder == FOLDER_IMAP;
  1389. }
  1390. // Loop through the commands in the prgCmds array looking for ones that haven't been handled
  1391. for (UINT i = 0; i < cCmds; i++)
  1392. {
  1393. if (prgCmds[i].cmdf == 0)
  1394. {
  1395. switch (prgCmds[i].cmdID)
  1396. {
  1397. case ID_OPEN_FOLDER:
  1398. case ID_REMOVE_SHORTCUT:
  1399. case ID_NEW_SHORTCUT:
  1400. case ID_HIDE:
  1401. case ID_FIND_MESSAGE:
  1402. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  1403. break;
  1404. case ID_LARGE_ICONS:
  1405. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  1406. if (m_fLarge)
  1407. prgCmds[i].cmdf |= OLECMDF_NINCHED;
  1408. break;
  1409. case ID_SMALL_ICONS:
  1410. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  1411. if (!m_fLarge)
  1412. prgCmds[i].cmdf |= OLECMDF_NINCHED;
  1413. break;
  1414. case ID_RENAME_SHORTCUT:
  1415. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  1416. break;
  1417. case ID_PROPERTIES:
  1418. {
  1419. Assert(idFolder != FOLDERID_INVALID);
  1420. prgCmds[i].cmdf |= OLECMDF_SUPPORTED;
  1421. // Everything except the root and the personal folders node
  1422. if (!fRoot && ((fServer && (fNews || fIMAP)) || !fServer))
  1423. prgCmds[i].cmdf |= OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  1424. break;
  1425. }
  1426. case ID_EMPTY_WASTEBASKET:
  1427. {
  1428. if (rFolder.cMessages > 0 || FHasChildren(&rFolder, SUBSCRIBED))
  1429. prgCmds[i].cmdf = OLECMDF_ENABLED | OLECMDF_SUPPORTED;
  1430. break;
  1431. }
  1432. }
  1433. }
  1434. }
  1435. g_pStore->FreeRecord(&rFolder);
  1436. return (S_OK);
  1437. }
  1438. HRESULT COutBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  1439. {
  1440. TBBUTTONINFO tbbi = { 0 };
  1441. FOLDERID id = FOLDERID_INVALID;
  1442. int iPos = -1;
  1443. // Get the ID of the folder that was selected
  1444. tbbi.cbSize = sizeof(tbbi);
  1445. tbbi.dwMask = TBIF_LPARAM;
  1446. tbbi.lParam = 0;
  1447. if (-1 != (iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, m_idSel, (LPARAM) &tbbi)))
  1448. {
  1449. id = (FOLDERID) tbbi.lParam;
  1450. }
  1451. switch (nCmdID)
  1452. {
  1453. case ID_OPEN_FOLDER:
  1454. {
  1455. if (id != FOLDERID_INVALID)
  1456. m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0);
  1457. return (S_OK);
  1458. }
  1459. case ID_REMOVE_SHORTCUT:
  1460. {
  1461. _DeleteButton(iPos);
  1462. return (S_OK);
  1463. }
  1464. case ID_RENAME_SHORTCUT:
  1465. break;
  1466. case ID_PROPERTIES:
  1467. {
  1468. if (id != FOLDERID_INVALID)
  1469. MenuUtil_OnProperties(m_hwndParent, id);
  1470. return (S_OK);
  1471. }
  1472. case ID_LARGE_ICONS:
  1473. case ID_SMALL_ICONS:
  1474. {
  1475. _SetButtonStyle(nCmdID == ID_SMALL_ICONS);
  1476. return (S_OK);
  1477. }
  1478. case ID_NEW_SHORTCUT:
  1479. {
  1480. FOLDERID idFolderDest;
  1481. HRESULT hr;
  1482. hr = SelectFolderDialog(m_hwnd, SFD_SELECTFOLDER, FOLDERID_ROOT,
  1483. FD_NONEWFOLDERS, (LPCTSTR) idsNewShortcutTitle,
  1484. (LPCTSTR) idsNewShortcutCaption, &idFolderDest);
  1485. if (SUCCEEDED(hr))
  1486. {
  1487. OutlookBar_AddShortcut(idFolderDest);
  1488. }
  1489. return (S_OK);
  1490. }
  1491. case ID_HIDE:
  1492. {
  1493. if (m_pBrowser)
  1494. {
  1495. m_pBrowser->SetViewLayout(DISPID_MSGVIEW_OUTLOOK_BAR, LAYOUT_POS_NA, FALSE, 0, 0);
  1496. }
  1497. return (S_OK);
  1498. }
  1499. case ID_EMPTY_WASTEBASKET:
  1500. {
  1501. if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsWarnEmptyDeletedItems),
  1502. NULL, MB_YESNO | MB_DEFBUTTON2) == IDYES)
  1503. {
  1504. EmptyFolder(m_hwnd, id);
  1505. }
  1506. return (S_OK);
  1507. }
  1508. case ID_FIND_MESSAGE:
  1509. {
  1510. DoFindMsg(id, 0);
  1511. return (S_OK);
  1512. }
  1513. }
  1514. return (OLECMDERR_E_NOTSUPPORTED);
  1515. }
  1516. BOOL COutBar::_SetButtonStyle(BOOL fSmall)
  1517. {
  1518. LONG lStyle;
  1519. SIZE s1, s2;
  1520. // Get the current style
  1521. lStyle = (LONG) SendMessage(m_hwndTools, TB_GETSTYLE, 0, 0);
  1522. // Make sure we have the right image list loaded
  1523. if (fSmall && !m_himlSmall)
  1524. {
  1525. // Load the image list for the toolbar
  1526. m_himlSmall = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0, RGB(255, 0, 255));
  1527. if (!m_himlSmall)
  1528. return FALSE;
  1529. }
  1530. if (!fSmall && !m_himlLarge)
  1531. {
  1532. // Load the image list for the toolbar
  1533. m_himlLarge = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFoldersLarge), 32, 0, RGB(255, 0, 255));
  1534. if (!m_himlLarge)
  1535. return FALSE;
  1536. }
  1537. // Get the size
  1538. RECT rc;
  1539. GetClientRect(m_hwndTools, &rc);
  1540. NMPGCALCSIZE nm;
  1541. nm.hdr.code = PGN_CALCSIZE;
  1542. nm.dwFlag = PGF_CALCHEIGHT;
  1543. nm.iWidth = 0;
  1544. nm.iHeight = 0;
  1545. SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) &nm);
  1546. // Now swap styles
  1547. if (fSmall)
  1548. {
  1549. lStyle |= TBSTYLE_LIST;
  1550. SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle);
  1551. SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
  1552. SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlSmall);
  1553. SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 1, 0L);
  1554. SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right));
  1555. }
  1556. else
  1557. {
  1558. lStyle &= ~TBSTYLE_LIST;
  1559. SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle);
  1560. SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlLarge);
  1561. SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(32, 32));
  1562. SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 2, 0L);
  1563. SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right));
  1564. }
  1565. PostMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
  1566. InvalidateRect(m_hwndTools, NULL, TRUE);
  1567. m_fLarge = !fSmall;
  1568. return (TRUE);
  1569. }
  1570. HRESULT OutlookBar_AddShortcut(FOLDERID idFolder)
  1571. {
  1572. HRESULT hr;
  1573. BAR_PERSIST_INFO *pPersist = NULL;
  1574. DWORD cbData = 0;
  1575. INotify *pNotify = NULL;
  1576. // Load the current settings out of the registry. If it fails, that means
  1577. // we've never saved our settings before.
  1578. if (SUCCEEDED(hr = OutlookBar_LoadSettings(&pPersist)))
  1579. {
  1580. // Get the size of the current struct and add room for a new folder
  1581. cbData = sizeof(BAR_PERSIST_INFO) + (pPersist->cItems * sizeof(FOLDERID));
  1582. // Realloc the structure
  1583. if (MemRealloc((LPVOID *) &pPersist, cbData))
  1584. {
  1585. // Add our new button to the end
  1586. pPersist->rgFolders[pPersist->cItems] = idFolder;
  1587. pPersist->cItems++;
  1588. // Save the new settings out
  1589. if (SUCCEEDED(OutlookBar_SaveSettings(pPersist, cbData)))
  1590. {
  1591. // Send notifications
  1592. if (SUCCEEDED(CreateNotify(&pNotify)))
  1593. {
  1594. if (SUCCEEDED(pNotify->Initialize(c_szOutBarNotifyName)))
  1595. {
  1596. pNotify->Lock(NULL);
  1597. pNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
  1598. pNotify->Unlock();
  1599. }
  1600. pNotify->Release();
  1601. }
  1602. }
  1603. }
  1604. SafeMemFree(pPersist);
  1605. }
  1606. return (hr);
  1607. }
  1608. HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist)
  1609. {
  1610. HKEY hKey = 0;
  1611. LONG lResult;
  1612. DWORD dwType;
  1613. BAR_PERSIST_INFO *pPersist = NULL;
  1614. DWORD cbData;
  1615. HRESULT hr = E_FAIL;
  1616. if (!ppPersist)
  1617. return (E_INVALIDARG);
  1618. // Get the reg key for this user
  1619. if (ERROR_SUCCESS != AthUserOpenKey(NULL, KEY_READ, &hKey))
  1620. return (hr);
  1621. // Get the size of the blob in the registry
  1622. lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, NULL, &cbData);
  1623. if (ERROR_SUCCESS != lResult)
  1624. goto exit;
  1625. // Allocate a buffer for the blob in the registry
  1626. if (!MemAlloc((LPVOID *) &pPersist, cbData + 1))
  1627. {
  1628. hr = E_OUTOFMEMORY;
  1629. goto exit;
  1630. }
  1631. // Now get the data from the registry
  1632. lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, (LPBYTE) pPersist, &cbData);
  1633. if (ERROR_SUCCESS != lResult)
  1634. goto exit;
  1635. // Check to see if this version matches our version
  1636. if (pPersist->dwVersion != COutBar::GetOutlookBarVersion())
  1637. goto exit;
  1638. // Check to see if the saved time is valid
  1639. // $REVIEW - How?
  1640. // Double check that the size is correct
  1641. if (cbData != (sizeof(BAR_PERSIST_INFO) + ((pPersist->cItems - 1) * sizeof(FOLDERID))))
  1642. goto exit;
  1643. hr = S_OK;
  1644. exit:
  1645. if (hKey)
  1646. RegCloseKey(hKey);
  1647. if (FAILED(hr))
  1648. SafeMemFree(pPersist);
  1649. *ppPersist = pPersist;
  1650. return (hr);
  1651. }
  1652. HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData)
  1653. {
  1654. // Open the registry and save the blob
  1655. AthUserSetValue(NULL, COutBar::GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData);
  1656. return (S_OK);
  1657. }
  1658. HRESULT COutBar::OnTransaction(HTRANSACTION hTransaction, DWORD_PTR dwCookie, IDatabase *pDB)
  1659. {
  1660. TRANSACTIONTYPE tyTransaction;
  1661. ORDINALLIST Ordinals;
  1662. FOLDERINFO Folder1={0};
  1663. FOLDERINFO Folder2={0};
  1664. DWORD cButtons;
  1665. TBBUTTON tbb;
  1666. TCHAR szName[2 * MAX_PATH];
  1667. LPTSTR pszFree = NULL;
  1668. BOOL fChanged;
  1669. INDEXORDINAL iIndex;
  1670. TBBUTTONINFO tbbi;
  1671. int iButton;
  1672. if (!IsWindow(m_hwnd))
  1673. return (S_OK);
  1674. // Get the number of buttons on our bar
  1675. cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0);
  1676. // Walk through the notifications
  1677. while (hTransaction)
  1678. {
  1679. // Get Transact
  1680. if (FAILED(pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals)))
  1681. break;
  1682. // Delete
  1683. if (TRANSACTION_DELETE == tyTransaction)
  1684. {
  1685. for (iButton = cButtons - 1; iButton >= 0; iButton--)
  1686. {
  1687. // Get the button information
  1688. ToolBar_GetButton(m_hwndTools, iButton, &tbb);
  1689. // If the ID of this button matches the ID that changed
  1690. if ((FOLDERID) tbb.dwData == Folder1.idFolder)
  1691. {
  1692. // Blow it away
  1693. SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0);
  1694. }
  1695. }
  1696. }
  1697. // Update
  1698. else if (TRANSACTION_UPDATE == tyTransaction)
  1699. {
  1700. // Loop through all our buttons since we might have dupes
  1701. for (iButton = cButtons - 1; iButton >= 0; iButton--)
  1702. {
  1703. fChanged = FALSE;
  1704. // Get the button information
  1705. ToolBar_GetButton(m_hwndTools, iButton, &tbb);
  1706. // If the ID of this button matches the ID that changed
  1707. if ((FOLDERID) tbb.dwData == Folder1.idFolder)
  1708. {
  1709. tbbi.cbSize = sizeof(TBBUTTONINFO);
  1710. tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE;
  1711. tbbi.pszText = szName;
  1712. tbbi.cchText = ARRAYSIZE(szName);
  1713. ToolBar_GetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi);
  1714. // Unread Change || Folder Renamed
  1715. if (Folder1.cUnread != Folder2.cUnread ||
  1716. lstrcmp(Folder1.pszName, Folder2.pszName) != 0)
  1717. {
  1718. if (Folder2.cUnread)
  1719. {
  1720. DWORD cchSize = ARRAYSIZE(szName);
  1721. if (lstrlen(Folder2.pszName) + 13 < ARRAYSIZE(szName))
  1722. tbbi.pszText = szName;
  1723. else
  1724. {
  1725. cchSize = (lstrlen(Folder2.pszName) + 14);
  1726. if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR)))
  1727. return FALSE;
  1728. tbbi.pszText = pszFree;
  1729. }
  1730. wnsprintf(tbbi.pszText, cchSize, "%s (%d)", Folder2.pszName, CUnread(&Folder2));
  1731. }
  1732. else
  1733. {
  1734. tbbi.pszText = Folder2.pszName;
  1735. }
  1736. fChanged = TRUE;
  1737. }
  1738. // synchronize state changed ?
  1739. if ((0 == (Folder1.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL))) ^
  1740. (0 == (Folder2.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL))))
  1741. {
  1742. tbbi.iImage = GetFolderIcon(&Folder2);
  1743. fChanged = TRUE;
  1744. }
  1745. if (ISFLAGSET(Folder1.dwFlags, FOLDER_SUBSCRIBED) != ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED))
  1746. {
  1747. if (ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED))
  1748. {
  1749. tbbi.iImage = GetFolderIcon(&Folder2);
  1750. fChanged = TRUE;
  1751. }
  1752. else
  1753. {
  1754. SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0);
  1755. fChanged = FALSE;
  1756. }
  1757. }
  1758. }
  1759. if (fChanged)
  1760. {
  1761. ToolBar_SetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi);
  1762. }
  1763. SafeMemFree(pszFree);
  1764. }
  1765. }
  1766. }
  1767. pDB->FreeRecord(&Folder1);
  1768. pDB->FreeRecord(&Folder2);
  1769. return (S_OK);
  1770. }
  1771. BOOL COutBar::_IsTempNewsgroup(IDataObject *pObject)
  1772. {
  1773. FORMATETC fe;
  1774. STGMEDIUM stm;
  1775. FOLDERID *pidFolder;
  1776. FOLDERINFO rInfo;
  1777. BOOL fReturn = TRUE;
  1778. SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
  1779. if (SUCCEEDED(pObject->GetData(&fe, &stm)))
  1780. {
  1781. pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal);
  1782. if (SUCCEEDED(g_pStore->GetFolderInfo(*pidFolder, &rInfo)))
  1783. {
  1784. if ((rInfo.tySpecial == FOLDER_NOTSPECIAL) &&
  1785. (rInfo.tyFolder == FOLDER_NEWS) &&
  1786. (0 == (rInfo.dwFlags & FOLDER_SUBSCRIBED)))
  1787. {
  1788. fReturn = FALSE;
  1789. }
  1790. g_pStore->FreeRecord(&rInfo);
  1791. }
  1792. GlobalUnlock(stm.hGlobal);
  1793. ReleaseStgMedium(&stm);
  1794. }
  1795. return (fReturn);
  1796. }
  1797. LPCTSTR COutBar::GetRegKey()
  1798. {
  1799. LPCTSTR retval;
  1800. if (g_dwAthenaMode & MODE_NEWSONLY)
  1801. {
  1802. retval = c_szRegOutlookBarNewsOnly;
  1803. }
  1804. else
  1805. {
  1806. retval = c_szRegOutlookBar;
  1807. }
  1808. return retval;
  1809. }
  1810. DWORD COutBar::GetOutlookBarVersion()
  1811. {
  1812. DWORD retval;
  1813. if (g_dwAthenaMode & MODE_NEWSONLY)
  1814. {
  1815. retval = OUTLOOK_BAR_NEWSONLY_VERSION;
  1816. }
  1817. else
  1818. {
  1819. retval = OUTLOOK_BAR_VERSION;
  1820. }
  1821. return retval;
  1822. }