windows-nt/Source/XPSP1/NT/shell/explorer/desktop2/startpage.cpp
2020-09-26 16:20:57 +08:00

1214 lines
35 KiB
C++

// Start.cpp : DirectUI
//
#include "stdafx.h"
#ifdef FEATURE_STARTPAGE
#include <lmcons.h> // for UNLEN
#include <shlapip.h>
#include <DUserCtrl.h>
#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<PaneItem> _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<StartFrame>();
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<ByUsageDUI *>(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<ButtonClickEvent *>(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<StartFrame,HWNDElement>::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