- Defined IDs for string constants for font color names and for the
[wine] / dlls / commdlg / filedlg.c
1 /*
2  * COMMDLG - 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "windef.h"
26 #include "winnls.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "wine/winbase16.h"
30 #include "wine/winuser16.h"
31 #include "wine/unicode.h"
32 #include "commdlg.h"
33 #include "wine/debug.h"
34 #include "cderr.h"
35 #include "winternl.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
38
39 #include "cdlg.h"
40
41 #define BUFFILE 512
42 #define BUFFILEALLOC 512 * sizeof(WCHAR)
43
44 struct FSPRIVATE
45 {
46     HWND hwnd; /* file dialog window handle */
47     BOOL hook; /* TRUE if the dialog is hooked */
48     UINT lbselchstring; /* registered message id */
49     UINT fileokstring; /* registered message id */
50     LPARAM lParam; /* save original lparam */
51     HANDLE16 hDlgTmpl16; /* handle for resource 16 */
52     HANDLE16 hResource16; /* handle for allocated resource 16 */
53     HANDLE16 hGlobal16; /* 16 bits mem block (resources) */
54     LPCVOID template; /* template for 32 bits resource */
55     BOOL open; /* TRUE if open dialog, FALSE if save dialog */
56     OPENFILENAMEW *ofnW; /* original structure or work struct */
57     OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
58     OPENFILENAME16 *ofn16; /* original structure if 16 bits dialog */
59 };
60
61
62 #define LFSPRIVATE struct FSPRIVATE *
63
64 #define LFS16 1
65 #define LFS32A 2
66 #define LFS32W 3
67
68 static const WCHAR FILE_star[] = {'*','.','*', 0};
69 static const WCHAR FILE_bslash[] = {'\\', 0};
70 static const WCHAR FILE_specc[] = {'%','c',':', 0};
71
72 static HICON hFolder = 0;
73 static HICON hFolder2 = 0;
74 static HICON hFloppy = 0;
75 static HICON hHDisk = 0;
76 static HICON hCDRom = 0;
77 static HICON hNet = 0;
78 static const int fldrHeight = 16;
79 static const int fldrWidth = 20;
80
81 #define OFN_PROP "FILEDLG_OFN"
82
83 static char defaultopen[]="Open File";
84 static char defaultsave[]="Save as";
85
86 /***********************************************************************
87  *
88  * Windows 3.1 style OpenFileName/SaveFileName dialog
89  *
90  */
91
92 BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
93                                  LPARAM lParam);
94 BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
95                                  LPARAM lParam);
96
97 static INT_PTR CALLBACK FileOpenDlgProc(HWND hDlg, UINT msg,
98                                       WPARAM wParam, LPARAM lParam);
99
100 /***********************************************************************
101  *                              FileDlg_Init                    [internal]
102  */
103 static BOOL FileDlg_Init(void)
104 {
105     static BOOL initialized = 0;
106
107     if (!initialized) {
108         HINSTANCE inst = GetModuleHandleA( "comdlg32.dll" );
109         if (!inst)
110         {
111             ERR( "cannot get comdlg32.dll instance\n" );
112             return FALSE;
113         }
114         hFolder  = LoadImageA( inst, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED );
115         hFolder2 = LoadImageA( inst, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED );
116         hFloppy  = LoadImageA( inst, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED );
117         hHDisk   = LoadImageA( inst, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED );
118         hCDRom   = LoadImageA( inst, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED );
119         hNet     = LoadImageA( inst, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED );
120         if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 ||
121             hHDisk == 0 || hCDRom == 0 || hNet == 0)
122         {
123             ERR("Error loading icons !\n");
124             return FALSE;
125         }
126         initialized = TRUE;
127     }
128     return TRUE;
129 }
130
131
132 /***********************************************************************
133  *           Get32BitsTemplate                                  [internal]
134  *
135  * Get a template (or FALSE if failure) when 16 bits dialogs are used
136  * by a 32 bits application
137  *
138  */
139 BOOL Get32BitsTemplate(LFSPRIVATE lfs)
140 {
141     LPOPENFILENAMEW ofnW = lfs->ofnW;
142     HANDLE hDlgTmpl;
143
144     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
145     {
146         if (!(lfs->template = LockResource( ofnW->hInstance )))
147         {
148             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
149             return FALSE;
150         }
151     }
152     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
153     {
154         HRSRC hResInfo;
155         if (lfs->ofnA)
156             hResInfo = FindResourceA(lfs->ofnA->hInstance,
157                                  lfs->ofnA->lpTemplateName,
158                                  RT_DIALOGA);
159         else
160             hResInfo = FindResourceW(ofnW->hInstance,
161                                  ofnW->lpTemplateName,
162                                  RT_DIALOGW);
163         if (!hResInfo)
164         {
165             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
166             return FALSE;
167         }
168         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
169                                 hResInfo)) ||
170                     !(lfs->template = LockResource(hDlgTmpl)))
171         {
172             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
173             return FALSE;
174         }
175     } else { /* get it from internal Wine resource */
176         HRSRC hResInfo;
177         if (!(hResInfo = FindResourceA(COMMDLG_hInstance32,
178              lfs->open? "OPEN_FILE":"SAVE_FILE", RT_DIALOGA)))
179         {
180             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
181             return FALSE;
182         }
183         if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hResInfo )) ||
184                 !(lfs->template = LockResource( hDlgTmpl )))
185         {
186             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
187             return FALSE;
188         }
189     }
190     return TRUE;
191 }
192
193
194 /***********************************************************************
195  *           Get16BitsTemplate                                [internal]
196  *
197  * Get a template (FALSE if failure) when 16 bits dialogs are used
198  * by a 16 bits application
199  *
200  */
201 BOOL Get16BitsTemplate(LFSPRIVATE lfs)
202 {
203     LPOPENFILENAME16 ofn16 = lfs->ofn16;
204     LPCVOID template;
205     HGLOBAL16 hGlobal16 = 0;
206
207     if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE)
208         lfs->hDlgTmpl16 = ofn16->hInstance;
209     else if (ofn16->Flags & OFN_ENABLETEMPLATE)
210     {
211         HANDLE16 hResInfo;
212         if (!(hResInfo = FindResource16(ofn16->hInstance,
213                                         MapSL(ofn16->lpTemplateName),
214                                         RT_DIALOGA)))
215         {
216             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
217             return FALSE;
218         }
219         if (!(lfs->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo )))
220         {
221             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
222             return FALSE;
223         }
224         lfs->hResource16 = lfs->hDlgTmpl16;
225     }
226     else
227     { /* get resource from (32 bits) own Wine resource; convert it to 16 */
228         HRSRC hResInfo;
229         HGLOBAL hDlgTmpl32;
230         LPCVOID template32;
231         DWORD size;
232
233         if (!(hResInfo = FindResourceA(COMMDLG_hInstance32,
234                lfs->open ? "OPEN_FILE":"SAVE_FILE", RT_DIALOGA)))
235         {
236             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
237             return FALSE;
238         }
239         if (!(hDlgTmpl32 = LoadResource(COMMDLG_hInstance32, hResInfo )) ||
240             !(template32 = LockResource( hDlgTmpl32 )))
241         {
242             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
243             return FALSE;
244         }
245         size = SizeofResource(GetModuleHandleA("COMDLG32"), hResInfo);
246         hGlobal16 = GlobalAlloc16(0, size);
247         if (!hGlobal16)
248         {
249             COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
250             ERR("alloc failure for %ld bytes\n", size);
251             return FALSE;
252         }
253         template = GlobalLock16(hGlobal16);
254         if (!template)
255         {
256             COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE);
257             ERR("global lock failure for %x handle\n", hGlobal16);
258             GlobalFree16(hGlobal16);
259             return FALSE;
260         }
261         ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template);
262         lfs->hDlgTmpl16 = hGlobal16;
263         lfs->hGlobal16 = hGlobal16;
264     }
265     return TRUE;
266 }
267
268 /***********************************************************************
269  *                              FILEDLG_StripEditControl        [internal]
270  * Strip pathnames off the contents of the edit control.
271  */
272 static void FILEDLG_StripEditControl(HWND hwnd)
273 {
274     WCHAR temp[BUFFILE], *cp;
275
276     GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR));
277     cp = strrchrW(temp, '\\');
278     if (cp != NULL) {
279         strcpyW(temp, cp+1);
280     }
281     cp = strrchrW(temp, ':');
282     if (cp != NULL) {
283         strcpyW(temp, cp+1);
284     }
285     /* FIXME: shouldn't we do something with the result here? ;-) */
286 }
287
288
289
290 /***********************************************************************
291  *                              FILEDLG_CallWindowProc          [internal]
292  *
293  *      Call the appropriate hook
294  */
295 static BOOL FILEDLG_CallWindowProc(LFSPRIVATE lfs, UINT wMsg, WPARAM wParam,
296                                    LPARAM lParam)
297 {
298     if (lfs->ofn16)
299     {
300         return (BOOL16) CallWindowProc16(
301           (WNDPROC16)lfs->ofn16->lpfnHook, HWND_16(lfs->hwnd),
302           (UINT16)wMsg, (WPARAM16)wParam, lParam);
303     }
304     if (lfs->ofnA)
305     {
306         return (BOOL) CallWindowProcA(
307           (WNDPROC)lfs->ofnA->lpfnHook, lfs->hwnd,
308           wMsg, wParam, lParam);
309     }
310
311     if (lfs->ofnW)
312     {
313         return (BOOL) CallWindowProcW(
314           (WNDPROC)lfs->ofnW->lpfnHook, lfs->hwnd,
315           wMsg, wParam, lParam);
316     }
317     return FALSE;
318 }
319
320
321 /***********************************************************************
322  *                              FILEDLG_ScanDir                 [internal]
323  */
324 static BOOL FILEDLG_ScanDir(HWND hWnd, LPWSTR newPath)
325 {
326     WCHAR               buffer[BUFFILE];
327     HWND                hdlg, hdlgDir;
328     LRESULT             lRet = TRUE;
329     HCURSOR             hCursorWait, oldCursor;
330
331     if  ( !SetCurrentDirectoryW( newPath ))
332         return FALSE;
333     lstrcpynW(buffer, newPath, sizeof(buffer)/sizeof(WCHAR));
334
335     /* get the list of spec files */
336     GetDlgItemTextW(hWnd, edt1, buffer, sizeof(buffer)/sizeof(WCHAR));
337
338     hCursorWait = LoadCursorA(0, IDC_WAITA);
339     oldCursor = SetCursor(hCursorWait);
340
341     /* list of files */
342     if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) {
343         WCHAR*  scptr; /* ptr on semi-colon */
344         WCHAR*  filter = buffer;
345
346         TRACE("Using filter %s\n", debugstr_w(filter));
347         SendMessageW(hdlg, LB_RESETCONTENT, 0, 0);
348         while (filter) {
349             scptr = strchrW(filter, ';');
350             if (scptr)  *scptr = 0;
351             while (*filter == ' ') filter++;
352             TRACE("Using file spec %s\n", debugstr_w(filter));
353             if (SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter) == LB_ERR)
354                 return FALSE;
355             if (scptr) *scptr = ';';
356                 filter = (scptr) ? (scptr + 1) : 0;
357          }
358     }
359
360     /* list of directories */
361     strcpyW(buffer, FILE_star);
362
363     if ((hdlgDir = GetDlgItem(hWnd, lst2)) != 0) {
364         lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY);
365     }
366     SetCursor(oldCursor);
367     return lRet;
368 }
369
370
371 /***********************************************************************
372  *                              FILEDLG_GetFileType             [internal]
373  */
374
375 static LPWSTR FILEDLG_GetFileType(LPWSTR cfptr, LPWSTR fptr, WORD index)
376 {
377   int n, i;
378   i = 0;
379   if (cfptr)
380     for ( ;(n = lstrlenW(cfptr)) != 0; i++)
381       {
382         cfptr += n + 1;
383         if (i == index)
384           return cfptr;
385         cfptr += lstrlenW(cfptr) + 1;
386       }
387   if (fptr)
388     for ( ;(n = lstrlenW(fptr)) != 0; i++)
389       {
390         fptr += n + 1;
391         if (i == index)
392           return fptr;
393         fptr += lstrlenW(fptr) + 1;
394     }
395   return (LPWSTR) FILE_star; /* FIXME */
396 }
397
398 /***********************************************************************
399  *                              FILEDLG_WMDrawItem              [internal]
400  */
401 static LONG FILEDLG_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
402        int savedlg, LPDRAWITEMSTRUCT lpdis)
403 {
404     WCHAR *str;
405     HICON hIcon;
406     COLORREF oldText = 0, oldBk = 0;
407
408     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1)
409     {
410         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE;
411         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
412                       (LPARAM)str);
413
414         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
415         {
416             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
417             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
418         }
419         if (savedlg)
420             SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) );
421
422         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1,
423                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
424                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
425
426         if (lpdis->itemState & ODS_SELECTED)
427             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
428
429         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
430         {
431             SetBkColor( lpdis->hDC, oldBk );
432             SetTextColor( lpdis->hDC, oldText );
433         }
434         HeapFree(GetProcessHeap(), 0, str);
435         return TRUE;
436     }
437
438     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2)
439     {
440         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
441             return FALSE;
442         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
443                       (LPARAM)str);
444
445         if (lpdis->itemState & ODS_SELECTED)
446         {
447             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
448             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
449         }
450         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
451                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
452                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
453
454         if (lpdis->itemState & ODS_SELECTED)
455             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
456
457         if (lpdis->itemState & ODS_SELECTED)
458         {
459             SetBkColor( lpdis->hDC, oldBk );
460             SetTextColor( lpdis->hDC, oldText );
461         }
462         DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder);
463         HeapFree(GetProcessHeap(), 0, str);
464         return TRUE;
465     }
466     if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2)
467     {
468         char root[] = "a:";
469         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
470             return FALSE;
471         SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID,
472                       (LPARAM)str);
473         root[0] += str[2] - 'a';
474         switch(GetDriveTypeA(root))
475         {
476         case DRIVE_REMOVABLE: hIcon = hFloppy; break;
477         case DRIVE_CDROM:     hIcon = hCDRom; break;
478         case DRIVE_REMOTE:    hIcon = hNet; break;
479         case DRIVE_FIXED:
480         default:           hIcon = hHDisk; break;
481         }
482         if (lpdis->itemState & ODS_SELECTED)
483         {
484             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
485             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
486         }
487         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
488                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
489                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
490
491         if (lpdis->itemState & ODS_SELECTED)
492         {
493             SetBkColor( lpdis->hDC, oldBk );
494             SetTextColor( lpdis->hDC, oldText );
495         }
496         DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon);
497         HeapFree(GetProcessHeap(), 0, str);
498         return TRUE;
499     }
500     return FALSE;
501 }
502
503 /***********************************************************************
504  *                              FILEDLG_WMMeasureItem           [internal]
505  */
506 static LONG FILEDLG_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
507 {
508     LPMEASUREITEMSTRUCT lpmeasure;
509
510     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
511     lpmeasure->itemHeight = fldrHeight;
512     return TRUE;
513 }
514
515 /***********************************************************************
516  *                              FILEDLG_WMMeasureItem16         [internal]
517  */
518 static LONG FILEDLG_WMMeasureItem16(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam)
519 {
520     LPMEASUREITEMSTRUCT16 lpmeasure;
521
522     lpmeasure = MapSL(lParam);
523     lpmeasure->itemHeight = fldrHeight;
524     return TRUE;
525 }
526
527 /***********************************************************************
528  *                              FILEDLG_WMInitDialog            [internal]
529  */
530
531 static LONG FILEDLG_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
532 {
533   int i, n;
534   WCHAR tmpstr[BUFFILE];
535   LPWSTR pstr, old_pstr;
536   LPOPENFILENAMEW ofn;
537   LFSPRIVATE lfs = (LFSPRIVATE) lParam;
538
539   if (!lfs) return FALSE;
540   SetPropA(hWnd, OFN_PROP, (HANDLE)lfs);
541   lfs->hwnd = hWnd;
542   ofn = lfs->ofnW;
543
544   TRACE("flags=%lx initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir));
545
546   SetWindowTextW( hWnd, ofn->lpstrTitle );
547   /* read custom filter information */
548   if (ofn->lpstrCustomFilter)
549     {
550       pstr = ofn->lpstrCustomFilter;
551       n = 0;
552       TRACE("lpstrCustomFilter = %p\n", pstr);
553       while(*pstr)
554         {
555           old_pstr = pstr;
556           i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
557                                    (LPARAM)(ofn->lpstrCustomFilter) + n );
558           n += lstrlenW(pstr) + 1;
559           pstr += lstrlenW(pstr) + 1;
560           TRACE("add str=%s associated to %s\n",
561                 debugstr_w(old_pstr), debugstr_w(pstr));
562           SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
563           n += lstrlenW(pstr) + 1;
564           pstr += lstrlenW(pstr) + 1;
565         }
566     }
567   /* read filter information */
568   if (ofn->lpstrFilter) {
569         pstr = (LPWSTR) ofn->lpstrFilter;
570         n = 0;
571         while(*pstr) {
572           old_pstr = pstr;
573           i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
574                                        (LPARAM)(ofn->lpstrFilter + n) );
575           n += lstrlenW(pstr) + 1;
576           pstr += lstrlenW(pstr) + 1;
577           TRACE("add str=%s associated to %s\n",
578                 debugstr_w(old_pstr), debugstr_w(pstr));
579           SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
580           n += lstrlenW(pstr) + 1;
581           pstr += lstrlenW(pstr) + 1;
582         }
583   }
584   /* set default filter */
585   if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL)
586         ofn->nFilterIndex = 1;
587   SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0);
588   lstrcpynW(tmpstr, FILEDLG_GetFileType(ofn->lpstrCustomFilter,
589              (LPWSTR)ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE);
590   TRACE("nFilterIndex = %ld, SetText of edt1 to %s\n",
591                         ofn->nFilterIndex, debugstr_w(tmpstr));
592   SetDlgItemTextW( hWnd, edt1, tmpstr );
593   /* get drive list */
594   *tmpstr = 0;
595   DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE);
596   /* read initial directory */
597   /* FIXME: Note that this is now very version-specific (See MSDN description of
598    * the OPENFILENAME structure).  For example under 2000/XP any path in the
599    * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME
600    */
601   if (ofn->lpstrInitialDir != NULL)
602     {
603       int len;
604       lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511);
605       len = lstrlenW(tmpstr);
606       if (len > 0 && tmpstr[len-1] != '\\'  && tmpstr[len-1] != ':') {
607         tmpstr[len]='\\';
608         tmpstr[len+1]='\0';
609       }
610     }
611   else
612     *tmpstr = 0;
613   if (!FILEDLG_ScanDir(hWnd, tmpstr)) {
614     *tmpstr = 0;
615     if (!FILEDLG_ScanDir(hWnd, tmpstr))
616       WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
617   }
618   /* select current drive in combo 2, omit missing drives */
619   {
620       char dir[MAX_PATH];
621       char str[4] = "a:\\";
622       GetCurrentDirectoryA( sizeof(dir), dir );
623       for(i = 0, n = -1; i < 26; i++)
624       {
625           str[0] = 'a' + i;
626           if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++;
627           if (toupper(str[0]) == toupper(dir[0])) break;
628       }
629   }
630   SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0);
631   if (!(ofn->Flags & OFN_SHOWHELP))
632     ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
633   if (ofn->Flags & OFN_HIDEREADONLY)
634     ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
635   if (lfs->hook)
636       return (BOOL) FILEDLG_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
637   return TRUE;
638 }
639
640 /***********************************************************************
641  *                              FILEDLG_UpdateResult            [internal]
642  *      update the displayed file name (with path)
643  */
644 void FILEDLG_UpdateResult(LFSPRIVATE lfs, WCHAR *tmpstr)
645 {
646     int lenstr2;
647     LPOPENFILENAMEW ofnW = lfs->ofnW;
648     WCHAR tmpstr2[BUFFILE];
649
650     GetCurrentDirectoryW(BUFFILE, tmpstr2);
651     lenstr2 = strlenW(tmpstr2);
652     if (lenstr2 > 3)
653         tmpstr2[lenstr2++]='\\';
654     lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2);
655     if (ofnW->lpstrFile)
656         lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile);
657     ofnW->nFileOffset = strrchrW(tmpstr2,'\\') - tmpstr2 +1;
658     ofnW->nFileExtension = 0;
659     while(tmpstr2[ofnW->nFileExtension] != '.' && tmpstr2[ofnW->nFileExtension] != '\0')
660         ofnW->nFileExtension++;
661     if (tmpstr2[ofnW->nFileExtension] == '\0')
662         ofnW->nFileExtension = 0;
663     else
664         ofnW->nFileExtension++;
665     /* update the real client structures if any */
666     if (lfs->ofn16)
667     { /* we have to convert to short (8.3) path */
668         char tmp[1024]; /* MAX_PATHNAME_LEN */
669         LPOPENFILENAME16 ofn16 = lfs->ofn16;
670         char *dest = MapSL(ofn16->lpstrFile);
671         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
672                                   tmp, sizeof(tmp), NULL, NULL ))
673             tmp[sizeof(tmp)-1] = 0;
674         GetShortPathNameA(tmp, dest, ofn16->nMaxFile);
675
676         /* the same procedure as every year... */
677         ofn16->nFileOffset = strrchr(dest,'\\') - dest +1;
678         ofn16->nFileExtension = 0;
679         while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0')
680             ofn16->nFileExtension++;
681         if (dest[ofn16->nFileExtension] == '\0')
682             ofn16->nFileExtension = 0;
683         else
684             ofn16->nFileExtension++;
685     }
686     if (lfs->ofnA)
687     {
688         if (ofnW->nMaxFile &&
689             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
690                                   lfs->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
691             lfs->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
692         lfs->ofnA->nFileOffset = ofnW->nFileOffset;
693         lfs->ofnA->nFileExtension = ofnW->nFileExtension;
694     }
695 }
696
697
698 /***********************************************************************
699  *                              FILEDLG_UpdateFileTitle         [internal]
700  *      update the displayed file name (without path)
701  */
702 void FILEDLG_UpdateFileTitle(LFSPRIVATE lfs)
703 {
704   LONG lRet;
705   LPOPENFILENAMEW ofnW = lfs->ofnW;
706   if (ofnW->lpstrFileTitle != NULL)
707   {
708     lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
709     SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet,
710                              (LPARAM)ofnW->lpstrFileTitle );
711     if (lfs->ofn16)
712     {
713         char *dest = MapSL(lfs->ofn16->lpstrFileTitle);
714         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
715                                   dest, ofnW->nMaxFileTitle, NULL, NULL ))
716             dest[ofnW->nMaxFileTitle-1] = 0;
717     }
718     if (lfs->ofnA)
719     {
720         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
721                                   lfs->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
722             lfs->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
723     }
724   }
725 }
726
727
728
729 /***********************************************************************
730  *                              FILEDLG_DirListDblClick         [internal]
731  */
732 static LRESULT FILEDLG_DirListDblClick( LFSPRIVATE lfs )
733 {
734   LONG lRet;
735   HWND hWnd = lfs->hwnd;
736   LPWSTR pstr;
737   WCHAR tmpstr[BUFFILE];
738
739   /* get the raw string (with brackets) */
740   lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
741   if (lRet == LB_ERR) return TRUE;
742   pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
743   SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
744                      (LPARAM)pstr);
745   strcpyW( tmpstr, pstr );
746   HeapFree(GetProcessHeap(), 0, pstr);
747   /* get the selected directory in tmpstr */
748   if (tmpstr[0] == '[')
749     {
750       tmpstr[lstrlenW(tmpstr) - 1] = 0;
751       strcpyW(tmpstr,tmpstr+1);
752     }
753   strcatW(tmpstr, FILE_bslash);
754
755   FILEDLG_ScanDir(hWnd, tmpstr);
756   /* notify the app */
757   if (lfs->hook)
758     {
759       if (FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, lst2,
760               MAKELONG(lRet,CD_LBSELCHANGE)))
761         return TRUE;
762     }
763   return TRUE;
764 }
765
766
767 /***********************************************************************
768  *                              FILEDLG_FileListSelect         [internal]
769  *    called when a new item is picked in the file list
770  */
771 static LRESULT FILEDLG_FileListSelect( LFSPRIVATE lfs )
772 {
773     LONG lRet;
774     HWND hWnd = lfs->hwnd;
775     LPWSTR pstr;
776
777     lRet = SendDlgItemMessageW(hWnd, lst1, LB_GETCURSEL16, 0, 0);
778     if (lRet == LB_ERR)
779         return TRUE;
780
781     /* set the edit control to the choosen file */
782     if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
783     {
784         SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
785                        (LPARAM)pstr);
786         SetDlgItemTextW( hWnd, edt1, pstr );
787         HeapFree(GetProcessHeap(), 0, pstr);
788     }
789     if (lfs->hook)
790     {
791         FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, lst1,
792                            MAKELONG(lRet,CD_LBSELCHANGE));
793     }
794     /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD,
795            CD_LBSELNOITEMS */
796     return TRUE;
797 }
798
799 /***********************************************************************
800  *                              FILEDLG_TestPath      [internal]
801  *      before accepting the file name, test if it includes wild cards
802  *      tries to scan the directory and returns TRUE if no error.
803  */
804 static LRESULT FILEDLG_TestPath( LFSPRIVATE lfs, LPWSTR path )
805 {
806     HWND hWnd = lfs->hwnd;
807     LPWSTR pBeginFileName, pstr2;
808     WCHAR tmpstr2[BUFFILE];
809
810     pBeginFileName = strrchrW(path, '\\');
811     if (pBeginFileName == NULL)
812         pBeginFileName = strrchrW(path, ':');
813
814     if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL)
815     {
816         /* edit control contains wildcards */
817         if (pBeginFileName != NULL)
818         {
819             lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE);
820             *(pBeginFileName + 1) = 0;
821         }
822         else
823         {
824             strcpyW(tmpstr2, path);
825             *path = 0;
826         }
827
828         TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
829         SetDlgItemTextW( hWnd, edt1, tmpstr2 );
830         FILEDLG_ScanDir(hWnd, path);
831         return FALSE;
832     }
833
834     /* no wildcards, we might have a directory or a filename */
835     /* try appending a wildcard and reading the directory */
836
837     pstr2 = path + lstrlenW(path);
838     if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
839         strcatW(path, FILE_bslash);
840
841     /* if ScanDir succeeds, we have changed the directory */
842     if (FILEDLG_ScanDir(hWnd, path))
843         return TRUE;
844
845     /* if not, this must be a filename */
846
847     *pstr2 = 0; /* remove the wildcard added before */
848
849     if (pBeginFileName != NULL)
850     {
851         /* strip off the pathname */
852         *pBeginFileName = 0;
853         SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 );
854
855         lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) );
856         /* Should we MessageBox() if this fails? */
857         if (!FILEDLG_ScanDir(hWnd, path))
858         {
859             return FALSE;
860         }
861         strcpyW(path, tmpstr2);
862     }
863     else
864         SetDlgItemTextW( hWnd, edt1, path );
865     return TRUE;
866 }
867
868 /***********************************************************************
869  *                              FILEDLG_Validate               [internal]
870  *   called on: click Ok button, Enter in edit, DoubleClick in file list
871  */
872 static LRESULT FILEDLG_Validate( LFSPRIVATE lfs, LPWSTR path, UINT control, INT itemIndex,
873                                  BOOL internalUse )
874 {
875     LONG lRet;
876     HWND hWnd = lfs->hwnd;
877     OPENFILENAMEW ofnsav;
878     LPOPENFILENAMEW ofnW = lfs->ofnW;
879     WCHAR filename[BUFFILE];
880
881     ofnsav = *ofnW; /* for later restoring */
882
883     /* get current file name */
884     if (path)
885         lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR));
886     else
887         GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR));
888
889     /* if we did not click in file list to get there */
890     if (control != lst1)
891     {
892         if (!FILEDLG_TestPath( lfs, filename) )
893            return FALSE;
894     }
895     FILEDLG_UpdateResult(lfs, filename);
896
897     if (internalUse)
898     { /* called internally after a change in a combo */
899         if (lfs->hook)
900         {
901              FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, control,
902                              MAKELONG(itemIndex,CD_LBSELCHANGE));
903         }
904         return TRUE;
905     }
906
907     FILEDLG_UpdateFileTitle(lfs);
908     if (lfs->hook)
909     {
910         lRet = (BOOL)FILEDLG_CallWindowProc(lfs, lfs->fileokstring,
911                   0, lfs->lParam );
912         if (lRet)
913         {
914             *ofnW = ofnsav; /* restore old state */
915             return FALSE;
916         }
917     }
918     if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER))
919     {
920         if (ofnW->lpstrFile)
921         {
922             LPWSTR str = (LPWSTR)ofnW->lpstrFile;
923             LPWSTR ptr = strrchrW(str, '\\');
924             str[lstrlenW(str) + 1] = '\0';
925             *ptr = 0;
926         }
927     }
928     return TRUE;
929 }
930
931 /***********************************************************************
932  *                              FILEDLG_DiskChange             [internal]
933  *    called when a new item is picked in the disk selection combo
934  */
935 static LRESULT FILEDLG_DiskChange( LFSPRIVATE lfs )
936 {
937     LONG lRet;
938     HWND hWnd = lfs->hwnd;
939     LPWSTR pstr;
940     WCHAR diskname[BUFFILE];
941
942     FILEDLG_StripEditControl(hWnd);
943     lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L);
944     if (lRet == LB_ERR)
945         return 0;
946     pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
947     SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
948                          (LPARAM)pstr);
949     wsprintfW(diskname, FILE_specc, pstr[2]);
950     HeapFree(GetProcessHeap(), 0, pstr);
951
952     return FILEDLG_Validate( lfs, diskname, cmb2, lRet, TRUE );
953 }
954
955
956 /***********************************************************************
957  *                              FILEDLG_FileTypeChange         [internal]
958  *    called when a new item is picked in the file type combo
959  */
960 static LRESULT FILEDLG_FileTypeChange( LFSPRIVATE lfs )
961 {
962     LONG lRet;
963     WCHAR diskname[BUFFILE];
964     LPWSTR pstr;
965
966     diskname[0] = 0;
967
968     lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0);
969     if (lRet == LB_ERR)
970         return TRUE;
971     pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0);
972     TRACE("Selected filter : %s\n", debugstr_w(pstr));
973     SetDlgItemTextW( lfs->hwnd, edt1, pstr );
974
975     return FILEDLG_Validate( lfs, NULL, cmb1, lRet, TRUE );
976 }
977
978 /***********************************************************************
979  *                              FILEDLG_WMCommand               [internal]
980  */
981 static LRESULT FILEDLG_WMCommand(HWND hWnd, LPARAM lParam, UINT notification,
982        UINT control, LFSPRIVATE lfs )
983 {
984     switch (control)
985     {
986         case lst1: /* file list */
987         FILEDLG_StripEditControl(hWnd);
988         if (notification == LBN_DBLCLK)
989         {
990             if (FILEDLG_Validate( lfs, NULL, control, 0, FALSE ))
991                 EndDialog(hWnd, TRUE);
992             return TRUE;
993         }
994         else if (notification == LBN_SELCHANGE)
995             return FILEDLG_FileListSelect( lfs );
996         break;
997
998         case lst2: /* directory list */
999         FILEDLG_StripEditControl(hWnd);
1000         if (notification == LBN_DBLCLK)
1001             return FILEDLG_DirListDblClick( lfs );
1002         break;
1003
1004         case cmb1: /* file type drop list */
1005         if (notification == CBN_SELCHANGE)
1006             return FILEDLG_FileTypeChange( lfs );
1007         break;
1008
1009         case chx1:
1010         break;
1011
1012         case pshHelp:
1013         break;
1014
1015         case cmb2: /* disk dropdown combo */
1016         if (notification == CBN_SELCHANGE)
1017             return FILEDLG_DiskChange( lfs );
1018         break;
1019
1020         case IDOK:
1021         if (FILEDLG_Validate( lfs, NULL, control, 0, FALSE ))
1022             EndDialog(hWnd, TRUE);
1023         return TRUE;
1024
1025         case IDCANCEL:
1026         EndDialog(hWnd, FALSE);
1027         return TRUE;
1028
1029         case IDABORT: /* can be sent by the hook procedure */
1030         EndDialog(hWnd, TRUE);
1031         return TRUE;
1032     }
1033     return FALSE;
1034 }
1035
1036 /***********************************************************************
1037  *                              FILEDLG_MapDrawItemStruct       [internal]
1038  *      map a 16 bits drawitem struct to 32
1039  */
1040 void FILEDLG_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis)
1041 {
1042     lpdis->CtlType = lpdis16->CtlType;
1043     lpdis->CtlID = lpdis16->CtlID;
1044     lpdis->itemID = lpdis16->itemID;
1045     lpdis->itemAction = lpdis16->itemAction;
1046     lpdis->itemState = lpdis16->itemState;
1047     lpdis->hwndItem = HWND_32(lpdis16->hwndItem);
1048     lpdis->hDC = HDC_32(lpdis16->hDC);
1049     lpdis->rcItem.right = lpdis16->rcItem.right;
1050     lpdis->rcItem.left = lpdis16->rcItem.left;
1051     lpdis->rcItem.top = lpdis16->rcItem.top;
1052     lpdis->rcItem.bottom = lpdis16->rcItem.bottom;
1053     lpdis->itemData = lpdis16->itemData;
1054 }
1055
1056 /************************************************************************
1057  *                              FILEDLG_MapStringPairsToW       [internal]
1058  *      map string pairs to Unicode
1059  */
1060 static LPWSTR FILEDLG_MapStringPairsToW(LPCSTR strA, UINT size)
1061 {
1062     LPCSTR s;
1063     LPWSTR x;
1064     int n, len;
1065
1066     s = strA;
1067     while (*s)
1068         s = s+strlen(s)+1;
1069     s++;
1070     n = s + 1 - strA; /* Don't forget the other \0 */
1071     if (n < size) n = size;
1072
1073     len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 );
1074     x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR));
1075     MultiByteToWideChar( CP_ACP, 0, strA, n, x, len );
1076     return x;
1077 }
1078
1079
1080 /************************************************************************
1081  *                              FILEDLG_DupToW                  [internal]
1082  *      duplicates an Ansi string to unicode, with a buffer size
1083  */
1084 LPWSTR FILEDLG_DupToW(LPCSTR str, DWORD size)
1085 {
1086     LPWSTR strW = NULL;
1087     if (str && (size > 0))
1088     {
1089         strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1090         if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size );
1091     }
1092     return strW;
1093 }
1094
1095
1096 /************************************************************************
1097  *                              FILEDLG_MapOfnStructA          [internal]
1098  *      map a 32 bits Ansi structure to an Unicode one
1099  */
1100 void FILEDLG_MapOfnStructA(LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open)
1101 {
1102     LPCSTR str;
1103     UNICODE_STRING usBuffer;
1104
1105     ofnW->lStructSize = sizeof(OPENFILENAMEW);
1106     ofnW->hwndOwner = ofnA->hwndOwner;
1107     ofnW->hInstance = ofnA->hInstance;
1108     if (ofnA->lpstrFilter)
1109         ofnW->lpstrFilter = FILEDLG_MapStringPairsToW(ofnA->lpstrFilter, 0);
1110
1111     if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter)))
1112         ofnW->lpstrCustomFilter = FILEDLG_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter);
1113     ofnW->nMaxCustFilter = ofnA->nMaxCustFilter;
1114     ofnW->nFilterIndex = ofnA->nFilterIndex;
1115     ofnW->nMaxFile = ofnA->nMaxFile;
1116     ofnW->lpstrFile = FILEDLG_DupToW(ofnA->lpstrFile, ofnW->nMaxFile);
1117     ofnW->nMaxFileTitle = ofnA->nMaxFileTitle;
1118     ofnW->lpstrFileTitle = FILEDLG_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle);
1119     if (ofnA->lpstrInitialDir)
1120     {
1121         RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrInitialDir);
1122         ofnW->lpstrInitialDir = usBuffer.Buffer;
1123     }
1124     if (ofnA->lpstrTitle)
1125         str = ofnA->lpstrTitle;
1126     else
1127         /* Allocates default title (FIXME : get it from resource) */
1128         str = open ? defaultopen:defaultsave;
1129     RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrTitle);
1130     ofnW->lpstrTitle = usBuffer.Buffer;
1131     ofnW->Flags = ofnA->Flags;
1132     ofnW->nFileOffset = ofnA->nFileOffset;
1133     ofnW->nFileExtension = ofnA->nFileExtension;
1134     ofnW->lpstrDefExt = FILEDLG_DupToW(ofnA->lpstrDefExt, 3);
1135     if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
1136     {
1137         if (HIWORD(ofnA->lpTemplateName))
1138         {
1139             RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName);
1140             ofnW->lpTemplateName = usBuffer.Buffer;
1141         }
1142         else /* numbered resource */
1143             ofnW->lpTemplateName = (LPWSTR) ofnA->lpTemplateName;
1144     }
1145 }
1146
1147
1148 /************************************************************************
1149  *                              FILEDLG_MapOfnStruct16          [internal]
1150  *      map a 16 bits structure to an Unicode one
1151  */
1152 void FILEDLG_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open)
1153 {
1154     OPENFILENAMEA ofnA;
1155     /* first convert to linear pointers */
1156     memset(&ofnA, 0, sizeof(OPENFILENAMEA));
1157     ofnA.lStructSize = sizeof(OPENFILENAMEA);
1158     ofnA.hwndOwner = HWND_32(ofn16->hwndOwner);
1159     ofnA.hInstance = HINSTANCE_32(ofn16->hInstance);
1160     if (ofn16->lpstrFilter)
1161         ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter);
1162     if (ofn16->lpstrCustomFilter)
1163         ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter);
1164     ofnA.nMaxCustFilter = ofn16->nMaxCustFilter;
1165     ofnA.nFilterIndex = ofn16->nFilterIndex;
1166     ofnA.lpstrFile = MapSL(ofn16->lpstrFile);
1167     ofnA.nMaxFile = ofn16->nMaxFile;
1168     ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle);
1169     ofnA.nMaxFileTitle = ofn16->nMaxFileTitle;
1170     ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir);
1171     ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle);
1172     ofnA.Flags = ofn16->Flags;
1173     ofnA.nFileOffset = ofn16->nFileOffset;
1174     ofnA.nFileExtension = ofn16->nFileExtension;
1175     ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt);
1176     if (HIWORD(ofn16->lpTemplateName))
1177         ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName);
1178     else
1179         ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */
1180     /* now calls the 32 bits Ansi to Unicode version to complete the job */
1181     FILEDLG_MapOfnStructA(&ofnA, ofnW, open);
1182 }
1183
1184
1185 /************************************************************************
1186  *                              FILEDLG_DestroyPrivate            [internal]
1187  *      destroys the private object
1188  */
1189 void FILEDLG_DestroyPrivate(LFSPRIVATE lfs)
1190 {
1191     HWND hwnd;
1192     if (!lfs) return;
1193     hwnd = lfs->hwnd;
1194     /* free resources for a 16 bits dialog */
1195     if (lfs->hResource16) FreeResource16(lfs->hResource16);
1196     if (lfs->hGlobal16)
1197     {
1198         GlobalUnlock16(lfs->hGlobal16);
1199         GlobalFree16(lfs->hGlobal16);
1200     }
1201     /* if ofnW has been allocated, have to free everything in it */
1202     if (lfs->ofn16 || lfs->ofnA)
1203     {
1204        LPOPENFILENAMEW ofnW = lfs->ofnW;
1205        if (ofnW->lpstrFilter) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter);
1206        if (ofnW->lpstrCustomFilter) HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter);
1207        if (ofnW->lpstrFile) HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile);
1208        if (ofnW->lpstrFileTitle) HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle);
1209        if (ofnW->lpstrInitialDir) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir);
1210        if (ofnW->lpstrTitle) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle);
1211        if ((ofnW->lpTemplateName) && (HIWORD(ofnW->lpTemplateName)))
1212            HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName);
1213        HeapFree(GetProcessHeap(), 0, ofnW);
1214     }
1215     TRACE("destroying private allocation %p\n", lfs);
1216     HeapFree(GetProcessHeap(), 0, lfs);
1217     RemovePropA(hwnd, OFN_PROP);
1218 }
1219
1220 /************************************************************************
1221  *                              FILEDLG_AllocPrivate            [internal]
1222  *      allocate a private object to hold 32 bits Unicode
1223  *      structure that will be used throughtout the calls, while
1224  *      keeping available the original structures and a few variables
1225  *      On entry : type = dialog procedure type (16,32A,32W)
1226  *                 dlgType = dialog type (open or save)
1227  */
1228 LFSPRIVATE FILEDLG_AllocPrivate(LPARAM lParam, int type, UINT dlgType)
1229 {
1230     LFSPRIVATE lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FSPRIVATE));
1231     LFSPRIVATE ret;
1232     TRACE("alloc private buf %p\n", lfs);
1233     if (!lfs) return NULL;
1234     lfs->hook = FALSE;
1235     lfs->lParam = lParam;
1236     if (dlgType == OPEN_DIALOG)
1237         lfs->open = TRUE;
1238     else
1239         lfs->open = FALSE;
1240     lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
1241     lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
1242     switch(type)
1243     {
1244         case LFS16:
1245         lfs->ofn16 = MapSL(lParam);
1246         if (lfs->ofn16->Flags & OFN_ENABLEHOOK)
1247             if (lfs->ofn16->lpfnHook)
1248                 lfs->hook = TRUE;
1249
1250         break;
1251
1252         case LFS32A:
1253         lfs->ofnA = (LPOPENFILENAMEA) lParam;
1254         if (lfs->ofnA->Flags & OFN_ENABLEHOOK)
1255             if (lfs->ofnA->lpfnHook)
1256                 lfs->hook = TRUE;
1257         break;
1258
1259         case LFS32W:
1260         lfs->ofnW = (LPOPENFILENAMEW) lParam;
1261         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
1262             if (lfs->ofnW->lpfnHook)
1263                 lfs->hook = TRUE;
1264         break;
1265     }
1266     ret = lfs;
1267     if (!lfs->ofnW)
1268     { /* this structure is needed internally, so create it */
1269         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OPENFILENAMEW));
1270         if (lfs->ofnW)
1271         {
1272             if (lfs->ofn16)
1273                 FILEDLG_MapOfnStruct16(lfs->ofn16, lfs->ofnW, lfs->open);
1274             if (lfs->ofnA)
1275                 FILEDLG_MapOfnStructA(lfs->ofnA, lfs->ofnW, lfs->open);
1276         }
1277         else
1278             ret = NULL;
1279     }
1280     if (lfs->ofn16)
1281     {
1282         if (!Get16BitsTemplate(lfs)) ret = NULL;
1283     }
1284     else
1285         if (!Get32BitsTemplate(lfs)) ret = NULL;
1286     if (!ret) FILEDLG_DestroyPrivate(lfs);
1287     return ret;
1288 }
1289
1290
1291 /***********************************************************************
1292  *           GetFileName31A                                 [internal]
1293  *
1294  * Creates a win31 style dialog box for the user to select a file to open/save.
1295  */
1296 BOOL WINAPI GetFileName31A(
1297                            LPOPENFILENAMEA lpofn, /* addess of structure with data*/
1298                            UINT dlgType /* type dialogue : open/save */
1299                           )
1300 {
1301     HINSTANCE hInst;
1302     BOOL bRet = FALSE;
1303     LFSPRIVATE lfs;
1304
1305     if (!lpofn || !FileDlg_Init()) return FALSE;
1306
1307     lfs = FILEDLG_AllocPrivate((LPARAM) lpofn, LFS32A, dlgType);
1308     if (lfs)
1309     {
1310         hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1311         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
1312                                         FileOpenDlgProc, (LPARAM)lfs);
1313         FILEDLG_DestroyPrivate(lfs);
1314     }
1315
1316     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
1317     return bRet;
1318 }
1319
1320
1321 /***********************************************************************
1322  *           GetFileName31W                                 [internal]
1323  *
1324  * Creates a win31 style dialog box for the user to select a file to open/save
1325  */
1326 BOOL WINAPI GetFileName31W(
1327                            LPOPENFILENAMEW lpofn, /* addess of structure with data*/
1328                            UINT dlgType /* type dialogue : open/save */
1329                           )
1330 {
1331     HINSTANCE hInst;
1332     BOOL bRet = FALSE;
1333     LFSPRIVATE lfs;
1334
1335     if (!lpofn || !FileDlg_Init()) return FALSE;
1336
1337     lfs = FILEDLG_AllocPrivate((LPARAM) lpofn, LFS32W, dlgType);
1338     if (lfs)
1339     {
1340         hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1341         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
1342                                         FileOpenDlgProc, (LPARAM)lfs);
1343         FILEDLG_DestroyPrivate(lfs);
1344     }
1345
1346     TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn->lpstrFile));
1347     return bRet;
1348 }
1349
1350
1351 /* ------------------ Dialog procedures ---------------------- */
1352
1353 /***********************************************************************
1354  *           FileOpenDlgProc   (COMMDLG.6)
1355  */
1356 BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
1357                                LPARAM lParam)
1358 {
1359     HWND hWnd = HWND_32(hWnd16);
1360     LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1361     DRAWITEMSTRUCT dis;
1362
1363     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1364     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1365         {
1366             LRESULT lRet = (BOOL16)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1367             if (lRet)
1368                 return lRet;         /* else continue message processing */
1369         }
1370     switch (wMsg)
1371     {
1372     case WM_INITDIALOG:
1373         return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1374
1375     case WM_MEASUREITEM:
1376         return FILEDLG_WMMeasureItem16(hWnd16, wParam, lParam);
1377
1378     case WM_DRAWITEM:
1379         FILEDLG_MapDrawItemStruct(MapSL(lParam), &dis);
1380         return FILEDLG_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis);
1381
1382     case WM_COMMAND:
1383         return FILEDLG_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs);
1384 #if 0
1385     case WM_CTLCOLOR:
1386          SetBkColor((HDC16)wParam, 0x00C0C0C0);
1387          switch (HIWORD(lParam))
1388          {
1389          case CTLCOLOR_BTN:
1390              SetTextColor((HDC16)wParam, 0x00000000);
1391              return hGRAYBrush;
1392         case CTLCOLOR_STATIC:
1393              SetTextColor((HDC16)wParam, 0x00000000);
1394              return hGRAYBrush;
1395         }
1396       break;
1397 #endif
1398     }
1399     return FALSE;
1400 }
1401
1402 /***********************************************************************
1403  *           FileSaveDlgProc   (COMMDLG.7)
1404  */
1405 BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
1406                                LPARAM lParam)
1407 {
1408  HWND hWnd = HWND_32(hWnd16);
1409  LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1410  DRAWITEMSTRUCT dis;
1411
1412  TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1413  if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1414   {
1415    LRESULT  lRet;
1416    lRet = (BOOL16)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1417    if (lRet)
1418     return lRet;         /* else continue message processing */
1419   }
1420   switch (wMsg) {
1421    case WM_INITDIALOG:
1422       return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1423
1424    case WM_MEASUREITEM:
1425       return FILEDLG_WMMeasureItem16(hWnd16, wParam, lParam);
1426
1427    case WM_DRAWITEM:
1428       FILEDLG_MapDrawItemStruct(MapSL(lParam), &dis);
1429       return FILEDLG_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis);
1430
1431    case WM_COMMAND:
1432       return FILEDLG_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs);
1433   }
1434
1435   /*
1436   case WM_CTLCOLOR:
1437    SetBkColor((HDC16)wParam, 0x00C0C0C0);
1438    switch (HIWORD(lParam))
1439    {
1440     case CTLCOLOR_BTN:
1441      SetTextColor((HDC16)wParam, 0x00000000);
1442      return hGRAYBrush;
1443     case CTLCOLOR_STATIC:
1444      SetTextColor((HDC16)wParam, 0x00000000);
1445      return hGRAYBrush;
1446    }
1447    return FALSE;
1448
1449    */
1450   return FALSE;
1451 }
1452
1453 /***********************************************************************
1454  *           FileOpenDlgProc                                    [internal]
1455  *      Used for open and save, in fact.
1456  */
1457 static INT_PTR CALLBACK FileOpenDlgProc(HWND hWnd, UINT wMsg,
1458                                       WPARAM wParam, LPARAM lParam)
1459 {
1460     LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1461
1462     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1463     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1464         {
1465             INT_PTR lRet;
1466             lRet  = (INT_PTR)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1467             if (lRet)
1468                 return lRet;         /* else continue message processing */
1469         }
1470     switch (wMsg)
1471     {
1472     case WM_INITDIALOG:
1473         return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1474
1475     case WM_MEASUREITEM:
1476         return FILEDLG_WMMeasureItem(hWnd, wParam, lParam);
1477
1478     case WM_DRAWITEM:
1479         return FILEDLG_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
1480
1481     case WM_COMMAND:
1482         return FILEDLG_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
1483 #if 0
1484     case WM_CTLCOLOR:
1485          SetBkColor((HDC16)wParam, 0x00C0C0C0);
1486          switch (HIWORD(lParam))
1487          {
1488          case CTLCOLOR_BTN:
1489              SetTextColor((HDC16)wParam, 0x00000000);
1490              return hGRAYBrush;
1491         case CTLCOLOR_STATIC:
1492              SetTextColor((HDC16)wParam, 0x00000000);
1493              return hGRAYBrush;
1494         }
1495       break;
1496 #endif
1497     }
1498     return FALSE;
1499 }
1500
1501 /* ------------------ APIs ---------------------- */
1502
1503 /***********************************************************************
1504  *           GetOpenFileName   (COMMDLG.1)
1505  *
1506  * Creates a dialog box for the user to select a file to open.
1507  *
1508  * RETURNS
1509  *    TRUE on success: user selected a valid file
1510  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1511  *
1512  * BUGS
1513  *    unknown, there are some FIXME's left.
1514  */
1515 BOOL16 WINAPI GetOpenFileName16(
1516                                 SEGPTR ofn /* [in/out] address of structure with data*/
1517                                 )
1518 {
1519     HINSTANCE16 hInst;
1520     BOOL bRet = FALSE;
1521     LPOPENFILENAME16 lpofn = MapSL(ofn);
1522     LFSPRIVATE lfs;
1523     FARPROC16 ptr;
1524
1525     if (!lpofn || !FileDlg_Init()) return FALSE;
1526
1527     lfs = FILEDLG_AllocPrivate((LPARAM) ofn, LFS16, OPEN_DIALOG);
1528     if (lfs)
1529     {
1530         hInst = GetWindowWord( HWND_32(lpofn->hwndOwner), GWL_HINSTANCE );
1531         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6);
1532         bRet = DialogBoxIndirectParam16( hInst, lfs->hDlgTmpl16, lpofn->hwndOwner,
1533                                          (DLGPROC16) ptr, (LPARAM) lfs);
1534         FILEDLG_DestroyPrivate(lfs);
1535     }
1536
1537     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
1538     return bRet;
1539 }
1540
1541 /***********************************************************************
1542  *           GetSaveFileName   (COMMDLG.2)
1543  *
1544  * Creates a dialog box for the user to select a file to save.
1545  *
1546  * RETURNS
1547  *    TRUE on success: user enters a valid file
1548  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1549  *
1550  * BUGS
1551  *    unknown. There are some FIXME's left.
1552  */
1553 BOOL16 WINAPI GetSaveFileName16(
1554                                 SEGPTR ofn /* [in/out] addess of structure with data*/
1555                                 )
1556 {
1557     HINSTANCE16 hInst;
1558     BOOL bRet = FALSE;
1559     LPOPENFILENAME16 lpofn = MapSL(ofn);
1560     LFSPRIVATE lfs;
1561     FARPROC16 ptr;
1562
1563     if (!lpofn || !FileDlg_Init()) return FALSE;
1564
1565     lfs = FILEDLG_AllocPrivate((LPARAM) ofn, LFS16, SAVE_DIALOG);
1566     if (lfs)
1567     {
1568         hInst = GetWindowWord( HWND_32(lpofn->hwndOwner), GWL_HINSTANCE );
1569         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7);
1570         bRet = DialogBoxIndirectParam16( hInst, lfs->hDlgTmpl16, lpofn->hwndOwner,
1571                                          (DLGPROC16) ptr, (LPARAM) lfs);
1572         FILEDLG_DestroyPrivate(lfs);
1573     }
1574
1575     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
1576     return bRet;
1577 }
1578
1579 /***********************************************************************
1580  *            GetOpenFileNameA  (COMDLG32.@)
1581  *
1582  * Creates a dialog box for the user to select a file to open.
1583  *
1584  * RETURNS
1585  *    TRUE on success: user enters a valid file
1586  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1587  *
1588  */
1589 BOOL WINAPI GetOpenFileNameA(
1590         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
1591 {
1592     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1593     COMDLG32_SetCommDlgExtendedError(0);
1594     /* some flags don't allow to match the TWEAK_WineLook */
1595     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1596     {
1597       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1598     }
1599
1600     if (newlook)
1601     {
1602         return GetFileDialog95A(ofn, OPEN_DIALOG);
1603     }
1604     else
1605     {
1606         return GetFileName31A(ofn, OPEN_DIALOG);
1607     }
1608 }
1609
1610 /***********************************************************************
1611  *            GetOpenFileNameW (COMDLG32.@)
1612  *
1613  * Creates a dialog box for the user to select a file to open.
1614  *
1615  * RETURNS
1616  *    TRUE on success: user enters a valid file
1617  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1618  *
1619  */
1620 BOOL WINAPI GetOpenFileNameW(
1621         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
1622 {
1623     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1624     COMDLG32_SetCommDlgExtendedError(0);
1625     /* some flags don't allow to match the TWEAK_WineLook */
1626     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1627     {
1628       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1629     }
1630
1631     if (newlook)
1632     {
1633         return GetFileDialog95W(ofn, OPEN_DIALOG);
1634     }
1635     else
1636     {
1637         return GetFileName31W(ofn, OPEN_DIALOG);
1638     }
1639 }
1640
1641 /***********************************************************************
1642  *            GetSaveFileNameA  (COMDLG32.@)
1643  *
1644  * Creates a dialog box for the user to select a file to save.
1645  *
1646  * RETURNS
1647  *    TRUE on success: user enters a valid file
1648  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1649  *
1650  */
1651 BOOL WINAPI GetSaveFileNameA(
1652         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
1653 {
1654     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1655     COMDLG32_SetCommDlgExtendedError(0);
1656     /* some flags don't allow to match the TWEAK_WineLook */
1657     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1658     {
1659       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1660     }
1661
1662     if (newlook)
1663     {
1664         return GetFileDialog95A(ofn, SAVE_DIALOG);
1665     }
1666     else
1667     {
1668         return GetFileName31A(ofn, SAVE_DIALOG);
1669     }
1670 }
1671
1672 /***********************************************************************
1673  *            GetSaveFileNameW  (COMDLG32.@)
1674  *
1675  * Creates a dialog box for the user to select a file to save.
1676  *
1677  * RETURNS
1678  *    TRUE on success: user enters a valid file
1679  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1680  *
1681  */
1682 BOOL WINAPI GetSaveFileNameW(
1683         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
1684 {
1685     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1686     COMDLG32_SetCommDlgExtendedError(0);
1687     /* some flags don't allow to match the TWEAK_WineLook */
1688     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1689     {
1690       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1691     }
1692
1693     if (newlook)
1694     {
1695         return GetFileDialog95W(ofn, SAVE_DIALOG);
1696     }
1697     else
1698     {
1699         return GetFileName31W(ofn, SAVE_DIALOG);
1700     }
1701 }