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