// Start.cpp : DirectUI // #include "stdafx.h" #ifdef FEATURE_STARTPAGE #include // for UNLEN #include #include #include "pidlbutton.h" #include "ProgList.h" #include "hostutil.h" #include "..\rcids.h" using namespace DirectUI; // Using ALL controls UsingDUIClass(Element); UsingDUIClass(HWNDElement); UsingDUIClass(Button); UsingDUIClass(Edit); UsingDUIClass(Progress); UsingDUIClass(RefPointElement); UsingDUIClass(RepeatButton); UsingDUIClass(ScrollBar); UsingDUIClass(ScrollViewer); UsingDUIClass(Selector); UsingDUIClass(Thumb); UsingDUIClass(Viewer); EXTERN_C void Tray_OnStartMenuDismissed(); EXTERN_C void Tray_OnStartPageDismissed(); EXTERN_C void Tray_MenuInvoke(int idCmd); EXTERN_C void Tray_SetStartPaneActive(BOOL fActive); EXTERN_C void Tray_DoProperties(DWORD nStartPage); HBITMAP GetBitmapForIDList(IShellFolder *psf, LPCITEMIDLIST pidlLast, UINT cx, UINT cy) { HBITMAP hBitmap = NULL; IExtractImage *pei; HRESULT hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_PPV_ARG_NULL(IExtractImage, &pei)); if (SUCCEEDED(hr)) { DWORD dwPriority; DWORD dwFlags = IEIFLAG_SCREEN | IEIFLAG_OFFLINE; SIZEL rgSize = {cx, cy}; WCHAR szBufferW[MAX_PATH]; hr = pei->GetLocation(szBufferW, ARRAYSIZE(szBufferW), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags); if (S_OK == hr) { hr = pei->Extract(&hBitmap); } } return hBitmap; } HBITMAP GetBitmapForFile(LPCITEMIDLIST pidl, LPWSTR pszFile, UINT cx, UINT cy) { HBITMAP hbmp = NULL; if (pidl) { IShellFolder *psf; HRESULT hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf)); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlChild; hr = psf->ParseDisplayName(NULL, NULL, pszFile, NULL, &pidlChild, NULL); if (SUCCEEDED(hr)) { hbmp = GetBitmapForIDList(psf, pidlChild, cx, cy); ILFree(pidlChild); } psf->Release(); } } else { LPITEMIDLIST pidlFull = ILCreateFromPath(pszFile); if (pidlFull) { IShellFolder *psf; LPCITEMIDLIST pidlChild; HRESULT hr = SHBindToParent(pidlFull, IID_PPV_ARG(IShellFolder, &psf), &pidlChild); if (SUCCEEDED(hr)) { hbmp = GetBitmapForIDList(psf, pidlChild, cx, cy); psf->Release(); } ILFree(pidlFull); } } return hbmp; } //////////////////////////////////////////////////////// // StartFrame //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// // Frame declaration class StartFrame : public HWNDElement, public ByUsageDUI { public: static HRESULT Create(OUT Element** ppElement); static HRESULT Create(HWND hwnd, HINSTANCE hInst, OUT Element** ppElement); virtual void OnInput(InputEvent* pie); virtual void OnEvent(Event* pEvent); virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); virtual void OnKeyFocusMoved(Element* peFrom, Element* peTo); HRESULT Populate(); static void CALLBACK ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine); static int CALLBACK _SortItemsAfterEnum(PaneItem *p1, PaneItem *p2, ByUsage *pbu); // ByUsageDUI virtual BOOL AddItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlChild); virtual BOOL RegisterNotify(UINT id, LONG lEvents, LPITEMIDLIST pidl, BOOL fRecursive); virtual BOOL UnregisterNotify(UINT id); virtual HRESULT Register(); enum {TIMER_RECENT, TIMER_PROGRAMS, TIMER_ANIMATE}; StartFrame(); protected: virtual ~StartFrame(); HRESULT Initialize(HWND hwnd) { return HWNDElement::Initialize(hwnd, true /* false */, 0); } IShellFolder *GetRecentFilesFolder(LPITEMIDLIST *ppidl); HRESULT InvokePidl(LPITEMIDLIST pidl); LRESULT _OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnSetMenuForward(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnChangeNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnSize(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _OnActivate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); private: BOOL _IsShortcutToFolder(IShellFolder *psf, LPCITEMIDLIST pidl); HRESULT _PopulateSpecialFolders(); HRESULT _PopulateRecentDocuments(); HRESULT _PopulateRecentPrograms(); HRESULT _PopulatePictures(); HRESULT _SetPicture(Element *pe); HINSTANCE _hInstance; LPITEMIDLIST _pidlBrowser; LPITEMIDLIST _pidlEmail; LPITEMIDLIST _pidlSearch; Element * _peAnimating; int _iAnimationColor; // // Context menu handling // PIDLButton * _pPidlButtonPop; /* has currently popped-up context menu */ // Handler for the recent programs list ByUsage * _pByUsage; // // _dpaEnum is the DPA of enumerated items, sorted in the // _SortItemsAfterEnum sense, which prepares them for _RepopulateList. // When _dpaEnum is destroyed, its pointers must be delete'd. // CDPA _dpaEnum; enum { DUI_MAXNOTIFY = 5 }; ULONG _rguChangeNotify[DUI_MAXNOTIFY]; enum { IDCN_LASTMOD = DUI_MAXNOTIFY -1 }; /* Outstanding change notification (if any) */ enum { SPM_CHANGENOTIFY = WM_USER + 2, // WM_USER+1 is already being used by the pidl gadgets, WM_USER is used by DirectUI SPM_SET_THUMBNAIL = SPM_CHANGENOTIFY + DUI_MAXNOTIFY }; enum { SPM_ACTIVATE = WM_USER + 107 }; // Bad HACK to get activation loss info static WCHAR _szParseError[]; static int _dParseError; int _iMaxShow; // How many items we should show in the recent lists public: // ClassInfo accessors (static and virtual instance-based) static IClassInfo* Class; virtual IClassInfo* GetClassInfo() { return Class; } }; //////////////////////////////////////////////////////// // Frame construction StartFrame::StartFrame() { _pidlBrowser = ILCreateFromPath(TEXT("shell:::{2559a1f4-21d7-11d4-bdaf-00c04f60b9f0}")); _pidlEmail = ILCreateFromPath(TEXT("shell:::{2559a1f5-21d7-11d4-bdaf-00c04f60b9f0}")); _pidlSearch = ILCreateFromPath(TEXT("shell:::{2559a1f0-21d7-11d4-bdaf-00c04f60b9f0}")); } StartFrame::~StartFrame() { ILFree(_pidlBrowser); ILFree(_pidlEmail); ILFree(_pidlSearch); } HRESULT StartFrame::Create(OUT Element** ppElement) { UNREFERENCED_PARAMETER(ppElement); DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution."); return E_NOTIMPL; } HRESULT StartFrame::Create(HWND hwnd, HINSTANCE hInst, OUT Element** ppElement) { *ppElement = NULL; StartFrame* ppf = HNew(); if (!ppf) return E_OUTOFMEMORY; HRESULT hr = ppf->Initialize(hwnd); if (FAILED(hr)) return hr; hr = ppf->SetActive(AE_MouseAndKeyboard); ppf->_hInstance = hInst; *ppElement = ppf; return S_OK; } HRESULT AddPidlToList(LPITEMIDLIST pidl, Element *peList, BOOL fInsert) { Element *pPidlButton; HRESULT hr = PIDLButton::Create(pidl, &pPidlButton); if (SUCCEEDED(hr)) { if (fInsert) hr = peList->Insert(pPidlButton, 0); else hr = peList->Add(pPidlButton); if (FAILED(hr)) { pPidlButton->Destroy(); } } else { ILFree(pidl); } return hr; } HRESULT InsertCSIDLIntoList(int csidl, Element *peList) { LPITEMIDLIST pidl; HRESULT hr = SHGetFolderLocation(NULL, csidl, NULL, 0, &pidl); if (SUCCEEDED(hr)) { hr = AddPidlToList(pidl, peList, TRUE); // Insert } return hr; } BOOL StartFrame::AddItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlChild) { BOOL fRet = TRUE; if (_dpaEnum.AppendPtr(pitem) < 0) { fRet = FALSE; delete pitem; } return fRet; } BOOL StartFrame::_IsShortcutToFolder(IShellFolder *psf, LPCITEMIDLIST pidl) { BOOL fRc = FALSE; // assume not IShellLink *psl; HRESULT hr; hr = psf->GetUIObjectOf(GetHWND(), 1, &pidl, IID_PPV_ARG_NULL(IShellLink, &psl)); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlTarget; if (SUCCEEDED(psl->GetIDList(&pidlTarget))) { DWORD dwAttr = SFGAO_FOLDER | SFGAO_BROWSABLE; if (SUCCEEDED(SHGetAttributesOf(pidlTarget, &dwAttr))) { fRc = dwAttr & SFGAO_FOLDER; } ILFree(pidlTarget); } psl->Release(); } return fRc; } IShellFolder *StartFrame::GetRecentFilesFolder(LPITEMIDLIST *ppidl) { HRESULT hr; IShellFolder *psf = NULL; hr = SHGetSpecialFolderLocation(GetHWND(), CSIDL_RECENT, ppidl); if (SUCCEEDED(hr)) { hr = SHBindToObjectEx(NULL, *ppidl, NULL, IID_PPV_ARG(IShellFolder, &psf)); if (FAILED(hr)) { ILFree(*ppidl); *ppidl = NULL; } } return psf; } HRESULT StartFrame::_PopulateSpecialFolders() { Element *peList; peList = FindDescendent(StrToID(L"DocList")); if (peList) { PIDLButton::SetImageSize(SHGFI_LARGEICON); InsertCSIDLIntoList(CSIDL_BITBUCKET, peList); InsertCSIDLIntoList(CSIDL_NETWORK, peList); InsertCSIDLIntoList(CSIDL_MYMUSIC, peList); InsertCSIDLIntoList(CSIDL_MYPICTURES, peList); InsertCSIDLIntoList(CSIDL_PERSONAL, peList); } peList = FindDescendent(StrToID(L"SystemDocList")); if (peList) { LPITEMIDLIST pidlHelp = ILCreateFromPath(TEXT("shell:::{2559a1f1-21d7-11d4-bdaf-00c04f60b9f0}")); // Help and support if (pidlHelp) AddPidlToList(pidlHelp, peList, TRUE); // Insert InsertCSIDLIntoList(CSIDL_CONTROLS, peList); InsertCSIDLIntoList(CSIDL_DRIVES, peList); } return S_OK; } HRESULT StartFrame::_PopulateRecentDocuments() { Selector *peList; peList = (Selector*)FindDescendent(StrToID(L"Documents")); if (peList) { PIDLButton::SetImageSize(SHGFI_LARGEICON); peList->DestroyAll(); IEnumIDList *peidl; LPITEMIDLIST pidlRoot; IShellFolder *psfRecentFiles = GetRecentFilesFolder(&pidlRoot); // The CSIDL_RECENT folder is magic: The items are enumerated // out of it in MRU order! if (psfRecentFiles) { if (SUCCEEDED(psfRecentFiles->EnumObjects(GetHWND(), SHCONTF_NONFOLDERS, &peidl))) { LPITEMIDLIST pidl; int cAdded = 0; while (cAdded < _iMaxShow && peidl->Next(1, &pidl, NULL) == S_OK) { // Filter out shortcuts to folders if (!_IsShortcutToFolder(psfRecentFiles, pidl)) { LPITEMIDLIST pidlFull = ILCombine(pidlRoot, pidl); if (pidlFull) { // AddPidlToList takes ownership of the pidl AddPidlToList(pidlFull, peList, FALSE); cAdded++; } } ILFree(pidl); } peidl->Release(); } RegisterNotify(IDCN_LASTMOD, SHCNE_DISKEVENTS | SHCNE_UPDATEIMAGE, pidlRoot, FALSE); ILFree(pidlRoot); psfRecentFiles->Release(); } } return S_OK; } int CALLBACK StartFrame::_SortItemsAfterEnum(PaneItem *p1, PaneItem *p2, ByUsage *pbu) { // // Put all pinned items (sorted by pin position) ahead of unpinned items. // if (p1->IsPinned()) { if (p2->IsPinned()) { return p1->GetPinPos() - p2->GetPinPos(); } return -1; } else if (p2->IsPinned()) { return +1; } // // Both unpinned - let the client decide. // return pbu->CompareItems(p1, p2); } HRESULT StartFrame::_PopulateRecentPrograms() { Element *peList; peList = FindDescendent(StrToID(L"Programs")); if (peList) { PIDLButton::SetImageSize(SHGFI_LARGEICON); peList->DestroyAll(); if (!_pByUsage) { _pByUsage = new ByUsage(NULL, static_cast(this)); if (_pByUsage) { IPropertyBag *pbag; if(SUCCEEDED(CreatePropBagFromReg(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage\\Normal\\W32Control1"), &pbag))) { if (SUCCEEDED(_pByUsage->Initialize()) && _dpaEnum.Create(4)) { } else { delete _pByUsage; _pByUsage = NULL; } pbag->Release(); } } } if (_pByUsage) { _pByUsage->EnumItems(); _dpaEnum.SortEx(_SortItemsAfterEnum, _pByUsage); int iPos; // the slot we are trying to fill int iEnum; // the item index we will fill it from PaneItem *pitem; // the item that will fill it // Note that the loop control must be a _dpaEnum.GetPtr(), not a // _dpaEnum.FastGetPtr(), because iEnum can go past the end of the // array if we do't have _iMaxShow items in the first place. // for (iPos = iEnum = 0; iEnum < _iMaxShow && (pitem = _dpaEnum.GetPtr(iEnum)) != NULL; iEnum++) { LPITEMIDLIST pidl = _pByUsage->GetFullPidl(pitem); if (pidl) { AddPidlToList(pidl, peList, FALSE); } } // Clear out the DPA _dpaEnum.EnumCallbackEx(PaneItem::DPAEnumCallback, (LPVOID)NULL); _dpaEnum.DeleteAllPtrs(); } } return S_OK; } LPWSTR GetStrPictureFromID(int nImageID) { LPWSTR pszPic = NULL; switch (nImageID) { case 1: pszPic = L"Picture1"; break; case 2: pszPic = L"Picture2"; break; case 3: pszPic = L"Picture3"; break; } return pszPic; } BOOL IsValidExtension(LPWSTR pszPath) { if (pszPath) { WCHAR *pszExt = PathFindExtension(pszPath); if (pszExt && (lstrcmpi(pszExt, TEXT(".bmp")) == 0 || lstrcmpi(pszExt, TEXT(".jpg")) == 0 || lstrcmpi(pszExt, TEXT(".jpeg")) == 0)) return TRUE; } return FALSE; } HRESULT StartFrame::_PopulatePictures() { LPITEMIDLIST pidl; HRESULT hr = SHGetFolderLocation(NULL, CSIDL_MYPICTURES, NULL, 0, &pidl); if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) { WCHAR szPath[MAX_PATH]; hr = SHGetPathFromIDList(pidl, szPath); if (SUCCEEDED(hr)) { WIN32_FIND_DATA fd; HKEY hkey = NULL; RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage"), &hkey); StrCatBuff(szPath, TEXT("\\*"), ARRAYSIZE(szPath)); int nImageID = 1; HANDLE hFind = FindFirstFile(szPath, &fd); while (nImageID <= 3) { LPWSTR pszPic = GetStrPictureFromID(nImageID); LPWSTR pszPathToImage = NULL; LPITEMIDLIST pidlFolder = NULL; if (hkey) { DWORD dwType; DWORD cb = sizeof(szPath); if (RegQueryValueEx(hkey, pszPic, NULL, &dwType, (LPBYTE)szPath, &cb) == ERROR_SUCCESS && dwType == REG_SZ && PathFileExists(szPath) && IsValidExtension(szPath)) pszPathToImage = szPath; } while (!pszPathToImage && hFind != INVALID_HANDLE_VALUE) { pidlFolder = pidl; pszPathToImage = fd.cFileName; if (!FindNextFile(hFind, &fd)) { FindClose(hFind); hFind = INVALID_HANDLE_VALUE; } // Skip the stupid sample if (lstrcmpi(pszPathToImage, TEXT("sample.jpg")) == 0 || !IsValidExtension(pszPathToImage)) pszPathToImage = NULL; } if (pszPathToImage) { HBITMAP hbmp = GetBitmapForFile(pidlFolder, pszPathToImage, 150, 113); if (hbmp) { Element *pe = FindDescendent(StrToID(pszPic)); if (pe) { Value *pvalIcon = Value::CreateGraphic(hbmp); if (pvalIcon) { pe->SetValue(ContentProp, PI_Local, pvalIcon); pvalIcon->Release(); } else { DeleteObject(hbmp); } } } } nImageID++; } if (hFind != INVALID_HANDLE_VALUE) FindClose(hFind); if (hkey) RegCloseKey(hkey); } } ILFree(pidl); } return hr; } HRESULT StartFrame::_SetPicture(Element *pe) { LPITEMIDLIST pidl; HRESULT hr = SHGetFolderLocation(NULL, CSIDL_MYPICTURES, NULL, 0, &pidl); if (SUCCEEDED(hr)) { WCHAR szPath[MAX_PATH]; hr = SHGetPathFromIDList(pidl, szPath); if (SUCCEEDED(hr)) { OPENFILENAME ofn; // common dialog box structure WCHAR szFile[MAX_PATH]; // buffer for file name *szFile = L'\0'; // Initialize OPENFILENAME ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetHWND(); ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = TEXT("Pictures\0*.JPG;*.JPEG;*.BMP\0"); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = szPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_DONTADDTORECENT; // Display the Open dialog box. if (GetOpenFileName(&ofn)==TRUE) { WCHAR *pszExt = PathFindExtension(ofn.lpstrFile); if (pszExt && (lstrcmpi(pszExt, TEXT(".bmp")) == 0 || lstrcmpi(pszExt, TEXT(".jpg")) == 0 || lstrcmpi(pszExt, TEXT(".jpg")) == 0)) { HBITMAP hbmp = GetBitmapForFile(NULL, ofn.lpstrFile, 150, 113); if (hbmp) { Value *pvalIcon = Value::CreateGraphic(hbmp); if (pvalIcon) { pe->SetValue(ContentProp, PI_Local, pvalIcon); pvalIcon->Release(); HKEY hkey = NULL; RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage"), &hkey); if (hkey) { LPWSTR pszPic; for (int i=1; i<=3; i++) { pszPic = GetStrPictureFromID(i); if (FindDescendent(StrToID(pszPic)) == pe) break; pszPic = NULL; } if (pszPic) RegSetValueEx(hkey, pszPic, NULL, REG_SZ, (LPBYTE)ofn.lpstrFile, (lstrlen(ofn.lpstrFile)+1) * sizeof(TCHAR)); RegCloseKey(hkey); } } else { DeleteObject(hbmp); } } } } } } return S_OK; } HRESULT StartFrame::Populate() { Element *pe = FindDescendent(StrToID(L"name")); if (pe) { WCHAR szUserName[UNLEN + 1]; ULONG uLen = ARRAYSIZE(szUserName); *szUserName = _T('\0'); SHGetUserDisplayName(szUserName, &uLen); pe->SetContentString(szUserName); } pe = FindDescendent(StrToID(L"UserPicture")); if (pe) { TCHAR szUserPicturePath[MAX_PATH]; if (SUCCEEDED(SHGetUserPicturePath(NULL, SHGUPP_FLAG_CREATE, szUserPicturePath))) { HBITMAP hbmUserPicture = (HBITMAP)LoadImage(NULL, szUserPicturePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if (hbmUserPicture) { Value *pvalIcon = Value::CreateGraphic(hbmUserPicture); if (pvalIcon) { pe->SetValue(ContentProp, PI_Local, pvalIcon); pvalIcon->Release(); } else { DeleteObject(hbmUserPicture); } } } } _PopulatePictures(); _PopulateSpecialFolders(); return S_OK; } void StartFrame::OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { if (id == IDCN_LASTMOD) // Change in last documents { UnregisterNotify(id); KillTimer(GetHWND(), TIMER_RECENT); SetTimer(GetHWND(), TIMER_RECENT, 2000, NULL); } else { ASSERT(_pByUsage); if(_pByUsage) { _pByUsage->GetMenuCache()->OnChangeNotify(id, lEvent, pidl1, pidl2); KillTimer(GetHWND(), TIMER_PROGRAMS); SetTimer(GetHWND(), TIMER_PROGRAMS, 10 * 1000, NULL); } } } LRESULT StartFrame::_OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (wParam == TIMER_RECENT) { KillTimer(hwnd, wParam); StartDefer(); _PopulateRecentDocuments(); EndDefer(); } else if (wParam == TIMER_PROGRAMS) { KillTimer(hwnd, wParam); StartDefer(); _PopulateRecentPrograms(); EndDefer(); SetTimer(GetHWND(), TIMER_PROGRAMS, 1 * 60 * 1000, NULL); // 1 minute } else if (wParam == TIMER_ANIMATE) { if (_iAnimationColor & 1) { _iAnimationColor += 16; if (_iAnimationColor == 255) KillTimer(hwnd, wParam); } else { if (_iAnimationColor > 16) _iAnimationColor -= 16; else _iAnimationColor = 15; } _peAnimating->SetForegroundColor(RGB(_iAnimationColor, _iAnimationColor, (3*_iAnimationColor + 255) /4)); } return 0; } BOOL StartFrame::RegisterNotify(UINT id, LONG lEvents, LPITEMIDLIST pidl, BOOL fRecursive) { ASSERT(id < DUI_MAXNOTIFY); if (id < DUI_MAXNOTIFY) { UnregisterNotify(id); SHChangeNotifyEntry fsne; fsne.fRecursive = fRecursive; fsne.pidl = pidl; int fSources = SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel; _rguChangeNotify[id] = SHChangeNotifyRegister(GetHWND(), fSources, lEvents, SPM_CHANGENOTIFY + id, 1, &fsne); return _rguChangeNotify[id]; } return FALSE; } BOOL StartFrame::UnregisterNotify(UINT id) { ASSERT(id < DUI_MAXNOTIFY); if (id < DUI_MAXNOTIFY && _rguChangeNotify[id]) { UINT uChangeNotify = _rguChangeNotify[id]; _rguChangeNotify[id] = 0; return SHChangeNotifyDeregister(uChangeNotify); } return FALSE; } //////////////////////////////////////////////////////// // System events void StartFrame::OnInput(InputEvent* pie) { HWNDElement::OnInput(pie); } void StartFrame::OnEvent(Event* pEvent) { if (pEvent->nStage == GMF_BUBBLED) { if (pEvent->uidType == Button::Click) { if (pEvent->peTarget->GetID() == StrToID(L"email")) { InvokePidl(_pidlEmail); } else if (pEvent->peTarget->GetID() == StrToID(L"internet")) { InvokePidl(_pidlBrowser); } else if (pEvent->peTarget->GetID() == StrToID(L"search")) { InvokePidl(_pidlSearch); } else if (pEvent->peTarget->GetID() == StrToID(L"MorePrograms")) { LPITEMIDLIST pidl = ILCreateFromPath(TEXT("shell:::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a}")); if (pidl) { InvokePidl(pidl); ILFree(pidl); } } else if (pEvent->peTarget->GetID() == StrToID(L"MoreDocuments")) { LPITEMIDLIST pidl = ILCreateFromPath(TEXT("shell:::{9387ae38-d19b-4de5-baf5-1f7767a1cf04}")); if (pidl) { InvokePidl(pidl); ILFree(pidl); } } else if (pEvent->peTarget->GetID() == StrToID(L"turnoff")) { Tray_MenuInvoke(IDM_EXITWIN); } else if (pEvent->peTarget->GetID() == StrToID(L"logoff")) { Tray_MenuInvoke(IDM_LOGOFF); } else { HMENU hmenu = LoadMenu(_hInstance, MAKEINTRESOURCE(IDM_PICTMENU)); if (hmenu) { HMENU hMenuTrack = GetSubMenu(hmenu, 0); ButtonClickEvent *peButton = reinterpret_cast(pEvent); if (peButton->pt.x == -1) // Keyboard context menu { Value *pv; const SIZE *psize = pEvent->peTarget->GetExtent(&pv); peButton->pt.x = psize->cx/2; peButton->pt.y = psize->cy/2; pv->Release(); } POINT pt; MapElementPoint(pEvent->peTarget, &peButton->pt, &pt); ClientToScreen(GetHWND(), &pt); int idCmd = TrackPopupMenuEx(hMenuTrack, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, pt.x, pt.y, GetHWND(), NULL); DestroyMenu(hmenu); if (idCmd == ID_CMD_CHANGE_PICTURE) { _SetPicture(pEvent->peTarget); } } } } } HWNDElement::OnEvent(pEvent); } HRESULT StartFrame::InvokePidl(LPITEMIDLIST pidl) { HRESULT hr = E_FAIL; IShellFolder *psf; LPCITEMIDLIST pidlShort; // Multi-level child pidl if (SUCCEEDED(SHBindToFolderIDListParent(NULL, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort))) { hr = SHInvokeDefaultCommand(GetHWND(), psf, pidlShort); psf->Release(); } return hr; } WCHAR StartFrame::_szParseError[201]; int StartFrame::_dParseError; void StartFrame::ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine) { if (dLine != -1) swprintf(_szParseError, L"%s '%s' at line %d", pszError, pszToken, dLine); else swprintf(_szParseError, L"%s '%s'", pszError, pszToken); _dParseError = dLine; } LRESULT StartFrame::_OnSetMenuForward(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _pPidlButtonPop = (PIDLButton *)lParam; return 0; } LRESULT StartFrame::_OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (_pPidlButtonPop) return _pPidlButtonPop->OnMenuMessage(hwnd, uMsg, wParam, lParam); return 0; } LRESULT StartFrame::_OnChangeNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPITEMIDLIST *ppidl; LONG lEvent; LPSHChangeNotificationLock pshcnl; pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent); if (pshcnl) { OnChangeNotify(uMsg - SPM_CHANGENOTIFY, lEvent, ppidl[0], ppidl[1]); SHChangeNotification_Unlock(pshcnl); } return 0; } LRESULT StartFrame::_OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { UINT id; for (id = 0; id < DUI_MAXNOTIFY; id++) { UnregisterNotify(id); } delete _pByUsage; _pByUsage = NULL; #if 0 // REVIEW fabriced if (_hwndList) { RevokeDragDrop(_hwndList); } if (_psched) { _psched->RemoveTasks(TOID_SFTBarHostBackgroundEnum, (DWORD_PTR)this, FALSE); } #endif return HWNDElement::WndProc(hwnd, uMsg, wParam, lParam); } LRESULT StartFrame::_OnActivate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (WA_ACTIVE == LOWORD(wParam)) { // Run a little animation when we come up _peAnimating = FindDescendent(StrToID(L"name")); _iAnimationColor = 64; SetTimer(GetHWND(), TIMER_ANIMATE, 20, NULL); } // If we are loosing focus, reset the start button. else if (WA_INACTIVE == LOWORD(wParam)) { if (_peAnimating) _peAnimating->SetForegroundColor(RGB(255, 255, 255)); KillTimer(GetHWND(), TIMER_ANIMATE); Tray_SetStartPaneActive(FALSE); Tray_OnStartPageDismissed(); } return 0; } LRESULT StartFrame::_OnSize(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { Element::StartDefer(); SetWidth(LOWORD(lParam)); SetHeight(HIWORD(lParam)); if (HIWORD(lParam) < 590) { _iMaxShow = 7; Element *pe = FindDescendent(StrToID(L"CurveZone")); if (pe) pe->SetPadding(0, 0, 0, 74); pe = FindDescendent(StrToID(L"LogoffZone")); if (pe) pe->SetPadding(50, 0, 50, 10); } else if (HIWORD(lParam) < 700) { _iMaxShow = 7; Element *pe = FindDescendent(StrToID(L"CurveZone")); if (pe) pe->SetPadding(0, 0, 0, 105); pe = FindDescendent(StrToID(L"LogoffZone")); if (pe) pe->SetPadding(50, 0, 50, 41); } else if (HIWORD(lParam) < 760) { _iMaxShow = 10; Element *pe = FindDescendent(StrToID(L"CurveZone")); if (pe) pe->SetPadding(0, 0, 0, 74); pe = FindDescendent(StrToID(L"LogoffZone")); if (pe) pe->SetPadding(50, 0, 50, 10); } else { _iMaxShow = 10; Element *pe = FindDescendent(StrToID(L"CurveZone")); if (pe) pe->SetPadding(0, 0, 0, 105); pe = FindDescendent(StrToID(L"LogoffZone")); if (pe) pe->SetPadding(50, 0, 50, 41); } _PopulateRecentDocuments(); _PopulateRecentPrograms(); Element::EndDefer(); return 0; } void StartFrame::OnKeyFocusMoved(Element* peFrom, Element* peTo) { } LRESULT StartFrame::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { #define HANDLE_SF_MESSAGE(wm, fn) case wm: return fn(hWnd, uMsg, wParam, lParam) if (SPM_CHANGENOTIFY <= uMsg && uMsg < SPM_CHANGENOTIFY + DUI_MAXNOTIFY) return _OnChangeNotify(hWnd, uMsg, wParam, lParam); switch (uMsg) { HANDLE_SF_MESSAGE(WM_DESTROY, _OnDestroy); HANDLE_SF_MESSAGE(WM_TIMER, _OnTimer); HANDLE_SF_MESSAGE(WM_SIZE, _OnSize); HANDLE_SF_MESSAGE(SPM_ACTIVATE, _OnActivate); // Context menus handlers HANDLE_SF_MESSAGE(WM_INITMENUPOPUP,_OnMenuMessage); HANDLE_SF_MESSAGE(WM_DRAWITEM, _OnMenuMessage); HANDLE_SF_MESSAGE(WM_MENUCHAR, _OnMenuMessage); HANDLE_SF_MESSAGE(WM_MEASUREITEM, _OnMenuMessage); HANDLE_SF_MESSAGE(PIDLButton::PBM_SETMENUFORWARD, _OnSetMenuForward); } return HWNDElement::WndProc(hWnd, uMsg, wParam, lParam); } //////////////////////////////////////////////////////// // ClassInfo (must appear after property definitions) // Define class info with type and base type, set static class pointer IClassInfo* StartFrame::Class = NULL; HRESULT StartFrame::Register() { return ClassInfo::Register(L"StartFrame", NULL, 0); } //////////////////////////////////////////////////////// // Parser //////////////////////////////////////////////////////// void CALLBACK ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine) { WCHAR buf[201]; if (dLine != -1) swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine); else swprintf(buf, L"%s '%s'", pszError, pszToken); MessageBoxW(NULL, buf, L"Parser Message", MB_OK); } // Privates from Shell32. STDAPI_(HWND) SetPeekMsgEx(FARPROC fp, HANDLE hDesktop); STDAPI_(BOOL) SetStartPageHWND(HANDLE hDesktop, HWND hwnd); typedef HWND (*SetPeek)(FARPROC fp, HANDLE hDesktop); ///////////////////////////////////// // Creation of the Start Page void CreateStartPage(HINSTANCE hInstance, HANDLE hDesktop) { HWND hwndParent = NULL; CoInitialize(NULL); // DirectUI init thread in caller InitThread(); hwndParent = SetPeekMsgEx((FARPROC)PeekMessageEx, hDesktop); Element::StartDefer(); // HWND Root StartFrame* psf; HRESULT hr = StartFrame::Create(hwndParent, hInstance, (Element**)&psf); if (FAILED(hr)) return; // Fill content of frame (using substitution) Parser* pParser; Parser::Create(IDR_STARTUI, hInstance, ParseError, &pParser); if (!pParser) return; if (pParser->WasParseError()) { ASSERTMSG(FALSE, "Parse error!"); pParser->Destroy(); return; } Element* pe; pParser->CreateElement(L"main", psf, &pe); // Done with parser pParser->Destroy(); // Disable Drag-drop for now. BuildDropTarget( psf->GetDisplayNode(), psf->GetHWND()); psf->Populate(); // Set visible and host psf->SetVisible(true); RECT rect; GetWindowRect(hwndParent, &rect); psf->SetWidth(RECTWIDTH(rect)); psf->SetHeight(RECTHEIGHT(rect)); Element::EndDefer(); SetStartPageHWND(hDesktop, psf->GetHWND()); SetTimer(psf->GetHWND(), StartFrame::TIMER_PROGRAMS, 1 * 60 * 1000, NULL); // 1 minute HWND hwndDesktop = GetParent(GetParent(hwndParent)); ShowWindow(hwndDesktop, SW_SHOW); UpdateWindow(hwndDesktop); return; } #endif // FEATURE_STARTPAGE