windows-nt/Source/XPSP1/NT/shell/shell32/shlexec2.c
2020-09-26 16:20:57 +08:00

289 lines
9.1 KiB
C

#include "shellprv.h"
#pragma hdrstop
#include "fstreex.h"
typedef struct {
HWND hDlg;
// input output
LPTSTR lpszExe; // base file name (to search for)
LPTSTR lpszPath; // starting location for search
LPCTSTR lpszName; // doc type name "Winword Document"
} FINDEXE_PARAMS, *LPFINDEXE_PARAMS;
int CALLBACK LocateCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
TCHAR szPath[MAX_PATH + 80];
int id;
LPFINDEXE_PARAMS lpfind = (LPFINDEXE_PARAMS)lpData;
switch(uMsg)
{
case BFFM_SELCHANGED:
SHGetPathFromIDList((LPITEMIDLIST)lParam, szPath);
if ((lstrlen(szPath) + lstrlen(lpfind->lpszExe)) < MAX_PATH)
{
PathAppend(szPath, lpfind->lpszExe);
if (PathFileExistsAndAttributes(szPath, NULL))
{
id = IDS_FILEFOUND;
}
else
{
id = IDS_FILENOTFOUND;
}
}
else
{
id = IDS_FILENOTFOUND;
}
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, id);
break;
case BFFM_INITIALIZED:
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, IDS_FILENOTFOUND);
break;
}
return 0;
}
void _GetBrowseTitle(LPFINDEXE_PARAMS lpfind, LPTSTR lpszBuffer, UINT cchBuffer)
{
TCHAR szTemplate[100];
LoadString(HINST_THISDLL, IDS_FINDASSEXEBROWSETITLE, szTemplate, ARRAYSIZE(szTemplate));
wnsprintf(lpszBuffer, cchBuffer, szTemplate, lpfind->lpszExe);
}
void DoBrowseForFile(LPFINDEXE_PARAMS lpfind)
{
TCHAR szFilePath[MAX_PATH] = { 0 }; // buffer for file name
TCHAR szInitialDir[MAX_PATH] = { 0 }; // buffer for file name
// initial directory to Program Files
SHGetSpecialFolderPath(NULL, szInitialDir, CSIDL_PROGRAM_FILES, TRUE);
if (GetFileNameFromBrowse(lpfind->hDlg, szFilePath, ARRAYSIZE(szFilePath), szInitialDir,
MAKEINTRESOURCE(IDS_EXE), MAKEINTRESOURCE(IDS_PROGRAMSFILTER), MAKEINTRESOURCE(IDS_BROWSE)))
{
SetDlgItemText(lpfind->hDlg, IDD_PATH, szFilePath);
lstrcpy((LPTSTR)lpfind->lpszPath, szFilePath);
}
}
void InitFindDlg(HWND hDlg, LPFINDEXE_PARAMS lpfind)
{
TCHAR szPath[MAX_PATH]; /* This must be the same size as lpfind->lpszPath */
TCHAR szBuffer[MAX_PATH + 100];
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpfind);
lpfind->hDlg = hDlg;
GetDlgItemText(hDlg, IDD_TEXT1, szPath, ARRAYSIZE(szPath));
wsprintf(szBuffer, szPath, lpfind->lpszExe, lpfind->lpszName);
SetDlgItemText(hDlg, IDD_TEXT1, szBuffer);
GetDlgItemText(hDlg, IDD_TEXT2, szPath, ARRAYSIZE(szPath));
wsprintf(szBuffer, szPath, lpfind->lpszExe);
SetDlgItemText(hDlg, IDD_TEXT2, szBuffer);
SetDlgItemText(hDlg, IDD_PATH, lpfind->lpszPath);
SHAutoComplete(GetDlgItem(hDlg, IDD_PATH), (SHACF_FILESYSTEM | SHACF_URLALL | SHACF_FILESYS_ONLY));
}
BOOL FindOk(LPFINDEXE_PARAMS lpfind)
{
GetDlgItemText(lpfind->hDlg, IDD_PATH, lpfind->lpszPath, MAX_PATH);
// If they entered a directory, then append the EXE name to it
// The dialog is confusing - it asks for the "location". Does that
// mean I should enter the directory or the filename?
// Allow both to work.
if (PathIsDirectory(lpfind->lpszPath))
{
PathAppend(lpfind->lpszPath, lpfind->lpszExe);
}
if (!PathFileExistsAndAttributes(lpfind->lpszPath, NULL))
{
ShellMessageBox(HINST_THISDLL, lpfind->hDlg,
MAKEINTRESOURCE(IDS_STILLNOTFOUND), NULL, MB_ICONHAND | MB_OK, (LPTSTR)lpfind->lpszPath);
return FALSE;
}
// HACKHACK we should use the registry but it's too late now;
// Win95 shipped with this code so it's gonna be in win.ini forever...
WriteProfileString(TEXT("programs"), lpfind->lpszExe, lpfind->lpszPath);
return TRUE;
}
//----------------------------------------------------------------------------
// FindExeDlgProc was mistakenly exported in the original NT SHELL32.DLL when
// it didn't need to be (dlgproc's, like wndproc's don't need to be exported
// in the 32-bit world). In order to maintain loadability of some app
// which might have linked to it, we stub it here. If some app ended up really
// using it, then we'll look into a specific fix for that app.
//
// -BobDay
//
BOOL_PTR WINAPI FindExeDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LONG lParam )
{
return FALSE;
}
BOOL_PTR CALLBACK FindExeDlgProcA(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
LPFINDEXE_PARAMS lpfind = (LPFINDEXE_PARAMS)GetWindowLongPtr(hDlg, DWLP_USER);
switch (wMsg)
{
case WM_INITDIALOG:
InitFindDlg(hDlg, (LPFINDEXE_PARAMS)lParam);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDD_BROWSE:
DoBrowseForFile(lpfind);
break;
case IDOK:
if (!FindOk(lpfind))
break;
// fall through
case IDCANCEL:
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//
// Give a command line, change the exe (leaving the args). For example,
// PathReplaceExe(C:\Old\foo.exe -silent, C:\NewDirectory\foo.exe)
// yields C:\NewDirectory\foo.exe -silent.
//
void PathReplaceExe(LPTSTR lpCommand, UINT cchCommand, LPCTSTR pszExe)
{
LPTSTR lpArgs;
lpArgs = PathGetArgs(lpCommand);
if (*lpArgs)
{
// Must save the original args before copying pszExe because it
// might overwrite lpCommand. I could be clever with hmemcpy and
// avoid allocating memory but this function is called so rarely
// it isn't worth it.
UINT cchArgs = lstrlen(lpArgs);
LPTSTR lpArgsCopy = (LPTSTR)_alloca((cchArgs + 1) * sizeof(TCHAR));
lstrcpy(lpArgsCopy, lpArgs);
lstrcpyn(lpCommand, pszExe, cchCommand);
PathQuoteSpaces(lpCommand);
// lpArgs is no good after this point
lstrcatn(lpCommand, c_szSpace, cchCommand);
lstrcatn(lpCommand, lpArgsCopy, cchCommand);
}
else
{
lstrcpyn(lpCommand, pszExe, cchCommand);
PathQuoteSpaces(lpCommand);
}
}
//
// put up cool ui to find the exe responsible for performing
// a ShellExecute()
// "excel.exe foo.xls" -> "c:\excel\excel.exe foo.xls"
//
// in:
// hwnd to post UI on
// lpCommand command line to try to repair [in/out]
// cchCommand size of lpCommand buffer
// hkeyProgID program ID
//
// out:
// lpCommand change cmd line if we returned -1
//
// returns:
// -1 we found a new location lpCommand, use it
// or other win exec error codes, notably...
// 2 we really didn't find it
// 15 user cancel, fail the exec quietly
//
int FindAssociatedExe(HWND hwnd, LPTSTR lpCommand, UINT cchCommand,
LPCTSTR pszDocument, HKEY hkeyProgID)
{
FINDEXE_PARAMS find;
TCHAR szPath[MAX_PATH];
TCHAR szExe[MAX_PATH];
TCHAR szType[MAX_PATH];
// strip down to just the EXE name
lstrcpyn(szPath, lpCommand, ARRAYSIZE(szPath));
PathRemoveArgs(szPath);
PathUnquoteSpaces(szPath);
// check to see if the file does exist. if it does then
// the original exec must have failed because some
// dependant DLL is missing. so we return file not
// found, even though we really found the file
PathAddExtension(szPath, NULL);
if (PathFileExists(szPath))
return SE_ERR_FNF; // file exists, but some dll must not
// store the file name component
lstrcpyn(szExe, PathFindFileName(szPath), ARRAYSIZE(szExe));
// HACKHACK we should use the registry but it's too late now;
// Win95 shipped with this code so it's gonna be in win.ini forever...
GetProfileString(TEXT("programs"), szExe, szNULL, szPath, ARRAYSIZE(szPath));
if (szPath[0]) {
if (PathFileExists(szPath)) {
PathReplaceExe(lpCommand, cchCommand, szPath); // return the new path
return -1; // this means to try again
}
PathRemoveFileSpec(szPath);
} else {
/* Prompt with the disk that Windows is on */
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
szPath[3] = TEXT('\0');
}
SHGetTypeName(pszDocument, hkeyProgID, FALSE, szType, ARRAYSIZE(szType));
find.lpszExe = szExe; // base file name (to search for)
find.lpszPath = szPath; // starting location for search
find.lpszName = szType; // file type we are looking for
switch (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FINDEXE), hwnd, FindExeDlgProcA, (LPARAM)(LPFINDEXE_PARAMS)&find))
{
case IDOK:
PathReplaceExe(lpCommand, cchCommand, szPath); // return the new path
return -1; // file found and lpCommand fixed up
case IDCANCEL:
return ERROR_INVALID_FUNCTION; // This is the user cancel return
default:
return SE_ERR_FNF; // stick with the file not found
}
}