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