Fixed license text.
[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 "heap.h"
33 #include "commdlg.h"
34 #include "wine/debug.h"
35 #include "cderr.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 HICON16 hFolder = 0;
73 static HICON16 hFolder2 = 0;
74 static HICON16 hFloppy = 0;
75 static HICON16 hHDisk = 0;
76 static HICON16 hCDRom = 0;
77 static HICON16 hNet = 0;
78 static const int fldrHeight = 16;
79 static const int fldrWidth = 20;
80
81 #define OFN_PROP "FILEDLG_OFN"
82
83 static const char defaultfilter[]=" \0\0";
84 static char defaultopen[]="Open File";
85 static char defaultsave[]="Save as";
86
87 /***********************************************************************
88  *
89  * Windows 3.1 style OpenFileName/SaveFileName dialog
90  *
91  */
92
93 LRESULT WINAPI FileOpenDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
94                                  LPARAM lParam);
95 LRESULT WINAPI FileSaveDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
96                                  LPARAM lParam);
97
98 static LRESULT WINAPI FileOpenDlgProc(HWND hDlg, UINT msg,
99                                       WPARAM wParam, LPARAM lParam);
100
101 /***********************************************************************
102  *                              FileDlg_Init                    [internal]
103  */
104 static BOOL FileDlg_Init(void)
105 {
106     static BOOL initialized = 0;
107
108     if (!initialized) {
109         HINSTANCE inst = GetModuleHandleA( "comdlg32.dll" );
110         if (!inst)
111         {
112             ERR( "cannot get comdlg32.dll instance\n" );
113             return FALSE;
114         }
115         hFolder  = LoadImageA( inst, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED );
116         hFolder2 = LoadImageA( inst, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED );
117         hFloppy  = LoadImageA( inst, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED );
118         hHDisk   = LoadImageA( inst, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED );
119         hCDRom   = LoadImageA( inst, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED );
120         hNet     = LoadImageA( inst, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED );
121         if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 || 
122             hHDisk == 0 || hCDRom == 0 || hNet == 0)
123         {
124             ERR("Error loading icons !\n");
125             return FALSE;
126         }
127         initialized = TRUE;
128     }
129     return TRUE;
130 }
131
132
133 /***********************************************************************
134  *           Get32BitsTemplate                                  [internal]
135  *
136  * Get a template (or FALSE if failure) when 16 bits dialogs are used
137  * by a 32 bits application
138  *
139  */
140 BOOL Get32BitsTemplate(LFSPRIVATE lfs)
141 {
142     LPOPENFILENAMEW ofnW = lfs->ofnW;
143     HANDLE hDlgTmpl;
144
145     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
146     {
147         if (!(lfs->template = LockResource( ofnW->hInstance )))
148         {
149             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
150             return FALSE;
151         }
152     }
153     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
154     {
155         HANDLE hResInfo;
156         if (lfs->ofnA)
157             hResInfo = FindResourceA(lfs->ofnA->hInstance,
158                                  lfs->ofnA->lpTemplateName,
159                                  RT_DIALOGA);
160         else
161             hResInfo = FindResourceW(ofnW->hInstance,
162                                  ofnW->lpTemplateName,
163                                  RT_DIALOGW);
164         if (!hResInfo)
165         {
166             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
167             return FALSE;
168         }
169         if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
170                                 hResInfo)) ||
171                     !(lfs->template = LockResource(hDlgTmpl)))
172         {
173             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
174             return FALSE;
175         }
176     } else { /* get it from internal Wine resource */
177         HANDLE hResInfo;
178         if (!(hResInfo = FindResourceA(COMMDLG_hInstance32, 
179              lfs->open? "OPEN_FILE":"SAVE_FILE", RT_DIALOGA)))
180         {
181             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
182             return FALSE;
183         }
184         if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hResInfo )) ||
185                 !(lfs->template = LockResource( hDlgTmpl )))
186         {
187             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
188             return FALSE;
189         }
190     }
191     return TRUE;
192 }
193
194
195 /***********************************************************************
196  *           Get16BitsTemplate                                [internal]
197  *
198  * Get a template (FALSE if failure) when 16 bits dialogs are used
199  * by a 16 bits application
200  *
201  */
202 BOOL Get16BitsTemplate(LFSPRIVATE lfs)
203 {
204     LPOPENFILENAME16 ofn16 = lfs->ofn16;
205     LPCVOID template;
206     HGLOBAL16 hGlobal16 = 0;
207
208     if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE)
209         lfs->hDlgTmpl16 = ofn16->hInstance;
210     else if (ofn16->Flags & OFN_ENABLETEMPLATE)
211     {
212         HANDLE16 hResInfo;
213         if (!(hResInfo = FindResource16(ofn16->hInstance,
214                                         MapSL(ofn16->lpTemplateName),
215                                         RT_DIALOGA)))
216         {
217             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
218             return FALSE;
219         }
220         if (!(lfs->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo )))
221         {
222             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
223             return FALSE;
224         }
225         lfs->hResource16 = lfs->hDlgTmpl16;
226     }
227     else
228     { /* get resource from (32 bits) own Wine resource; convert it to 16 */
229         HANDLE hResInfo, 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, 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   if (ofn->lpstrInitialDir != NULL) 
598     {
599       int len;
600       lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511);
601       len = lstrlenW(tmpstr);
602       if (len > 0 && tmpstr[len-1] != '\\'  && tmpstr[len-1] != ':') {
603         tmpstr[len]='\\';
604         tmpstr[len+1]='\0';
605       }
606     }
607   else
608     *tmpstr = 0;
609   if (!FILEDLG_ScanDir(hWnd, tmpstr)) {
610     *tmpstr = 0;
611     if (!FILEDLG_ScanDir(hWnd, tmpstr))
612       WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
613   }
614   /* select current drive in combo 2, omit missing drives */
615   {
616       char dir[MAX_PATH];
617       char str[4] = "a:\\";
618       GetCurrentDirectoryA( sizeof(dir), dir );
619       for(i = 0, n = -1; i < 26; i++)
620       {
621           str[0] = 'a' + i;
622           if (GetDriveTypeA(str) <= DRIVE_NO_ROOT_DIR) n++;
623           if (toupper(str[0]) == toupper(dir[0])) break;
624       }
625   }
626   SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0);
627   if (!(ofn->Flags & OFN_SHOWHELP))
628     ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
629   if (ofn->Flags & OFN_HIDEREADONLY)
630     ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
631   if (lfs->hook)
632       return (BOOL) FILEDLG_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
633   return TRUE;
634 }
635
636 /***********************************************************************
637  *                              FILEDLG_UpdateResult            [internal]
638  *      update the displayed file name (with path) 
639  */
640 void FILEDLG_UpdateResult(LFSPRIVATE lfs, WCHAR *tmpstr)
641 {
642     int lenstr2;
643     LPOPENFILENAMEW ofnW = lfs->ofnW;
644     WCHAR tmpstr2[BUFFILE];
645
646     GetCurrentDirectoryW(BUFFILE, tmpstr2);
647     lenstr2 = strlenW(tmpstr2);
648     if (lenstr2 > 3)
649         tmpstr2[lenstr2++]='\\';
650     lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2);
651     if (ofnW->lpstrFile)
652         lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile);
653     ofnW->nFileOffset = strrchrW(tmpstr2,'\\') - tmpstr2 +1;
654     ofnW->nFileExtension = 0;
655     while(tmpstr2[ofnW->nFileExtension] != '.' && tmpstr2[ofnW->nFileExtension] != '\0')
656         ofnW->nFileExtension++;
657     if (tmpstr2[ofnW->nFileExtension] == '\0')
658         ofnW->nFileExtension = 0;
659     else
660         ofnW->nFileExtension++;
661     /* update the real client structures if any */
662     if (lfs->ofn16)
663     { /* we have to convert to short (8.3) path */
664         char tmp[1024]; /* MAX_PATHNAME_LEN */
665         LPOPENFILENAME16 ofn16 = lfs->ofn16;
666         char *dest = MapSL(ofn16->lpstrFile);
667         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
668                                   tmp, ofnW->nMaxFile, NULL, NULL ))
669             tmp[ofnW->nMaxFile-1] = 0;
670         GetShortPathNameA(tmp, dest, ofn16->nMaxFile);
671
672         /* the same procedure as every year... */
673         ofn16->nFileOffset = strrchr(dest,'\\') - dest +1;
674         ofn16->nFileExtension = 0;
675         while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0')
676             ofn16->nFileExtension++;
677         if (dest[ofn16->nFileExtension] == '\0')
678             ofn16->nFileExtension = 0;
679         else
680             ofn16->nFileExtension++;
681     }
682     if (lfs->ofnA)
683     {
684         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
685                                   lfs->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
686             lfs->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
687         lfs->ofnA->nFileOffset = ofnW->nFileOffset;
688         lfs->ofnA->nFileExtension = ofnW->nFileExtension;
689     }
690 }
691
692
693 /***********************************************************************
694  *                              FILEDLG_UpdateFileTitle         [internal]
695  *      update the displayed file name (without path) 
696  */
697 void FILEDLG_UpdateFileTitle(LFSPRIVATE lfs)
698 {
699   LONG lRet;
700   LPOPENFILENAMEW ofnW = lfs->ofnW;
701   if (ofnW->lpstrFileTitle != NULL) 
702   {
703     lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
704     SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet,
705                              (LPARAM)ofnW->lpstrFileTitle );
706     if (lfs->ofn16)
707     {
708         char *dest = MapSL(lfs->ofn16->lpstrFileTitle);
709         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
710                                   dest, ofnW->nMaxFileTitle, NULL, NULL ))
711             dest[ofnW->nMaxFileTitle-1] = 0;
712     }
713     if (lfs->ofnA)
714     {
715         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
716                                   lfs->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
717             lfs->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
718     }
719   }
720 }
721
722
723
724 /***********************************************************************
725  *                              FILEDLG_DirListDblClick         [internal]
726  */
727 static LRESULT FILEDLG_DirListDblClick( LFSPRIVATE lfs )
728 {
729   LONG lRet;
730   HWND hWnd = lfs->hwnd;
731   LPWSTR pstr;
732   WCHAR tmpstr[BUFFILE];
733
734   /* get the raw string (with brackets) */
735   lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
736   if (lRet == LB_ERR) return TRUE;
737   pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
738   SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
739                      (LPARAM)pstr);
740   strcpyW( tmpstr, pstr );
741   HeapFree(GetProcessHeap(), 0, pstr);
742   /* get the selected directory in tmpstr */
743   if (tmpstr[0] == '[')
744     {
745       tmpstr[lstrlenW(tmpstr) - 1] = 0;
746       strcpyW(tmpstr,tmpstr+1);
747     }
748   strcatW(tmpstr, FILE_bslash);
749
750   FILEDLG_ScanDir(hWnd, tmpstr);
751   /* notify the app */
752   if (lfs->hook)
753     {
754       if (FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, lst2,
755               MAKELONG(lRet,CD_LBSELCHANGE)))
756         return TRUE;
757     }
758   return TRUE;
759 }
760
761
762 /***********************************************************************
763  *                              FILEDLG_FileListSelect         [internal]
764  *    called when a new item is picked in the file list
765  */
766 static LRESULT FILEDLG_FileListSelect( LFSPRIVATE lfs )
767 {
768     LONG lRet;
769     HWND hWnd = lfs->hwnd;
770     LPWSTR pstr;
771
772     lRet = SendDlgItemMessageW(hWnd, lst1, LB_GETCURSEL16, 0, 0);
773     if (lRet == LB_ERR)
774         return TRUE;
775
776     /* set the edit control to the choosen file */
777     if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
778     {
779         SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
780                        (LPARAM)pstr);
781         SetDlgItemTextW( hWnd, edt1, pstr );
782         HeapFree(GetProcessHeap(), 0, pstr);
783     }
784     if (lfs->hook)
785     {
786         FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, lst1,
787                            MAKELONG(lRet,CD_LBSELCHANGE));
788     }
789     /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD,
790            CD_LBSELNOITEMS */
791     return TRUE;
792 }
793
794 /***********************************************************************
795  *                              FILEDLG_TestPath      [internal]
796  *      before accepting the file name, test if it includes wild cards
797  *      tries to scan the directory and returns TRUE if no error.
798  */
799 static LRESULT FILEDLG_TestPath( LFSPRIVATE lfs, LPWSTR path )
800 {
801     HWND hWnd = lfs->hwnd;
802     LPWSTR pBeginFileName, pstr2;
803     WCHAR tmpstr2[BUFFILE];
804
805     pBeginFileName = strrchrW(path, '\\');
806     if (pBeginFileName == NULL)
807         pBeginFileName = strrchrW(path, ':');
808
809     if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL)
810     {
811         /* edit control contains wildcards */
812         if (pBeginFileName != NULL)
813         {
814             lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE);
815             *(pBeginFileName + 1) = 0;
816         }
817         else
818         {
819             strcpyW(tmpstr2, path);
820             *path = 0;
821         }
822
823         TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
824         SetDlgItemTextW( hWnd, edt1, tmpstr2 );
825         FILEDLG_ScanDir(hWnd, path);
826         return FALSE;
827     }
828
829     /* no wildcards, we might have a directory or a filename */
830     /* try appending a wildcard and reading the directory */
831
832     pstr2 = path + lstrlenW(path);
833     if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
834         strcatW(path, FILE_bslash);
835
836     /* if ScanDir succeeds, we have changed the directory */
837     if (FILEDLG_ScanDir(hWnd, path))
838         return TRUE;
839
840     /* if not, this must be a filename */
841
842     *pstr2 = 0; /* remove the wildcard added before */
843
844     if (pBeginFileName != NULL)
845     {
846         /* strip off the pathname */
847         *pBeginFileName = 0;
848         SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 );
849
850         lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) );
851         /* Should we MessageBox() if this fails? */
852         if (!FILEDLG_ScanDir(hWnd, path))
853         {
854             return FALSE;
855         }
856         strcpyW(path, tmpstr2);
857     }
858     else
859         SetDlgItemTextW( hWnd, edt1, path );
860     return TRUE;
861 }
862
863 /***********************************************************************
864  *                              FILEDLG_Validate               [internal]
865  *   called on: click Ok button, Enter in edit, DoubleClick in file list
866  */
867 static LRESULT FILEDLG_Validate( LFSPRIVATE lfs, LPWSTR path, UINT control, INT itemIndex,
868                                  BOOL internalUse )
869 {
870     LONG lRet;
871     HWND hWnd = lfs->hwnd;
872     OPENFILENAMEW ofnsav;
873     LPOPENFILENAMEW ofnW = lfs->ofnW;
874     WCHAR filename[BUFFILE];
875
876     ofnsav = *ofnW; /* for later restoring */
877
878     /* get current file name */
879     if (path)
880         lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR));
881     else
882         GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR));
883
884     /* if we did not click in file list to get there */
885     if (control != lst1)
886     {
887         if (!FILEDLG_TestPath( lfs, filename) )
888            return FALSE;
889     }
890     FILEDLG_UpdateResult(lfs, filename);
891
892     if (internalUse)
893     { /* called internally after a change in a combo */
894         if (lfs->hook)
895         {
896              FILEDLG_CallWindowProc(lfs, lfs->lbselchstring, control,
897                              MAKELONG(itemIndex,CD_LBSELCHANGE));
898         }
899         return TRUE;
900     }
901
902     FILEDLG_UpdateFileTitle(lfs);
903     if (lfs->hook)
904     {
905         lRet = (BOOL)FILEDLG_CallWindowProc(lfs, lfs->fileokstring,
906                   0, lfs->lParam );
907         if (lRet)       
908         {
909             *ofnW = ofnsav; /* restore old state */
910             return FALSE;
911         }
912     }
913     if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER))
914     {
915         if (ofnW->lpstrFile)
916         {
917             LPWSTR str = (LPWSTR)ofnW->lpstrFile;
918             LPWSTR ptr = strrchrW(str, '\\');
919             str[lstrlenW(str) + 1] = '\0';
920             *ptr = 0;
921         }
922     }
923     return TRUE;
924 }
925
926 /***********************************************************************
927  *                              FILEDLG_DiskChange             [internal]
928  *    called when a new item is picked in the disk selection combo
929  */
930 static LRESULT FILEDLG_DiskChange( LFSPRIVATE lfs )
931 {
932     LONG lRet;
933     HWND hWnd = lfs->hwnd;
934     LPWSTR pstr;
935     WCHAR diskname[BUFFILE];
936
937     FILEDLG_StripEditControl(hWnd);
938     lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L);
939     if (lRet == LB_ERR)
940         return 0;
941     pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
942     SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
943                          (LPARAM)pstr);
944     wsprintfW(diskname, FILE_specc, pstr[2]);
945     HeapFree(GetProcessHeap(), 0, pstr);    
946
947     return FILEDLG_Validate( lfs, diskname, cmb2, lRet, TRUE );
948 }
949
950
951 /***********************************************************************
952  *                              FILEDLG_FileTypeChange         [internal]
953  *    called when a new item is picked in the file type combo
954  */
955 static LRESULT FILEDLG_FileTypeChange( LFSPRIVATE lfs )
956 {
957     LONG lRet;
958     WCHAR diskname[BUFFILE];
959     LPWSTR pstr;
960
961     diskname[0] = 0;
962
963     lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0);
964     if (lRet == LB_ERR)
965         return TRUE;
966     pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0);
967     TRACE("Selected filter : %s\n", debugstr_w(pstr));
968     SetDlgItemTextW( lfs->hwnd, edt1, pstr );
969
970     return FILEDLG_Validate( lfs, NULL, cmb1, lRet, TRUE );
971 }
972
973 /***********************************************************************
974  *                              FILEDLG_WMCommand               [internal]
975  */
976 static LRESULT FILEDLG_WMCommand(HWND hWnd, LPARAM lParam, UINT notification,
977        UINT control, LFSPRIVATE lfs ) 
978 {
979     switch (control)
980     {
981         case lst1: /* file list */
982         FILEDLG_StripEditControl(hWnd);
983         if (notification == LBN_DBLCLK)
984         {
985             if (FILEDLG_Validate( lfs, NULL, control, 0, FALSE ))
986                 EndDialog(hWnd, TRUE);
987             return TRUE;
988         }
989         else if (notification == LBN_SELCHANGE)
990             return FILEDLG_FileListSelect( lfs );
991         break;
992
993         case lst2: /* directory list */
994         FILEDLG_StripEditControl(hWnd);
995         if (notification == LBN_DBLCLK)
996             return FILEDLG_DirListDblClick( lfs );
997         break;
998
999         case cmb1: /* file type drop list */
1000         if (notification == CBN_SELCHANGE) 
1001             return FILEDLG_FileTypeChange( lfs );
1002         break;
1003
1004         case chx1:
1005         break;
1006
1007         case pshHelp:
1008         break;
1009
1010         case cmb2: /* disk dropdown combo */
1011         if (notification == CBN_SELCHANGE)
1012             return FILEDLG_DiskChange( lfs );
1013         break;
1014
1015         case IDOK:
1016         if (FILEDLG_Validate( lfs, NULL, control, 0, FALSE ))
1017             EndDialog(hWnd, TRUE);
1018         return TRUE;
1019
1020         case IDCANCEL:
1021         EndDialog(hWnd, FALSE);
1022         return TRUE;
1023
1024         case IDABORT: /* can be sent by the hook procedure */
1025         EndDialog(hWnd, TRUE);
1026         return TRUE;
1027     }
1028     return FALSE;
1029 }
1030
1031 /***********************************************************************
1032  *                              FILEDLG_MapDrawItemStruct       [internal]
1033  *      map a 16 bits drawitem struct to 32
1034  */
1035 void FILEDLG_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis)
1036 {
1037     lpdis->CtlType = lpdis16->CtlType;
1038     lpdis->CtlID = lpdis16->CtlID;
1039     lpdis->itemID = lpdis16->itemID;
1040     lpdis->itemAction = lpdis16->itemAction;
1041     lpdis->itemState = lpdis16->itemState;
1042     lpdis->hwndItem = lpdis16->hwndItem;
1043     lpdis->hDC = lpdis16->hDC;
1044     lpdis->rcItem.right = lpdis16->rcItem.right;
1045     lpdis->rcItem.left = lpdis16->rcItem.left;
1046     lpdis->rcItem.top = lpdis16->rcItem.top;
1047     lpdis->rcItem.bottom = lpdis16->rcItem.bottom;
1048     lpdis->itemData = lpdis16->itemData;
1049 }
1050
1051 /************************************************************************
1052  *                              FILEDLG_MapStringPairsToW       [internal]
1053  *      map string pairs to Unicode
1054  */
1055 LPWSTR FILEDLG_MapStringPairsToW(LPCSTR strA, UINT size)
1056 {
1057     LPCSTR s;
1058     LPWSTR x;
1059     int n, len;
1060
1061     s = strA;
1062     while (*s)
1063         s = s+strlen(s)+1;
1064     s++;
1065     n = s - strA;
1066     if (n < size) n = size;
1067
1068     len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 );
1069     x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR));
1070     MultiByteToWideChar( CP_ACP, 0, strA, n, x, len );
1071     return x;
1072 }
1073
1074
1075 /************************************************************************
1076  *                              FILEDLG_DupToW                  [internal]
1077  *      duplicates an Ansi string to unicode, with a buffer size
1078  */
1079 LPWSTR FILEDLG_DupToW(LPCSTR str, DWORD size)
1080 {
1081     LPWSTR strW = NULL;
1082     if (str && (size > 0))
1083     {
1084         strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1085         if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size );
1086     }
1087     return strW;
1088 }
1089
1090
1091 /************************************************************************
1092  *                              FILEDLG_MapOfnStructA          [internal]
1093  *      map a 32 bits Ansi structure to an Unicode one
1094  */
1095 void FILEDLG_MapOfnStructA(LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open)
1096 {
1097     LPCSTR str;
1098
1099     ofnW->lStructSize = sizeof(OPENFILENAMEW);
1100     ofnW->hwndOwner = ofnA->hwndOwner;
1101     ofnW->hInstance = ofnA->hInstance;
1102     if (ofnA->lpstrFilter)
1103         ofnW->lpstrFilter = FILEDLG_MapStringPairsToW(ofnA->lpstrFilter, 0);
1104     else
1105         ofnW->lpstrFilter = FILEDLG_MapStringPairsToW(defaultfilter, 0);
1106
1107     if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter)))
1108         ofnW->lpstrCustomFilter = FILEDLG_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter);
1109     ofnW->nMaxCustFilter = ofnA->nMaxCustFilter;
1110     ofnW->nFilterIndex = ofnA->nFilterIndex;
1111     ofnW->nMaxFile = ofnA->nMaxFile;
1112     ofnW->lpstrFile = FILEDLG_DupToW(ofnA->lpstrFile, ofnW->nMaxFile);
1113     ofnW->nMaxFileTitle = ofnA->nMaxFileTitle;
1114     ofnW->lpstrFileTitle = FILEDLG_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle);
1115     if (ofnA->lpstrInitialDir)
1116         ofnW->lpstrInitialDir = HEAP_strdupAtoW(GetProcessHeap(),0,ofnA->lpstrInitialDir);
1117     if (ofnA->lpstrTitle)
1118         str = ofnA->lpstrTitle;
1119     else 
1120         /* Allocates default title (FIXME : get it from resource) */
1121         str = open ? defaultopen:defaultsave;
1122     ofnW->lpstrTitle = HEAP_strdupAtoW(GetProcessHeap(),0, str);
1123     ofnW->Flags = ofnA->Flags;
1124     ofnW->nFileOffset = ofnA->nFileOffset;
1125     ofnW->nFileExtension = ofnA->nFileExtension;
1126     ofnW->lpstrDefExt = FILEDLG_DupToW(ofnA->lpstrDefExt, 3);
1127     if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
1128     {
1129         if (HIWORD(ofnA->lpTemplateName))
1130             ofnW->lpTemplateName = HEAP_strdupAtoW(GetProcessHeap(), 0, ofnA->lpTemplateName);
1131         else /* numbered resource */
1132             ofnW->lpTemplateName = (LPWSTR) ofnA->lpTemplateName;
1133     }
1134 }
1135
1136
1137 /************************************************************************
1138  *                              FILEDLG_MapOfnStruct16          [internal]
1139  *      map a 16 bits structure to an Unicode one
1140  */
1141 void FILEDLG_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open)
1142 {
1143     OPENFILENAMEA ofnA;
1144     /* first convert to linear pointers */
1145     memset(&ofnA, 0, sizeof(OPENFILENAMEA));
1146     ofnA.lStructSize = sizeof(OPENFILENAMEA);
1147     ofnA.hwndOwner = ofn16->hwndOwner;
1148     ofnA.hInstance = ofn16->hInstance;
1149     if (ofn16->lpstrFilter)
1150         ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter);
1151     if (ofn16->lpstrCustomFilter)
1152         ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter);
1153     ofnA.nMaxCustFilter = ofn16->nMaxCustFilter;
1154     ofnA.nFilterIndex = ofn16->nFilterIndex;
1155     ofnA.lpstrFile = MapSL(ofn16->lpstrFile);
1156     ofnA.nMaxFile = ofn16->nMaxFile;
1157     ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle);
1158     ofnA.nMaxFileTitle = ofn16->nMaxFileTitle;
1159     ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir);
1160     ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle);
1161     ofnA.Flags = ofn16->Flags;
1162     ofnA.nFileOffset = ofn16->nFileOffset;
1163     ofnA.nFileExtension = ofn16->nFileExtension;
1164     ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt);
1165     if (HIWORD(ofn16->lpTemplateName))
1166         ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName);
1167     else
1168         ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */
1169     /* now calls the 32 bits Ansi to Unicode version to complete the job */
1170     FILEDLG_MapOfnStructA(&ofnA, ofnW, open);
1171 }
1172
1173
1174 /************************************************************************
1175  *                              FILEDLG_DestroyPrivate            [internal]
1176  *      destroys the private object 
1177  */
1178 void FILEDLG_DestroyPrivate(LFSPRIVATE lfs)
1179 {
1180     HWND hwnd;
1181     if (!lfs) return;
1182     hwnd = lfs->hwnd;
1183     /* free resources for a 16 bits dialog */
1184     if (lfs->hResource16) FreeResource16(lfs->hResource16);
1185     if (lfs->hGlobal16)
1186     {
1187         GlobalUnlock16(lfs->hGlobal16);
1188         GlobalFree16(lfs->hGlobal16);
1189     }
1190     /* if ofnW has been allocated, have to free everything in it */
1191     if (lfs->ofn16 || lfs->ofnA)
1192     {
1193        LPOPENFILENAMEW ofnW = lfs->ofnW;
1194        if (ofnW->lpstrFilter) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter);
1195        if (ofnW->lpstrCustomFilter) HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter);
1196        if (ofnW->lpstrFile) HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile);
1197        if (ofnW->lpstrFileTitle) HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle);
1198        if (ofnW->lpstrInitialDir) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir);
1199        if (ofnW->lpstrTitle) HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle);
1200        if ((ofnW->lpTemplateName) && (HIWORD(ofnW->lpTemplateName)))
1201            HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName);
1202        HeapFree(GetProcessHeap(), 0, ofnW);
1203     }
1204     TRACE("destroying private allocation %p\n", lfs);
1205     HeapFree(GetProcessHeap(), 0, lfs);
1206     RemovePropA(hwnd, OFN_PROP);
1207 }
1208
1209 /************************************************************************
1210  *                              FILEDLG_AllocPrivate            [internal]
1211  *      allocate a private object to hold 32 bits Unicode 
1212  *      structure that will be used throughtout the calls, while
1213  *      keeping available the original structures and a few variables
1214  *      On entry : type = dialog procedure type (16,32A,32W)
1215  *                 dlgType = dialog type (open or save)
1216  */
1217 LFSPRIVATE FILEDLG_AllocPrivate(LPARAM lParam, int type, UINT dlgType)
1218 {
1219     LFSPRIVATE lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FSPRIVATE));
1220     LFSPRIVATE ret;
1221     TRACE("alloc private buf %p\n", lfs);
1222     if (!lfs) return NULL;
1223     lfs->hook = FALSE;
1224     lfs->lParam = lParam;
1225     if (dlgType == OPEN_DIALOG)
1226         lfs->open = TRUE;
1227     else
1228         lfs->open = FALSE;
1229     lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
1230     lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
1231     switch(type)
1232     {
1233         case LFS16:
1234         lfs->ofn16 = MapSL(lParam);
1235         if (lfs->ofn16->Flags & OFN_ENABLEHOOK)
1236             if (lfs->ofn16->lpfnHook)
1237                 lfs->hook = TRUE;
1238
1239         break;
1240
1241         case LFS32A:
1242         lfs->ofnA = (LPOPENFILENAMEA) lParam;
1243         if (lfs->ofnA->Flags & OFN_ENABLEHOOK)
1244             if (lfs->ofnA->lpfnHook)
1245                 lfs->hook = TRUE;
1246         break;
1247
1248         case LFS32W:
1249         lfs->ofnW = (LPOPENFILENAMEW) lParam;
1250         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
1251             if (lfs->ofnW->lpfnHook)
1252                 lfs->hook = TRUE;
1253         break;
1254     }
1255     ret = lfs;
1256     if (!lfs->ofnW)
1257     { /* this structure is needed internally, so create it */
1258         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OPENFILENAMEW));
1259         if (lfs->ofnW)
1260         {
1261             if (lfs->ofn16)
1262                 FILEDLG_MapOfnStruct16(lfs->ofn16, lfs->ofnW, lfs->open);
1263             if (lfs->ofnA)
1264                 FILEDLG_MapOfnStructA(lfs->ofnA, lfs->ofnW, lfs->open);
1265         }
1266         else 
1267             ret = NULL;
1268     }
1269     if (lfs->ofn16)
1270     {
1271         if (!Get16BitsTemplate(lfs)) ret = NULL;
1272     }
1273     else
1274         if (!Get32BitsTemplate(lfs)) ret = NULL;
1275     if (!ret) FILEDLG_DestroyPrivate(lfs);
1276     return ret;
1277 }
1278
1279
1280 /***********************************************************************
1281  *           GetFileName31A                                 [internal]
1282  *
1283  * Creates a win31 style dialog box for the user to select a file to open/save.
1284  */
1285 BOOL WINAPI GetFileName31A( 
1286                            LPOPENFILENAMEA lpofn, /* addess of structure with data*/
1287                            UINT dlgType /* type dialogue : open/save */
1288                           )
1289 {
1290     HINSTANCE hInst;
1291     BOOL bRet = FALSE;
1292     LFSPRIVATE lfs;
1293
1294     if (!lpofn || !FileDlg_Init()) return FALSE;
1295
1296     lfs = FILEDLG_AllocPrivate((LPARAM) lpofn, LFS32A, dlgType);
1297     if (lfs)
1298     {
1299         hInst = GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1300         bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner, 
1301              (DLGPROC) FileOpenDlgProc, (DWORD) lfs);
1302         FILEDLG_DestroyPrivate(lfs);
1303     }
1304
1305     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
1306     return bRet;
1307 }
1308
1309
1310 /***********************************************************************
1311  *           GetFileName31W                                 [internal]
1312  *
1313  * Creates a win31 style dialog box for the user to select a file to open/save
1314  */
1315 BOOL WINAPI GetFileName31W( 
1316                            LPOPENFILENAMEW lpofn, /* addess of structure with data*/
1317                            UINT dlgType /* type dialogue : open/save */
1318                           )
1319 {
1320     HINSTANCE hInst;
1321     BOOL bRet = FALSE;
1322     LFSPRIVATE lfs;
1323
1324     if (!lpofn || !FileDlg_Init()) return FALSE;
1325
1326     lfs = FILEDLG_AllocPrivate((LPARAM) lpofn, LFS32W, dlgType);
1327     if (lfs)
1328     {
1329         hInst = GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1330         bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner, 
1331              (DLGPROC) FileOpenDlgProc, (DWORD) lfs);
1332         FILEDLG_DestroyPrivate(lfs);
1333     }
1334
1335     TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn->lpstrFile));
1336     return bRet;
1337 }
1338
1339
1340 /* ------------------ Dialog procedures ---------------------- */
1341
1342 /***********************************************************************
1343  *           FileOpenDlgProc   (COMMDLG.6)
1344  */
1345 LRESULT WINAPI FileOpenDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
1346                                LPARAM lParam)
1347 {  
1348     LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1349     DRAWITEMSTRUCT dis;
1350  
1351     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1352     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1353         {
1354             LRESULT lRet = (BOOL16)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1355             if (lRet)   
1356                 return lRet;         /* else continue message processing */
1357         }
1358     switch (wMsg)
1359     {
1360     case WM_INITDIALOG:
1361         return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1362
1363     case WM_MEASUREITEM:
1364         return FILEDLG_WMMeasureItem16(hWnd, wParam, lParam);
1365
1366     case WM_DRAWITEM:
1367         FILEDLG_MapDrawItemStruct(MapSL(lParam), &dis);
1368         return FILEDLG_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis);
1369
1370     case WM_COMMAND:
1371         return FILEDLG_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs);
1372 #if 0
1373     case WM_CTLCOLOR:
1374          SetBkColor((HDC16)wParam, 0x00C0C0C0);
1375          switch (HIWORD(lParam))
1376          {
1377          case CTLCOLOR_BTN:
1378              SetTextColor((HDC16)wParam, 0x00000000);
1379              return hGRAYBrush;
1380         case CTLCOLOR_STATIC:
1381              SetTextColor((HDC16)wParam, 0x00000000);
1382              return hGRAYBrush;
1383         }
1384       break;
1385 #endif
1386     }
1387     return FALSE;
1388 }
1389
1390 /***********************************************************************
1391  *           FileSaveDlgProc   (COMMDLG.7)
1392  */
1393 LRESULT WINAPI FileSaveDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
1394                                LPARAM lParam)
1395 {
1396  LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1397  DRAWITEMSTRUCT dis;
1398
1399  TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1400  if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1401   {
1402    LRESULT  lRet;
1403    lRet = (BOOL16)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1404    if (lRet)   
1405     return lRet;         /* else continue message processing */
1406   }             
1407   switch (wMsg) {
1408    case WM_INITDIALOG:
1409       return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1410       
1411    case WM_MEASUREITEM:
1412       return FILEDLG_WMMeasureItem16(hWnd, wParam, lParam);
1413     
1414    case WM_DRAWITEM:
1415       FILEDLG_MapDrawItemStruct(MapSL(lParam), &dis);
1416       return FILEDLG_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis);
1417
1418    case WM_COMMAND:
1419       return FILEDLG_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs);
1420   }
1421   
1422   /*
1423   case WM_CTLCOLOR:
1424    SetBkColor((HDC16)wParam, 0x00C0C0C0);
1425    switch (HIWORD(lParam))
1426    {
1427     case CTLCOLOR_BTN:
1428      SetTextColor((HDC16)wParam, 0x00000000);
1429      return hGRAYBrush;
1430     case CTLCOLOR_STATIC:
1431      SetTextColor((HDC16)wParam, 0x00000000);
1432      return hGRAYBrush;
1433    }
1434    return FALSE;
1435    
1436    */
1437   return FALSE;
1438 }
1439
1440 /***********************************************************************
1441  *           FileOpenDlgProc                                    [internal]
1442  *      Used for open and save, in fact.   
1443  */
1444 static LRESULT WINAPI FileOpenDlgProc(HWND hWnd, UINT wMsg,
1445                                       WPARAM wParam, LPARAM lParam)
1446 {
1447     LFSPRIVATE lfs = (LFSPRIVATE)GetPropA(hWnd,OFN_PROP);
1448
1449     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
1450     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1451         {
1452             LRESULT lRet;
1453             lRet  = (BOOL)FILEDLG_CallWindowProc(lfs, wMsg, wParam, lParam);
1454             if (lRet)   
1455                 return lRet;         /* else continue message processing */
1456         }
1457     switch (wMsg)
1458     {
1459     case WM_INITDIALOG:
1460         return FILEDLG_WMInitDialog(hWnd, wParam, lParam);
1461
1462     case WM_MEASUREITEM:
1463         return FILEDLG_WMMeasureItem(hWnd, wParam, lParam);
1464
1465     case WM_DRAWITEM:
1466         return FILEDLG_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
1467
1468     case WM_COMMAND:
1469         return FILEDLG_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
1470 #if 0
1471     case WM_CTLCOLOR:
1472          SetBkColor((HDC16)wParam, 0x00C0C0C0);
1473          switch (HIWORD(lParam))
1474          {
1475          case CTLCOLOR_BTN:
1476              SetTextColor((HDC16)wParam, 0x00000000);
1477              return hGRAYBrush;
1478         case CTLCOLOR_STATIC:
1479              SetTextColor((HDC16)wParam, 0x00000000);
1480              return hGRAYBrush;
1481         }
1482       break;
1483 #endif
1484     }
1485     return FALSE;
1486 }
1487
1488 /* ------------------ APIs ---------------------- */ 
1489
1490 /***********************************************************************
1491  *           GetOpenFileName   (COMMDLG.1)
1492  *
1493  * Creates a dialog box for the user to select a file to open.
1494  *
1495  * RETURNS
1496  *    TRUE on success: user selected a valid file
1497  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1498  *
1499  * BUGS
1500  *    unknown, there are some FIXME's left.
1501  */
1502 BOOL16 WINAPI GetOpenFileName16( 
1503                                 SEGPTR ofn /* [in/out] address of structure with data*/
1504                                 )
1505 {
1506     HINSTANCE hInst;
1507     BOOL bRet = FALSE;
1508     LPOPENFILENAME16 lpofn = MapSL(ofn);
1509     LFSPRIVATE lfs;
1510     FARPROC16 ptr;
1511
1512     if (!lpofn || !FileDlg_Init()) return FALSE;
1513
1514     lfs = FILEDLG_AllocPrivate((LPARAM) ofn, LFS16, OPEN_DIALOG);
1515     if (lfs)
1516     {
1517         hInst = GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1518         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6);
1519         bRet = DialogBoxIndirectParam16( hInst, lfs->hDlgTmpl16, lpofn->hwndOwner, 
1520              (DLGPROC16) ptr, (DWORD) lfs);
1521         FILEDLG_DestroyPrivate(lfs);
1522     }
1523
1524     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
1525     return bRet;
1526 }
1527
1528 /***********************************************************************
1529  *           GetSaveFileName   (COMMDLG.2)
1530  *
1531  * Creates a dialog box for the user to select a file to save.
1532  *
1533  * RETURNS
1534  *    TRUE on success: user enters a valid file
1535  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1536  *
1537  * BUGS
1538  *    unknown. There are some FIXME's left.
1539  */
1540 BOOL16 WINAPI GetSaveFileName16( 
1541                                 SEGPTR ofn /* [in/out] addess of structure with data*/
1542                                 )
1543 {
1544     HINSTANCE hInst;
1545     BOOL bRet = FALSE;
1546     LPOPENFILENAME16 lpofn = MapSL(ofn);
1547     LFSPRIVATE lfs;
1548     FARPROC16 ptr;
1549
1550     if (!lpofn || !FileDlg_Init()) return FALSE;
1551
1552     lfs = FILEDLG_AllocPrivate((LPARAM) ofn, LFS16, SAVE_DIALOG);
1553     if (lfs)
1554     {
1555         hInst = GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
1556         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7);
1557         bRet = DialogBoxIndirectParam16( hInst, lfs->hDlgTmpl16, lpofn->hwndOwner, 
1558              (DLGPROC16) ptr, (DWORD) lfs);
1559         FILEDLG_DestroyPrivate(lfs);
1560     } 
1561
1562     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
1563     return bRet;
1564 }
1565
1566 /***********************************************************************
1567  *            GetOpenFileNameA  (COMDLG32.@)
1568  *
1569  * Creates a dialog box for the user to select a file to open.
1570  *
1571  * RETURNS
1572  *    TRUE on success: user enters a valid file
1573  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1574  *
1575  */
1576 BOOL WINAPI GetOpenFileNameA(
1577         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
1578 {
1579     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1580     COMDLG32_SetCommDlgExtendedError(0);
1581     /* some flags don't allow to match the TWEAK_WineLook */
1582     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1583     {
1584       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1585     }
1586
1587     if (newlook)
1588     {
1589         return GetFileDialog95A(ofn, OPEN_DIALOG);
1590     }
1591     else
1592     {
1593         return GetFileName31A(ofn, OPEN_DIALOG);
1594     }
1595 }
1596
1597 /***********************************************************************
1598  *            GetOpenFileNameW (COMDLG32.@)
1599  *
1600  * Creates a dialog box for the user to select a file to open.
1601  *
1602  * RETURNS
1603  *    TRUE on success: user enters a valid file
1604  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1605  *
1606  */
1607 BOOL WINAPI GetOpenFileNameW(
1608         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
1609 {
1610     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1611     COMDLG32_SetCommDlgExtendedError(0);
1612     /* some flags don't allow to match the TWEAK_WineLook */
1613     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1614     {
1615       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1616     }
1617
1618     if (newlook)
1619     {
1620         return GetFileDialog95W(ofn, OPEN_DIALOG);
1621     }
1622     else
1623     {
1624         return GetFileName31W(ofn, OPEN_DIALOG);
1625     }
1626 }
1627
1628 /***********************************************************************
1629  *            GetSaveFileNameA  (COMDLG32.@)
1630  *
1631  * Creates a dialog box for the user to select a file to save.
1632  *
1633  * RETURNS
1634  *    TRUE on success: user enters a valid file
1635  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1636  *
1637  */
1638 BOOL WINAPI GetSaveFileNameA(
1639         LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
1640 {
1641     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1642     COMDLG32_SetCommDlgExtendedError(0);
1643     /* some flags don't allow to match the TWEAK_WineLook */
1644     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1645     {
1646       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1647     }
1648
1649     if (newlook)
1650     {
1651         return GetFileDialog95A(ofn, SAVE_DIALOG);
1652     } 
1653     else
1654     {
1655         return GetFileName31A(ofn, SAVE_DIALOG);
1656     }
1657 }
1658
1659 /***********************************************************************
1660  *            GetSaveFileNameW  (COMDLG32.@)
1661  *
1662  * Creates a dialog box for the user to select a file to save.
1663  *
1664  * RETURNS
1665  *    TRUE on success: user enters a valid file
1666  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
1667  *
1668  */
1669 BOOL WINAPI GetSaveFileNameW(
1670         LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
1671 {
1672     BOOL  newlook = TRUE; /* FIXME: TWEAK_WineLook */
1673     COMDLG32_SetCommDlgExtendedError(0);
1674     /* some flags don't allow to match the TWEAK_WineLook */
1675     if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
1676     {
1677       newlook = (ofn->Flags & OFN_EXPLORER) ? TRUE : FALSE;
1678     }
1679
1680     if (newlook)
1681     {
1682         return GetFileDialog95W(ofn, SAVE_DIALOG);
1683     } 
1684     else
1685     {
1686         return GetFileName31W(ofn, SAVE_DIALOG);
1687     }
1688 }