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.

1495 lines
44 KiB

  1. //
  2. // Browse.C
  3. //
  4. // Copyright (C) Microsoft, 1994,1995 All Rights Reserved.
  5. //
  6. // History:
  7. // ral 5/23/94 - First pass
  8. // 3/20/95 [stevecat] - NT port & real clean up, unicode, etc.
  9. //
  10. //
  11. #include "priv.h"
  12. #include "appwiz.h"
  13. #include "util.h"
  14. #ifdef WINNT
  15. #include <uastrfnc.h>
  16. #endif
  17. #ifdef WINNT
  18. #ifndef DOWNLEVEL_PLATFORM
  19. #include <tsappcmp.h> // for TermsrvAppInstallMode
  20. #endif // DOWNLEVEL_PLATFORM
  21. #endif // WINNT
  22. // Copied from shelldll\ole2dup.h
  23. #define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  24. //
  25. // Initialize the browse property sheet. Limit the size of the edit control.
  26. //
  27. void BrowseInitPropSheet(HWND hDlg, LPARAM lParam)
  28. {
  29. LPWIZDATA lpwd = InitWizSheet(hDlg, lParam, 0);
  30. Edit_LimitText(GetDlgItem(hDlg, IDC_COMMAND), ARRAYSIZE(lpwd->szExeName)-1);
  31. #ifndef DOWNLEVEL_PLATFORM
  32. if (FAILED(SHAutoComplete(GetDlgItem(hDlg, IDC_COMMAND), 0)))
  33. {
  34. TraceMsg(TF_WARNING, "%s", "WARNING: Create Shortcut wizard won't AutoComplete because: 1) bad registry, 2) bad OleInit, or 3) Out of memory.");
  35. }
  36. #endif //DOWNLEVEL_PLATFORM
  37. }
  38. //
  39. // Sets the appropriate wizard buttons. If there's any text in the
  40. // edit control then Next is enabled. Otherwise, Next and Back are both
  41. // grey.
  42. //
  43. void SetBrowseButtons(LPWIZDATA lpwd)
  44. {
  45. BOOL fIsText = GetWindowTextLength(GetDlgItem(lpwd->hwnd, IDC_COMMAND)) > 0;
  46. BOOL fIsSetup = (lpwd->dwFlags & WDFLAG_SETUPWIZ);
  47. int iBtns = fIsSetup ? PSWIZB_BACK : 0;
  48. if (fIsSetup)
  49. {
  50. #ifndef DOWNLEVEL_PLATFORM
  51. #ifdef WINNT
  52. // Are we running Terminal Service? Is this user an Admin?
  53. if (IsTerminalServicesRunning() && IsUserAnAdmin())
  54. {
  55. lpwd->bTermSrvAndAdmin = TRUE;
  56. iBtns |= fIsText ? PSWIZB_NEXT : PSWIZB_DISABLEDFINISH;
  57. }
  58. else
  59. #endif // WINNT
  60. #endif // DOWNLEVEL_PLATFORM
  61. iBtns |= fIsText ? PSWIZB_FINISH : PSWIZB_DISABLEDFINISH;
  62. }
  63. else
  64. {
  65. if (fIsText)
  66. {
  67. iBtns |= PSWIZB_NEXT;
  68. }
  69. }
  70. PropSheet_SetWizButtons(GetParent(lpwd->hwnd), iBtns);
  71. }
  72. //
  73. // NOTES: 1) This function assumes that lpwd->hwnd has already been set to
  74. // the dialogs hwnd. 2) This function is called from NextPushed
  75. // if the application specified can not be found.
  76. //
  77. // BrowseSetActive enables the next button and sets the focus to the edit
  78. // control by posting a POKEFOCUS message.
  79. //
  80. void BrowseSetActive(LPWIZDATA lpwd)
  81. {
  82. //
  83. // NOTE: We re-use the szProgDesc string since it will always be reset
  84. // when this page is activated. Use it to construct a command line.
  85. //
  86. #define szCmdLine lpwd->szProgDesc
  87. lstrcpy(szCmdLine, lpwd->szExeName);
  88. PathQuoteSpaces(szCmdLine);
  89. if (lpwd->szParams[0] != 0)
  90. {
  91. lstrcat(szCmdLine, TEXT(" "));
  92. lstrcat(szCmdLine, lpwd->szParams);
  93. }
  94. Edit_SetText(GetDlgItem(lpwd->hwnd, IDC_COMMAND), szCmdLine);
  95. if (lpwd->dwFlags & WDFLAG_SETUPWIZ)
  96. {
  97. int iHaveHeader = IsTerminalServicesRunning() ? IDS_TSHAVESETUPPRG : IDS_HAVESETUPPRG;
  98. int iHeader = szCmdLine[0] != 0 ? iHaveHeader : IDS_NOSETUPPRG;
  99. TCHAR szInstruct[MAX_PATH];
  100. LoadString(g_hinst, iHeader, szInstruct, ARRAYSIZE(szInstruct));
  101. Static_SetText(GetDlgItem(lpwd->hwnd, IDC_SETUPMSG), szInstruct);
  102. }
  103. SetBrowseButtons(lpwd);
  104. PostMessage(lpwd->hwnd, WMPRIV_POKEFOCUS, 0, 0);
  105. szCmdLine[0] = 0; // Reset progdesc to empty string
  106. #undef szCmdLine
  107. }
  108. //
  109. // Returns TRUE if able to get properties for szExeName from PifMgr. The
  110. // program properties will be read into lpwd->PropPrg.
  111. //
  112. BOOL ReadPifProps(LPWIZDATA lpwd)
  113. {
  114. HANDLE hPifProp;
  115. LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  116. hPifProp = PifMgr_OpenProperties(lpszName, NULL, 0, OPENPROPS_INHIBITPIF);
  117. if (!hPifProp)
  118. {
  119. TraceMsg(TF_ERROR, "%s", "Unable to open properties for DOS exe.");
  120. }
  121. if (hPifProp == 0)
  122. return(FALSE);
  123. PifMgr_GetProperties(hPifProp, (LPSTR)GROUP_PRG, &(lpwd->PropPrg),
  124. sizeof(lpwd->PropPrg), GETPROPS_NONE);
  125. PifMgr_CloseProperties(hPifProp, CLOSEPROPS_DISCARD);
  126. return(TRUE);
  127. }
  128. //
  129. // Returns TRUE if lpwd->szExeName points to a valid exe type. It also sets
  130. // the appropriate flags, such as APPKNOWN and DOSAPP in the wizdata structure
  131. // if the exe is valid.
  132. //
  133. void DetermineExeType(LPWIZDATA lpwd)
  134. {
  135. DWORD dwExeType;
  136. LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  137. lpwd->dwFlags &= ~(WDFLAG_APPKNOWN | WDFLAG_DOSAPP | WDFLAG_SINGLEAPP);
  138. dwExeType = (DWORD)SHGetFileInfo(lpszName, 0, NULL, 0, SHGFI_EXETYPE);
  139. if (LOWORD(dwExeType) != ('M' | ('Z' << 8)))
  140. {
  141. lpwd->dwFlags |= WDFLAG_APPKNOWN;
  142. if (lstrcmpi(PathFindExtension(lpszName), c_szPIF) == 0)
  143. {
  144. lpwd->dwFlags |= WDFLAG_DOSAPP;
  145. }
  146. }
  147. else
  148. {
  149. lpwd->dwFlags |= WDFLAG_DOSAPP;
  150. if (ReadPifProps(lpwd))
  151. {
  152. if ((lpwd->PropPrg.flPrgInit & PRGINIT_INFSETTINGS) ||
  153. ((lpwd->PropPrg.flPrgInit &
  154. (PRGINIT_NOPIF | PRGINIT_DEFAULTPIF)) == 0))
  155. {
  156. lpwd->dwFlags |= WDFLAG_APPKNOWN;
  157. if (lpwd->PropPrg.flPrgInit & PRGINIT_REALMODE)
  158. {
  159. lpwd->dwFlags |= WDFLAG_SINGLEAPP;
  160. }
  161. }
  162. }
  163. }
  164. }
  165. //
  166. // Removes the filename extension (if any) from the string.
  167. //
  168. void StripExt(LPTSTR lpsz)
  169. {
  170. if(lpsz)
  171. {
  172. LPTSTR pExt = PathFindExtension(lpsz);
  173. if (*pExt)
  174. *pExt = 0; // null out the "."
  175. }
  176. }
  177. //
  178. // Sets the working directory as appropriate for the file type.
  179. //
  180. void FindWorkingDir(LPWIZDATA lpwd)
  181. {
  182. LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  183. #ifdef WINNT
  184. TCHAR szWindir[ MAX_PATH ];
  185. DWORD dwLen;
  186. #endif
  187. if (PathIsUNC(lpszName) || PathIsDirectory(lpszName))
  188. {
  189. lpwd->szWorkingDir[0] = 0;
  190. }
  191. else
  192. {
  193. lstrcpy(lpwd->szWorkingDir, lpszName);
  194. PathRemoveFileSpec(lpwd->szWorkingDir);
  195. }
  196. #ifdef WINNT
  197. //
  198. // Okay, at this point we should have the absolute path for the
  199. // working directory of the link. On NT, if the working dir happens to be for
  200. // something in the %Windir% directory (or a subdir of %windir%),
  201. // then store the path as %windir%\blah\blah\blah instead of as an
  202. // absolute path. This will help with interoperability of shortcuts
  203. // across different machines, etc. But only do this for shortcuts that
  204. // are already marked as having expandable env strings...
  205. //
  206. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  207. {
  208. dwLen = ExpandEnvironmentStrings( TEXT("%windir%"),
  209. szWindir,
  210. ARRAYSIZE(szWindir)
  211. );
  212. if (dwLen &&
  213. dwLen < ARRAYSIZE(szWindir) &&
  214. lstrlen(szWindir) <= lstrlen(lpwd->szWorkingDir)
  215. )
  216. {
  217. //
  218. // we use dwLen-1 because dwLen includes the '\0' character
  219. //
  220. if (CompareString( LOCALE_SYSTEM_DEFAULT,
  221. NORM_IGNORECASE,
  222. szWindir, dwLen-1 ,
  223. lpwd->szWorkingDir, dwLen-1
  224. ) == 2)
  225. {
  226. TCHAR szWorkingDir[ MAX_PATH ];
  227. //
  228. // We should substitute the env variable for the
  229. // actual string here...
  230. //
  231. ualstrcpy( szWorkingDir, lpwd->szWorkingDir );
  232. ualstrcpy( lpwd->szWorkingDir, TEXT("%windir%") );
  233. // 8 == lstrlen("%windir%")
  234. ualstrcpy( lpwd->szWorkingDir + 12, szWorkingDir+dwLen-1 );
  235. }
  236. }
  237. }
  238. #endif // winnt
  239. }
  240. #ifndef NO_NEW_SHORTCUT_HOOK
  241. //
  242. // Returns:
  243. // Hook result or error.
  244. //
  245. // S_OK:
  246. // *pnshhk is the INewShortcutHook of the object to use to save the new Shortcut.
  247. // szProgDesc[] and szExt[] are filled in.
  248. // szExeName[] may be translated.
  249. // otherwise:
  250. // *pnshhk is NULL.
  251. // szProgDesc[] and szExt[] are empty strings.
  252. //
  253. HRESULT QueryNewLinkHandler(LPWIZDATA lpwd, LPCLSID pclsidHook)
  254. {
  255. HRESULT hr;
  256. IUnknown *punk;
  257. LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  258. lpwd->pnshhk = NULL;
  259. #ifdef UNICODE
  260. lpwd->pnshhkA = NULL;
  261. #endif
  262. *(lpwd->szProgDesc) = TEXT('\0');
  263. *(lpwd->szExt) = TEXT('\0');
  264. hr = CoCreateInstance(pclsidHook, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, &punk);
  265. if (hr == S_OK)
  266. {
  267. INewShortcutHook *pnshhk;
  268. hr = punk->lpVtbl->QueryInterface(punk, &IID_INewShortcutHook, &pnshhk);
  269. if (hr == S_OK)
  270. {
  271. hr = pnshhk->lpVtbl->SetReferent(pnshhk, lpszName, lpwd->hwnd);
  272. if (hr == S_OK)
  273. {
  274. hr = pnshhk->lpVtbl->SetFolder(pnshhk, lpwd->lpszFolder);
  275. if (hr == S_OK)
  276. {
  277. hr = pnshhk->lpVtbl->GetName(pnshhk, lpwd->szProgDesc,
  278. ARRAYSIZE(lpwd->szProgDesc));
  279. if (hr == S_OK)
  280. {
  281. hr = pnshhk->lpVtbl->GetExtension(pnshhk, lpwd->szExt,
  282. ARRAYSIZE(lpwd->szExt));
  283. if (hr == S_OK)
  284. hr = pnshhk->lpVtbl->GetReferent(pnshhk, lpszName,
  285. ARRAYSIZE(lpwd->szExeName));
  286. }
  287. }
  288. }
  289. if (hr == S_OK)
  290. lpwd->pnshhk = pnshhk;
  291. else
  292. pnshhk->lpVtbl->Release(pnshhk);
  293. }
  294. #ifdef UNICODE
  295. else
  296. {
  297. INewShortcutHookA *pnshhkA;
  298. hr = punk->lpVtbl->QueryInterface(punk, &IID_INewShortcutHookA, &pnshhkA);
  299. if (hr == S_OK)
  300. {
  301. UINT cFolderA = WideCharToMultiByte(CP_ACP,0,lpwd->lpszFolder,-1,NULL,0,0,0)+1;
  302. LPSTR lpszFolderA = (LPSTR)LocalAlloc(LPTR,cFolderA*SIZEOF(CHAR));
  303. if (NULL == lpszFolderA)
  304. {
  305. hr = E_OUTOFMEMORY;
  306. }
  307. else
  308. {
  309. CHAR szNameA[MAX_PATH];
  310. CHAR szProgDescA[MAX_PATH];
  311. CHAR szExtA[MAX_PATH];
  312. WideCharToMultiByte(CP_ACP, 0,
  313. lpszName, -1,
  314. szNameA, ARRAYSIZE(szNameA),
  315. 0, 0);
  316. WideCharToMultiByte(CP_ACP, 0,
  317. lpwd->lpszFolder, -1,
  318. lpszFolderA, cFolderA,
  319. 0, 0);
  320. hr = pnshhkA->lpVtbl->SetReferent(pnshhkA, szNameA, lpwd->hwnd);
  321. if (hr == S_OK)
  322. {
  323. hr = pnshhkA->lpVtbl->SetFolder(pnshhkA, lpszFolderA);
  324. if (hr == S_OK)
  325. {
  326. hr = pnshhkA->lpVtbl->GetName(pnshhkA, szProgDescA,
  327. ARRAYSIZE(szProgDescA));
  328. if (hr == S_OK)
  329. {
  330. MultiByteToWideChar(CP_ACP, 0,
  331. szProgDescA, -1,
  332. lpwd->szProgDesc, ARRAYSIZE(lpwd->szProgDesc));
  333. hr = pnshhkA->lpVtbl->GetExtension(pnshhkA, szExtA,
  334. ARRAYSIZE(szExtA));
  335. if (hr == S_OK)
  336. {
  337. MultiByteToWideChar(CP_ACP, 0,
  338. szExtA, -1,
  339. lpwd->szExt, ARRAYSIZE(lpwd->szExt));
  340. hr = pnshhkA->lpVtbl->GetReferent(pnshhkA, szNameA,
  341. ARRAYSIZE(szNameA));
  342. MultiByteToWideChar(CP_ACP, 0,
  343. szExtA, -1,
  344. lpszName, ARRAYSIZE(lpwd->szExeName));
  345. }
  346. }
  347. }
  348. }
  349. if (hr == S_OK)
  350. lpwd->pnshhkA = pnshhkA;
  351. else
  352. pnshhkA->lpVtbl->Release(pnshhkA);
  353. LocalFree(lpszFolderA);
  354. }
  355. }
  356. }
  357. #endif
  358. punk->lpVtbl->Release(punk);
  359. }
  360. return(hr);
  361. }
  362. const TCHAR c_szNewLinkHandlers[] = REGSTR_PATH_EXPLORER TEXT("\\NewShortcutHandlers");
  363. //
  364. // Sets lpwd->pnshhk to NULL for CLSID_ShellLink (default) or to the
  365. // INewShortcutHook of the object to be used.
  366. //
  367. // If lpwd->pnshhk is returned non-NULL, szProgDesc[] and szExt[] are also
  368. // filled in.
  369. //
  370. void DetermineLinkHandler(LPWIZDATA lpwd)
  371. {
  372. HKEY hkeyHooks;
  373. // Lose any previously saved external new Shortcut handler.
  374. if (lpwd->pnshhk)
  375. {
  376. lpwd->pnshhk->lpVtbl->Release(lpwd->pnshhk);
  377. lpwd->pnshhk = NULL;
  378. }
  379. #ifdef UNICODE
  380. if (lpwd->pnshhkA)
  381. {
  382. lpwd->pnshhkA->lpVtbl->Release(lpwd->pnshhkA);
  383. lpwd->pnshhkA = NULL;
  384. }
  385. #endif
  386. //
  387. // Enumerate the list of new link handlers. Each new link handler is
  388. // registered as a GUID value under c_szNewLinkHandlers.
  389. //
  390. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szNewLinkHandlers, &hkeyHooks)
  391. == ERROR_SUCCESS)
  392. {
  393. DWORD dwiValue;
  394. TCHAR szCLSID[GUIDSTR_MAX];
  395. DWORD dwcbCLSIDLen;
  396. //
  397. // Invoke each hook. A hook returns S_FALSE if it does not wish to
  398. // handle the new link. Stop if a hook returns S_OK.
  399. //
  400. for (dwcbCLSIDLen = ARRAYSIZE(szCLSID), dwiValue = 0;
  401. RegEnumValue(hkeyHooks, dwiValue, szCLSID, &dwcbCLSIDLen, NULL,
  402. NULL, NULL, NULL) == ERROR_SUCCESS;
  403. dwcbCLSIDLen = ARRAYSIZE(szCLSID), dwiValue++)
  404. {
  405. CLSID clsidHook;
  406. if (SHCLSIDFromString(szCLSID, &clsidHook) == S_OK &&
  407. QueryNewLinkHandler(lpwd, &clsidHook) == S_OK)
  408. break;
  409. }
  410. RegCloseKey(hkeyHooks);
  411. }
  412. return;
  413. }
  414. #endif
  415. //
  416. // Returns TRUE if it's OK to go to the next wizard dialog.
  417. //
  418. BOOL NextPushed(LPWIZDATA lpwd)
  419. {
  420. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
  421. // Is the string a path with spaces, without arguments, but isn't correctly
  422. // quoted? NT #d: >C:\Program Files\Windows NT\dialer.exe< is treated like
  423. // "C:\Program" with "Files\Windows NT\dialer.exe" as args.
  424. if (PathFileExists(lpwd->szExeName))
  425. {
  426. // Yes, so let's quote it so we don't treat the stuff after
  427. // the space like args.
  428. PathQuoteSpaces(lpwd->szExeName);
  429. }
  430. PathRemoveBlanks(lpwd->szExeName);
  431. if (lpwd->szExeName[0] != 0)
  432. {
  433. BOOL bUNC;
  434. LPTSTR lpszTarget = NULL;
  435. HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  436. LPTSTR lpszArgs = PathGetArgs(lpwd->szExeName);
  437. lstrcpy(lpwd->szParams, lpszArgs);
  438. if (*lpszArgs)
  439. {
  440. *(lpszArgs - 1) = 0; // clobber the ' ' in the exe name field
  441. }
  442. ExpandEnvironmentStrings( lpwd->szExeName,
  443. lpwd->szExpExeName,
  444. ARRAYSIZE(lpwd->szExpExeName)
  445. );
  446. lpwd->szExpExeName[ MAX_PATH-1 ] = TEXT('\0');
  447. if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName))
  448. lpwd->dwFlags |= WDFLAG_EXPSZ;
  449. lpszTarget = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  450. PathUnquoteSpaces(lpszTarget);
  451. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  452. PathUnquoteSpaces(lpwd->szExeName);
  453. lpwd->dwFlags &= ~WDFLAG_COPYLINK;
  454. #ifndef NO_NEW_SHORTCUT_HOOK
  455. //
  456. // Figure out who wants to handle this string as a link referent.
  457. //
  458. DetermineLinkHandler(lpwd);
  459. if (lpwd->pnshhk)
  460. {
  461. //
  462. // We are using an external link handler. Skip file system
  463. // validation.
  464. //
  465. lpwd->dwFlags |= WDFLAG_APPKNOWN;
  466. SetCursor(hcurOld);
  467. return(TRUE);
  468. }
  469. #ifdef UNICODE
  470. if (lpwd->pnshhkA)
  471. {
  472. //
  473. // We are using an external link handler. Skip file system
  474. // validation.
  475. //
  476. lpwd->dwFlags |= WDFLAG_APPKNOWN;
  477. SetCursor(hcurOld);
  478. return(TRUE);
  479. }
  480. #endif
  481. #endif
  482. bUNC = PathIsUNC(lpszTarget);
  483. if (bUNC && !SHValidateUNC(lpwd->hwnd, lpszTarget, FALSE))
  484. goto Done;
  485. //
  486. // If the user tries to make a link to A:\ and there's no disk
  487. // in the drive, PathResolve would fail. So, for drive roots, we
  488. // don't try to resolve it.
  489. //
  490. if ((PathIsRoot(lpszTarget) && !bUNC &&
  491. DriveType(DRIVEID(lpszTarget))) ||
  492. PathResolve(lpszTarget, NULL,
  493. PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS))
  494. {
  495. //
  496. // If we found a PIF file then we'll try to convert it to the
  497. // name of the file it points to.
  498. //
  499. if (lstrcmpi(PathFindExtension(lpszTarget), c_szPIF) == 0)
  500. {
  501. if (!ReadPifProps(lpwd))
  502. {
  503. goto Done;
  504. }
  505. #ifdef UNICODE
  506. MultiByteToWideChar(CP_ACP, 0, lpwd->PropPrg.achCmdLine, -1,
  507. lpszTarget, ARRAYSIZE(lpwd->szExeName));
  508. #else
  509. lstrcpy(lpszTarget, lpwd->PropPrg.achCmdLine);
  510. #endif // UNICODE
  511. PathRemoveArgs(lpszTarget);
  512. if (!PathResolve(lpszTarget, NULL,
  513. PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS))
  514. {
  515. goto Done;
  516. }
  517. }
  518. #ifdef WINNT
  519. //
  520. // Okay, at this point we should have the absolute path for the
  521. // target of the link. On NT, if the target happens to be for
  522. // something in the %Windir% directory (or a subdir of %Windir%),
  523. // AND the user didn't type in an expandable path already, then
  524. // store the path as %windir%\blah\blah\blah instead of as an
  525. // absolute path. This will help with interoperability of shortcuts
  526. // across different machines, etc.
  527. //
  528. if (!(lpwd->dwFlags & WDFLAG_EXPSZ))
  529. {
  530. TCHAR szWindir[ MAX_PATH ];
  531. DWORD dwLen;
  532. //
  533. // What did the user type in?
  534. //
  535. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, szWindir, ARRAYSIZE(szWindir));
  536. if (ualstrcmpi(szWindir, lpwd->szExeName)==0)
  537. {
  538. //
  539. // If we didn't change it, it means the user typed in an
  540. // exact path. In that case, don't try to map anyting.
  541. //
  542. goto LinkToALinkCase;
  543. }
  544. dwLen = ExpandEnvironmentStrings( TEXT("%windir%"),
  545. szWindir,
  546. ARRAYSIZE(szWindir)
  547. );
  548. if (dwLen &&
  549. dwLen < ARRAYSIZE(szWindir) &&
  550. lstrlen(szWindir) <= lstrlen(lpszTarget)
  551. )
  552. {
  553. //
  554. // we use dwLen-1 because dwLen includes the '\0' character
  555. //
  556. if (CompareString( LOCALE_SYSTEM_DEFAULT,
  557. NORM_IGNORECASE,
  558. szWindir, dwLen-1 ,
  559. lpszTarget, dwLen-1
  560. ) == 2)
  561. {
  562. //
  563. // We should substitute the env variable for the
  564. // actual string here...
  565. //
  566. lstrcpy( lpwd->szExpExeName, lpwd->szExeName );
  567. lstrcpy( lpwd->szExeName, TEXT("%windir%") );
  568. // 8 == lstrlen("%windir%")
  569. ualstrcpy( lpwd->szExeName + 8, lpwd->szExpExeName+dwLen-1 );
  570. lpwd->dwFlags |= WDFLAG_EXPSZ;
  571. lpszTarget = lpwd->szExpExeName;
  572. }
  573. }
  574. }
  575. #endif // winnt
  576. #ifdef WINNT
  577. //
  578. // Okay, at this point we should have the absolute path for the
  579. // target of the link. On NT, if the target happens to be for
  580. // something in the %Windir% directory (or a subdir of %Windir%),
  581. // AND the user didn't type in an expandable path already, then
  582. // store the path as %windir%\blah\blah\blah instead of as an
  583. // absolute path. This will help with interoperability of shortcuts
  584. // across different machines, etc.
  585. //
  586. if (!(lpwd->dwFlags & WDFLAG_EXPSZ))
  587. {
  588. TCHAR szWindir[ MAX_PATH ];
  589. DWORD dwLen;
  590. //
  591. // What did the user type in?
  592. //
  593. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, szWindir, ARRAYSIZE(szWindir));
  594. if (ualstrcmpi(szWindir, lpwd->szExeName)==0)
  595. {
  596. //
  597. // If we didn't change it, it means the user typed in an
  598. // exact path. In that case, don't try to map anyting.
  599. //
  600. goto LinkToALinkCase;
  601. }
  602. dwLen = ExpandEnvironmentStrings( TEXT("%windir%"),
  603. szWindir,
  604. ARRAYSIZE(szWindir)
  605. );
  606. if (dwLen &&
  607. dwLen < ARRAYSIZE(szWindir) &&
  608. lstrlen(szWindir) <= lstrlen(lpszTarget)
  609. )
  610. {
  611. //
  612. // we use dwLen-1 because dwLen includes the '\0' character
  613. //
  614. if (CompareString( LOCALE_SYSTEM_DEFAULT,
  615. NORM_IGNORECASE,
  616. szWindir, dwLen-1 ,
  617. lpszTarget, dwLen-1
  618. ) == 2)
  619. {
  620. //
  621. // We should substitute the env variable for the
  622. // actual string here...
  623. //
  624. lstrcpy( lpwd->szExpExeName, lpwd->szExeName );
  625. lstrcpy( lpwd->szExeName, TEXT("%windir%") );
  626. // 8 == lstrlen("%windir%")
  627. ualstrcpy( lpwd->szExeName + 8, lpwd->szExpExeName+dwLen-1 );
  628. lpwd->dwFlags |= WDFLAG_EXPSZ;
  629. lpszTarget = lpwd->szExpExeName;
  630. }
  631. }
  632. }
  633. LinkToALinkCase:
  634. #endif // winnt
  635. //
  636. // Really, really obscure case. The user creates "New Shortcut" and
  637. // tries to point it to itself. Don't allow it. We'd be confused
  638. // later. Since it's so obscure, just give a generic error about
  639. // "Can't find this file"
  640. //
  641. if (!(lpwd->lpszOriginalName &&
  642. lstrcmpi(lpwd->lpszOriginalName, lpszTarget) == 0))
  643. {
  644. DetermineExeType(lpwd);
  645. FindWorkingDir(lpwd);
  646. lpwd->szProgDesc[0] = 0; // Reset description
  647. // EVEN IF WE DON'T RECREATE IT HERE!
  648. if (lpwd->lpszFolder && lpwd->lpszFolder[0] != 0 &&
  649. !DetermineDefaultTitle(lpwd))
  650. {
  651. goto Done;
  652. }
  653. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  654. {
  655. LPTSTR lpszExt = PathFindExtension( lpwd->szExeName );
  656. if (!(*lpszExt))
  657. {
  658. // do simple check to make sure there was a file name
  659. // at the end of the original entry. we assume that
  660. // if we got this far, lpszExt points to the end of
  661. // the string pointed to by lpwd->szExeName, and that
  662. // lpwd->szExeName has at least one character in it.
  663. if (lpwd->szExeName &&
  664. (*lpwd->szExeName) &&
  665. (*(lpszExt-1)!=TEXT('%'))
  666. )
  667. {
  668. lstrcpy( lpszExt, PathFindExtension( lpszTarget ) );
  669. }
  670. }
  671. }
  672. SetCursor(hcurOld);
  673. return(TRUE);
  674. }
  675. }
  676. Done:
  677. SetCursor(hcurOld);
  678. ShellMessageBox(g_hinst, lpwd->hwnd, MAKEINTRESOURCE(IDS_BADPATHMSG), 0, MB_OK | MB_ICONEXCLAMATION, lpwd->szExeName);
  679. }
  680. BrowseSetActive(lpwd);
  681. return(FALSE);
  682. }
  683. //
  684. // Returns TRUE if it's OK to run the setup program.
  685. //
  686. BOOL SetupCleanupExePath(LPWIZDATA lpwd)
  687. {
  688. BOOL fValidPrg = FALSE;
  689. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
  690. // Is the string a path with spaces, without arguments, but isn't correctly
  691. // quoted? NT #d: >C:\Program Files\Windows NT\dialer.exe< is treated like
  692. // "C:\Program" with "Files\Windows NT\dialer.exe" as args.
  693. if (PathFileExists(lpwd->szExeName))
  694. {
  695. // Yes, so let's quote it so we don't treat the stuff after
  696. // the space like args.
  697. PathQuoteSpaces(lpwd->szExeName);
  698. }
  699. PathRemoveBlanks(lpwd->szExeName);
  700. if (lpwd->szExeName[0] != 0)
  701. {
  702. LPTSTR lpszTarget = NULL;
  703. LPTSTR lpszArgs = NULL;
  704. HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  705. ExpandEnvironmentStrings( lpwd->szExeName,
  706. lpwd->szExpExeName,
  707. ARRAYSIZE(lpwd->szExpExeName)
  708. );
  709. if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName))
  710. lpwd->dwFlags |= WDFLAG_EXPSZ;
  711. lpszTarget = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
  712. lpszArgs = PathGetArgs(lpszTarget);
  713. lstrcpy(lpwd->szParams, lpszArgs);
  714. if (*lpszArgs)
  715. {
  716. *(lpszArgs - 1) = 0; // clobber the ' ' in the exe name field
  717. }
  718. PathUnquoteSpaces(lpszTarget);
  719. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  720. PathUnquoteSpaces(lpwd->szExeName);
  721. if (PathResolve(lpszTarget, NULL,
  722. PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS))
  723. {
  724. LPTSTR lpszExt = PathFindExtension( lpszTarget );
  725. fValidPrg = TRUE;
  726. FindWorkingDir(lpwd);
  727. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  728. {
  729. if (!(*lpszExt))
  730. {
  731. lstrcpy( lpszExt, PathFindExtension( lpszTarget ) );
  732. }
  733. }
  734. if ((*lpszExt) && lpwd->bTermSrvAndAdmin && (!lstrcmpi(lpszExt, TEXT(".msi"))))
  735. lstrcat(lpwd->szParams, TEXT(" ALLUSERS=1"));
  736. PathQuoteSpaces( lpszTarget );
  737. }
  738. SetCursor(hcurOld);
  739. }
  740. if (!fValidPrg)
  741. {
  742. ShellMessageBox(g_hinst, lpwd->hwnd, MAKEINTRESOURCE(IDS_BADPATHMSG), 0, MB_OK | MB_ICONEXCLAMATION, lpwd->szExeName);
  743. BrowseSetActive(lpwd);
  744. }
  745. return(fValidPrg);
  746. }
  747. BOOL DetermineDefaultTitle(LPWIZDATA lpwd)
  748. {
  749. TCHAR szFullName[MAX_PATH];
  750. BOOL fCopy;
  751. LPTSTR lpszName;
  752. lpwd->dwFlags &= ~WDFLAG_COPYLINK;
  753. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  754. lpszName = lpwd->szExpExeName;
  755. else
  756. lpszName = lpwd->szExeName;
  757. if (!SHGetNewLinkInfo(lpszName, lpwd->lpszFolder, szFullName,
  758. &fCopy, 0))
  759. {
  760. //
  761. // failure...
  762. //
  763. return(FALSE);
  764. }
  765. lpszName = PathFindFileName(szFullName);
  766. StripExt(lpszName);
  767. lstrcpyn(lpwd->szProgDesc, lpszName, ARRAYSIZE(lpwd->szProgDesc));
  768. //
  769. // We will never copy PIF files since they often do not contain
  770. // the appropriate current directory. This is becuase they are
  771. // automatically created when you run a DOS application from the
  772. // shell.
  773. //
  774. if ((lpwd->dwFlags & WDFLAG_DOSAPP) == 0)
  775. {
  776. if (fCopy)
  777. {
  778. lpwd->dwFlags |= WDFLAG_COPYLINK;
  779. }
  780. #ifndef NO_NEW_SHORTCUT_HOOK
  781. lstrcpy(lpwd->szExt, c_szLNK);
  782. }
  783. else
  784. {
  785. lstrcpy(lpwd->szExt, c_szPIF);
  786. #endif
  787. }
  788. return(TRUE);
  789. }
  790. //
  791. // paranoia: evaluate each time in case it is installed after ARP was first open, but
  792. // before it is closed and re-opened
  793. //
  794. BOOL MSI_IsMSIAvailable()
  795. {
  796. BOOL bAvailable = FALSE;
  797. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  798. if (hinst)
  799. {
  800. bAvailable = TRUE;
  801. FreeLibrary(hinst);
  802. }
  803. return bAvailable;
  804. }
  805. //
  806. // Call the common dialog code for File Open
  807. //
  808. BOOL BrowseForExe(HWND hwnd, LPTSTR pszName, DWORD cchName, LPCTSTR pszInitDir)
  809. {
  810. TCHAR szExt[80];
  811. TCHAR szFilter[200];
  812. TCHAR szTitle[80];
  813. TCHAR szBootDir[64];
  814. //
  815. // Must pass the buffer size to GetBootDir because that is what
  816. // the RegQueryValueEx function expects - not count of chars.
  817. //
  818. if (!pszInitDir)
  819. {
  820. GetBootDir(szBootDir, ARRAYSIZE(szBootDir));
  821. }
  822. else
  823. {
  824. // we want to pass in an initial directory since GetFileNameFromBrowse
  825. // try to determine an initial directory by doing a PathRemoveFileSpec
  826. // on pszName. If pszName is already a directory then the last directory
  827. // is removed (even though it's not a file). E.g.: "c:\winnt" -> "c:\"
  828. lstrcpyn(szBootDir, pszInitDir, ARRAYSIZE(szBootDir));
  829. }
  830. if (MSI_IsMSIAvailable())
  831. LoadAndStrip(IDS_BROWSEFILTERMSI, szFilter, ARRAYSIZE(szFilter));
  832. else
  833. LoadAndStrip(IDS_BROWSEFILTER, szFilter, ARRAYSIZE(szFilter));
  834. LoadString(g_hinst, IDS_BROWSEEXT, szExt, ARRAYSIZE(szExt));
  835. LoadString(g_hinst, IDS_BROWSETITLE, szTitle, ARRAYSIZE(szTitle));
  836. // we need to set pszName to NULL or else GetFileNameFromBrowse will use it
  837. // to find the initial directory even though we explicitly pass in an initial
  838. // dir.
  839. *pszName = 0;
  840. return(GetFileNameFromBrowse(hwnd, pszName, cchName,
  841. szBootDir, szExt, szFilter, szTitle));
  842. }
  843. //
  844. // Use the common open dialog to browse for program. Used by SetupBrowseDlgProc
  845. //
  846. void BrowsePushed(LPWIZDATA lpwd)
  847. {
  848. LPTSTR lpszName;
  849. DWORD cchName = 0;
  850. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
  851. ExpandEnvironmentStrings( lpwd->szExeName, lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName) );
  852. if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName))
  853. lpwd->dwFlags |= WDFLAG_EXPSZ;
  854. if (lpwd->dwFlags & WDFLAG_EXPSZ)
  855. {
  856. lpszName = lpwd->szExpExeName;
  857. cchName = ARRAYSIZE(lpwd->szExpExeName);
  858. }
  859. else
  860. {
  861. lpszName = lpwd->szExeName;
  862. cchName = ARRAYSIZE(lpwd->szExeName);
  863. }
  864. if (BrowseForExe(lpwd->hwnd, lpszName, cchName, lpszName))
  865. {
  866. lpwd->szParams[0] = 0;
  867. BrowseSetActive(lpwd);
  868. }
  869. }
  870. int CALLBACK BrowseCallbackProc(
  871. HWND hwnd,
  872. UINT uMsg,
  873. LPARAM lParam,
  874. LPARAM lpData
  875. )
  876. {
  877. LPITEMIDLIST pidlNavigate;
  878. switch (uMsg)
  879. {
  880. case BFFM_INITIALIZED:
  881. // Check if we should navigate to a folder on initialize
  882. pidlNavigate = (LPITEMIDLIST) lpData;
  883. if (pidlNavigate != NULL)
  884. {
  885. // Yes! We have a folder to navigate to; send the message
  886. SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM) FALSE, (LPARAM) pidlNavigate);
  887. }
  888. break;
  889. case BFFM_SELCHANGED:
  890. // Check if we should enable/disable the Ok button
  891. pidlNavigate = (LPITEMIDLIST)lParam;
  892. if (pidlNavigate != NULL)
  893. {
  894. DWORD dwFlags = SFGAO_FILESYSTEM;
  895. WCHAR szName[MAX_PATH] = L"";
  896. if (SUCCEEDED(SHGetNameAndFlags(pidlNavigate, SHGDN_NORMAL, szName, ARRAYSIZE(szName), &dwFlags)))
  897. {
  898. if ((dwFlags & SFGAO_FILESYSTEM) != 0 ||
  899. !lstrncmp(szName, L"\\\\", 2))
  900. {
  901. // Path is either a valid local path
  902. // or a valid network path, enable the ok button
  903. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM)0, (LPARAM)1);
  904. }
  905. else
  906. {
  907. // Path does not exist, disable the ok button
  908. // This could be My Computer or an empty floppy drive etc...
  909. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM)0, (LPARAM)0);
  910. }
  911. }
  912. }
  913. }
  914. return 0;
  915. }
  916. // This implementation of 'Browse' uses SHBrowseForFolder to find a file or folder
  917. // for the shortcut wizard - used by BrowseDlgProc
  918. void BrowseForFileOrFolder(LPWIZDATA lpwd)
  919. {
  920. TCHAR szBrowseTitle[256];
  921. TCHAR szName[MAX_PATH];
  922. BROWSEINFO bi = {0};
  923. LPITEMIDLIST pidlSelected;
  924. LPITEMIDLIST pidlStartBrowse;
  925. IShellFolder* pdesktop;
  926. // Try to start the browse at a location indicated by the typed-in command line,
  927. // if possible
  928. GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
  929. // ..Get the desktop folder
  930. if (SUCCEEDED(SHGetDesktopFolder(&pdesktop)))
  931. {
  932. // ..Now try to parse the path the user entered into a pidl to start at
  933. ULONG chEaten;
  934. #ifdef UNICODE
  935. if (FAILED(pdesktop->lpVtbl->ParseDisplayName(pdesktop, lpwd->hwnd, NULL,
  936. lpwd->szExeName, &chEaten, &pidlStartBrowse, NULL)))
  937. #else
  938. WCHAR szTmp[MAX_PATH];
  939. SHAnsiToUnicode(lpwd->szExeName, szTmp, MAX_PATH);
  940. if (FAILED(pdesktop->lpVtbl->ParseDisplayName(pdesktop, lpwd->hwnd, NULL,
  941. szTmp, &chEaten, &pidlStartBrowse, NULL)))
  942. #endif
  943. {
  944. // The path the user entered didn't make any sense
  945. // pidlStartBrowse should already be NULL, but we want to make sure
  946. pidlStartBrowse = NULL;
  947. }
  948. // Now we can continue and display the browse window
  949. // Load the title string for the browse window
  950. LoadString(g_hinst, IDS_FILEFOLDERBROWSE_TITLE, szBrowseTitle, ARRAYSIZE(szBrowseTitle));
  951. // Note that bi = {0} for all other members except:
  952. bi.hwndOwner = lpwd->hwnd;
  953. bi.pszDisplayName = szName;
  954. bi.lpszTitle = szBrowseTitle;
  955. bi.ulFlags = BIF_BROWSEINCLUDEFILES | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
  956. // Ensure the pidl we want to start at is passed to the callback function
  957. bi.lpfn = BrowseCallbackProc;
  958. bi.lParam = (LPARAM) pidlStartBrowse;
  959. pidlSelected = SHBrowseForFolder(&bi);
  960. if (pidlSelected != NULL)
  961. {
  962. STRRET strret;
  963. if (SUCCEEDED(pdesktop->lpVtbl->GetDisplayNameOf(pdesktop, pidlSelected, SHGDN_NORMAL | SHGDN_FORPARSING, &strret)))
  964. {
  965. StrRetToBuf(&strret, pidlSelected, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
  966. // Assume no parameters for this new file
  967. lpwd->szParams[0] = 0;
  968. // Populate the text box with the new file, etc.
  969. BrowseSetActive(lpwd);
  970. }
  971. // Free the pidl
  972. ILFree(pidlSelected);
  973. }
  974. if (pidlStartBrowse != NULL)
  975. {
  976. ILFree(pidlStartBrowse);
  977. }
  978. pdesktop->lpVtbl->Release(pdesktop);
  979. }
  980. else
  981. {
  982. // This really shouldn't happen; SHGetDesktopdesktop failed; out of memory?
  983. }
  984. }
  985. //
  986. // Main dialog procedure for first page of shortcut wizard.
  987. //
  988. //
  989. // Note that there are now two BrowseDlgProcs, the one below and
  990. // 'SetupBrowseDlgProc'. This is because BrowseDlgProc now uses
  991. // a different method for implementing the 'Browse' button and I
  992. // wanted to do this without affecting the Setup Wizard which will
  993. // now use SetupBrowseDlgProc. - dsheldon 6/16/98
  994. //
  995. BOOL_PTR CALLBACK BrowseDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  996. {
  997. NMHDR FAR *lpnm = NULL;
  998. LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
  999. LPWIZDATA lpwd = NULL;
  1000. if (lpPropSheet)
  1001. {
  1002. lpwd = (LPWIZDATA)lpPropSheet->lParam;
  1003. }
  1004. switch(message)
  1005. {
  1006. case WM_NOTIFY:
  1007. lpnm = (NMHDR FAR *)lParam;
  1008. if(lpnm)
  1009. {
  1010. switch(lpnm->code)
  1011. {
  1012. case PSN_SETACTIVE:
  1013. if(lpwd)
  1014. {
  1015. lpwd->hwnd = hDlg;
  1016. if (lpwd->dwFlags & WDFLAG_NOBROWSEPAGE)
  1017. {
  1018. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1019. }
  1020. else
  1021. {
  1022. BrowseSetActive(lpwd);
  1023. }
  1024. }
  1025. break;
  1026. case PSN_WIZNEXT:
  1027. if(lpwd)
  1028. {
  1029. if (!NextPushed(lpwd) ||
  1030. ((lpwd->dwFlags & WDFLAG_SETUPWIZ) && !SetupCleanupExePath(lpwd)))
  1031. {
  1032. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1033. }
  1034. }
  1035. break;
  1036. case PSN_WIZFINISH:
  1037. if(lpwd)
  1038. {
  1039. BOOL ForceWx86;
  1040. #ifdef WX86
  1041. ForceWx86 = bWx86Enabled && bForceX86Env;
  1042. #else
  1043. ForceWx86 = FALSE;
  1044. #endif
  1045. if (!SetupCleanupExePath(lpwd) ||
  1046. !ExecSetupProg(lpwd, ForceWx86, TRUE))
  1047. {
  1048. BrowseSetActive(lpwd);
  1049. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1050. }
  1051. }
  1052. break;
  1053. case PSN_RESET:
  1054. if(lpwd)
  1055. {
  1056. CleanUpWizData(lpwd);
  1057. }
  1058. break;
  1059. default:
  1060. return FALSE;
  1061. }
  1062. }
  1063. break;
  1064. case WM_INITDIALOG:
  1065. BrowseInitPropSheet(hDlg, lParam);
  1066. break;
  1067. case WMPRIV_POKEFOCUS:
  1068. {
  1069. HWND hCmd = GetDlgItem(hDlg, IDC_COMMAND);
  1070. SetFocus(hCmd);
  1071. Edit_SetSel(hCmd, 0, -1);
  1072. break;
  1073. }
  1074. case WM_DESTROY:
  1075. case WM_HELP:
  1076. case WM_CONTEXTMENU:
  1077. break;
  1078. case WM_COMMAND:
  1079. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1080. {
  1081. case IDHELP:
  1082. break;
  1083. case IDC_COMMAND:
  1084. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1085. {
  1086. case EN_CHANGE:
  1087. if(lpwd)
  1088. {
  1089. SetBrowseButtons(lpwd);
  1090. }
  1091. break;
  1092. }
  1093. break;
  1094. case IDC_BROWSE:
  1095. if(lpwd)
  1096. {
  1097. BrowseForFileOrFolder(lpwd);
  1098. }
  1099. break;
  1100. } // end of switch on WM_COMMAND
  1101. break;
  1102. default:
  1103. return FALSE;
  1104. } // end of switch on message
  1105. return TRUE;
  1106. } // BrowseDlgProc
  1107. BOOL_PTR CALLBACK SetupBrowseDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  1108. {
  1109. NMHDR FAR *lpnm = NULL;
  1110. LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
  1111. LPWIZDATA lpwd = NULL;
  1112. if (lpPropSheet)
  1113. {
  1114. lpwd = (LPWIZDATA)lpPropSheet->lParam;
  1115. }
  1116. switch(message)
  1117. {
  1118. case WM_NOTIFY:
  1119. lpnm = (NMHDR FAR *)lParam;
  1120. if(lpnm)
  1121. {
  1122. switch(lpnm->code)
  1123. {
  1124. BOOL bForceWx86;
  1125. case PSN_SETACTIVE:
  1126. if(lpwd)
  1127. {
  1128. lpwd->hwnd = hDlg;
  1129. if (lpwd->dwFlags & WDFLAG_NOBROWSEPAGE)
  1130. {
  1131. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1132. }
  1133. else
  1134. {
  1135. BrowseSetActive(lpwd);
  1136. }
  1137. }
  1138. break;
  1139. case PSN_WIZNEXT:
  1140. if(lpwd)
  1141. {
  1142. // Remember the previous "InstallMode"
  1143. lpwd->bPrevMode = TermsrvAppInstallMode();
  1144. // Set the "InstallMode"
  1145. SetTermsrvAppInstallMode(TRUE);
  1146. #ifdef WX86
  1147. bForceWx86 = bWx86Enabled && bForceX86Env;
  1148. #else
  1149. bForceWx86 = FALSE;
  1150. #endif
  1151. if (!NextPushed(lpwd) || !SetupCleanupExePath(lpwd) ||
  1152. !ExecSetupProg(lpwd, bForceWx86, FALSE))
  1153. {
  1154. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1155. }
  1156. }
  1157. break;
  1158. case PSN_WIZFINISH:
  1159. if(lpwd)
  1160. {
  1161. #ifdef WX86
  1162. bForceWx86 = bWx86Enabled && bForceX86Env;
  1163. #else
  1164. bForceWx86 = FALSE;
  1165. #endif
  1166. if (!SetupCleanupExePath(lpwd) ||
  1167. !ExecSetupProg(lpwd, bForceWx86, TRUE))
  1168. {
  1169. BrowseSetActive(lpwd);
  1170. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  1171. }
  1172. }
  1173. break;
  1174. case PSN_RESET:
  1175. if(lpwd)
  1176. {
  1177. CleanUpWizData(lpwd);
  1178. }
  1179. break;
  1180. default:
  1181. return FALSE;
  1182. }
  1183. }
  1184. break;
  1185. case WM_INITDIALOG:
  1186. BrowseInitPropSheet(hDlg, lParam);
  1187. break;
  1188. case WMPRIV_POKEFOCUS:
  1189. {
  1190. HWND hCmd = GetDlgItem(hDlg, IDC_COMMAND);
  1191. SetFocus(hCmd);
  1192. Edit_SetSel(hCmd, 0, -1);
  1193. break;
  1194. }
  1195. case WM_DESTROY:
  1196. case WM_HELP:
  1197. case WM_CONTEXTMENU:
  1198. break;
  1199. case WM_COMMAND:
  1200. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1201. {
  1202. case IDHELP:
  1203. break;
  1204. case IDC_COMMAND:
  1205. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1206. {
  1207. case EN_CHANGE:
  1208. if(lpwd)
  1209. {
  1210. SetBrowseButtons(lpwd);
  1211. }
  1212. break;
  1213. }
  1214. break;
  1215. case IDC_BROWSE:
  1216. if(lpwd)
  1217. {
  1218. BrowsePushed(lpwd);
  1219. }
  1220. break;
  1221. } // end of switch on WM_COMMAND
  1222. break;
  1223. default:
  1224. return FALSE;
  1225. } // end of switch on message
  1226. return TRUE;
  1227. } // SetupBrowseDlgProc