289 lines
9.1 KiB
C
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
|
||
|
}
|
||
|
}
|