Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1213 lines
35 KiB

  1. // Start.cpp : DirectUI
  2. //
  3. #include "stdafx.h"
  4. #ifdef FEATURE_STARTPAGE
  5. #include <lmcons.h> // for UNLEN
  6. #include <shlapip.h>
  7. #include <DUserCtrl.h>
  8. #include "pidlbutton.h"
  9. #include "ProgList.h"
  10. #include "hostutil.h"
  11. #include "..\rcids.h"
  12. using namespace DirectUI;
  13. // Using ALL controls
  14. UsingDUIClass(Element);
  15. UsingDUIClass(HWNDElement);
  16. UsingDUIClass(Button);
  17. UsingDUIClass(Edit);
  18. UsingDUIClass(Progress);
  19. UsingDUIClass(RefPointElement);
  20. UsingDUIClass(RepeatButton);
  21. UsingDUIClass(ScrollBar);
  22. UsingDUIClass(ScrollViewer);
  23. UsingDUIClass(Selector);
  24. UsingDUIClass(Thumb);
  25. UsingDUIClass(Viewer);
  26. EXTERN_C void Tray_OnStartMenuDismissed();
  27. EXTERN_C void Tray_OnStartPageDismissed();
  28. EXTERN_C void Tray_MenuInvoke(int idCmd);
  29. EXTERN_C void Tray_SetStartPaneActive(BOOL fActive);
  30. EXTERN_C void Tray_DoProperties(DWORD nStartPage);
  31. HBITMAP GetBitmapForIDList(IShellFolder *psf, LPCITEMIDLIST pidlLast, UINT cx, UINT cy)
  32. {
  33. HBITMAP hBitmap = NULL;
  34. IExtractImage *pei;
  35. HRESULT hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_PPV_ARG_NULL(IExtractImage, &pei));
  36. if (SUCCEEDED(hr))
  37. {
  38. DWORD dwPriority;
  39. DWORD dwFlags = IEIFLAG_SCREEN | IEIFLAG_OFFLINE;
  40. SIZEL rgSize = {cx, cy};
  41. WCHAR szBufferW[MAX_PATH];
  42. hr = pei->GetLocation(szBufferW, ARRAYSIZE(szBufferW), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags);
  43. if (S_OK == hr)
  44. {
  45. hr = pei->Extract(&hBitmap);
  46. }
  47. }
  48. return hBitmap;
  49. }
  50. HBITMAP GetBitmapForFile(LPCITEMIDLIST pidl, LPWSTR pszFile, UINT cx, UINT cy)
  51. {
  52. HBITMAP hbmp = NULL;
  53. if (pidl)
  54. {
  55. IShellFolder *psf;
  56. HRESULT hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
  57. if (SUCCEEDED(hr))
  58. {
  59. LPITEMIDLIST pidlChild;
  60. hr = psf->ParseDisplayName(NULL, NULL, pszFile, NULL, &pidlChild, NULL);
  61. if (SUCCEEDED(hr))
  62. {
  63. hbmp = GetBitmapForIDList(psf, pidlChild, cx, cy);
  64. ILFree(pidlChild);
  65. }
  66. psf->Release();
  67. }
  68. }
  69. else
  70. {
  71. LPITEMIDLIST pidlFull = ILCreateFromPath(pszFile);
  72. if (pidlFull)
  73. {
  74. IShellFolder *psf;
  75. LPCITEMIDLIST pidlChild;
  76. HRESULT hr = SHBindToParent(pidlFull, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  77. if (SUCCEEDED(hr))
  78. {
  79. hbmp = GetBitmapForIDList(psf, pidlChild, cx, cy);
  80. psf->Release();
  81. }
  82. ILFree(pidlFull);
  83. }
  84. }
  85. return hbmp;
  86. }
  87. ////////////////////////////////////////////////////////
  88. // StartFrame
  89. ////////////////////////////////////////////////////////
  90. ////////////////////////////////////////////////////////
  91. // Frame declaration
  92. class StartFrame : public HWNDElement, public ByUsageDUI
  93. {
  94. public:
  95. static HRESULT Create(OUT Element** ppElement);
  96. static HRESULT Create(HWND hwnd, HINSTANCE hInst, OUT Element** ppElement);
  97. virtual void OnInput(InputEvent* pie);
  98. virtual void OnEvent(Event* pEvent);
  99. virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  100. virtual void OnKeyFocusMoved(Element* peFrom, Element* peTo);
  101. HRESULT Populate();
  102. static void CALLBACK ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine);
  103. static int CALLBACK _SortItemsAfterEnum(PaneItem *p1, PaneItem *p2, ByUsage *pbu);
  104. // ByUsageDUI
  105. virtual BOOL AddItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlChild);
  106. virtual BOOL RegisterNotify(UINT id, LONG lEvents, LPITEMIDLIST pidl, BOOL fRecursive);
  107. virtual BOOL UnregisterNotify(UINT id);
  108. virtual HRESULT Register();
  109. enum {TIMER_RECENT, TIMER_PROGRAMS, TIMER_ANIMATE};
  110. StartFrame();
  111. protected:
  112. virtual ~StartFrame();
  113. HRESULT Initialize(HWND hwnd) { return HWNDElement::Initialize(hwnd, true /* false */, 0); }
  114. IShellFolder *GetRecentFilesFolder(LPITEMIDLIST *ppidl);
  115. HRESULT InvokePidl(LPITEMIDLIST pidl);
  116. LRESULT _OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  117. LRESULT _OnSetMenuForward(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  118. LRESULT _OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  119. LRESULT _OnChangeNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  120. LRESULT _OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  121. LRESULT _OnSize(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  122. LRESULT _OnActivate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  123. void OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  124. private:
  125. BOOL _IsShortcutToFolder(IShellFolder *psf, LPCITEMIDLIST pidl);
  126. HRESULT _PopulateSpecialFolders();
  127. HRESULT _PopulateRecentDocuments();
  128. HRESULT _PopulateRecentPrograms();
  129. HRESULT _PopulatePictures();
  130. HRESULT _SetPicture(Element *pe);
  131. HINSTANCE _hInstance;
  132. LPITEMIDLIST _pidlBrowser;
  133. LPITEMIDLIST _pidlEmail;
  134. LPITEMIDLIST _pidlSearch;
  135. Element * _peAnimating;
  136. int _iAnimationColor;
  137. //
  138. // Context menu handling
  139. //
  140. PIDLButton * _pPidlButtonPop; /* has currently popped-up context menu */
  141. // Handler for the recent programs list
  142. ByUsage * _pByUsage;
  143. //
  144. // _dpaEnum is the DPA of enumerated items, sorted in the
  145. // _SortItemsAfterEnum sense, which prepares them for _RepopulateList.
  146. // When _dpaEnum is destroyed, its pointers must be delete'd.
  147. //
  148. CDPA<PaneItem> _dpaEnum;
  149. enum { DUI_MAXNOTIFY = 5 };
  150. ULONG _rguChangeNotify[DUI_MAXNOTIFY];
  151. enum { IDCN_LASTMOD = DUI_MAXNOTIFY -1 };
  152. /* Outstanding change notification (if any) */
  153. enum {
  154. SPM_CHANGENOTIFY = WM_USER + 2, // WM_USER+1 is already being used by the pidl gadgets, WM_USER is used by DirectUI
  155. SPM_SET_THUMBNAIL = SPM_CHANGENOTIFY + DUI_MAXNOTIFY
  156. };
  157. enum { SPM_ACTIVATE = WM_USER + 107 }; // Bad HACK to get activation loss info
  158. static WCHAR _szParseError[];
  159. static int _dParseError;
  160. int _iMaxShow; // How many items we should show in the recent lists
  161. public:
  162. // ClassInfo accessors (static and virtual instance-based)
  163. static IClassInfo* Class;
  164. virtual IClassInfo* GetClassInfo() { return Class; }
  165. };
  166. ////////////////////////////////////////////////////////
  167. // Frame construction
  168. StartFrame::StartFrame()
  169. {
  170. _pidlBrowser = ILCreateFromPath(TEXT("shell:::{2559a1f4-21d7-11d4-bdaf-00c04f60b9f0}"));
  171. _pidlEmail = ILCreateFromPath(TEXT("shell:::{2559a1f5-21d7-11d4-bdaf-00c04f60b9f0}"));
  172. _pidlSearch = ILCreateFromPath(TEXT("shell:::{2559a1f0-21d7-11d4-bdaf-00c04f60b9f0}"));
  173. }
  174. StartFrame::~StartFrame()
  175. {
  176. ILFree(_pidlBrowser);
  177. ILFree(_pidlEmail);
  178. ILFree(_pidlSearch);
  179. }
  180. HRESULT StartFrame::Create(OUT Element** ppElement)
  181. {
  182. UNREFERENCED_PARAMETER(ppElement);
  183. DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
  184. return E_NOTIMPL;
  185. }
  186. HRESULT StartFrame::Create(HWND hwnd, HINSTANCE hInst, OUT Element** ppElement)
  187. {
  188. *ppElement = NULL;
  189. StartFrame* ppf = HNew<StartFrame>();
  190. if (!ppf)
  191. return E_OUTOFMEMORY;
  192. HRESULT hr = ppf->Initialize(hwnd);
  193. if (FAILED(hr))
  194. return hr;
  195. hr = ppf->SetActive(AE_MouseAndKeyboard);
  196. ppf->_hInstance = hInst;
  197. *ppElement = ppf;
  198. return S_OK;
  199. }
  200. HRESULT AddPidlToList(LPITEMIDLIST pidl, Element *peList, BOOL fInsert)
  201. {
  202. Element *pPidlButton;
  203. HRESULT hr = PIDLButton::Create(pidl, &pPidlButton);
  204. if (SUCCEEDED(hr))
  205. {
  206. if (fInsert)
  207. hr = peList->Insert(pPidlButton, 0);
  208. else
  209. hr = peList->Add(pPidlButton);
  210. if (FAILED(hr))
  211. {
  212. pPidlButton->Destroy();
  213. }
  214. }
  215. else
  216. {
  217. ILFree(pidl);
  218. }
  219. return hr;
  220. }
  221. HRESULT InsertCSIDLIntoList(int csidl, Element *peList)
  222. {
  223. LPITEMIDLIST pidl;
  224. HRESULT hr = SHGetFolderLocation(NULL, csidl, NULL, 0, &pidl);
  225. if (SUCCEEDED(hr))
  226. {
  227. hr = AddPidlToList(pidl, peList, TRUE); // Insert
  228. }
  229. return hr;
  230. }
  231. BOOL StartFrame::AddItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlChild)
  232. {
  233. BOOL fRet = TRUE;
  234. if (_dpaEnum.AppendPtr(pitem) < 0)
  235. {
  236. fRet = FALSE;
  237. delete pitem;
  238. }
  239. return fRet;
  240. }
  241. BOOL StartFrame::_IsShortcutToFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  242. {
  243. BOOL fRc = FALSE; // assume not
  244. IShellLink *psl;
  245. HRESULT hr;
  246. hr = psf->GetUIObjectOf(GetHWND(), 1, &pidl, IID_PPV_ARG_NULL(IShellLink, &psl));
  247. if (SUCCEEDED(hr))
  248. {
  249. LPITEMIDLIST pidlTarget;
  250. if (SUCCEEDED(psl->GetIDList(&pidlTarget)))
  251. {
  252. DWORD dwAttr = SFGAO_FOLDER | SFGAO_BROWSABLE;
  253. if (SUCCEEDED(SHGetAttributesOf(pidlTarget, &dwAttr)))
  254. {
  255. fRc = dwAttr & SFGAO_FOLDER;
  256. }
  257. ILFree(pidlTarget);
  258. }
  259. psl->Release();
  260. }
  261. return fRc;
  262. }
  263. IShellFolder *StartFrame::GetRecentFilesFolder(LPITEMIDLIST *ppidl)
  264. {
  265. HRESULT hr;
  266. IShellFolder *psf = NULL;
  267. hr = SHGetSpecialFolderLocation(GetHWND(), CSIDL_RECENT, ppidl);
  268. if (SUCCEEDED(hr))
  269. {
  270. hr = SHBindToObjectEx(NULL, *ppidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
  271. if (FAILED(hr))
  272. {
  273. ILFree(*ppidl);
  274. *ppidl = NULL;
  275. }
  276. }
  277. return psf;
  278. }
  279. HRESULT StartFrame::_PopulateSpecialFolders()
  280. {
  281. Element *peList;
  282. peList = FindDescendent(StrToID(L"DocList"));
  283. if (peList)
  284. {
  285. PIDLButton::SetImageSize(SHGFI_LARGEICON);
  286. InsertCSIDLIntoList(CSIDL_BITBUCKET, peList);
  287. InsertCSIDLIntoList(CSIDL_NETWORK, peList);
  288. InsertCSIDLIntoList(CSIDL_MYMUSIC, peList);
  289. InsertCSIDLIntoList(CSIDL_MYPICTURES, peList);
  290. InsertCSIDLIntoList(CSIDL_PERSONAL, peList);
  291. }
  292. peList = FindDescendent(StrToID(L"SystemDocList"));
  293. if (peList)
  294. {
  295. LPITEMIDLIST pidlHelp = ILCreateFromPath(TEXT("shell:::{2559a1f1-21d7-11d4-bdaf-00c04f60b9f0}")); // Help and support
  296. if (pidlHelp)
  297. AddPidlToList(pidlHelp, peList, TRUE); // Insert
  298. InsertCSIDLIntoList(CSIDL_CONTROLS, peList);
  299. InsertCSIDLIntoList(CSIDL_DRIVES, peList);
  300. }
  301. return S_OK;
  302. }
  303. HRESULT StartFrame::_PopulateRecentDocuments()
  304. {
  305. Selector *peList;
  306. peList = (Selector*)FindDescendent(StrToID(L"Documents"));
  307. if (peList)
  308. {
  309. PIDLButton::SetImageSize(SHGFI_LARGEICON);
  310. peList->DestroyAll();
  311. IEnumIDList *peidl;
  312. LPITEMIDLIST pidlRoot;
  313. IShellFolder *psfRecentFiles = GetRecentFilesFolder(&pidlRoot);
  314. // The CSIDL_RECENT folder is magic: The items are enumerated
  315. // out of it in MRU order!
  316. if (psfRecentFiles)
  317. {
  318. if (SUCCEEDED(psfRecentFiles->EnumObjects(GetHWND(), SHCONTF_NONFOLDERS, &peidl)))
  319. {
  320. LPITEMIDLIST pidl;
  321. int cAdded = 0;
  322. while (cAdded < _iMaxShow && peidl->Next(1, &pidl, NULL) == S_OK)
  323. {
  324. // Filter out shortcuts to folders
  325. if (!_IsShortcutToFolder(psfRecentFiles, pidl))
  326. {
  327. LPITEMIDLIST pidlFull = ILCombine(pidlRoot, pidl);
  328. if (pidlFull)
  329. {
  330. // AddPidlToList takes ownership of the pidl
  331. AddPidlToList(pidlFull, peList, FALSE);
  332. cAdded++;
  333. }
  334. }
  335. ILFree(pidl);
  336. }
  337. peidl->Release();
  338. }
  339. RegisterNotify(IDCN_LASTMOD, SHCNE_DISKEVENTS | SHCNE_UPDATEIMAGE, pidlRoot, FALSE);
  340. ILFree(pidlRoot);
  341. psfRecentFiles->Release();
  342. }
  343. }
  344. return S_OK;
  345. }
  346. int CALLBACK StartFrame::_SortItemsAfterEnum(PaneItem *p1, PaneItem *p2, ByUsage *pbu)
  347. {
  348. //
  349. // Put all pinned items (sorted by pin position) ahead of unpinned items.
  350. //
  351. if (p1->IsPinned())
  352. {
  353. if (p2->IsPinned())
  354. {
  355. return p1->GetPinPos() - p2->GetPinPos();
  356. }
  357. return -1;
  358. }
  359. else if (p2->IsPinned())
  360. {
  361. return +1;
  362. }
  363. //
  364. // Both unpinned - let the client decide.
  365. //
  366. return pbu->CompareItems(p1, p2);
  367. }
  368. HRESULT StartFrame::_PopulateRecentPrograms()
  369. {
  370. Element *peList;
  371. peList = FindDescendent(StrToID(L"Programs"));
  372. if (peList)
  373. {
  374. PIDLButton::SetImageSize(SHGFI_LARGEICON);
  375. peList->DestroyAll();
  376. if (!_pByUsage)
  377. {
  378. _pByUsage = new ByUsage(NULL, static_cast<ByUsageDUI *>(this));
  379. if (_pByUsage)
  380. {
  381. IPropertyBag *pbag;
  382. if(SUCCEEDED(CreatePropBagFromReg(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage\\Normal\\W32Control1"), &pbag)))
  383. {
  384. if (SUCCEEDED(_pByUsage->Initialize()) && _dpaEnum.Create(4))
  385. {
  386. }
  387. else
  388. {
  389. delete _pByUsage;
  390. _pByUsage = NULL;
  391. }
  392. pbag->Release();
  393. }
  394. }
  395. }
  396. if (_pByUsage)
  397. {
  398. _pByUsage->EnumItems();
  399. _dpaEnum.SortEx(_SortItemsAfterEnum, _pByUsage);
  400. int iPos; // the slot we are trying to fill
  401. int iEnum; // the item index we will fill it from
  402. PaneItem *pitem; // the item that will fill it
  403. // Note that the loop control must be a _dpaEnum.GetPtr(), not a
  404. // _dpaEnum.FastGetPtr(), because iEnum can go past the end of the
  405. // array if we do't have _iMaxShow items in the first place.
  406. //
  407. for (iPos = iEnum = 0;
  408. iEnum < _iMaxShow && (pitem = _dpaEnum.GetPtr(iEnum)) != NULL;
  409. iEnum++)
  410. {
  411. LPITEMIDLIST pidl = _pByUsage->GetFullPidl(pitem);
  412. if (pidl)
  413. {
  414. AddPidlToList(pidl, peList, FALSE);
  415. }
  416. }
  417. // Clear out the DPA
  418. _dpaEnum.EnumCallbackEx(PaneItem::DPAEnumCallback, (LPVOID)NULL);
  419. _dpaEnum.DeleteAllPtrs();
  420. }
  421. }
  422. return S_OK;
  423. }
  424. LPWSTR GetStrPictureFromID(int nImageID)
  425. {
  426. LPWSTR pszPic = NULL;
  427. switch (nImageID)
  428. {
  429. case 1: pszPic = L"Picture1";
  430. break;
  431. case 2: pszPic = L"Picture2";
  432. break;
  433. case 3: pszPic = L"Picture3";
  434. break;
  435. }
  436. return pszPic;
  437. }
  438. BOOL IsValidExtension(LPWSTR pszPath)
  439. {
  440. if (pszPath)
  441. {
  442. WCHAR *pszExt = PathFindExtension(pszPath);
  443. if (pszExt && (lstrcmpi(pszExt, TEXT(".bmp")) == 0 || lstrcmpi(pszExt, TEXT(".jpg")) == 0 ||
  444. lstrcmpi(pszExt, TEXT(".jpeg")) == 0))
  445. return TRUE;
  446. }
  447. return FALSE;
  448. }
  449. HRESULT StartFrame::_PopulatePictures()
  450. {
  451. LPITEMIDLIST pidl;
  452. HRESULT hr = SHGetFolderLocation(NULL, CSIDL_MYPICTURES, NULL, 0, &pidl);
  453. if (SUCCEEDED(hr))
  454. {
  455. if (SUCCEEDED(hr))
  456. {
  457. WCHAR szPath[MAX_PATH];
  458. hr = SHGetPathFromIDList(pidl, szPath);
  459. if (SUCCEEDED(hr))
  460. {
  461. WIN32_FIND_DATA fd;
  462. HKEY hkey = NULL;
  463. RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage"), &hkey);
  464. StrCatBuff(szPath, TEXT("\\*"), ARRAYSIZE(szPath));
  465. int nImageID = 1;
  466. HANDLE hFind = FindFirstFile(szPath, &fd);
  467. while (nImageID <= 3)
  468. {
  469. LPWSTR pszPic = GetStrPictureFromID(nImageID);
  470. LPWSTR pszPathToImage = NULL;
  471. LPITEMIDLIST pidlFolder = NULL;
  472. if (hkey)
  473. {
  474. DWORD dwType;
  475. DWORD cb = sizeof(szPath);
  476. if (RegQueryValueEx(hkey, pszPic, NULL, &dwType, (LPBYTE)szPath, &cb) == ERROR_SUCCESS
  477. && dwType == REG_SZ && PathFileExists(szPath) && IsValidExtension(szPath))
  478. pszPathToImage = szPath;
  479. }
  480. while (!pszPathToImage && hFind != INVALID_HANDLE_VALUE)
  481. {
  482. pidlFolder = pidl;
  483. pszPathToImage = fd.cFileName;
  484. if (!FindNextFile(hFind, &fd))
  485. {
  486. FindClose(hFind);
  487. hFind = INVALID_HANDLE_VALUE;
  488. }
  489. // Skip the stupid sample
  490. if (lstrcmpi(pszPathToImage, TEXT("sample.jpg")) == 0 || !IsValidExtension(pszPathToImage))
  491. pszPathToImage = NULL;
  492. }
  493. if (pszPathToImage)
  494. {
  495. HBITMAP hbmp = GetBitmapForFile(pidlFolder, pszPathToImage, 150, 113);
  496. if (hbmp)
  497. {
  498. Element *pe = FindDescendent(StrToID(pszPic));
  499. if (pe)
  500. {
  501. Value *pvalIcon = Value::CreateGraphic(hbmp);
  502. if (pvalIcon)
  503. {
  504. pe->SetValue(ContentProp, PI_Local, pvalIcon);
  505. pvalIcon->Release();
  506. }
  507. else
  508. {
  509. DeleteObject(hbmp);
  510. }
  511. }
  512. }
  513. }
  514. nImageID++;
  515. }
  516. if (hFind != INVALID_HANDLE_VALUE)
  517. FindClose(hFind);
  518. if (hkey)
  519. RegCloseKey(hkey);
  520. }
  521. }
  522. ILFree(pidl);
  523. }
  524. return hr;
  525. }
  526. HRESULT StartFrame::_SetPicture(Element *pe)
  527. {
  528. LPITEMIDLIST pidl;
  529. HRESULT hr = SHGetFolderLocation(NULL, CSIDL_MYPICTURES, NULL, 0, &pidl);
  530. if (SUCCEEDED(hr))
  531. {
  532. WCHAR szPath[MAX_PATH];
  533. hr = SHGetPathFromIDList(pidl, szPath);
  534. if (SUCCEEDED(hr))
  535. {
  536. OPENFILENAME ofn; // common dialog box structure
  537. WCHAR szFile[MAX_PATH]; // buffer for file name
  538. *szFile = L'\0';
  539. // Initialize OPENFILENAME
  540. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  541. ofn.lStructSize = sizeof(OPENFILENAME);
  542. ofn.hwndOwner = GetHWND();
  543. ofn.lpstrFile = szFile;
  544. ofn.nMaxFile = sizeof(szFile);
  545. ofn.lpstrFilter = TEXT("Pictures\0*.JPG;*.JPEG;*.BMP\0");
  546. ofn.nFilterIndex = 1;
  547. ofn.lpstrFileTitle = NULL;
  548. ofn.nMaxFileTitle = 0;
  549. ofn.lpstrInitialDir = szPath;
  550. ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_DONTADDTORECENT;
  551. // Display the Open dialog box.
  552. if (GetOpenFileName(&ofn)==TRUE)
  553. {
  554. WCHAR *pszExt = PathFindExtension(ofn.lpstrFile);
  555. if (pszExt && (lstrcmpi(pszExt, TEXT(".bmp")) == 0 || lstrcmpi(pszExt, TEXT(".jpg")) == 0 ||
  556. lstrcmpi(pszExt, TEXT(".jpg")) == 0))
  557. {
  558. HBITMAP hbmp = GetBitmapForFile(NULL, ofn.lpstrFile, 150, 113);
  559. if (hbmp)
  560. {
  561. Value *pvalIcon = Value::CreateGraphic(hbmp);
  562. if (pvalIcon)
  563. {
  564. pe->SetValue(ContentProp, PI_Local, pvalIcon);
  565. pvalIcon->Release();
  566. HKEY hkey = NULL;
  567. RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartPage"), &hkey);
  568. if (hkey)
  569. {
  570. LPWSTR pszPic;
  571. for (int i=1; i<=3; i++)
  572. {
  573. pszPic = GetStrPictureFromID(i);
  574. if (FindDescendent(StrToID(pszPic)) == pe)
  575. break;
  576. pszPic = NULL;
  577. }
  578. if (pszPic)
  579. RegSetValueEx(hkey, pszPic, NULL, REG_SZ, (LPBYTE)ofn.lpstrFile, (lstrlen(ofn.lpstrFile)+1) * sizeof(TCHAR));
  580. RegCloseKey(hkey);
  581. }
  582. }
  583. else
  584. {
  585. DeleteObject(hbmp);
  586. }
  587. }
  588. }
  589. }
  590. }
  591. }
  592. return S_OK;
  593. }
  594. HRESULT StartFrame::Populate()
  595. {
  596. Element *pe = FindDescendent(StrToID(L"name"));
  597. if (pe)
  598. {
  599. WCHAR szUserName[UNLEN + 1];
  600. ULONG uLen = ARRAYSIZE(szUserName);
  601. *szUserName = _T('\0');
  602. SHGetUserDisplayName(szUserName, &uLen);
  603. pe->SetContentString(szUserName);
  604. }
  605. pe = FindDescendent(StrToID(L"UserPicture"));
  606. if (pe)
  607. {
  608. TCHAR szUserPicturePath[MAX_PATH];
  609. if (SUCCEEDED(SHGetUserPicturePath(NULL, SHGUPP_FLAG_CREATE, szUserPicturePath)))
  610. {
  611. HBITMAP hbmUserPicture = (HBITMAP)LoadImage(NULL, szUserPicturePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  612. if (hbmUserPicture)
  613. {
  614. Value *pvalIcon = Value::CreateGraphic(hbmUserPicture);
  615. if (pvalIcon)
  616. {
  617. pe->SetValue(ContentProp, PI_Local, pvalIcon);
  618. pvalIcon->Release();
  619. }
  620. else
  621. {
  622. DeleteObject(hbmUserPicture);
  623. }
  624. }
  625. }
  626. }
  627. _PopulatePictures();
  628. _PopulateSpecialFolders();
  629. return S_OK;
  630. }
  631. void StartFrame::OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  632. {
  633. if (id == IDCN_LASTMOD) // Change in last documents
  634. {
  635. UnregisterNotify(id);
  636. KillTimer(GetHWND(), TIMER_RECENT);
  637. SetTimer(GetHWND(), TIMER_RECENT, 2000, NULL);
  638. }
  639. else
  640. {
  641. ASSERT(_pByUsage);
  642. if(_pByUsage)
  643. {
  644. _pByUsage->GetMenuCache()->OnChangeNotify(id, lEvent, pidl1, pidl2);
  645. KillTimer(GetHWND(), TIMER_PROGRAMS);
  646. SetTimer(GetHWND(), TIMER_PROGRAMS, 10 * 1000, NULL);
  647. }
  648. }
  649. }
  650. LRESULT StartFrame::_OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  651. {
  652. if (wParam == TIMER_RECENT)
  653. {
  654. KillTimer(hwnd, wParam);
  655. StartDefer();
  656. _PopulateRecentDocuments();
  657. EndDefer();
  658. }
  659. else if (wParam == TIMER_PROGRAMS)
  660. {
  661. KillTimer(hwnd, wParam);
  662. StartDefer();
  663. _PopulateRecentPrograms();
  664. EndDefer();
  665. SetTimer(GetHWND(), TIMER_PROGRAMS, 1 * 60 * 1000, NULL); // 1 minute
  666. }
  667. else if (wParam == TIMER_ANIMATE)
  668. {
  669. if (_iAnimationColor & 1)
  670. {
  671. _iAnimationColor += 16;
  672. if (_iAnimationColor == 255)
  673. KillTimer(hwnd, wParam);
  674. }
  675. else
  676. {
  677. if (_iAnimationColor > 16)
  678. _iAnimationColor -= 16;
  679. else
  680. _iAnimationColor = 15;
  681. }
  682. _peAnimating->SetForegroundColor(RGB(_iAnimationColor, _iAnimationColor, (3*_iAnimationColor + 255) /4));
  683. }
  684. return 0;
  685. }
  686. BOOL StartFrame::RegisterNotify(UINT id, LONG lEvents, LPITEMIDLIST pidl, BOOL fRecursive)
  687. {
  688. ASSERT(id < DUI_MAXNOTIFY);
  689. if (id < DUI_MAXNOTIFY)
  690. {
  691. UnregisterNotify(id);
  692. SHChangeNotifyEntry fsne;
  693. fsne.fRecursive = fRecursive;
  694. fsne.pidl = pidl;
  695. int fSources = SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel;
  696. _rguChangeNotify[id] = SHChangeNotifyRegister(GetHWND(), fSources, lEvents,
  697. SPM_CHANGENOTIFY + id, 1, &fsne);
  698. return _rguChangeNotify[id];
  699. }
  700. return FALSE;
  701. }
  702. BOOL StartFrame::UnregisterNotify(UINT id)
  703. {
  704. ASSERT(id < DUI_MAXNOTIFY);
  705. if (id < DUI_MAXNOTIFY && _rguChangeNotify[id])
  706. {
  707. UINT uChangeNotify = _rguChangeNotify[id];
  708. _rguChangeNotify[id] = 0;
  709. return SHChangeNotifyDeregister(uChangeNotify);
  710. }
  711. return FALSE;
  712. }
  713. ////////////////////////////////////////////////////////
  714. // System events
  715. void StartFrame::OnInput(InputEvent* pie)
  716. {
  717. HWNDElement::OnInput(pie);
  718. }
  719. void StartFrame::OnEvent(Event* pEvent)
  720. {
  721. if (pEvent->nStage == GMF_BUBBLED)
  722. {
  723. if (pEvent->uidType == Button::Click)
  724. {
  725. if (pEvent->peTarget->GetID() == StrToID(L"email"))
  726. {
  727. InvokePidl(_pidlEmail);
  728. }
  729. else if (pEvent->peTarget->GetID() == StrToID(L"internet"))
  730. {
  731. InvokePidl(_pidlBrowser);
  732. }
  733. else if (pEvent->peTarget->GetID() == StrToID(L"search"))
  734. {
  735. InvokePidl(_pidlSearch);
  736. }
  737. else if (pEvent->peTarget->GetID() == StrToID(L"MorePrograms"))
  738. {
  739. LPITEMIDLIST pidl = ILCreateFromPath(TEXT("shell:::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a}"));
  740. if (pidl)
  741. {
  742. InvokePidl(pidl);
  743. ILFree(pidl);
  744. }
  745. }
  746. else if (pEvent->peTarget->GetID() == StrToID(L"MoreDocuments"))
  747. {
  748. LPITEMIDLIST pidl = ILCreateFromPath(TEXT("shell:::{9387ae38-d19b-4de5-baf5-1f7767a1cf04}"));
  749. if (pidl)
  750. {
  751. InvokePidl(pidl);
  752. ILFree(pidl);
  753. }
  754. }
  755. else if (pEvent->peTarget->GetID() == StrToID(L"turnoff"))
  756. {
  757. Tray_MenuInvoke(IDM_EXITWIN);
  758. }
  759. else if (pEvent->peTarget->GetID() == StrToID(L"logoff"))
  760. {
  761. Tray_MenuInvoke(IDM_LOGOFF);
  762. }
  763. else
  764. {
  765. HMENU hmenu = LoadMenu(_hInstance, MAKEINTRESOURCE(IDM_PICTMENU));
  766. if (hmenu)
  767. {
  768. HMENU hMenuTrack = GetSubMenu(hmenu, 0);
  769. ButtonClickEvent *peButton = reinterpret_cast<ButtonClickEvent *>(pEvent);
  770. if (peButton->pt.x == -1) // Keyboard context menu
  771. {
  772. Value *pv;
  773. const SIZE *psize = pEvent->peTarget->GetExtent(&pv);
  774. peButton->pt.x = psize->cx/2;
  775. peButton->pt.y = psize->cy/2;
  776. pv->Release();
  777. }
  778. POINT pt;
  779. MapElementPoint(pEvent->peTarget, &peButton->pt, &pt);
  780. ClientToScreen(GetHWND(), &pt);
  781. int idCmd = TrackPopupMenuEx(hMenuTrack, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, pt.x, pt.y, GetHWND(), NULL);
  782. DestroyMenu(hmenu);
  783. if (idCmd == ID_CMD_CHANGE_PICTURE)
  784. {
  785. _SetPicture(pEvent->peTarget);
  786. }
  787. }
  788. }
  789. }
  790. }
  791. HWNDElement::OnEvent(pEvent);
  792. }
  793. HRESULT StartFrame::InvokePidl(LPITEMIDLIST pidl)
  794. {
  795. HRESULT hr = E_FAIL;
  796. IShellFolder *psf;
  797. LPCITEMIDLIST pidlShort;
  798. // Multi-level child pidl
  799. if (SUCCEEDED(SHBindToFolderIDListParent(NULL, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort)))
  800. {
  801. hr = SHInvokeDefaultCommand(GetHWND(), psf, pidlShort);
  802. psf->Release();
  803. }
  804. return hr;
  805. }
  806. WCHAR StartFrame::_szParseError[201];
  807. int StartFrame::_dParseError;
  808. void StartFrame::ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  809. {
  810. if (dLine != -1)
  811. swprintf(_szParseError, L"%s '%s' at line %d", pszError, pszToken, dLine);
  812. else
  813. swprintf(_szParseError, L"%s '%s'", pszError, pszToken);
  814. _dParseError = dLine;
  815. }
  816. LRESULT StartFrame::_OnSetMenuForward(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  817. {
  818. _pPidlButtonPop = (PIDLButton *)lParam;
  819. return 0;
  820. }
  821. LRESULT StartFrame::_OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  822. {
  823. if (_pPidlButtonPop)
  824. return _pPidlButtonPop->OnMenuMessage(hwnd, uMsg, wParam, lParam);
  825. return 0;
  826. }
  827. LRESULT StartFrame::_OnChangeNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  828. {
  829. LPITEMIDLIST *ppidl;
  830. LONG lEvent;
  831. LPSHChangeNotificationLock pshcnl;
  832. pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
  833. if (pshcnl)
  834. {
  835. OnChangeNotify(uMsg - SPM_CHANGENOTIFY, lEvent, ppidl[0], ppidl[1]);
  836. SHChangeNotification_Unlock(pshcnl);
  837. }
  838. return 0;
  839. }
  840. LRESULT StartFrame::_OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  841. {
  842. UINT id;
  843. for (id = 0; id < DUI_MAXNOTIFY; id++)
  844. {
  845. UnregisterNotify(id);
  846. }
  847. delete _pByUsage;
  848. _pByUsage = NULL;
  849. #if 0 // REVIEW fabriced
  850. if (_hwndList)
  851. {
  852. RevokeDragDrop(_hwndList);
  853. }
  854. if (_psched)
  855. {
  856. _psched->RemoveTasks(TOID_SFTBarHostBackgroundEnum, (DWORD_PTR)this, FALSE);
  857. }
  858. #endif
  859. return HWNDElement::WndProc(hwnd, uMsg, wParam, lParam);
  860. }
  861. LRESULT StartFrame::_OnActivate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  862. {
  863. if (WA_ACTIVE == LOWORD(wParam))
  864. {
  865. // Run a little animation when we come up
  866. _peAnimating = FindDescendent(StrToID(L"name"));
  867. _iAnimationColor = 64;
  868. SetTimer(GetHWND(), TIMER_ANIMATE, 20, NULL);
  869. }
  870. // If we are loosing focus, reset the start button.
  871. else if (WA_INACTIVE == LOWORD(wParam))
  872. {
  873. if (_peAnimating)
  874. _peAnimating->SetForegroundColor(RGB(255, 255, 255));
  875. KillTimer(GetHWND(), TIMER_ANIMATE);
  876. Tray_SetStartPaneActive(FALSE);
  877. Tray_OnStartPageDismissed();
  878. }
  879. return 0;
  880. }
  881. LRESULT StartFrame::_OnSize(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  882. {
  883. Element::StartDefer();
  884. SetWidth(LOWORD(lParam));
  885. SetHeight(HIWORD(lParam));
  886. if (HIWORD(lParam) < 590)
  887. {
  888. _iMaxShow = 7;
  889. Element *pe = FindDescendent(StrToID(L"CurveZone"));
  890. if (pe)
  891. pe->SetPadding(0, 0, 0, 74);
  892. pe = FindDescendent(StrToID(L"LogoffZone"));
  893. if (pe)
  894. pe->SetPadding(50, 0, 50, 10);
  895. }
  896. else if (HIWORD(lParam) < 700)
  897. {
  898. _iMaxShow = 7;
  899. Element *pe = FindDescendent(StrToID(L"CurveZone"));
  900. if (pe)
  901. pe->SetPadding(0, 0, 0, 105);
  902. pe = FindDescendent(StrToID(L"LogoffZone"));
  903. if (pe)
  904. pe->SetPadding(50, 0, 50, 41);
  905. }
  906. else if (HIWORD(lParam) < 760)
  907. {
  908. _iMaxShow = 10;
  909. Element *pe = FindDescendent(StrToID(L"CurveZone"));
  910. if (pe)
  911. pe->SetPadding(0, 0, 0, 74);
  912. pe = FindDescendent(StrToID(L"LogoffZone"));
  913. if (pe)
  914. pe->SetPadding(50, 0, 50, 10);
  915. }
  916. else
  917. {
  918. _iMaxShow = 10;
  919. Element *pe = FindDescendent(StrToID(L"CurveZone"));
  920. if (pe)
  921. pe->SetPadding(0, 0, 0, 105);
  922. pe = FindDescendent(StrToID(L"LogoffZone"));
  923. if (pe)
  924. pe->SetPadding(50, 0, 50, 41);
  925. }
  926. _PopulateRecentDocuments();
  927. _PopulateRecentPrograms();
  928. Element::EndDefer();
  929. return 0;
  930. }
  931. void StartFrame::OnKeyFocusMoved(Element* peFrom, Element* peTo)
  932. {
  933. }
  934. LRESULT StartFrame::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  935. {
  936. #define HANDLE_SF_MESSAGE(wm, fn) case wm: return fn(hWnd, uMsg, wParam, lParam)
  937. if (SPM_CHANGENOTIFY <= uMsg && uMsg < SPM_CHANGENOTIFY + DUI_MAXNOTIFY)
  938. return _OnChangeNotify(hWnd, uMsg, wParam, lParam);
  939. switch (uMsg)
  940. {
  941. HANDLE_SF_MESSAGE(WM_DESTROY, _OnDestroy);
  942. HANDLE_SF_MESSAGE(WM_TIMER, _OnTimer);
  943. HANDLE_SF_MESSAGE(WM_SIZE, _OnSize);
  944. HANDLE_SF_MESSAGE(SPM_ACTIVATE, _OnActivate);
  945. // Context menus handlers
  946. HANDLE_SF_MESSAGE(WM_INITMENUPOPUP,_OnMenuMessage);
  947. HANDLE_SF_MESSAGE(WM_DRAWITEM, _OnMenuMessage);
  948. HANDLE_SF_MESSAGE(WM_MENUCHAR, _OnMenuMessage);
  949. HANDLE_SF_MESSAGE(WM_MEASUREITEM, _OnMenuMessage);
  950. HANDLE_SF_MESSAGE(PIDLButton::PBM_SETMENUFORWARD, _OnSetMenuForward);
  951. }
  952. return HWNDElement::WndProc(hWnd, uMsg, wParam, lParam);
  953. }
  954. ////////////////////////////////////////////////////////
  955. // ClassInfo (must appear after property definitions)
  956. // Define class info with type and base type, set static class pointer
  957. IClassInfo* StartFrame::Class = NULL;
  958. HRESULT StartFrame::Register()
  959. {
  960. return ClassInfo<StartFrame,HWNDElement>::Register(L"StartFrame", NULL, 0);
  961. }
  962. ////////////////////////////////////////////////////////
  963. // Parser
  964. ////////////////////////////////////////////////////////
  965. void CALLBACK ParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  966. {
  967. WCHAR buf[201];
  968. if (dLine != -1)
  969. swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
  970. else
  971. swprintf(buf, L"%s '%s'", pszError, pszToken);
  972. MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
  973. }
  974. // Privates from Shell32.
  975. STDAPI_(HWND) SetPeekMsgEx(FARPROC fp, HANDLE hDesktop);
  976. STDAPI_(BOOL) SetStartPageHWND(HANDLE hDesktop, HWND hwnd);
  977. typedef HWND (*SetPeek)(FARPROC fp, HANDLE hDesktop);
  978. /////////////////////////////////////
  979. // Creation of the Start Page
  980. void CreateStartPage(HINSTANCE hInstance, HANDLE hDesktop)
  981. {
  982. HWND hwndParent = NULL;
  983. CoInitialize(NULL);
  984. // DirectUI init thread in caller
  985. InitThread();
  986. hwndParent = SetPeekMsgEx((FARPROC)PeekMessageEx, hDesktop);
  987. Element::StartDefer();
  988. // HWND Root
  989. StartFrame* psf;
  990. HRESULT hr = StartFrame::Create(hwndParent, hInstance, (Element**)&psf);
  991. if (FAILED(hr))
  992. return;
  993. // Fill content of frame (using substitution)
  994. Parser* pParser;
  995. Parser::Create(IDR_STARTUI, hInstance, ParseError, &pParser);
  996. if (!pParser)
  997. return;
  998. if (pParser->WasParseError())
  999. {
  1000. ASSERTMSG(FALSE, "Parse error!");
  1001. pParser->Destroy();
  1002. return;
  1003. }
  1004. Element* pe;
  1005. pParser->CreateElement(L"main", psf, &pe);
  1006. // Done with parser
  1007. pParser->Destroy();
  1008. // Disable Drag-drop for now.
  1009. BuildDropTarget( psf->GetDisplayNode(), psf->GetHWND());
  1010. psf->Populate();
  1011. // Set visible and host
  1012. psf->SetVisible(true);
  1013. RECT rect;
  1014. GetWindowRect(hwndParent, &rect);
  1015. psf->SetWidth(RECTWIDTH(rect));
  1016. psf->SetHeight(RECTHEIGHT(rect));
  1017. Element::EndDefer();
  1018. SetStartPageHWND(hDesktop, psf->GetHWND());
  1019. SetTimer(psf->GetHWND(), StartFrame::TIMER_PROGRAMS, 1 * 60 * 1000, NULL); // 1 minute
  1020. HWND hwndDesktop = GetParent(GetParent(hwndParent));
  1021. ShowWindow(hwndDesktop, SW_SHOW);
  1022. UpdateWindow(hwndDesktop);
  1023. return;
  1024. }
  1025. #endif // FEATURE_STARTPAGE