|
|
//
// Browse.C
//
// Copyright (C) Microsoft, 1994,1995 All Rights Reserved.
//
// History:
// ral 5/23/94 - First pass
// 3/20/95 [stevecat] - NT port & real clean up, unicode, etc.
//
//
#include "priv.h"
#include "appwiz.h"
#include "util.h"
#include <uastrfnc.h>
#include <tsappcmp.h> // for TermsrvAppInstallMode
// Copied from shelldll\ole2dup.h
#define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
//
// Initialize the browse property sheet. Limit the size of the edit control.
//
void BrowseInitPropSheet(HWND hDlg, LPARAM lParam) { LPWIZDATA lpwd = InitWizSheet(hDlg, lParam, 0);
Edit_LimitText(GetDlgItem(hDlg, IDC_COMMAND), ARRAYSIZE(lpwd->szExeName)-1);
if (FAILED(SHAutoComplete(GetDlgItem(hDlg, IDC_COMMAND), 0))) { TraceMsg(TF_WARNING, "%s", "WARNING: Create Shortcut wizard won't AutoComplete because: 1) bad registry, 2) bad OleInit, or 3) Out of memory."); } }
//
// Sets the appropriate wizard buttons. If there's any text in the
// edit control then Next is enabled. Otherwise, Next and Back are both
// grey.
//
void SetBrowseButtons(LPWIZDATA lpwd) { BOOL fIsText = GetWindowTextLength(GetDlgItem(lpwd->hwnd, IDC_COMMAND)) > 0; BOOL fIsSetup = (lpwd->dwFlags & WDFLAG_SETUPWIZ); int iBtns = fIsSetup ? PSWIZB_BACK : 0;
if (fIsSetup) { // Are we running Terminal Service? Is this user an Admin?
if (IsTerminalServicesRunning() && IsUserAnAdmin()) { lpwd->bTermSrvAndAdmin = TRUE; iBtns |= fIsText ? PSWIZB_NEXT : PSWIZB_DISABLEDFINISH; } else iBtns |= fIsText ? PSWIZB_FINISH : PSWIZB_DISABLEDFINISH; } else { if (fIsText) { iBtns |= PSWIZB_NEXT; } } PropSheet_SetWizButtons(GetParent(lpwd->hwnd), iBtns); }
//
// NOTES: 1) This function assumes that lpwd->hwnd has already been set to
// the dialogs hwnd. 2) This function is called from NextPushed
// if the application specified can not be found.
//
// BrowseSetActive enables the next button and sets the focus to the edit
// control by posting a POKEFOCUS message.
//
void BrowseSetActive(LPWIZDATA lpwd) { //
// NOTE: We re-use the szProgDesc string since it will always be reset
// when this page is activated. Use it to construct a command line.
//
#define szCmdLine lpwd->szProgDesc
StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), lpwd->szExeName);
PathQuoteSpaces(szCmdLine);
if (lpwd->szParams[0] != 0) { StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), TEXT(" ")); StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), lpwd->szParams); }
Edit_SetText(GetDlgItem(lpwd->hwnd, IDC_COMMAND), szCmdLine);
if (lpwd->dwFlags & WDFLAG_SETUPWIZ) { int iHaveHeader = IsTerminalServicesRunning() ? IDS_TSHAVESETUPPRG : IDS_HAVESETUPPRG; int iHeader = szCmdLine[0] != 0 ? iHaveHeader : IDS_NOSETUPPRG; TCHAR szInstruct[MAX_PATH];
LoadString(g_hinst, iHeader, szInstruct, ARRAYSIZE(szInstruct));
Static_SetText(GetDlgItem(lpwd->hwnd, IDC_SETUPMSG), szInstruct); }
SetBrowseButtons(lpwd);
PostMessage(lpwd->hwnd, WMPRIV_POKEFOCUS, 0, 0);
szCmdLine[0] = 0; // Reset progdesc to empty string
#undef szCmdLine
}
//
// Returns TRUE if able to get properties for szExeName from PifMgr. The
// program properties will be read into lpwd->PropPrg.
//
BOOL ReadPifProps(LPWIZDATA lpwd) { HANDLE hPifProp; LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
hPifProp = PifMgr_OpenProperties(lpszName, NULL, 0, OPENPROPS_INHIBITPIF); if (!hPifProp) { TraceMsg(TF_ERROR, "%s", "Unable to open properties for DOS exe."); }
if (hPifProp == 0) return(FALSE);
PifMgr_GetProperties(hPifProp, (LPSTR)GROUP_PRG, &(lpwd->PropPrg), sizeof(lpwd->PropPrg), GETPROPS_NONE);
PifMgr_CloseProperties(hPifProp, CLOSEPROPS_DISCARD);
return(TRUE); }
//
// Returns TRUE if lpwd->szExeName points to a valid exe type. It also sets
// the appropriate flags, such as APPKNOWN and DOSAPP in the wizdata structure
// if the exe is valid.
//
void DetermineExeType(LPWIZDATA lpwd) {
DWORD dwExeType; LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
lpwd->dwFlags &= ~(WDFLAG_APPKNOWN | WDFLAG_DOSAPP);
dwExeType = (DWORD)SHGetFileInfo(lpszName, 0, NULL, 0, SHGFI_EXETYPE);
if (LOWORD(dwExeType) != ('M' | ('Z' << 8))) { lpwd->dwFlags |= WDFLAG_APPKNOWN;
if (lstrcmpi(PathFindExtension(lpszName), c_szPIF) == 0) { lpwd->dwFlags |= WDFLAG_DOSAPP; } } else { lpwd->dwFlags |= WDFLAG_DOSAPP;
if (ReadPifProps(lpwd)) { if ((lpwd->PropPrg.flPrgInit & PRGINIT_INFSETTINGS) || ((lpwd->PropPrg.flPrgInit & (PRGINIT_NOPIF | PRGINIT_DEFAULTPIF)) == 0)) { lpwd->dwFlags |= WDFLAG_APPKNOWN; } } } }
//
// Removes the filename extension (if any) from the string.
//
void StripExt(LPTSTR lpsz) { if(lpsz) { LPTSTR pExt = PathFindExtension(lpsz);
if (*pExt) *pExt = 0; // null out the "."
} }
//
// Sets the working directory as appropriate for the file type.
//
void FindWorkingDir(LPWIZDATA lpwd) { LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName; TCHAR szWindir[ MAX_PATH ]; DWORD dwLen;
if (PathIsUNC(lpszName) || PathIsDirectory(lpszName)) { lpwd->szWorkingDir[0] = 0; } else { StringCchCopy(lpwd->szWorkingDir, ARRAYSIZE(lpwd->szWorkingDir), lpszName); PathRemoveFileSpec(lpwd->szWorkingDir); }
//
// Okay, at this point we should have the absolute path for the
// working directory of the link. On NT, if the working dir happens to be for
// something in the %Windir% directory (or a subdir of %windir%),
// then store the path as %windir%\blah\blah\blah instead of as an
// absolute path. This will help with interoperability of shortcuts
// across different machines, etc. But only do this for shortcuts that
// are already marked as having expandable env strings...
//
if (lpwd->dwFlags & WDFLAG_EXPSZ) { dwLen = ExpandEnvironmentStrings( TEXT("%windir%"), szWindir, ARRAYSIZE(szWindir) ); if (dwLen && dwLen < ARRAYSIZE(szWindir) && lstrlen(szWindir) <= lstrlen(lpwd->szWorkingDir) ) { //
// we use dwLen-1 because dwLen includes the '\0' character
//
if (CompareString( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szWindir, dwLen-1 , lpwd->szWorkingDir, dwLen-1 ) == 2) { TCHAR szWorkingDir[ MAX_PATH ]; //
// We should substitute the env variable for the
// actual string here...
//
StringCchCopy(szWorkingDir, ARRAYSIZE(szWorkingDir), lpwd->szWorkingDir); StringCchCopy(lpwd->szWorkingDir, ARRAYSIZE(lpwd->szWorkingDir), TEXT("%windir%"));
// 8 == lstrlen("%windir%")
StringCchCopy( lpwd->szWorkingDir + 12, ARRAYSIZE(lpwd->szWorkingDir)-12, szWorkingDir+dwLen-1 );
} } } }
#ifndef NO_NEW_SHORTCUT_HOOK
//
// Returns:
// Hook result or error.
//
// S_OK:
// *pnshhk is the INewShortcutHook of the object to use to save the new Shortcut.
// szProgDesc[] and szExt[] are filled in.
// szExeName[] may be translated.
// otherwise:
// *pnshhk is NULL.
// szProgDesc[] and szExt[] are empty strings.
//
HRESULT QueryNewLinkHandler(LPWIZDATA lpwd, LPCLSID pclsidHook) { HRESULT hr; IUnknown *punk; LPTSTR lpszName = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
lpwd->pnshhk = NULL; lpwd->pnshhkA = NULL;
*(lpwd->szProgDesc) = TEXT('\0'); *(lpwd->szExt) = TEXT('\0');
hr = CoCreateInstance(pclsidHook, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, &punk);
if (hr == S_OK) { INewShortcutHook *pnshhk;
hr = punk->lpVtbl->QueryInterface(punk, &IID_INewShortcutHook, &pnshhk);
if (hr == S_OK) { hr = pnshhk->lpVtbl->SetReferent(pnshhk, lpszName, lpwd->hwnd);
if (hr == S_OK) { hr = pnshhk->lpVtbl->SetFolder(pnshhk, lpwd->lpszFolder);
if (hr == S_OK) { hr = pnshhk->lpVtbl->GetName(pnshhk, lpwd->szProgDesc, ARRAYSIZE(lpwd->szProgDesc));
if (hr == S_OK) { hr = pnshhk->lpVtbl->GetExtension(pnshhk, lpwd->szExt, ARRAYSIZE(lpwd->szExt));
if (hr == S_OK) hr = pnshhk->lpVtbl->GetReferent(pnshhk, lpszName, ARRAYSIZE(lpwd->szExeName)); } } }
if (hr == S_OK) lpwd->pnshhk = pnshhk; else pnshhk->lpVtbl->Release(pnshhk); } else { INewShortcutHookA *pnshhkA; hr = punk->lpVtbl->QueryInterface(punk, &IID_INewShortcutHookA, &pnshhkA);
if (hr == S_OK) { UINT cFolderA = WideCharToMultiByte(CP_ACP,0,lpwd->lpszFolder,-1,NULL,0,0,0)+1; LPSTR lpszFolderA = (LPSTR)LocalAlloc(LPTR,cFolderA*SIZEOF(CHAR));
if (NULL == lpszFolderA) { hr = E_OUTOFMEMORY; } else { CHAR szNameA[MAX_PATH]; CHAR szProgDescA[MAX_PATH]; CHAR szExtA[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, lpszName, -1, szNameA, ARRAYSIZE(szNameA), 0, 0);
WideCharToMultiByte(CP_ACP, 0, lpwd->lpszFolder, -1, lpszFolderA, cFolderA, 0, 0);
hr = pnshhkA->lpVtbl->SetReferent(pnshhkA, szNameA, lpwd->hwnd);
if (hr == S_OK) { hr = pnshhkA->lpVtbl->SetFolder(pnshhkA, lpszFolderA);
if (hr == S_OK) { hr = pnshhkA->lpVtbl->GetName(pnshhkA, szProgDescA, ARRAYSIZE(szProgDescA));
if (hr == S_OK) { MultiByteToWideChar(CP_ACP, 0, szProgDescA, -1, lpwd->szProgDesc, ARRAYSIZE(lpwd->szProgDesc));
hr = pnshhkA->lpVtbl->GetExtension(pnshhkA, szExtA, ARRAYSIZE(szExtA));
if (hr == S_OK) { MultiByteToWideChar(CP_ACP, 0, szExtA, -1, lpwd->szExt, ARRAYSIZE(lpwd->szExt));
hr = pnshhkA->lpVtbl->GetReferent(pnshhkA, szNameA, ARRAYSIZE(szNameA));
MultiByteToWideChar(CP_ACP, 0, szExtA, -1, lpszName, ARRAYSIZE(lpwd->szExeName)); } } } }
if (hr == S_OK) lpwd->pnshhkA = pnshhkA; else pnshhkA->lpVtbl->Release(pnshhkA);
LocalFree(lpszFolderA); } } } punk->lpVtbl->Release(punk); }
return(hr); }
const TCHAR c_szNewLinkHandlers[] = REGSTR_PATH_EXPLORER TEXT("\\NewShortcutHandlers");
//
// Sets lpwd->pnshhk to NULL for CLSID_ShellLink (default) or to the
// INewShortcutHook of the object to be used.
//
// If lpwd->pnshhk is returned non-NULL, szProgDesc[] and szExt[] are also
// filled in.
//
void DetermineLinkHandler(LPWIZDATA lpwd) { HKEY hkeyHooks;
// Lose any previously saved external new Shortcut handler.
if (lpwd->pnshhk) { lpwd->pnshhk->lpVtbl->Release(lpwd->pnshhk); lpwd->pnshhk = NULL; } if (lpwd->pnshhkA) { lpwd->pnshhkA->lpVtbl->Release(lpwd->pnshhkA); lpwd->pnshhkA = NULL; }
//
// Enumerate the list of new link handlers. Each new link handler is
// registered as a GUID value under c_szNewLinkHandlers.
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szNewLinkHandlers, 0, KEY_READ, &hkeyHooks) == ERROR_SUCCESS) { DWORD dwiValue; TCHAR szCLSID[GUIDSTR_MAX]; DWORD dwcbCLSIDLen;
//
// Invoke each hook. A hook returns S_FALSE if it does not wish to
// handle the new link. Stop if a hook returns S_OK.
//
for (dwcbCLSIDLen = ARRAYSIZE(szCLSID), dwiValue = 0; RegEnumValue(hkeyHooks, dwiValue, szCLSID, &dwcbCLSIDLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; dwcbCLSIDLen = ARRAYSIZE(szCLSID), dwiValue++) { CLSID clsidHook;
if (SHCLSIDFromString(szCLSID, &clsidHook) == S_OK && QueryNewLinkHandler(lpwd, &clsidHook) == S_OK) break; }
RegCloseKey(hkeyHooks); }
return; }
#endif
//
// Returns TRUE if it's OK to go to the next wizard dialog.
//
BOOL NextPushed(LPWIZDATA lpwd) { GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
// Is the string a path with spaces, without arguments, but isn't correctly
// quoted? NT #d: >C:\Program Files\Windows NT\dialer.exe< is treated like
// "C:\Program" with "Files\Windows NT\dialer.exe" as args.
if (PathFileExists(lpwd->szExeName)) { // Yes, so let's quote it so we don't treat the stuff after
// the space like args.
PathQuoteSpaces(lpwd->szExeName); } PathRemoveBlanks(lpwd->szExeName);
if (lpwd->szExeName[0] != 0) { BOOL bUNC; LPTSTR lpszTarget = NULL; HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); LPTSTR lpszArgs = PathGetArgs(lpwd->szExeName);
StringCchCopy(lpwd->szParams, ARRAYSIZE(lpwd->szParams), lpszArgs);
if (*lpszArgs) { *(lpszArgs - 1) = 0; // clobber the ' ' in the exe name field
}
ExpandEnvironmentStrings( lpwd->szExeName, lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName) ); lpwd->szExpExeName[ MAX_PATH-1 ] = TEXT('\0'); if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName)) lpwd->dwFlags |= WDFLAG_EXPSZ;
lpszTarget = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
PathUnquoteSpaces(lpszTarget); if (lpwd->dwFlags & WDFLAG_EXPSZ) PathUnquoteSpaces(lpwd->szExeName);
lpwd->dwFlags &= ~WDFLAG_COPYLINK;
#ifndef NO_NEW_SHORTCUT_HOOK
//
// Figure out who wants to handle this string as a link referent.
//
DetermineLinkHandler(lpwd);
if (lpwd->pnshhk) { //
// We are using an external link handler. Skip file system
// validation.
//
lpwd->dwFlags |= WDFLAG_APPKNOWN; SetCursor(hcurOld); return(TRUE); } if (lpwd->pnshhkA) { //
// We are using an external link handler. Skip file system
// validation.
//
lpwd->dwFlags |= WDFLAG_APPKNOWN; SetCursor(hcurOld); return(TRUE); }
#endif
bUNC = PathIsUNC(lpszTarget);
if (bUNC && !SHValidateUNC(lpwd->hwnd, lpszTarget, FALSE)) goto Done;
//
// If the user tries to make a link to A:\ and there's no disk
// in the drive, PathResolve would fail. So, for drive roots, we
// don't try to resolve it.
//
if ((PathIsRoot(lpszTarget) && !bUNC && DriveType(DRIVEID(lpszTarget))) || PathResolve(lpszTarget, NULL, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS)) { //
// If we found a PIF file then we'll try to convert it to the
// name of the file it points to.
//
if (lstrcmpi(PathFindExtension(lpszTarget), c_szPIF) == 0) { if (!ReadPifProps(lpwd)) { goto Done; }
MultiByteToWideChar(CP_ACP, 0, lpwd->PropPrg.achCmdLine, -1, lpszTarget, ARRAYSIZE(lpwd->szExeName));
PathRemoveArgs(lpszTarget);
if (!PathResolve(lpszTarget, NULL, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS)) { goto Done; } }
//
// Okay, at this point we should have the absolute path for the
// target of the link. On NT, if the target happens to be for
// something in the %Windir% directory (or a subdir of %Windir%),
// AND the user didn't type in an expandable path already, then
// store the path as %windir%\blah\blah\blah instead of as an
// absolute path. This will help with interoperability of shortcuts
// across different machines, etc.
//
if (!(lpwd->dwFlags & WDFLAG_EXPSZ)) { TCHAR szWindir[ MAX_PATH ]; DWORD dwLen;
//
// What did the user type in?
//
GetDlgItemText(lpwd->hwnd, IDC_COMMAND, szWindir, ARRAYSIZE(szWindir)); if (ualstrcmpi(szWindir, lpwd->szExeName)==0) { //
// If we didn't change it, it means the user typed in an
// exact path. In that case, don't try to map anyting.
//
goto LinkToALinkCase; } dwLen = ExpandEnvironmentStrings( TEXT("%windir%"), szWindir, ARRAYSIZE(szWindir) ); if (dwLen && dwLen < ARRAYSIZE(szWindir) && lstrlen(szWindir) <= lstrlen(lpszTarget) ) { //
// we use dwLen-1 because dwLen includes the '\0' character
//
if (CompareString( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szWindir, dwLen-1 , lpszTarget, dwLen-1 ) == 2) { //
// We should substitute the env variable for the
// actual string here...
//
StringCchCopy(lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName), lpwd->szExeName); StringCchCopy(lpwd->szExeName, ARRAYSIZE(lpwd->szExeName), TEXT("%windir%"));
// 8 == lstrlen("%windir%")
StringCchCopy( lpwd->szExeName + 8, ARRAYSIZE(lpwd->szExeName)-8, lpwd->szExpExeName+dwLen-1 ); lpwd->dwFlags |= WDFLAG_EXPSZ; lpszTarget = lpwd->szExpExeName;
} } }
//
// Okay, at this point we should have the absolute path for the
// target of the link. On NT, if the target happens to be for
// something in the %Windir% directory (or a subdir of %Windir%),
// AND the user didn't type in an expandable path already, then
// store the path as %windir%\blah\blah\blah instead of as an
// absolute path. This will help with interoperability of shortcuts
// across different machines, etc.
//
if (!(lpwd->dwFlags & WDFLAG_EXPSZ)) { TCHAR szWindir[ MAX_PATH ]; DWORD dwLen;
//
// What did the user type in?
//
GetDlgItemText(lpwd->hwnd, IDC_COMMAND, szWindir, ARRAYSIZE(szWindir)); if (ualstrcmpi(szWindir, lpwd->szExeName)==0) { //
// If we didn't change it, it means the user typed in an
// exact path. In that case, don't try to map anyting.
//
goto LinkToALinkCase; } dwLen = ExpandEnvironmentStrings( TEXT("%windir%"), szWindir, ARRAYSIZE(szWindir) ); if (dwLen && dwLen < ARRAYSIZE(szWindir) && lstrlen(szWindir) <= lstrlen(lpszTarget) ) { //
// we use dwLen-1 because dwLen includes the '\0' character
//
if (CompareString( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szWindir, dwLen-1 , lpszTarget, dwLen-1 ) == 2) { //
// We should substitute the env variable for the
// actual string here...
//
StringCchCopy(lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName), lpwd->szExeName); StringCchCopy(lpwd->szExeName, ARRAYSIZE(lpwd->szExeName), TEXT("%windir%"));
// 8 == lstrlen("%windir%")
StringCchCopy( lpwd->szExeName + 8, ARRAYSIZE(lpwd->szExeName)-8, lpwd->szExpExeName+dwLen-1 ); lpwd->dwFlags |= WDFLAG_EXPSZ; lpszTarget = lpwd->szExpExeName;
} } } LinkToALinkCase:
//
// Really, really obscure case. The user creates "New Shortcut" and
// tries to point it to itself. Don't allow it. We'd be confused
// later. Since it's so obscure, just give a generic error about
// "Can't find this file"
//
if (!(lpwd->lpszOriginalName && lstrcmpi(lpwd->lpszOriginalName, lpszTarget) == 0)) { DetermineExeType(lpwd); FindWorkingDir(lpwd);
lpwd->szProgDesc[0] = 0; // Reset description
// EVEN IF WE DON'T RECREATE IT HERE!
if (lpwd->lpszFolder && lpwd->lpszFolder[0] != 0 && !DetermineDefaultTitle(lpwd)) { goto Done; }
if (lpwd->dwFlags & WDFLAG_EXPSZ) { LPTSTR lpszExt = PathFindExtension( lpwd->szExeName );
if (!(*lpszExt)) { // do simple check to make sure there was a file name
// at the end of the original entry. we assume that
// if we got this far, lpszExt points to the end of
// the string pointed to by lpwd->szExeName, and that
// lpwd->szExeName has at least one character in it.
if (lpwd->szExeName && (*lpwd->szExeName) && (*(lpszExt-1)!=TEXT('%')) ) { lstrcpy( lpszExt, PathFindExtension( lpszTarget ) ); } } }
SetCursor(hcurOld); return(TRUE); }
} Done:
SetCursor(hcurOld); ShellMessageBox(g_hinst, lpwd->hwnd, MAKEINTRESOURCE(IDS_BADPATHMSG), 0, MB_OK | MB_ICONEXCLAMATION, lpwd->szExeName); }
BrowseSetActive(lpwd); return(FALSE); }
//
// Returns TRUE if it's OK to run the setup program.
//
BOOL SetupCleanupExePath(LPWIZDATA lpwd) { BOOL fValidPrg = FALSE;
GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
// Is the string a path with spaces, without arguments, but isn't correctly
// quoted? NT #d: >C:\Program Files\Windows NT\dialer.exe< is treated like
// "C:\Program" with "Files\Windows NT\dialer.exe" as args.
if (PathFileExists(lpwd->szExeName)) { // Yes, so let's quote it so we don't treat the stuff after
// the space like args.
PathQuoteSpaces(lpwd->szExeName); }
PathRemoveBlanks(lpwd->szExeName);
if (lpwd->szExeName[0] != 0) { LPTSTR lpszTarget = NULL; LPTSTR lpszArgs = NULL; HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
ExpandEnvironmentStrings( lpwd->szExeName, lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName) ); if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName)) lpwd->dwFlags |= WDFLAG_EXPSZ;
lpszTarget = (lpwd->dwFlags & WDFLAG_EXPSZ) ? lpwd->szExpExeName : lpwd->szExeName;
lpszArgs = PathGetArgs(lpszTarget); StringCchCopy(lpwd->szParams, ARRAYSIZE(lpwd->szParams), lpszArgs); if (*lpszArgs) { *(lpszArgs - 1) = 0; // clobber the ' ' in the exe name field
} PathUnquoteSpaces(lpszTarget); if (lpwd->dwFlags & WDFLAG_EXPSZ) PathUnquoteSpaces(lpwd->szExeName);
if (PathResolve(lpszTarget, NULL, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS)) { LPTSTR lpszExt = PathFindExtension( lpszTarget ); fValidPrg = TRUE; FindWorkingDir(lpwd); if (lpwd->dwFlags & WDFLAG_EXPSZ) { if (!(*lpszExt)) { lstrcpy( lpszExt, PathFindExtension( lpszTarget ) ); } } if ((*lpszExt) && lpwd->bTermSrvAndAdmin && (!lstrcmpi(lpszExt, TEXT(".msi")))) { StringCchCat(lpwd->szParams, ARRAYSIZE(lpwd->szParams), TEXT(" ALLUSERS=1")); }
PathQuoteSpaces( lpszTarget ); } SetCursor(hcurOld); }
if (!fValidPrg) { ShellMessageBox(g_hinst, lpwd->hwnd, MAKEINTRESOURCE(IDS_BADPATHMSG), 0, MB_OK | MB_ICONEXCLAMATION, lpwd->szExeName); BrowseSetActive(lpwd); } return(fValidPrg); }
BOOL DetermineDefaultTitle(LPWIZDATA lpwd) { TCHAR szFullName[MAX_PATH]; BOOL fCopy; LPTSTR lpszName;
lpwd->dwFlags &= ~WDFLAG_COPYLINK;
if (lpwd->dwFlags & WDFLAG_EXPSZ) lpszName = lpwd->szExpExeName; else lpszName = lpwd->szExeName;
if (!SHGetNewLinkInfo(lpszName, lpwd->lpszFolder, szFullName, &fCopy, 0)) { //
// failure...
//
return(FALSE); }
lpszName = PathFindFileName(szFullName);
StripExt(lpszName);
lstrcpyn(lpwd->szProgDesc, lpszName, ARRAYSIZE(lpwd->szProgDesc));
//
// We will never copy PIF files since they often do not contain
// the appropriate current directory. This is becuase they are
// automatically created when you run a DOS application from the
// shell.
//
if ((lpwd->dwFlags & WDFLAG_DOSAPP) == 0) { if (fCopy) { lpwd->dwFlags |= WDFLAG_COPYLINK; } #ifndef NO_NEW_SHORTCUT_HOOK
StringCchCopy(lpwd->szExt, ARRAYSIZE(lpwd->szExt), c_szLNK); } else { StringCchCopy(lpwd->szExt, ARRAYSIZE(lpwd->szExt), c_szPIF); #endif
}
return(TRUE); }
//
// paranoia: evaluate each time in case it is installed after ARP was first open, but
// before it is closed and re-opened
//
BOOL MSI_IsMSIAvailable() { BOOL bAvailable = FALSE;
HINSTANCE hinst = LoadLibraryA("MSI.DLL"); if (hinst) { bAvailable = TRUE;
FreeLibrary(hinst); }
return bAvailable; }
//
// Call the common dialog code for File Open
//
BOOL BrowseForExe(HWND hwnd, LPTSTR pszName, DWORD cchName, LPCTSTR pszInitDir) { TCHAR szExt[80]; TCHAR szFilter[200]; TCHAR szTitle[80]; TCHAR szBootDir[64];
// we want to pass in an initial directory since GetFileNameFromBrowse
// try to determine an initial directory by doing a PathRemoveFileSpec
// on pszName. If pszName is already a directory then the last directory
// is removed (even though it's not a file). E.g.: "c:\winnt" -> "c:\"
lstrcpyn(szBootDir, pszInitDir, ARRAYSIZE(szBootDir));
if (MSI_IsMSIAvailable()) LoadAndStrip(IDS_BROWSEFILTERMSI, szFilter, ARRAYSIZE(szFilter)); else LoadAndStrip(IDS_BROWSEFILTER, szFilter, ARRAYSIZE(szFilter));
LoadString(g_hinst, IDS_BROWSEEXT, szExt, ARRAYSIZE(szExt)); LoadString(g_hinst, IDS_BROWSETITLE, szTitle, ARRAYSIZE(szTitle));
// we need to set pszName to NULL or else GetFileNameFromBrowse will use it
// to find the initial directory even though we explicitly pass in an initial
// dir.
*pszName = 0;
return(GetFileNameFromBrowse(hwnd, pszName, cchName, szBootDir, szExt, szFilter, szTitle)); }
//
// Use the common open dialog to browse for program. Used by SetupBrowseDlgProc
//
void BrowsePushed(LPWIZDATA lpwd) { LPTSTR lpszName; DWORD cchName = 0;
GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName)); ExpandEnvironmentStrings( lpwd->szExeName, lpwd->szExpExeName, ARRAYSIZE(lpwd->szExpExeName) ); if (lstrcmp(lpwd->szExeName, lpwd->szExpExeName)) lpwd->dwFlags |= WDFLAG_EXPSZ;
if (lpwd->dwFlags & WDFLAG_EXPSZ) { lpszName = lpwd->szExpExeName; cchName = ARRAYSIZE(lpwd->szExpExeName); } else { lpszName = lpwd->szExeName; cchName = ARRAYSIZE(lpwd->szExeName); }
if (BrowseForExe(lpwd->hwnd, lpszName, cchName, lpszName)) { lpwd->szParams[0] = 0; BrowseSetActive(lpwd); } }
void EnableOKButton(HWND hwndDlg, LPITEMIDLIST pidl) { DWORD dwFlags = SFGAO_FILESYSTEM; WCHAR szName[MAX_PATH] = L""; HRESULT hr = E_FAIL; if (pidl) { if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, ARRAYSIZE(szName), &dwFlags))) { if ((dwFlags & SFGAO_FILESYSTEM) != 0 || !lstrncmp(szName, L"\\\\", 2)) { hr = S_OK; } } } if (SUCCEEDED(hr)) { // Path is either a valid local path
// or a valid network path, enable the ok button
SendMessage(hwndDlg, BFFM_ENABLEOK, (WPARAM)0, (LPARAM)1); } else { // Path does not exist, disable the ok button
// This could be My Computer or an empty floppy drive etc...
SendMessage(hwndDlg, BFFM_ENABLEOK, (WPARAM)0, (LPARAM)0); } }
int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData ) { LPITEMIDLIST pidlNavigate;
switch (uMsg) { case BFFM_INITIALIZED: // Check if we should navigate to a folder on initialize
pidlNavigate = (LPITEMIDLIST) lpData; if (pidlNavigate != NULL) { // Yes! We have a folder to navigate to; send the message
SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM) FALSE, (LPARAM) pidlNavigate); } EnableOKButton(hwnd, pidlNavigate); break;
case BFFM_SELCHANGED: // Check if we should enable/disable the Ok button
pidlNavigate = (LPITEMIDLIST)lParam; if (pidlNavigate != NULL) { EnableOKButton(hwnd, pidlNavigate); } } return 0; }
// This implementation of 'Browse' uses SHBrowseForFolder to find a file or folder
// for the shortcut wizard - used by BrowseDlgProc
void BrowseForFileOrFolder(LPWIZDATA lpwd) { TCHAR szBrowseTitle[256]; TCHAR szName[MAX_PATH]; BROWSEINFO bi = {0}; LPITEMIDLIST pidlSelected; LPITEMIDLIST pidlStartBrowse; IShellFolder* pdesktop;
// Try to start the browse at a location indicated by the typed-in command line,
// if possible
GetDlgItemText(lpwd->hwnd, IDC_COMMAND, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
// ..Get the desktop folder
if (SUCCEEDED(SHGetDesktopFolder(&pdesktop))) { // ..Now try to parse the path the user entered into a pidl to start at
ULONG chEaten;
if (FAILED(pdesktop->lpVtbl->ParseDisplayName(pdesktop, lpwd->hwnd, NULL, lpwd->szExeName, &chEaten, &pidlStartBrowse, NULL))) { // The path the user entered didn't make any sense
// pidlStartBrowse should already be NULL, but we want to make sure
pidlStartBrowse = NULL; }
// Now we can continue and display the browse window
// Load the title string for the browse window
LoadString(g_hinst, IDS_FILEFOLDERBROWSE_TITLE, szBrowseTitle, ARRAYSIZE(szBrowseTitle));
// Note that bi = {0} for all other members except:
bi.hwndOwner = lpwd->hwnd; bi.pszDisplayName = szName; bi.lpszTitle = szBrowseTitle; bi.ulFlags = BIF_BROWSEINCLUDEFILES | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
// Ensure the pidl we want to start at is passed to the callback function
bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM) pidlStartBrowse;
pidlSelected = SHBrowseForFolder(&bi);
if (pidlSelected != NULL) { STRRET strret; if (SUCCEEDED(pdesktop->lpVtbl->GetDisplayNameOf(pdesktop, pidlSelected, SHGDN_NORMAL | SHGDN_FORPARSING, &strret))) { StrRetToBuf(&strret, pidlSelected, lpwd->szExeName, ARRAYSIZE(lpwd->szExeName));
// Assume no parameters for this new file
lpwd->szParams[0] = 0; // Populate the text box with the new file, etc.
BrowseSetActive(lpwd); } // Free the pidl
ILFree(pidlSelected); }
if (pidlStartBrowse != NULL) { ILFree(pidlStartBrowse); } pdesktop->lpVtbl->Release(pdesktop); } else { // This really shouldn't happen; SHGetDesktopdesktop failed; out of memory?
} }
//
// Main dialog procedure for first page of shortcut wizard.
//
//
// Note that there are now two BrowseDlgProcs, the one below and
// 'SetupBrowseDlgProc'. This is because BrowseDlgProc now uses
// a different method for implementing the 'Browse' button and I
// wanted to do this without affecting the Setup Wizard which will
// now use SetupBrowseDlgProc. - dsheldon 6/16/98
//
BOOL_PTR CALLBACK BrowseDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm = NULL; LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER)); LPWIZDATA lpwd = NULL;
if (lpPropSheet) { lpwd = (LPWIZDATA)lpPropSheet->lParam; }
switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; if(lpnm) { switch(lpnm->code) { case PSN_SETACTIVE: if(lpwd) { lpwd->hwnd = hDlg; if (lpwd->dwFlags & WDFLAG_NOBROWSEPAGE) { SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } else { BrowseSetActive(lpwd); } } break;
case PSN_WIZNEXT: if(lpwd) { if (!NextPushed(lpwd) || ((lpwd->dwFlags & WDFLAG_SETUPWIZ) && !SetupCleanupExePath(lpwd))) { SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } } break;
case PSN_WIZFINISH: if(lpwd) { BOOL ForceWx86;
#ifdef WX86
ForceWx86 = bWx86Enabled && bForceX86Env; #else
ForceWx86 = FALSE; #endif
if (!SetupCleanupExePath(lpwd) || !ExecSetupProg(lpwd, ForceWx86, TRUE)) { BrowseSetActive(lpwd); SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } } break;
case PSN_RESET: if(lpwd) { CleanUpWizData(lpwd); } break;
default: return FALSE; } } break;
case WM_INITDIALOG: BrowseInitPropSheet(hDlg, lParam); break;
case WMPRIV_POKEFOCUS: { HWND hCmd = GetDlgItem(hDlg, IDC_COMMAND);
SetFocus(hCmd);
Edit_SetSel(hCmd, 0, -1);
break; }
case WM_DESTROY: case WM_HELP: case WM_CONTEXTMENU: break;
case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDHELP: break;
case IDC_COMMAND: switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case EN_CHANGE: if(lpwd) { SetBrowseButtons(lpwd); } break; } break;
case IDC_BROWSE: if(lpwd) { BrowseForFileOrFolder(lpwd); } break;
} // end of switch on WM_COMMAND
break;
default: return FALSE;
} // end of switch on message
return TRUE; } // BrowseDlgProc
BOOL_PTR CALLBACK SetupBrowseDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm = NULL; LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER)); LPWIZDATA lpwd = NULL;
if (lpPropSheet) { lpwd = (LPWIZDATA)lpPropSheet->lParam; }
switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; if(lpnm) { switch(lpnm->code) { BOOL bForceWx86; case PSN_SETACTIVE: if(lpwd) { lpwd->hwnd = hDlg; if (lpwd->dwFlags & WDFLAG_NOBROWSEPAGE) { SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } else { BrowseSetActive(lpwd); } } break;
case PSN_WIZNEXT: if(lpwd) { // Remember the previous "InstallMode"
lpwd->bPrevMode = TermsrvAppInstallMode();
// Set the "InstallMode"
SetTermsrvAppInstallMode(TRUE);
#ifdef WX86
bForceWx86 = bWx86Enabled && bForceX86Env; #else
bForceWx86 = FALSE; #endif
if (!NextPushed(lpwd) || !SetupCleanupExePath(lpwd) || !ExecSetupProg(lpwd, bForceWx86, FALSE)) { SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } } break;
case PSN_WIZFINISH: if(lpwd) { #ifdef WX86
bForceWx86 = bWx86Enabled && bForceX86Env; #else
bForceWx86 = FALSE; #endif
if (!SetupCleanupExePath(lpwd) || !ExecSetupProg(lpwd, bForceWx86, TRUE)) { BrowseSetActive(lpwd); SetDlgMsgResult(hDlg, WM_NOTIFY, -1); } } break;
case PSN_RESET: if(lpwd) { CleanUpWizData(lpwd); } break;
default: return FALSE; } } break;
case WM_INITDIALOG: BrowseInitPropSheet(hDlg, lParam); break;
case WMPRIV_POKEFOCUS: { HWND hCmd = GetDlgItem(hDlg, IDC_COMMAND);
SetFocus(hCmd);
Edit_SetSel(hCmd, 0, -1);
break; }
case WM_DESTROY: case WM_HELP: case WM_CONTEXTMENU: break;
case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDHELP: break;
case IDC_COMMAND: switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case EN_CHANGE: if(lpwd) { SetBrowseButtons(lpwd); } break; } break;
case IDC_BROWSE: if(lpwd) { BrowsePushed(lpwd); } break;
} // end of switch on WM_COMMAND
break;
default: return FALSE;
} // end of switch on message
return TRUE; } // SetupBrowseDlgProc
|