[SHELL32]
[reactos.git] / dll / win32 / comdlg32 / filedlg31.c
1 /*
2 * Win 3.1 Style File Dialogs
3 *
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Albrecht Kleine
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "cdlg.h"
23
24 #define BUFFILE 512
25 #define BUFFILEALLOC 512 * sizeof(WCHAR)
26
27 static const WCHAR FILE_star[] = {'*','.','*', 0};
28 static const WCHAR FILE_bslash[] = {'\\', 0};
29 static const WCHAR FILE_specc[] = {'%','c',':', 0};
30 static const int fldrHeight = 16;
31 static const int fldrWidth = 20;
32
33 static HICON hFolder = 0;
34 static HICON hFolder2 = 0;
35 static HICON hFloppy = 0;
36 static HICON hHDisk = 0;
37 static HICON hCDRom = 0;
38 static HICON hNet = 0;
39
40 #define FD31_OFN_PROP "FILEDLG_OFN"
41
42 typedef struct tagFD31_DATA
43 {
44 HWND hwnd; /* file dialog window handle */
45 BOOL hook; /* TRUE if the dialog is hooked */
46 UINT lbselchstring; /* registered message id */
47 UINT fileokstring; /* registered message id */
48 LPARAM lParam; /* save original lparam */
49 LPCVOID template; /* template for 32 bits resource */
50 BOOL open; /* TRUE if open dialog, FALSE if save dialog */
51 LPOPENFILENAMEW ofnW; /* pointer either to the original structure or
52 a W copy for A/16 API */
53 LPOPENFILENAMEA ofnA; /* original structure if 32bits ansi dialog */
54 } FD31_DATA, *PFD31_DATA;
55
56 /***********************************************************************
57 * FD31_Init [internal]
58 */
59 static BOOL FD31_Init(void)
60 {
61 static BOOL initialized = FALSE;
62
63 if (!initialized) {
64 hFolder = LoadImageA( COMDLG32_hInstance, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED );
65 hFolder2 = LoadImageA( COMDLG32_hInstance, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED );
66 hFloppy = LoadImageA( COMDLG32_hInstance, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED );
67 hHDisk = LoadImageA( COMDLG32_hInstance, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED );
68 hCDRom = LoadImageA( COMDLG32_hInstance, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED );
69 hNet = LoadImageA( COMDLG32_hInstance, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED );
70 if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 ||
71 hHDisk == 0 || hCDRom == 0 || hNet == 0)
72 {
73 ERR("Error loading icons!\n");
74 return FALSE;
75 }
76 initialized = TRUE;
77 }
78 return TRUE;
79 }
80
81 /***********************************************************************
82 * FD31_StripEditControl [internal]
83 * Strip pathnames off the contents of the edit control.
84 */
85 static void FD31_StripEditControl(HWND hwnd)
86 {
87 WCHAR temp[BUFFILE], *cp;
88
89 GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR));
90 cp = strrchrW(temp, '\\');
91 if (cp != NULL) {
92 strcpyW(temp, cp+1);
93 }
94 cp = strrchrW(temp, ':');
95 if (cp != NULL) {
96 strcpyW(temp, cp+1);
97 }
98 /* FIXME: shouldn't we do something with the result here? ;-) */
99 }
100
101 /***********************************************************************
102 * FD31_CallWindowProc [internal]
103 *
104 * Call the appropriate hook
105 */
106 static BOOL FD31_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam, LPARAM lParam)
107 {
108 BOOL ret;
109
110 if (lfs->ofnA)
111 {
112 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
113 lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
114 ret = lfs->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
115 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
116 lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
117 return ret;
118 }
119
120 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
121 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
122 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
123 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
124 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
125 return ret;
126 }
127
128 /***********************************************************************
129 * FD31_GetFileType [internal]
130 */
131 static LPCWSTR FD31_GetFileType(LPCWSTR cfptr, LPCWSTR fptr, const WORD index)
132 {
133 int n, i;
134 i = 0;
135 if (cfptr)
136 for ( ;(n = lstrlenW(cfptr)) != 0; i++)
137 {
138 cfptr += n + 1;
139 if (i == index)
140 return cfptr;
141 cfptr += lstrlenW(cfptr) + 1;
142 }
143 if (fptr)
144 for ( ;(n = lstrlenW(fptr)) != 0; i++)
145 {
146 fptr += n + 1;
147 if (i == index)
148 return fptr;
149 fptr += lstrlenW(fptr) + 1;
150 }
151 return FILE_star; /* FIXME */
152 }
153
154 /***********************************************************************
155 * FD31_ScanDir [internal]
156 */
157 static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
158 {
159 WCHAR buffer[BUFFILE];
160 HWND hdlg;
161 LRESULT lRet = TRUE;
162 HCURSOR hCursorWait, oldCursor;
163
164 TRACE("Trying to change to %s\n", debugstr_w(newPath));
165 if ( newPath[0] && !SetCurrentDirectoryW( newPath ))
166 return FALSE;
167
168 /* get the list of spec files */
169 lstrcpynW(buffer, FD31_GetFileType(ofn->lpstrCustomFilter,
170 ofn->lpstrFilter, ofn->nFilterIndex - 1), BUFFILE);
171
172 hCursorWait = LoadCursorA(0, (LPSTR)IDC_WAIT);
173 oldCursor = SetCursor(hCursorWait);
174
175 /* list of files */
176 if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) {
177 WCHAR* scptr; /* ptr on semi-colon */
178 WCHAR* filter = buffer;
179
180 TRACE("Using filter %s\n", debugstr_w(filter));
181 SendMessageW(hdlg, LB_RESETCONTENT, 0, 0);
182 while (filter) {
183 scptr = strchrW(filter, ';');
184 if (scptr) *scptr = 0;
185 while (*filter == ' ') filter++;
186 TRACE("Using file spec %s\n", debugstr_w(filter));
187 SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter);
188 if (scptr) *scptr = ';';
189 filter = (scptr) ? (scptr + 1) : 0;
190 }
191 }
192
193 /* list of directories */
194 strcpyW(buffer, FILE_star);
195
196 if (GetDlgItem(hWnd, lst2) != 0) {
197 lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY);
198 }
199 SetCursor(oldCursor);
200 return lRet;
201 }
202
203 /***********************************************************************
204 * FD31_WMDrawItem [internal]
205 */
206 static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
207 int savedlg, const DRAWITEMSTRUCT *lpdis)
208 {
209 WCHAR *str;
210 HICON hIcon;
211 COLORREF oldText = 0, oldBk = 0;
212
213 if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1)
214 {
215 if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE;
216 SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
217 (LPARAM)str);
218
219 if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
220 {
221 oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
222 oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
223 }
224 if (savedlg)
225 SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) );
226
227 ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1,
228 lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
229 &(lpdis->rcItem), str, lstrlenW(str), NULL);
230
231 if (lpdis->itemState & ODS_SELECTED)
232 DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
233
234 if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
235 {
236 SetBkColor( lpdis->hDC, oldBk );
237 SetTextColor( lpdis->hDC, oldText );
238 }
239 HeapFree(GetProcessHeap(), 0, str);
240 return TRUE;
241 }
242
243 if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2)
244 {
245 if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
246 return FALSE;
247 SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
248 (LPARAM)str);
249
250 if (lpdis->itemState & ODS_SELECTED)
251 {
252 oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
253 oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
254 }
255 ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
256 lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
257 &(lpdis->rcItem), str, lstrlenW(str), NULL);
258
259 if (lpdis->itemState & ODS_SELECTED)
260 DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
261
262 if (lpdis->itemState & ODS_SELECTED)
263 {
264 SetBkColor( lpdis->hDC, oldBk );
265 SetTextColor( lpdis->hDC, oldText );
266 }
267 DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder, 16, 16, 0, 0, DI_NORMAL );
268 HeapFree(GetProcessHeap(), 0, str);
269 return TRUE;
270 }
271 if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2)
272 {
273 char root[] = "a:";
274 if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
275 return FALSE;
276 SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID,
277 (LPARAM)str);
278 root[0] += str[2] - 'a';
279 switch(GetDriveTypeA(root))
280 {
281 case DRIVE_REMOVABLE: hIcon = hFloppy; break;
282 case DRIVE_CDROM: hIcon = hCDRom; break;
283 case DRIVE_REMOTE: hIcon = hNet; break;
284 case DRIVE_FIXED:
285 default: hIcon = hHDisk; break;
286 }
287 if (lpdis->itemState & ODS_SELECTED)
288 {
289 oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
290 oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
291 }
292 ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
293 lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
294 &(lpdis->rcItem), str, lstrlenW(str), NULL);
295
296 if (lpdis->itemState & ODS_SELECTED)
297 {
298 SetBkColor( lpdis->hDC, oldBk );
299 SetTextColor( lpdis->hDC, oldText );
300 }
301 DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon, 16, 16, 0, 0, DI_NORMAL );
302 HeapFree(GetProcessHeap(), 0, str);
303 return TRUE;
304 }
305 return FALSE;
306 }
307
308 /***********************************************************************
309 * FD31_UpdateResult [internal]
310 * update the displayed file name (with path)
311 */
312 static void FD31_UpdateResult(const FD31_DATA *lfs, const WCHAR *tmpstr)
313 {
314 int lenstr2;
315 LPOPENFILENAMEW ofnW = lfs->ofnW;
316 LPOPENFILENAMEA ofnA = lfs->ofnA;
317 WCHAR tmpstr2[BUFFILE];
318 WCHAR *p;
319
320 TRACE("%s\n", debugstr_w(tmpstr));
321 if(ofnW->Flags & OFN_NOVALIDATE)
322 tmpstr2[0] = '\0';
323 else
324 GetCurrentDirectoryW(BUFFILE, tmpstr2);
325 lenstr2 = strlenW(tmpstr2);
326 if (lenstr2 > 3)
327 tmpstr2[lenstr2++]='\\';
328 lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2);
329 if (!ofnW->lpstrFile)
330 return;
331
332 lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile);
333
334 /* set filename offset */
335 p = PathFindFileNameW(ofnW->lpstrFile);
336 ofnW->nFileOffset = (p - ofnW->lpstrFile);
337
338 /* set extension offset */
339 p = PathFindExtensionW(ofnW->lpstrFile);
340 ofnW->nFileExtension = (*p) ? (p - ofnW->lpstrFile) + 1 : 0;
341
342 TRACE("file %s, file offset %d, ext offset %d\n",
343 debugstr_w(ofnW->lpstrFile), ofnW->nFileOffset, ofnW->nFileExtension);
344
345 /* update the real client structures if any */
346 if (ofnA)
347 {
348 LPSTR lpszTemp;
349 if (ofnW->nMaxFile &&
350 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
351 ofnA->lpstrFile, ofnA->nMaxFile, NULL, NULL ))
352 ofnA->lpstrFile[ofnA->nMaxFile-1] = 0;
353
354 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
355 /* set filename offset */
356 lpszTemp = PathFindFileNameA(ofnA->lpstrFile);
357 ofnA->nFileOffset = (lpszTemp - ofnA->lpstrFile);
358
359 /* set extension offset */
360 lpszTemp = PathFindExtensionA(ofnA->lpstrFile);
361 ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - ofnA->lpstrFile) + 1 : 0;
362 }
363 }
364
365 /***********************************************************************
366 * FD31_UpdateFileTitle [internal]
367 * update the displayed file name (without path)
368 */
369 static void FD31_UpdateFileTitle(const FD31_DATA *lfs)
370 {
371 LONG lRet;
372 LPOPENFILENAMEW ofnW = lfs->ofnW;
373 LPOPENFILENAMEA ofnA = lfs->ofnA;
374
375 if (ofnW->lpstrFileTitle != NULL)
376 {
377 lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
378 SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet,
379 (LPARAM)ofnW->lpstrFileTitle );
380 if (ofnA)
381 {
382 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
383 ofnA->lpstrFileTitle, ofnA->nMaxFileTitle, NULL, NULL ))
384 ofnA->lpstrFileTitle[ofnA->nMaxFileTitle-1] = 0;
385 }
386 }
387 }
388
389 /***********************************************************************
390 * FD31_DirListDblClick [internal]
391 */
392 static LRESULT FD31_DirListDblClick( const FD31_DATA *lfs )
393 {
394 LONG lRet;
395 HWND hWnd = lfs->hwnd;
396 LPWSTR pstr;
397 WCHAR tmpstr[BUFFILE];
398
399 /* get the raw string (with brackets) */
400 lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
401 if (lRet == LB_ERR) return TRUE;
402 pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
403 SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
404 (LPARAM)pstr);
405 strcpyW( tmpstr, pstr );
406 HeapFree(GetProcessHeap(), 0, pstr);
407 /* get the selected directory in tmpstr */
408 if (tmpstr[0] == '[')
409 {
410 tmpstr[lstrlenW(tmpstr) - 1] = 0;
411 strcpyW(tmpstr,tmpstr+1);
412 }
413 strcatW(tmpstr, FILE_bslash);
414
415 FD31_ScanDir(lfs->ofnW, hWnd, tmpstr);
416 /* notify the app */
417 if (lfs->hook)
418 {
419 if (FD31_CallWindowProc(lfs, lfs->lbselchstring, lst2,
420 MAKELONG(lRet,CD_LBSELCHANGE)))
421 return TRUE;
422 }
423 return TRUE;
424 }
425
426 /***********************************************************************
427 * FD31_FileListSelect [internal]
428 * called when a new item is picked in the file list
429 */
430 static LRESULT FD31_FileListSelect( const FD31_DATA *lfs )
431 {
432 LONG lRet;
433 HWND hWnd = lfs->hwnd;
434 LPWSTR pstr;
435
436 lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
437 if (lRet == LB_ERR)
438 return TRUE;
439
440 /* set the edit control to the chosen file */
441 if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
442 {
443 SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
444 (LPARAM)pstr);
445 SetDlgItemTextW( hWnd, edt1, pstr );
446 HeapFree(GetProcessHeap(), 0, pstr);
447 }
448 if (lfs->hook)
449 {
450 FD31_CallWindowProc(lfs, lfs->lbselchstring, lst1,
451 MAKELONG(lRet,CD_LBSELCHANGE));
452 }
453 /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD,
454 CD_LBSELNOITEMS */
455 return TRUE;
456 }
457
458 /***********************************************************************
459 * FD31_TestPath [internal]
460 * before accepting the file name, test if it includes wild cards
461 * tries to scan the directory and returns TRUE if no error.
462 */
463 static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
464 {
465 HWND hWnd = lfs->hwnd;
466 LPWSTR pBeginFileName, pstr2;
467 WCHAR tmpstr2[BUFFILE];
468
469 pBeginFileName = strrchrW(path, '\\');
470 if (pBeginFileName == NULL)
471 pBeginFileName = strrchrW(path, ':');
472
473 if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL)
474 {
475 /* edit control contains wildcards */
476 if (pBeginFileName != NULL)
477 {
478 lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE);
479 *(pBeginFileName + 1) = 0;
480 }
481 else
482 {
483 strcpyW(tmpstr2, path);
484 if(!(lfs->ofnW->Flags & OFN_NOVALIDATE))
485 *path = 0;
486 }
487
488 TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
489 SetDlgItemTextW( hWnd, edt1, tmpstr2 );
490 FD31_ScanDir(lfs->ofnW, hWnd, path);
491 return (lfs->ofnW->Flags & OFN_NOVALIDATE) != 0;
492 }
493
494 /* no wildcards, we might have a directory or a filename */
495 /* try appending a wildcard and reading the directory */
496
497 pstr2 = path + lstrlenW(path);
498 if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
499 strcatW(path, FILE_bslash);
500
501 /* if ScanDir succeeds, we have changed the directory */
502 if (FD31_ScanDir(lfs->ofnW, hWnd, path))
503 return FALSE; /* and path is not a valid file name */
504
505 /* if not, this must be a filename */
506
507 *pstr2 = 0; /* remove the wildcard added before */
508
509 if (pBeginFileName != NULL)
510 {
511 /* strip off the pathname */
512 *pBeginFileName = 0;
513 SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 );
514
515 lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) );
516 /* Should we MessageBox() if this fails? */
517 if (!FD31_ScanDir(lfs->ofnW, hWnd, path))
518 {
519 return FALSE;
520 }
521 strcpyW(path, tmpstr2);
522 }
523 else
524 SetDlgItemTextW( hWnd, edt1, path );
525 return TRUE;
526 }
527
528 /***********************************************************************
529 * FD31_Validate [internal]
530 * called on: click Ok button, Enter in edit, DoubleClick in file list
531 */
532 static LRESULT FD31_Validate( const FD31_DATA *lfs, LPCWSTR path, UINT control, INT itemIndex,
533 BOOL internalUse )
534 {
535 LONG lRet;
536 HWND hWnd = lfs->hwnd;
537 OPENFILENAMEW ofnsav;
538 LPOPENFILENAMEW ofnW = lfs->ofnW;
539 WCHAR filename[BUFFILE];
540 int copied_size = min( ofnW->lStructSize, sizeof(ofnsav) );
541
542 memcpy( &ofnsav, ofnW, copied_size ); /* for later restoring */
543
544 /* get current file name */
545 if (path)
546 lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR));
547 else
548 GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR));
549
550 TRACE("got filename = %s\n", debugstr_w(filename));
551 /* if we did not click in file list to get there */
552 if (control != lst1)
553 {
554 if (!FD31_TestPath( lfs, filename) )
555 return FALSE;
556 }
557 FD31_UpdateResult(lfs, filename);
558
559 if (internalUse)
560 { /* called internally after a change in a combo */
561 if (lfs->hook)
562 {
563 FD31_CallWindowProc(lfs, lfs->lbselchstring, control,
564 MAKELONG(itemIndex,CD_LBSELCHANGE));
565 }
566 return TRUE;
567 }
568
569 FD31_UpdateFileTitle(lfs);
570 if (lfs->hook)
571 {
572 lRet = FD31_CallWindowProc(lfs, lfs->fileokstring,
573 0, lfs->lParam );
574 if (lRet)
575 {
576 memcpy( ofnW, &ofnsav, copied_size ); /* restore old state */
577 return FALSE;
578 }
579 }
580 if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER))
581 {
582 if (ofnW->lpstrFile)
583 {
584 LPWSTR str = ofnW->lpstrFile;
585 LPWSTR ptr = strrchrW(str, '\\');
586 str[lstrlenW(str) + 1] = '\0';
587 *ptr = 0;
588 }
589 }
590 return TRUE;
591 }
592
593 /***********************************************************************
594 * FD31_DiskChange [internal]
595 * called when a new item is picked in the disk selection combo
596 */
597 static LRESULT FD31_DiskChange( const FD31_DATA *lfs )
598 {
599 LONG lRet;
600 HWND hWnd = lfs->hwnd;
601 LPWSTR pstr;
602 WCHAR diskname[BUFFILE];
603
604 FD31_StripEditControl(hWnd);
605 lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L);
606 if (lRet == LB_ERR)
607 return 0;
608 pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
609 SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
610 (LPARAM)pstr);
611 wsprintfW(diskname, FILE_specc, pstr[2]);
612 HeapFree(GetProcessHeap(), 0, pstr);
613
614 return FD31_Validate( lfs, diskname, cmb2, lRet, TRUE );
615 }
616
617 /***********************************************************************
618 * FD31_FileTypeChange [internal]
619 * called when a new item is picked in the file type combo
620 */
621 static LRESULT FD31_FileTypeChange( const FD31_DATA *lfs )
622 {
623 LONG lRet;
624 LPWSTR pstr;
625
626 lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0);
627 if (lRet == LB_ERR)
628 return TRUE;
629 lfs->ofnW->nFilterIndex = lRet + 1;
630 if (lfs->ofnA)
631 lfs->ofnA->nFilterIndex = lRet + 1;
632 pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0);
633 TRACE("Selected filter : %s\n", debugstr_w(pstr));
634
635 return FD31_Validate( lfs, pstr, cmb1, lRet, TRUE );
636 }
637
638 /***********************************************************************
639 * FD31_WMCommand [internal]
640 */
641 static LRESULT FD31_WMCommand( HWND hWnd, LPARAM lParam, UINT notification,
642 UINT control, const FD31_DATA *lfs )
643 {
644 switch (control)
645 {
646 case lst1: /* file list */
647 FD31_StripEditControl(hWnd);
648 if (notification == LBN_DBLCLK)
649 {
650 return SendMessageW(hWnd, WM_COMMAND, IDOK, 0);
651 }
652 else if (notification == LBN_SELCHANGE)
653 return FD31_FileListSelect( lfs );
654 break;
655
656 case lst2: /* directory list */
657 FD31_StripEditControl(hWnd);
658 if (notification == LBN_DBLCLK)
659 return FD31_DirListDblClick( lfs );
660 break;
661
662 case cmb1: /* file type drop list */
663 if (notification == CBN_SELCHANGE)
664 return FD31_FileTypeChange( lfs );
665 break;
666
667 case chx1:
668 break;
669
670 case pshHelp:
671 break;
672
673 case cmb2: /* disk dropdown combo */
674 if (notification == CBN_SELCHANGE)
675 return FD31_DiskChange( lfs );
676 break;
677
678 case IDOK:
679 TRACE("OK pressed\n");
680 if (FD31_Validate( lfs, NULL, control, 0, FALSE ))
681 EndDialog(hWnd, TRUE);
682 return TRUE;
683
684 case IDCANCEL:
685 EndDialog(hWnd, FALSE);
686 return TRUE;
687
688 case IDABORT: /* can be sent by the hook procedure */
689 EndDialog(hWnd, TRUE);
690 return TRUE;
691 }
692 return FALSE;
693 }
694
695 /************************************************************************
696 * FD31_MapStringPairsToW [internal]
697 * map string pairs to Unicode
698 */
699 static LPWSTR FD31_MapStringPairsToW(LPCSTR strA, UINT size)
700 {
701 LPCSTR s;
702 LPWSTR x;
703 unsigned int n, len;
704
705 s = strA;
706 while (*s)
707 s = s+strlen(s)+1;
708 s++;
709 n = s + 1 - strA; /* Don't forget the other \0 */
710 if (n < size) n = size;
711
712 len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 );
713 x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR));
714 MultiByteToWideChar( CP_ACP, 0, strA, n, x, len );
715 return x;
716 }
717
718
719 /************************************************************************
720 * FD31_DupToW [internal]
721 * duplicates an Ansi string to unicode, with a buffer size
722 */
723 static LPWSTR FD31_DupToW(LPCSTR str, DWORD size)
724 {
725 LPWSTR strW = NULL;
726 if (str && (size > 0))
727 {
728 strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
729 if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size );
730 }
731 return strW;
732 }
733
734 /************************************************************************
735 * FD31_MapOfnStructA [internal]
736 * map a 32 bits Ansi structure to a Unicode one
737 */
738 static void FD31_MapOfnStructA(const OPENFILENAMEA *ofnA, LPOPENFILENAMEW ofnW, BOOL open)
739 {
740 UNICODE_STRING usBuffer;
741
742 ofnW->hwndOwner = ofnA->hwndOwner;
743 ofnW->hInstance = ofnA->hInstance;
744 if (ofnA->lpstrFilter)
745 ofnW->lpstrFilter = FD31_MapStringPairsToW(ofnA->lpstrFilter, 0);
746
747 if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter)))
748 ofnW->lpstrCustomFilter = FD31_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter);
749 ofnW->nMaxCustFilter = ofnA->nMaxCustFilter;
750 ofnW->nFilterIndex = ofnA->nFilterIndex;
751 ofnW->nMaxFile = ofnA->nMaxFile;
752 ofnW->lpstrFile = FD31_DupToW(ofnA->lpstrFile, ofnW->nMaxFile);
753 ofnW->nMaxFileTitle = ofnA->nMaxFileTitle;
754 ofnW->lpstrFileTitle = FD31_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle);
755 if (ofnA->lpstrInitialDir)
756 {
757 RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrInitialDir);
758 ofnW->lpstrInitialDir = usBuffer.Buffer;
759 }
760 if (ofnA->lpstrTitle) {
761 RtlCreateUnicodeStringFromAsciiz (&usBuffer, ofnA->lpstrTitle);
762 ofnW->lpstrTitle = usBuffer.Buffer;
763 } else {
764 WCHAR buf[16];
765 LPWSTR title_tmp;
766 int len;
767 LoadStringW(COMDLG32_hInstance, open ? IDS_OPEN_FILE : IDS_SAVE_AS,
768 buf, sizeof(buf)/sizeof(WCHAR));
769 len = lstrlenW(buf)+1;
770 title_tmp = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
771 memcpy(title_tmp, buf, len * sizeof(WCHAR));
772 ofnW->lpstrTitle = title_tmp;
773 }
774 ofnW->Flags = ofnA->Flags;
775 ofnW->nFileOffset = ofnA->nFileOffset;
776 ofnW->nFileExtension = ofnA->nFileExtension;
777 ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3);
778 if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
779 {
780 if (!IS_INTRESOURCE(ofnA->lpTemplateName))
781 {
782 RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName);
783 ofnW->lpTemplateName = usBuffer.Buffer;
784 }
785 else /* numbered resource */
786 ofnW->lpTemplateName = (LPCWSTR) ofnA->lpTemplateName;
787 }
788 if (ofnW->lStructSize > OPENFILENAME_SIZE_VERSION_400W)
789 {
790 ofnW->pvReserved = ofnA->pvReserved;
791 ofnW->dwReserved = ofnA->dwReserved;
792 ofnW->FlagsEx = ofnA->FlagsEx;
793 }
794 }
795
796
797 /************************************************************************
798 * FD31_FreeOfnW [internal]
799 * Undo all allocations done by FD31_MapOfnStructA
800 */
801 static void FD31_FreeOfnW(OPENFILENAMEW *ofnW)
802 {
803 HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter);
804 HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter);
805 HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile);
806 HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle);
807 HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir);
808 HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle);
809 if (!IS_INTRESOURCE(ofnW->lpTemplateName))
810 HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName);
811 }
812
813 /************************************************************************
814 * FD31_DestroyPrivate [internal]
815 * destroys the private object
816 */
817 static void FD31_DestroyPrivate(PFD31_DATA lfs)
818 {
819 HWND hwnd;
820 if (!lfs) return;
821 hwnd = lfs->hwnd;
822 TRACE("destroying private allocation %p\n", lfs);
823
824 /* if ofnW has been allocated, have to free everything in it */
825 if (lfs->ofnA)
826 {
827 FD31_FreeOfnW(lfs->ofnW);
828 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
829 }
830 HeapFree(GetProcessHeap(), 0, lfs);
831 RemovePropA(hwnd, FD31_OFN_PROP);
832 }
833
834 /***********************************************************************
835 * FD31_GetTemplate [internal]
836 *
837 * Get a template (or FALSE if failure) when 16 bits dialogs are used
838 * by a 32 bits application
839 *
840 */
841 static BOOL FD31_GetTemplate(PFD31_DATA lfs)
842 {
843 LPOPENFILENAMEW ofnW = lfs->ofnW;
844 LPOPENFILENAMEA ofnA = lfs->ofnA;
845 HANDLE hDlgTmpl;
846
847 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
848 {
849 if (!(lfs->template = LockResource( ofnW->hInstance )))
850 {
851 COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
852 return FALSE;
853 }
854 }
855 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
856 {
857 HRSRC hResInfo;
858 if (ofnA)
859 hResInfo = FindResourceA( ofnA->hInstance, ofnA->lpTemplateName, (LPSTR)RT_DIALOG );
860 else
861 hResInfo = FindResourceW( ofnW->hInstance, ofnW->lpTemplateName, (LPWSTR)RT_DIALOG );
862 if (!hResInfo)
863 {
864 COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
865 return FALSE;
866 }
867 if (!(hDlgTmpl = LoadResource( ofnW->hInstance, hResInfo )) ||
868 !(lfs->template = LockResource( hDlgTmpl )))
869 {
870 COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
871 return FALSE;
872 }
873 }
874 else /* get it from internal Wine resource */
875 {
876 HRSRC hResInfo;
877 if (!(hResInfo = FindResourceA( COMDLG32_hInstance, lfs->open ? "OPEN_FILE" : "SAVE_FILE", (LPSTR)RT_DIALOG )))
878 {
879 COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
880 return FALSE;
881 }
882 if (!(hDlgTmpl = LoadResource( COMDLG32_hInstance, hResInfo )) ||
883 !(lfs->template = LockResource( hDlgTmpl )))
884 {
885 COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
886 return FALSE;
887 }
888 }
889 return TRUE;
890 }
891
892 /************************************************************************
893 * FD31_AllocPrivate [internal]
894 * allocate a private object to hold 32 bits Unicode
895 * structure that will be used throughout the calls, while
896 * keeping available the original structures and a few variables
897 * On entry : type = dialog procedure type (16,32A,32W)
898 * dlgType = dialog type (open or save)
899 */
900 static PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, BOOL IsUnicode)
901 {
902 PFD31_DATA lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD31_DATA));
903
904 TRACE("alloc private buf %p\n", lfs);
905 if (!lfs) return NULL;
906 lfs->hook = FALSE;
907 lfs->lParam = lParam;
908 lfs->open = (dlgType == OPEN_DIALOG);
909
910 if (IsUnicode)
911 {
912 lfs->ofnA = NULL;
913 lfs->ofnW = (LPOPENFILENAMEW) lParam;
914 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
915 if (lfs->ofnW->lpfnHook)
916 lfs->hook = TRUE;
917 }
918 else
919 {
920 lfs->ofnA = (LPOPENFILENAMEA) lParam;
921 if (lfs->ofnA->Flags & OFN_ENABLEHOOK)
922 if (lfs->ofnA->lpfnHook)
923 lfs->hook = TRUE;
924 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lfs->ofnA->lStructSize);
925 lfs->ofnW->lStructSize = lfs->ofnA->lStructSize;
926 FD31_MapOfnStructA(lfs->ofnA, lfs->ofnW, lfs->open);
927 }
928
929 if (! FD31_GetTemplate(lfs))
930 {
931 FD31_DestroyPrivate(lfs);
932 return NULL;
933 }
934 lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
935 lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
936
937 return lfs;
938 }
939
940 /***********************************************************************
941 * FD31_WMInitDialog [internal]
942 */
943 static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
944 {
945 int i, n;
946 WCHAR tmpstr[BUFFILE];
947 LPWSTR pstr, old_pstr;
948 LPOPENFILENAMEW ofn;
949 PFD31_DATA lfs = (PFD31_DATA) lParam;
950
951 if (!lfs) return FALSE;
952 SetPropA(hWnd, FD31_OFN_PROP, lfs);
953 lfs->hwnd = hWnd;
954 ofn = lfs->ofnW;
955
956 TRACE("flags=%x initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir));
957
958 SetWindowTextW( hWnd, ofn->lpstrTitle );
959 /* read custom filter information */
960 if (ofn->lpstrCustomFilter)
961 {
962 pstr = ofn->lpstrCustomFilter;
963 n = 0;
964 TRACE("lpstrCustomFilter = %p\n", pstr);
965 while(*pstr)
966 {
967 old_pstr = pstr;
968 i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
969 (LPARAM)(ofn->lpstrCustomFilter) + n );
970 n += lstrlenW(pstr) + 1;
971 pstr += lstrlenW(pstr) + 1;
972 TRACE("add str=%s associated to %s\n",
973 debugstr_w(old_pstr), debugstr_w(pstr));
974 SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
975 n += lstrlenW(pstr) + 1;
976 pstr += lstrlenW(pstr) + 1;
977 }
978 }
979 /* read filter information */
980 if (ofn->lpstrFilter) {
981 pstr = (LPWSTR) ofn->lpstrFilter;
982 n = 0;
983 while(*pstr) {
984 old_pstr = pstr;
985 i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
986 (LPARAM)(ofn->lpstrFilter + n) );
987 n += lstrlenW(pstr) + 1;
988 pstr += lstrlenW(pstr) + 1;
989 TRACE("add str=%s associated to %s\n",
990 debugstr_w(old_pstr), debugstr_w(pstr));
991 SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
992 n += lstrlenW(pstr) + 1;
993 pstr += lstrlenW(pstr) + 1;
994 }
995 }
996 /* set default filter */
997 if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL)
998 ofn->nFilterIndex = 1;
999 SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0);
1000 if (ofn->lpstrFile && ofn->lpstrFile[0])
1001 {
1002 TRACE( "SetText of edt1 to %s\n", debugstr_w(ofn->lpstrFile) );
1003 SetDlgItemTextW( hWnd, edt1, ofn->lpstrFile );
1004 }
1005 else
1006 {
1007 lstrcpynW(tmpstr, FD31_GetFileType(ofn->lpstrCustomFilter,
1008 ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE);
1009 TRACE("nFilterIndex = %d, SetText of edt1 to %s\n",
1010 ofn->nFilterIndex, debugstr_w(tmpstr));
1011 SetDlgItemTextW( hWnd, edt1, tmpstr );
1012 }
1013 /* get drive list */
1014 *tmpstr = 0;
1015 DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE);
1016 /* read initial directory */
1017 /* FIXME: Note that this is now very version-specific (See MSDN description of
1018 * the OPENFILENAME structure). For example under 2000/XP any path in the
1019 * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME
1020 */
1021 if (ofn->lpstrInitialDir != NULL)
1022 {
1023 int len;
1024 lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511);
1025 len = lstrlenW(tmpstr);
1026 if (len > 0 && tmpstr[len-1] != '\\' && tmpstr[len-1] != ':') {
1027 tmpstr[len]='\\';
1028 tmpstr[len+1]='\0';
1029 }
1030 }
1031 else
1032 *tmpstr = 0;
1033 if (!FD31_ScanDir(ofn, hWnd, tmpstr)) {
1034 *tmpstr = 0;
1035 if (!FD31_ScanDir(ofn, hWnd, tmpstr))
1036 WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
1037 }
1038 /* select current drive in combo 2, omit missing drives */
1039 {
1040 char dir[MAX_PATH];
1041 char str[4] = "a:\\";
1042 GetCurrentDirectoryA( sizeof(dir), dir );
1043 for(i = 0, n = -1; i < 26; i++)
1044 {
1045 str[0] = 'a' + i;
1046 if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++;
1047 if (toupper(str[0]) == toupper(dir[0])) break;
1048 }
1049 }
1050 SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0);
1051 if (!(ofn->Flags & OFN_SHOWHELP))
1052 ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
1053 if (ofn->Flags & OFN_HIDEREADONLY)
1054 ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
1055 if (lfs->hook)
1056 return FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
1057 return TRUE;
1058 }
1059
1060 static int FD31_GetFldrHeight(void)
1061 {
1062 return fldrHeight;
1063 }
1064
1065 /***********************************************************************
1066 * FD31_WMMeasureItem [internal]
1067 */
1068 static LONG FD31_WMMeasureItem(LPARAM lParam)
1069 {
1070 LPMEASUREITEMSTRUCT lpmeasure;
1071
1072 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
1073 lpmeasure->itemHeight = FD31_GetFldrHeight();
1074 return TRUE;
1075 }
1076
1077
1078 /***********************************************************************
1079 * FileOpenDlgProc [internal]
1080 * Used for open and save, in fact.
1081 */
1082 static INT_PTR CALLBACK FD31_FileOpenDlgProc(HWND hWnd, UINT wMsg,
1083 WPARAM wParam, LPARAM lParam)
1084 {
1085 PFD31_DATA lfs = (PFD31_DATA)GetPropA( hWnd, FD31_OFN_PROP );
1086
1087 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
1088 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1089 {
1090 INT_PTR lRet;
1091 lRet = (INT_PTR)FD31_CallWindowProc( lfs, wMsg, wParam, lParam );
1092 if (lRet) return lRet; /* else continue message processing */
1093 }
1094 switch (wMsg)
1095 {
1096 case WM_INITDIALOG:
1097 return FD31_WMInitDialog( hWnd, wParam, lParam );
1098
1099 case WM_MEASUREITEM:
1100 return FD31_WMMeasureItem( lParam );
1101
1102 case WM_DRAWITEM:
1103 return FD31_WMDrawItem( hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam );
1104
1105 case WM_COMMAND:
1106 return FD31_WMCommand( hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs );
1107 #if 0
1108 case WM_CTLCOLOR:
1109 SetBkColor( (HDC16)wParam, 0x00C0C0C0 );
1110 switch (HIWORD(lParam))
1111 {
1112 case CTLCOLOR_BTN:
1113 SetTextColor( (HDC16)wParam, 0x00000000 );
1114 return hGRAYBrush;
1115 case CTLCOLOR_STATIC:
1116 SetTextColor( (HDC16)wParam, 0x00000000 );
1117 return hGRAYBrush;
1118 }
1119 break;
1120 #endif
1121 }
1122 return FALSE;
1123 }
1124
1125 /***********************************************************************
1126 * GetFileName31A [internal]
1127 *
1128 * Creates a win31 style dialog box for the user to select a file to open/save.
1129 */
1130 BOOL GetFileName31A( OPENFILENAMEA *lpofn, UINT dlgType )
1131 {
1132 BOOL bRet = FALSE;
1133 PFD31_DATA lfs;
1134
1135 if (!lpofn || !FD31_Init()) return FALSE;
1136
1137 TRACE("ofn flags %08x\n", lpofn->Flags);
1138 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
1139 if (lfs)
1140 {
1141 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1142 FD31_FileOpenDlgProc, (LPARAM)lfs);
1143 FD31_DestroyPrivate(lfs);
1144 }
1145
1146 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
1147 return bRet;
1148 }
1149
1150 /***********************************************************************
1151 * GetFileName31W [internal]
1152 *
1153 * Creates a win31 style dialog box for the user to select a file to open/save
1154 */
1155 BOOL GetFileName31W( OPENFILENAMEW *lpofn, UINT dlgType )
1156 {
1157 BOOL bRet = FALSE;
1158 PFD31_DATA lfs;
1159
1160 if (!lpofn || !FD31_Init()) return FALSE;
1161
1162 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
1163 if (lfs)
1164 {
1165 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1166 FD31_FileOpenDlgProc, (LPARAM)lfs);
1167 FD31_DestroyPrivate(lfs);
1168 }
1169
1170 TRACE("file %s, file offset %d, ext offset %d\n",
1171 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
1172 return bRet;
1173 }