1496 lines
44 KiB
C
1496 lines
44 KiB
C
|
//
|
||
|
// 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"
|
||
|
#ifdef WINNT
|
||
|
#include <uastrfnc.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef WINNT
|
||
|
#ifndef DOWNLEVEL_PLATFORM
|
||
|
#include <tsappcmp.h> // for TermsrvAppInstallMode
|
||
|
#endif // DOWNLEVEL_PLATFORM
|
||
|
#endif // WINNT
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
#ifndef DOWNLEVEL_PLATFORM
|
||
|
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.");
|
||
|
}
|
||
|
#endif //DOWNLEVEL_PLATFORM
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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)
|
||
|
{
|
||
|
#ifndef DOWNLEVEL_PLATFORM
|
||
|
#ifdef WINNT
|
||
|
// Are we running Terminal Service? Is this user an Admin?
|
||
|
if (IsTerminalServicesRunning() && IsUserAnAdmin())
|
||
|
{
|
||
|
lpwd->bTermSrvAndAdmin = TRUE;
|
||
|
iBtns |= fIsText ? PSWIZB_NEXT : PSWIZB_DISABLEDFINISH;
|
||
|
}
|
||
|
else
|
||
|
#endif // WINNT
|
||
|
#endif // DOWNLEVEL_PLATFORM
|
||
|
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
|
||
|
|
||
|
lstrcpy(szCmdLine, lpwd->szExeName);
|
||
|
|
||
|
PathQuoteSpaces(szCmdLine);
|
||
|
|
||
|
if (lpwd->szParams[0] != 0)
|
||
|
{
|
||
|
lstrcat(szCmdLine, TEXT(" "));
|
||
|
lstrcat(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 | WDFLAG_SINGLEAPP);
|
||
|
|
||
|
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;
|
||
|
|
||
|
if (lpwd->PropPrg.flPrgInit & PRGINIT_REALMODE)
|
||
|
{
|
||
|
lpwd->dwFlags |= WDFLAG_SINGLEAPP;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
#ifdef WINNT
|
||
|
TCHAR szWindir[ MAX_PATH ];
|
||
|
DWORD dwLen;
|
||
|
#endif
|
||
|
|
||
|
if (PathIsUNC(lpszName) || PathIsDirectory(lpszName))
|
||
|
{
|
||
|
lpwd->szWorkingDir[0] = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpy(lpwd->szWorkingDir, lpszName);
|
||
|
PathRemoveFileSpec(lpwd->szWorkingDir);
|
||
|
}
|
||
|
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// 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...
|
||
|
//
|
||
|
ualstrcpy( szWorkingDir, lpwd->szWorkingDir );
|
||
|
ualstrcpy( lpwd->szWorkingDir, TEXT("%windir%") );
|
||
|
|
||
|
// 8 == lstrlen("%windir%")
|
||
|
ualstrcpy( lpwd->szWorkingDir + 12, szWorkingDir+dwLen-1 );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // winnt
|
||
|
}
|
||
|
|
||
|
|
||
|
#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;
|
||
|
#ifdef UNICODE
|
||
|
lpwd->pnshhkA = NULL;
|
||
|
#endif
|
||
|
|
||
|
*(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);
|
||
|
}
|
||
|
#ifdef UNICODE
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
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;
|
||
|
}
|
||
|
#ifdef UNICODE
|
||
|
if (lpwd->pnshhkA)
|
||
|
{
|
||
|
lpwd->pnshhkA->lpVtbl->Release(lpwd->pnshhkA);
|
||
|
lpwd->pnshhkA = NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Enumerate the list of new link handlers. Each new link handler is
|
||
|
// registered as a GUID value under c_szNewLinkHandlers.
|
||
|
//
|
||
|
|
||
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szNewLinkHandlers, &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);
|
||
|
|
||
|
lstrcpy(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);
|
||
|
}
|
||
|
#ifdef UNICODE
|
||
|
if (lpwd->pnshhkA)
|
||
|
{
|
||
|
//
|
||
|
// We are using an external link handler. Skip file system
|
||
|
// validation.
|
||
|
//
|
||
|
|
||
|
lpwd->dwFlags |= WDFLAG_APPKNOWN;
|
||
|
SetCursor(hcurOld);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
MultiByteToWideChar(CP_ACP, 0, lpwd->PropPrg.achCmdLine, -1,
|
||
|
lpszTarget, ARRAYSIZE(lpwd->szExeName));
|
||
|
#else
|
||
|
lstrcpy(lpszTarget, lpwd->PropPrg.achCmdLine);
|
||
|
#endif // UNICODE
|
||
|
|
||
|
PathRemoveArgs(lpszTarget);
|
||
|
|
||
|
if (!PathResolve(lpszTarget, NULL,
|
||
|
PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS))
|
||
|
{
|
||
|
goto Done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// 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...
|
||
|
//
|
||
|
lstrcpy( lpwd->szExpExeName, lpwd->szExeName );
|
||
|
lstrcpy( lpwd->szExeName, TEXT("%windir%") );
|
||
|
|
||
|
// 8 == lstrlen("%windir%")
|
||
|
ualstrcpy( lpwd->szExeName + 8, lpwd->szExpExeName+dwLen-1 );
|
||
|
lpwd->dwFlags |= WDFLAG_EXPSZ;
|
||
|
lpszTarget = lpwd->szExpExeName;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // winnt
|
||
|
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// 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...
|
||
|
//
|
||
|
lstrcpy( lpwd->szExpExeName, lpwd->szExeName );
|
||
|
lstrcpy( lpwd->szExeName, TEXT("%windir%") );
|
||
|
|
||
|
// 8 == lstrlen("%windir%")
|
||
|
ualstrcpy( lpwd->szExeName + 8, lpwd->szExpExeName+dwLen-1 );
|
||
|
lpwd->dwFlags |= WDFLAG_EXPSZ;
|
||
|
lpszTarget = lpwd->szExpExeName;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
LinkToALinkCase:
|
||
|
|
||
|
#endif // winnt
|
||
|
|
||
|
//
|
||
|
// 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);
|
||
|
lstrcpy(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"))))
|
||
|
lstrcat(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
|
||
|
lstrcpy(lpwd->szExt, c_szLNK);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpy(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];
|
||
|
|
||
|
//
|
||
|
// Must pass the buffer size to GetBootDir because that is what
|
||
|
// the RegQueryValueEx function expects - not count of chars.
|
||
|
//
|
||
|
|
||
|
if (!pszInitDir)
|
||
|
{
|
||
|
GetBootDir(szBootDir, ARRAYSIZE(szBootDir));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BFFM_SELCHANGED:
|
||
|
// Check if we should enable/disable the Ok button
|
||
|
pidlNavigate = (LPITEMIDLIST)lParam;
|
||
|
if (pidlNavigate != NULL)
|
||
|
{
|
||
|
DWORD dwFlags = SFGAO_FILESYSTEM;
|
||
|
WCHAR szName[MAX_PATH] = L"";
|
||
|
|
||
|
if (SUCCEEDED(SHGetNameAndFlags(pidlNavigate, SHGDN_NORMAL, szName, ARRAYSIZE(szName), &dwFlags)))
|
||
|
{
|
||
|
if ((dwFlags & SFGAO_FILESYSTEM) != 0 ||
|
||
|
!lstrncmp(szName, L"\\\\", 2))
|
||
|
{
|
||
|
// Path is either a valid local path
|
||
|
// or a valid network path, enable the ok button
|
||
|
SendMessage(hwnd, 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(hwnd, BFFM_ENABLEOK, (WPARAM)0, (LPARAM)0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
if (FAILED(pdesktop->lpVtbl->ParseDisplayName(pdesktop, lpwd->hwnd, NULL,
|
||
|
lpwd->szExeName, &chEaten, &pidlStartBrowse, NULL)))
|
||
|
#else
|
||
|
WCHAR szTmp[MAX_PATH];
|
||
|
|
||
|
SHAnsiToUnicode(lpwd->szExeName, szTmp, MAX_PATH);
|
||
|
|
||
|
if (FAILED(pdesktop->lpVtbl->ParseDisplayName(pdesktop, lpwd->hwnd, NULL,
|
||
|
szTmp, &chEaten, &pidlStartBrowse, NULL)))
|
||
|
#endif
|
||
|
{
|
||
|
// 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
|
||
|
|
||
|
|
||
|
|
||
|
|