windows-nt/Source/XPSP1/NT/base/pnp/setupapi/prompt.c
2020-09-26 16:20:57 +08:00

4125 lines
104 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
prompt.c
Abstract:
Disk/file prompt and file error prompt dialogs.
Author:
Ted Miller (tedm) 8-Feb-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <winnetwk.h>
#include <winnetp.h>
#include <winioctl.h>
//
// Structure used internally to store information
// about the file/disk being prompted for or the copy error
// that has occured. We store a pointer to one of these as
// a window property of the prompt dialog box. This eliminates
// the need for our own dialog class and for global/static variables.
//
typedef struct _PROMPTPARAMS {
//
// Reason we are displaying the dialog. One of DLGTYPE_ERROR or
// DLGTYPE_PROMPT. Used to modify controls and dialog's behavior.
//
UINT DialogType;
//
// For error dialogs, these values tell us the win32 error code
// that indicated failure. Used in the details message box.
//
UINT Win32Error;
//
// Window handle of the prompt/error dialog, and of its owner window,
// if any.
//
HWND hdlg;
HWND Owner;
//
// String to be used as the caption for the prompt/error dialog.
//
PCTSTR DialogTitle;
//
// Disk tag file. Used when prompting for a disk. We look for
// this file at the root of the drive to verify presence of the disk.
//
PCTSTR TagFile;
//
// Desriptive name for the disk where we expect the file to be.
// This is used even when the source location is non-removable,
// because the user might elect to furnish the file on disk, etc.
//
PCTSTR DiskName;
//
// The path to the source file (not including the file name)
// and the filename part of the source file. This filename is
// displayed when the user elects to browse and in certain other
// messages we may display in the dialog box.
//
PCTSTR PathToSource;
PCTSTR FileSought;
//
// Full path of the target file, if any. Used for copy errors and rename,
// so we can tell the user the name of the target file in the details
// message box.
//
PCTSTR TargetFile;
//
// IDF_xxx style bits that control behavior of the promt dialog.
//
DWORD PromptStyle;
//
// Drive type for PathToSource and flag indicating whether
// it's for removable media.
//
UINT DriveType;
BOOL IsRemovable;
//
// List of installation paths, from the registry.
// Access to that list is not synchronized among processes;
// oh well.
//
PTSTR *PathList;
UINT PathCount;
//
// Flag indicating whether the user has browsed (Browse button)
// during the lifetime of the dialog invocation.
//
BOOL UserBrowsed;
//
// Flag indicating whether the user is allowed to type in the combo box
// edit control.
//
BOOL ReadOnlyMru;
//
// Identifier of the combo box in use.
//
UINT ComboBoxId;
//
// Value used to indicate whether or not we're doing a presence check and,
// if so, whether there's a pending cancel to be processed once we're done
// (i.e., upon receipt of a WMX_PRESENCE_RESULT message posted from the
// AuxPromptThread).
//
// Possible values are:
// == 0 -- not currently doing a presence check--no pending cancels.
// == 1 -- currently doing a presence check--no pending cancels.
// >= 2 -- currently doing a presence check--one or more pending cancels.
//
BOOL PresenceCheckState;
BOOL BrowseAutoComplete;
#if ASSERTS_ON
//
// Make sure that if we fired off a presence check thread, that it has
// notified us of its completion prior to our processing of WM_DESTROY.
//
BOOL PresenceCheckThreadRunning;
//
// Keep track of when the dialog's controls are disabled (hence we don't
// expect to see the OK button pressed).
//
BOOL ControlsDisabled;
#endif // ASSERTS_ON
//
// Parameters that are passed to the simple message box
//
MSGBOXPARAMS MsgBoxParams;
} PROMPTPARAMS, *PPROMPTPARAMS;
//
// PROMPTPARAMS.DialogType
//
#define DLGTYPE_PROMPT 0
#define DLGTYPE_ERROR 1
//
// Define a signature for WMX_PRESENCE_RESULT (contained in lParam) that is
// used to validate the sender as being our own AuxPromptThread.
//
#define PRESENCE_RESULT_SIG 0x52504D53 // "SMPR" (Setupapi Message Presence Result)
//
// Structure used in delete/rename error dialog.
//
typedef struct _FILEERRDLGPARAMS {
PCTSTR MessageText;
DWORD Style;
PCTSTR Caption;
} FILEERRDLGPARAMS, *PFILEERRDLGPARAMS;
//
// Text constants.
//
TCHAR pszDiskPromptPropName[] = TEXT("_diskpromptparams");
//
// Custom window messages
//
#define WMX_PRESENCE_RESULT (WM_USER+121)
#define WMX_HELLO (WM_USER+122)
#define WMX_FIXUP_FILENAME (WM_USER+123)
//
// Linked-list node structure that tracks what temporary connections we
// need to clean up on unload (connections made as a result of user doing
// a "Connect As").
//
typedef struct _TEMP_NET_CONNECTION {
struct _TEMP_NET_CONNECTION *Next;
TCHAR NetResourceName[MAX_PATH];
} TEMP_NET_CONNECTION, *PTEMP_NET_CONNECTION;
//
// Global variables that track temporary net connections.
//
PTEMP_NET_CONNECTION NetConnectionList;
//
// global window message for cancelling autoplay.
//
UINT g_uQueryCancelAutoPlay = 0;
//
// Private routine prototypes.
//
BOOL
ConnectToNetShare(
IN PCTSTR FileName,
IN HWND hwndParent
);
BOOL
IsDriveReallyAHardDrive(
IN TCHAR DriveLetter
)
{
TCHAR DriveNameNt[7];
HANDLE hDisk;
DWORD DataSize;
DISK_GEOMETRY MediaInfo;
BOOL b;
#ifdef _X86_
if(OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
//
// Blow off the win9x case since the win32 support
// for making this determination is poor at best.
// A nauseating hack lets this work at least some of
// the time but PC98 is hosed since the basic assumption that
// floppies are generally A: and B: is invalid.
//
return(!IsNEC98() && (DriveLetter >= TEXT('C')));
}
#endif
//
// NT case allows us to make the determination reliably by opening
// the drive and reading some attributes.
//
wsprintf(DriveNameNt,TEXT("\\\\.\\%c:"),DriveLetter);
hDisk = CreateFile(
DriveNameNt,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(hDisk == INVALID_HANDLE_VALUE) {
return(FALSE);
}
b = DeviceIoControl(
hDisk,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&MediaInfo,
sizeof(MediaInfo),
&DataSize,
NULL
);
CloseHandle(hDisk);
//
// It's really a hard disk if the media type is removable.
//
return(b && (MediaInfo.MediaType == RemovableMedia));
}
VOID
DiskPromptGetDriveType(
IN PCTSTR PathToSource,
OUT PUINT DriveType,
OUT PBOOL IsRemovable
)
/*++
Routine Description:
Determine the drive type of the drive on which a path resides.
If the path starts with x: we call GetDriveType() on it.
If GetDriveType fails we assume it's removable.
If the path starts with \\ we assume it's remote.
Otherwise we assume it's a relative path on a hard drive.
Arguments:
PathToSource - pathname of path whose drive type is needed.
DriveType - receives value indicating drive type. The set of
possible values is the same as the named constants that can
be returned by GetDriveType().
IsRemovable - receives flag indicating whether DriveType
is a removable media type (floppy, cd-rom).
Return Value:
None.
--*/
{
TCHAR DriveRoot[4];
TCHAR c;
c = (TCHAR)CharUpper((PTSTR)PathToSource[0]);
if((c >= TEXT('A')) && (c <= TEXT('Z')) && (PathToSource[1] == TEXT(':'))) {
DriveRoot[0] = PathToSource[0];
DriveRoot[1] = PathToSource[1];
DriveRoot[2] = TEXT('\\');
DriveRoot[3] = 0;
*DriveType = GetDriveType(DriveRoot);
if(*DriveType == DRIVE_NO_ROOT_DIR) {
//
// Typically indicates that this drive-letter is invalid
// we will not get this if drive-letter is valid
// but media is not inserted.
//
*DriveType = DRIVE_UNKNOWN;
}
*IsRemovable = ((*DriveType == DRIVE_REMOVABLE) || (*DriveType == DRIVE_CDROM) || (*DriveType == DRIVE_UNKNOWN));
//
// If the drive is really a removeable hard drive as opposed to a
// floppy drive, change the drive type field to indicate a fixed
// drive, but don't change the removable flag. This allows callers
// to make this distinction if they need to.
//
// If the system is installed on the drive in question, then leave
// the drive type alone, but indicate that the media is not actually
// removable.
//
if(*DriveType == DRIVE_REMOVABLE) {
if(IsDriveReallyAHardDrive(c)) {
*DriveType = DRIVE_FIXED;
}
if((WindowsDirectory[0] == PathToSource[0]) && (WindowsDirectory[1] == TEXT(':'))) {
*IsRemovable = FALSE;
}
}
} else {
//
// Not drive letter: so try unc.
//
if((PathToSource[0] == TEXT('\\')) && (PathToSource[1] == TEXT('\\'))) {
*DriveType = DRIVE_REMOTE;
} else {
//
// Not recognized full path spec; assume relative path on HD.
//
*DriveType = DRIVE_FIXED;
}
*IsRemovable = FALSE;
}
}
typedef struct _MYOPENPARAMS {
PCTSTR Filename1;
PCTSTR Filename2;
PCTSTR Filename3;
} MYOPENPARAMS, *PMYOPENPARAMS;
UINT_PTR
APIENTRY
BrowseHookProc(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Hook procedure used with the OpenFile common dialog
for file browsing. We use a hook proc so that the user
is forced to look for only one particular file, and can't
look at any other file.
Arguments:
Standard Window Procedure arguments.
Return Value:
Always FALSE, to indicate that the common dialog should
process the message.
--*/
{
HWND hwnd;
LPOFNOTIFY NotifyParams;
LPOPENFILENAME OpenParams;
PMYOPENPARAMS MyOpenParams;
TCHAR Path[MAX_PATH];
WIN32_FIND_DATA FindData;
BOOL b;
UINT NotifyCode;
UNREFERENCED_PARAMETER(wParam);
switch(msg) {
case WM_INITDIALOG:
//
// Save away the OPENFILENAME structure for later.
//
SetWindowLongPtr(hdlg,GWLP_USERDATA,lParam);
break;
case WMX_FIXUP_FILENAME:
case WM_NOTIFY:
if(msg == WM_NOTIFY) {
NotifyParams = (LPOFNOTIFY)lParam;
NotifyCode = NotifyParams->hdr.code;
} else {
NotifyCode = CDN_FOLDERCHANGE;
}
hwnd = GetParent(hdlg);
switch(NotifyCode) {
case CDN_INITDONE:
//
// Make the "files of type" combo box read-only.
//
EnableWindow(GetDlgItem(hwnd,cmb1),FALSE);
//
// Post ourselves a message, so that we'll initialize the editbox
// correctly (we can't do it here, because it's too early).
//
PostMessage(hdlg, WMX_FIXUP_FILENAME, 0, 0);
break;
case CDN_FOLDERCHANGE:
case CDN_FILEOK:
//
// See if the file actually exists and if so
// set up the edit control.
//
OpenParams = (LPOPENFILENAME)GetWindowLongPtr(hdlg,GWLP_USERDATA);
MyOpenParams = (PMYOPENPARAMS)OpenParams->lCustData;
CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
pSetupConcatenatePaths(Path,MyOpenParams->Filename1,MAX_PATH,NULL);
if(FileExists(Path,&FindData)) {
b = TRUE;
} else {
if(MyOpenParams->Filename2) {
CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
pSetupConcatenatePaths(Path,MyOpenParams->Filename2,MAX_PATH,NULL);
if(FileExists(Path,&FindData)) {
b = TRUE;
} else {
if(MyOpenParams->Filename3) {
CommDlg_OpenSave_GetFolderPath(hwnd,Path,MAX_PATH);
pSetupConcatenatePaths(Path,MyOpenParams->Filename3,MAX_PATH,NULL);
b = FileExists(Path,&FindData);
} else {
b = FALSE;
}
}
} else {
b = FALSE;
}
}
if(NotifyCode == CDN_FOLDERCHANGE) {
if(b) {
CommDlg_OpenSave_SetControlText(hwnd, edt1, FindData.cFileName);
}
} else {
if(!b) {
MessageBeep(MB_ICONASTERISK);
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,TRUE);
return(TRUE);
}
}
break;
}
break;
}
//
// Let commdlg process it
//
return(FALSE);
}
BOOL
DoBrowse(
IN HWND hdlg,
IN PPROMPTPARAMS Params
)
/*++
Routine Description:
Allow the user to browse for a file. The user is allowed to look
only for the file in question -- he is not allowed to change the filter,
select an alternate file, etc.
Arguments:
hdlg - supplies the window handle of the window to own the
browse dialog.
File - supplies the filename (no path) of the file being looked for.
Return Value:
TRUE if the user located the file. FALSE otherwise.
If TRUE, the edit control of the combo box in hdlg has been given the
final path entered by the user in the browse dialog.
--*/
{
OPENFILENAME ofn;
TCHAR Path[MAX_PATH];
TCHAR Filter[2*MAX_PATH];
TCHAR InitialDir[MAX_PATH];
UINT InitialDirDriveType;
BOOL IsInitialDirOnRemovableDrive, InitialDirMediaPresent;
PTSTR CompressedFormName;
BOOL found=FALSE;
PTSTR p;
LPCTSTR q;
PCTSTR File;
LONG l;
HKEY hKey1,hKey2;
DWORD Type;
DWORD Size;
BOOL GotDesc;
MYOPENPARAMS MyParams;
File = Params->FileSought;
//
// Create the compressed-form name of the source file.
//
CompressedFormName = (Params->PromptStyle & IDF_NOCOMPRESSED)
? NULL
: SetupGenerateCompressedName(File);
//
// Build a filter that contains the file we're looking for
// and its compressed form name, if any. If the file is of
// the form *.ext then we'll build a more descriptive name.
//
GotDesc = FALSE;
if(!CompressedFormName
&& (File[0] == TEXT('*'))
&& (File[1] == TEXT('.'))
&& File[2]
&& !_tcschr(File+2,TEXT('.'))) {
l = RegOpenKeyEx(HKEY_CLASSES_ROOT,File+1,0,KEY_QUERY_VALUE,&hKey1);
if(l == NO_ERROR) {
Size = sizeof(Filter);
l = RegQueryValueEx(hKey1,TEXT(""),NULL,&Type,(LPBYTE)Filter,&Size);
if((l == NO_ERROR) && (Type == REG_SZ)) {
l = RegOpenKeyEx(HKEY_CLASSES_ROOT,Filter,0,KEY_QUERY_VALUE,&hKey2);
if(l == NO_ERROR) {
Size = sizeof(Filter);
l = RegQueryValueEx(hKey2,TEXT(""),NULL,&Type,(LPBYTE)Filter,&Size);
if((l == NO_ERROR) && (Type == REG_SZ)) {
lstrcat(Filter,TEXT(" ("));
lstrcat(Filter,File);
lstrcat(Filter,TEXT(")"));
p = Filter + lstrlen(Filter) + 1;
p += wsprintf(p,File);
GotDesc = TRUE;
}
RegCloseKey(hKey2);
}
}
RegCloseKey(hKey1);
}
}
if(!GotDesc) {
//
// Not able to fetch a meaningful description. Use the filenames.
// The filter has the description and the filespec set to
// the filename, for both the filename and its compressed form like so:
// foo.exe;foo.ex_ foo.exe;foo.ex_
//
p = Filter + wsprintf(Filter,File);
if(CompressedFormName) {
*p++ = TEXT(';');
p += wsprintf(p,CompressedFormName) + 1;
} else {
p++;
}
p += wsprintf(p,File);
if(CompressedFormName) {
*p++ = TEXT(';');
p += wsprintf(p,CompressedFormName);
}
}
//
// Stick the cabinet name in there if we think there is one.
// We do a dirty hackola to tell the difference between a tag file
// and a cabinet, namely we look for a .cab extension.
//
// Note that at this point p points at the terminating nul
// of the last filename placed into Filter.
//
if(Params->TagFile) {
l = lstrlen(q = pSetupGetFileTitle(Params->TagFile));
if((l > 4) && !lstrcmpi((q+l)-4,TEXT(".cab"))) {
*p++ = TEXT(';');
p += wsprintf(p,q);
} else {
q = NULL;
}
} else {
q = NULL;
}
//
// Add final terminating nul
//
*(++p) = 0;
MyParams.Filename1 = File;
MyParams.Filename2 = CompressedFormName;
MyParams.Filename3 = q;
lstrcpyn(Path,File,MAX_PATH);
InitialDir[0] = TEXT('\0');
GetDlgItemText(hdlg,Params->ComboBoxId,InitialDir,MAX_PATH);
InitialDir[MAX_PATH-1] = TEXT('\0');
//
// If the initial directory is on removable media, make sure that the media
// is present prior to firing off the common dialog. Otherwise, the user
// will a popup that the media isn't accessible.
//
DiskPromptGetDriveType(InitialDir,
&InitialDirDriveType,
&IsInitialDirOnRemovableDrive
);
if(IsInitialDirOnRemovableDrive) {
//
// We have a removable drive--make sure the media is present.
// if it's not, we'll probably get ERROR_INVALID_DRIVE
// if it is, we'll either succeed or get ERROR_FILE_NOT_FOUND
//
InitialDirMediaPresent = (FileExists(InitialDir, NULL) ||
GetLastError() == ERROR_FILE_NOT_FOUND);
} else {
InitialDirMediaPresent = TRUE;
}
#ifdef ANSI_SETUPAPI
ofn.lStructSize = sizeof(OPENFILENAME);
#else
ofn.lStructSize = GuiSetupInProgress
? OPENFILENAME_SIZE_VERSION_400
: sizeof(OPENFILENAME);
#endif
ofn.hwndOwner = hdlg;
ofn.hInstance = NULL;
ofn.lpstrFilter = Filter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = Path;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = InitialDirMediaPresent ? InitialDir : NULL;
ofn.lpstrTitle = MyLoadString(IDS_LOCATEFILE);
#ifdef ANSI_SETUPAPI
ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST | OFN_EXPLORER;
#else
ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK | OFN_NOCHANGEDIR | OFN_ENABLESIZING
| OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_FORCESHOWHIDDEN;
#endif
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = NULL;
ofn.lCustData = (LPARAM)&MyParams;
ofn.lpfnHook = BrowseHookProc;
ofn.lpTemplateName = NULL;
found = GetOpenFileName(&ofn);
if(ofn.lpstrTitle) {
MyFree(ofn.lpstrTitle);
}
if(CompressedFormName) {
MyFree(CompressedFormName);
}
UpdateWindow(hdlg);
if(found) {
//
// Remove file part, put the resulting directory in the path field
// This does not cause the string to be added to the combo box list.
//
if(ofn.nFileOffset<MAX_PATH) {
Path[ofn.nFileOffset - 1] = TEXT('\0');
} else {
Path[MAX_PATH-1] = TEXT('\0');
}
SetDlgItemText(hdlg,Params->ComboBoxId,Path);
return(TRUE);
}
return(FALSE);
}
PTSTR
GetErrorDetails(
IN PPROMPTPARAMS Params
)
/*++
Routine Description:
Display a message box with details about a file copy error.
Arguments:
Params - supplies file error dialog parameters.
Return Value:
None.
--*/
{
PTSTR Message;
TCHAR FullPath[MAX_PATH];
PTSTR ErrorName;
PTCHAR p;
DWORD chars;
PTSTR ShorterText = NULL;
TCHAR TargetPath[MAX_PATH];
//
// Form full path name.
//
lstrcpyn(FullPath,Params->PathToSource,SIZECHARS(FullPath));
pSetupConcatenatePaths(FullPath,Params->FileSought,MAX_PATH,NULL);
//
// try to make the path fit in our dialog
//
chars = ExtraChars(GetDlgItem(Params->hdlg,IDT_TEXT2),FullPath);
if (chars) {
ShorterText = CompactFileName(FullPath,chars);
if (ShorterText) {
lstrcpyn(FullPath, ShorterText,SIZECHARS(FullPath));
MyFree(ShorterText);
ShorterText = NULL;
}
}
lstrcpyn(TargetPath, Params->TargetFile,SIZECHARS(TargetPath));
chars = ExtraChars(GetDlgItem(Params->hdlg,IDT_TEXT2),Params->TargetFile);
if (chars) {
ShorterText = CompactFileName(Params->TargetFile,chars);
if (ShorterText) {
lstrcpyn(TargetPath, ShorterText,SIZECHARS(TargetPath));
MyFree(ShorterText);
ShorterText = NULL;
}
}
//
// Fetch error description. Remove trailing cr/lf if present.
//
ErrorName = RetreiveAndFormatMessage(Params->Win32Error);
if(ErrorName) {
p = ErrorName + lstrlen(ErrorName) - 1;
while((p > ErrorName) && (*p <= TEXT(' '))) {
*p-- = 0;
}
} else {
return NULL;
}
Message = RetreiveAndFormatMessage(
MSG_FILEERROR_DETAILS1,
ErrorName,
Params->Win32Error,
FullPath,
TargetPath
);
MyFree(ErrorName);
return Message;
}
BOOL
DoPresenceCheck(
IN PPROMPTPARAMS Params,
IN BOOL AllowConnectAs
)
/*++
Routine Description:
Check for the presence of a source file or source disk.
If the source path is on removable media and a tag file is
specified, we attempt to locate the tag file on the root of
the drive specified by the source path.
If the source path is not on removable media or a tag file
is not specified, we look for the file (including compressed-form
names) in the given path.
Arguments:
Params - supplies pointer to disk prompt dialog parameters.
AllowConnectAs - supplies a boolean indicating whether or not this
routine should give the user a "Connect as:" dialog if they've
typed in a UNC path that they currently don't have access to.
Return Value:
TRUE if the disk/file is present and accessible. FALSE if not.
--*/
{
BOOL b;
TCHAR FileName[MAX_PATH];
DWORD d;
WIN32_FIND_DATA FindData;
PTSTR p;
//
// If there's a tagfile then look for the tag file.
// Otherwise look for the file in the target path -- note that the
// file's name could be in compressed form.
//
if(Params->TagFile && !Params->UserBrowsed) {
if(Params->IsRemovable) {
//
// Removable media. Look for tag at root.
// If tag not found at root, look in actual directory.
//
MYASSERT(Params->PathToSource[0]);
MYASSERT(Params->PathToSource[1] == TEXT(':'));
lstrcpyn(FileName,Params->PathToSource,3);
pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
b = FileExists(FileName,NULL);
//
// If we couldn't find the tagfile at the root and the path
// is not for the root, look for the file in the path also.
//
// If we get here, we already know that PathToSource starts
// with x:. We could have a path of the form x:\foo\bar
// or x:foo\bar.
//
if(!b
&& Params->PathToSource[2]
&& !((Params->PathToSource[2] == TEXT('\\')) && !Params->PathToSource[3])) {
lstrcpy(FileName,Params->PathToSource);
pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
b = FileExists(FileName,NULL);
}
//
// Additional check for removeable hard drives to allow winnt32
// to work, because in that case there's no tagfiles!
//
if(Params->DriveType == DRIVE_FIXED) {
goto check1;
}
} else {
//
// Fixed media. Look for tag in the path where the file
// is being sought. If it's not found there, look for
// the file itself. This logic makes cabinets work right.
//
lstrcpy(FileName,Params->PathToSource);
pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
b = FileExists(FileName,NULL);
if(!b && (Params->DriveType == DRIVE_REMOTE)) {
d = GetLastError();
if((d == ERROR_ACCESS_DENIED) || (d == ERROR_WRONG_PASSWORD) ||
(d == ERROR_LOGON_FAILURE) || (d == ERROR_NOT_AUTHENTICATED) ||
(d == ERROR_INVALID_PASSWORD) || (d == ERROR_BAD_NETPATH)) {
//
// If this is a network path, and we got 'access denied'-type of error,
// then give the user "Connect As" dialog (if caller specified it's OK).
//
if(AllowConnectAs && ConnectToNetShare(FileName, Params->hdlg)) {
//
// We successfully connected to the network share--now try our
// file existence check again.
//
b = FileExists(FileName,NULL);
}
}
}
check1:
if(!b && lstrcmpi(Params->TagFile,Params->FileSought)) {
//
// We couldn't find the tagfile and the file we're seeking is
// not the tagfile. So now we look for the file itself
// in the path given to us. Note that the name of the file
// could be the compressed form.
//
lstrcpy(FileName,Params->PathToSource);
pSetupConcatenatePaths(FileName,Params->FileSought,MAX_PATH,NULL);
d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
if(d == NO_ERROR) {
MyFree(p);
b = TRUE;
} else {
b = FALSE;
}
}
}
} else {
lstrcpy(FileName,Params->PathToSource);
pSetupConcatenatePaths(FileName,Params->FileSought,MAX_PATH,NULL);
d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
if(Params->DriveType == DRIVE_REMOTE) {
//
// This is a network path. If we got an 'access denied'-type of error, then
// give the user "Connect As" dialog (if caller specified it's OK).
//
if((d == ERROR_ACCESS_DENIED) || (d == ERROR_WRONG_PASSWORD) ||
(d == ERROR_LOGON_FAILURE) || (d == ERROR_NOT_AUTHENTICATED) ||
(d == ERROR_INVALID_PASSWORD) || (d == ERROR_BAD_NETPATH)) {
if(AllowConnectAs && ConnectToNetShare(FileName, Params->hdlg)) {
//
// We successfully connected to the network share--now try to find
// the source file again.
//
d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
}
}
}
if(d == NO_ERROR) {
MyFree(p);
b = TRUE;
} else {
//
// Make cabinet-based browse work by also looking for the tag file.
// Note sleazy hack that matches a similar sleazy hack in DoBrowse(),
// namely looking at extension to see if it's .cab.
//
b = FALSE;
if(Params->TagFile) {
d = lstrlen(Params->TagFile);
if((d > 4) && !lstrcmpi((Params->TagFile+d)-4,TEXT(".cab"))) {
lstrcpy(FileName,Params->PathToSource);
pSetupConcatenatePaths(FileName,Params->TagFile,MAX_PATH,NULL);
d = SetupDetermineSourceFileName(FileName,&b,&p,&FindData);
if(b = (d == NO_ERROR)) {
MyFree(p);
}
}
}
}
}
return(b);
}
void
__cdecl
AuxPromptThread(
IN void *args
)
/*++
Routine Description:
Thread entry point to wrap DoPresenceCheck.
Calls DoPresenceCheck and then posts a message to the prompt
dialog indicating the outcome.
Arguments:
args - supplies file error dialog parameters.
Return Value:
None.
--*/
{
PPROMPTPARAMS Params;
BOOL b;
HWND hwnd;
Params = args;
#if ASSERTS_ON
//
// Set a flag to indicate that our presence check thread is up and running.
//
MYASSERT(!Params->PresenceCheckThreadRunning);
Params->PresenceCheckThreadRunning = TRUE;
#endif // ASSERTS_ON
hwnd = Params->hdlg;
b = DoPresenceCheck(Params, TRUE);
#if ASSERTS_ON
//
// The window had better not have gone away!
//
MYASSERT(IsWindow(hwnd));
//
// Now reset the flag to indicate that our presence check thread is
// finished.
//
Params->PresenceCheckThreadRunning = FALSE;
#endif // ASSERTS_ON
//
// Tell the dialog what we found.
//
PostMessage(hwnd, WMX_PRESENCE_RESULT, b, PRESENCE_RESULT_SIG);
}
VOID
PresenceCheckSetControls(
IN PPROMPTPARAMS Params,
IN BOOL Starting
)
/*++
Routine Description:
Disable or re-enable various controls in the error/prompt dialog
in preparation for or upon return from a file presence check.
We do this because the presence check occurs in another thread,
so the main dialog remains responsive. We don't want the user
to click OK again while we're checking, etc.
Arguments:
Params - supplies file error/disk prompt dialog parameters.
Starting - indicates whether we are preparing for a presence check
(TRUE) or returning from one (FALSE).
Return Value:
None.
--*/
{
#if ASSERTS_ON
if(!Starting) {
Params->ControlsDisabled = FALSE;
}
#endif // ASSERTS_ON
EnableWindow(GetDlgItem(Params->hdlg,IDOK),!Starting);
EnableWindow(GetDlgItem(Params->hdlg,IDCANCEL),!Starting);
EnableWindow(GetDlgItem(Params->hdlg,Params->ComboBoxId),!Starting);
EnableWindow(
GetDlgItem(Params->hdlg,IDB_BROWSE),
Starting ? FALSE : !(Params->PromptStyle & IDF_NOBROWSE)
);
#if ASSERTS_ON
if(Starting) {
Params->ControlsDisabled = TRUE;
}
#endif // ASSERTS_ON
}
BOOL
StartPresenceCheck(
IN PPROMPTPARAMS Params
)
/*++
Routine Description:
Perform a presence check, doing the real work asynchronously
in another thread. See AuxPromptThread().
Arguments:
Params - supplies file error/disk prompt dialog parameters.
Return Value:
Boolean value indicating whether the check could be started.
If FALSE, assume out of memory.
--*/
{
//
// need to disable controls so user can't do anything
// while we're off performing the file presence check.
//
PresenceCheckSetControls(Params,TRUE);
//
// Make sure we don't already have a presence check going on...
//
MYASSERT(Params->PresenceCheckState == 0);
//
// Set flag in prompt params to indicate we're doing a presence check.
//
Params->PresenceCheckState = 1;
return(_beginthread(AuxPromptThread,0,Params) != -1);
}
BOOL
InitDiskPromptDialog(
IN OUT PPROMPTPARAMS Params
)
/*++
Routine Description:
Initialize the disk prompt dialog. This involves hiding buttons
and other control, and setting up static text controls, based on the
prompt style specified by the caller.
Arguments:
Params - supplies parameters for the disk prompting
Return Value:
TRUE if success; FALSE if out of memory.
--*/
{
int i;
PTCHAR p,q;
BOOL b;
UINT IconId;
HICON hIcon;
HWND ComboBox;
UINT ComboBoxId;
HWND OtherComboBox;
//
// Remember parameter list
//
if(!SetProp(Params->hdlg,pszDiskPromptPropName,(HANDLE)Params)) {
return(FALSE);
}
if(!SetWindowText(Params->hdlg,Params->DialogTitle)) {
return(FALSE);
}
//
// Figure out which combo box to use. This depends on whether
// we're supposed to have an editable mru.
//
ComboBoxId = Params->ReadOnlyMru ? IDC_COMBO2 : IDC_COMBO1;
ComboBox = GetDlgItem(Params->hdlg,ComboBoxId);
OtherComboBox = GetDlgItem(Params->hdlg,Params->ReadOnlyMru ? IDC_COMBO1 : IDC_COMBO2);
Params->ComboBoxId = ComboBoxId;
ShowWindow(OtherComboBox,SW_HIDE);
EnableWindow(OtherComboBox,FALSE);
//
// Set up combo box title.
//
p = MyLoadString((Params->PromptStyle & IDF_OEMDISK) ? IDS_COPYFROMOEM : IDS_COPYFROM);
if(!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDT_TITLE1,p);
MyFree(p);
if(!b) {
return(FALSE);
}
//
// Set up the combo box.
//
for(i=0; i<(int)Params->PathCount; i++) {
if(SendMessage(ComboBox,CB_ADDSTRING,0,(LPARAM)Params->PathList[i]) < 0) {
return(FALSE);
}
}
SendMessage(ComboBox,CB_LIMITTEXT,MAX_PATH,0);
if(Params->ReadOnlyMru) {
//
// Select the first string in the list.
//
SendMessage(ComboBox,CB_SETCURSEL,0,0);
} else {
//
// Set text of combo box to the path we're searching along.
// This does not cause the string to be added to the combo box list.
//
if(!SetDlgItemText(Params->hdlg,ComboBoxId,Params->PathToSource)) {
return(FALSE);
}
#ifdef UNICODE
if(Params->BrowseAutoComplete) {
SHAutoComplete(GetWindow(ComboBox, GW_CHILD), SHACF_FILESYS_DIRS);
}
#endif
}
//
// Hide buttons if necessary.
//
if(Params->PromptStyle & IDF_NOBROWSE) {
ShowWindow(GetDlgItem(Params->hdlg,IDB_BROWSE),SW_HIDE);
EnableWindow(GetDlgItem(Params->hdlg,IDB_BROWSE),FALSE);
}
//
// Set icon.
//
if(Params->DialogType == DLGTYPE_ERROR) {
hIcon = LoadIcon(NULL,IDI_HAND);
} else {
switch(Params->DriveType) {
case DRIVE_REMOTE:
IconId = ICON_NETWORK;
break;
case DRIVE_CDROM:
IconId = ICON_CD;
break;
case DRIVE_FIXED:
IconId = ICON_HARD;
break;
case DRIVE_REMOVABLE:
default:
IconId = ICON_FLOPPY;
break;
}
hIcon = LoadIcon(MyDllModuleHandle,MAKEINTRESOURCE(IconId));
}
if(hIcon) {
SendDlgItemMessage(Params->hdlg,IDI_ICON1,STM_SETICON,(WPARAM)hIcon,0);
}
return(TRUE);
}
BOOL
SetDiskPromptDialogText(
IN OUT PPROMPTPARAMS Params
)
/*++
Routine Description:
Set up static text fields that explain to the user what is requested
and what he has to do to continue. These fields depend on whether we're
prompting for an oem disk, whether the file is on removable media, and
whether a tag file has been specified.
Arguments:
Params - supplies parameters for the disk prompting
Return Value:
TRUE if success; FALSE if out of memory.
--*/
{
BOOL b;
PTSTR p;
if(Params->DialogType == DLGTYPE_PROMPT) {
//
// There are 2 text fields - the explanation and action.
// What the text looks like depends on the prompt style flags,
// whether the file is on removable media, etc.
//
// First handle the explanation text.
//
if (Params->PromptStyle & IDF_USEDISKNAMEASPROMPT) {
b = SetDlgItemText(Params->hdlg,IDT_TEXT1,Params->DiskName);
} else {
if(Params->PromptStyle & IDF_OEMDISK) {
p = MyLoadString(IDS_DISKPROMPTOEM);
} else {
if(Params->IsRemovable && Params->TagFile) {
p = FormatStringMessage(IDS_DISKPROMPT1,Params->DiskName);
} else {
p = FormatStringMessage(IDS_DISKPROMPT2,Params->FileSought,Params->DiskName);
}
}
if(!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDT_TEXT1,p);
MyFree(p);
}
if(!b) {
return(FALSE);
}
//
// Now handle the explanation text. This is hidden for oem disks.
//
if(Params->PromptStyle & IDF_OEMDISK) {
ShowWindow(GetDlgItem(Params->hdlg,IDT_TEXT2),SW_HIDE);
EnableWindow(GetDlgItem(Params->hdlg,IDT_TEXT2),FALSE);
} else {
if(Params->IsRemovable && Params->TagFile) {
p = FormatStringMessage(IDS_PROMPTACTION1,Params->DiskName);
} else {
p = MyLoadString(IDS_PROMPTACTION2);
}
if(!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDT_TEXT2,p);
MyFree(p);
if(!b) {
return(FALSE);
}
}
} else {
if(Params->DialogType != DLGTYPE_ERROR) {
return(FALSE);
}
p = MyLoadString(IDS_RETRY);
if (!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDOK,p);
MyFree(p);
if (!b) {
return(FALSE);
}
//
// Explanation text -- "An error occurred copying a file" etc.
//
p = FormatStringMessage(IDS_FILEERRCOPY,Params->FileSought);
if(!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDT_TEXT1,p);
MyFree(p);
if(!b) {
return(FALSE);
}
//
// Action text.
//
if (Params->Win32Error != ERROR_DIRECTORY &&
Params->Win32Error != ERROR_DISK_FULL) {
if(Params->PromptStyle & IDF_OEMDISK) {
p = MyLoadString(IDS_COPYERROROEM);
} else {
if(Params->IsRemovable) {
p = FormatStringMessage(IDS_COPYERROR1,Params->DiskName);
} else {
p = FormatStringMessage(IDS_COPYERROR2,Params->DiskName);
}
}
} else {
p = GetErrorDetails(Params);
}
if(!p) {
return(FALSE);
}
b = SetDlgItemText(Params->hdlg,IDT_TEXT2,p);
MyFree(p);
if(!b) {
return(FALSE);
}
}
return(TRUE);
}
BOOL
WarnSkip(
IN HWND hwnd,
IN BOOL Skip
)
/*++
Routine Description:
Warn the user that skipping the file or cancelling
can tank the system.
Arguments:
hwnd - supplies window handle for window to own the message box
this routine will display.
Skip - if TRUE, user is trying to skip the file; FALSE means
he is trying to cancel.
Return Value:
TRUE if user wants to skip file/cancel; false otherwise.
--*/
{
PCTSTR Caption;
PCTSTR Message;
BOOL b;
b = TRUE;
if(Caption = MyLoadString(IDS_WARNING)) {
if(Message = MyLoadString(Skip ? IDS_SURESKIP : IDS_SURECANCEL)) {
b = (MessageBox(hwnd,Message,Caption,MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES);
MyFree(Message);
}
MyFree(Caption);
}
return(b);
}
BOOL
CancelAllCopies(
IN HWND hwnd
)
/*++
Routine Description:
ask the user if they want to cancel copying one file or all files
Arguments:
hwnd - supplies window handle for window to own the message box
this routine will display.
Return Value:
TRUE if user wants to cancel just this copy (really the same as skipping a file)
FALSE if user wants to cancel all copies;
--*/
{
PCTSTR Caption;
PCTSTR Message;
BOOL b;
b = TRUE;
if(Caption = MyLoadString(IDS_COPYERROR)) {
if(Message = MyLoadString(IDS_CANCELALL)) {
b = (MessageBox(hwnd,Message,Caption,MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) == IDYES);
MyFree(Message);
}
MyFree(Caption);
}
return(b);
}
INT_PTR
DlgProcSimplePrompt(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Dialog procedure for disk prompting dialog.
The return value for the dialog is
DPROMPT_CANCEL - user cancelled
DPROMPT_SKIPFILE - user elected to skip file
DPROMPT_SUCCESS - disk is in the drive/we found the file we're looking for
DPROMPT_OUTOFMEMORY - out of memory
Arguments:
Standard dialog routine parameters.
Return Value:
TRUE if message processed; FALSE if not.
--*/
{
BOOL b = FALSE;
TCHAR Text[MAX_PATH];
PPROMPTPARAMS PromptParams;
BOOL WarnIfSkip;
BOOL ReallyCancel;
HICON hIcon;
static DWORD UnitMask = 0xFFFFFFFF;
switch(msg) {
case WM_INITDIALOG:
PromptParams = (PPROMPTPARAMS)lParam;
MYASSERT(PromptParams != NULL);
if(!SetProp(hdlg,pszDiskPromptPropName,(HANDLE)&(PromptParams->MsgBoxParams))) {
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
break;
}
if(!SetWindowText(hdlg,PromptParams->MsgBoxParams.lpszCaption)) {
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
break;
}
if(!SetWindowText(hdlg,PromptParams->MsgBoxParams.lpszCaption)) {
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
break;
}
if (!SetDlgItemText(hdlg,IDT_TEXT1,PromptParams->MsgBoxParams.lpszText)) {
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
break;
}
hIcon = LoadIcon(MyDllModuleHandle,PromptParams->MsgBoxParams.lpszIcon);
if(hIcon) {
SendDlgItemMessage(hdlg,IDI_ICON1,STM_SETICON,(WPARAM)hIcon,0);
}
pSetupCenterWindowRelativeToParent(hdlg);
if ((PromptParams->PathToSource[0] != TEXT('\0')) &&
_istalpha(PromptParams->PathToSource[0])) {
UnitMask = (1 << (_toupper(PromptParams->PathToSource[0]) - TEXT('A')));
}
b = FALSE;
break;
case WM_DEVICECHANGE:
if ((wParam == DBT_DEVICEARRIVAL) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_devicetype == DBT_DEVTYP_VOLUME) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_flags & DBTF_MEDIA) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_unitmask == UnitMask)) {
//
// The user inserted a CD or removable media into the source drive,
// so do an automatic OK so we can check this new media.
//
PostMessage(hdlg, WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED), 0L);
}
break;
case WM_COMMAND:
if(HIWORD(wParam) == BN_CLICKED) {
b = TRUE;
EndDialog(hdlg,LOWORD(wParam));
break;
} else {
b = FALSE;
}
break;
case WM_DESTROY:
//
// Nothing to do about this if it fails.
// Note: the return value is typically a pointer to stack data
//
RemoveProp(hdlg,pszDiskPromptPropName);
//
// Let default processing take place by indicating that
// we didn't process this message
//
b = FALSE;
break;
default:
if (!g_uQueryCancelAutoPlay) {
g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
}
if (msg == g_uQueryCancelAutoPlay) {
SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
return 1; // cancel auto-play
}
b = FALSE;
break;
}
return(b);
}
INT_PTR
DlgProcDiskPrompt1(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Dialog procedure for disk prompting dialog.
The return value for the dialog is
DPROMPT_CANCEL - user cancelled
DPROMPT_SKIPFILE - user elected to skip file
DPROMPT_SUCCESS - disk is in the drive/we found the file we're looking for
DPROMPT_OUTOFMEMORY - out of memory
Arguments:
Standard dialog routine parameters.
Return Value:
TRUE if message processed; FALSE if not.
--*/
{
BOOL b = FALSE;
PPROMPTPARAMS PromptParams;
TCHAR Text[MAX_PATH];
BOOL WarnIfSkip;
BOOL ReallyCancel;
static DWORD UnitMask = 0xFFFFFFFF;
switch(msg) {
case WM_INITDIALOG:
PromptParams = (PPROMPTPARAMS)lParam;
MYASSERT( PromptParams != NULL );
PromptParams->hdlg = hdlg;
//
// Initialize the dialog.
//
if(InitDiskPromptDialog(PromptParams) && SetDiskPromptDialogText(PromptParams)) {
//
// Set focus to directory combobox and continue.
//
SetFocus(GetDlgItem(hdlg, PromptParams->ReadOnlyMru ? IDC_COMBO2 : IDC_COMBO1));
} else {
//
// Out of memory.
//
b = TRUE;
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
break;
}
//
// Indicate to windows that we set the focus.
//
b = FALSE;
if(!(PromptParams->PromptStyle & IDF_NOBEEP)) {
MessageBeep(MB_ICONASTERISK);
}
if ((PromptParams->PathToSource[0] != TEXT('\0')) &&
_istalpha(PromptParams->PathToSource[0])) {
UnitMask = (1 << (_toupper(PromptParams->PathToSource[0]) - TEXT('A')));
}
pSetupCenterWindowRelativeToParent(hdlg);
PostMessage(hdlg,WMX_HELLO,0,0);
break;
case WMX_HELLO:
b = TRUE;
PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
MYASSERT(PromptParams != NULL);
if(PromptParams && !(PromptParams->PromptStyle & IDF_NOFOREGROUND)) {
SetForegroundWindow(hdlg);
}
break;
case WM_DEVICECHANGE:
if ((wParam == DBT_DEVICEARRIVAL) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_devicetype == DBT_DEVTYP_VOLUME) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_flags & DBTF_MEDIA) &&
(((PDEV_BROADCAST_VOLUME)lParam)->dbcv_unitmask == UnitMask)) {
//
// The user inserted a CD or removable media into the source drive,
// so do an automatic OK so we can check this new media.
//
PostMessage(hdlg, WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED), 0L);
}
break;
case WM_COMMAND:
if(HIWORD(wParam) == BN_CLICKED) {
PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
MYASSERT(PromptParams != NULL);
WarnIfSkip = (PromptParams && (PromptParams->PromptStyle & IDF_WARNIFSKIP));
b = TRUE;
switch(LOWORD(wParam)) {
case IDOK:
//
// We'd better not get here if controls are disabled!
//
MYASSERT(!PromptParams->ControlsDisabled);
//
// User might have changed the source path.
// Get the current path from the combo's edit control
//
Text[0] = TEXT('\0'); // default value
GetDlgItemText(hdlg,PromptParams->ComboBoxId,Text,SIZECHARS(Text));
Text[SIZECHARS(Text)-1] = TEXT('\0'); // make sure it's terminated.
MyFree(PromptParams->PathToSource);
PromptParams->PathToSource = DuplicateString(Text);
DiskPromptGetDriveType(Text,&PromptParams->DriveType,&PromptParams->IsRemovable);
//
// See whether we can get at the file.
//
if(!PromptParams->PathToSource || !StartPresenceCheck(PromptParams)) {
EndDialog(hdlg,DPROMPT_OUTOFMEMORY);
}
break;
case IDCANCEL:
//
// We'd better not get here if controls are disabled!
//
MYASSERT(!PromptParams->ControlsDisabled);
//
// ask if they want to cancel all copies or just cancel one copy
//
if (PromptParams->DialogType != DLGTYPE_ERROR) {
ReallyCancel = TRUE;
} else {
if (PromptParams->PromptStyle & IDF_NOSKIP) {
ReallyCancel = TRUE;
} else {
ReallyCancel = !CancelAllCopies(hdlg);
}
}
if(WarnIfSkip ? WarnSkip(hdlg,!ReallyCancel) : TRUE) {
//
// If we're currently doing a file presence check, then
// just increment our PresenceCheckState value, and defer
// the EndDialog until receipt of WMX_PRESENCE_RESULT.
//
if (ReallyCancel) {
if(PromptParams->PresenceCheckState == 0) {
EndDialog(hdlg,DPROMPT_CANCEL);
} else {
(PromptParams->PresenceCheckState)++;
}
} else {
EndDialog(hdlg,DPROMPT_SKIPFILE);
}
}
break;
case IDB_BROWSE:
//
// We'd better not get here if controls are disabled!
//
MYASSERT(!PromptParams->ControlsDisabled);
if(DoBrowse(hdlg,PromptParams)) {
PromptParams->UserBrowsed = TRUE;
}
break;
default:
b = FALSE;
break;
}
} else {
b = FALSE;
}
break;
case WM_DESTROY:
#if ASSERTS_ON
//
// We'd better not have an outstanding presence check thread running!
//
PromptParams = (PPROMPTPARAMS)GetProp(hdlg, pszDiskPromptPropName);
MYASSERT(PromptParams != NULL);
if(PromptParams) {
MYASSERT(!PromptParams->PresenceCheckThreadRunning);
}
#endif // ASSERTS_ON
//
// Nothing to do about this if it fails.
//
RemoveProp(hdlg,pszDiskPromptPropName);
//
// Let default processing take place by indicating that
// we didn't process this message
//
b = FALSE;
break;
case WMX_PRESENCE_RESULT:
//
// Make sure this message came from AuxPromptThread--we've seen weird
// stress failures indicating that someone else was sending us this
// message from time to time.
//
MYASSERT(lParam == PRESENCE_RESULT_SIG);
//
// In case the above does happen, just ignore this message...
//
if(lParam != PRESENCE_RESULT_SIG) {
b = FALSE;
break;
}
b = TRUE;
PromptParams = (PPROMPTPARAMS)GetProp(hdlg,pszDiskPromptPropName);
//
// Also, we don't expect to get this message unless we actually had a
// presence check thread running.
//
MYASSERT(PromptParams != NULL);
MYASSERT(PromptParams->PresenceCheckState);
//
// If the user pressed cancel while we were off doing our presence
// check, then honor that request now.
//
if(PromptParams->PresenceCheckState > 1) {
EndDialog(hdlg, DPROMPT_CANCEL);
}
//
// Aux thread is telling us that it knows whether the file is present.
// wParam has the boolean.
// PromptParams->PathToSource is already set.
//
if(wParam) {
EndDialog(hdlg,DPROMPT_SUCCESS);
} else {
//
// File/disk is not accessible. Don't end the dialog.
//
if(!(PromptParams->PromptStyle & IDF_NOFOREGROUND)) {
SetForegroundWindow(hdlg);
}
//
// If we're searching for a directory containing INFs (e.g.,
// SetupDiSelectOEMDrv), then we want to popup a message informing
// the user that the location they've specified doesn't contain
// information about their hardware. Otherwise, we want to maintain
// the file prompt behavior of just beeping.
//
if(lstrcmpi(PromptParams->FileSought, pszInfWildcard)) {
if(!(PromptParams->PromptStyle & IDF_NOBEEP)) {
MessageBeep(MB_ICONASTERISK);
}
} else {
if(!LoadString(MyDllModuleHandle,
IDS_SELECT_DEVICE,
Text,
SIZECHARS(Text))) {
*Text = TEXT('\0');
}
FormatMessageBox(MyDllModuleHandle,
NULL,
MSG_NO_DEVICEINFO_ERROR,
Text,
MB_OK | MB_TASKMODAL
);
}
//
// Reset value indicating we're no longer doing a presence check.
//
PromptParams->PresenceCheckState = 0;
//
// Restore controls that were disabled when we started the presence check.
//
PresenceCheckSetControls(PromptParams,FALSE);
SetFocus(GetDlgItem(hdlg,PromptParams->ComboBoxId));
}
break;
default:
if (!g_uQueryCancelAutoPlay) {
g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
}
if (msg == g_uQueryCancelAutoPlay) {
SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
return 1; // cancel auto-play
}
b = FALSE;
break;
}
return(b);
}
VOID
ModifyPathList(
IN PPROMPTPARAMS Params
)
/*++
Routine Description:
Modifies a list of installation paths kept in the registry.
The existing list is scanned for the path the user accepted in the disk
prompt dialog. That path is added if not already in the list.
Arguments:
Params - supplies disk prompt dialog parameters.
Return Value:
None. If any part of the operation, the list simply doesn't get updated
in the registry.
--*/
{
//
// Params->PathToSource will be the final path entered by the user
// in the combo box. Add to list. If this fails, oh well.
//
SetupAddToSourceList(SRCLIST_SYSIFADMIN,Params->PathToSource);
}
UINT
_SetupPromptForDisk(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR DiskName, OPTIONAL
IN PCTSTR PathToSource, OPTIONAL
IN PCTSTR FileSought,
IN PCTSTR TagFile, OPTIONAL
IN DWORD DiskPromptStyle,
OUT PTSTR PathBuffer,
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
PROMPTPARAMS Params;
INT_PTR i;
TCHAR Buffer[256];
DWORD d;
DWORD ResultPathLen;
PTSTR Message;
HANDLE hDialogEvent = NULL;
BOOL PromptUser = FALSE;
//
// If we're running non-interactive, bail now. Unless, that is, we've been
// instructed to check for the presence of the source file _before_ doing
// any UI, in which case we can hang around until we do our presence check
// down below.
//
if((GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) &&
!(DiskPromptStyle & IDF_CHECKFIRST)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return DPROMPT_CANCEL;
}
//
// It is illegal to specify both the IDF_USEDISKNAMEASPROMPT and the
// IDF_OEMDISK flag. This is due to the fact that they both cause
// a different style of UI text to be displayed that would conflict
// with itself.
//
if ((DiskPromptStyle & IDF_USEDISKNAMEASPROMPT) &&
(DiskPromptStyle & IDF_OEMDISK)) {
SetLastError(ERROR_INVALID_PARAMETER);
return DPROMPT_CANCEL;
}
ZeroMemory(&Params,sizeof(PROMPTPARAMS));
//
// Determine the path to the source. Start by fetching the entire
// installation locations list for the current user.
//
d = pSetupGetList(0,&Params.PathList,&Params.PathCount,&Params.ReadOnlyMru);
if(d != NO_ERROR) {
i = DPROMPT_OUTOFMEMORY;
goto c0;
}
if(PathToSource) {
//
// Code in dialog box relies on being able to free this
// so duplicate it here.
//
Params.PathToSource = DuplicateString(PathToSource);
} else {
if(Params.PathCount) {
Params.PathToSource = DuplicateString(Params.PathList[0]);
} else {
//
// Nothing in system path lists. Use a reasonable default.
//
Params.PathToSource = DuplicateString(pszOemInfDefaultPath);
}
}
if(!Params.PathToSource) {
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
goto c1;
}
//
// Determine the drive type of the source path.
//
DiskPromptGetDriveType(Params.PathToSource,&Params.DriveType,&Params.IsRemovable);
//
// If the disk name wasn't specified, fetch a default.
//
if(DiskName) {
Params.DiskName = DiskName;
} else {
Params.DiskName = MyLoadString(IDS_UNKNOWN_PARENS);
if(!Params.DiskName) {
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
goto c2;
}
}
//
// If a dialog title wasn't specified, try to get text from parent window.
//
if(DialogTitle) {
Params.DialogTitle = DialogTitle;
} else {
if(Params.Owner
&& (i = GetWindowTextLength(Params.Owner))
&& GetWindowText(Params.Owner,Buffer,sizeof(Buffer)/sizeof(TCHAR))) {
Params.DialogTitle = FormatStringMessage(IDS_FILESNEEDED2,Buffer);
} else {
Params.DialogTitle = MyLoadString(IDS_FILESNEEDED);
}
if(!Params.DialogTitle) {
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
goto c3;
}
}
Params.TagFile = TagFile;
//
// Validate parent window.
//
Params.Owner = IsWindow(hwndParent) ? hwndParent : NULL;
//
// Fill in other fields.
//
if((Params.FileSought = FileSought) == NULL) {
i = DPROMPT_CANCEL;
d = ERROR_INVALID_PARAMETER;
goto c4;
}
Params.Owner = hwndParent;
Params.PromptStyle = DiskPromptStyle | IDF_NODETAILS;
Params.hdlg = NULL;
Params.UserBrowsed = FALSE;
Params.DialogType = DLGTYPE_PROMPT;
Params.TargetFile = NULL;
if(Params.ReadOnlyMru) {
Params.PromptStyle |= IDF_NOBROWSE;
}
if (GuiSetupInProgress) {
hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
}
//
// If we're supposed to, check for the disk/file first.
//
if((DiskPromptStyle & IDF_CHECKFIRST) && DoPresenceCheck(&Params, FALSE)) {
i = DPROMPT_SUCCESS;
d = NO_ERROR;
} else if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
i = DPROMPT_CANCEL;
d = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
} else {
//
// Before invoking the dialog, we will prompt the user with a simple
// message box in some cases to avoid the user ever actually seeing
// a path in the more complicated prompt dialog.
//
if(DiskName &&
!(DiskPromptStyle & IDF_NOREMOVABLEMEDIAPROMPT) &&
((Params.DriveType == DRIVE_REMOVABLE) || (Params.DriveType == DRIVE_CDROM))) {
Message = RetreiveAndFormatMessage(
(Params.DriveType == DRIVE_CDROM)
? ( GuiSetupInProgress ? MSG_CDPROMPT_NONETWORK : MSG_CDPROMPT )
: ( GuiSetupInProgress ? MSG_FLOPPYPROMPT_NONETWORK : MSG_FLOPPYPROMPT ),
DiskName,
(TCHAR)CharUpper((PTSTR)Params.PathToSource[0])
);
if(Message) {
LoadString(MyDllModuleHandle,IDS_PROMPTTITLE,Buffer,sizeof(Buffer)/sizeof(TCHAR));
if(!(DiskPromptStyle & IDF_NOBEEP)) {
MessageBeep(MB_ICONASTERISK);
}
reprompt:
Params.MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS);
Params.MsgBoxParams.hwndOwner = hwndParent;
Params.MsgBoxParams.hInstance = MyDllModuleHandle;
Params.MsgBoxParams.lpszText = Message;
Params.MsgBoxParams.lpszCaption = Buffer;
Params.MsgBoxParams.dwStyle = MB_USERICON | MB_OKCANCEL;
Params.MsgBoxParams.lpszIcon = (Params.DriveType == DRIVE_CDROM)
? MAKEINTRESOURCE(ICON_CD)
: MAKEINTRESOURCE(ICON_FLOPPY);
Params.MsgBoxParams.lpfnMsgBoxCallback = NULL;
Params.MsgBoxParams.dwLanguageId = LANG_NEUTRAL;
if (hDialogEvent) {
SetEvent(hDialogEvent);
}
switch(DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_SIMPLEPROMPT),
hwndParent,
DlgProcSimplePrompt,
(LPARAM)&Params
)) {
case DPROMPT_OUTOFMEMORY:
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
break;
case IDOK:
if(DoPresenceCheck(&Params, FALSE)) {
i = DPROMPT_SUCCESS;
d = NO_ERROR;
} else {
i = DPROMPT_SKIPFILE;
}
break;
case IDCANCEL:
d = ERROR_CANCELLED;
i = DPROMPT_CANCEL;
if((DiskPromptStyle & IDF_WARNIFSKIP) && !WarnSkip(hwndParent,FALSE)) {
goto reprompt;
}
break;
default:
MYASSERT( FALSE );
}
if (hDialogEvent) {
ResetEvent(hDialogEvent);
}
MyFree(Message);
} else {
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
goto c4;
}
} else {
i = DPROMPT_SKIPFILE;
}
if(i == DPROMPT_SKIPFILE) {
if (hDialogEvent) {
SetEvent(hDialogEvent);
}
Params.BrowseAutoComplete = FALSE;
if(!GuiSetupInProgress) {
d = OleInitialize(NULL);
if(SUCCEEDED(d)) {
Params.BrowseAutoComplete = TRUE;
}
}
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_DISKPROMPT1),
hwndParent,
DlgProcDiskPrompt1,
(LPARAM)&Params
);
if(!GuiSetupInProgress && (d==NO_ERROR)) {
OleUninitialize();
}
if (hDialogEvent) {
ResetEvent(hDialogEvent);
}
switch(i) {
case DPROMPT_SUCCESS:
PromptUser = TRUE;
d = NO_ERROR;
break;
case DPROMPT_SKIPFILE:
d = NO_ERROR;
break;
case DPROMPT_CANCEL:
d = ERROR_CANCELLED;
break;
case DPROMPT_BUFFERTOOSMALL:
d = ERROR_INSUFFICIENT_BUFFER;
break;
default:
i = DPROMPT_OUTOFMEMORY;
d = ERROR_NOT_ENOUGH_MEMORY;
break;
}
}
}
//
// If success, we want to add the path string to the list of path strings
// if it's not already in there.
//
if(i == DPROMPT_SUCCESS) {
//
// Only add the file to the MRU list if we prompted the user and
// they entered a valid path.
//
if (PromptUser) {
ModifyPathList(&Params);
}
//
// Now determine what to return to the user depending on the
// buffer and sizes passed in.
//
ResultPathLen = lstrlen(Params.PathToSource)+1;
if(PathRequiredSize) {
*PathRequiredSize = ResultPathLen;
}
if(PathBuffer) {
if(ResultPathLen > PathBufferSize) {
i = DPROMPT_BUFFERTOOSMALL;
} else {
lstrcpy(PathBuffer,Params.PathToSource);
}
}
}
c4:
if (hDialogEvent) {
CloseHandle(hDialogEvent);
}
if(!DialogTitle) {
MyFree(Params.DialogTitle);
}
c3:
if(!DiskName) {
MyFree(Params.DiskName);
}
c2:
MyFree(Params.PathToSource);
c1:
SetupFreeSourceList(&Params.PathList,Params.PathCount);
c0:
SetLastError(d);
return((UINT)i);
}
#ifdef UNICODE
//
// ANSI version
//
UINT
SetupPromptForDiskA(
IN HWND hwndParent,
IN PCSTR DialogTitle, OPTIONAL
IN PCSTR DiskName, OPTIONAL
IN PCSTR PathToSource, OPTIONAL
IN PCSTR FileSought,
IN PCSTR TagFile, OPTIONAL
IN DWORD DiskPromptStyle,
OUT PSTR PathBuffer,
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
PCWSTR dialogTitle;
PCWSTR diskName;
PCWSTR pathToSource;
PCWSTR fileSought;
PCWSTR tagFile;
WCHAR pathBuffer[MAX_PATH];
CHAR ansiBuffer[MAX_PATH];
DWORD rc;
UINT u;
DWORD Size;
dialogTitle = NULL;
diskName = NULL;
pathToSource = NULL;
fileSought = NULL;
tagFile = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
}
if((rc == NO_ERROR) && DiskName) {
rc = pSetupCaptureAndConvertAnsiArg(DiskName,&diskName);
}
if((rc == NO_ERROR) && PathToSource) {
rc = pSetupCaptureAndConvertAnsiArg(PathToSource,&pathToSource);
}
if((rc == NO_ERROR) && FileSought) {
rc = pSetupCaptureAndConvertAnsiArg(FileSought,&fileSought);
}
if((rc == NO_ERROR) && TagFile) {
rc = pSetupCaptureAndConvertAnsiArg(TagFile,&tagFile);
}
if(rc == NO_ERROR) {
u = _SetupPromptForDisk(
hwndParent,
dialogTitle,
diskName,
pathToSource,
fileSought,
tagFile,
DiskPromptStyle,
pathBuffer,
MAX_PATH,
&Size
);
rc = GetLastError();
if(u == DPROMPT_SUCCESS) {
Size = (DWORD)WideCharToMultiByte(
CP_ACP,
0,
pathBuffer,
(int)Size,
ansiBuffer,
MAX_PATH,
NULL,
NULL
);
if(PathRequiredSize) {
*PathRequiredSize = Size;
}
if(PathBuffer) {
if(Size > PathBufferSize) {
u = DPROMPT_BUFFERTOOSMALL;
} else {
lstrcpynA(PathBuffer,ansiBuffer,Size);
}
}
}
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(diskName) {
MyFree(diskName);
}
if(pathToSource) {
MyFree(pathToSource);
}
if(fileSought) {
MyFree(fileSought);
}
if(tagFile) {
MyFree(tagFile);
}
SetLastError(rc);
return(u);
}
#else
//
// Unicode stub
//
UINT
SetupPromptForDiskW(
IN HWND hwndParent,
IN PCWSTR DialogTitle, OPTIONAL
IN PCWSTR DiskName, OPTIONAL
IN PCWSTR PathToSource, OPTIONAL
IN PCWSTR FileSought,
IN PCWSTR TagFile, OPTIONAL
IN DWORD DiskPromptStyle,
OUT PWSTR PathBuffer,
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(DialogTitle);
UNREFERENCED_PARAMETER(DiskName);
UNREFERENCED_PARAMETER(PathToSource);
UNREFERENCED_PARAMETER(FileSought);
UNREFERENCED_PARAMETER(TagFile);
UNREFERENCED_PARAMETER(DiskPromptStyle);
UNREFERENCED_PARAMETER(PathBuffer);
UNREFERENCED_PARAMETER(PathBufferSize);
UNREFERENCED_PARAMETER(PathRequiredSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(DPROMPT_CANCEL);
}
#endif
UINT
SetupPromptForDisk(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR DiskName, OPTIONAL
IN PCTSTR PathToSource, OPTIONAL
IN PCTSTR FileSought,
IN PCTSTR TagFile, OPTIONAL
IN DWORD DiskPromptStyle,
OUT PTSTR PathBuffer,
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
PCTSTR dialogTitle;
PCTSTR diskName;
PCTSTR pathToSource;
PCTSTR fileSought;
PCTSTR tagFile;
TCHAR pathBuffer[MAX_PATH];
DWORD rc;
UINT u;
DWORD Size;
dialogTitle = NULL;
diskName = NULL;
pathToSource = NULL;
fileSought = NULL;
tagFile = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = CaptureStringArg(DialogTitle,&dialogTitle);
}
if((rc == NO_ERROR) && DiskName) {
rc = CaptureStringArg(DiskName,&diskName);
}
if((rc == NO_ERROR) && PathToSource) {
rc = CaptureStringArg(PathToSource,&pathToSource);
}
if((rc == NO_ERROR) && FileSought) {
rc = CaptureStringArg(FileSought,&fileSought);
}
if((rc == NO_ERROR) && TagFile) {
rc = CaptureStringArg(TagFile,&tagFile);
}
if(rc == NO_ERROR) {
u = _SetupPromptForDisk(
hwndParent,
dialogTitle,
diskName,
pathToSource,
fileSought,
tagFile,
DiskPromptStyle,
pathBuffer,
MAX_PATH,
&Size
);
rc = GetLastError();
if(u == DPROMPT_SUCCESS) {
if(PathRequiredSize) {
*PathRequiredSize = Size;
}
if(PathBuffer) {
if(Size > PathBufferSize) {
u = DPROMPT_BUFFERTOOSMALL;
} else {
lstrcpyn(PathBuffer,pathBuffer,Size);
}
}
}
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(diskName) {
MyFree(diskName);
}
if(pathToSource) {
MyFree(pathToSource);
}
if(fileSought) {
MyFree(fileSought);
}
if(tagFile) {
MyFree(tagFile);
}
SetLastError(rc);
return(u);
}
INT_PTR
DlgProcFileError(
IN HWND hdlg,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Dialog procedure for delete/rename error dialog.
The return value for the dialog is
DPROMPT_CANCEL - user cancelled
DPROMPT_SKIPFILE - user elected to skip file
DPROMPT_SUCCESS - user said retry
DPROMPT_OUTOFMEMORY - out of memory
Arguments:
Standard dialog routine parameters.
Return Value:
TRUE if message processed; FALSE if not.
--*/
{
static PFILEERRDLGPARAMS Params = NULL;
BOOL b;
switch(msg) {
case WM_INITDIALOG:
Params = (PFILEERRDLGPARAMS)lParam;
SetDlgItemText(hdlg,IDT_TEXT1,Params->MessageText);
SetWindowText(hdlg,Params->Caption);
SendDlgItemMessage(
hdlg,
IDI_ICON1,
STM_SETICON,
(WPARAM)LoadIcon(NULL,IDI_HAND),
0
);
if(!(Params->Style & IDF_NOBEEP)) {
MessageBeep(MB_ICONASTERISK);
}
if(!(Params->Style & IDF_NOFOREGROUND)) {
PostMessage(hdlg,WMX_HELLO,0,0);
}
pSetupCenterWindowRelativeToParent(hdlg);
//
// Set focus to retry button and continue.
//
SetFocus(GetDlgItem(hdlg,IDOK));
b = FALSE;
break;
case WMX_HELLO:
SetForegroundWindow(hdlg);
b = TRUE;
break;
case WM_COMMAND:
if(HIWORD(wParam) == BN_CLICKED) {
b = TRUE;
switch(LOWORD(wParam)) {
case IDOK:
EndDialog(hdlg,DPROMPT_SUCCESS);
break;
case IDCANCEL:
if ( (Params->Style & IDF_NOSKIP) || !CancelAllCopies(hdlg)) {
EndDialog(hdlg,DPROMPT_CANCEL);
} else {
EndDialog(hdlg,DPROMPT_SKIPFILE);
}
break;
default:
b = FALSE;
break;
}
} else {
b = FALSE;
}
break;
default:
if (!g_uQueryCancelAutoPlay) {
g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
}
if (msg == g_uQueryCancelAutoPlay) {
SetWindowLongPtr( hdlg, DWLP_MSGRESULT, 1 );
return 1; // cancel auto-play
}
b = FALSE;
break;
}
return(b);
}
#ifdef UNICODE
//
// ANSI version
//
UINT
SetupCopyErrorA(
IN HWND hwndParent,
IN PCSTR DialogTitle, OPTIONAL
IN PCSTR DiskName, OPTIONAL
IN PCSTR PathToSource,
IN PCSTR SourceFile,
IN PCSTR TargetPathFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style,
OUT PSTR PathBuffer, OPTIONAL
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
PCWSTR dialogTitle;
PCWSTR diskName;
PCWSTR pathToSource;
PCWSTR sourceFile;
PCWSTR targetPathFile;
WCHAR pathBuffer[MAX_PATH];
CHAR ansiBuffer[MAX_PATH];
DWORD rc;
UINT u;
DWORD Size;
dialogTitle = NULL;
diskName = NULL;
pathToSource = NULL;
sourceFile = NULL;
targetPathFile = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
}
if((rc == NO_ERROR) && DiskName) {
rc = pSetupCaptureAndConvertAnsiArg(DiskName,&diskName);
}
if((rc == NO_ERROR) && PathToSource) {
rc = pSetupCaptureAndConvertAnsiArg(PathToSource,&pathToSource);
}
if((rc == NO_ERROR) && SourceFile) {
rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
}
if((rc == NO_ERROR) && TargetPathFile) {
rc = pSetupCaptureAndConvertAnsiArg(TargetPathFile,&targetPathFile);
}
if(rc == NO_ERROR) {
u = SetupCopyErrorW(
hwndParent,
dialogTitle,
diskName,
pathToSource,
sourceFile,
targetPathFile,
Win32ErrorCode,
Style,
pathBuffer,
MAX_PATH,
&Size
);
rc = GetLastError();
if(u == DPROMPT_SUCCESS) {
Size = (DWORD)WideCharToMultiByte(
CP_ACP,
0,
pathBuffer,
(int)Size,
ansiBuffer,
MAX_PATH,
NULL,
NULL
);
if(PathRequiredSize) {
*PathRequiredSize = Size;
}
if(PathBuffer) {
if(Size > PathBufferSize) {
u = DPROMPT_BUFFERTOOSMALL;
} else {
lstrcpynA(PathBuffer,ansiBuffer,Size);
}
}
}
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(diskName) {
MyFree(diskName);
}
if(pathToSource) {
MyFree(pathToSource);
}
if(sourceFile) {
MyFree(sourceFile);
}
if(targetPathFile) {
MyFree(targetPathFile);
}
SetLastError(rc);
return(u);
}
#else
//
// Unicode stub
//
UINT
SetupCopyErrorW(
IN HWND hwndParent,
IN PCWSTR DialogTitle, OPTIONAL
IN PCWSTR DiskName, OPTIONAL
IN PCWSTR PathToSource,
IN PCWSTR SourceFile,
IN PCWSTR TargetPathFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style,
OUT PWSTR PathBuffer, OPTIONAL
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(DialogTitle);
UNREFERENCED_PARAMETER(DiskName);
UNREFERENCED_PARAMETER(PathToSource);
UNREFERENCED_PARAMETER(SourceFile);
UNREFERENCED_PARAMETER(TargetPathFile);
UNREFERENCED_PARAMETER(Win32ErrorCode);
UNREFERENCED_PARAMETER(Style);
UNREFERENCED_PARAMETER(PathBuffer);
UNREFERENCED_PARAMETER(PathBufferSize);
UNREFERENCED_PARAMETER(PathRequiredSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(DPROMPT_CANCEL);
}
#endif
UINT
SetupCopyError(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR DiskName, OPTIONAL
IN PCTSTR PathToSource,
IN PCTSTR SourceFile,
IN PCTSTR TargetPathFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style,
OUT PTSTR PathBuffer, OPTIONAL
IN DWORD PathBufferSize,
OUT PDWORD PathRequiredSize OPTIONAL
)
/*++
Routine Description:
Inform the user about a file copy error.
Arguments:
hwndParent - supplies window handle of window/dialog to own the error dialog
displayed by this routine.
DialogTitle - if specified, supplies title for error dialog. If not specified
a default of "Copy Error" will be supplied.
DiskName - if specified, supplies name of the disk from which a source file
was expected. If not specified a default of "(Unknown)" will be supplied.
PathToSource - supplies full path part of source file name.
SourceFile - supplies filename part of the source file name.
TargetPathFile - if specified supplies the full pathname of the target.
Win32ErrorCode - supplies win32 error code of failure.
Style - supplies flags to control the behavior of the dialog.
Return Value:
DPROMPT_xxx indicating outcome.
--*/
{
INT_PTR i;
DWORD d = NO_ERROR;
DWORD TmpRequiredSize;
HANDLE hDialogEvent = NULL;
PCTSTR dialogTitle = NULL;
PCTSTR diskName = NULL;
PCTSTR pathToSource = NULL;
PCTSTR sourceFile = NULL;
PCTSTR targetPathFile = NULL;
PTSTR ErrorText = NULL;
PTSTR Message = NULL;
PTSTR p;
//
// If we're running non-interactive, bail now...
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return DPROMPT_CANCEL;
}
//
// verify & snap all parameters
//
if(DialogTitle) {
d = CaptureStringArg(DialogTitle,&dialogTitle);
} else {
dialogTitle = MyLoadString(IDS_COPYERROR);
if(!dialogTitle) {
d = ERROR_NOT_ENOUGH_MEMORY;
}
}
if(d == NO_ERROR) {
if(DiskName) {
d = CaptureStringArg(DiskName,&diskName);
} else {
diskName = MyLoadString(IDS_UNKNOWN_PARENS);
if(!diskName) {
d = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
if(d == NO_ERROR) {
if(PathToSource) {
d = CaptureStringArg(PathToSource,&pathToSource);
} else {
d = ERROR_INVALID_PARAMETER;
}
}
if(d == NO_ERROR) {
if(SourceFile) {
d = CaptureStringArg(SourceFile,&sourceFile);
} else {
d = ERROR_INVALID_PARAMETER;
}
}
if((d == NO_ERROR) && TargetPathFile) {
d = CaptureStringArg(TargetPathFile,&targetPathFile);
}
if(d) {
if(d == ERROR_NOT_ENOUGH_MEMORY) {
i = DPROMPT_OUTOFMEMORY;
} else {
i = DPROMPT_CANCEL;
}
goto clean;
}
if(Win32ErrorCode == ERROR_INVALID_TARGET) {
FILEERRDLGPARAMS FileErrorDlgParams;
//
// Fatal copy error not fixed by changing source location
//
ErrorText = MyLoadString(IDS_COPY_INVALID_TARGET);
if(!ErrorText) {
i = DPROMPT_OUTOFMEMORY;
goto clean;
}
//
// don't display the error-code in this case
// just the error text
//
Message = RetreiveAndFormatMessage(
MSG_FILEERROR_COPY,
sourceFile,
ErrorText
);
if(!Message) {
i = DPROMPT_OUTOFMEMORY;
goto clean;
}
FileErrorDlgParams.MessageText = Message;
FileErrorDlgParams.Style = Style;
FileErrorDlgParams.Caption = dialogTitle;
if(!FileErrorDlgParams.Caption) {
i = DPROMPT_OUTOFMEMORY;
goto clean;
}
if (GuiSetupInProgress) {
hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
}
if ( hDialogEvent ) {
SetEvent( hDialogEvent );
}
d = NO_ERROR;
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_FILEERROR2),
hwndParent,
DlgProcFileError,
(LPARAM)&FileErrorDlgParams
);
if ( hDialogEvent ) {
ResetEvent( hDialogEvent );
CloseHandle( hDialogEvent );
}
if(i == -1) {
i = DPROMPT_OUTOFMEMORY;
}
} else {
PROMPTPARAMS Params;
ZeroMemory(&Params,sizeof(PROMPTPARAMS));
//
// If the dialog title is not specified fetch a default.
//
Params.DialogTitle = dialogTitle;
Params.DiskName = diskName;
Params.FileSought = sourceFile;
Params.PathToSource = pathToSource;
Params.TargetFile = targetPathFile;
//
// assume dialog proc may change any of these
//
dialogTitle = NULL;
diskName = NULL;
sourceFile = NULL;
pathToSource = NULL;
targetPathFile = NULL;
//
// There is no tag file usage in the error dialog.
//
Params.TagFile = NULL;
//
// Determine drive type of source path
//
DiskPromptGetDriveType(Params.PathToSource,&Params.DriveType,&Params.IsRemovable);
//
// Fetch the installation path list.
//
d = pSetupGetList(
0,
&Params.PathList,
&Params.PathCount,
&Params.ReadOnlyMru
);
if(d != NO_ERROR) {
i = (d == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
goto clean;
}
//
// Other fields
//
Params.Owner = hwndParent;
Params.PromptStyle = Style;
Params.UserBrowsed = FALSE;
Params.DialogType = DLGTYPE_ERROR;
Params.Win32Error = Win32ErrorCode;
if(Params.ReadOnlyMru) {
Params.PromptStyle |= IDF_NOBROWSE;
}
if (GuiSetupInProgress) {
hDialogEvent = CreateEvent(NULL,TRUE,FALSE,SETUP_HAS_OPEN_DIALOG_EVENT);
}
if ( hDialogEvent ) {
SetEvent( hDialogEvent );
}
Params.BrowseAutoComplete = FALSE;
if(!GuiSetupInProgress) {
d = OleInitialize(NULL);
if(SUCCEEDED(d)) {
Params.BrowseAutoComplete = TRUE;
}
}
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_DISKPROMPT1),
hwndParent,
DlgProcDiskPrompt1,
(LPARAM)&Params
);
if(!GuiSetupInProgress && (d==NO_ERROR)) {
OleUninitialize();
}
if ( hDialogEvent ) {
ResetEvent( hDialogEvent );
CloseHandle( hDialogEvent );
}
d = GetLastError();
if(i == DPROMPT_SUCCESS) {
ModifyPathList(&Params);
//
// Now determine what to return to the user depending on the
// buffer and sizes passed in.
//
TmpRequiredSize = lstrlen(Params.PathToSource)+1;
if(PathRequiredSize) {
*PathRequiredSize = TmpRequiredSize;
}
if(PathBuffer) {
if(TmpRequiredSize > PathBufferSize) {
i = DPROMPT_BUFFERTOOSMALL;
} else {
lstrcpy(PathBuffer,Params.PathToSource);
}
}
}
SetupFreeSourceList(&Params.PathList,Params.PathCount);
//
// release params (either we, or DlgProcDiskPrompt1 allocated the data)
//
if (Params.DialogTitle) {
MyFree(Params.DialogTitle);
}
if (Params.DiskName) {
MyFree(Params.DiskName);
}
if (Params.FileSought) {
MyFree(Params.FileSought);
}
if (Params.PathToSource) {
MyFree(Params.PathToSource);
}
if (Params.TargetFile) {
MyFree(Params.TargetFile);
}
}
clean:
if(dialogTitle) {
MyFree(dialogTitle);
}
if(diskName) {
MyFree(diskName);
}
if(pathToSource) {
MyFree(pathToSource);
}
if(sourceFile) {
MyFree(sourceFile);
}
if(targetPathFile) {
MyFree(targetPathFile);
}
if(ErrorText) {
MyFree(ErrorText);
}
if(Message) {
MyFree(Message);
}
SetLastError(d);
return((UINT)i);
}
#ifdef UNICODE
//
// ANSI version
//
UINT
SetupRenameErrorA(
IN HWND hwndParent,
IN PCSTR DialogTitle, OPTIONAL
IN PCSTR SourceFile,
IN PCSTR TargetFile,
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
PCWSTR dialogTitle,sourceFile,targetFile;
DWORD rc;
UINT u;
dialogTitle = NULL;
sourceFile = NULL;
targetFile = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
}
if((rc == NO_ERROR) && SourceFile) {
rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
}
if((rc == NO_ERROR) && TargetFile) {
rc = pSetupCaptureAndConvertAnsiArg(TargetFile,&targetFile);
}
if(rc == NO_ERROR) {
u = SetupRenameErrorW(
hwndParent,
dialogTitle,
sourceFile,
targetFile,
Win32ErrorCode,
Style
);
rc = GetLastError();
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(sourceFile) {
MyFree(sourceFile);
}
if(targetFile) {
MyFree(targetFile);
}
SetLastError(rc);
return(u);
}
#else
//
// Unicode stub
//
UINT
SetupRenameErrorW(
IN HWND hwndParent,
IN PCWSTR DialogTitle, OPTIONAL
IN PCWSTR SourceFile,
IN PCWSTR TargetFile,
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(DialogTitle);
UNREFERENCED_PARAMETER(SourceFile);
UNREFERENCED_PARAMETER(TargetFile);
UNREFERENCED_PARAMETER(Win32ErrorCode);
UNREFERENCED_PARAMETER(Style);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(DPROMPT_CANCEL);
}
#endif
UINT
SetupRenameError(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR SourceFile,
IN PCTSTR TargetFile,
IN UINT Win32ErrorCode,
IN DWORD Style
)
/*++
Routine Description:
Inform the user about a rename error.
Arguments:
hwndParent - supplies window handle of window/dialog to own the error dialog
displayed by this routine.
DialogTitle - if specified, supplies title for error dialog. If not specified
a default of "Rename Error" will be supplied.
SourceFile - supplies full path and filename of source.
TargetFile - supplies full path and filename of target.
Win32ErrorCode - supplies win32 error code of failure.
Style - supplies flags to control the behavior of the dialog.
Return Value:
DPROMPT_xxx indicating outcome.
--*/
{
PTSTR ErrorText;
PTSTR Message;
PTCHAR p;
INT_PTR i;
FILEERRDLGPARAMS FileErrorDlgParams;
//
// If we're running non-interactive, bail now...
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return DPROMPT_CANCEL;
}
ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
if(ErrorText) {
p = ErrorText + lstrlen(ErrorText) - 1;
while((p > ErrorText) && (*p <= TEXT(' '))) {
*p-- = 0;
}
} else {
return(DPROMPT_OUTOFMEMORY);
}
Message = RetreiveAndFormatMessage(
MSG_FILEERROR_RENAME,
ErrorText,
Win32ErrorCode,
SourceFile,
TargetFile
);
if(!Message) {
MyFree(ErrorText);
return(DPROMPT_OUTOFMEMORY);
}
FileErrorDlgParams.MessageText = Message;
FileErrorDlgParams.Style = Style;
FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_RENAMEERROR);
if(!FileErrorDlgParams.Caption) {
MyFree(ErrorText);
MyFree(Message);
SetLastError(NO_ERROR);
return(DPROMPT_OUTOFMEMORY);
}
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_FILEERROR2),
hwndParent,
DlgProcFileError,
(LPARAM)&FileErrorDlgParams
);
MyFree(ErrorText);
MyFree(Message);
if(!DialogTitle) {
MyFree(FileErrorDlgParams.Caption);
}
if(i == -1) {
i = DPROMPT_OUTOFMEMORY;
}
SetLastError(NO_ERROR);
return((UINT)i);
}
#ifdef UNICODE
//
// ANSI version
//
UINT
SetupDeleteErrorA(
IN HWND hwndParent,
IN PCSTR DialogTitle, OPTIONAL
IN PCSTR File,
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
PCWSTR dialogTitle,file;
DWORD rc;
UINT u;
dialogTitle = NULL;
file = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
}
if((rc ==NO_ERROR) && File) {
rc = pSetupCaptureAndConvertAnsiArg(File,&file);
}
if(rc == NO_ERROR) {
u = SetupDeleteErrorW(hwndParent,dialogTitle,file,Win32ErrorCode,Style);
rc = GetLastError();
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(file) {
MyFree(file);
}
SetLastError(rc);
return(u);
}
#else
//
// Unicode stub
//
UINT
SetupDeleteErrorW(
IN HWND hwndParent,
IN PCWSTR DialogTitle, OPTIONAL
IN PCWSTR File,
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(DialogTitle);
UNREFERENCED_PARAMETER(File);
UNREFERENCED_PARAMETER(Win32ErrorCode);
UNREFERENCED_PARAMETER(Style);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(DPROMPT_CANCEL);
}
#endif
UINT
SetupDeleteError(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR File,
IN UINT Win32ErrorCode,
IN DWORD Style
)
/*++
Routine Description:
Inform the user about a rename error.
Arguments:
hwndParent - supplies window handle of window/dialog to own the error dialog
displayed by this routine.
DialogTitle - if specified, supplies title for error dialog. If not specified
a default of "Delete Error" will be supplied.
File - supplies full path and filename of file being deleted.
Win32ErrorCode - supplies win32 error code of failure.
Style - supplies flags to control the behavior of the dialog.
Return Value:
DPROMPT_xxx indicating outcome.
--*/
{
PTSTR ErrorText;
PTSTR Message;
PTCHAR p;
INT_PTR i;
FILEERRDLGPARAMS FileErrorDlgParams;
//
// If we're running non-interactive, bail now...
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return DPROMPT_CANCEL;
}
ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
if(ErrorText) {
p = ErrorText + lstrlen(ErrorText) - 1;
while((p > ErrorText) && (*p <= TEXT(' '))) {
*p-- = 0;
}
} else {
return(DPROMPT_OUTOFMEMORY);
}
Message = RetreiveAndFormatMessage(
MSG_FILEERROR_DELETE,
File,
ErrorText,
Win32ErrorCode
);
if(!Message) {
MyFree(ErrorText);
return(DPROMPT_OUTOFMEMORY);
}
FileErrorDlgParams.MessageText = Message;
FileErrorDlgParams.Style = Style;
FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_DELETEERROR);
if(!FileErrorDlgParams.Caption) {
MyFree(ErrorText);
MyFree(Message);
return(DPROMPT_OUTOFMEMORY);
}
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_FILEERROR2),
hwndParent,
DlgProcFileError,
(LPARAM)&FileErrorDlgParams
);
MyFree(ErrorText);
MyFree(Message);
if(!DialogTitle) {
MyFree(FileErrorDlgParams.Caption);
}
if(i == -1) {
i = DPROMPT_OUTOFMEMORY;
}
return((UINT)i);
}
#ifdef UNICODE
//
// ANSI version
//
UINT
SetupBackupErrorA(
IN HWND hwndParent,
IN PCSTR DialogTitle, OPTIONAL
IN PCSTR SourceFile,
IN PCSTR TargetFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
PCWSTR dialogTitle,sourceFile,targetFile;
DWORD rc;
UINT u;
dialogTitle = NULL;
sourceFile = NULL;
targetFile = NULL;
rc = NO_ERROR;
if(DialogTitle) {
rc = pSetupCaptureAndConvertAnsiArg(DialogTitle,&dialogTitle);
}
if((rc == NO_ERROR) && SourceFile) {
rc = pSetupCaptureAndConvertAnsiArg(SourceFile,&sourceFile);
}
if((rc == NO_ERROR) && TargetFile) {
rc = pSetupCaptureAndConvertAnsiArg(TargetFile,&targetFile);
}
if(rc == NO_ERROR) {
u = SetupBackupErrorW(
hwndParent,
dialogTitle,
sourceFile,
targetFile,
Win32ErrorCode,
Style
);
rc = GetLastError();
} else {
u = (rc == ERROR_NOT_ENOUGH_MEMORY) ? DPROMPT_OUTOFMEMORY : DPROMPT_CANCEL;
}
if(dialogTitle) {
MyFree(dialogTitle);
}
if(sourceFile) {
MyFree(sourceFile);
}
if(targetFile) {
MyFree(targetFile);
}
SetLastError(rc);
return(u);
}
#else
//
// Unicode stub
//
UINT
SetupBackupErrorW(
IN HWND hwndParent,
IN PCWSTR DialogTitle, OPTIONAL
IN PCWSTR SourceFile,
IN PCWSTR TargetFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(DialogTitle);
UNREFERENCED_PARAMETER(SourceFile);
UNREFERENCED_PARAMETER(TargetFile);
UNREFERENCED_PARAMETER(Win32ErrorCode);
UNREFERENCED_PARAMETER(Style);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(DPROMPT_CANCEL);
}
#endif
UINT
SetupBackupError(
IN HWND hwndParent,
IN PCTSTR DialogTitle, OPTIONAL
IN PCTSTR SourceFile,
IN PCTSTR TargetFile, OPTIONAL
IN UINT Win32ErrorCode,
IN DWORD Style
)
/*++
Routine Description:
Inform the user about a backup error.
Arguments:
hwndParent - supplies window handle of window/dialog to own the error dialog
displayed by this routine.
DialogTitle - if specified, supplies title for error dialog. If not specified
a default of "Rename Error" will be supplied.
SourceFile - supplies full path and filename of file to be backed up
TargetFile - supplies full path and filename of final name, if known
Win32ErrorCode - supplies win32 error code of failure.
Style - supplies flags to control the behavior of the dialog.
Return Value:
DPROMPT_xxx indicating outcome.
--*/
{
PTSTR ErrorText;
PTSTR Message;
PTCHAR p;
INT_PTR i;
FILEERRDLGPARAMS FileErrorDlgParams;
//
// If we're running non-interactive, bail now...
//
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
return DPROMPT_CANCEL;
}
ErrorText = RetreiveAndFormatMessage(Win32ErrorCode);
if(ErrorText) {
p = ErrorText + lstrlen(ErrorText) - 1;
while((p > ErrorText) && (*p <= TEXT(' '))) {
*p-- = 0;
}
} else {
return(DPROMPT_OUTOFMEMORY);
}
Message = RetreiveAndFormatMessage(
MSG_FILEERROR_BACKUP,
SourceFile,
ErrorText,
Win32ErrorCode
);
if(!Message) {
MyFree(ErrorText);
return(DPROMPT_OUTOFMEMORY);
}
FileErrorDlgParams.MessageText = Message;
FileErrorDlgParams.Style = Style;
FileErrorDlgParams.Caption = DialogTitle ? DialogTitle : MyLoadString(IDS_BACKUPERROR);
if(!FileErrorDlgParams.Caption) {
MyFree(ErrorText);
MyFree(Message);
return(DPROMPT_OUTOFMEMORY);
}
i = DialogBoxParam(
MyDllModuleHandle,
MAKEINTRESOURCE(IDD_FILEERROR2),
hwndParent,
DlgProcFileError,
(LPARAM)&FileErrorDlgParams
);
MyFree(ErrorText);
MyFree(Message);
if(!DialogTitle) {
MyFree(FileErrorDlgParams.Caption);
}
if(i == -1) {
i = DPROMPT_OUTOFMEMORY;
}
return((UINT)i);
}
BOOL
ConnectToNetShare(
IN PCTSTR FileName,
IN HWND hwndParent
)
/*++
Routine Description:
This routine determines the network share component of the specified file path,
and give the user a "Connect As" dialog so that they can connect to this share.
Arguments:
FileName - supplies the path of a file contained in the network share to be
connected to.
hwndParent - supplies a handle to the window that should be the parent of the
"Connect As" dialog.
Return Value:
If the network share is successfully connected to, the return value is TRUE, otherwise,
it is FALSE.
--*/
{
TCHAR TempFileName[MAX_PATH];
NETRESOURCE NetResourceIn;
LPNETRESOURCE NetResourceOut = NULL;
PTSTR TempString;
DWORD BufferSize, d;
BOOL Success = FALSE;
BOOL locked = FALSE;
PTEMP_NET_CONNECTION NewConnectionNode;
//
// Surround this code in try/except, in case we get an exception going out to
// the network.
//
try {
//
// Copy the filename into a local (writable) buffer, because the WNet structure
// doesn't specify its string pointers as CONST, and we don't want to take any chances.
//
lstrcpyn(TempFileName, FileName, SIZECHARS(TempFileName));
ZeroMemory(&NetResourceIn, sizeof(NetResourceIn));
NetResourceIn.lpRemoteName = TempFileName;
NetResourceIn.dwType = RESOURCETYPE_DISK;
//
// Use a reasonable default buffer size in hopes of avoiding multiple calls to
// WNetGetResourceInformation.
//
BufferSize = sizeof(NETRESOURCE) + (MAX_PATH * sizeof(TCHAR));
while(TRUE) {
if(!(NetResourceOut = MyMalloc(BufferSize))) {
goto clean0;
}
d = WNetGetResourceInformation(&NetResourceIn, NetResourceOut, &BufferSize, &TempString);
if(d == WN_SUCCESS) {
break;
} else {
//
// Free the buffer currently allocated for the net resource information.
//
MyFree(NetResourceOut);
NetResourceOut = NULL;
if(d != WN_MORE_DATA) {
//
// The call failed for some reason other than too small a buffer, so we just
// need to bail.
//
goto clean0;
}
}
}
//
// If we get to this point, then we've successfully retrieved network resource information
// for the caller-supplied path. Now give the user a chance to connect to that network
// location.
//
if(WNetAddConnection3(hwndParent,
NetResourceOut,
NULL,
NULL,
CONNECT_INTERACTIVE | CONNECT_PROMPT) == NO_ERROR) {
Success = TRUE;
//
// Now, add a new node for this connection into our temporary network
// connections list, so that we can disconnect during DLL unload.
//
if(NewConnectionNode = MyMalloc(sizeof(TEMP_NET_CONNECTION))) {
lstrcpy(NewConnectionNode->NetResourceName, NetResourceOut->lpRemoteName);
try {
EnterCriticalSection(&NetConnectionListCritSect);
locked = TRUE;
NewConnectionNode->Next = NetConnectionList;
NetConnectionList = NewConnectionNode;
} except(EXCEPTION_EXECUTE_HANDLER) {
}
if(locked) {
LeaveCriticalSection(&NetConnectionListCritSect);
}
}
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Reference the following variable so the compiler will respect our statement
// ordering for it.
//
NetResourceOut = NetResourceOut;
}
if(NetResourceOut) {
MyFree(NetResourceOut);
}
return Success;
}
VOID
pSetupInitNetConnectionList(
IN BOOL Init
)
/*++
Routine Description:
This routine initializes/tears down the temporary network connection linked list that is
used to track what UNC connections the user has made (via "Connect As" dialog) that need
to be cleaned up on DLL unload. As the list is being torn down, the network connection
for each node is deleted.
Arguments:
Init - specifies whether we're initializing or tearing down this list.
Return Value:
None.
--*/
{
PTEMP_NET_CONNECTION CurNode, NextNode;
if(Init) {
NetConnectionList = NULL;
} else {
for(CurNode = NetConnectionList; CurNode; CurNode = NextNode) {
//
// First, attempt to disconnect from this network resource.
//
WNetCancelConnection2(CurNode->NetResourceName, 0, FALSE);
NextNode = CurNode->Next;
MyFree(CurNode);
}
}
}