Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
9.1 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "fstreex.h"
  4. typedef struct {
  5. HWND hDlg;
  6. // input output
  7. LPTSTR lpszExe; // base file name (to search for)
  8. LPTSTR lpszPath; // starting location for search
  9. LPCTSTR lpszName; // doc type name "Winword Document"
  10. } FINDEXE_PARAMS, *LPFINDEXE_PARAMS;
  11. int CALLBACK LocateCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  12. {
  13. TCHAR szPath[MAX_PATH + 80];
  14. int id;
  15. LPFINDEXE_PARAMS lpfind = (LPFINDEXE_PARAMS)lpData;
  16. switch(uMsg)
  17. {
  18. case BFFM_SELCHANGED:
  19. SHGetPathFromIDList((LPITEMIDLIST)lParam, szPath);
  20. if ((lstrlen(szPath) + lstrlen(lpfind->lpszExe)) < MAX_PATH)
  21. {
  22. PathAppend(szPath, lpfind->lpszExe);
  23. if (PathFileExistsAndAttributes(szPath, NULL))
  24. {
  25. id = IDS_FILEFOUND;
  26. }
  27. else
  28. {
  29. id = IDS_FILENOTFOUND;
  30. }
  31. }
  32. else
  33. {
  34. id = IDS_FILENOTFOUND;
  35. }
  36. SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, id);
  37. break;
  38. case BFFM_INITIALIZED:
  39. SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, IDS_FILENOTFOUND);
  40. break;
  41. }
  42. return 0;
  43. }
  44. void _GetBrowseTitle(LPFINDEXE_PARAMS lpfind, LPTSTR lpszBuffer, UINT cchBuffer)
  45. {
  46. TCHAR szTemplate[100];
  47. LoadString(HINST_THISDLL, IDS_FINDASSEXEBROWSETITLE, szTemplate, ARRAYSIZE(szTemplate));
  48. wnsprintf(lpszBuffer, cchBuffer, szTemplate, lpfind->lpszExe);
  49. }
  50. void DoBrowseForFile(LPFINDEXE_PARAMS lpfind)
  51. {
  52. TCHAR szFilePath[MAX_PATH] = { 0 }; // buffer for file name
  53. TCHAR szInitialDir[MAX_PATH] = { 0 }; // buffer for file name
  54. // initial directory to Program Files
  55. SHGetSpecialFolderPath(NULL, szInitialDir, CSIDL_PROGRAM_FILES, TRUE);
  56. if (GetFileNameFromBrowse(lpfind->hDlg, szFilePath, ARRAYSIZE(szFilePath), szInitialDir,
  57. MAKEINTRESOURCE(IDS_EXE), MAKEINTRESOURCE(IDS_PROGRAMSFILTER), MAKEINTRESOURCE(IDS_BROWSE)))
  58. {
  59. SetDlgItemText(lpfind->hDlg, IDD_PATH, szFilePath);
  60. lstrcpy((LPTSTR)lpfind->lpszPath, szFilePath);
  61. }
  62. }
  63. void InitFindDlg(HWND hDlg, LPFINDEXE_PARAMS lpfind)
  64. {
  65. TCHAR szPath[MAX_PATH]; /* This must be the same size as lpfind->lpszPath */
  66. TCHAR szBuffer[MAX_PATH + 100];
  67. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)lpfind);
  68. lpfind->hDlg = hDlg;
  69. GetDlgItemText(hDlg, IDD_TEXT1, szPath, ARRAYSIZE(szPath));
  70. wsprintf(szBuffer, szPath, lpfind->lpszExe, lpfind->lpszName);
  71. SetDlgItemText(hDlg, IDD_TEXT1, szBuffer);
  72. GetDlgItemText(hDlg, IDD_TEXT2, szPath, ARRAYSIZE(szPath));
  73. wsprintf(szBuffer, szPath, lpfind->lpszExe);
  74. SetDlgItemText(hDlg, IDD_TEXT2, szBuffer);
  75. SetDlgItemText(hDlg, IDD_PATH, lpfind->lpszPath);
  76. SHAutoComplete(GetDlgItem(hDlg, IDD_PATH), (SHACF_FILESYSTEM | SHACF_URLALL | SHACF_FILESYS_ONLY));
  77. }
  78. BOOL FindOk(LPFINDEXE_PARAMS lpfind)
  79. {
  80. GetDlgItemText(lpfind->hDlg, IDD_PATH, lpfind->lpszPath, MAX_PATH);
  81. // If they entered a directory, then append the EXE name to it
  82. // The dialog is confusing - it asks for the "location". Does that
  83. // mean I should enter the directory or the filename?
  84. // Allow both to work.
  85. if (PathIsDirectory(lpfind->lpszPath))
  86. {
  87. PathAppend(lpfind->lpszPath, lpfind->lpszExe);
  88. }
  89. if (!PathFileExistsAndAttributes(lpfind->lpszPath, NULL))
  90. {
  91. ShellMessageBox(HINST_THISDLL, lpfind->hDlg,
  92. MAKEINTRESOURCE(IDS_STILLNOTFOUND), NULL, MB_ICONHAND | MB_OK, (LPTSTR)lpfind->lpszPath);
  93. return FALSE;
  94. }
  95. // HACKHACK we should use the registry but it's too late now;
  96. // Win95 shipped with this code so it's gonna be in win.ini forever...
  97. WriteProfileString(TEXT("programs"), lpfind->lpszExe, lpfind->lpszPath);
  98. return TRUE;
  99. }
  100. //----------------------------------------------------------------------------
  101. // FindExeDlgProc was mistakenly exported in the original NT SHELL32.DLL when
  102. // it didn't need to be (dlgproc's, like wndproc's don't need to be exported
  103. // in the 32-bit world). In order to maintain loadability of some app
  104. // which might have linked to it, we stub it here. If some app ended up really
  105. // using it, then we'll look into a specific fix for that app.
  106. //
  107. // -BobDay
  108. //
  109. BOOL_PTR WINAPI FindExeDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LONG lParam )
  110. {
  111. return FALSE;
  112. }
  113. BOOL_PTR CALLBACK FindExeDlgProcA(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  114. {
  115. LPFINDEXE_PARAMS lpfind = (LPFINDEXE_PARAMS)GetWindowLongPtr(hDlg, DWLP_USER);
  116. switch (wMsg)
  117. {
  118. case WM_INITDIALOG:
  119. InitFindDlg(hDlg, (LPFINDEXE_PARAMS)lParam);
  120. break;
  121. case WM_COMMAND:
  122. switch (GET_WM_COMMAND_ID(wParam, lParam))
  123. {
  124. case IDD_BROWSE:
  125. DoBrowseForFile(lpfind);
  126. break;
  127. case IDOK:
  128. if (!FindOk(lpfind))
  129. break;
  130. // fall through
  131. case IDCANCEL:
  132. EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  133. break;
  134. }
  135. break;
  136. default:
  137. return FALSE;
  138. }
  139. return TRUE;
  140. }
  141. //
  142. // Give a command line, change the exe (leaving the args). For example,
  143. // PathReplaceExe(C:\Old\foo.exe -silent, C:\NewDirectory\foo.exe)
  144. // yields C:\NewDirectory\foo.exe -silent.
  145. //
  146. void PathReplaceExe(LPTSTR lpCommand, UINT cchCommand, LPCTSTR pszExe)
  147. {
  148. LPTSTR lpArgs;
  149. lpArgs = PathGetArgs(lpCommand);
  150. if (*lpArgs)
  151. {
  152. // Must save the original args before copying pszExe because it
  153. // might overwrite lpCommand. I could be clever with hmemcpy and
  154. // avoid allocating memory but this function is called so rarely
  155. // it isn't worth it.
  156. UINT cchArgs = lstrlen(lpArgs);
  157. LPTSTR lpArgsCopy = (LPTSTR)_alloca((cchArgs + 1) * sizeof(TCHAR));
  158. lstrcpy(lpArgsCopy, lpArgs);
  159. lstrcpyn(lpCommand, pszExe, cchCommand);
  160. PathQuoteSpaces(lpCommand);
  161. // lpArgs is no good after this point
  162. lstrcatn(lpCommand, c_szSpace, cchCommand);
  163. lstrcatn(lpCommand, lpArgsCopy, cchCommand);
  164. }
  165. else
  166. {
  167. lstrcpyn(lpCommand, pszExe, cchCommand);
  168. PathQuoteSpaces(lpCommand);
  169. }
  170. }
  171. //
  172. // put up cool ui to find the exe responsible for performing
  173. // a ShellExecute()
  174. // "excel.exe foo.xls" -> "c:\excel\excel.exe foo.xls"
  175. //
  176. // in:
  177. // hwnd to post UI on
  178. // lpCommand command line to try to repair [in/out]
  179. // cchCommand size of lpCommand buffer
  180. // hkeyProgID program ID
  181. //
  182. // out:
  183. // lpCommand change cmd line if we returned -1
  184. //
  185. // returns:
  186. // -1 we found a new location lpCommand, use it
  187. // or other win exec error codes, notably...
  188. // 2 we really didn't find it
  189. // 15 user cancel, fail the exec quietly
  190. //
  191. int FindAssociatedExe(HWND hwnd, LPTSTR lpCommand, UINT cchCommand,
  192. LPCTSTR pszDocument, HKEY hkeyProgID)
  193. {
  194. FINDEXE_PARAMS find;
  195. TCHAR szPath[MAX_PATH];
  196. TCHAR szExe[MAX_PATH];
  197. TCHAR szType[MAX_PATH];
  198. // strip down to just the EXE name
  199. lstrcpyn(szPath, lpCommand, ARRAYSIZE(szPath));
  200. PathRemoveArgs(szPath);
  201. PathUnquoteSpaces(szPath);
  202. // check to see if the file does exist. if it does then
  203. // the original exec must have failed because some
  204. // dependant DLL is missing. so we return file not
  205. // found, even though we really found the file
  206. PathAddExtension(szPath, NULL);
  207. if (PathFileExists(szPath))
  208. return SE_ERR_FNF; // file exists, but some dll must not
  209. // store the file name component
  210. lstrcpyn(szExe, PathFindFileName(szPath), ARRAYSIZE(szExe));
  211. // HACKHACK we should use the registry but it's too late now;
  212. // Win95 shipped with this code so it's gonna be in win.ini forever...
  213. GetProfileString(TEXT("programs"), szExe, szNULL, szPath, ARRAYSIZE(szPath));
  214. if (szPath[0]) {
  215. if (PathFileExists(szPath)) {
  216. PathReplaceExe(lpCommand, cchCommand, szPath); // return the new path
  217. return -1; // this means to try again
  218. }
  219. PathRemoveFileSpec(szPath);
  220. } else {
  221. /* Prompt with the disk that Windows is on */
  222. GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
  223. szPath[3] = TEXT('\0');
  224. }
  225. SHGetTypeName(pszDocument, hkeyProgID, FALSE, szType, ARRAYSIZE(szType));
  226. find.lpszExe = szExe; // base file name (to search for)
  227. find.lpszPath = szPath; // starting location for search
  228. find.lpszName = szType; // file type we are looking for
  229. switch (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FINDEXE), hwnd, FindExeDlgProcA, (LPARAM)(LPFINDEXE_PARAMS)&find))
  230. {
  231. case IDOK:
  232. PathReplaceExe(lpCommand, cchCommand, szPath); // return the new path
  233. return -1; // file found and lpCommand fixed up
  234. case IDCANCEL:
  235. return ERROR_INVALID_FUNCTION; // This is the user cancel return
  236. default:
  237. return SE_ERR_FNF; // stick with the file not found
  238. }
  239. }