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.

547 lines
15 KiB

  1. /* ** This file contains routines required to display a standard open
  2. dialog box. Apps can directly link to object file or modify this
  3. source for slightly different dialog box.
  4. Note - in order to use these routines, the application must
  5. export DlgfnOpen(). Also, an app that uses these routines must
  6. be running ss=ds, since they use near pointers into stack.
  7. */
  8. #include "cal.h"
  9. #define ATTRDIRLIST 0xC010 /* include directories and drives in listbox */
  10. #define ATTRFILELIST 0x0000
  11. #define ID_LISTBOX 10
  12. #define ID_EDIT 11
  13. #define CBEXTMAX 6 /* Number of bytes in "\*.txt" */
  14. CHAR szLastDir[120]; /* Dir where the last open occurred */
  15. /* useful if file is picked up from other than current dir e.g path */
  16. INT idEditSave;
  17. INT idListboxSave;
  18. INT idPathSave;
  19. CHAR * szExtSave;
  20. CHAR * szFileNameSave;
  21. INT *pfpSave;
  22. OFSTRUCT * rgbOpenSave;
  23. INT cbRootNameMax;
  24. #define CCHNG 15
  25. CHAR rgchNg[CCHNG] = {'"', '\\', '/', '[', ']', ':', '|',
  26. '<', '>', '+', '=', ';', ',', ' ', 0};
  27. /*
  28. * Function prototypes
  29. */
  30. VOID cDlgAddCorrectExtension(CHAR *szEdit, WORD fSearching);
  31. /*
  32. * Functions
  33. */
  34. #if 0
  35. /************************* commented out unused code . L.Raman 12/12/90 */
  36. /* int far DlgfnOpen(); */
  37. /* void far cDlgCheckOkEnable(); */
  38. /* BOOL far cDlgCheckFileName();*/
  39. /* ** Display dialog box for opening files. Allow user to interact with
  40. dialogbox, change directories as necessary, and try to open file if user
  41. selects one. Automatically append extension to filename if necessary.
  42. The open dialog box contains an edit field, listbox, static field,
  43. and OK and CANCEL buttons.
  44. This routine correctly parses filenames containing KANJI characters.
  45. Input - hInstance if app module instance handle.
  46. hwndParent is window handle of parent window
  47. idDlgIn is dialog id
  48. idEditIn is id of edit field
  49. idListboxIn is id of listbox
  50. idPathIn is id of static field which gets path name
  51. szExtIn is pointer to zero terminated string containing
  52. default extension to be added to filenames.
  53. cbFileNameMaxIn is number of bytes in edit field buffer.
  54. Output - *pfp gets value of file handle if file is opened.
  55. or -1 if file could not be opened.
  56. *rgbOpenIn is initialized with file info by OpenFile()
  57. *szFileNameIn gets name of selected file (fully qualified)
  58. Any leading blanks are removed from sszFileName.
  59. Trailing blanks are replaced with a 0 terminator.
  60. Returns - -1 if dialogbox() fails (out of memory).
  61. 0 if user presses cancel
  62. 1 if user enters legal filename and presses ok
  63. 2 if user enters illegal file name and presses ok
  64. */
  65. INT APIENTRY cDlgOpen(
  66. HANDLE hInstance,
  67. HWND hwndParent,
  68. INT idDlgIn,
  69. INT idEditIn,
  70. INT idListboxIn,
  71. INT idPathIn,
  72. CHAR *szExtIn,
  73. INT cbFileNameMaxIn,
  74. CHAR *szFileNameIn,
  75. OFSTRUCT * rgbOpenIn,
  76. INT *pfp)
  77. {
  78. BOOL fResult;
  79. idEditSave = idEditIn;
  80. idListboxSave = idListboxIn;
  81. idPathSave = idPathIn;
  82. szExtSave = szExtIn;
  83. /* Limit for bytes in filename is max bytes in filename less
  84. space for extension and 0 terminator. */
  85. cbRootNameMax = cbFileNameMaxIn - CBEXTMAX - 1;
  86. szFileNameSave = szFileNameIn;
  87. rgbOpenSave = rgbOpenIn;
  88. pfpSave = pfp;
  89. fResult = (BOOL)DialogBox(hInstance, MAKEINTRESOURCE(idDlgIn), hwndParent, cDlgfnOpen );
  90. return fResult;
  91. }
  92. /* ** Dialog function for Open File */
  93. INT_PTR CALLBACK cDlgfnOpen(
  94. HWND hwnd,
  95. UINT msg,
  96. WPARAM wParam,
  97. LPARAM lParam)
  98. {
  99. INT item;
  100. CHAR rgch[256];
  101. INT cchFile, cchDir;
  102. CHAR *pchFile;
  103. BOOL fWild;
  104. static BOOL bRO=FALSE;
  105. INT result = 2; /* Assume illegal filename */
  106. INT len, nx;
  107. switch (msg) {
  108. case WM_INITDIALOG:
  109. /* Save the global read-only status. */
  110. bRO=vfOpenFileReadOnly;
  111. /* Set edit field with default search spec */
  112. SetDlgItemText(hwnd, idEditSave, g(szExtSave+1));
  113. SendDlgItemMessage(hwnd, idEditSave, +++EM_SETSEL(use macros)+++, 0, MAKELONG(6,0));
  114. /* Don't let user type more than cbRootNameMax bytes in edit ctl. */
  115. SendDlgItemMessage(hwnd, idEditSave, EM_LIMITTEXT, cbRootNameMax-1, 0L);
  116. /* fill list box with filenames that match spec, and fill static
  117. field with path name */
  118. if (!DlgDirList(hwnd, g(szExtSave+1), IDCN_LISTBOXDIR, idPathSave, ATTRDIRLIST))
  119. EndDialog(hwnd, 0);
  120. if (!DlgDirList(hwnd, g(szExtSave+1), IDCN_LISTBOX, idPathSave, ATTRFILELIST))
  121. EndDialog(hwnd, 0);
  122. break;
  123. case WM_COMMAND:
  124. wParam = GET_WM_COMMAND_ID(wParam, lParam);
  125. #ifdef NEVER
  126. /* The following lines are commented out because they introduce this bug:
  127. When the edit field becomes empty, OK button is not greyed
  128. SANKAR 06-21-89.
  129. */
  130. if (wParam == idEditSave)
  131. wParam = ID_EDIT;
  132. #endif
  133. switch (wParam) {
  134. case IDOK:
  135. LoadIt:
  136. vfOpenFileReadOnly=IsDlgButtonChecked(hwnd, IDCN_READONLY);
  137. if (IsWindowEnabled(GetDlgItem(hwnd, IDOK)))
  138. {
  139. /* Get contents of edit field */
  140. /* Add search spec if it does not contain one. */
  141. len = 7 + GetWindowTextLength (GetDlgItem(hwnd, IDCN_EDIT));
  142. GetDlgItemText(hwnd, idEditSave, gszFileNameSave, len);
  143. lstrcpy(grgch, szFileNameSave);
  144. /* Append appropriate extension to user's entry */
  145. cDlgAddCorrectExtension(rgch, TRUE);
  146. /* Try to open directory. If successful, fill listbox with
  147. contents of new directory. Otherwise, open datafile. */
  148. if (cFSearchSpec(rgch))
  149. {
  150. if (DlgDirList(hwnd, grgch, IDCN_LISTBOXDIR, idPathSave, ATTRDIRLIST))
  151. {
  152. lstrcpy(gszFileNameSave, rgch);
  153. DlgDirList(hwnd, grgch, IDCN_LISTBOX, idPathSave, ATTRFILELIST);
  154. SetDlgItemText(hwnd, idEditSave, gszFileNameSave);
  155. break;
  156. }
  157. }
  158. cDlgAddCorrectExtension(szFileNameSave, FALSE);
  159. /* If no directory list and filename contained search spec,
  160. honk and don't try to open. */
  161. if (cFSearchSpec(szFileNameSave)) {
  162. MessageBeep(0);
  163. break;
  164. }
  165. /* Make filename upper case and if it's a legal dos
  166. name, try to open the file. */
  167. AnsiUpper(gszFileNameSave);
  168. if (cDlgCheckFileName(szFileNameSave)) {
  169. result = 1;
  170. *pfpSave = MOpenFile(gszFileNameSave, (LPOFSTRUCT)rgbOpenSave, OF_PROMPT+OF_CANCEL);
  171. if ((*pfpSave == -1) &&
  172. (((LPOFSTRUCT)rgbOpenSave)->nErrCode == 0))
  173. result = 2;
  174. else { /* successful file open */
  175. strcpy(szLastDir, ((LPOFSTRUCT)rgbOpenSave)->szPathName);
  176. szLastDir[strlen(szLastDir)-strlen(szFileNameSave)] = 0;
  177. }
  178. }
  179. EndDialog(hwnd, result);
  180. }
  181. break;
  182. case IDCANCEL:
  183. /* User pressed cancel. Just take down dialog box. */
  184. vfOpenFileReadOnly=bRO; /* And restore this. */
  185. EndDialog(hwnd, 0);
  186. break;
  187. /* User single clicked or doubled clicked in listbox -
  188. Single click means fill edit box with selection.
  189. Double click means go ahead and open the selection. */
  190. case IDCN_LISTBOX:
  191. case IDCN_LISTBOXDIR:
  192. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  193. /* Single click case */
  194. case 1:
  195. GetDlgItemText(hwnd, idEditSave, grgch, cbRootNameMax+1);
  196. /* Get selection, which may be either a prefix to a new search
  197. path or a filename. DlgDirSelectEx parses selection, and
  198. appends a backslash if selection is a prefix */
  199. if (wParam==IDCN_LISTBOXDIR)
  200. SendDlgItemMessage(hwnd, IDCN_LISTBOX, LB_SETCURSEL, -1, 0L);
  201. else
  202. SendDlgItemMessage(hwnd, IDCN_LISTBOXDIR, LB_SETCURSEL, -1, 0L);
  203. nx=DLGDIRSELECT(hwnd, szFileNameSave, +++nLen+++, wParam);
  204. if (nx)
  205. {
  206. cchDir = lstrlen(gszFileNameSave);
  207. cchFile = lstrlen(grgch);
  208. pchFile = rgch+cchFile;
  209. /* Now see if there are any wild characters (* or ?) in
  210. edit field. If so, append to prefix. If edit field
  211. contains no wild cards append default search spec
  212. which is "*.TXT" for notepad. */
  213. fWild = (*pchFile == '*' || *pchFile == ':');
  214. while (pchFile > rgch) {
  215. pchFile = (CHAR *)LOWORD((LONG)AnsiPrev(g(rgch), pchFile));
  216. if (*pchFile == '*' || *pchFile == '?')
  217. fWild = TRUE;
  218. if (*pchFile == '\\' || *pchFile == ':') {
  219. pchFile = (CHAR *)LOWORD((LONG)AnsiNext(gpchFile));
  220. break;
  221. }
  222. }
  223. if (fWild)
  224. lstrcpy(gszFileNameSave + cchDir, pchFile);
  225. else
  226. lstrcpy(gszFileNameSave + cchDir, (szExtSave+1));
  227. }
  228. /* Set edit field to entire file/path name. */
  229. SetDlgItemText(hwnd, idEditSave, gszFileNameSave);
  230. break;
  231. /* Double click case - first click has already been processed
  232. as single click */
  233. case 2:
  234. /* Basically the same as ok. If new selection is directory,
  235. open it and list it. Otherwise, open file. */
  236. #if NEVER
  237. /* None of this code is necessary. A double click is more than basically the
  238. same as pressing OK, it is EXACTLY the same as pressing OK. No point in
  239. duplicating all this code, especially since it will bring up 2 consecutive
  240. System-Modal Dialogs if the path investigated references drive A with the
  241. door open. Clark Cyr, 14 August 1989 */
  242. DlgDirList(hwnd, szFileNameSave, IDCN_LISTBOX, idPathSave,ATTRFILELIST);
  243. if (DlgDirList (hwnd, szFileNameSave, IDCN_LISTBOXDIR,IDCN_PATH, ATTRDIRLIST))
  244. {
  245. SetDlgItemText(hwnd, idEditSave, gszFileNameSave);
  246. break;
  247. }
  248. #endif
  249. goto LoadIt; /* go load it up */
  250. }
  251. break;
  252. case IDCN_EDIT:
  253. cDlgCheckOkEnable(hwnd, idEditSave, GET_WM_COMMAND_ID(wParam, lParam));
  254. break;
  255. default:
  256. return(FALSE);
  257. }
  258. default:
  259. return FALSE;
  260. }
  261. return(TRUE);
  262. }
  263. /* ** Enable ok button in a dialog box if and only if edit item
  264. contains text. Edit item must have id of idEditSave */
  265. VOID APIENTRY cDlgCheckOkEnable(
  266. HWND hwnd,
  267. INT idEdit,
  268. WORD message)
  269. {
  270. if (message == EN_CHANGE) {
  271. EnableWindow(GetDlgItem(hwnd, IDOK), (SendMessage(GetDlgItem(hwnd, idEdit), WM_GETTEXTLENGTH, 0, 0L)));
  272. }
  273. }
  274. /* ** Given filename or partial filename or search spec or partial
  275. search spec, add appropriate extension. */
  276. VOID cDlgAddCorrectExtension(CHAR *szEdit, WORD fSearching)
  277. {
  278. register CHAR *pchLast;
  279. register CHAR *pchT;
  280. INT ichExt;
  281. BOOL fDone = FALSE;
  282. INT cchEdit;
  283. pchT = pchLast = (CHAR *)LOWORD((LONG)AnsiPrev(gszEdit, (szEdit + (cchEdit = lstrlen(szEdit)))));
  284. if ((*pchLast == '.' && *(AnsiPrev(gszEdit, pchLast)) == '.') && cchEdit == 2)
  285. ichExt = 0;
  286. else if (*pchLast == '\\' || *pchLast == ':')
  287. ichExt = 1;
  288. else {
  289. ichExt = fSearching ? 0 : 2;
  290. for (; pchT > szEdit; pchT = (CHAR *)LOWORD((LONG)AnsiPrev(gszEdit, pchT))) {
  291. /* If we're not searching and we encounter a period, don't add
  292. any extension. If we are searching, period is assumed to be
  293. part of directory name, so go ahead and add extension. However,
  294. if we are searching and find a search spec, do not add any
  295. extension. */
  296. if (fSearching) {
  297. if (*pchT == '*' || *pchT == '?')
  298. return;
  299. } else if (*pchT == '.'){
  300. return;
  301. }
  302. /* Quit when we get to beginning of last node. */
  303. if (*pchT == '\\')
  304. break;
  305. }
  306. /* Special case hack fix since AnsiPrev can not return value less than
  307. szEdit. If first char is wild card, return without appending. */
  308. if (fSearching && (*pchT == '*' || *pchT == '?'))
  309. return;
  310. }
  311. #ifdef DBCS
  312. lstrcpy(gAnsiNext(pchLast), (szExtSave+ichExt));
  313. #else
  314. lstrcpy(g(pchLast+1), (szExtSave+ichExt));
  315. #endif
  316. }
  317. /* ** Check for legal filename. Strip leading blanks and
  318. 0 terminate */
  319. BOOL APIENTRY cDlgCheckFilename(register CHAR *pch)
  320. {
  321. #ifndef CRISPY
  322. OFSTRUCT ofT;
  323. return (MOpenFile(gpch, (LPOFSTRUCT)&ofT, OF_PARSE) == 0);
  324. }
  325. #else
  326. INT cchFN;
  327. register INT cchT;
  328. CHAR *pchIn;
  329. CHAR *pchFirst;
  330. CHAR *pchSave;
  331. INT s;
  332. BOOL fBackSlash;
  333. s = 0;
  334. fBackSlash = FALSE;
  335. pchIn = pch;
  336. for (;; pch = AnsiNext(gpch)) {
  337. switch (s) {
  338. /* Trim leading blanks */
  339. case 0:
  340. if (*pch == ' ')
  341. break;
  342. if (*pch == '\\') {
  343. pchFirst = pch;
  344. cchT = 0;
  345. s = 2;
  346. } else if (*pch == 0 || !cIsChLegal(*pch)) {
  347. return FALSE;
  348. } else {
  349. pchFirst = pch;
  350. cchT = 1;
  351. if (*pch == '.')
  352. s = 5;
  353. else
  354. s = 1;
  355. }
  356. break;
  357. /* Volume, drive, subdirectory node or filename */
  358. case 1:
  359. if (*pch == ':' && cchT == 1) {
  360. if (*(pch-1) < 'A' || *(pch-1) > 'Z')
  361. return FALSE;
  362. s = 2;
  363. cchT--;
  364. } else if (*pch == '\\') {
  365. if (*(pch+1) == '\\')
  366. return FALSE;
  367. cchT = 0;
  368. } else if (*pch == '.') {
  369. cchT = 0;
  370. s = 3;
  371. } else if (!cIsChLegal(*pch))
  372. return FALSE;
  373. else if (*pch == 0)
  374. goto RetGood;
  375. else if (cchT++) {
  376. s++;
  377. }
  378. break;
  379. /* sub directory node or filename */
  380. case 2:
  381. if (*pch == '\\') {
  382. if (*(pch+1) == '\\')
  383. return FALSE;
  384. fBackSlash = TRUE;
  385. cchT = 0;
  386. } else if (*pch == '.') {
  387. if (*pch+1 == '.') {
  388. if (fBackSlash || cchT)
  389. return FALSE;
  390. s = 5;
  391. cchT = 1;
  392. } else {
  393. s++;
  394. cchT = 0;
  395. }
  396. } else if (*pch == 0)
  397. goto RetGood;
  398. else if (cchT++ > 7 || *pch == ' ' || !IsChLegal(*pch))
  399. return FALSE;
  400. break;
  401. /* up to three characters in extension */
  402. case 3:
  403. if (*pch == 0) {
  404. goto RetGood;
  405. }
  406. if (cchT++ > 2 || *pch == '.' || !IsChLegal(*pch))
  407. return FALSE;
  408. if (*pch == ' ') {
  409. pchSave = pch;
  410. s++;
  411. }
  412. break;
  413. /* Trim trailing blanks */
  414. case 4:
  415. if (*pch == 0) {
  416. *pchSave = 0;
  417. goto RetGood;
  418. } else if (*pch != ' ')
  419. return FALSE;
  420. break;
  421. /* check for ..\ */
  422. case 5:
  423. if (*pch++ != '.' || *pch != '\\')
  424. return FALSE;
  425. cchT = 0;
  426. fBackSlash = TRUE;
  427. s = 2;
  428. break;
  429. }
  430. }
  431. RetGood:
  432. if (pchFirst != pchIn)
  433. lstrcpy(gpchIn, pchFirst);
  434. return TRUE;
  435. }
  436. /* ** Check for legal MS-DOS filename characters.
  437. return TRUE if legal, FALSE otherwise. */
  438. BOOL APIENTRY cIsChLegal(INT ch)
  439. {
  440. register CHAR *pch = rgchNg;
  441. register INT ich = 0;
  442. if (ch < ' ')
  443. return FALSE;
  444. rgchNg[CCHNG-1] = ch;
  445. #ifdef DBCS
  446. while (ch != *pch){
  447. if( IsDBCSLeadByte( *pch ) )
  448. ich++;
  449. ich++;
  450. pch = AnsiNext(pch);
  451. }
  452. #else
  453. while (ch != *pch++)
  454. ich++;
  455. #endif
  456. return (ich == CCHNG-1);
  457. }
  458. #endif
  459. /* ** return TRUE iff 0 terminated string contains a '*' or '\' */
  460. BOOL APIENTRY cFSearchSpec(register CHAR *sz)
  461. {
  462. #ifdef DBCS
  463. for (; *sz;sz=AnsiNext(sz)){
  464. if (*sz == '*' || *sz == '?')
  465. return TRUE;
  466. }
  467. #else
  468. for (; *sz;sz++) {
  469. if (*sz == '*' || *sz == '?')
  470. return TRUE;
  471. }
  472. #endif
  473. return FALSE;
  474. }
  475. #endif