454 lines
13 KiB
C
454 lines
13 KiB
C
#define UNICODE 1
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
const WCHAR szCommdlgHelp[] = L"commdlg_help";
|
|
|
|
UINT wBrowseHelp = WM_USER; /* Set to an unused value */
|
|
|
|
const CHAR szGetOpenFileName[] = "GetOpenFileNameW";
|
|
|
|
/* the defines below should be in windows.h */
|
|
|
|
/* Dialog window class */
|
|
#define WC_DIALOG (MAKEINTATOM(0x8002))
|
|
|
|
/* cbWndExtra bytes needed by dialog manager for dialog classes */
|
|
#define DLGWINDOWEXTRA 30
|
|
|
|
|
|
/* Get/SetWindowWord/Long offsets for use with WC_DIALOG windows */
|
|
#define DWL_MSGRESULT 0
|
|
#define DWL_DLGPROC 4
|
|
#define DWL_USER 8
|
|
|
|
/* For Long File Name support */
|
|
#define MAX_EXTENSION 64
|
|
|
|
typedef struct {
|
|
LPWSTR lpszExe;
|
|
LPWSTR lpszPath;
|
|
LPWSTR lpszName;
|
|
} FINDEXE_PARAMS, FAR *LPFINDEXE_PARAMS;
|
|
|
|
typedef INT (APIENTRY *LPFNGETOPENFILENAME)(LPOPENFILENAME);
|
|
|
|
VOID APIENTRY
|
|
CheckEscapesW(LPWSTR szFile, DWORD cch)
|
|
{
|
|
LPWSTR szT;
|
|
WCHAR *p, *pT;
|
|
|
|
for (p = szFile; *p; p++) {
|
|
|
|
switch (*p) {
|
|
case WCHAR_SPACE:
|
|
case WCHAR_COMMA:
|
|
case WCHAR_SEMICOLON:
|
|
case WCHAR_HAT:
|
|
case WCHAR_QUOTE:
|
|
{
|
|
// this path contains an annoying character
|
|
if (cch < (wcslen(szFile) + 2)) {
|
|
return;
|
|
}
|
|
szT = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
|
|
if (!szT) {
|
|
return;
|
|
}
|
|
wcscpy(szT,szFile);
|
|
p = szFile;
|
|
*p++ = WCHAR_QUOTE;
|
|
for (pT = szT; *pT; ) {
|
|
*p++ = *pT++;
|
|
}
|
|
*p++ = WCHAR_QUOTE;
|
|
*p = WCHAR_NULL;
|
|
LocalFree(szT);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID APIENTRY
|
|
CheckEscapesA(LPSTR lpFileA, DWORD cch)
|
|
{
|
|
if (lpFileA && *lpFileA) {
|
|
LPWSTR lpFileW;
|
|
|
|
lpFileW = (LPWSTR)LocalAlloc(LPTR, (cch * sizeof(WCHAR)));
|
|
if (!lpFileW) {
|
|
return;
|
|
}
|
|
|
|
SHAnsiToUnicode(lpFileA, lpFileW, cch);
|
|
|
|
CheckEscapesW(lpFileW, cch);
|
|
|
|
try {
|
|
SHUnicodeToAnsi(lpFileW, lpFileA, cch);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
LocalFree(lpFileW);
|
|
return;
|
|
}
|
|
|
|
LocalFree(lpFileW);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Hooks into common dialog to allow size of selected files to be displayed.
|
|
BOOL APIENTRY
|
|
LocateHookProc(
|
|
HWND hDlg,
|
|
UINT uiMessage,
|
|
WPARAM wParam,
|
|
LONG lParam)
|
|
{
|
|
WCHAR szTemp[40];
|
|
WORD wID;
|
|
|
|
switch (uiMessage) {
|
|
case WM_INITDIALOG:
|
|
PostMessage(hDlg, WM_COMMAND, ctlLast+1, 0L);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
case ctlLast+1:
|
|
GetDlgItemText(hDlg, edt1, szTemp, ARRAYSIZE(szTemp));
|
|
if (SendDlgItemMessage(hDlg, lst1, LB_FINDSTRING, (WPARAM)-1,
|
|
(LONG_PTR)(LPSTR)szTemp) >= 0) {
|
|
wID = IDS_PROGFOUND;
|
|
} else {
|
|
wID = IDS_PROGNOTFOUND;
|
|
}
|
|
LoadString(HINST_THISDLL, wID, szTemp, ARRAYSIZE(szTemp));
|
|
SetDlgItemText(hDlg, ctlLast+2, szTemp);
|
|
break;
|
|
|
|
case lst2:
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == LBN_DBLCLK)
|
|
PostMessage(hDlg, WM_COMMAND, ctlLast+1, 0L);
|
|
break;
|
|
|
|
case cmb2:
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
|
|
case CBN_SELCHANGE:
|
|
PostMessage(hDlg, WM_COMMAND, ctlLast+1, 1L);
|
|
break;
|
|
|
|
case CBN_CLOSEUP:
|
|
PostMessage(hDlg, WM_COMMAND, GET_WM_COMMAND_MPS(cmb2,
|
|
GetDlgItem(hDlg, cmb2), CBN_SELCHANGE));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
case IDABORT:
|
|
PostMessage(hDlg, WM_COMMAND, ctlLast+1, 0L);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
return(FALSE); // commdlg, do your thing
|
|
}
|
|
|
|
BOOL_PTR APIENTRY
|
|
FindExeDlgProcW(
|
|
HWND hDlg,
|
|
register UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
/* Notice this is OK as a global, because it will be reloaded
|
|
* when needed
|
|
*/
|
|
static HANDLE hCommDlg = NULL;
|
|
|
|
WCHAR szPath[MAX_PATH]; /* This must be the same size as lpfind->lpszPath */
|
|
WCHAR szBuffer[MAX_PATH + 100];
|
|
LPFINDEXE_PARAMS lpfind;
|
|
int temp;
|
|
LPWSTR lpTemp;
|
|
|
|
switch (wMsg) {
|
|
case WM_INITDIALOG:
|
|
wBrowseHelp = RegisterWindowMessage(szCommdlgHelp);
|
|
|
|
lpfind = (LPFINDEXE_PARAMS)lParam;
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpfind);
|
|
|
|
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);
|
|
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if (hCommDlg >= (HANDLE)32) {
|
|
FreeLibrary(hCommDlg);
|
|
hCommDlg = NULL;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
case IDD_BROWSE:
|
|
{
|
|
LPFNGETOPENFILENAME lpfnGetOpenFileName;
|
|
WCHAR szExts[MAX_EXTENSION];
|
|
OPENFILENAME ofn;
|
|
|
|
GetDlgItemText(hDlg, IDD_PATH, szBuffer, ARRAYSIZE(szBuffer));
|
|
|
|
lpfind = (LPFINDEXE_PARAMS)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
wcscpy(szPath, lpfind->lpszExe);
|
|
SheRemoveQuotesW(szPath);
|
|
|
|
/* Make up a file types string
|
|
*/
|
|
// BUG BUG this assumes extensions are of length 3.
|
|
szExts[0] = WCHAR_CAP_A;
|
|
szExts[1] = WCHAR_NULL;
|
|
szExts[2] = WCHAR_STAR;
|
|
szExts[3] = WCHAR_DOT;
|
|
szExts[4] = WCHAR_NULL;
|
|
if (NULL != (lpTemp=StrRChrW(szPath, NULL, WCHAR_DOT)))
|
|
StrCpyN(szExts+3, lpTemp, ((wcslen(lpTemp) < 60) ? wcslen(lpTemp) : 60));
|
|
szExts[3+wcslen(szExts+3)+1] = WCHAR_NULL;
|
|
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.hInstance = HINST_THISDLL;
|
|
ofn.lpstrFilter = L"A\0\?.?\0"; // a dummy filter
|
|
ofn.lpstrCustomFilter = NULL;
|
|
ofn.nMaxCustFilter = 0;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = szPath;
|
|
ofn.nMaxFile = sizeof(szPath);
|
|
ofn.lpstrInitialDir = NULL;
|
|
ofn.lpstrTitle = NULL;
|
|
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST |
|
|
OFN_ENABLETEMPLATE | OFN_SHOWHELP;
|
|
ofn.lCustData = (LONG_PTR) hDlg;
|
|
ofn.lpfnHook = NULL; // AddFileHookProc;
|
|
ofn.lpTemplateName = MAKEINTRESOURCE(DLG_BROWSE);
|
|
ofn.nFileOffset = 0;
|
|
ofn.nFileExtension = 0;
|
|
ofn.lpstrDefExt = NULL;
|
|
ofn.lpstrFileTitle = NULL;
|
|
|
|
if (hCommDlg < (HANDLE)32 &&
|
|
(hCommDlg = LoadLibrary(TEXT("comdlg32.dll"))) < (HANDLE)32) {
|
|
CommDlgError:
|
|
LoadString(HINST_THISDLL, IDS_NOCOMMDLG, szBuffer, ARRAYSIZE(szBuffer));
|
|
GetWindowText(hDlg, szPath, ARRAYSIZE(szPath));
|
|
MessageBox(hDlg, szBuffer, szPath, MB_ICONHAND|MB_OK);
|
|
break;
|
|
}
|
|
if (!(lpfnGetOpenFileName =
|
|
(LPFNGETOPENFILENAME)GetProcAddress((HINSTANCE)hCommDlg,
|
|
(LPSTR)szGetOpenFileName)))
|
|
goto CommDlgError;
|
|
|
|
temp = (*lpfnGetOpenFileName)(&ofn);
|
|
|
|
if (temp) {
|
|
LPWSTR lpTemp;
|
|
|
|
lpTemp = StrRChrW(szPath, NULL, WCHAR_BSLASH);
|
|
*lpTemp = WCHAR_NULL;
|
|
SetDlgItemText(hDlg, IDD_PATH, szPath);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IDOK:
|
|
{
|
|
HANDLE hFile;
|
|
|
|
lpfind = (LPFINDEXE_PARAMS)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
if (lpfind) {
|
|
GetDlgItemText(hDlg, IDD_PATH, lpfind->lpszPath, MAX_PATH);
|
|
|
|
switch (*CharPrev(lpfind->lpszPath,
|
|
lpTemp=lpfind->lpszPath+lstrlen(lpfind->lpszPath))) {
|
|
case WCHAR_BSLASH:
|
|
case WCHAR_COLON:
|
|
break;
|
|
|
|
default:
|
|
*lpTemp++ = WCHAR_BSLASH;
|
|
break;
|
|
}
|
|
|
|
wcscpy(lpTemp, lpfind->lpszExe);
|
|
|
|
hFile = CreateFile(lpfind->lpszPath, GENERIC_EXECUTE, (FILE_SHARE_READ | FILE_SHARE_WRITE),
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
LoadString(HINST_THISDLL, IDS_STILLNOTFOUND, szPath, ARRAYSIZE(szPath));
|
|
wsprintf(szBuffer, szPath, lpfind->lpszPath);
|
|
GetWindowText(hDlg, szPath, ARRAYSIZE(szPath));
|
|
MessageBox(hDlg, szBuffer, szPath, MB_ICONHAND|MB_OK);
|
|
break;
|
|
}
|
|
|
|
WriteProfileString(TEXT("programs"), lpfind->lpszExe,
|
|
lpfind->lpszPath);
|
|
}
|
|
}
|
|
|
|
// fall through
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Returns -1 if we found the file (and it was not in an obvious place)
|
|
// or an error code which will be returned to the app (see the error
|
|
// returns for ShellExecute)
|
|
|
|
HANDLE APIENTRY
|
|
FindAssociatedExeW(
|
|
HWND hwnd,
|
|
LPWSTR lpCommand,
|
|
LPWSTR lpName)
|
|
{
|
|
FINDEXE_PARAMS find;
|
|
WCHAR szPath[MAX_PATH];
|
|
WCHAR szExe[MAX_PATH];
|
|
LPWSTR lpSpace, lpTemp;
|
|
HANDLE hFile = NULL;
|
|
BOOL fQuote = FALSE;
|
|
|
|
|
|
// find the param list
|
|
lpSpace = lpCommand;
|
|
while (*lpSpace)
|
|
{
|
|
if ((*lpSpace == WCHAR_SPACE) && (!fQuote))
|
|
{
|
|
break;
|
|
}
|
|
else if (*lpSpace == WCHAR_QUOTE)
|
|
{
|
|
fQuote = !fQuote;
|
|
}
|
|
lpSpace++;
|
|
}
|
|
|
|
if (*lpSpace == WCHAR_SPACE) {
|
|
*lpSpace = 0;
|
|
wcscpy(szPath, lpCommand);
|
|
*lpSpace = WCHAR_SPACE;
|
|
} else {
|
|
lpSpace = TEXT("");
|
|
wcscpy(szPath, lpCommand);
|
|
}
|
|
SheRemoveQuotesW(szPath);
|
|
|
|
/* Add ".exe" if there is no extension
|
|
* Check if the file can be opened; if it can, then some DLL could not
|
|
* be found during the WinExec, so return file not found
|
|
*/
|
|
if (NULL != (lpTemp=StrRChrW(szPath, NULL, WCHAR_BSLASH))
|
|
|| NULL != (lpTemp=StrRChrW(szPath, NULL, WCHAR_COLON))) {
|
|
++lpTemp;
|
|
} else {
|
|
lpTemp = szPath;
|
|
}
|
|
|
|
hFile = CreateFile(szPath, GENERIC_EXECUTE, (FILE_SHARE_READ | FILE_SHARE_WRITE),
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFile);
|
|
return((HANDLE)2);
|
|
}
|
|
|
|
// store the file name component
|
|
wcscpy(szExe, lpTemp);
|
|
|
|
// make sure there is an extension
|
|
if (!StrChrW(szExe, WCHAR_DOT)) {
|
|
wcscat(szExe, TEXT(".exe"));
|
|
}
|
|
|
|
// add back the quotes, if necessary
|
|
CheckEscapesW(szExe, MAX_PATH);
|
|
|
|
// look in win.ini
|
|
GetProfileString(TEXT("programs"), szExe, TEXT(""), szPath, ARRAYSIZE(szPath));
|
|
|
|
if (szPath[0]) {
|
|
hFile = CreateFile(szPath, GENERIC_EXECUTE, (FILE_SHARE_READ | FILE_SHARE_WRITE),
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
CloseHandle(hFile);
|
|
wcscat(szPath, lpSpace); // add the parameters
|
|
wcscpy(lpCommand, szPath); // return the new path
|
|
return((HANDLE)-1);
|
|
}
|
|
|
|
/* Strip off the file part */
|
|
if (NULL != (lpTemp=StrRChrW(szPath, NULL, WCHAR_BSLASH))) {
|
|
if (*CharPrev(szPath, lpTemp) == WCHAR_COLON) {
|
|
++lpTemp;
|
|
}
|
|
*lpTemp = WCHAR_NULL;
|
|
} else if (NULL != (lpTemp=StrRChrW(szPath, NULL, WCHAR_COLON))) {
|
|
*(lpTemp+1) = WCHAR_NULL;
|
|
}
|
|
} else {
|
|
/* Prompt with the disk that Windows is on */
|
|
GetWindowsDirectory(szPath, ARRAYSIZE(szPath)-1);
|
|
szPath[3] = WCHAR_NULL;
|
|
}
|
|
|
|
find.lpszExe = szExe;
|
|
find.lpszPath = szPath;
|
|
find.lpszName = lpName;
|
|
|
|
switch(DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FINDEXE), hwnd,
|
|
FindExeDlgProcW, (LONG_PTR)(LPFINDEXE_PARAMS)&find)) {
|
|
case IDOK:
|
|
wcscat(szPath, lpSpace); // add the parameters
|
|
wcscpy(lpCommand, szPath); // return the new path
|
|
return ((HANDLE)-1);
|
|
|
|
case IDCANCEL:
|
|
return((HANDLE)15); // This is the user cancel return
|
|
|
|
default:
|
|
return((HANDLE)2); // stick with the file not found
|
|
}
|
|
}
|