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