///////////////////////////////////////////////////////////////////////////// // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved. // // MODULE: outbar.cpp // // PURPOSE: Implements the Outlook Bar // #include "pch.hxx" #include "resource.h" #include "outbar.h" #include "goptions.h" #include "ourguid.h" #include #include #include #include #include #include #include "shlwapip.h" #include "storutil.h" #include "menures.h" #include "menuutil.h" #include "dragdrop.h" #include "newfldr.h" #include "finder.h" #include "instance.h" ASSERTDATA #define IDC_FRAME 100 #define IDC_PAGER 101 #define IDC_TOOLBAR 102 #define HT_ENTER 1 #define HT_OVER 2 #define HT_LEAVE 3 // Special HitTest results #define IBHT_SOURCE (-32768) #define IBHT_BACKGROUND (-32767) #define IBHT_PAGER (-32766) //////////////////////////////////////////////////////////////////////// // // Prototypes // //////////////////////////////////////////////////////////////////////// HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist); HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData); extern DWORD CUnread(FOLDERINFO *pfi); //////////////////////////////////////////////////////////////////////// // // Module Data // //////////////////////////////////////////////////////////////////////// static const TCHAR s_szOutBarWndClass[] = TEXT("Outlook Express Outlook Bar"); static const TCHAR s_szOutBarFrameClass[] = TEXT("Outlook Express Outlook Bar Frame"); static const TCHAR c_szOutBarNotifyName[] = TEXT("Outlook Express Outlook Bar Notify"); //////////////////////////////////////////////////////////////////////// // // Constructors, Destructors, and other initialization stuff // //////////////////////////////////////////////////////////////////////// COutBar::COutBar() { m_cRef = 1; m_hwndParent = NULL; m_hwnd = NULL; m_hwndFrame = NULL; m_hwndPager = NULL; m_hwndTools = NULL; m_ptbSite = NULL; m_fShow = FALSE; m_pBrowser = NULL; m_pStNotify = NULL; m_idCommand = 0; m_fResizing = FALSE; m_idSel = -1; // load the width from resource m_cxWidth = 70; TCHAR szBuffer[64]; if (AthLoadString(idsMaxOutbarBtnWidth, szBuffer, ARRAYSIZE(szBuffer))) { m_cxWidth = StrToInt(szBuffer); if (m_cxWidth == 0) m_cxWidth = 70; } m_fLarge = TRUE; m_himlLarge = NULL; m_himlSmall = NULL; m_pOutBarNotify = NULL; m_pDataObject = NULL; m_grfKeyState = 0; m_dwEffectCur = DROPEFFECT_NONE; m_idCur = -1; m_pTargetCur = NULL; m_idDropHilite = 0; m_fInsertMark = FALSE; m_fOnce = TRUE; } COutBar::~COutBar() { Assert(NULL == m_pStNotify); if (m_hwnd) DestroyWindow(m_hwnd); if (m_himlLarge) ImageList_Destroy(m_himlLarge); if (m_himlSmall) ImageList_Destroy(m_himlSmall); SafeRelease(m_pDataObject); } HRESULT COutBar::HrInit(LPSHELLFOLDER psf, IAthenaBrowser *psb) { HRESULT hr; m_pBrowser = psb; hr = CreateNotify(&m_pStNotify); if (FAILED(hr)) return(hr); return m_pStNotify->Initialize((TCHAR *)c_szMailFolderNotify); } //////////////////////////////////////////////////////////////////////// // // IUnknown // //////////////////////////////////////////////////////////////////////// HRESULT COutBar::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, IID_IDockingWindow) || IsEqualIID(riid, IID_IDatabaseNotify)) { *ppvObj = (void*)(IDockingWindow*)this; } else if (IsEqualIID(riid, IID_IObjectWithSite)) { *ppvObj = (void*)(IObjectWithSite*)this; } else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } ULONG COutBar::AddRef() { return ++m_cRef; } ULONG COutBar::Release() { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; } //////////////////////////////////////////////////////////////////////// // // IOleWindow // //////////////////////////////////////////////////////////////////////// HRESULT COutBar::GetWindow(HWND * lphwnd) { *lphwnd = m_hwnd; return (*lphwnd ? S_OK : E_FAIL); } HRESULT COutBar::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; } // // FUNCTION: COutBar::ShowDW() // // PURPOSE: Causes the bar to be displayed. If it has not yet been // created, we do that here too. // // PARAMETERS: // [in] fShow - TRUE to make the bar visible, FALSE to hide. // // RETURN VALUE: // HRESULT // HRESULT COutBar::ShowDW(BOOL fShow) { // Make sure we have a site pointer first if (!m_ptbSite) { AssertSz(0, _T("COutBar::ShowDW() - Can't show without calling SetSite() first.")); return E_FAIL; } // Decide if we need to create a new window or show a currently existing // window if (!m_hwnd) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); if (!GetClassInfoEx(g_hInst, s_szOutBarWndClass, &wc)) { // We need to register the outlook bar class wc.style = 0; wc.lpfnWndProc = COutBar::OutBarWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hInst; wc.hCursor = LoadCursor(NULL, IDC_SIZEWE); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = s_szOutBarWndClass; wc.hIcon = NULL; wc.hIconSm = NULL; if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) return E_FAIL; // Also need to register the frame class wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpfnWndProc = COutBar::ExtFrameWndProc; wc.lpszClassName = s_szOutBarFrameClass; wc.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1); if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) return E_FAIL; } // Get the handle of the parent window if (FAILED(m_ptbSite->GetWindow(&m_hwndParent))) return E_FAIL; // Create the window m_hwnd = CreateWindowEx(0, s_szOutBarWndClass, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, m_hwndParent, NULL, g_hInst, (LPVOID) this); if (!m_hwnd) { AssertSz(0, _T("COutBar::ShowDW() - Failed to create window.")); return E_FAIL; } if (FAILED(_CreateToolbar())) return E_FAIL; } // Show or hide the window and resize the parent windows accordingly m_fShow = fShow; ResizeBorderDW(NULL, NULL, FALSE); ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE); // Do notifications if (SUCCEEDED(CreateNotify(&m_pOutBarNotify))) { if (SUCCEEDED(m_pOutBarNotify->Initialize(c_szOutBarNotifyName))) { m_pOutBarNotify->Register(m_hwnd, g_hwndInit, FALSE); } } // Drag Drop RegisterDragDrop(m_hwndTools, this); g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, 0, (IDatabaseNotify *)this); return S_OK; } // // FUNCTION: COutBar::CloseDW() // // PURPOSE: Destroys the bar and cleans up. // HRESULT COutBar::CloseDW(DWORD dwReserved) { // Save our settings _SaveSettings(); RevokeDragDrop(m_hwndTools); g_pStore->UnregisterNotify((IDatabaseNotify *) this); // Release if (m_pOutBarNotify != NULL) { if (m_hwnd != NULL) m_pOutBarNotify->Unregister(m_hwnd); m_pOutBarNotify->Release(); m_pOutBarNotify = NULL; } // Release our notification interface if (m_pStNotify != NULL) { if (m_hwnd != NULL) m_pStNotify->Unregister(m_hwnd); m_pStNotify->Release(); m_pStNotify = NULL; } // Clean up the toolbar and other child windows if (m_hwnd) { if (m_hwndTools) _EmptyToolbar(FALSE); DestroyWindow(m_hwnd); m_hwnd = NULL; } return S_OK; } // // FUNCTION: COutBar::ResizeBorderDW() // // PURPOSE: // // PARAMETERS: // LPCRECT prcBorder // IUnknown *punkToolbarSite // BOOL fReserved // // RETURN VALUE: // HRESULT // HRESULT COutBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved) { RECT rcRequest = { 0, 0, 0, 0 }; RECT rcFrame; if (!m_ptbSite) { AssertSz(0, _T("COutBar::ResizeBorderDW() - Can't resize without calling SetSite() first.")); return E_FAIL; } if (m_fShow) { RECT rcBorder; if (!prcBorder) { // Find out how big our parent's border space is m_ptbSite->GetBorderDW((IDockingWindow*) this, &rcBorder); prcBorder = &rcBorder; } // Figure out how much border space to ask the site for GetWindowRect(m_hwndFrame, &rcFrame); rcFrame.right = min(m_cxWidth - GetSystemMetrics(SM_CXFRAME) + 1, prcBorder->right - prcBorder->left); rcRequest.left = min(m_cxWidth, prcBorder->right - prcBorder->left - 32); // Set our new window position SetWindowPos(m_hwndFrame, NULL, 0, 0, rcFrame.right, prcBorder->bottom - prcBorder->top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); SetWindowPos(m_hwnd, NULL, prcBorder->left, prcBorder->top, rcRequest.left, prcBorder->bottom - prcBorder->top, SWP_NOACTIVATE | SWP_NOZORDER); } m_ptbSite->SetBorderSpaceDW((IDockingWindow*) this, &rcRequest); return S_OK; } // // FUNCTION: COutBar::SetSite() // // PURPOSE: Set's a site pointer for the class // HRESULT COutBar::SetSite(IUnknown* punkSite) { // If we already have a site pointer, release it now if (m_ptbSite) { m_ptbSite->Release(); m_ptbSite = NULL; } // If the caller provided a new site interface, get the IDockingWindowSite // and keep a pointer to it. if (punkSite) { if (FAILED(punkSite->QueryInterface(IID_IDockingWindowSite, (void **)&m_ptbSite))) return E_FAIL; } return S_OK; } HRESULT COutBar::GetSite(REFIID riid, LPVOID *ppvSite) { return E_NOTIMPL; } // // FUNCTION: COutBar::DragEnter() // // PURPOSE: This get's called when the user starts dragging an object // over our target area. // // PARAMETERS: // pDataObject - Pointer to the data object being dragged // grfKeyState - Pointer to the current key states // pt - Point in screen coordinates of the mouse // pdwEffect - Where we return whether this is a valid place for // pDataObject to be dropped and if so what type of // drop. // // RETURN VALUE: // S_OK - The function succeeded. // HRESULT STDMETHODCALLTYPE COutBar::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { FORMATETC fe; POINT ptTemp = {pt.x, pt.y}; // Initialize our state SafeRelease(m_pDataObject); // Hold on to this new object m_pDataObject = pDataObject; m_pDataObject->AddRef(); // The big question here is whether or not this data object is an OE folder // or is it something else. SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL); m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe)); if (!m_fDropShortcut) { SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL); m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe)); } if (m_fDropShortcut) { m_fDropShortcut = _IsTempNewsgroup(m_pDataObject); } DOUTL(32, "COutBar::DragEnter() - Data is %s shortcut", m_fDropShortcut ? "a" : "not a"); // Hang on to this little gem m_grfKeyState = grfKeyState; // Initialize some other stuff m_idCur = -1; Assert(m_pTargetCur == NULL); m_tbim.iButton = -1; m_tbim.dwFlags = 0; // Set the default return value here m_dwEffectCur = *pdwEffect = DROPEFFECT_NONE; // Update the highlight point _UpdateDragDropHilite(&ptTemp); return (S_OK); } int COutBar::_GetItemFromPoint(POINT pt) { int iPos; TBBUTTON tb; // Figure out which button this is over ScreenToClient(m_hwndTools, &pt); iPos = ToolBar_HitTest(m_hwndTools, &pt); // If this is over a button, convert that button position to a command if (iPos >= 0) { ToolBar_GetButton(m_hwndTools, iPos, &tb); return (tb.idCommand); } return (-1); } void COutBar::_UpdateDragDropHilite(LPPOINT ppt) { TBINSERTMARK tbim; int iPos; // If this is a shortcut we do one thing, if it's anything else we do another if (m_fDropShortcut) { if (m_fInsertMark) { tbim.iButton = -1; tbim.dwFlags = 0; ToolBar_SetInsertMark(m_hwndTools, &tbim); m_fInsertMark = FALSE; } if (ppt) { ScreenToClient(m_hwndTools, ppt); ToolBar_InsertMarkHitTest(m_hwndTools, ppt, &tbim); ToolBar_SetInsertMark(m_hwndTools, &tbim); m_fInsertMark = TRUE; } } else { // Remove any previous marks if (m_idDropHilite) { ToolBar_MarkButton(m_hwndTools, m_idDropHilite, FALSE); m_idDropHilite = 0; } // Hilite the new button if (ppt) { // First check to see if we're over a button or in between m_idDropHilite = _GetItemFromPoint(*ppt); ToolBar_MarkButton(m_hwndTools, m_idDropHilite, TRUE); #ifdef DEBUG FOLDERINFO rInfo; FOLDERID idFolder; idFolder = _FolderIdFromCmd(m_idDropHilite); if (SUCCEEDED(g_pStore->GetFolderInfo(idFolder, &rInfo))) { DOUTL(32, "COutBar::_UpdateDragDropHilite() - Hiliting %s", rInfo.pszName); g_pStore->FreeRecord(&rInfo); } #endif } } } FOLDERID COutBar::_FolderIdFromCmd(int idCmd) { TBBUTTON tbb; int iPos; iPos = (int) SendMessage(m_hwndTools, TB_COMMANDTOINDEX, idCmd, 0); ToolBar_GetButton(m_hwndTools, iPos, &tbb); return ((FOLDERID) tbb.dwData); } // // FUNCTION: COutBar::DragOver() // // PURPOSE: This is called as the user drags an object over our target. // If we allow this object to be dropped on us, then we will have // a pointer in m_pDataObject. // // PARAMETERS: // grfKeyState - Pointer to the current key states // pt - Point in screen coordinates of the mouse // pdwEffect - Where we return whether this is a valid place for // pDataObject to be dropped and if so what type of // drop. // // RETURN VALUE: // S_OK - The function succeeded. // HRESULT STDMETHODCALLTYPE COutBar::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { DWORD idCur; HRESULT hr = E_FAIL; // If we don't have a data object from DragEnter, bail if (NULL == m_pDataObject) return (S_OK); // If this is a shortcut we do one thing, if it's anything else we do another if (m_fDropShortcut) { TBINSERTMARK tbim; POINT ptTemp = {pt.x, pt.y}; ScreenToClient(m_hwndTools, &ptTemp); ToolBar_InsertMarkHitTest(m_hwndTools, &ptTemp, &tbim); if (tbim.iButton != m_tbim.iButton || tbim.dwFlags != m_tbim.dwFlags) { m_tbim = tbim; ptTemp.x = pt.x; ptTemp.y = pt.y; _UpdateDragDropHilite(&ptTemp); } if (DROPEFFECT_LINK & *pdwEffect) *pdwEffect = DROPEFFECT_LINK; else *pdwEffect = DROPEFFECT_MOVE; return (S_OK); } else { // Figure out which item we're over POINT ptTemp = {pt.x, pt.y}; if (-1 == (idCur = _GetItemFromPoint(ptTemp))) { DOUTL(32, "COutBar::DragOver() - _GetItemFromPoint() returns -1."); } DOUTL(32, "COutBar::DragOver() - m_idCur = %d, id = %d", m_idCur, idCur); // If we're over a new button, then get the drop target for that button if (m_idCur != idCur) { // Release any previous drop target, if any. SafeRelease(m_pTargetCur); // Update our current object marker m_idCur = idCur; // Assume error m_dwEffectCur = DROPEFFECT_NONE; // Update the UI _UpdateDragDropHilite(&ptTemp); // If we're over a button if (m_idCur != -1) { FOLDERID id = _FolderIdFromCmd(m_idCur); // Create the drop target object m_pTargetCur = new CDropTarget(); if (m_pTargetCur) { hr = m_pTargetCur->Initialize(m_hwnd, id); } // If we have an initialized drop target, call DragEnter() if (SUCCEEDED(hr) && m_pTargetCur) { hr = m_pTargetCur->DragEnter(m_pDataObject, grfKeyState, pt, pdwEffect); m_dwEffectCur = *pdwEffect; } } else { m_dwEffectCur = DROPEFFECT_NONE; } } else { // No target change, but did the key state change? if ((m_grfKeyState != grfKeyState) && m_pTargetCur) { m_dwEffectCur = *pdwEffect; hr = m_pTargetCur->DragOver(grfKeyState, pt, &m_dwEffectCur); } else { hr = S_OK; } } *pdwEffect = m_dwEffectCur; m_grfKeyState = grfKeyState; } return (hr); } // // FUNCTION: COutBar::DragLeave() // // PURPOSE: Allows us to release any stored data we have from a successful // DragEnter() // // RETURN VALUE: // S_OK - Everything is groovy // HRESULT STDMETHODCALLTYPE COutBar::DragLeave(void) { SafeRelease(m_pDataObject); SafeRelease(m_pTargetCur); _UpdateDragDropHilite(NULL); return (S_OK); } // // FUNCTION: COutBar::Drop() // // PURPOSE: The user has let go of the object over our target. If we // can accept this object we will already have the pDataObject // stored in m_pDataObject. If this is a copy or move, then // we go ahead and update the store. Otherwise, we bring up // a send note with the object attached. // // PARAMETERS: // pDataObject - Pointer to the data object being dragged // grfKeyState - Pointer to the current key states // pt - Point in screen coordinates of the mouse // pdwEffect - Where we return whether this is a valid place for // pDataObject to be dropped and if so what type of // drop. // // RETURN VALUE: // S_OK - Everything worked OK // HRESULT STDMETHODCALLTYPE COutBar::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { HRESULT hr = E_FAIL; Assert(m_pDataObject == pDataObject); if (m_fDropShortcut) { hr = _AddShortcut(pDataObject); } else { if (m_pTargetCur) { hr = m_pTargetCur->Drop(pDataObject, grfKeyState, pt, pdwEffect); } else { *pdwEffect = DROPEFFECT_NONE; hr = S_OK; } } _UpdateDragDropHilite(NULL); SafeRelease(m_pTargetCur); SafeRelease(m_pDataObject); return (hr); } HRESULT COutBar::_AddShortcut(IDataObject *pObject) { FORMATETC fe; STGMEDIUM stm; FOLDERID *pidFolder; HRESULT hr = E_UNEXPECTED; TBINSERTMARK tbim; if (!pObject) return (E_INVALIDARG); // Get the data from the data object SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL); if (SUCCEEDED(pObject->GetData(&fe, &stm))) { pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal); ToolBar_GetInsertMark(m_hwndTools, &tbim); _InsertButton(tbim.iButton + tbim.dwFlags, *pidFolder); _SaveSettings(); _EmptyToolbar(TRUE); _FillToolbar(); m_pOutBarNotify->Lock(m_hwnd); m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG); m_pOutBarNotify->Unlock(); GlobalUnlock(stm.hGlobal); ReleaseStgMedium(&stm); } else { SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL); if (SUCCEEDED(pObject->GetData(&fe, &stm))) { UINT *piPosOld = (UINT *) GlobalLock(stm.hGlobal); UINT iPosNew; ToolBar_GetInsertMark(m_hwndTools, &tbim); iPosNew = tbim.iButton; if (tbim.dwFlags & TBIMHT_AFTER) iPosNew++; TBBUTTON tbb; ToolBar_GetButton(m_hwndTools, *piPosOld, &tbb); SendMessage(m_hwndTools, TB_INSERTBUTTON, iPosNew, (LPARAM)&tbb); if (iPosNew < *piPosOld) (*piPosOld)++; SendMessage(m_hwndTools, TB_DELETEBUTTON, *piPosOld, 0); _SaveSettings(); _EmptyToolbar(TRUE); _FillToolbar(); m_pOutBarNotify->Lock(m_hwnd); m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG); m_pOutBarNotify->Unlock(); GlobalUnlock(stm.hGlobal); ReleaseStgMedium(&stm); } } return (hr); } HRESULT STDMETHODCALLTYPE COutBar::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { if (fEscapePressed) return (DRAGDROP_S_CANCEL); if (grfKeyState & MK_RBUTTON) return (DRAGDROP_S_CANCEL); if (!(grfKeyState & MK_LBUTTON)) return (DRAGDROP_S_DROP); return (S_OK); } HRESULT STDMETHODCALLTYPE COutBar::GiveFeedback(DWORD dwEffect) { return (DRAGDROP_S_USEDEFAULTCURSORS); } LRESULT CALLBACK COutBar::OutBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { COutBar *pThis; if (uMsg == WM_NCCREATE) { pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis); } else { pThis = (COutBar *) GetWindowLongPtr(hwnd, GWLP_USERDATA); } Assert(pThis); return pThis->WndProc(hwnd, uMsg, wParam, lParam); } LRESULT CALLBACK COutBar::ExtFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { COutBar *pThis; if (uMsg == WM_NCCREATE) { pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis); } else { pThis = (COutBar *)GetWindowLongPtr(hwnd, GWLP_USERDATA); } Assert(pThis); return pThis->FrameWndProc(hwnd, uMsg, wParam, lParam); } LRESULT COutBar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove); HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown); HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp); case WM_SYSCOLORCHANGE: case WM_WININICHANGE: case WM_FONTCHANGE: { SendMessage(m_hwndPager, msg, wParam, lParam); SendMessage(m_hwndTools, msg, wParam, lParam); ResizeBorderDW(NULL, NULL, FALSE); return (0); } case WM_RELOADSHORTCUTS: { _EmptyToolbar(TRUE); _FillToolbar(); return (0); } } return DefWindowProc(hwnd, msg, wParam, lParam); } LRESULT COutBar::FrameWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { HANDLE_MSG(hwnd, WM_NOTIFY, Frame_OnNotify); HANDLE_MSG(hwnd, WM_SIZE, Frame_OnSize); HANDLE_MSG(hwnd, WM_COMMAND, Frame_OnCommand); HANDLE_MSG(hwnd, WM_NCDESTROY, Frame_OnNCDestroy); } return DefWindowProc(hwnd, msg, wParam, lParam); } void COutBar::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { if (!m_fResizing) { SetCapture(hwnd); m_fResizing = TRUE; } } void COutBar::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) { POINT pt = { x, y }; RECT rcClient; if (m_fResizing) { if (pt.x > 32) { GetClientRect(m_hwndParent, &rcClient); m_cxWidth = min(pt.x, rcClient.right - 32); ResizeBorderDW(0, 0, FALSE); } } } void COutBar::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) { if (m_fResizing) { ReleaseCapture(); m_fResizing = FALSE; } } void COutBar::Frame_OnNCDestroy(HWND hwnd) { SetWindowLong(hwnd, GWLP_USERDATA, NULL); m_hwndFrame = m_hwndPager = m_hwndTools = NULL; } void COutBar::Frame_OnSize(HWND hwnd, UINT state, int cx, int cy) { // When we get resized, we resize our children and update the toolbar button width if (m_hwndPager) { SetWindowPos(m_hwndPager, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(cx, cx)); } } void COutBar::Frame_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { int iPos; TBBUTTONINFO tbbi; if (id < ID_FIRST) { tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) id, (LPARAM)&tbbi); if (iPos >= 0) m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0); } } LRESULT COutBar::Frame_OnNotify(HWND hwnd, int idFrom, NMHDR *pnmhdr) { if (pnmhdr->code <= PGN_FIRST && pnmhdr->code >= PGN_LAST) return SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) pnmhdr); switch (pnmhdr->code) { case NM_CUSTOMDRAW: { NMCUSTOMDRAW *pnmcd = (NMCUSTOMDRAW*) pnmhdr; if (pnmcd->dwDrawStage == CDDS_PREPAINT) return CDRF_NOTIFYITEMDRAW; if (pnmcd->dwDrawStage == CDDS_ITEMPREPAINT) { NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd; ptbcd->clrText = GetSysColor(COLOR_WINDOW); return CDRF_NEWFONT; } } break; case NM_RCLICK: { if (pnmhdr->hwndFrom == m_hwndTools) { DWORD dwPos = GetMessagePos(); _OnContextMenu(GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos)); return 1; } } case TBN_DRAGOUT: { NMTOOLBAR *pnmtb = (NMTOOLBAR *) pnmhdr; DWORD dwEffect = DROPEFFECT_NONE; UINT id = ToolBar_CommandToIndex(m_hwndTools, pnmtb->iItem); // Create a new data object CShortcutDataObject *pDataObj = new CShortcutDataObject(id); if (pDataObj) { DoDragDrop(pDataObj, (IDropSource *) this, DROPEFFECT_MOVE, &dwEffect); pDataObj->Release(); } return 0; } } return (FALSE); } HRESULT COutBar::_CreateToolbar() { HIMAGELIST himl, himlOld; LRESULT lButtonSize; RECT rc; int iButtonWidth = 70; TCHAR szName[CCHMAX_STRINGRES]; // Create the frame window m_hwndFrame = CreateWindowEx(WS_EX_CLIENTEDGE, s_szOutBarFrameClass, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 0, 0, m_hwnd, (HMENU) IDC_FRAME, g_hInst, this); if (!m_hwndFrame) return E_FAIL; // Create the pager m_hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | PGS_VERT | PGS_DRAGNDROP, 0, 0, 0, 0, m_hwndFrame, (HMENU) IDC_PAGER, g_hInst, NULL); if (!m_hwndPager) return E_FAIL; ZeroMemory(szName, ARRAYSIZE(szName)); LoadString(g_hLocRes, idsOutlookBar, szName, ARRAYSIZE(szName)); // Create the toolbar m_hwndTools = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, szName, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_VERT, 0, 0, 0, 0, m_hwndPager, (HMENU) IDC_TOOLBAR, g_hInst, NULL); if (!m_hwndTools) return E_FAIL; // This tells the toolbar what version we are SendMessage(m_hwndTools, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); _FillToolbar(); _SetButtonStyle(!m_fLarge); SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(0, m_cxWidth)); m_pStNotify->Register(m_hwnd, g_hwndInit, FALSE); SendMessage(m_hwndPager, PGM_SETCHILD, 0, (LPARAM)m_hwndTools); // Let's try this COLORSCHEME cs; cs.dwSize = sizeof(COLORSCHEME); cs.clrBtnHighlight = GetSysColor(COLOR_3DFACE); cs.clrBtnShadow = GetSysColor(COLOR_WINDOWFRAME); SendMessage(m_hwndTools, TB_SETCOLORSCHEME, 0, (LPARAM) &cs); return S_OK; } void COutBar::_FillToolbar() { if (FAILED(_LoadSettings())) _CreateDefaultButtons(); SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L); } void COutBar::_EmptyToolbar(BOOL fDelete) { if (fDelete) while (SendMessage(m_hwndTools, TB_DELETEBUTTON, 0, 0)) ; } BOOL COutBar::_FindButton(int *piBtn, LPITEMIDLIST pidl) { BOOL fFound = FALSE; #if 0 int iBtn, cBtn, iCmp; TBBUTTON tbb; Assert(pidl); cBtn = (int)SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0L); // skip the root, so start at index 1 for (iBtn = 1; iBtn < cBtn; iBtn++) { if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb)) { Assert(tbb.dwData); iCmp = ShortFromResult(m_pShellFolder->CompareIDs(0, pidl, (LPITEMIDLIST)(tbb.dwData))); if (iCmp <= 0) { fFound = (iCmp == 0); break; } } } *piBtn = iBtn; #endif return fFound; } BOOL COutBar::_InsertButton(int index, FOLDERINFO *pInfo) { TBBUTTON tbb; TCHAR szName[2 * MAX_PATH]; LPTSTR pszFree = NULL; BOOL fRet; tbb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP; tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_NOPREFIX; tbb.idCommand = m_idCommand++; tbb.dwData = (DWORD_PTR) pInfo->idFolder; tbb.iBitmap = GetFolderIcon(pInfo); tbb.iString = (INT_PTR) pInfo->pszName; if (pInfo->cUnread) { DWORD cchSize = ARRAYSIZE(szName);; if (lstrlen(pInfo->pszName) + 13 < ARRAYSIZE(szName)) tbb.iString = (INT_PTR)szName; else { cchSize = (lstrlen(pInfo->pszName) + 14); if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR))) return FALSE; tbb.iString = (INT_PTR)pszFree; } wnsprintf((LPTSTR)tbb.iString, cchSize, "%s (%d)", pInfo->pszName, CUnread(pInfo)); } // Check to see if we're inserting at the end if (index == -1) { index = ToolBar_ButtonCount(m_hwndTools); } // insert the root fRet = (BOOL)SendMessage(m_hwndTools, TB_INSERTBUTTON, index, (LPARAM)&tbb); SafeMemFree(pszFree); return fRet; } BOOL COutBar::_InsertButton(int iIndex, FOLDERID id) { FOLDERINFO rInfo = {0}; if (SUCCEEDED(g_pStore->GetFolderInfo(id, &rInfo))) { _InsertButton(iIndex, &rInfo); g_pStore->FreeRecord(&rInfo); } return (TRUE); } BOOL COutBar::_DeleteButton(int iBtn) { TBBUTTON tbb; if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb)) { if (SendMessage(m_hwndTools, TB_DELETEBUTTON, iBtn, 0L)) { _SaveSettings(); m_pOutBarNotify->Lock(m_hwnd); m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG); m_pOutBarNotify->Unlock(); return (TRUE); } } return FALSE; } BOOL COutBar::_UpdateButton(int iBtn, LPITEMIDLIST pidl) { #if 0 TBBUTTON tbb; TBBUTTONINFO tbbi; TCHAR szName[2 * MAX_PATH]; LPTSTR pszFree = NULL; BOOL fRet = FALSE; if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb)) { tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE | TBIF_LPARAM; tbbi.iImage = FIDL_ICONID(pidl); tbbi.lParam = (DWORD)pidl; if (FIDL_UNREAD(pidl)) { DWORD cchSize = ARRAYSIZE(szName); if (lstrlen(FIDL_NAME(pidl)) + 13 < ARRAYSIZE(szName)) tbbi.pszText = szName; else { cchSize = (lstrlen(FIDL_NAME(pidl)) + 14); if (!MemAlloc((LPVOID*)&pszFree, (cchSize * sizeof(TCHAR)))) return FALSE; tbbi.pszText = pszFree; } wnsprintf(tbbi.pszText, cchSize, "%s (%d)", FIDL_NAME(pidl), FIDL_UNREAD(pidl)); } else tbbi.pszText = FIDL_NAME(pidl); fRet = SendMessage(m_hwndTools, TB_SETBUTTONINFO, (WPARAM)tbb.idCommand, (LPARAM)&tbbi); if (tbb.dwData) PidlFree((LPITEMIDLIST)(tbb.dwData)); if (pszFree) MemFree(pszFree); } return fRet; #endif return 0; } #if 0 void COutBar::_OnFolderNotify(FOLDERNOTIFY *pnotify) { LPITEMIDLIST pidl; int iBtn; BOOL fRecalc = FALSE; Assert(pnotify != NULL); Assert(pnotify->pidlNew != NULL); switch (pnotify->msg) { case NEW_FOLDER: // only insert if it is a root level pidl if (0 == NEXTID(pnotify->pidlNew)->mkid.cb) { // check for dups and figure out where to insert if (!FindButton(&iBtn, pnotify->pidlNew)) { if (pidl = PidlDupIdList(pnotify->pidlNew)) fRecalc = InsertButton(iBtn, pidl); } } break ; case DELETE_FOLDER: // only look for it if it is a root level pidl if (0 == NEXTID(pnotify->pidlNew)->mkid.cb) { if (FindButton(&iBtn, pnotify->pidlNew)) fRecalc = DeleteButton(iBtn); } break ; case RENAME_FOLDER: case MOVE_FOLDER: // only look for it if it is a root level pidl if (0 == NEXTID(pnotify->pidlOld)->mkid.cb) { if (FindButton(&iBtn, pnotify->pidlOld)) fRecalc = DeleteButton(iBtn); } // only insert if it is a root level pidl if (0 == NEXTID(pnotify->pidlNew)->mkid.cb) { // check for dups and figure out where to insert if (!FindButton(&iBtn, pnotify->pidlNew)) { if (pidl = PidlDupIdList(pnotify->pidlNew)) fRecalc = InsertButton(iBtn, pidl); } } break ; case UNREAD_CHANGE: case UPDATEFLAG_CHANGE: // only look for it if it is a root level pidl if (0 == NEXTID(pnotify->pidlNew)->mkid.cb) { // check for dups and figure out where to insert if (FindButton(&iBtn, pnotify->pidlNew)) { if (pidl = PidlDupIdList(pnotify->pidlNew)) UpdateButton(iBtn, pidl); } } break ; case IMAPFLAG_CHANGE: // don't care break ; case FOLDER_PROPS_CHANGED: //Don't care break ; default: AssertSz(FALSE, "Unhandled CFolderCache notification!"); break; } if (fRecalc) SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L); } #endif // // FUNCTION: COutBar::_OnContextMenu // // PURPOSE: If the WM_CONTEXTMENU message is generated from the keyboard // then figure out a pos to invoke the menu. Then dispatch the // request to the handler. // // PARAMETERS: // hwnd - Handle of the view window. // hwndClick - Handle of the window the user clicked in. // x, y - Position of the mouse click in screen coordinates. // void COutBar::_OnContextMenu(int x, int y) { HRESULT hr; HMENU hMenu; int id = 0; int i; POINT pt = { x, y }; TBBUTTON tbb; // Figure out where the click was ScreenToClient(m_hwndTools, &pt); i = ToolBar_HitTest(m_hwndTools, &pt); // If the click was on a button, then bring up the item context menu if (i >= 0) { // Get the button info SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb); // Load the context menu hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_ITEM_POPUP); if (!hMenu) return; // Mark the button SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP | TBSTATE_MARKED)); m_idSel = tbb.idCommand; // If this is the deleted items folder, add the "empty" menu item TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; if (-1 != SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi)) { FOLDERINFO rInfo; if (SUCCEEDED(g_pStore->GetFolderInfo((FOLDERID) tbbi.lParam, &rInfo))) { if (rInfo.tySpecial != FOLDER_DELETED) { DeleteMenu(hMenu, ID_EMPTY_WASTEBASKET, MF_BYCOMMAND); } g_pStore->FreeRecord(&rInfo); } } // Do the enable-disable thing MenuUtil_EnablePopupMenu(hMenu, this); // Display the context menu id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, m_hwnd, NULL); // Unmark the button SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP)); // See if the user chose a menu item if (id != 0) { Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL); } m_idSel = -1; // Clean this up DestroyMenu(hMenu); } // Else if the click was in the empty space, show the bar context menu else { // Load the context menu hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_POPUP); if (!hMenu) return; // Do the enable-disable thing MenuUtil_EnablePopupMenu(hMenu, this); // Display the context menu id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, m_hwnd, NULL); // See if the user chose a menu item if (id != 0) { Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL); } // Clean this up DestroyMenu(hMenu); } } HRESULT COutBar::_CreateDefaultButtons() { IEnumerateFolders *pEnum = NULL; FOLDERINFO rFolder; UINT iIndex = 0; FOLDERID idFolderDefault; // Figure out the default server first if (FAILED(GetDefaultServerId(ACCT_MAIL, &idFolderDefault))) idFolderDefault = FOLDERID_LOCAL_STORE; if (!(g_dwAthenaMode & MODE_NEWSONLY)) { // Inbox first if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_INBOX, &rFolder))) { _InsertButton(iIndex++, &rFolder); g_pStore->FreeRecord(&rFolder); } } // Outbox if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_OUTBOX, &rFolder))) { _InsertButton(iIndex++, &rFolder); g_pStore->FreeRecord(&rFolder); } // Sent Items if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_SENT, &rFolder))) { _InsertButton(iIndex++, &rFolder); g_pStore->FreeRecord(&rFolder); } // Deleted if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_DELETED, &rFolder))) { _InsertButton(iIndex++, &rFolder); g_pStore->FreeRecord(&rFolder); } // Drafts if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_DRAFT, &rFolder))) { _InsertButton(iIndex++, &rFolder); g_pStore->FreeRecord(&rFolder); } // Save at this point so everyone will be in sync _SaveSettings(); return (S_OK); } HRESULT COutBar::_LoadSettings(void) { BAR_PERSIST_INFO *pPersist = NULL; HRESULT hr = E_FAIL; DWORD iIndex = 0; FOLDERINFO rInfo; UINT i; // Load the settings if (FAILED(hr = OutlookBar_LoadSettings(&pPersist))) goto exit; // Load the bar from the saved folder ID's for (i = 0; i < pPersist->cItems; i++) { // Get the folder info for this folder if (SUCCEEDED(g_pStore->GetFolderInfo(pPersist->rgFolders[i], &rInfo))) { if (_InsertButton(iIndex, &rInfo)) iIndex++; g_pStore->FreeRecord(&rInfo); } } // If the bar is empty, and the user didn't save it empty, use the defaults if (iIndex == 0 && pPersist->cItems) hr = E_FAIL; else hr = S_OK; // Also restore the width while we're at it if (pPersist->cxWidth >= 28) { m_cxWidth = pPersist->cxWidth; } if (m_fOnce) { m_fLarge = !pPersist->fSmall; m_fOnce = FALSE; } exit: SafeMemFree(pPersist); return (hr); } HRESULT COutBar::_SaveSettings(void) { BAR_PERSIST_INFO *pPersist = NULL; DWORD cbData; DWORD iIndex = 0; FOLDERINFO rInfo; UINT i; DWORD cButtons; TBBUTTON tbb; RECT rcClient; // Get the count of buttons from the outlook bar cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0); // Allocate a persist info struct big enough for everything cbData = sizeof(BAR_PERSIST_INFO) + ((cButtons - 1) * sizeof(FOLDERID)); if (!MemAlloc((LPVOID *) &pPersist, cbData)) return (E_OUTOFMEMORY); // Fill in the persist info pPersist->dwVersion = GetOutlookBarVersion(); pPersist->cItems = cButtons; pPersist->fSmall = !m_fLarge; pPersist->ftSaved.dwHighDateTime = 0; pPersist->ftSaved.dwLowDateTime = 0; GetClientRect(m_hwnd, &rcClient); pPersist->cxWidth = rcClient.right; // Loop through the buttons on the toolbar and get the info from each for (i = 0; i < cButtons; i++) { SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb); pPersist->rgFolders[i] = (FOLDERID) tbb.dwData; } // Now open the registry and save the blob AthUserSetValue(NULL, GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData); // Free up the struct SafeMemFree(pPersist); return (S_OK); } HRESULT COutBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) { BOOL fSpecial = FALSE; BOOL fServer = FALSE; BOOL fRoot = FALSE; BOOL fNews = FALSE; BOOL fIMAP = FALSE; FOLDERINFO rFolder = {0}; FOLDERID idFolder = FOLDERID_INVALID; if (m_idSel != -1) { // Get the ID of the folder that is selected TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; if (-1 == SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi)) return (E_UNEXPECTED); // Get the Folder Info idFolder = (FOLDERID) tbbi.lParam; if (FAILED(g_pStore->GetFolderInfo(idFolder, &rFolder))) return (E_UNEXPECTED); // Break some of this down for readability fSpecial = rFolder.tySpecial != FOLDER_NOTSPECIAL; fServer = rFolder.dwFlags & FOLDER_SERVER; fRoot = FOLDERID_ROOT == idFolder; fNews = rFolder.tyFolder == FOLDER_NEWS; fIMAP = rFolder.tyFolder == FOLDER_IMAP; } // Loop through the commands in the prgCmds array looking for ones that haven't been handled for (UINT i = 0; i < cCmds; i++) { if (prgCmds[i].cmdf == 0) { switch (prgCmds[i].cmdID) { case ID_OPEN_FOLDER: case ID_REMOVE_SHORTCUT: case ID_NEW_SHORTCUT: case ID_HIDE: case ID_FIND_MESSAGE: prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; break; case ID_LARGE_ICONS: prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; if (m_fLarge) prgCmds[i].cmdf |= OLECMDF_NINCHED; break; case ID_SMALL_ICONS: prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; if (!m_fLarge) prgCmds[i].cmdf |= OLECMDF_NINCHED; break; case ID_RENAME_SHORTCUT: prgCmds[i].cmdf = OLECMDF_SUPPORTED; break; case ID_PROPERTIES: { Assert(idFolder != FOLDERID_INVALID); prgCmds[i].cmdf |= OLECMDF_SUPPORTED; // Everything except the root and the personal folders node if (!fRoot && ((fServer && (fNews || fIMAP)) || !fServer)) prgCmds[i].cmdf |= OLECMDF_SUPPORTED | OLECMDF_ENABLED; break; } case ID_EMPTY_WASTEBASKET: { if (rFolder.cMessages > 0 || FHasChildren(&rFolder, SUBSCRIBED)) prgCmds[i].cmdf = OLECMDF_ENABLED | OLECMDF_SUPPORTED; break; } } } } g_pStore->FreeRecord(&rFolder); return (S_OK); } HRESULT COutBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { TBBUTTONINFO tbbi = { 0 }; FOLDERID id = FOLDERID_INVALID; int iPos = -1; // Get the ID of the folder that was selected tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; tbbi.lParam = 0; if (-1 != (iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, m_idSel, (LPARAM) &tbbi))) { id = (FOLDERID) tbbi.lParam; } switch (nCmdID) { case ID_OPEN_FOLDER: { if (id != FOLDERID_INVALID) m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0); return (S_OK); } case ID_REMOVE_SHORTCUT: { _DeleteButton(iPos); return (S_OK); } case ID_RENAME_SHORTCUT: break; case ID_PROPERTIES: { if (id != FOLDERID_INVALID) MenuUtil_OnProperties(m_hwndParent, id); return (S_OK); } case ID_LARGE_ICONS: case ID_SMALL_ICONS: { _SetButtonStyle(nCmdID == ID_SMALL_ICONS); return (S_OK); } case ID_NEW_SHORTCUT: { FOLDERID idFolderDest; HRESULT hr; hr = SelectFolderDialog(m_hwnd, SFD_SELECTFOLDER, FOLDERID_ROOT, FD_NONEWFOLDERS, (LPCTSTR) idsNewShortcutTitle, (LPCTSTR) idsNewShortcutCaption, &idFolderDest); if (SUCCEEDED(hr)) { OutlookBar_AddShortcut(idFolderDest); } return (S_OK); } case ID_HIDE: { if (m_pBrowser) { m_pBrowser->SetViewLayout(DISPID_MSGVIEW_OUTLOOK_BAR, LAYOUT_POS_NA, FALSE, 0, 0); } return (S_OK); } case ID_EMPTY_WASTEBASKET: { if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsWarnEmptyDeletedItems), NULL, MB_YESNO | MB_DEFBUTTON2) == IDYES) { EmptyFolder(m_hwnd, id); } return (S_OK); } case ID_FIND_MESSAGE: { DoFindMsg(id, 0); return (S_OK); } } return (OLECMDERR_E_NOTSUPPORTED); } BOOL COutBar::_SetButtonStyle(BOOL fSmall) { LONG lStyle; SIZE s1, s2; // Get the current style lStyle = (LONG) SendMessage(m_hwndTools, TB_GETSTYLE, 0, 0); // Make sure we have the right image list loaded if (fSmall && !m_himlSmall) { // Load the image list for the toolbar m_himlSmall = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0, RGB(255, 0, 255)); if (!m_himlSmall) return FALSE; } if (!fSmall && !m_himlLarge) { // Load the image list for the toolbar m_himlLarge = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFoldersLarge), 32, 0, RGB(255, 0, 255)); if (!m_himlLarge) return FALSE; } // Get the size RECT rc; GetClientRect(m_hwndTools, &rc); NMPGCALCSIZE nm; nm.hdr.code = PGN_CALCSIZE; nm.dwFlag = PGF_CALCHEIGHT; nm.iWidth = 0; nm.iHeight = 0; SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) &nm); // Now swap styles if (fSmall) { lStyle |= TBSTYLE_LIST; SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle); SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16)); SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlSmall); SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 1, 0L); SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right)); } else { lStyle &= ~TBSTYLE_LIST; SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle); SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlLarge); SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(32, 32)); SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 2, 0L); SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right)); } PostMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L); InvalidateRect(m_hwndTools, NULL, TRUE); m_fLarge = !fSmall; return (TRUE); } HRESULT OutlookBar_AddShortcut(FOLDERID idFolder) { HRESULT hr; BAR_PERSIST_INFO *pPersist = NULL; DWORD cbData = 0; INotify *pNotify = NULL; // Load the current settings out of the registry. If it fails, that means // we've never saved our settings before. if (SUCCEEDED(hr = OutlookBar_LoadSettings(&pPersist))) { // Get the size of the current struct and add room for a new folder cbData = sizeof(BAR_PERSIST_INFO) + (pPersist->cItems * sizeof(FOLDERID)); // Realloc the structure if (MemRealloc((LPVOID *) &pPersist, cbData)) { // Add our new button to the end pPersist->rgFolders[pPersist->cItems] = idFolder; pPersist->cItems++; // Save the new settings out if (SUCCEEDED(OutlookBar_SaveSettings(pPersist, cbData))) { // Send notifications if (SUCCEEDED(CreateNotify(&pNotify))) { if (SUCCEEDED(pNotify->Initialize(c_szOutBarNotifyName))) { pNotify->Lock(NULL); pNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG); pNotify->Unlock(); } pNotify->Release(); } } } SafeMemFree(pPersist); } return (hr); } HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist) { HKEY hKey = 0; LONG lResult; DWORD dwType; BAR_PERSIST_INFO *pPersist = NULL; DWORD cbData; HRESULT hr = E_FAIL; if (!ppPersist) return (E_INVALIDARG); // Get the reg key for this user if (ERROR_SUCCESS != AthUserOpenKey(NULL, KEY_READ, &hKey)) return (hr); // Get the size of the blob in the registry lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, NULL, &cbData); if (ERROR_SUCCESS != lResult) goto exit; // Allocate a buffer for the blob in the registry if (!MemAlloc((LPVOID *) &pPersist, cbData + 1)) { hr = E_OUTOFMEMORY; goto exit; } // Now get the data from the registry lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, (LPBYTE) pPersist, &cbData); if (ERROR_SUCCESS != lResult) goto exit; // Check to see if this version matches our version if (pPersist->dwVersion != COutBar::GetOutlookBarVersion()) goto exit; // Check to see if the saved time is valid // $REVIEW - How? // Double check that the size is correct if (cbData != (sizeof(BAR_PERSIST_INFO) + ((pPersist->cItems - 1) * sizeof(FOLDERID)))) goto exit; hr = S_OK; exit: if (hKey) RegCloseKey(hKey); if (FAILED(hr)) SafeMemFree(pPersist); *ppPersist = pPersist; return (hr); } HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData) { // Open the registry and save the blob AthUserSetValue(NULL, COutBar::GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData); return (S_OK); } HRESULT COutBar::OnTransaction(HTRANSACTION hTransaction, DWORD_PTR dwCookie, IDatabase *pDB) { TRANSACTIONTYPE tyTransaction; ORDINALLIST Ordinals; FOLDERINFO Folder1={0}; FOLDERINFO Folder2={0}; DWORD cButtons; TBBUTTON tbb; TCHAR szName[2 * MAX_PATH]; LPTSTR pszFree = NULL; BOOL fChanged; INDEXORDINAL iIndex; TBBUTTONINFO tbbi; int iButton; if (!IsWindow(m_hwnd)) return (S_OK); // Get the number of buttons on our bar cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0); // Walk through the notifications while (hTransaction) { // Get Transact if (FAILED(pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals))) break; // Delete if (TRANSACTION_DELETE == tyTransaction) { for (iButton = cButtons - 1; iButton >= 0; iButton--) { // Get the button information ToolBar_GetButton(m_hwndTools, iButton, &tbb); // If the ID of this button matches the ID that changed if ((FOLDERID) tbb.dwData == Folder1.idFolder) { // Blow it away SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0); } } } // Update else if (TRANSACTION_UPDATE == tyTransaction) { // Loop through all our buttons since we might have dupes for (iButton = cButtons - 1; iButton >= 0; iButton--) { fChanged = FALSE; // Get the button information ToolBar_GetButton(m_hwndTools, iButton, &tbb); // If the ID of this button matches the ID that changed if ((FOLDERID) tbb.dwData == Folder1.idFolder) { tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE; tbbi.pszText = szName; tbbi.cchText = ARRAYSIZE(szName); ToolBar_GetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi); // Unread Change || Folder Renamed if (Folder1.cUnread != Folder2.cUnread || lstrcmp(Folder1.pszName, Folder2.pszName) != 0) { if (Folder2.cUnread) { DWORD cchSize = ARRAYSIZE(szName); if (lstrlen(Folder2.pszName) + 13 < ARRAYSIZE(szName)) tbbi.pszText = szName; else { cchSize = (lstrlen(Folder2.pszName) + 14); if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR))) return FALSE; tbbi.pszText = pszFree; } wnsprintf(tbbi.pszText, cchSize, "%s (%d)", Folder2.pszName, CUnread(&Folder2)); } else { tbbi.pszText = Folder2.pszName; } fChanged = TRUE; } // synchronize state changed ? if ((0 == (Folder1.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL))) ^ (0 == (Folder2.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)))) { tbbi.iImage = GetFolderIcon(&Folder2); fChanged = TRUE; } if (ISFLAGSET(Folder1.dwFlags, FOLDER_SUBSCRIBED) != ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED)) { if (ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED)) { tbbi.iImage = GetFolderIcon(&Folder2); fChanged = TRUE; } else { SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0); fChanged = FALSE; } } } if (fChanged) { ToolBar_SetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi); } SafeMemFree(pszFree); } } } pDB->FreeRecord(&Folder1); pDB->FreeRecord(&Folder2); return (S_OK); } BOOL COutBar::_IsTempNewsgroup(IDataObject *pObject) { FORMATETC fe; STGMEDIUM stm; FOLDERID *pidFolder; FOLDERINFO rInfo; BOOL fReturn = TRUE; SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL); if (SUCCEEDED(pObject->GetData(&fe, &stm))) { pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal); if (SUCCEEDED(g_pStore->GetFolderInfo(*pidFolder, &rInfo))) { if ((rInfo.tySpecial == FOLDER_NOTSPECIAL) && (rInfo.tyFolder == FOLDER_NEWS) && (0 == (rInfo.dwFlags & FOLDER_SUBSCRIBED))) { fReturn = FALSE; } g_pStore->FreeRecord(&rInfo); } GlobalUnlock(stm.hGlobal); ReleaseStgMedium(&stm); } return (fReturn); } LPCTSTR COutBar::GetRegKey() { LPCTSTR retval; if (g_dwAthenaMode & MODE_NEWSONLY) { retval = c_szRegOutlookBarNewsOnly; } else { retval = c_szRegOutlookBar; } return retval; } DWORD COutBar::GetOutlookBarVersion() { DWORD retval; if (g_dwAthenaMode & MODE_NEWSONLY) { retval = OUTLOOK_BAR_NEWSONLY_VERSION; } else { retval = OUTLOOK_BAR_VERSION; } return retval; }