Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1211 lines
31 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1996.
  5. //
  6. // File: selprog.cxx
  7. //
  8. // Contents: Task wizard program selection property page implementation.
  9. //
  10. // Classes: CSelectProgramPage
  11. //
  12. // History: 4-28-1997 DavidMun Created
  13. //
  14. //---------------------------------------------------------------------------
  15. #include "..\pch\headers.hxx"
  16. #pragma hdrstop
  17. #include "myheaders.hxx"
  18. #include "commdlg.h"
  19. #include "..\schedui\rc.h"
  20. #include "..\inc\resource.h"
  21. #include "..\folderui\jobicons.hxx"
  22. #include "walklib.h"
  23. //
  24. // Types
  25. //
  26. // COLUMNS - indexes to the columns in the listview displaying the results
  27. // of walking the start menu
  28. //
  29. enum COLUMNS
  30. {
  31. COL_APP,
  32. COL_VERSION,
  33. NUM_COLUMNS
  34. };
  35. //
  36. // Forward references
  37. //
  38. INT
  39. InsertSmallIcon(
  40. HIMAGELIST hSmallImageList,
  41. LPCTSTR tszExeName);
  42. //
  43. // Externals
  44. //
  45. extern HICON GetDefaultAppIcon(UINT nIconSize);
  46. //+--------------------------------------------------------------------------
  47. //
  48. // Member: CSelectProgramPage::CSelectProgramPage
  49. //
  50. // Synopsis: ctor
  51. //
  52. // Arguments: [ptszFolderPath] - full path to tasks folder with dummy
  53. // filename appended
  54. // [phPSP] - filled with prop page handle
  55. //
  56. // History: 4-28-1997 DavidMun Created
  57. //
  58. //---------------------------------------------------------------------------
  59. CSelectProgramPage::CSelectProgramPage(
  60. CTaskWizard *pParent,
  61. LPTSTR ptszFolderPath,
  62. HPROPSHEETPAGE *phPSP):
  63. CWizPage(MAKEINTRESOURCE(IDD_SELECT_PROGRAM), ptszFolderPath)
  64. {
  65. TRACE_CONSTRUCTOR(CSelectProgramPage);
  66. _hwndLV = NULL;
  67. _pSelectedLinkInfo = NULL;
  68. _idxSelectedIcon = 0;
  69. _fUseBrowseSelection = FALSE;
  70. _tszExePath[0] = TEXT('\0');
  71. _tszExeName[0] = TEXT('\0');
  72. _CreatePage(IDS_SELPROG_HDR1, IDS_SELPROG_HDR2, phPSP);
  73. }
  74. //+--------------------------------------------------------------------------
  75. //
  76. // Member: CSelectProgramPage::~CSelectProgramPage
  77. //
  78. // Synopsis: dtor
  79. //
  80. // History: 4-28-1997 DavidMun Created
  81. //
  82. //---------------------------------------------------------------------------
  83. CSelectProgramPage::~CSelectProgramPage()
  84. {
  85. TRACE_DESTRUCTOR(CSelectProgramPage);
  86. }
  87. //===========================================================================
  88. //
  89. // CPropPage overrides
  90. //
  91. //===========================================================================
  92. //+--------------------------------------------------------------------------
  93. //
  94. // Member: CSelectProgramPage::_OnCommand
  95. //
  96. // Synopsis: Handle the browse button being clicked, ignore all else.
  97. //
  98. // History: 5-20-1997 DavidMun Created
  99. //
  100. //---------------------------------------------------------------------------
  101. LRESULT
  102. CSelectProgramPage::_OnCommand(
  103. int id,
  104. HWND hwndCtl,
  105. UINT codeNotify)
  106. {
  107. TRACE_METHOD(CSelectProgramPage, _OnCommand);
  108. LRESULT lr = 0;
  109. if (codeNotify == BN_CLICKED && id == selprogs_browse_pb)
  110. {
  111. _OnBrowse();
  112. }
  113. else
  114. {
  115. lr = 1; // not handled
  116. }
  117. return lr;
  118. }
  119. //+--------------------------------------------------------------------------
  120. //
  121. // Member: CSelectProgramPage::_OnInitDialog
  122. //
  123. // Synopsis: Perform initialization that should only occur once.
  124. //
  125. // Arguments: [lParam] - LPPROPSHEETPAGE used to create this page
  126. //
  127. // Returns: TRUE (let windows set focus)
  128. //
  129. // History: 5-20-1997 DavidMun Created
  130. //
  131. //---------------------------------------------------------------------------
  132. LRESULT
  133. CSelectProgramPage::_OnInitDialog(
  134. LPARAM lParam)
  135. {
  136. TRACE_METHOD(CSelectProgramPage, _OnInitDialog);
  137. HRESULT hr = S_OK;
  138. // Policy dictates whether we have a browse button or not
  139. // true means don't allow us to browse
  140. if (RegReadPolicyKey(TS_KEYPOLICY_DENY_BROWSE))
  141. {
  142. DEBUG_OUT((DEB_ITRACE, "Policy DENY_BROWSE active - removing browse btn\n"));
  143. EnableWindow(_hCtrl(selprogs_browse_pb), FALSE);
  144. ShowWindow(_hCtrl(selprogs_browse_pb), SW_HIDE);
  145. ShowWindow(_hCtrl(selprogs_static_text_browse), SW_HIDE);
  146. }
  147. // Next not enabled till user picks app
  148. _SetWizButtons(PSWIZB_BACK);
  149. _hwndLV = _hCtrl(selprog_programs_lv);
  150. hr = _InitListView();
  151. if (SUCCEEDED(hr))
  152. {
  153. _PopulateListView();
  154. }
  155. return (HRESULT) TRUE; // wm_initdialog wants BOOL for setfocus info
  156. }
  157. //+--------------------------------------------------------------------------
  158. //
  159. // Member: CSelectProgramPage::_OnPSNSetActive
  160. //
  161. // Synopsis: Enable the Next button if an item has been selected in the
  162. // listview.
  163. //
  164. // History: 5-20-1997 DavidMun Created
  165. //
  166. //---------------------------------------------------------------------------
  167. LRESULT
  168. CSelectProgramPage::_OnPSNSetActive(
  169. LPARAM lParam)
  170. {
  171. _fUseBrowseSelection = FALSE;
  172. if (_pSelectedLinkInfo)
  173. {
  174. _SetWizButtons(PSWIZB_BACK | PSWIZB_NEXT);
  175. }
  176. else
  177. {
  178. _SetWizButtons(PSWIZB_BACK);
  179. }
  180. return CPropPage::_OnPSNSetActive(lParam);
  181. }
  182. //+--------------------------------------------------------------------------
  183. //
  184. // Member: CSelectProgramPage::_OnDestroy
  185. //
  186. // Synopsis: Free all the linkinfos stored as user data in the listview.
  187. //
  188. // History: 5-20-1997 DavidMun Created
  189. //
  190. //---------------------------------------------------------------------------
  191. LRESULT
  192. CSelectProgramPage::_OnDestroy()
  193. {
  194. DEBUG_ASSERT(IsWindow(_hwndLV));
  195. ULONG cItems = ListView_GetItemCount(_hwndLV);
  196. ULONG i;
  197. LV_ITEM lvi;
  198. SecureZeroMemory(&lvi, sizeof lvi);
  199. lvi.mask = LVIF_PARAM;
  200. for (i = 0; i < cItems; i++)
  201. {
  202. lvi.iItem = i;
  203. lvi.lParam = 0;
  204. BOOL fOk = ListView_GetItem(_hwndLV, &lvi);
  205. if (fOk)
  206. {
  207. delete (LINKINFO *) lvi.lParam;
  208. }
  209. else
  210. {
  211. DEBUG_OUT_LASTERROR;
  212. }
  213. }
  214. return 0;
  215. }
  216. //+--------------------------------------------------------------------------
  217. //
  218. // Member: CSelectProgramPage::_ProcessListViewNotifications
  219. //
  220. // Synopsis: If the user makes a selection in the listview, remember the
  221. // associated linkinfo and enable the next button.
  222. //
  223. // Returns: FALSE
  224. //
  225. // History: 5-20-1997 DavidMun Created
  226. //
  227. // Notes: Ignores all other notifications.
  228. //
  229. //---------------------------------------------------------------------------
  230. BOOL
  231. CSelectProgramPage::_ProcessListViewNotifications(
  232. UINT uMsg,
  233. WPARAM wParam,
  234. LPARAM lParam)
  235. {
  236. UINT code = ((LPNMHDR)lParam)->code;
  237. if (((LPNMHDR)lParam)->idFrom != selprog_programs_lv)
  238. {
  239. return FALSE;
  240. }
  241. DEBUG_ASSERT(code != LVN_GETDISPINFO); // not using callbacks
  242. DEBUG_ASSERT(code != LVN_SETDISPINFO); // items are r/o
  243. if (code == LVN_ITEMCHANGED)
  244. {
  245. NM_LISTVIEW *pnmLV = (NM_LISTVIEW *) lParam;
  246. if ((pnmLV->uChanged & LVIF_STATE) &&
  247. (pnmLV->uNewState & LVIS_SELECTED))
  248. {
  249. // translate the index into a LinkInfo pointer
  250. LV_ITEM lvi;
  251. lvi.iItem = pnmLV->iItem;
  252. lvi.iSubItem = 0;
  253. lvi.mask = LVIF_PARAM | LVIF_IMAGE;
  254. if (!ListView_GetItem(_hwndLV, &lvi))
  255. {
  256. DEBUG_OUT_LASTERROR;
  257. return FALSE;
  258. }
  259. _pSelectedLinkInfo = (LINKINFO *) lvi.lParam;
  260. _idxSelectedIcon = lvi.iImage;
  261. _SetWizButtons(PSWIZB_BACK | PSWIZB_NEXT);
  262. }
  263. }
  264. return FALSE;
  265. }
  266. //===========================================================================
  267. //
  268. // CSelectProgramPage members
  269. //
  270. //===========================================================================
  271. //+--------------------------------------------------------------------------
  272. //
  273. // Member: CSelectProgramPage::GetDefaultDisplayName
  274. //
  275. // Synopsis: Fill [tszDisplayName] with the string to offer the user
  276. // as the new task object name.
  277. //
  278. // Arguments: [tszDisplayName] - buffer to receive string
  279. // [cchDisplayName] - size, in chars, of buffer
  280. //
  281. // Modifies: *[tszDisplayName]
  282. //
  283. // History: 5-20-1997 DavidMun Created
  284. //
  285. //---------------------------------------------------------------------------
  286. VOID
  287. CSelectProgramPage::GetDefaultDisplayName(
  288. LPTSTR tszDisplayName,
  289. ULONG cchDisplayName)
  290. {
  291. LPTSTR ptszToCopy;
  292. if (_fUseBrowseSelection)
  293. {
  294. ptszToCopy = _tszExeName;
  295. }
  296. else if (*_pSelectedLinkInfo->szLnkName)
  297. {
  298. ptszToCopy = _pSelectedLinkInfo->szLnkName;
  299. }
  300. else
  301. {
  302. ptszToCopy = _pSelectedLinkInfo->szExeName;
  303. }
  304. lstrcpyn(tszDisplayName, ptszToCopy, cchDisplayName);
  305. //
  306. // Truncate at the file extension
  307. //
  308. LPTSTR ptszExt = PathFindExtension(tszDisplayName);
  309. if (ptszExt)
  310. {
  311. *ptszExt = TEXT('\0');
  312. }
  313. }
  314. //+--------------------------------------------------------------------------
  315. //
  316. // Member: CSelectProgramPage::GetSelectedAppIcon
  317. //
  318. // Synopsis: Retrieve the icon associated with the selected appliation.
  319. //
  320. // Returns: The selected app's small icon, or NULL if no small icon is
  321. // available.
  322. //
  323. // History: 5-20-1997 DavidMun Created
  324. //
  325. //---------------------------------------------------------------------------
  326. HICON
  327. CSelectProgramPage::GetSelectedAppIcon()
  328. {
  329. if (_fUseBrowseSelection)
  330. {
  331. HICON hicon = NULL;
  332. TCHAR tszFullPath[MAX_PATH];
  333. GetExeFullPath(tszFullPath, ARRAYLEN(tszFullPath));
  334. TS_ExtractIconEx(tszFullPath, 0, &hicon, 1, GetSystemMetrics(SM_CXSMICON));
  335. return hicon;
  336. }
  337. if (_idxSelectedIcon == -1)
  338. {
  339. return NULL;
  340. }
  341. HIMAGELIST hSmallImageList = ListView_GetImageList(_hwndLV, LVSIL_SMALL);
  342. if (!hSmallImageList)
  343. {
  344. return NULL;
  345. }
  346. return ImageList_ExtractIcon(0, hSmallImageList, _idxSelectedIcon);
  347. }
  348. //+--------------------------------------------------------------------------
  349. //
  350. // Member: CSelectProgramPage::_InitListView
  351. //
  352. // Synopsis: Initialize the listview's columns and image lists.
  353. //
  354. // Returns: HRESULT
  355. //
  356. // History: 5-20-1997 DavidMun Created
  357. //
  358. //---------------------------------------------------------------------------
  359. HRESULT
  360. CSelectProgramPage::_InitListView()
  361. {
  362. HRESULT hr = S_OK;
  363. HIMAGELIST himlSmall = NULL;
  364. INT cxSmall = GetSystemMetrics(SM_CXSMICON);
  365. INT cySmall = GetSystemMetrics(SM_CYSMICON);
  366. DWORD dwFlag = ILC_MASK | ILC_COLOR32;
  367. do
  368. {
  369. if (!_hwndLV || !cxSmall || !cySmall)
  370. {
  371. hr = E_UNEXPECTED;
  372. DEBUG_OUT_HRESULT(hr);
  373. break;
  374. }
  375. //
  376. // Create the listview image list. Only the small image list is
  377. // required, since this listview will be restricted to report
  378. // mode.
  379. //
  380. if (GetWindowLongPtr(_hwndLV, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) {
  381. dwFlag |= ILC_MIRROR;
  382. }
  383. himlSmall = ImageList_Create(cxSmall, cySmall, dwFlag, 1, 1);
  384. if (!himlSmall)
  385. {
  386. hr = HRESULT_FROM_LASTERROR;
  387. DEBUG_OUT_LASTERROR;
  388. break;
  389. }
  390. // Add the generic icon
  391. HICON hiconGeneric = GetDefaultAppIcon(GetSystemMetrics(SM_CXSMICON));
  392. DEBUG_ASSERT(hiconGeneric);
  393. INT index = ImageList_AddIcon(himlSmall, hiconGeneric);
  394. DEBUG_ASSERT(index != -1);
  395. // Assign the image list to the listview
  396. if (!ListView_SetImageList(_hwndLV, himlSmall, LVSIL_SMALL))
  397. {
  398. himlSmall = NULL;
  399. }
  400. else
  401. {
  402. hr = HRESULT_FROM_LASTERROR;
  403. DEBUG_OUT_LASTERROR;
  404. break;
  405. }
  406. //
  407. // Create 2 listview columns. If more are added, the column
  408. // width calculation needs to change.
  409. //
  410. DEBUG_ASSERT(NUM_COLUMNS == 2);
  411. LV_COLUMN lvc;
  412. RECT rcLV;
  413. TCHAR tszColumnLabel[MAX_LVIEW_HEADER_CCH];
  414. VERIFY(GetClientRect(_hwndLV, &rcLV));
  415. rcLV.right -= GetSystemMetrics(SM_CXVSCROLL);
  416. SecureZeroMemory(&lvc, sizeof lvc);
  417. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  418. lvc.fmt = LVCFMT_LEFT;
  419. lvc.cx = (2 * rcLV.right) / 3;
  420. lvc.pszText = tszColumnLabel;
  421. int iCol;
  422. for (iCol = 0; iCol < NUM_COLUMNS; iCol++)
  423. {
  424. lvc.iSubItem = iCol;
  425. LoadStr(IDS_FIRSTCOLUMN + iCol,
  426. tszColumnLabel,
  427. ARRAYLEN(tszColumnLabel));
  428. //
  429. // Once the first column has been inserted, allocate the
  430. // remaining width to the second column.
  431. //
  432. if (iCol)
  433. {
  434. lvc.cx = rcLV.right - lvc.cx;
  435. }
  436. if (ListView_InsertColumn(_hwndLV, iCol, &lvc) == -1)
  437. {
  438. hr = HRESULT_FROM_LASTERROR;
  439. DEBUG_OUT_LASTERROR;
  440. break;
  441. }
  442. }
  443. BREAK_ON_FAIL_HRESULT(hr);
  444. } while (0);
  445. if (FAILED(hr))
  446. {
  447. if (himlSmall)
  448. {
  449. VERIFY(ImageList_Destroy(himlSmall));
  450. }
  451. if (_hwndLV)
  452. {
  453. EnableWindow(_hwndLV, FALSE);
  454. }
  455. }
  456. return hr;
  457. }
  458. //+--------------------------------------------------------------------------
  459. //
  460. // Member: CSelectProgramPage::_PopulateListView
  461. //
  462. // Synopsis: Fill the listview from the shortcuts found under the start
  463. // menu directory.
  464. //
  465. // Returns: HRESULT
  466. //
  467. // History: 5-20-1997 DavidMun Created
  468. //
  469. // Notes: Searches both under the current user and the all users
  470. // start menu directories. Note the walk link code ignores
  471. // links to certain programs, e.g. notepad.exe. These would
  472. // generally not make interesting tasks.
  473. //
  474. //---------------------------------------------------------------------------
  475. HRESULT
  476. CSelectProgramPage::_PopulateListView()
  477. {
  478. TRACE_METHOD(CSelectProgramPage, _PopulateListView);
  479. HRESULT hr = S_OK;
  480. LPLINKINFO pLinkInfo = new LINKINFO;
  481. HWALK hWalk = NULL;
  482. ERR errWalk;
  483. LV_ITEM lvi;
  484. HIMAGELIST hSmallImageList = ListView_GetImageList(_hwndLV, LVSIL_SMALL);
  485. SecureZeroMemory(&lvi, sizeof lvi);
  486. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  487. if (hSmallImageList)
  488. {
  489. lvi.mask |= LVIF_IMAGE;
  490. }
  491. CWaitCursor HourGlass;
  492. do
  493. {
  494. if (!pLinkInfo)
  495. {
  496. hr = E_OUTOFMEMORY;
  497. DEBUG_OUT_HRESULT(hr);
  498. break;
  499. }
  500. TCHAR tszAllUsersStartMenuPath[MAX_PATH];
  501. TCHAR tszAllUsersStartMenuPathExpanded[MAX_PATH];
  502. //
  503. // This CSIDL is valid on NT only
  504. //
  505. hr = SHGetFolderPath(NULL,
  506. CSIDL_COMMON_STARTMENU,
  507. NULL,
  508. 0,
  509. tszAllUsersStartMenuPath);
  510. if (FAILED(hr))
  511. {
  512. DEBUG_OUT_HRESULT(hr);
  513. break;
  514. }
  515. VERIFY(ExpandEnvironmentStrings(tszAllUsersStartMenuPath,
  516. tszAllUsersStartMenuPathExpanded,
  517. MAX_PATH));
  518. hWalk = GetFirstFileLnkInfo(pLinkInfo,
  519. INPTYPE_STARTMENU |
  520. INPTYPE_ANYFOLDER |
  521. INPFLAG_SKIPFILES,
  522. tszAllUsersStartMenuPathExpanded,
  523. &errWalk);
  524. if (!hWalk || FAILED(errWalk))
  525. {
  526. DEBUG_OUT((DEB_ERROR,
  527. "_PopulateListView: GetFirstFileLnkInfo %dL\n",
  528. errWalk));
  529. hr = E_FAIL;
  530. break; // no links in start menu (!) or error
  531. }
  532. hr = _AddAppToListView(&lvi, hSmallImageList, pLinkInfo);
  533. BREAK_ON_FAIL_HRESULT(hr);
  534. } while (0);
  535. //
  536. // If the first link was found, continue until no more are found
  537. // or an error occurs.
  538. //
  539. while (SUCCEEDED(hr))
  540. {
  541. pLinkInfo = new LINKINFO;
  542. if (!pLinkInfo)
  543. {
  544. hr = E_OUTOFMEMORY;
  545. DEBUG_OUT_HRESULT(hr);
  546. break;
  547. }
  548. if (GetNextFileLnkInfo(hWalk, pLinkInfo) > 0)
  549. {
  550. if (!_AppAlreadyInListView(pLinkInfo))
  551. {
  552. hr = _AddAppToListView(&lvi, hSmallImageList, pLinkInfo);
  553. BREAK_ON_FAIL_HRESULT(hr);
  554. }
  555. else
  556. {
  557. DEBUG_OUT((DEB_TRACE,
  558. "Discarding duplicate link %S %S\n",
  559. pLinkInfo->szLnkName,
  560. pLinkInfo->szExeVersionInfo));
  561. delete pLinkInfo;
  562. }
  563. }
  564. else
  565. {
  566. break; // no more links or error
  567. }
  568. }
  569. delete pLinkInfo;
  570. CloseWalk(hWalk); // no-op on null
  571. //
  572. // If anything was added to the listview, make the first item focused
  573. // (but not selected).
  574. //
  575. if (ListView_GetItemCount(_hwndLV))
  576. {
  577. ListView_SetItemState(_hwndLV, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  578. }
  579. return hr;
  580. }
  581. //+--------------------------------------------------------------------------
  582. //
  583. // Member: CSelectProgramPage::_AppAlreadyInListView
  584. //
  585. // Synopsis: Return TRUE if a link with the same name and version info
  586. // as [pLinkInfo] has already been inserted in the listview.
  587. //
  588. // Arguments: [pLinkInfo] - contains link name to check
  589. //
  590. // Returns: TRUE - same link name found
  591. // FALSE - same link not found, or error
  592. //
  593. // History: 5-20-1997 DavidMun Created
  594. //
  595. // Notes: This eliminates links that have the same name, even if they
  596. // point to different programs, or have different arguments.
  597. //
  598. //---------------------------------------------------------------------------
  599. BOOL
  600. CSelectProgramPage::_AppAlreadyInListView(
  601. LPLINKINFO pLinkInfo)
  602. {
  603. LV_FINDINFO lvfi;
  604. lvfi.flags = LVFI_STRING;
  605. lvfi.psz = pLinkInfo->szLnkName;
  606. INT iItem = ListView_FindItem(_hwndLV, -1, &lvfi);
  607. if (iItem == -1)
  608. {
  609. return FALSE;
  610. }
  611. LV_ITEM lvi;
  612. lvi.mask = LVIF_PARAM;
  613. lvi.iItem = iItem;
  614. lvi.iSubItem = 0;
  615. BOOL fOk = ListView_GetItem(_hwndLV, &lvi);
  616. if (!fOk)
  617. {
  618. DEBUG_OUT_LASTERROR;
  619. return FALSE;
  620. }
  621. LPLINKINFO pliInserted = (LPLINKINFO) lvi.lParam;
  622. DEBUG_ASSERT(pliInserted);
  623. return !lstrcmpi(pLinkInfo->szExeVersionInfo,
  624. pliInserted->szExeVersionInfo);
  625. }
  626. //+--------------------------------------------------------------------------
  627. //
  628. // Member: CSelectProgramPage::_AddAppToListView
  629. //
  630. // Synopsis: Add an entry to the listview and its image list for the
  631. // application specified by [pLinkInfo].
  632. //
  633. // Arguments: [plvi] - all fields valid except pszText, lParam,
  634. // and iImage.
  635. // [hSmallImageList] - listview's small icon imagelist
  636. // [pLinkInfo] - describes app to insert info on
  637. //
  638. // Returns: HRESULT
  639. //
  640. // Modifies: pszText, lparam, and iImage fields of [plvi]; contents of
  641. // [hSmallImageList].
  642. //
  643. // History: 5-20-1997 DavidMun Created
  644. //
  645. //---------------------------------------------------------------------------
  646. HRESULT
  647. CSelectProgramPage::_AddAppToListView(
  648. LV_ITEM *plvi,
  649. HIMAGELIST hSmallImageList,
  650. LPLINKINFO pLinkInfo)
  651. {
  652. HRESULT hr = S_OK;
  653. plvi->pszText = pLinkInfo->szLnkName;
  654. plvi->lParam = (LPARAM) pLinkInfo;
  655. if (hSmallImageList)
  656. {
  657. TCHAR tszExeFullPath[MAX_PATH +1];
  658. StringCchPrintf(tszExeFullPath,
  659. MAX_PATH +1,
  660. TEXT("%s\\%s"),
  661. pLinkInfo->szExePath,
  662. pLinkInfo->szExeName);
  663. plvi->iImage = InsertSmallIcon(hSmallImageList, tszExeFullPath);
  664. if (plvi->iImage == -1)
  665. {
  666. plvi->iImage = 0;
  667. }
  668. }
  669. INT iIndex = ListView_InsertItem(_hwndLV, plvi);
  670. if (iIndex == -1)
  671. {
  672. hr = E_FAIL;
  673. DEBUG_OUT_LASTERROR;
  674. return hr;
  675. }
  676. ListView_SetItemText(_hwndLV,
  677. iIndex,
  678. COL_VERSION,
  679. pLinkInfo->szExeVersionInfo);
  680. plvi->iItem++;
  681. return hr;
  682. }
  683. //+--------------------------------------------------------------------------
  684. //
  685. // Function: InsertSmallIcon
  686. //
  687. // Synopsis: Extract the small icon from [tszExeName] and add it to
  688. // [hSmallImageList].
  689. //
  690. // Arguments: [hSmallImageList] - handle to small icon imagelist
  691. // [tszExeName] - full path to executable
  692. //
  693. // Returns: Index of new entry or -1 if [tszExeName] doesn't have a
  694. // small icon or an error occurred.
  695. //
  696. // History: 5-20-1997 DavidMun Created
  697. //
  698. //---------------------------------------------------------------------------
  699. INT
  700. InsertSmallIcon(
  701. HIMAGELIST hSmallImageList,
  702. LPCTSTR tszExeName)
  703. {
  704. HICON hSmallIcon = NULL;
  705. UINT uiResult;
  706. uiResult = TS_ExtractIconEx(tszExeName, 0, &hSmallIcon, 1, GetSystemMetrics(SM_CXSMICON));
  707. if (!hSmallIcon)
  708. {
  709. DEBUG_OUT((DEB_IWARN, "Can't find icon for app '%s'\n", tszExeName));
  710. }
  711. if (uiResult)
  712. {
  713. INT retVal;
  714. DEBUG_ASSERT(hSmallIcon);
  715. retVal = ImageList_AddIcon(hSmallImageList, hSmallIcon);
  716. if( hSmallIcon && !DestroyIcon( hSmallIcon ) )
  717. {
  718. CHECK_LASTERROR(GetLastError());
  719. }
  720. return retVal;
  721. }
  722. CHECK_LASTERROR(GetLastError());
  723. return -1;
  724. }
  725. //+--------------------------------------------------------------------------
  726. //
  727. // Member: CSelectProgramPage::GetExeName
  728. //
  729. // Synopsis: Fill [tszBuf] with the name of the executable selected by
  730. // the user.
  731. //
  732. // Arguments: [tszBuf] - buffer to receive name
  733. // [cchBuf] - size, in characters, of buffer
  734. //
  735. // Modifies: *[tszBuf]
  736. //
  737. // History: 10-28-1997 DavidMun Created
  738. //
  739. //---------------------------------------------------------------------------
  740. VOID
  741. CSelectProgramPage::GetExeName(
  742. LPTSTR tszBuf,
  743. ULONG cchBuf)
  744. {
  745. LPTSTR ptszExeName;
  746. if (_fUseBrowseSelection)
  747. {
  748. ptszExeName = _tszExeName;
  749. }
  750. else
  751. {
  752. ptszExeName = _pSelectedLinkInfo->szExeName;
  753. }
  754. lstrcpyn(tszBuf, ptszExeName, cchBuf);
  755. }
  756. //+--------------------------------------------------------------------------
  757. //
  758. // Member: CSelectProgramPage::GetExeFullPath
  759. //
  760. // Synopsis: Fill [tszBuf] with the full path to the executable selected
  761. // by the user.
  762. //
  763. // Arguments: [tszBuf] - buffer to receive path
  764. // [cchBuf] - size, in characters, of buffer
  765. //
  766. // Modifies: *[tszBuf]
  767. //
  768. // History: 5-20-1997 DavidMun Created
  769. //
  770. //---------------------------------------------------------------------------
  771. VOID
  772. CSelectProgramPage::GetExeFullPath(
  773. LPTSTR tszBuf,
  774. ULONG cchBuf)
  775. {
  776. LPTSTR ptszExePath;
  777. LPTSTR ptszExeName;
  778. if (_fUseBrowseSelection)
  779. {
  780. ptszExePath = _tszExePath;
  781. ptszExeName = _tszExeName;
  782. }
  783. else
  784. {
  785. ptszExePath = _pSelectedLinkInfo->szExePath;
  786. ptszExeName = _pSelectedLinkInfo->szExeName;
  787. }
  788. ULONG cchRequired = lstrlen(ptszExePath) +
  789. 1 + // backslash
  790. lstrlen(ptszExeName) +
  791. 1; // terminating null
  792. // if there's not enough room in the buffer for the whole path
  793. // just copy the executable name
  794. if (cchRequired > cchBuf)
  795. {
  796. lstrcpyn(tszBuf, ptszExeName, cchBuf);
  797. }
  798. else
  799. {
  800. StringCchCopy(tszBuf, cchBuf, ptszExePath);
  801. StringCchCat(tszBuf, cchBuf, TEXT("\\"));
  802. StringCchCat(tszBuf, cchBuf, ptszExeName);
  803. }
  804. }
  805. //+--------------------------------------------------------------------------
  806. //
  807. // Function: FixupRemoteLink
  808. //
  809. // Synopsis: determine whether a link came from another computer
  810. // If so, append server name
  811. //
  812. // History: 5-24-2002 hhance Created
  813. //
  814. // Notes: assumes that exePath is MAX_PATH long
  815. //
  816. //---------------------------------------------------------------------------
  817. void FixupRemoteLink(LPCWSTR linkPath, LPWSTR exePath)
  818. {
  819. // step one - if the exePath is already a UNC name, do nothing
  820. if ((exePath[0] == L'\\') &&
  821. (exePath[1] == L'\\'))
  822. return;
  823. WCHAR drive[4];
  824. StringCchCopyN(drive, 4, linkPath, 3);
  825. if ((drive[1] == L':') &&
  826. (drive[2] == L'\\') &&
  827. (GetDriveType(drive) == DRIVE_REMOTE))
  828. {
  829. // now we only want the drive letter
  830. drive[2] = L'\0';
  831. // we know the link file exists on a remote drive
  832. // therefore, the path is based on ANOTHER machine somewhere.
  833. WCHAR serverName[MAX_PATH];
  834. DWORD dLength = MAX_PATH;
  835. if (0 == WNetGetConnection(drive, serverName, &dLength)
  836. && ((wcslen(serverName) + wcslen(exePath) +1) <= MAX_PATH))
  837. {
  838. // server name will be of the form \\machine\c$
  839. // but all we need is "\\machine\"
  840. WCHAR* pChar = wcsrchr(serverName, L'\\');
  841. if (pChar)
  842. {
  843. *(pChar +1) = L'\0';
  844. WCHAR copyBuf[MAX_PATH +1];
  845. StringCchCopy(copyBuf, MAX_PATH +1, exePath);
  846. StringCchCopy(exePath, MAX_PATH +1, serverName);
  847. StringCchCat(exePath, MAX_PATH +1, copyBuf);
  848. // and make it C$ rather than C: ...
  849. WCHAR* pChar = wcschr(exePath, L':');
  850. if (pChar)
  851. *pChar = L'$';
  852. }
  853. }
  854. }
  855. // maybe they've keyed in a UNC name all by their little lonesomes
  856. // we're expecting \\servername\somepath at this point
  857. else if ((linkPath[0] == L'\\') &&
  858. (linkPath[1] == L'\\'))
  859. {
  860. WCHAR copyBuf[MAX_PATH +1];
  861. StringCchCopy(copyBuf, MAX_PATH +1, linkPath);
  862. WCHAR* pChar = wcschr(&copyBuf[2], L'\\');
  863. // Shouldn't be able to get here otherwise
  864. // if we did - we'll let them get what they've asked for.
  865. if (!pChar)
  866. return;
  867. // append exepath right behind the backwhack
  868. StringCchCopy(pChar +1, MAX_PATH +1 - (pChar - copyBuf), exePath);
  869. // make it C$ rather than C: ...
  870. pChar = wcschr(copyBuf, L':');
  871. if (pChar)
  872. *pChar = L'$';
  873. // and copy it into the output buffer
  874. StringCchCopy(exePath, MAX_PATH +1, copyBuf);
  875. }
  876. }
  877. //+--------------------------------------------------------------------------
  878. //
  879. // Member: CSelectProgramPage::_OnBrowse
  880. //
  881. // Synopsis: Allow the user to set the task's application via a common
  882. // file open dialog.
  883. //
  884. // History: 5-20-1997 DavidMun Created
  885. //
  886. // Notes: If successful, advances to the next page.
  887. //
  888. //---------------------------------------------------------------------------
  889. VOID
  890. CSelectProgramPage::_OnBrowse()
  891. {
  892. TRACE_METHOD(CSelectProgramPage, _OnBrowse);
  893. TCHAR tszDefExt[5];
  894. TCHAR tszFilter[MAX_PATH];
  895. TCHAR tszTitle[100];
  896. DWORD dwFlags = OFN_HIDEREADONLY |
  897. OFN_FILEMUSTEXIST |
  898. OFN_NOCHANGEDIR |
  899. OFN_NONETWORKBUTTON |
  900. OFN_PATHMUSTEXIST;
  901. LoadStr(IDS_EXE, tszDefExt, ARRAYLEN(tszDefExt));
  902. LoadStr(IDS_WIZARD_BROWSE_CAPTION, tszTitle, ARRAYLEN(tszTitle));
  903. SecureZeroMemory(tszFilter, sizeof tszFilter);
  904. LoadStr(IDS_WIZARD_FILTER, tszFilter, ARRAYLEN(tszFilter));
  905. OPENFILENAME ofn;
  906. SecureZeroMemory(&ofn, sizeof(ofn));
  907. _tszExeName[0] = TEXT('\0');
  908. _tszExePath[0] = TEXT('\0');
  909. // Set up info for common file open dialog.
  910. ofn.lStructSize = CDSIZEOF_STRUCT(OPENFILENAME, lpTemplateName);
  911. ofn.hwndOwner = Hwnd();
  912. ofn.lpstrFilter = tszFilter;
  913. ofn.nFilterIndex = 1;
  914. ofn.lpstrFile = _tszExePath;
  915. ofn.nMaxFile = MAX_PATH;
  916. ofn.lpstrFileTitle = _tszExeName;
  917. ofn.nMaxFileTitle = MAX_PATH;
  918. ofn.lpstrInitialDir = TEXT("\\");
  919. ofn.lpstrTitle = tszTitle;
  920. ofn.Flags = dwFlags;
  921. ofn.lpstrDefExt = tszDefExt;
  922. //
  923. // Invoke the dialog. If the user makes a selection and hits OK, record
  924. // the name selected and go on to the trigger selection page.
  925. //
  926. if (GetOpenFileName(&ofn))
  927. {
  928. PathRemoveFileSpec(_tszExePath);
  929. LPTSTR ptszLastSlash = _tcsrchr(_tszExePath, TEXT('\\'));
  930. if (ptszLastSlash && lstrlen(ptszLastSlash) == 1)
  931. {
  932. *ptszLastSlash = TEXT('\0');
  933. }
  934. _fUseBrowseSelection = TRUE;
  935. // if the user chose a link, resolve the link
  936. TCHAR tszFullPath[MAX_PATH +1];
  937. GetExeFullPath(tszFullPath, ARRAYLEN(tszFullPath));
  938. if (*tszFullPath != TEXT('\0'))
  939. {
  940. LPTSTR ptszExt = PathFindExtension(tszFullPath);
  941. if (ptszExt && !_tcsicmp(ptszExt, TEXT(".LNK")))
  942. {
  943. TCHAR szLnkPath[MAX_PATH +1] = {TEXT('\0')};
  944. TCHAR szArguments[MAX_PATH] = {TEXT('\0')};
  945. WIN32_FIND_DATA wfdExeData;
  946. if (ResolveLnk(tszFullPath, szLnkPath, &wfdExeData, szArguments) == 0)
  947. {
  948. ptszLastSlash = _tcsrchr(szLnkPath, TEXT('\\'));
  949. if (ptszLastSlash)
  950. {
  951. lstrcpyn(_tszExeName, ptszLastSlash + 1, MAX_PATH);
  952. *ptszLastSlash = TEXT('\0');
  953. lstrcpyn(_tszExePath, szLnkPath, MAX_PATH);
  954. // got this far. Now need to see whether this is a remote link
  955. FixupRemoteLink(tszFullPath, _tszExePath);
  956. }
  957. }
  958. }
  959. }
  960. PropSheet_PressButton(GetParent(Hwnd()), PSBTN_NEXT);
  961. }
  962. else
  963. {
  964. // user hit cancel or an error occurred
  965. if (CommDlgExtendedError())
  966. {
  967. DEBUG_OUT((DEB_ERROR,
  968. "GetOpenFileName failed<0x%x>\n",
  969. CommDlgExtendedError()));
  970. }
  971. }
  972. }