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.

4124 lines
109 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. prompt.c
  5. Abstract:
  6. Disk/file prompt and file error prompt dialogs.
  7. Author:
  8. Ted Miller (tedm) 8-Feb-1995
  9. Revision History:
  10. Jamie Hunter (JamieHun) May-04-2002
  11. Security code review
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <winnetwk.h>
  16. #include <winnetp.h>
  17. #include <winioctl.h>
  18. //
  19. // Structure used internally to store information
  20. // about the file/disk being prompted for or the copy error
  21. // that has occured. We store a pointer to one of these as
  22. // a window property of the prompt dialog box. This eliminates
  23. // the need for our own dialog class and for global/static variables.
  24. //
  25. typedef struct _PROMPTPARAMS {
  26. //
  27. // Reason we are displaying the dialog. One of DLGTYPE_ERROR or
  28. // DLGTYPE_PROMPT. Used to modify controls and dialog's behavior.
  29. //
  30. UINT DialogType;
  31. //
  32. // For error dialogs, these values tell us the win32 error code
  33. // that indicated failure. Used in the details message box.
  34. //
  35. UINT Win32Error;
  36. //
  37. // Window handle of the prompt/error dialog, and of its owner window,
  38. // if any.
  39. //
  40. HWND hdlg;
  41. HWND Owner;
  42. //
  43. // String to be used as the caption for the prompt/error dialog.
  44. //
  45. PCTSTR DialogTitle;
  46. //
  47. // Disk tag file. Used when prompting for a disk. We look for
  48. // this file at the root of the drive to verify presence of the disk.
  49. //
  50. PCTSTR TagFile;
  51. //
  52. // Desriptive name for the disk where we expect the file to be.
  53. // This is used even when the source location is non-removable,
  54. // because the user might elect to furnish the file on disk, etc.
  55. //
  56. PCTSTR DiskName;
  57. //
  58. // The path to the source file (not including the file name)
  59. // and the filename part of the source file. This filename is
  60. // displayed when the user elects to browse and in certain other
  61. // messages we may display in the dialog box.
  62. //
  63. PCTSTR PathToSource;
  64. PCTSTR FileSought;
  65. //
  66. // Full path of the target file, if any. Used for copy errors and rename,
  67. // so we can tell the user the name of the target file in the details
  68. // message box.
  69. //
  70. PCTSTR TargetFile;
  71. //
  72. // IDF_xxx style bits that control behavior of the promt dialog.
  73. //
  74. DWORD PromptStyle;
  75. //
  76. // Drive type for PathToSource and flag indicating whether
  77. // it's for removable media.
  78. //
  79. UINT DriveType;
  80. BOOL IsRemovable;
  81. //
  82. // List of installation paths, from the registry.
  83. // Access to that list is not synchronized among processes;
  84. // oh well.
  85. //
  86. PTSTR *PathList;
  87. UINT PathCount;
  88. //
  89. // Flag indicating whether the user has browsed (Browse button)
  90. // during the lifetime of the dialog invocation.
  91. //
  92. BOOL UserBrowsed;
  93. //
  94. // Flag indicating whether the user is allowed to type in the combo box
  95. // edit control.
  96. //
  97. BOOL ReadOnlyMru;
  98. //
  99. // Identifier of the combo box in use.
  100. //
  101. UINT ComboBoxId;
  102. //
  103. // Value used to indicate whether or not we're doing a presence check and,
  104. // if so, whether there's a pending cancel to be processed once we're done
  105. // (i.e., upon receipt of a WMX_PRESENCE_RESULT message posted from the
  106. // AuxPromptThread).
  107. //
  108. // Possible values are:
  109. // == 0 -- not currently doing a presence check--no pending cancels.
  110. // == 1 -- currently doing a presence check--no pending cancels.
  111. // >= 2 -- currently doing a presence check--one or more pending cancels.
  112. //
  113. BOOL PresenceCheckState;
  114. BOOL BrowseAutoComplete;
  115. #if ASSERTS_ON
  116. //
  117. // Make sure that if we fired off a presence check thread, that it has
  118. // notified us of its completion prior to our processing of WM_DESTROY.
  119. //
  120. BOOL PresenceCheckThreadRunning;
  121. //
  122. // Keep track of when the dialog's controls are disabled (hence we don't
  123. // expect to see the OK button pressed).
  124. //
  125. BOOL ControlsDisabled;
  126. #endif // ASSERTS_ON
  127. //
  128. // Parameters that are passed to the simple message box
  129. //
  130. MSGBOXPARAMS MsgBoxParams;
  131. } PROMPTPARAMS, *PPROMPTPARAMS;
  132. //
  133. // PROMPTPARAMS.DialogType
  134. //
  135. #define DLGTYPE_PROMPT 0
  136. #define DLGTYPE_ERROR 1
  137. //
  138. // Define a signature for WMX_PRESENCE_RESULT (contained in lParam) that is
  139. // used to validate the sender as being our own AuxPromptThread.
  140. //
  141. #define PRESENCE_RESULT_SIG 0x52504D53 // "SMPR" (Setupapi Message Presence Result)
  142. //
  143. // Structure used in delete/rename error dialog.
  144. //
  145. typedef struct _FILEERRDLGPARAMS {
  146. PCTSTR MessageText;
  147. DWORD Style;
  148. PCTSTR Caption;
  149. } FILEERRDLGPARAMS, *PFILEERRDLGPARAMS;
  150. //
  151. // Text constants.
  152. //
  153. TCHAR pszDiskPromptPropName[] = TEXT("_diskpromptparams");
  154. //
  155. // Custom window messages
  156. //
  157. #define WMX_PRESENCE_RESULT (WM_USER+121)
  158. #define WMX_HELLO (WM_USER+122)
  159. #define WMX_FIXUP_FILENAME (WM_USER+123)
  160. //
  161. // Linked-list node structure that tracks what temporary connections we
  162. // need to clean up on unload (connections made as a result of user doing
  163. // a "Connect As").
  164. //
  165. typedef struct _TEMP_NET_CONNECTION {
  166. struct _TEMP_NET_CONNECTION *Next;
  167. TCHAR NetResourceName[MAX_PATH];
  168. } TEMP_NET_CONNECTION, *PTEMP_NET_CONNECTION;
  169. //
  170. // Global variables that track temporary net connections.
  171. //
  172. PTEMP_NET_CONNECTION NetConnectionList;
  173. //
  174. // global window message for cancelling autoplay.
  175. //
  176. UINT g_uQueryCancelAutoPlay = 0;
  177. //
  178. // Private routine prototypes.
  179. //
  180. BOOL
  181. ConnectToNetShare(
  182. IN PCTSTR FileName,
  183. IN HWND hwndParent
  184. );
  185. BOOL
  186. IsDriveReallyAHardDrive(
  187. IN TCHAR DriveLetter
  188. )
  189. {
  190. TCHAR DriveNameNt[7];
  191. HANDLE hDisk;
  192. DWORD DataSize;
  193. DISK_GEOMETRY MediaInfo;
  194. BOOL b;
  195. #ifdef _X86_
  196. if(OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  197. //
  198. // Blow off the win9x case since the win32 support
  199. // for making this determination is poor at best.
  200. // A nauseating hack lets this work at least some of
  201. // the time but PC98 is hosed since the basic assumption that
  202. // floppies are generally A: and B: is invalid.
  203. //
  204. return(!IsNEC98() && (DriveLetter >= TEXT('C')));
  205. }
  206. #endif
  207. //
  208. // NT case allows us to make the determination reliably by opening
  209. // the drive and reading some attributes.
  210. //
  211. wsprintf(DriveNameNt,TEXT("\\\\.\\%c:"),DriveLetter);
  212. hDisk = CreateFile(
  213. DriveNameNt,
  214. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  215. FILE_SHARE_READ | FILE_SHARE_WRITE,
  216. NULL,
  217. OPEN_EXISTING,
  218. 0,
  219. NULL
  220. );
  221. if(hDisk == INVALID_HANDLE_VALUE) {
  222. return(FALSE);
  223. }
  224. b = DeviceIoControl(
  225. hDisk,
  226. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  227. NULL,
  228. 0,
  229. &MediaInfo,
  230. sizeof(MediaInfo),
  231. &DataSize,
  232. NULL
  233. );
  234. CloseHandle(hDisk);
  235. //
  236. // It's really a hard disk if the media type is removable.
  237. //
  238. return(b && (MediaInfo.MediaType == RemovableMedia));
  239. }
  240. VOID
  241. DiskPromptGetDriveType(
  242. IN PCTSTR PathToSource,
  243. OUT PUINT DriveType,
  244. OUT PBOOL IsRemovable
  245. )
  246. /*++
  247. Routine Description:
  248. Determine the drive type of the drive on which a path resides.
  249. If the path starts with x: we call GetDriveType() on it.
  250. If GetDriveType fails we assume it's removable.
  251. If the path starts with \\ we assume it's remote.
  252. Otherwise we assume it's a relative path on a hard drive.
  253. Arguments:
  254. PathToSource - pathname of path whose drive type is needed.
  255. DriveType - receives value indicating drive type. The set of
  256. possible values is the same as the named constants that can
  257. be returned by GetDriveType().
  258. IsRemovable - receives flag indicating whether DriveType
  259. is a removable media type (floppy, cd-rom).
  260. Return Value:
  261. None.
  262. --*/
  263. {
  264. TCHAR DriveRoot[4];
  265. TCHAR c;
  266. c = (TCHAR)CharUpper((PTSTR)PathToSource[0]);
  267. if((c >= TEXT('A')) && (c <= TEXT('Z')) && (PathToSource[1] == TEXT(':'))) {
  268. DriveRoot[0] = PathToSource[0];
  269. DriveRoot[1] = PathToSource[1];
  270. DriveRoot[2] = TEXT('\\');
  271. DriveRoot[3] = 0;
  272. *DriveType = GetDriveType(DriveRoot);
  273. if(*DriveType == DRIVE_NO_ROOT_DIR) {
  274. //
  275. // Typically indicates that this drive-letter is invalid
  276. // we will not get this if drive-letter is valid
  277. // but media is not inserted.
  278. //
  279. *DriveType = DRIVE_UNKNOWN;
  280. }
  281. *IsRemovable = ((*DriveType == DRIVE_REMOVABLE) || (*DriveType == DRIVE_CDROM) || (*DriveType == DRIVE_UNKNOWN));
  282. //
  283. // If the drive is really a removeable hard drive as opposed to a
  284. // floppy drive, change the drive type field to indicate a fixed
  285. // drive, but don't change the removable flag. This allows callers
  286. // to make this distinction if they need to.
  287. //
  288. // If the system is installed on the drive in question, then leave
  289. // the drive type alone, but indicate that the media is not actually
  290. // removable.
  291. //
  292. if(*DriveType == DRIVE_REMOVABLE) {
  293. if(IsDriveReallyAHardDrive(c)) {
  294. *DriveType = DRIVE_FIXED;
  295. }
  296. if((WindowsDirectory[0] == PathToSource[0]) && (WindowsDirectory[1] == TEXT(':'))) {
  297. *IsRemovable = FALSE;
  298. }
  299. }
  300. } else {
  301. //
  302. // Not drive letter: so try unc.
  303. //
  304. if((PathToSource[0] == TEXT('\\')) && (PathToSource[1] == TEXT('\\'))) {
  305. *DriveType = DRIVE_REMOTE;
  306. } else {
  307. //
  308. // Not recognized full path spec; assume relative path on HD.
  309. //
  310. *DriveType = DRIVE_FIXED;
  311. }
  312. *IsRemovable = FALSE;
  313. }
  314. }
  315. typedef struct _MYOPENPARAMS {
  316. PCTSTR Filename1;
  317. PCTSTR Filename2;
  318. PCTSTR Filename3;
  319. } MYOPENPARAMS, *PMYOPENPARAMS;
  320. UINT_PTR
  321. APIENTRY
  322. BrowseHookProc(
  323. IN HWND hdlg,
  324. IN UINT msg,
  325. IN WPARAM wParam,
  326. IN LPARAM lParam
  327. )
  328. /*++
  329. Routine Description:
  330. Hook procedure used with the OpenFile common dialog
  331. for file browsing. We use a hook proc so that the user
  332. is forced to look for only one particular file, and can't
  333. look at any other file.
  334. Arguments:
  335. Standard Window Procedure arguments.
  336. Return Value:
  337. Always FALSE, to indicate that the common dialog should
  338. process the message.
  339. --*/
  340. {
  341. HWND hwnd;
  342. LPOFNOTIFY NotifyParams;
  343. LPOPENFILENAME OpenParams;
  344. PMYOPENPARAMS MyOpenParams;
  345. TCHAR Path[MAX_PATH];
  346. WIN32_FIND_DATA FindData;
  347. BOOL b;
  348. UINT NotifyCode;
  349. UNREFERENCED_PARAMETER(wParam);
  350. switch(msg) {
  351. case WM_INITDIALOG:
  352. //
  353. // Save away the OPENFILENAME structure for later.
  354. //
  355. SetWindowLongPtr(hdlg,GWLP_USERDATA,lParam);
  356. break;
  357. case WMX_FIXUP_FILENAME:
  358. case WM_NOTIFY:
  359. if(msg == WM_NOTIFY) {
  360. NotifyParams = (LPOFNOTIFY)lParam;
  361. NotifyCode = NotifyParams->hdr.code;
  362. } else {
  363. NotifyCode = CDN_FOLDERCHANGE;
  364. }
  365. hwnd = GetParent(hdlg);
  366. switch(NotifyCode) {
  367. case CDN_INITDONE:
  368. //
  369. // Make the "files of type" combo box read-only.
  370. //
  371. EnableWindow(GetDlgItem(hwnd,cmb1),FALSE);
  372. //
  373. // Post ourselves a message, so that we'll initialize the editbox
  374. // correctly (we can't do it here, because it's too early).
  375. //
  376. PostMessage(hdlg, WMX_FIXUP_FILENAME, 0, 0);
  377. break;
  378. case CDN_FOLDERCHANGE:
  379. case CDN_FILEOK:
  380. //
  381. // See if the file actually exists and if so
  382. // set up the edit control.
  383. //
  384. OpenParams = (LPOPENFILENAME)GetWindowLongPtr(hdlg,GWLP_USERDATA);
  385. MyOpenParams = (PMYOPENPARAMS)OpenParams->lCustData;
  386. CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
  387. pSetupConcatenatePaths(Path,MyOpenParams->Filename1,MAX_PATH,NULL);
  388. if(FileExists(Path,&FindData)) {
  389. b = TRUE;
  390. } else {
  391. if(MyOpenParams->Filename2) {
  392. CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
  393. pSetupConcatenatePaths(Path,MyOpenParams->Filename2,MAX_PATH,NULL);
  394. if(FileExists(Path,&FindData)) {
  395. b = TRUE;
  396. } else {
  397. if(MyOpenParams->Filename3) {
  398. CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
  399. pSetupConcatenatePaths(Path,MyOpenParams->Filename3,MAX_PATH,NULL);
  400. b = FileExists(Path,&FindData);
  401. } else {
  402. b = FALSE;
  403. }
  404. }
  405. } else {
  406. b = FALSE;
  407. }
  408. }
  409. if(NotifyCode == CDN_FOLDERCHANGE) {
  410. if(b) {
  411. CommDlg_OpenSave_SetControlText(hwnd, edt1, FindData.cFileName);
  412. }
  413. } else {
  414. if(!b) {
  415. MessageBeep(MB_ICONASTERISK);
  416. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,TRUE);
  417. return(TRUE);
  418. }
  419. }
  420. break;
  421. }
  422. break;
  423. }
  424. //
  425. // Let commdlg process it
  426. //
  427. return(FALSE);
  428. }
  429. BOOL
  430. DoBrowse(
  431. IN HWND hdlg,
  432. IN PPROMPTPARAMS Params
  433. )
  434. /*++
  435. Routine Description:
  436. Allow the user to browse for a file. The user is allowed to look
  437. only for the file in question -- he is not allowed to change the filter,
  438. select an alternate file, etc.
  439. Arguments:
  440. hdlg - supplies the window handle of the window to own the
  441. browse dialog.
  442. File - supplies the filename (no path) of the file being looked for.
  443. Return Value:
  444. TRUE if the user located the file. FALSE otherwise.
  445. If TRUE, the edit control of the combo box in hdlg has been given the
  446. final path entered by the user in the browse dialog.
  447. --*/
  448. {
  449. OPENFILENAME ofn;
  450. TCHAR Path[MAX_PATH];
  451. TCHAR Filter[2*MAX_PATH];
  452. TCHAR InitialDir[MAX_PATH];
  453. UINT InitialDirDriveType;
  454. BOOL IsInitialDirOnRemovableDrive, InitialDirMediaPresent;
  455. PTSTR CompressedFormName;
  456. BOOL found=FALSE;
  457. PCTSTR File;
  458. LONG l;
  459. DWORD err;
  460. HKEY hKey1,hKey2;
  461. DWORD Type;
  462. DWORD Size;
  463. BOOL GotDesc;
  464. MYOPENPARAMS MyParams;
  465. LPTSTR FilterPtr;
  466. LPTSTR q;
  467. size_t FilterLen;
  468. File = Params->FileSought;
  469. //
  470. // Create the compressed-form name of the source file.
  471. //
  472. CompressedFormName = (Params->PromptStyle & IDF_NOCOMPRESSED)
  473. ? NULL
  474. : SetupGenerateCompressedName(File);
  475. //
  476. // Build a filter that contains the file we're looking for
  477. // and its compressed form name, if any. If the file is of
  478. // the form *.ext then we'll build a more descriptive name.
  479. //
  480. GotDesc = FALSE;
  481. FilterPtr = Filter;
  482. FilterLen = MAX_PATH; // sub-length of Filter
  483. if(!CompressedFormName
  484. && (File[0] == TEXT('*'))
  485. && (File[1] == TEXT('.'))
  486. && File[2]
  487. && !_tcschr(File+2,TEXT('.'))) {
  488. l = RegOpenKeyEx(HKEY_CLASSES_ROOT,File+1,0,KEY_QUERY_VALUE,&hKey1);
  489. if(l == NO_ERROR) {
  490. Size = sizeof(Filter);
  491. l = RegQueryValueEx(hKey1,TEXT(""),NULL,&Type,(LPBYTE)Filter,&Size);
  492. if((l == NO_ERROR) && (Type == REG_SZ)) {
  493. Size /= sizeof(TCHAR);
  494. Size = min(Size,MAX_PATH-1);
  495. Filter[Size] = TEXT('\0');
  496. l = RegOpenKeyEx(HKEY_CLASSES_ROOT,Filter,0,KEY_QUERY_VALUE,&hKey2);
  497. if(l == NO_ERROR) {
  498. Size = sizeof(Filter);
  499. l = RegQueryValueEx(hKey2,TEXT(""),NULL,&Type,(LPBYTE)Filter,&Size);
  500. if((l == NO_ERROR) && (Type == REG_SZ)) {
  501. Size /= sizeof(TCHAR);
  502. Size = min(Size,MAX_PATH-1);
  503. Filter[Size] = TEXT('\0');
  504. Size = lstrlen(Filter); // real length of string
  505. FilterPtr = Filter+Size;
  506. FilterLen = MAX_PATH-Size;
  507. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,TEXT(" ("),&FilterPtr,&FilterLen,0))
  508. &&SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,File,&FilterPtr,&FilterLen,0))
  509. &&SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,TEXT(")"),&FilterPtr,&FilterLen,0)));
  510. FilterPtr++; // pass null
  511. FilterLen = SIZECHARS(Filter)-(FilterPtr-Filter)-1; // extend length (allow for extra null)
  512. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,File,&FilterPtr,&FilterLen,0)));
  513. GotDesc = TRUE;
  514. }
  515. RegCloseKey(hKey2);
  516. }
  517. }
  518. RegCloseKey(hKey1);
  519. }
  520. }
  521. if(!GotDesc) {
  522. //
  523. // Not able to fetch a meaningful description. Use the filenames.
  524. // The filter has the description and the filespec set to
  525. // the filename, for both the filename and its compressed form like so:
  526. // foo.exe;foo.ex_ foo.exe;foo.ex_
  527. //
  528. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,File,&FilterPtr,&FilterLen,0)));
  529. if(CompressedFormName) {
  530. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,TEXT(";"),&FilterPtr,&FilterLen,0))
  531. && SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,CompressedFormName,&FilterPtr,&FilterLen,0)));
  532. }
  533. FilterPtr++; // pass null
  534. FilterLen = SIZECHARS(Filter)-(FilterPtr-Filter)-1; // extend length (allow for extra null)
  535. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,File,&FilterPtr,&FilterLen,0)));
  536. if(CompressedFormName) {
  537. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,TEXT(";"),&FilterPtr,&FilterLen,0))
  538. && SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,CompressedFormName,&FilterPtr,&FilterLen,0)));
  539. }
  540. }
  541. //
  542. // Stick the cabinet name in there if we think there is one.
  543. // We do a dirty hackola to tell the difference between a tag file
  544. // and a cabinet, namely we look for a .cab extension.
  545. //
  546. // Note that at this point p points at the terminating nul
  547. // of the last filename placed into Filter.
  548. //
  549. if(Params->TagFile) {
  550. q = (PTSTR)pSetupGetFileTitle(Params->TagFile);
  551. l = lstrlen(q);
  552. if((l > 4) && !lstrcmpi((q+l)-4,TEXT(".cab"))) {
  553. MYVERIFY(SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,TEXT(";"),&FilterPtr,&FilterLen,0))
  554. && SUCCEEDED(StringCchCopyEx(FilterPtr,FilterLen,q,&FilterPtr,&FilterLen,0)));
  555. } else {
  556. q = NULL;
  557. }
  558. } else {
  559. q = NULL;
  560. }
  561. FilterPtr++; // skip null
  562. MYASSERT((FilterPtr-Filter)<SIZECHARS(Filter));
  563. *FilterPtr = TEXT('\0'); // final null
  564. MyParams.Filename1 = File;
  565. MyParams.Filename2 = CompressedFormName;
  566. MyParams.Filename3 = q;
  567. MYVERIFY(SUCCEEDED(StringCchCopy(Path,SIZECHARS(Path),File)));
  568. InitialDir[0] = TEXT('\0');
  569. GetDlgItemText(hdlg,Params->ComboBoxId,InitialDir,MAX_PATH);
  570. InitialDir[MAX_PATH-1] = TEXT('\0');
  571. //
  572. // If the initial directory is on removable media, make sure that the media
  573. // is present prior to firing off the common dialog. Otherwise, the user
  574. // will a popup that the media isn't accessible.
  575. //
  576. DiskPromptGetDriveType(InitialDir,
  577. &InitialDirDriveType,
  578. &IsInitialDirOnRemovableDrive
  579. );
  580. if(IsInitialDirOnRemovableDrive) {
  581. //
  582. // We have a removable drive--make sure the media is present.
  583. // if it's not, we'll probably get ERROR_INVALID_DRIVE
  584. // if it is, we'll either succeed or get ERROR_FILE_NOT_FOUND
  585. //
  586. InitialDirMediaPresent = (FileExists(InitialDir, NULL) ||
  587. GetLastError() == ERROR_FILE_NOT_FOUND);
  588. } else {
  589. InitialDirMediaPresent = TRUE;
  590. }
  591. ofn.lStructSize = GuiSetupInProgress ?
  592. OPENFILENAME_SIZE_VERSION_400 : sizeof(OPENFILENAME);
  593. ofn.hwndOwner = hdlg;
  594. ofn.hInstance = NULL;
  595. ofn.lpstrFilter = Filter;
  596. ofn.lpstrCustomFilter = NULL;
  597. ofn.nMaxCustFilter = 0;
  598. ofn.nFilterIndex = 1;
  599. ofn.lpstrFile = Path;
  600. ofn.nMaxFile = MAX_PATH;
  601. ofn.lpstrFileTitle = NULL;
  602. ofn.nMaxFileTitle = 0;
  603. ofn.lpstrInitialDir = InitialDirMediaPresent ? InitialDir : NULL;
  604. ofn.lpstrTitle = MyLoadString(IDS_LOCATEFILE);
  605. ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_NOCHANGEDIR | OFN_ENABLESIZING
  606. | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_FORCESHOWHIDDEN;
  607. ofn.nFileOffset = 0;
  608. ofn.nFileExtension = 0;
  609. ofn.lpstrDefExt = NULL;
  610. ofn.lCustData = (LPARAM)&MyParams;
  611. ofn.lpfnHook = BrowseHookProc;
  612. ofn.lpTemplateName = NULL;
  613. found = GetOpenFileName(&ofn);
  614. if(ofn.lpstrTitle) {
  615. MyFree(ofn.lpstrTitle);
  616. }
  617. if(CompressedFormName) {
  618. MyFree(CompressedFormName);
  619. }
  620. UpdateWindow(hdlg);
  621. if(found) {
  622. //
  623. // Remove file part, put the resulting directory in the path field
  624. // This does not cause the string to be added to the combo box list.
  625. //
  626. if(ofn.nFileOffset<MAX_PATH) {
  627. Path[ofn.nFileOffset - 1] = TEXT('\0');
  628. } else {
  629. Path[MAX_PATH-1] = TEXT('\0');
  630. }
  631. SetDlgItemText(hdlg,Params->ComboBoxId,Path);
  632. return(TRUE);
  633. }
  634. return(FALSE);
  635. }
  636. PTSTR
  637. GetErrorDetails(
  638. IN PPROMPTPARAMS Params
  639. )
  640. /*++
  641. Routine Description:
  642. Display a message box with details about a file copy error.
  643. Arguments:
  644. Params - supplies file error dialog parameters.
  645. Return Value:
  646. None.
  647. --*/
  648. {
  649. PTSTR Message;
  650. TCHAR FullPath[MAX_PATH];
  651. PTSTR ErrorName;
  652. PTCHAR p;
  653. DWORD chars;
  654. PTSTR ShorterText = NULL;
  655. TCHAR TargetPath[MAX_PATH];
  656. //
  657. // Form full path name.
  658. //
  659. lstrcpyn(FullPath,Params->PathToSource,SIZECHARS(FullPath));
  660. pSetupConcatenatePaths(FullPath,Params->FileSought,MAX_PATH,NULL);
  661. //
  662. // try to make the path fit in our dialog
  663. //
  664. chars = ExtraChars(GetDlgItem(Params->hdlg,IDT_TEXT2),FullPath);
  665. if (chars) {
  666. ShorterText = CompactFileName(FullPath,chars);
  667. if (ShorterText) {
  668. lstrcpyn(FullPath, ShorterText,SIZECHARS(FullPath));
  669. MyFree(ShorterText);
  670. ShorterText = NULL;
  671. }
  672. }
  673. lstrcpyn(TargetPath, Params->TargetFile,SIZECHARS(TargetPath));
  674. chars = ExtraChars(GetDlgItem(Params->hdlg,IDT_TEXT2),Params->TargetFile);
  675. if (chars) {
  676. ShorterText = CompactFileName(Params->TargetFile,chars);
  677. if (ShorterText) {
  678. lstrcpyn(TargetPath, ShorterText,SIZECHARS(TargetPath));
  679. MyFree(ShorterText);
  680. ShorterText = NULL;
  681. }
  682. }
  683. //
  684. // Fetch error description. Remove trailing cr/lf if present.
  685. //
  686. ErrorName = RetreiveAndFormatMessage(Params->Win32Error);
  687. if(ErrorName) {
  688. p = ErrorName + lstrlen(ErrorName) - 1;
  689. while((p > ErrorName) && (*p <= TEXT(' '))) {
  690. *p-- = 0;
  691. }
  692. } else {
  693. return NULL;
  694. }
  695. Message = RetreiveAndFormatMessage(
  696. MSG_FILEERROR_DETAILS1,
  697. ErrorName,
  698. Params->Win32Error,
  699. FullPath,
  700. TargetPath
  701. );
  702. MyFree(ErrorName);
  703. return Message;
  704. }
  705. BOOL
  706. DoPresenceCheck(
  707. IN PPROMPTPARAMS Params,
  708. IN BOOL AllowConnectAs
  709. )
  710. /*++
  711. Routine Description:
  712. Check for the presence of a source file or source disk.
  713. If the source path is on removable media and a tag file is
  714. specified, we attempt to locate the tag file on the root of
  715. the drive specified by the source path.
  716. If the source path is not on removable media or a tag file
  717. is not specified, we look for the file (including compressed-form
  718. names) in the given path.
  719. Arguments:
  720. Params - supplies pointer to disk prompt dialog parameters.
  721. AllowConnectAs - supplies a boolean indicating whether or not this
  722. routine should give the user a "Connect as:" dialog if they've
  723. typed in a UNC path that they currently don't have access to.
  724. Return Value:
  725. TRUE if the disk/file is present and accessible. FALSE if not.
  726. --*/
  727. {
  728. BOOL b;
  729. TCHAR FileName[MAX_PATH];
  730. DWORD d;
  731. WIN32_FIND_DATA FindData;
  732. PTSTR p;
  733. //
  734. // If there's a tagfile then look for the tag file.
  735. // Otherwise look for the file in the target path -- note that the
  736. // file's name could be in compressed form.
  737. //
  738. if(Params->TagFile && !Params->UserBrowsed) {
  739. if(Params->IsRemovable) {
  740. //
  741. // Removable media. Look for tag at root.
  742. // If tag not found at root, look in actual directory.
  743. //
  744. MYASSERT(Params->PathToSource[0]);
  745. MYASSERT(Params->PathToSource[1] == TEXT(':'));
  746. lstrcpyn(FileName,Params->PathToSource,3);
  747. pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
  748. b = FileExists(FileName,NULL);
  749. //
  750. // If we couldn't find the tagfile at the root and the path
  751. // is not for the root, look for the file in the path also.
  752. //
  753. // If we get here, we already know that PathToSource starts
  754. // with x:. We could have a path of the form x:\foo\bar
  755. // or x:foo\bar.
  756. //
  757. if(!b
  758. && Params->PathToSource[2]
  759. && !((Params->PathToSource[2] == TEXT('\\')) && !Params->PathToSource[3])) {
  760. lstrcpy(FileName,Params->PathToSource);
  761. pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
  762. b = FileExists(FileName,NULL);
  763. }
  764. //
  765. // Additional check for removeable hard drives to allow winnt32
  766. // to work, because in that case there's no tagfiles!
  767. //
  768. if(Params->DriveType == DRIVE_FIXED) {
  769. goto check1;
  770. }
  771. } else {
  772. //
  773. // Fixed media. Look for tag in the path where the file
  774. // is being sought. If it's not found there, look for
  775. // the file itself. This logic makes cabinets work right.
  776. //
  777. lstrcpy(FileName,Params->PathToSource);
  778. pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
  779. b = FileExists(FileName,NULL);
  780. if(!b && (Params->DriveType == DRIVE_REMOTE)) {
  781. d = GetLastError();
  782. if((d == ERROR_ACCESS_DENIED) || (d == ERROR_WRONG_PASSWORD) ||
  783. (d == ERROR_LOGON_FAILURE) || (d == ERROR_NOT_AUTHENTICATED) ||
  784. (d == ERROR_INVALID_PASSWORD) || (d == ERROR_BAD_NETPATH)) {
  785. //
  786. // If this is a network path, and we got 'access denied'-type of error,
  787. // then give the user "Connect As" dialog (if caller specified it's OK).
  788. //
  789. if(AllowConnectAs && ConnectToNetShare(FileName, Params->hdlg)) {
  790. //
  791. // We successfully connected to the network share--now try our
  792. // file existence check again.
  793. //
  794. b = FileExists(FileName,NULL);
  795. }
  796. }
  797. }
  798. check1:
  799. if(!b && lstrcmpi(Params->TagFile,Params->FileSought)) {
  800. //
  801. // We couldn't find the tagfile and the file we're seeking is
  802. // not the tagfile. So now we look for the file itself
  803. // in the path given to us. Note that the name of the file
  804. // could be the compressed form.
  805. //
  806. lstrcpy(FileName,Params->PathToSource);
  807. pSetupConcatenatePaths(FileName,Params->FileSought,MAX_PATH,NULL);
  808. d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
  809. if(d == NO_ERROR) {
  810. MyFree(p);
  811. b = TRUE;
  812. } else {
  813. b = FALSE;
  814. }
  815. }
  816. }
  817. } else {
  818. lstrcpy(FileName,Params->PathToSource);
  819. pSetupConcatenatePaths(FileName,Params->FileSought,MAX_PATH,NULL);
  820. d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
  821. if(Params->DriveType == DRIVE_REMOTE) {
  822. //
  823. // This is a network path. If we got an 'access denied'-type of error, then
  824. // give the user "Connect As" dialog (if caller specified it's OK).
  825. //
  826. if((d == ERROR_ACCESS_DENIED) || (d == ERROR_WRONG_PASSWORD) ||
  827. (d == ERROR_LOGON_FAILURE) || (d == ERROR_NOT_AUTHENTICATED) ||
  828. (d == ERROR_INVALID_PASSWORD) || (d == ERROR_BAD_NETPATH)) {
  829. if(AllowConnectAs && ConnectToNetShare(FileName, Params->hdlg)) {
  830. //
  831. // We successfully connected to the network share--now try to find
  832. // the source file again.
  833. //
  834. d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
  835. }
  836. }
  837. }
  838. if(d == NO_ERROR) {
  839. MyFree(p);
  840. b = TRUE;
  841. } else {
  842. //
  843. // Make cabinet-based browse work by also looking for the tag file.
  844. // Note sleazy hack that matches a similar sleazy hack in DoBrowse(),
  845. // namely looking at extension to see if it's .cab.
  846. //
  847. b = FALSE;
  848. if(Params->TagFile) {
  849. d = lstrlen(Params->TagFile);
  850. if((d > 4) && !lstrcmpi((Params->TagFile+d)-4,TEXT(".cab"))) {
  851. lstrcpy(FileName,Params->PathToSource);
  852. pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
  853. d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
  854. if(b = (d == NO_ERROR)) {
  855. MyFree(p);
  856. }
  857. }
  858. }
  859. }
  860. }
  861. return(b);
  862. }
  863. void
  864. __cdecl
  865. AuxPromptThread(
  866. IN void *args
  867. )
  868. /*++
  869. Routine Description:
  870. Thread entry point to wrap DoPresenceCheck.
  871. Calls DoPresenceCheck and then posts a message to the prompt
  872. dialog indicating the outcome.
  873. Arguments:
  874. args - supplies file error dialog parameters.
  875. Return Value:
  876. None.
  877. --*/
  878. {
  879. PPROMPTPARAMS Params;
  880. BOOL b;
  881. HWND hwnd;
  882. Params = args;
  883. #if ASSERTS_ON
  884. //
  885. // Set a flag to indicate that our presence check thread is up and running.
  886. //
  887. MYASSERT(!Params->PresenceCheckThreadRunning);
  888. Params->PresenceCheckThreadRunning = TRUE;
  889. #endif // ASSERTS_ON
  890. hwnd = Params->hdlg;
  891. b = DoPresenceCheck(Params, TRUE);
  892. #if ASSERTS_ON
  893. //
  894. // The window had better not have gone away!
  895. //
  896. MYASSERT(IsWindow(hwnd));
  897. //
  898. // Now reset the flag to indicate that our presence check thread is
  899. // finished.
  900. //
  901. Params->PresenceCheckThreadRunning = FALSE;
  902. #endif // ASSERTS_ON
  903. //
  904. // Tell the dialog what we found.
  905. //
  906. PostMessage(hwnd, WMX_PRESENCE_RESULT, b, PRESENCE_RESULT_SIG);
  907. }
  908. VOID
  909. PresenceCheckSetControls(
  910. IN PPROMPTPARAMS Params,
  911. IN BOOL Starting
  912. )
  913. /*++
  914. Routine Description:
  915. Disable or re-enable various controls in the error/prompt dialog
  916. in preparation for or upon return from a file presence check.
  917. We do this because the presence check occurs in another thread,
  918. so the main dialog remains responsive. We don't want the user
  919. to click OK again while we're checking, etc.
  920. Arguments:
  921. Params - supplies file error/disk prompt dialog parameters.
  922. Starting - indicates whether we are preparing for a presence check
  923. (TRUE) or returning from one (FALSE).
  924. Return Value:
  925. None.
  926. --*/
  927. {
  928. #if ASSERTS_ON
  929. if(!Starting) {
  930. Params->ControlsDisabled = FALSE;
  931. }
  932. #endif // ASSERTS_ON
  933. EnableWindow(GetDlgItem(Params->hdlg,IDOK),!Starting);
  934. EnableWindow(GetDlgItem(Params->hdlg,IDCANCEL),!Starting);
  935. EnableWindow(GetDlgItem(Params->hdlg,Params->ComboBoxId),!Starting);
  936. EnableWindow(
  937. GetDlgItem(Params->hdlg,IDB_BROWSE),
  938. Starting ? FALSE : !(Params->PromptStyle & IDF_NOBROWSE)
  939. );
  940. #if ASSERTS_ON
  941. if(Starting) {
  942. Params->ControlsDisabled = TRUE;
  943. }
  944. #endif // ASSERTS_ON
  945. }
  946. BOOL
  947. StartPresenceCheck(
  948. IN PPROMPTPARAMS Params
  949. )
  950. /*++
  951. Routine Description:
  952. Perform a presence check, doing the real work asynchronously
  953. in another thread. See AuxPromptThread().
  954. Arguments:
  955. Params - supplies file error/disk prompt dialog parameters.
  956. Return Value:
  957. Boolean value indicating whether the check could be started.
  958. If FALSE, assume out of memory.
  959. --*/
  960. {
  961. //
  962. // need to disable controls so user can't do anything
  963. // while we're off performing the file presence check.
  964. //
  965. PresenceCheckSetControls(Params,TRUE);
  966. //
  967. // Make sure we don't already have a presence check going on...
  968. //
  969. MYASSERT(Params->PresenceCheckState == 0);
  970. //
  971. // Set flag in prompt params to indicate we're doing a presence check.
  972. //
  973. Params->PresenceCheckState = 1;
  974. return(_beginthread(AuxPromptThread,0,Params) != -1);
  975. }
  976. BOOL
  977. InitDiskPromptDialog(
  978. IN OUT PPROMPTPARAMS Params
  979. )
  980. /*++
  981. Routine Description:
  982. Initialize the disk prompt dialog. This involves hiding buttons
  983. and other control, and setting up static text controls, based on the
  984. prompt style specified by the caller.
  985. Arguments:
  986. Params - supplies parameters for the disk prompting
  987. Return Value:
  988. TRUE if success; FALSE if out of memory.
  989. --*/
  990. {
  991. int i;
  992. PTCHAR p,q;
  993. BOOL b;
  994. UINT IconId;
  995. HICON hIcon;
  996. HWND ComboBox;
  997. UINT ComboBoxId;
  998. HWND OtherComboBox;
  999. //
  1000. // Remember parameter list
  1001. //
  1002. if(!SetProp(Params->hdlg,pszDiskPromptPropName,(HANDLE)Params)) {
  1003. return(FALSE);
  1004. }
  1005. if(!SetWindowText(Params->hdlg,Params->DialogTitle)) {
  1006. return(FALSE);
  1007. }
  1008. //
  1009. // Figure out which combo box to use. This depends on whether
  1010. // we're supposed to have an editable mru.
  1011. //
  1012. ComboBoxId = Params->ReadOnlyMru ? IDC_COMBO2 : IDC_COMBO1;
  1013. ComboBox = GetDlgItem(Params->hdlg,ComboBoxId);
  1014. OtherComboBox = GetDlgItem(Params->hdlg,Params->ReadOnlyMru ? IDC_COMBO1 : IDC_COMBO2);
  1015. Params->ComboBoxId = ComboBoxId;
  1016. ShowWindow(OtherComboBox,SW_HIDE);
  1017. EnableWindow(OtherComboBox,FALSE);
  1018. //
  1019. // Set up combo box title.
  1020. //
  1021. p = MyLoadString((Params->PromptStyle & IDF_OEMDISK) ? IDS_COPYFROMOEM : IDS_COPYFROM);
  1022. if(!p) {
  1023. return(FALSE);
  1024. }
  1025. b = SetDlgItemText(Params->hdlg,IDT_TITLE1,p);
  1026. MyFree(p);
  1027. if(!b) {
  1028. return(FALSE);
  1029. }
  1030. //
  1031. // Set up the combo box.
  1032. //
  1033. for(i=0; i<(int)Params->PathCount; i++) {
  1034. if(SendMessage(ComboBox,CB_ADDSTRING,0,(LPARAM)Params->PathList[i]) < 0) {
  1035. return(FALSE);
  1036. }
  1037. }
  1038. SendMessage(ComboBox,CB_LIMITTEXT,MAX_PATH,0);
  1039. if(Params->ReadOnlyMru) {
  1040. //
  1041. // Select the first string in the list.
  1042. //
  1043. SendMessage(ComboBox,CB_SETCURSEL,0,0);
  1044. } else {
  1045. //
  1046. // Set text of combo box to the path we're searching along.
  1047. // This does not cause the string to be added to the combo box list.
  1048. //
  1049. if(!SetDlgItemText(Params->hdlg,ComboBoxId,Params->PathToSource)) {
  1050. return(FALSE);
  1051. }
  1052. #ifdef UNICODE
  1053. if(Params->BrowseAutoComplete) {
  1054. SHAutoComplete(GetWindow(ComboBox, GW_CHILD), SHACF_FILESYS_DIRS);
  1055. }
  1056. #endif
  1057. }
  1058. //
  1059. // Hide buttons if necessary.
  1060. //
  1061. if(Params->PromptStyle & IDF_NOBROWSE) {
  1062. ShowWindow(GetDlgItem(Params->hdlg,IDB_BROWSE),SW_HIDE);
  1063. EnableWindow(GetDlgItem(Params->hdlg,IDB_BROWSE),FALSE);
  1064. }
  1065. //
  1066. // Set icon.
  1067. //
  1068. if(Params->DialogType == DLGTYPE_ERROR) {
  1069. hIcon = LoadIcon(NULL,IDI_HAND);
  1070. } else {
  1071. switch(Params->DriveType) {
  1072. case DRIVE_REMOTE:
  1073. IconId = ICON_NETWORK;
  1074. break;
  1075. case DRIVE_CDROM:
  1076. IconId = ICON_CD;
  1077. break;
  1078. case DRIVE_FIXED:
  1079. IconId = ICON_HARD;
  1080. break;
  1081. case DRIVE_REMOVABLE:
  1082. default:
  1083. IconId = ICON_FLOPPY;
  1084. break;
  1085. }
  1086. hIcon = LoadIcon(MyDllModuleHandle,MAKEINTRESOURCE(IconId));
  1087. }
  1088. if(hIcon) {
  1089. SendDlgItemMessage(Params->hdlg,IDI_ICON1,STM_SETICON,(WPARAM)hIcon,0);
  1090. }
  1091. return(TRUE);
  1092. }
  1093. BOOL
  1094. SetDiskPromptDialogText(
  1095. IN OUT PPROMPTPARAMS Params
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Set up static text fields that explain to the user what is requested
  1100. and what he has to do to continue. These fields depend on whether we're
  1101. prompting for an oem disk, whether the file is on removable media, and
  1102. whether a tag file has been specified.
  1103. Arguments:
  1104. Params - supplies parameters for the disk prompting
  1105. Return Value:
  1106. TRUE if success; FALSE if out of memory.
  1107. --*/
  1108. {
  1109. BOOL b;
  1110. PTSTR p;
  1111. if(Params->DialogType == DLGTYPE_PROMPT) {
  1112. //
  1113. // There are 2 text fields - the explanation and action.
  1114. // What the text looks like depends on the prompt style flags,
  1115. // whether the file is on removable media, etc.
  1116. //
  1117. // First handle the explanation text.
  1118. //
  1119. if (Params->PromptStyle & IDF_USEDISKNAMEASPROMPT) {
  1120. b = SetDlgItemText(Params->hdlg,IDT_TEXT1,Params->DiskName);
  1121. } else {
  1122. if(Params->PromptStyle & IDF_OEMDISK) {
  1123. p = MyLoadString(IDS_DISKPROMPTOEM);
  1124. } else {
  1125. if(Params->IsRemovable && Params->TagFile) {
  1126. p = FormatStringMessage(IDS_DISKPROMPT1,Params->DiskName);
  1127. } else {
  1128. p = FormatStringMessage(IDS_DISKPROMPT2,Params->FileSought,Params->DiskName);
  1129. }
  1130. }
  1131. if(!p) {
  1132. return(FALSE);
  1133. }
  1134. b = SetDlgItemText(Params->hdlg,IDT_TEXT1,p);
  1135. MyFree(p);
  1136. }
  1137. if(!b) {
  1138. return(FALSE);
  1139. }
  1140. //
  1141. // Now handle the explanation text. This is hidden for oem disks.
  1142. //
  1143. if(Params->PromptStyle & IDF_OEMDISK) {
  1144. ShowWindow(GetDlgItem(Params->hdlg,IDT_TEXT2),SW_HIDE);
  1145. EnableWindow(GetDlgItem(Params->hdlg,IDT_TEXT2),FALSE);
  1146. } else {
  1147. if(Params->IsRemovable && Params->TagFile) {
  1148. p = FormatStringMessage(IDS_PROMPTACTION1,Params->DiskName);
  1149. } else {
  1150. p = MyLoadString(IDS_PROMPTACTION2);
  1151. }
  1152. if(!p) {
  1153. return(FALSE);
  1154. }
  1155. b = SetDlgItemText(Params->hdlg,IDT_TEXT2,p);
  1156. MyFree(p);
  1157. if(!b) {
  1158. return(FALSE);
  1159. }
  1160. }
  1161. } else {
  1162. if(Params->DialogType != DLGTYPE_ERROR) {
  1163. return(FALSE);
  1164. }
  1165. p = MyLoadString(IDS_RETRY);
  1166. if (!p) {
  1167. return(FALSE);
  1168. }
  1169. b = SetDlgItemText(Params->hdlg,IDOK,p);
  1170. MyFree(p);
  1171. if (!b) {
  1172. return(FALSE);
  1173. }
  1174. //
  1175. // Explanation text -- "An error occurred copying a file" etc.
  1176. //
  1177. p = FormatStringMessage(IDS_FILEERRCOPY,Params->FileSought);
  1178. if(!p) {
  1179. return(FALSE);
  1180. }
  1181. b = SetDlgItemText(Params->hdlg,IDT_TEXT1,p);
  1182. MyFree(p);
  1183. if(!b) {
  1184. return(FALSE);
  1185. }
  1186. //
  1187. // Action text.
  1188. //
  1189. if (Params->Win32Error != ERROR_DIRECTORY &&
  1190. Params->Win32Error != ERROR_DISK_FULL) {
  1191. if(Params->PromptStyle & IDF_OEMDISK) {
  1192. p = MyLoadString(IDS_COPYERROROEM);
  1193. } else {
  1194. if(Params->IsRemovable) {
  1195. p = FormatStringMessage(IDS_COPYERROR1,Params->DiskName);
  1196. } else {
  1197. p = FormatStringMessage(IDS_COPYERROR2,Params->DiskName);
  1198. }
  1199. }
  1200. } else {
  1201. p = GetErrorDetails(Params);
  1202. }
  1203. if(!p) {
  1204. return(FALSE);
  1205. }
  1206. b = SetDlgItemText(Params->hdlg,IDT_TEXT2,p);
  1207. MyFree(p);
  1208. if(!b) {
  1209. return(FALSE);
  1210. }
  1211. }
  1212. return(TRUE);
  1213. }
  1214. BOOL
  1215. WarnSkip(
  1216. IN HWND hwnd,
  1217. IN BOOL Skip
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Warn the user that skipping the file or cancelling
  1222. can tank the system.
  1223. Arguments:
  1224. hwnd - supplies window handle for window to own the message box
  1225. this routine will display.
  1226. Skip - if TRUE, user is trying to skip the file; FALSE means
  1227. he is trying to cancel.
  1228. Return Value:
  1229. TRUE if user wants to skip file/cancel; false otherwise.
  1230. --*/
  1231. {
  1232. PCTSTR Caption;
  1233. PCTSTR Message;
  1234. BOOL b;
  1235. b = TRUE;
  1236. if(Caption = MyLoadString(IDS_WARNING)) {
  1237. if(Message = MyLoadString(Skip ? IDS_SURESKIP : IDS_SURECANCEL)) {
  1238. b = (MessageBox(hwnd,Message,Caption,MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES);
  1239. MyFree(Message);
  1240. }
  1241. MyFree(Caption);
  1242. }
  1243. return(b);
  1244. }
  1245. BOOL
  1246. CancelAllCopies(
  1247. IN HWND hwnd
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. ask the user if they want to cancel copying one file or all files
  1252. Arguments:
  1253. hwnd - supplies window handle for window to own the message box
  1254. this routine will display.
  1255. Return Value:
  1256. TRUE if user wants to cancel just this copy (really the same as skipping a file)
  1257. FALSE if user wants to cancel all copies;
  1258. --*/
  1259. {
  1260. PCTSTR Caption;
  1261. PCTSTR Message;
  1262. BOOL b;
  1263. b = TRUE;
  1264. if(Caption = MyLoadString(IDS_COPYERROR)) {
  1265. if(Message = MyLoadString(IDS_CANCELALL)) {
  1266. b = (MessageBox(hwnd,Message,Caption,MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES);
  1267. MyFree(Message);
  1268. }
  1269. MyFree(Caption);
  1270. }
  1271. return(b);
  1272. }
  1273. INT_PTR
  1274. DlgProcSimplePrompt(
  1275. IN HWND hdlg,
  1276. IN UINT msg,
  1277. IN WPARAM wParam,
  1278. IN LPARAM lParam
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. Dialog procedure for disk prompting dialog.
  1283. The return value for the dialog is
  1284. DPROMPT_CANCEL - user cancelled
  1285. DPROMPT_SKIPFILE - user elected to skip file
  1286. DPROMPT_SUCCESS - disk is in the drive/we found the file we're looking for
  1287. DPROMPT_OUTOFMEMORY - out of memory
  1288. Arguments:
  1289. Standard dialog routine parameters.
  1290. Return Value:
  1291. TRUE if message processed; FALSE if not.
  1292. --*/
  1293. {
  1294. BOOL b = FALSE;
  1295. TCHAR Text[MAX_PATH];
  1296. PPROMPTPARAMS PromptParams;
  1297. BOOL WarnIfSkip;
  1298. BOOL ReallyCancel;
  1299. HICON hIcon;
  1300. static DWORD UnitMask = 0xFFFFFFFF;
  1301. switch(msg) {
  1302. case WM_INITDIALOG:
  1303. PromptParams = (PPROMPTPARAMS)lParam;
  1304. MYASSERT(PromptParams != NULL);
  1305. if(!SetProp(hdlg,pszDiskPromptPropName,(HANDLE)&(PromptParams->MsgBoxParams))) {
  1306. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1307. break;
  1308. }
  1309. if(!SetWindowText(hdlg,PromptParams->MsgBoxParams.lpszCaption)) {
  1310. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1311. break;
  1312. }
  1313. if(!SetWindowText(hdlg,PromptParams->MsgBoxParams.lpszCaption)) {
  1314. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1315. break;
  1316. }
  1317. if (!SetDlgItemText(hdlg,IDT_TEXT1,PromptParams->MsgBoxParams.lpszText)) {
  1318. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1319. break;
  1320. }
  1321. hIcon = LoadIcon(MyDllModuleHandle,PromptParams->MsgBoxParams.lpszIcon);
  1322. if(hIcon) {
  1323. SendDlgItemMessage(hdlg,IDI_ICON1,STM_SETICON,(WPARAM)hIcon,0);
  1324. }
  1325. pSetupCenterWindowRelativeToParent(hdlg);
  1326. if ((PromptParams->PathToSource[0] != TEXT('\0')) &&
  1327. _istalpha(PromptParams->PathToSource[0])) {
  1328. UnitMask = (1 << (_totupper(PromptParams->PathToSource[0]) - TEXT('A')));
  1329. }
  1330. b = FALSE;
  1331. break;
  1332. case WM_DEVICECHANGE:
  1333. if ((wParam == DBT_DEVICEARRIVAL) &&
  1334. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_devicetype == DBT_DEVTYP_VOLUME) &&
  1335. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_flags & DBTF_MEDIA) &&
  1336. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_unitmask == UnitMask)) {
  1337. //
  1338. // The user inserted a CD or removable media into the source drive,
  1339. // so do an automatic OK so we can check this new media.
  1340. //
  1341. PostMessage(hdlg, WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED), 0L);
  1342. }
  1343. break;
  1344. case WM_COMMAND:
  1345. if(HIWORD(wParam) == BN_CLICKED) {
  1346. b = TRUE;
  1347. EndDialog(hdlg,LOWORD(wParam));
  1348. break;
  1349. } else {
  1350. b = FALSE;
  1351. }
  1352. break;
  1353. case WM_DESTROY:
  1354. //
  1355. // Nothing to do about this if it fails.
  1356. // Note: the return value is typically a pointer to stack data
  1357. //
  1358. RemoveProp(hdlg,pszDiskPromptPropName);
  1359. //
  1360. // Let default processing take place by indicating that
  1361. // we didn't process this message
  1362. //
  1363. b = FALSE;
  1364. break;
  1365. default:
  1366. if (!g_uQueryCancelAutoPlay) {
  1367. g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
  1368. }
  1369. if (msg == g_uQueryCancelAutoPlay) {
  1370. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
  1371. return 1; // cancel auto-play
  1372. }
  1373. b = FALSE;
  1374. break;
  1375. }
  1376. return(b);
  1377. }
  1378. INT_PTR
  1379. DlgProcDiskPrompt1(
  1380. IN HWND hdlg,
  1381. IN UINT msg,
  1382. IN WPARAM wParam,
  1383. IN LPARAM lParam
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. Dialog procedure for disk prompting dialog.
  1388. The return value for the dialog is
  1389. DPROMPT_CANCEL - user cancelled
  1390. DPROMPT_SKIPFILE - user elected to skip file
  1391. DPROMPT_SUCCESS - disk is in the drive/we found the file we're looking for
  1392. DPROMPT_OUTOFMEMORY - out of memory
  1393. Arguments:
  1394. Standard dialog routine parameters.
  1395. Return Value:
  1396. TRUE if message processed; FALSE if not.
  1397. --*/
  1398. {
  1399. BOOL b = FALSE;
  1400. PPROMPTPARAMS PromptParams;
  1401. TCHAR Text[MAX_PATH];
  1402. BOOL WarnIfSkip;
  1403. BOOL ReallyCancel;
  1404. static DWORD UnitMask = 0xFFFFFFFF;
  1405. switch(msg) {
  1406. case WM_INITDIALOG:
  1407. PromptParams = (PPROMPTPARAMS)lParam;
  1408. MYASSERT( PromptParams != NULL );
  1409. PromptParams->hdlg = hdlg;
  1410. //
  1411. // Initialize the dialog.
  1412. //
  1413. if(InitDiskPromptDialog(PromptParams) && SetDiskPromptDialogText(PromptParams)) {
  1414. //
  1415. // Set focus to directory combobox and continue.
  1416. //
  1417. SetFocus(GetDlgItem(hdlg, PromptParams->ReadOnlyMru ? IDC_COMBO2 : IDC_COMBO1));
  1418. } else {
  1419. //
  1420. // Out of memory.
  1421. //
  1422. b = TRUE;
  1423. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1424. break;
  1425. }
  1426. //
  1427. // Indicate to windows that we set the focus.
  1428. //
  1429. b = FALSE;
  1430. if(!(PromptParams->PromptStyle & IDF_NOBEEP)) {
  1431. MessageBeep(MB_ICONASTERISK);
  1432. }
  1433. if ((PromptParams->PathToSource[0] != TEXT('\0')) &&
  1434. _istalpha(PromptParams->PathToSource[0])) {
  1435. UnitMask = (1 << (_totupper(PromptParams->PathToSource[0]) - TEXT('A')));
  1436. }
  1437. pSetupCenterWindowRelativeToParent(hdlg);
  1438. PostMessage(hdlg,WMX_HELLO,0,0);
  1439. break;
  1440. case WMX_HELLO:
  1441. b = TRUE;
  1442. PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
  1443. MYASSERT(PromptParams != NULL);
  1444. if(PromptParams && !(PromptParams->PromptStyle & IDF_NOFOREGROUND)) {
  1445. SetForegroundWindow(hdlg);
  1446. }
  1447. break;
  1448. case WM_DEVICECHANGE:
  1449. if ((wParam == DBT_DEVICEARRIVAL) &&
  1450. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_devicetype == DBT_DEVTYP_VOLUME) &&
  1451. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_flags & DBTF_MEDIA) &&
  1452. (((PDEV_BROADCAST_VOLUME)lParam)->dbcv_unitmask == UnitMask)) {
  1453. //
  1454. // The user inserted a CD or removable media into the source drive,
  1455. // so do an automatic OK so we can check this new media.
  1456. //
  1457. PostMessage(hdlg, WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED), 0L);
  1458. }
  1459. break;
  1460. case WM_COMMAND:
  1461. if(HIWORD(wParam) == BN_CLICKED) {
  1462. PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
  1463. MYASSERT(PromptParams != NULL);
  1464. WarnIfSkip = (PromptParams && (PromptParams->PromptStyle & IDF_WARNIFSKIP));
  1465. b = TRUE;
  1466. switch(LOWORD(wParam)) {
  1467. case IDOK:
  1468. //
  1469. // We'd better not get here if controls are disabled!
  1470. //
  1471. MYASSERT(!PromptParams->ControlsDisabled);
  1472. //
  1473. // User might have changed the source path.
  1474. // Get the current path from the combo's edit control
  1475. //
  1476. Text[0] = TEXT('\0'); // default value
  1477. GetDlgItemText(hdlg,PromptParams->ComboBoxId,Text,SIZECHARS(Text));
  1478. Text[SIZECHARS(Text)-1] = TEXT('\0'); // make sure it's terminated.
  1479. MyFree(PromptParams->PathToSource);
  1480. PromptParams->PathToSource = DuplicateString(Text);
  1481. DiskPromptGetDriveType(Text,&PromptParams->DriveType,&PromptParams->IsRemovable);
  1482. //
  1483. // See whether we can get at the file.
  1484. //
  1485. if(!PromptParams->PathToSource || !StartPresenceCheck(PromptParams)) {
  1486. EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
  1487. }
  1488. break;
  1489. case IDCANCEL:
  1490. //
  1491. // We'd better not get here if controls are disabled!
  1492. //
  1493. MYASSERT(!PromptParams->ControlsDisabled);
  1494. //
  1495. // ask if they want to cancel all copies or just cancel one copy
  1496. //
  1497. if (PromptParams->DialogType != DLGTYPE_ERROR) {
  1498. ReallyCancel = TRUE;
  1499. } else {
  1500. if (PromptParams->PromptStyle & IDF_NOSKIP) {
  1501. ReallyCancel = TRUE;
  1502. } else {
  1503. ReallyCancel = !CancelAllCopies(hdlg);
  1504. }
  1505. }
  1506. if(WarnIfSkip ? WarnSkip(hdlg,!ReallyCancel) : TRUE) {
  1507. //
  1508. // If we're currently doing a file presence check, then
  1509. // just increment our PresenceCheckState value, and defer
  1510. // the EndDialog until receipt of WMX_PRESENCE_RESULT.
  1511. //
  1512. if (ReallyCancel) {
  1513. if(PromptParams->PresenceCheckState == 0) {
  1514. EndDialog(hdlg,DPROMPT_CANCEL);
  1515. } else {
  1516. (PromptParams->PresenceCheckState)++;
  1517. }
  1518. } else {
  1519. EndDialog(hdlg,DPROMPT_SKIPFILE);
  1520. }
  1521. }
  1522. break;
  1523. case IDB_BROWSE:
  1524. //
  1525. // We'd better not get here if controls are disabled!
  1526. //
  1527. MYASSERT(!PromptParams->ControlsDisabled);
  1528. if(DoBrowse(hdlg,PromptParams)) {
  1529. PromptParams->UserBrowsed = TRUE;
  1530. }
  1531. break;
  1532. default:
  1533. b = FALSE;
  1534. break;
  1535. }
  1536. } else {
  1537. b = FALSE;
  1538. }
  1539. break;
  1540. case WM_DESTROY:
  1541. #if ASSERTS_ON
  1542. //
  1543. // We'd better not have an outstanding presence check thread running!
  1544. //
  1545. PromptParams = (PPROMPTPARAMS)GetProp(hdlg, pszDiskPromptPropName);
  1546. MYASSERT(PromptParams != NULL);
  1547. if(PromptParams) {
  1548. MYASSERT(!PromptParams->PresenceCheckThreadRunning);
  1549. }
  1550. #endif // ASSERTS_ON
  1551. //
  1552. // Nothing to do about this if it fails.
  1553. //
  1554. RemoveProp(hdlg,pszDiskPromptPropName);
  1555. //
  1556. // Let default processing take place by indicating that
  1557. // we didn't process this message
  1558. //
  1559. b = FALSE;
  1560. break;
  1561. case WMX_PRESENCE_RESULT:
  1562. //
  1563. // Make sure this message came from AuxPromptThread--we've seen weird
  1564. // stress failures indicating that someone else was sending us this
  1565. // message from time to time.
  1566. //
  1567. MYASSERT(lParam == PRESENCE_RESULT_SIG);
  1568. //
  1569. // In case the above does happen, just ignore this message...
  1570. //
  1571. if(lParam != PRESENCE_RESULT_SIG) {
  1572. b = FALSE;
  1573. break;
  1574. }
  1575. b = TRUE;
  1576. PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
  1577. //
  1578. // Also, we don't expect to get this message unless we actually had a
  1579. // presence check thread running.
  1580. //
  1581. MYASSERT(PromptParams != NULL);
  1582. MYASSERT(PromptParams->PresenceCheckState);
  1583. //
  1584. // If the user pressed cancel while we were off doing our presence
  1585. // check, then honor that request now.
  1586. //
  1587. if(PromptParams->PresenceCheckState > 1) {
  1588. EndDialog(hdlg, DPROMPT_CANCEL);
  1589. }
  1590. //
  1591. // Aux thread is telling us that it knows whether the file is present.
  1592. // wParam has the boolean.
  1593. // PromptParams->PathToSource is already set.
  1594. //
  1595. if(wParam) {
  1596. EndDialog(hdlg,DPROMPT_SUCCESS);
  1597. } else {
  1598. //
  1599. // File/disk is not accessible. Don't end the dialog.
  1600. //
  1601. if(!(PromptParams->PromptStyle & IDF_NOFOREGROUND)) {
  1602. SetForegroundWindow(hdlg);
  1603. }
  1604. //
  1605. // If we're searching for a directory containing INFs (e.g.,
  1606. // SetupDiSelectOEMDrv), then we want to popup a message informing
  1607. // the user that the location they've specified doesn't contain
  1608. // information about their hardware. Otherwise, we want to maintain
  1609. // the file prompt behavior of just beeping.
  1610. //
  1611. if(lstrcmpi(PromptParams->FileSought, pszInfWildcard)) {
  1612. if(!(PromptParams->PromptStyle & IDF_NOBEEP)) {
  1613. MessageBeep(MB_ICONASTERISK);
  1614. }
  1615. } else {
  1616. if(!LoadString(MyDllModuleHandle,
  1617. IDS_SELECT_DEVICE,
  1618. Text,
  1619. SIZECHARS(Text))) {
  1620. *Text = TEXT('\0');
  1621. }
  1622. FormatMessageBox(MyDllModuleHandle,
  1623. NULL,
  1624. MSG_NO_DEVICEINFO_ERROR,
  1625. Text,
  1626. MB_OK | MB_TASKMODAL
  1627. );
  1628. }
  1629. //
  1630. // Reset value indicating we're no longer doing a presence check.
  1631. //
  1632. PromptParams->PresenceCheckState = 0;
  1633. //
  1634. // Restore controls that were disabled when we started the presence check.
  1635. //
  1636. PresenceCheckSetControls(PromptParams,FALSE);
  1637. SetFocus(GetDlgItem(hdlg,PromptParams->ComboBoxId));
  1638. }
  1639. break;
  1640. default:
  1641. if (!g_uQueryCancelAutoPlay) {
  1642. g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
  1643. }
  1644. if (msg == g_uQueryCancelAutoPlay) {
  1645. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
  1646. return 1; // cancel auto-play
  1647. }
  1648. b = FALSE;
  1649. break;
  1650. }
  1651. return(b);
  1652. }
  1653. VOID
  1654. ModifyPathList(
  1655. IN PPROMPTPARAMS Params
  1656. )
  1657. /*++
  1658. Routine Description:
  1659. Modifies a list of installation paths kept in the registry.
  1660. The existing list is scanned for the path the user accepted in the disk
  1661. prompt dialog. That path is added if not already in the list.
  1662. Arguments:
  1663. Params - supplies disk prompt dialog parameters.
  1664. Return Value:
  1665. None. If any part of the operation, the list simply doesn't get updated
  1666. in the registry.
  1667. --*/
  1668. {
  1669. //
  1670. // Params->PathToSource will be the final path entered by the user
  1671. // in the combo box. Add to list. If this fails, oh well.
  1672. //
  1673. SetupAddToSourceList(SRCLIST_SYSIFADMIN,Params->PathToSource);
  1674. }
  1675. UINT
  1676. _SetupPromptForDisk(
  1677. IN HWND hwndParent,
  1678. IN PCTSTR DialogTitle, OPTIONAL
  1679. IN PCTSTR DiskName, OPTIONAL
  1680. IN PCTSTR PathToSource, OPTIONAL
  1681. IN PCTSTR FileSought,
  1682. IN PCTSTR TagFile, OPTIONAL
  1683. IN DWORD DiskPromptStyle,
  1684. OUT PTSTR PathBuffer,
  1685. IN DWORD PathBufferSize,
  1686. OUT PDWORD PathRequiredSize OPTIONAL
  1687. )
  1688. {
  1689. PROMPTPARAMS Params;
  1690. INT_PTR i;
  1691. TCHAR Buffer[256];
  1692. DWORD d;
  1693. DWORD ResultPathLen;
  1694. PTSTR Message;
  1695. HANDLE hDialogEvent = NULL;
  1696. BOOL PromptUser = FALSE;
  1697. //
  1698. // If we're running non-interactive, bail now. Unless, that is, we've been
  1699. // instructed to check for the presence of the source file _before_ doing
  1700. // any UI, in which case we can hang around until we do our presence check
  1701. // down below.
  1702. //
  1703. if((GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) &&
  1704. !(DiskPromptStyle & IDF_CHECKFIRST)) {
  1705. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  1706. return DPROMPT_CANCEL;
  1707. }
  1708. //
  1709. // It is illegal to specify both the IDF_USEDISKNAMEASPROMPT and the
  1710. // IDF_OEMDISK flag. This is due to the fact that they both cause
  1711. // a different style of UI text to be displayed that would conflict
  1712. // with itself.
  1713. //
  1714. if ((DiskPromptStyle & IDF_USEDISKNAMEASPROMPT) &&
  1715. (DiskPromptStyle & IDF_OEMDISK)) {
  1716. SetLastError(ERROR_INVALID_PARAMETER);
  1717. return DPROMPT_CANCEL;
  1718. }
  1719. ZeroMemory(&Params,sizeof(PROMPTPARAMS));
  1720. //
  1721. // Determine the path to the source. Start by fetching the entire
  1722. // installation locations list for the current user.
  1723. //
  1724. d = pSetupGetList(0,&Params.PathList,&Params.PathCount,&Params.ReadOnlyMru);
  1725. if(d != NO_ERROR) {
  1726. i = DPROMPT_OUTOFMEMORY;
  1727. goto c0;
  1728. }
  1729. if(PathToSource) {
  1730. //
  1731. // Code in dialog box relies on being able to free this
  1732. // so duplicate it here.
  1733. //
  1734. Params.PathToSource = DuplicateString(PathToSource);
  1735. } else {
  1736. if(Params.PathCount) {
  1737. Params.PathToSource = DuplicateString(Params.PathList[0]);
  1738. } else {
  1739. //
  1740. // Nothing in system path lists. Use a reasonable default.
  1741. //
  1742. Params.PathToSource = DuplicateString(pszOemInfDefaultPath);
  1743. }
  1744. }
  1745. if(!Params.PathToSource) {
  1746. i = DPROMPT_OUTOFMEMORY;
  1747. d = ERROR_NOT_ENOUGH_MEMORY;
  1748. goto c1;
  1749. }
  1750. //
  1751. // Determine the drive type of the source path.
  1752. //
  1753. DiskPromptGetDriveType(Params.PathToSource,&Params.DriveType,&Params.IsRemovable);
  1754. //
  1755. // If the disk name wasn't specified, fetch a default.
  1756. //
  1757. if(DiskName) {
  1758. Params.DiskName = DiskName;
  1759. } else {
  1760. Params.DiskName = MyLoadString(IDS_UNKNOWN_PARENS);
  1761. if(!Params.DiskName) {
  1762. i = DPROMPT_OUTOFMEMORY;
  1763. d = ERROR_NOT_ENOUGH_MEMORY;
  1764. goto c2;
  1765. }
  1766. }
  1767. //
  1768. // If a dialog title wasn't specified, try to get text from parent window.
  1769. //
  1770. if(DialogTitle) {
  1771. Params.DialogTitle = DialogTitle;
  1772. } else {
  1773. if(Params.Owner
  1774. && (i = GetWindowTextLength(Params.Owner))
  1775. && GetWindowText(Params.Owner,Buffer,sizeof(Buffer)/sizeof(TCHAR))) {
  1776. Params.DialogTitle = FormatStringMessage(IDS_FILESNEEDED2,Buffer);
  1777. } else {
  1778. Params.DialogTitle = MyLoadString(IDS_FILESNEEDED);
  1779. }
  1780. if(!Params.DialogTitle) {
  1781. i = DPROMPT_OUTOFMEMORY;
  1782. d = ERROR_NOT_ENOUGH_MEMORY;
  1783. goto c3;
  1784. }
  1785. }
  1786. Params.TagFile = TagFile;
  1787. //
  1788. // Validate parent window.
  1789. //
  1790. Params.Owner = IsWindow(hwndParent) ? hwndParent : NULL;
  1791. //
  1792. // Fill in other fields.
  1793. //
  1794. if((Params.FileSought = FileSought) == NULL) {
  1795. i = DPROMPT_CANCEL;
  1796. d = ERROR_INVALID_PARAMETER;
  1797. goto c4;
  1798. }
  1799. Params.Owner = hwndParent;
  1800. Params.PromptStyle = DiskPromptStyle | IDF_NODETAILS;
  1801. Params.hdlg = NULL;
  1802. Params.UserBrowsed = FALSE;
  1803. Params.DialogType = DLGTYPE_PROMPT;
  1804. Params.TargetFile = NULL;
  1805. if(Params.ReadOnlyMru) {
  1806. Params.PromptStyle |= IDF_NOBROWSE;
  1807. }
  1808. if (GuiSetupInProgress) {
  1809. hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
  1810. }
  1811. //
  1812. // If we're supposed to, check for the disk/file first.
  1813. //
  1814. if((DiskPromptStyle & IDF_CHECKFIRST) && DoPresenceCheck(&Params, FALSE)) {
  1815. i = DPROMPT_SUCCESS;
  1816. d = NO_ERROR;
  1817. } else if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  1818. i = DPROMPT_CANCEL;
  1819. d = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1820. } else {
  1821. //
  1822. // Before invoking the dialog, we will prompt the user with a simple
  1823. // message box in some cases to avoid the user ever actually seeing
  1824. // a path in the more complicated prompt dialog.
  1825. //
  1826. if(DiskName &&
  1827. !(DiskPromptStyle & IDF_NOREMOVABLEMEDIAPROMPT) &&
  1828. ((Params.DriveType == DRIVE_REMOVABLE) || (Params.DriveType == DRIVE_CDROM))) {
  1829. Message = RetreiveAndFormatMessage(
  1830. (Params.DriveType == DRIVE_CDROM)
  1831. ? ( GuiSetupInProgress ? MSG_CDPROMPT_NONETWORK : MSG_CDPROMPT )
  1832. : ( GuiSetupInProgress ? MSG_FLOPPYPROMPT_NONETWORK : MSG_FLOPPYPROMPT ),
  1833. DiskName,
  1834. (TCHAR)CharUpper((PTSTR)Params.PathToSource[0])
  1835. );
  1836. if(Message) {
  1837. LoadString(MyDllModuleHandle,IDS_PROMPTTITLE,Buffer,sizeof(Buffer)/sizeof(TCHAR));
  1838. if(!(DiskPromptStyle & IDF_NOBEEP)) {
  1839. MessageBeep(MB_ICONASTERISK);
  1840. }
  1841. reprompt:
  1842. Params.MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS);
  1843. Params.MsgBoxParams.hwndOwner = hwndParent;
  1844. Params.MsgBoxParams.hInstance = MyDllModuleHandle;
  1845. Params.MsgBoxParams.lpszText = Message;
  1846. Params.MsgBoxParams.lpszCaption = Buffer;
  1847. Params.MsgBoxParams.dwStyle = MB_USERICON | MB_OKCANCEL;
  1848. Params.MsgBoxParams.lpszIcon = (Params.DriveType == DRIVE_CDROM)
  1849. ? MAKEINTRESOURCE(ICON_CD)
  1850. : MAKEINTRESOURCE(ICON_FLOPPY);
  1851. Params.MsgBoxParams.lpfnMsgBoxCallback = NULL;
  1852. Params.MsgBoxParams.dwLanguageId = LANG_NEUTRAL;
  1853. if (hDialogEvent) {
  1854. SetEvent(hDialogEvent);
  1855. }
  1856. switch(DialogBoxParam(
  1857. MyDllModuleHandle,
  1858. MAKEINTRESOURCE(IDD_SIMPLEPROMPT),
  1859. hwndParent,
  1860. DlgProcSimplePrompt,
  1861. (LPARAM)&Params
  1862. )) {
  1863. case DPROMPT_OUTOFMEMORY:
  1864. i = DPROMPT_OUTOFMEMORY;
  1865. d = ERROR_NOT_ENOUGH_MEMORY;
  1866. break;
  1867. case IDOK:
  1868. if(DoPresenceCheck(&Params, FALSE)) {
  1869. i = DPROMPT_SUCCESS;
  1870. d = NO_ERROR;
  1871. } else {
  1872. i = DPROMPT_SKIPFILE;
  1873. }
  1874. break;
  1875. case IDCANCEL:
  1876. d = ERROR_CANCELLED;
  1877. i = DPROMPT_CANCEL;
  1878. if((DiskPromptStyle & IDF_WARNIFSKIP) && !WarnSkip(hwndParent,FALSE)) {
  1879. goto reprompt;
  1880. }
  1881. break;
  1882. default:
  1883. MYASSERT( FALSE );
  1884. }
  1885. if (hDialogEvent) {
  1886. ResetEvent(hDialogEvent);
  1887. }
  1888. MyFree(Message);
  1889. } else {
  1890. i = DPROMPT_OUTOFMEMORY;
  1891. d = ERROR_NOT_ENOUGH_MEMORY;
  1892. goto c4;
  1893. }
  1894. } else {
  1895. i = DPROMPT_SKIPFILE;
  1896. }
  1897. if(i == DPROMPT_SKIPFILE) {
  1898. if (hDialogEvent) {
  1899. SetEvent(hDialogEvent);
  1900. }
  1901. Params.BrowseAutoComplete = FALSE;
  1902. if(!GuiSetupInProgress) {
  1903. d = OleInitialize(NULL);
  1904. if(SUCCEEDED(d)) {
  1905. Params.BrowseAutoComplete = TRUE;
  1906. }
  1907. }
  1908. i = DialogBoxParam(
  1909. MyDllModuleHandle,
  1910. MAKEINTRESOURCE(IDD_DISKPROMPT1),
  1911. hwndParent,
  1912. DlgProcDiskPrompt1,
  1913. (LPARAM)&Params
  1914. );
  1915. if(!GuiSetupInProgress && (d==NO_ERROR)) {
  1916. OleUninitialize();
  1917. }
  1918. if (hDialogEvent) {
  1919. ResetEvent(hDialogEvent);
  1920. }
  1921. switch(i) {
  1922. case DPROMPT_SUCCESS:
  1923. PromptUser = TRUE;
  1924. d = NO_ERROR;
  1925. break;
  1926. case DPROMPT_SKIPFILE:
  1927. d = NO_ERROR;
  1928. break;
  1929. case DPROMPT_CANCEL:
  1930. d = ERROR_CANCELLED;
  1931. break;
  1932. case DPROMPT_BUFFERTOOSMALL:
  1933. d = ERROR_INSUFFICIENT_BUFFER;
  1934. break;
  1935. default:
  1936. i = DPROMPT_OUTOFMEMORY;
  1937. d = ERROR_NOT_ENOUGH_MEMORY;
  1938. break;
  1939. }
  1940. }
  1941. }
  1942. //
  1943. // If success, we want to add the path string to the list of path strings
  1944. // if it's not already in there.
  1945. //
  1946. if(i == DPROMPT_SUCCESS) {
  1947. //
  1948. // Only add the file to the MRU list if we prompted the user and
  1949. // they entered a valid path.
  1950. //
  1951. if (PromptUser) {
  1952. ModifyPathList(&Params);
  1953. }
  1954. //
  1955. // Now determine what to return to the user depending on the
  1956. // buffer and sizes passed in.
  1957. //
  1958. ResultPathLen = lstrlen(Params.PathToSource)+1;
  1959. if(PathRequiredSize) {
  1960. *PathRequiredSize = ResultPathLen;
  1961. }
  1962. if(PathBuffer) {
  1963. if(ResultPathLen > PathBufferSize) {
  1964. i = DPROMPT_BUFFERTOOSMALL;
  1965. } else {
  1966. lstrcpy(PathBuffer,Params.PathToSource);
  1967. }
  1968. }
  1969. }
  1970. c4:
  1971. if (hDialogEvent) {
  1972. CloseHandle(hDialogEvent);
  1973. }
  1974. if(!DialogTitle) {
  1975. MyFree(Params.DialogTitle);
  1976. }
  1977. c3:
  1978. if(!DiskName) {
  1979. MyFree(Params.DiskName);
  1980. }
  1981. c2:
  1982. MyFree(Params.PathToSource);
  1983. c1:
  1984. SetupFreeSourceList(&Params.PathList,Params.PathCount);
  1985. c0:
  1986. SetLastError(d);
  1987. return((UINT)i);
  1988. }
  1989. #ifdef UNICODE
  1990. //
  1991. // ANSI version
  1992. //
  1993. UINT
  1994. SetupPromptForDiskA(
  1995. IN HWND hwndParent,
  1996. IN PCSTR DialogTitle, OPTIONAL
  1997. IN PCSTR DiskName, OPTIONAL
  1998. IN PCSTR PathToSource, OPTIONAL
  1999. IN PCSTR FileSought,
  2000. IN PCSTR TagFile, OPTIONAL
  2001. IN DWORD DiskPromptStyle,
  2002. OUT PSTR PathBuffer,
  2003. IN DWORD PathBufferSize,
  2004. OUT PDWORD PathRequiredSize OPTIONAL
  2005. )
  2006. {
  2007. PCWSTR dialogTitle;
  2008. PCWSTR diskName;
  2009. PCWSTR pathToSource;
  2010. PCWSTR fileSought;
  2011. PCWSTR tagFile;
  2012. WCHAR pathBuffer[MAX_PATH];
  2013. CHAR ansiBuffer[MAX_PATH];
  2014. DWORD rc;
  2015. UINT u;
  2016. DWORD Size;
  2017. dialogTitle = NULL;
  2018. diskName = NULL;
  2019. pathToSource = NULL;
  2020. fileSought = NULL;
  2021. tagFile = NULL;
  2022. rc = NO_ERROR;
  2023. if(DialogTitle) {
  2024. rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
  2025. }
  2026. if((rc == NO_ERROR) && DiskName) {
  2027. rc = pSetupCaptureAndConvertAnsiArg(DiskName,&diskName);
  2028. }
  2029. if((rc == NO_ERROR) && PathToSource) {
  2030. rc = pSetupCaptureAndConvertAnsiArg(PathToSource,&pathToSource);
  2031. }
  2032. if((rc == NO_ERROR) && FileSought) {
  2033. rc = pSetupCaptureAndConvertAnsiArg(FileSought,&fileSought);
  2034. }
  2035. if((rc == NO_ERROR) && TagFile) {
  2036. rc = pSetupCaptureAndConvertAnsiArg(TagFile,&tagFile);
  2037. }
  2038. if(rc == NO_ERROR) {
  2039. u = _SetupPromptForDisk(
  2040. hwndParent,
  2041. dialogTitle,
  2042. diskName,
  2043. pathToSource,
  2044. fileSought,
  2045. tagFile,
  2046. DiskPromptStyle,
  2047. pathBuffer,
  2048. MAX_PATH,
  2049. &Size
  2050. );
  2051. rc = GetLastError();
  2052. if(u == DPROMPT_SUCCESS) {
  2053. Size = (DWORD)WideCharToMultiByte(
  2054. CP_ACP,
  2055. 0,
  2056. pathBuffer,
  2057. (int)Size,
  2058. ansiBuffer,
  2059. MAX_PATH,
  2060. NULL,
  2061. NULL
  2062. );
  2063. if(PathRequiredSize) {
  2064. *PathRequiredSize = Size;
  2065. }
  2066. if(PathBuffer) {
  2067. if(Size > PathBufferSize) {
  2068. u = DPROMPT_BUFFERTOOSMALL;
  2069. } else {
  2070. lstrcpynA(PathBuffer,ansiBuffer,Size);
  2071. }
  2072. }
  2073. }
  2074. } else {
  2075. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2076. }
  2077. if(dialogTitle) {
  2078. MyFree(dialogTitle);
  2079. }
  2080. if(diskName) {
  2081. MyFree(diskName);
  2082. }
  2083. if(pathToSource) {
  2084. MyFree(pathToSource);
  2085. }
  2086. if(fileSought) {
  2087. MyFree(fileSought);
  2088. }
  2089. if(tagFile) {
  2090. MyFree(tagFile);
  2091. }
  2092. SetLastError(rc);
  2093. return(u);
  2094. }
  2095. #else
  2096. //
  2097. // Unicode stub
  2098. //
  2099. UINT
  2100. SetupPromptForDiskW(
  2101. IN HWND hwndParent,
  2102. IN PCWSTR DialogTitle, OPTIONAL
  2103. IN PCWSTR DiskName, OPTIONAL
  2104. IN PCWSTR PathToSource, OPTIONAL
  2105. IN PCWSTR FileSought,
  2106. IN PCWSTR TagFile, OPTIONAL
  2107. IN DWORD DiskPromptStyle,
  2108. OUT PWSTR PathBuffer,
  2109. IN DWORD PathBufferSize,
  2110. OUT PDWORD PathRequiredSize OPTIONAL
  2111. )
  2112. {
  2113. UNREFERENCED_PARAMETER(hwndParent);
  2114. UNREFERENCED_PARAMETER(DialogTitle);
  2115. UNREFERENCED_PARAMETER(DiskName);
  2116. UNREFERENCED_PARAMETER(PathToSource);
  2117. UNREFERENCED_PARAMETER(FileSought);
  2118. UNREFERENCED_PARAMETER(TagFile);
  2119. UNREFERENCED_PARAMETER(DiskPromptStyle);
  2120. UNREFERENCED_PARAMETER(PathBuffer);
  2121. UNREFERENCED_PARAMETER(PathBufferSize);
  2122. UNREFERENCED_PARAMETER(PathRequiredSize);
  2123. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2124. return(DPROMPT_CANCEL);
  2125. }
  2126. #endif
  2127. UINT
  2128. SetupPromptForDisk(
  2129. IN HWND hwndParent,
  2130. IN PCTSTR DialogTitle, OPTIONAL
  2131. IN PCTSTR DiskName, OPTIONAL
  2132. IN PCTSTR PathToSource, OPTIONAL
  2133. IN PCTSTR FileSought,
  2134. IN PCTSTR TagFile, OPTIONAL
  2135. IN DWORD DiskPromptStyle,
  2136. OUT PTSTR PathBuffer,
  2137. IN DWORD PathBufferSize,
  2138. OUT PDWORD PathRequiredSize OPTIONAL
  2139. )
  2140. {
  2141. PCTSTR dialogTitle;
  2142. PCTSTR diskName;
  2143. PCTSTR pathToSource;
  2144. PCTSTR fileSought;
  2145. PCTSTR tagFile;
  2146. TCHAR pathBuffer[MAX_PATH];
  2147. DWORD rc;
  2148. UINT u;
  2149. DWORD Size;
  2150. dialogTitle = NULL;
  2151. diskName = NULL;
  2152. pathToSource = NULL;
  2153. fileSought = NULL;
  2154. tagFile = NULL;
  2155. rc = NO_ERROR;
  2156. if(DialogTitle) {
  2157. rc = CaptureStringArg(DialogTitle,&dialogTitle);
  2158. }
  2159. if((rc == NO_ERROR) && DiskName) {
  2160. rc = CaptureStringArg(DiskName,&diskName);
  2161. }
  2162. if((rc == NO_ERROR) && PathToSource) {
  2163. rc = CaptureStringArg(PathToSource,&pathToSource);
  2164. }
  2165. if((rc == NO_ERROR) && FileSought) {
  2166. rc = CaptureStringArg(FileSought,&fileSought);
  2167. }
  2168. if((rc == NO_ERROR) && TagFile) {
  2169. rc = CaptureStringArg(TagFile,&tagFile);
  2170. }
  2171. if(rc == NO_ERROR) {
  2172. u = _SetupPromptForDisk(
  2173. hwndParent,
  2174. dialogTitle,
  2175. diskName,
  2176. pathToSource,
  2177. fileSought,
  2178. tagFile,
  2179. DiskPromptStyle,
  2180. pathBuffer,
  2181. MAX_PATH,
  2182. &Size
  2183. );
  2184. rc = GetLastError();
  2185. if(u == DPROMPT_SUCCESS) {
  2186. if(PathRequiredSize) {
  2187. *PathRequiredSize = Size;
  2188. }
  2189. if(PathBuffer) {
  2190. if(Size > PathBufferSize) {
  2191. u = DPROMPT_BUFFERTOOSMALL;
  2192. } else {
  2193. lstrcpyn(PathBuffer,pathBuffer,Size);
  2194. }
  2195. }
  2196. }
  2197. } else {
  2198. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2199. }
  2200. if(dialogTitle) {
  2201. MyFree(dialogTitle);
  2202. }
  2203. if(diskName) {
  2204. MyFree(diskName);
  2205. }
  2206. if(pathToSource) {
  2207. MyFree(pathToSource);
  2208. }
  2209. if(fileSought) {
  2210. MyFree(fileSought);
  2211. }
  2212. if(tagFile) {
  2213. MyFree(tagFile);
  2214. }
  2215. SetLastError(rc);
  2216. return(u);
  2217. }
  2218. INT_PTR
  2219. DlgProcFileError(
  2220. IN HWND hdlg,
  2221. IN UINT msg,
  2222. IN WPARAM wParam,
  2223. IN LPARAM lParam
  2224. )
  2225. /*++
  2226. Routine Description:
  2227. Dialog procedure for delete/rename error dialog.
  2228. The return value for the dialog is
  2229. DPROMPT_CANCEL - user cancelled
  2230. DPROMPT_SKIPFILE - user elected to skip file
  2231. DPROMPT_SUCCESS - user said retry
  2232. DPROMPT_OUTOFMEMORY - out of memory
  2233. Arguments:
  2234. Standard dialog routine parameters.
  2235. Return Value:
  2236. TRUE if message processed; FALSE if not.
  2237. --*/
  2238. {
  2239. static PFILEERRDLGPARAMS Params = NULL;
  2240. BOOL b;
  2241. switch(msg) {
  2242. case WM_INITDIALOG:
  2243. Params = (PFILEERRDLGPARAMS)lParam;
  2244. SetDlgItemText(hdlg,IDT_TEXT1,Params->MessageText);
  2245. SetWindowText(hdlg,Params->Caption);
  2246. SendDlgItemMessage(
  2247. hdlg,
  2248. IDI_ICON1,
  2249. STM_SETICON,
  2250. (WPARAM)LoadIcon(NULL,IDI_HAND),
  2251. 0
  2252. );
  2253. if(!(Params->Style & IDF_NOBEEP)) {
  2254. MessageBeep(MB_ICONASTERISK);
  2255. }
  2256. if(!(Params->Style & IDF_NOFOREGROUND)) {
  2257. PostMessage(hdlg,WMX_HELLO,0,0);
  2258. }
  2259. pSetupCenterWindowRelativeToParent(hdlg);
  2260. //
  2261. // Set focus to retry button and continue.
  2262. //
  2263. SetFocus(GetDlgItem(hdlg,IDOK));
  2264. b = FALSE;
  2265. break;
  2266. case WMX_HELLO:
  2267. SetForegroundWindow(hdlg);
  2268. b = TRUE;
  2269. break;
  2270. case WM_COMMAND:
  2271. if(HIWORD(wParam) == BN_CLICKED) {
  2272. b = TRUE;
  2273. switch(LOWORD(wParam)) {
  2274. case IDOK:
  2275. EndDialog(hdlg,DPROMPT_SUCCESS);
  2276. break;
  2277. case IDCANCEL:
  2278. if ( (Params->Style & IDF_NOSKIP) || !CancelAllCopies(hdlg)) {
  2279. EndDialog(hdlg,DPROMPT_CANCEL);
  2280. } else {
  2281. EndDialog(hdlg,DPROMPT_SKIPFILE);
  2282. }
  2283. break;
  2284. default:
  2285. b = FALSE;
  2286. break;
  2287. }
  2288. } else {
  2289. b = FALSE;
  2290. }
  2291. break;
  2292. default:
  2293. if (!g_uQueryCancelAutoPlay) {
  2294. g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
  2295. }
  2296. if (msg == g_uQueryCancelAutoPlay) {
  2297. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
  2298. return 1; // cancel auto-play
  2299. }
  2300. b = FALSE;
  2301. break;
  2302. }
  2303. return(b);
  2304. }
  2305. #ifdef UNICODE
  2306. //
  2307. // ANSI version
  2308. //
  2309. UINT
  2310. SetupCopyErrorA(
  2311. IN HWND hwndParent,
  2312. IN PCSTR DialogTitle, OPTIONAL
  2313. IN PCSTR DiskName, OPTIONAL
  2314. IN PCSTR PathToSource,
  2315. IN PCSTR SourceFile,
  2316. IN PCSTR TargetPathFile, OPTIONAL
  2317. IN UINT Win32ErrorCode,
  2318. IN DWORD Style,
  2319. OUT PSTR PathBuffer, OPTIONAL
  2320. IN DWORD PathBufferSize,
  2321. OUT PDWORD PathRequiredSize OPTIONAL
  2322. )
  2323. {
  2324. PCWSTR dialogTitle;
  2325. PCWSTR diskName;
  2326. PCWSTR pathToSource;
  2327. PCWSTR sourceFile;
  2328. PCWSTR targetPathFile;
  2329. WCHAR pathBuffer[MAX_PATH];
  2330. CHAR ansiBuffer[MAX_PATH];
  2331. DWORD rc;
  2332. UINT u;
  2333. DWORD Size;
  2334. dialogTitle = NULL;
  2335. diskName = NULL;
  2336. pathToSource = NULL;
  2337. sourceFile = NULL;
  2338. targetPathFile = NULL;
  2339. rc = NO_ERROR;
  2340. if(DialogTitle) {
  2341. rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
  2342. }
  2343. if((rc == NO_ERROR) && DiskName) {
  2344. rc = pSetupCaptureAndConvertAnsiArg(DiskName,&diskName);
  2345. }
  2346. if((rc == NO_ERROR) && PathToSource) {
  2347. rc = pSetupCaptureAndConvertAnsiArg(PathToSource,&pathToSource);
  2348. }
  2349. if((rc == NO_ERROR) && SourceFile) {
  2350. rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
  2351. }
  2352. if((rc == NO_ERROR) && TargetPathFile) {
  2353. rc = pSetupCaptureAndConvertAnsiArg(TargetPathFile,&targetPathFile);
  2354. }
  2355. if(rc == NO_ERROR) {
  2356. u = SetupCopyErrorW(
  2357. hwndParent,
  2358. dialogTitle,
  2359. diskName,
  2360. pathToSource,
  2361. sourceFile,
  2362. targetPathFile,
  2363. Win32ErrorCode,
  2364. Style,
  2365. pathBuffer,
  2366. MAX_PATH,
  2367. &Size
  2368. );
  2369. rc = GetLastError();
  2370. if(u == DPROMPT_SUCCESS) {
  2371. Size = (DWORD)WideCharToMultiByte(
  2372. CP_ACP,
  2373. 0,
  2374. pathBuffer,
  2375. (int)Size,
  2376. ansiBuffer,
  2377. MAX_PATH,
  2378. NULL,
  2379. NULL
  2380. );
  2381. if(PathRequiredSize) {
  2382. *PathRequiredSize = Size;
  2383. }
  2384. if(PathBuffer) {
  2385. if(Size > PathBufferSize) {
  2386. u = DPROMPT_BUFFERTOOSMALL;
  2387. } else {
  2388. lstrcpynA(PathBuffer,ansiBuffer,Size);
  2389. }
  2390. }
  2391. }
  2392. } else {
  2393. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2394. }
  2395. if(dialogTitle) {
  2396. MyFree(dialogTitle);
  2397. }
  2398. if(diskName) {
  2399. MyFree(diskName);
  2400. }
  2401. if(pathToSource) {
  2402. MyFree(pathToSource);
  2403. }
  2404. if(sourceFile) {
  2405. MyFree(sourceFile);
  2406. }
  2407. if(targetPathFile) {
  2408. MyFree(targetPathFile);
  2409. }
  2410. SetLastError(rc);
  2411. return(u);
  2412. }
  2413. #else
  2414. //
  2415. // Unicode stub
  2416. //
  2417. UINT
  2418. SetupCopyErrorW(
  2419. IN HWND hwndParent,
  2420. IN PCWSTR DialogTitle, OPTIONAL
  2421. IN PCWSTR DiskName, OPTIONAL
  2422. IN PCWSTR PathToSource,
  2423. IN PCWSTR SourceFile,
  2424. IN PCWSTR TargetPathFile, OPTIONAL
  2425. IN UINT Win32ErrorCode,
  2426. IN DWORD Style,
  2427. OUT PWSTR PathBuffer, OPTIONAL
  2428. IN DWORD PathBufferSize,
  2429. OUT PDWORD PathRequiredSize OPTIONAL
  2430. )
  2431. {
  2432. UNREFERENCED_PARAMETER(hwndParent);
  2433. UNREFERENCED_PARAMETER(DialogTitle);
  2434. UNREFERENCED_PARAMETER(DiskName);
  2435. UNREFERENCED_PARAMETER(PathToSource);
  2436. UNREFERENCED_PARAMETER(SourceFile);
  2437. UNREFERENCED_PARAMETER(TargetPathFile);
  2438. UNREFERENCED_PARAMETER(Win32ErrorCode);
  2439. UNREFERENCED_PARAMETER(Style);
  2440. UNREFERENCED_PARAMETER(PathBuffer);
  2441. UNREFERENCED_PARAMETER(PathBufferSize);
  2442. UNREFERENCED_PARAMETER(PathRequiredSize);
  2443. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2444. return(DPROMPT_CANCEL);
  2445. }
  2446. #endif
  2447. UINT
  2448. SetupCopyError(
  2449. IN HWND hwndParent,
  2450. IN PCTSTR DialogTitle, OPTIONAL
  2451. IN PCTSTR DiskName, OPTIONAL
  2452. IN PCTSTR PathToSource,
  2453. IN PCTSTR SourceFile,
  2454. IN PCTSTR TargetPathFile, OPTIONAL
  2455. IN UINT Win32ErrorCode,
  2456. IN DWORD Style,
  2457. OUT PTSTR PathBuffer, OPTIONAL
  2458. IN DWORD PathBufferSize,
  2459. OUT PDWORD PathRequiredSize OPTIONAL
  2460. )
  2461. /*++
  2462. Routine Description:
  2463. Inform the user about a file copy error.
  2464. Arguments:
  2465. hwndParent - supplies window handle of window/dialog to own the error dialog
  2466. displayed by this routine.
  2467. DialogTitle - if specified, supplies title for error dialog. If not specified
  2468. a default of "Copy Error" will be supplied.
  2469. DiskName - if specified, supplies name of the disk from which a source file
  2470. was expected. If not specified a default of "(Unknown)" will be supplied.
  2471. PathToSource - supplies full path part of source file name.
  2472. SourceFile - supplies filename part of the source file name.
  2473. TargetPathFile - if specified supplies the full pathname of the target.
  2474. Win32ErrorCode - supplies win32 error code of failure.
  2475. Style - supplies flags to control the behavior of the dialog.
  2476. Return Value:
  2477. DPROMPT_xxx indicating outcome.
  2478. --*/
  2479. {
  2480. INT_PTR i;
  2481. DWORD d = NO_ERROR;
  2482. DWORD TmpRequiredSize;
  2483. HANDLE hDialogEvent = NULL;
  2484. PCTSTR dialogTitle = NULL;
  2485. PCTSTR diskName = NULL;
  2486. PCTSTR pathToSource = NULL;
  2487. PCTSTR sourceFile = NULL;
  2488. PCTSTR targetPathFile = NULL;
  2489. PTSTR ErrorText = NULL;
  2490. PTSTR Message = NULL;
  2491. PTSTR p;
  2492. //
  2493. // If we're running non-interactive, bail now...
  2494. //
  2495. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  2496. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  2497. return DPROMPT_CANCEL;
  2498. }
  2499. //
  2500. // verify & snap all parameters
  2501. //
  2502. if(DialogTitle) {
  2503. d = CaptureStringArg(DialogTitle,&dialogTitle);
  2504. } else {
  2505. dialogTitle = MyLoadString(IDS_COPYERROR);
  2506. if(!dialogTitle) {
  2507. d = ERROR_NOT_ENOUGH_MEMORY;
  2508. }
  2509. }
  2510. if(d == NO_ERROR) {
  2511. if(DiskName) {
  2512. d = CaptureStringArg(DiskName,&diskName);
  2513. } else {
  2514. diskName = MyLoadString(IDS_UNKNOWN_PARENS);
  2515. if(!diskName) {
  2516. d = ERROR_NOT_ENOUGH_MEMORY;
  2517. }
  2518. }
  2519. }
  2520. if(d == NO_ERROR) {
  2521. if(PathToSource) {
  2522. d = CaptureStringArg(PathToSource,&pathToSource);
  2523. } else {
  2524. d = ERROR_INVALID_PARAMETER;
  2525. }
  2526. }
  2527. if(d == NO_ERROR) {
  2528. if(SourceFile) {
  2529. d = CaptureStringArg(SourceFile,&sourceFile);
  2530. } else {
  2531. d = ERROR_INVALID_PARAMETER;
  2532. }
  2533. }
  2534. if((d == NO_ERROR) && TargetPathFile) {
  2535. d = CaptureStringArg(TargetPathFile,&targetPathFile);
  2536. }
  2537. if(d) {
  2538. if(d == ERROR_NOT_ENOUGH_MEMORY) {
  2539. i = DPROMPT_OUTOFMEMORY;
  2540. } else {
  2541. i = DPROMPT_CANCEL;
  2542. }
  2543. goto clean;
  2544. }
  2545. if(Win32ErrorCode == ERROR_INVALID_TARGET) {
  2546. FILEERRDLGPARAMS FileErrorDlgParams;
  2547. //
  2548. // Fatal copy error not fixed by changing source location
  2549. //
  2550. ErrorText = MyLoadString(IDS_COPY_INVALID_TARGET);
  2551. if(!ErrorText) {
  2552. i = DPROMPT_OUTOFMEMORY;
  2553. goto clean;
  2554. }
  2555. //
  2556. // don't display the error-code in this case
  2557. // just the error text
  2558. //
  2559. Message = RetreiveAndFormatMessage(
  2560. MSG_FILEERROR_COPY,
  2561. sourceFile,
  2562. ErrorText
  2563. );
  2564. if(!Message) {
  2565. i = DPROMPT_OUTOFMEMORY;
  2566. goto clean;
  2567. }
  2568. FileErrorDlgParams.MessageText = Message;
  2569. FileErrorDlgParams.Style = Style;
  2570. FileErrorDlgParams.Caption = dialogTitle;
  2571. if(!FileErrorDlgParams.Caption) {
  2572. i = DPROMPT_OUTOFMEMORY;
  2573. goto clean;
  2574. }
  2575. if (GuiSetupInProgress) {
  2576. hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
  2577. }
  2578. if ( hDialogEvent ) {
  2579. SetEvent( hDialogEvent );
  2580. }
  2581. d = NO_ERROR;
  2582. i = DialogBoxParam(
  2583. MyDllModuleHandle,
  2584. MAKEINTRESOURCE(IDD_FILEERROR2),
  2585. hwndParent,
  2586. DlgProcFileError,
  2587. (LPARAM)&FileErrorDlgParams
  2588. );
  2589. if ( hDialogEvent ) {
  2590. ResetEvent( hDialogEvent );
  2591. CloseHandle( hDialogEvent );
  2592. }
  2593. if(i == -1) {
  2594. i = DPROMPT_OUTOFMEMORY;
  2595. }
  2596. } else {
  2597. PROMPTPARAMS Params;
  2598. ZeroMemory(&Params,sizeof(PROMPTPARAMS));
  2599. //
  2600. // If the dialog title is not specified fetch a default.
  2601. //
  2602. Params.DialogTitle = dialogTitle;
  2603. Params.DiskName = diskName;
  2604. Params.FileSought = sourceFile;
  2605. Params.PathToSource = pathToSource;
  2606. Params.TargetFile = targetPathFile;
  2607. //
  2608. // assume dialog proc may change any of these
  2609. //
  2610. dialogTitle = NULL;
  2611. diskName = NULL;
  2612. sourceFile = NULL;
  2613. pathToSource = NULL;
  2614. targetPathFile = NULL;
  2615. //
  2616. // There is no tag file usage in the error dialog.
  2617. //
  2618. Params.TagFile = NULL;
  2619. //
  2620. // Determine drive type of source path
  2621. //
  2622. DiskPromptGetDriveType(Params.PathToSource,&Params.DriveType,&Params.IsRemovable);
  2623. //
  2624. // Fetch the installation path list.
  2625. //
  2626. d = pSetupGetList(
  2627. 0,
  2628. &Params.PathList,
  2629. &Params.PathCount,
  2630. &Params.ReadOnlyMru
  2631. );
  2632. if(d != NO_ERROR) {
  2633. i = (d == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2634. goto clean;
  2635. }
  2636. //
  2637. // Other fields
  2638. //
  2639. Params.Owner = hwndParent;
  2640. Params.PromptStyle = Style;
  2641. Params.UserBrowsed = FALSE;
  2642. Params.DialogType = DLGTYPE_ERROR;
  2643. Params.Win32Error = Win32ErrorCode;
  2644. if(Params.ReadOnlyMru) {
  2645. Params.PromptStyle |= IDF_NOBROWSE;
  2646. }
  2647. if (GuiSetupInProgress) {
  2648. hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
  2649. }
  2650. if ( hDialogEvent ) {
  2651. SetEvent( hDialogEvent );
  2652. }
  2653. Params.BrowseAutoComplete = FALSE;
  2654. if(!GuiSetupInProgress) {
  2655. d = OleInitialize(NULL);
  2656. if(SUCCEEDED(d)) {
  2657. Params.BrowseAutoComplete = TRUE;
  2658. }
  2659. }
  2660. i = DialogBoxParam(
  2661. MyDllModuleHandle,
  2662. MAKEINTRESOURCE(IDD_DISKPROMPT1),
  2663. hwndParent,
  2664. DlgProcDiskPrompt1,
  2665. (LPARAM)&Params
  2666. );
  2667. if(!GuiSetupInProgress && (d==NO_ERROR)) {
  2668. OleUninitialize();
  2669. }
  2670. if ( hDialogEvent ) {
  2671. ResetEvent( hDialogEvent );
  2672. CloseHandle( hDialogEvent );
  2673. }
  2674. d = GetLastError();
  2675. if(i == DPROMPT_SUCCESS) {
  2676. ModifyPathList(&Params);
  2677. //
  2678. // Now determine what to return to the user depending on the
  2679. // buffer and sizes passed in.
  2680. //
  2681. TmpRequiredSize = lstrlen(Params.PathToSource)+1;
  2682. if(PathRequiredSize) {
  2683. *PathRequiredSize = TmpRequiredSize;
  2684. }
  2685. if(PathBuffer) {
  2686. if(TmpRequiredSize > PathBufferSize) {
  2687. i = DPROMPT_BUFFERTOOSMALL;
  2688. } else {
  2689. lstrcpy(PathBuffer,Params.PathToSource);
  2690. }
  2691. }
  2692. }
  2693. SetupFreeSourceList(&Params.PathList,Params.PathCount);
  2694. //
  2695. // release params (either we, or DlgProcDiskPrompt1 allocated the data)
  2696. //
  2697. if (Params.DialogTitle) {
  2698. MyFree(Params.DialogTitle);
  2699. }
  2700. if (Params.DiskName) {
  2701. MyFree(Params.DiskName);
  2702. }
  2703. if (Params.FileSought) {
  2704. MyFree(Params.FileSought);
  2705. }
  2706. if (Params.PathToSource) {
  2707. MyFree(Params.PathToSource);
  2708. }
  2709. if (Params.TargetFile) {
  2710. MyFree(Params.TargetFile);
  2711. }
  2712. }
  2713. clean:
  2714. if(dialogTitle) {
  2715. MyFree(dialogTitle);
  2716. }
  2717. if(diskName) {
  2718. MyFree(diskName);
  2719. }
  2720. if(pathToSource) {
  2721. MyFree(pathToSource);
  2722. }
  2723. if(sourceFile) {
  2724. MyFree(sourceFile);
  2725. }
  2726. if(targetPathFile) {
  2727. MyFree(targetPathFile);
  2728. }
  2729. if(ErrorText) {
  2730. MyFree(ErrorText);
  2731. }
  2732. if(Message) {
  2733. MyFree(Message);
  2734. }
  2735. SetLastError(d);
  2736. return((UINT)i);
  2737. }
  2738. #ifdef UNICODE
  2739. //
  2740. // ANSI version
  2741. //
  2742. UINT
  2743. SetupRenameErrorA(
  2744. IN HWND hwndParent,
  2745. IN PCSTR DialogTitle, OPTIONAL
  2746. IN PCSTR SourceFile,
  2747. IN PCSTR TargetFile,
  2748. IN UINT Win32ErrorCode,
  2749. IN DWORD Style
  2750. )
  2751. {
  2752. PCWSTR dialogTitle,sourceFile,targetFile;
  2753. DWORD rc;
  2754. UINT u;
  2755. dialogTitle = NULL;
  2756. sourceFile = NULL;
  2757. targetFile = NULL;
  2758. rc = NO_ERROR;
  2759. if(DialogTitle) {
  2760. rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
  2761. }
  2762. if((rc == NO_ERROR) && SourceFile) {
  2763. rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
  2764. }
  2765. if((rc == NO_ERROR) && TargetFile) {
  2766. rc = pSetupCaptureAndConvertAnsiArg(TargetFile,&targetFile);
  2767. }
  2768. if(rc == NO_ERROR) {
  2769. u = SetupRenameErrorW(
  2770. hwndParent,
  2771. dialogTitle,
  2772. sourceFile,
  2773. targetFile,
  2774. Win32ErrorCode,
  2775. Style
  2776. );
  2777. rc = GetLastError();
  2778. } else {
  2779. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2780. }
  2781. if(dialogTitle) {
  2782. MyFree(dialogTitle);
  2783. }
  2784. if(sourceFile) {
  2785. MyFree(sourceFile);
  2786. }
  2787. if(targetFile) {
  2788. MyFree(targetFile);
  2789. }
  2790. SetLastError(rc);
  2791. return(u);
  2792. }
  2793. #else
  2794. //
  2795. // Unicode stub
  2796. //
  2797. UINT
  2798. SetupRenameErrorW(
  2799. IN HWND hwndParent,
  2800. IN PCWSTR DialogTitle, OPTIONAL
  2801. IN PCWSTR SourceFile,
  2802. IN PCWSTR TargetFile,
  2803. IN UINT Win32ErrorCode,
  2804. IN DWORD Style
  2805. )
  2806. {
  2807. UNREFERENCED_PARAMETER(hwndParent);
  2808. UNREFERENCED_PARAMETER(DialogTitle);
  2809. UNREFERENCED_PARAMETER(SourceFile);
  2810. UNREFERENCED_PARAMETER(TargetFile);
  2811. UNREFERENCED_PARAMETER(Win32ErrorCode);
  2812. UNREFERENCED_PARAMETER(Style);
  2813. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2814. return(DPROMPT_CANCEL);
  2815. }
  2816. #endif
  2817. UINT
  2818. SetupRenameError(
  2819. IN HWND hwndParent,
  2820. IN PCTSTR DialogTitle, OPTIONAL
  2821. IN PCTSTR SourceFile,
  2822. IN PCTSTR TargetFile,
  2823. IN UINT Win32ErrorCode,
  2824. IN DWORD Style
  2825. )
  2826. /*++
  2827. Routine Description:
  2828. Inform the user about a rename error.
  2829. Arguments:
  2830. hwndParent - supplies window handle of window/dialog to own the error dialog
  2831. displayed by this routine.
  2832. DialogTitle - if specified, supplies title for error dialog. If not specified
  2833. a default of "Rename Error" will be supplied.
  2834. SourceFile - supplies full path and filename of source.
  2835. TargetFile - supplies full path and filename of target.
  2836. Win32ErrorCode - supplies win32 error code of failure.
  2837. Style - supplies flags to control the behavior of the dialog.
  2838. Return Value:
  2839. DPROMPT_xxx indicating outcome.
  2840. --*/
  2841. {
  2842. PTSTR ErrorText;
  2843. PTSTR Message;
  2844. PTCHAR p;
  2845. INT_PTR i;
  2846. FILEERRDLGPARAMS FileErrorDlgParams;
  2847. //
  2848. // If we're running non-interactive, bail now...
  2849. //
  2850. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  2851. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  2852. return DPROMPT_CANCEL;
  2853. }
  2854. ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
  2855. if(ErrorText) {
  2856. p = ErrorText + lstrlen(ErrorText) - 1;
  2857. while((p > ErrorText) && (*p <= TEXT(' '))) {
  2858. *p-- = 0;
  2859. }
  2860. } else {
  2861. return(DPROMPT_OUTOFMEMORY);
  2862. }
  2863. Message = RetreiveAndFormatMessage(
  2864. MSG_FILEERROR_RENAME,
  2865. ErrorText,
  2866. Win32ErrorCode,
  2867. SourceFile,
  2868. TargetFile
  2869. );
  2870. if(!Message) {
  2871. MyFree(ErrorText);
  2872. return(DPROMPT_OUTOFMEMORY);
  2873. }
  2874. FileErrorDlgParams.MessageText = Message;
  2875. FileErrorDlgParams.Style = Style;
  2876. FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_RENAMEERROR);
  2877. if(!FileErrorDlgParams.Caption) {
  2878. MyFree(ErrorText);
  2879. MyFree(Message);
  2880. SetLastError(NO_ERROR);
  2881. return(DPROMPT_OUTOFMEMORY);
  2882. }
  2883. i = DialogBoxParam(
  2884. MyDllModuleHandle,
  2885. MAKEINTRESOURCE(IDD_FILEERROR2),
  2886. hwndParent,
  2887. DlgProcFileError,
  2888. (LPARAM)&FileErrorDlgParams
  2889. );
  2890. MyFree(ErrorText);
  2891. MyFree(Message);
  2892. if(!DialogTitle) {
  2893. MyFree(FileErrorDlgParams.Caption);
  2894. }
  2895. if(i == -1) {
  2896. i = DPROMPT_OUTOFMEMORY;
  2897. }
  2898. SetLastError(NO_ERROR);
  2899. return((UINT)i);
  2900. }
  2901. #ifdef UNICODE
  2902. //
  2903. // ANSI version
  2904. //
  2905. UINT
  2906. SetupDeleteErrorA(
  2907. IN HWND hwndParent,
  2908. IN PCSTR DialogTitle, OPTIONAL
  2909. IN PCSTR File,
  2910. IN UINT Win32ErrorCode,
  2911. IN DWORD Style
  2912. )
  2913. {
  2914. PCWSTR dialogTitle,file;
  2915. DWORD rc;
  2916. UINT u;
  2917. dialogTitle = NULL;
  2918. file = NULL;
  2919. rc = NO_ERROR;
  2920. if(DialogTitle) {
  2921. rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
  2922. }
  2923. if((rc ==NO_ERROR) && File) {
  2924. rc = pSetupCaptureAndConvertAnsiArg(File,&file);
  2925. }
  2926. if(rc == NO_ERROR) {
  2927. u = SetupDeleteErrorW(hwndParent,dialogTitle,file,Win32ErrorCode,Style);
  2928. rc = GetLastError();
  2929. } else {
  2930. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  2931. }
  2932. if(dialogTitle) {
  2933. MyFree(dialogTitle);
  2934. }
  2935. if(file) {
  2936. MyFree(file);
  2937. }
  2938. SetLastError(rc);
  2939. return(u);
  2940. }
  2941. #else
  2942. //
  2943. // Unicode stub
  2944. //
  2945. UINT
  2946. SetupDeleteErrorW(
  2947. IN HWND hwndParent,
  2948. IN PCWSTR DialogTitle, OPTIONAL
  2949. IN PCWSTR File,
  2950. IN UINT Win32ErrorCode,
  2951. IN DWORD Style
  2952. )
  2953. {
  2954. UNREFERENCED_PARAMETER(hwndParent);
  2955. UNREFERENCED_PARAMETER(DialogTitle);
  2956. UNREFERENCED_PARAMETER(File);
  2957. UNREFERENCED_PARAMETER(Win32ErrorCode);
  2958. UNREFERENCED_PARAMETER(Style);
  2959. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2960. return(DPROMPT_CANCEL);
  2961. }
  2962. #endif
  2963. UINT
  2964. SetupDeleteError(
  2965. IN HWND hwndParent,
  2966. IN PCTSTR DialogTitle, OPTIONAL
  2967. IN PCTSTR File,
  2968. IN UINT Win32ErrorCode,
  2969. IN DWORD Style
  2970. )
  2971. /*++
  2972. Routine Description:
  2973. Inform the user about a rename error.
  2974. Arguments:
  2975. hwndParent - supplies window handle of window/dialog to own the error dialog
  2976. displayed by this routine.
  2977. DialogTitle - if specified, supplies title for error dialog. If not specified
  2978. a default of "Delete Error" will be supplied.
  2979. File - supplies full path and filename of file being deleted.
  2980. Win32ErrorCode - supplies win32 error code of failure.
  2981. Style - supplies flags to control the behavior of the dialog.
  2982. Return Value:
  2983. DPROMPT_xxx indicating outcome.
  2984. --*/
  2985. {
  2986. PTSTR ErrorText;
  2987. PTSTR Message;
  2988. PTCHAR p;
  2989. INT_PTR i;
  2990. FILEERRDLGPARAMS FileErrorDlgParams;
  2991. //
  2992. // If we're running non-interactive, bail now...
  2993. //
  2994. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  2995. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  2996. return DPROMPT_CANCEL;
  2997. }
  2998. ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
  2999. if(ErrorText) {
  3000. p = ErrorText + lstrlen(ErrorText) - 1;
  3001. while((p > ErrorText) && (*p <= TEXT(' '))) {
  3002. *p-- = 0;
  3003. }
  3004. } else {
  3005. return(DPROMPT_OUTOFMEMORY);
  3006. }
  3007. Message = RetreiveAndFormatMessage(
  3008. MSG_FILEERROR_DELETE,
  3009. File,
  3010. ErrorText,
  3011. Win32ErrorCode
  3012. );
  3013. if(!Message) {
  3014. MyFree(ErrorText);
  3015. return(DPROMPT_OUTOFMEMORY);
  3016. }
  3017. FileErrorDlgParams.MessageText = Message;
  3018. FileErrorDlgParams.Style = Style;
  3019. FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_DELETEERROR);
  3020. if(!FileErrorDlgParams.Caption) {
  3021. MyFree(ErrorText);
  3022. MyFree(Message);
  3023. return(DPROMPT_OUTOFMEMORY);
  3024. }
  3025. i = DialogBoxParam(
  3026. MyDllModuleHandle,
  3027. MAKEINTRESOURCE(IDD_FILEERROR2),
  3028. hwndParent,
  3029. DlgProcFileError,
  3030. (LPARAM)&FileErrorDlgParams
  3031. );
  3032. MyFree(ErrorText);
  3033. MyFree(Message);
  3034. if(!DialogTitle) {
  3035. MyFree(FileErrorDlgParams.Caption);
  3036. }
  3037. if(i == -1) {
  3038. i = DPROMPT_OUTOFMEMORY;
  3039. }
  3040. return((UINT)i);
  3041. }
  3042. #ifdef UNICODE
  3043. //
  3044. // ANSI version
  3045. //
  3046. UINT
  3047. SetupBackupErrorA(
  3048. IN HWND hwndParent,
  3049. IN PCSTR DialogTitle, OPTIONAL
  3050. IN PCSTR SourceFile,
  3051. IN PCSTR TargetFile, OPTIONAL
  3052. IN UINT Win32ErrorCode,
  3053. IN DWORD Style
  3054. )
  3055. {
  3056. PCWSTR dialogTitle,sourceFile,targetFile;
  3057. DWORD rc;
  3058. UINT u;
  3059. dialogTitle = NULL;
  3060. sourceFile = NULL;
  3061. targetFile = NULL;
  3062. rc = NO_ERROR;
  3063. if(DialogTitle) {
  3064. rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
  3065. }
  3066. if((rc == NO_ERROR) && SourceFile) {
  3067. rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
  3068. }
  3069. if((rc == NO_ERROR) && TargetFile) {
  3070. rc = pSetupCaptureAndConvertAnsiArg(TargetFile,&targetFile);
  3071. }
  3072. if(rc == NO_ERROR) {
  3073. u = SetupBackupErrorW(
  3074. hwndParent,
  3075. dialogTitle,
  3076. sourceFile,
  3077. targetFile,
  3078. Win32ErrorCode,
  3079. Style
  3080. );
  3081. rc = GetLastError();
  3082. } else {
  3083. u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
  3084. }
  3085. if(dialogTitle) {
  3086. MyFree(dialogTitle);
  3087. }
  3088. if(sourceFile) {
  3089. MyFree(sourceFile);
  3090. }
  3091. if(targetFile) {
  3092. MyFree(targetFile);
  3093. }
  3094. SetLastError(rc);
  3095. return(u);
  3096. }
  3097. #else
  3098. //
  3099. // Unicode stub
  3100. //
  3101. UINT
  3102. SetupBackupErrorW(
  3103. IN HWND hwndParent,
  3104. IN PCWSTR DialogTitle, OPTIONAL
  3105. IN PCWSTR SourceFile,
  3106. IN PCWSTR TargetFile, OPTIONAL
  3107. IN UINT Win32ErrorCode,
  3108. IN DWORD Style
  3109. )
  3110. {
  3111. UNREFERENCED_PARAMETER(hwndParent);
  3112. UNREFERENCED_PARAMETER(DialogTitle);
  3113. UNREFERENCED_PARAMETER(SourceFile);
  3114. UNREFERENCED_PARAMETER(TargetFile);
  3115. UNREFERENCED_PARAMETER(Win32ErrorCode);
  3116. UNREFERENCED_PARAMETER(Style);
  3117. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3118. return(DPROMPT_CANCEL);
  3119. }
  3120. #endif
  3121. UINT
  3122. SetupBackupError(
  3123. IN HWND hwndParent,
  3124. IN PCTSTR DialogTitle, OPTIONAL
  3125. IN PCTSTR SourceFile,
  3126. IN PCTSTR TargetFile, OPTIONAL
  3127. IN UINT Win32ErrorCode,
  3128. IN DWORD Style
  3129. )
  3130. /*++
  3131. Routine Description:
  3132. Inform the user about a backup error.
  3133. Arguments:
  3134. hwndParent - supplies window handle of window/dialog to own the error dialog
  3135. displayed by this routine.
  3136. DialogTitle - if specified, supplies title for error dialog. If not specified
  3137. a default of "Rename Error" will be supplied.
  3138. SourceFile - supplies full path and filename of file to be backed up
  3139. TargetFile - supplies full path and filename of final name, if known
  3140. Win32ErrorCode - supplies win32 error code of failure.
  3141. Style - supplies flags to control the behavior of the dialog.
  3142. Return Value:
  3143. DPROMPT_xxx indicating outcome.
  3144. --*/
  3145. {
  3146. PTSTR ErrorText;
  3147. PTSTR Message;
  3148. PTCHAR p;
  3149. INT_PTR i;
  3150. FILEERRDLGPARAMS FileErrorDlgParams;
  3151. //
  3152. // If we're running non-interactive, bail now...
  3153. //
  3154. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  3155. SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
  3156. return DPROMPT_CANCEL;
  3157. }
  3158. ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
  3159. if(ErrorText) {
  3160. p = ErrorText + lstrlen(ErrorText) - 1;
  3161. while((p > ErrorText) && (*p <= TEXT(' '))) {
  3162. *p-- = 0;
  3163. }
  3164. } else {
  3165. return(DPROMPT_OUTOFMEMORY);
  3166. }
  3167. Message = RetreiveAndFormatMessage(
  3168. MSG_FILEERROR_BACKUP,
  3169. SourceFile,
  3170. ErrorText,
  3171. Win32ErrorCode
  3172. );
  3173. if(!Message) {
  3174. MyFree(ErrorText);
  3175. return(DPROMPT_OUTOFMEMORY);
  3176. }
  3177. FileErrorDlgParams.MessageText = Message;
  3178. FileErrorDlgParams.Style = Style;
  3179. FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_BACKUPERROR);
  3180. if(!FileErrorDlgParams.Caption) {
  3181. MyFree(ErrorText);
  3182. MyFree(Message);
  3183. return(DPROMPT_OUTOFMEMORY);
  3184. }
  3185. i = DialogBoxParam(
  3186. MyDllModuleHandle,
  3187. MAKEINTRESOURCE(IDD_FILEERROR2),
  3188. hwndParent,
  3189. DlgProcFileError,
  3190. (LPARAM)&FileErrorDlgParams
  3191. );
  3192. MyFree(ErrorText);
  3193. MyFree(Message);
  3194. if(!DialogTitle) {
  3195. MyFree(FileErrorDlgParams.Caption);
  3196. }
  3197. if(i == -1) {
  3198. i = DPROMPT_OUTOFMEMORY;
  3199. }
  3200. return((UINT)i);
  3201. }
  3202. BOOL
  3203. ConnectToNetShare(
  3204. IN PCTSTR FileName,
  3205. IN HWND hwndParent
  3206. )
  3207. /*++
  3208. Routine Description:
  3209. This routine determines the network share component of the specified file path,
  3210. and give the user a "Connect As" dialog so that they can connect to this share.
  3211. Arguments:
  3212. FileName - supplies the path of a file contained in the network share to be
  3213. connected to.
  3214. hwndParent - supplies a handle to the window that should be the parent of the
  3215. "Connect As" dialog.
  3216. Return Value:
  3217. If the network share is successfully connected to, the return value is TRUE, otherwise,
  3218. it is FALSE.
  3219. --*/
  3220. {
  3221. TCHAR TempFileName[MAX_PATH];
  3222. NETRESOURCE NetResourceIn;
  3223. LPNETRESOURCE NetResourceOut = NULL;
  3224. PTSTR TempString;
  3225. DWORD BufferSize, d;
  3226. BOOL Success = FALSE;
  3227. BOOL locked = FALSE;
  3228. PTEMP_NET_CONNECTION NewConnectionNode;
  3229. //
  3230. // Surround this code in try/except, in case we get an exception going out to
  3231. // the network.
  3232. //
  3233. try {
  3234. //
  3235. // Copy the filename into a local (writable) buffer, because the WNet structure
  3236. // doesn't specify its string pointers as CONST, and we don't want to take any chances.
  3237. //
  3238. lstrcpyn(TempFileName, FileName, SIZECHARS(TempFileName));
  3239. ZeroMemory(&NetResourceIn, sizeof(NetResourceIn));
  3240. NetResourceIn.lpRemoteName = TempFileName;
  3241. NetResourceIn.dwType = RESOURCETYPE_DISK;
  3242. //
  3243. // Use a reasonable default buffer size in hopes of avoiding multiple calls to
  3244. // WNetGetResourceInformation.
  3245. //
  3246. BufferSize = sizeof(NETRESOURCE) + (MAX_PATH * sizeof(TCHAR));
  3247. while(TRUE) {
  3248. if(!(NetResourceOut = MyMalloc(BufferSize))) {
  3249. goto clean0;
  3250. }
  3251. d = WNetGetResourceInformation(&NetResourceIn, NetResourceOut, &BufferSize, &TempString);
  3252. if(d == WN_SUCCESS) {
  3253. break;
  3254. } else {
  3255. //
  3256. // Free the buffer currently allocated for the net resource information.
  3257. //
  3258. MyFree(NetResourceOut);
  3259. NetResourceOut = NULL;
  3260. if(d != WN_MORE_DATA) {
  3261. //
  3262. // The call failed for some reason other than too small a buffer, so we just
  3263. // need to bail.
  3264. //
  3265. goto clean0;
  3266. }
  3267. }
  3268. }
  3269. //
  3270. // If we get to this point, then we've successfully retrieved network resource information
  3271. // for the caller-supplied path. Now give the user a chance to connect to that network
  3272. // location.
  3273. //
  3274. if(WNetAddConnection3(hwndParent,
  3275. NetResourceOut,
  3276. NULL,
  3277. NULL,
  3278. CONNECT_INTERACTIVE | CONNECT_PROMPT) == NO_ERROR) {
  3279. Success = TRUE;
  3280. //
  3281. // Now, add a new node for this connection into our temporary network
  3282. // connections list, so that we can disconnect during DLL unload.
  3283. //
  3284. if(NewConnectionNode = MyMalloc(sizeof(TEMP_NET_CONNECTION))) {
  3285. lstrcpy(NewConnectionNode->NetResourceName, NetResourceOut->lpRemoteName);
  3286. try {
  3287. EnterCriticalSection(&NetConnectionListCritSect);
  3288. locked = TRUE;
  3289. NewConnectionNode->Next = NetConnectionList;
  3290. NetConnectionList = NewConnectionNode;
  3291. } except(EXCEPTION_EXECUTE_HANDLER) {
  3292. }
  3293. if(locked) {
  3294. LeaveCriticalSection(&NetConnectionListCritSect);
  3295. }
  3296. }
  3297. }
  3298. clean0: ; // nothing to do.
  3299. } except(EXCEPTION_EXECUTE_HANDLER) {
  3300. //
  3301. // Reference the following variable so the compiler will respect our statement
  3302. // ordering for it.
  3303. //
  3304. NetResourceOut = NetResourceOut;
  3305. }
  3306. if(NetResourceOut) {
  3307. MyFree(NetResourceOut);
  3308. }
  3309. return Success;
  3310. }
  3311. VOID
  3312. pSetupInitNetConnectionList(
  3313. IN BOOL Init
  3314. )
  3315. /*++
  3316. Routine Description:
  3317. This routine initializes/tears down the temporary network connection linked list that is
  3318. used to track what UNC connections the user has made (via "Connect As" dialog) that need
  3319. to be cleaned up on DLL unload. As the list is being torn down, the network connection
  3320. for each node is deleted.
  3321. Arguments:
  3322. Init - specifies whether we're initializing or tearing down this list.
  3323. Return Value:
  3324. None.
  3325. --*/
  3326. {
  3327. PTEMP_NET_CONNECTION CurNode, NextNode;
  3328. if(Init) {
  3329. NetConnectionList = NULL;
  3330. } else {
  3331. for(CurNode = NetConnectionList; CurNode; CurNode = NextNode) {
  3332. //
  3333. // First, attempt to disconnect from this network resource.
  3334. //
  3335. WNetCancelConnection2(CurNode->NetResourceName, 0, FALSE);
  3336. NextNode = CurNode->Next;
  3337. MyFree(CurNode);
  3338. }
  3339. }
  3340. }