wined3d: wined3d_device_get_scissor_rect() never fails.
[wine] / dlls / comdlg32 / filedlg31.c
1 /*
2  * Win 3.1 Style 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winuser.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33 #include "winreg.h"
34 #include "winternl.h"
35 #include "commdlg.h"
36 #include "shlwapi.h"
37 #include "cderr.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
40
41 #include "cdlg.h"
42
43 #define BUFFILE 512
44 #define BUFFILEALLOC 512 * sizeof(WCHAR)
45
46 static const WCHAR FILE_star[] = {'*','.','*', 0};
47 static const WCHAR FILE_bslash[] = {'\\', 0};
48 static const WCHAR FILE_specc[] = {'%','c',':', 0};
49 static const int fldrHeight = 16;
50 static const int fldrWidth = 20;
51
52 static HICON hFolder = 0;
53 static HICON hFolder2 = 0;
54 static HICON hFloppy = 0;
55 static HICON hHDisk = 0;
56 static HICON hCDRom = 0;
57 static HICON hNet = 0;
58
59 #define FD31_OFN_PROP "FILEDLG_OFN"
60
61 typedef struct tagFD31_DATA
62 {
63     HWND hwnd; /* file dialog window handle */
64     BOOL hook; /* TRUE if the dialog is hooked */
65     UINT lbselchstring; /* registered message id */
66     UINT fileokstring; /* registered message id */
67     LPARAM lParam; /* save original lparam */
68     LPCVOID template; /* template for 32 bits resource */
69     BOOL open; /* TRUE if open dialog, FALSE if save dialog */
70     LPOPENFILENAMEW ofnW; /* pointer either to the original structure or
71                              a W copy for A/16 API */
72     LPOPENFILENAMEA ofnA; /* original structure if 32bits ansi dialog */
73 } FD31_DATA, *PFD31_DATA;
74
75 /***********************************************************************
76  *                              FD31_Init                       [internal]
77  */
78 static BOOL FD31_Init(void)
79 {
80     static BOOL initialized = 0;
81
82     if (!initialized) {
83         hFolder  = LoadImageA( COMDLG32_hInstance, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED );
84         hFolder2 = LoadImageA( COMDLG32_hInstance, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED );
85         hFloppy  = LoadImageA( COMDLG32_hInstance, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED );
86         hHDisk   = LoadImageA( COMDLG32_hInstance, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED );
87         hCDRom   = LoadImageA( COMDLG32_hInstance, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED );
88         hNet     = LoadImageA( COMDLG32_hInstance, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED );
89         if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 ||
90             hHDisk == 0 || hCDRom == 0 || hNet == 0)
91         {
92             ERR("Error loading icons !\n");
93             return FALSE;
94         }
95         initialized = TRUE;
96     }
97     return TRUE;
98 }
99
100 /***********************************************************************
101  *                              FD31_StripEditControl        [internal]
102  * Strip pathnames off the contents of the edit control.
103  */
104 static void FD31_StripEditControl(HWND hwnd)
105 {
106     WCHAR temp[BUFFILE], *cp;
107
108     GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR));
109     cp = strrchrW(temp, '\\');
110     if (cp != NULL) {
111         strcpyW(temp, cp+1);
112     }
113     cp = strrchrW(temp, ':');
114     if (cp != NULL) {
115         strcpyW(temp, cp+1);
116     }
117     /* FIXME: shouldn't we do something with the result here? ;-) */
118 }
119
120 /***********************************************************************
121  *                              FD31_CallWindowProc          [internal]
122  *
123  *      Call the appropriate hook
124  */
125 static BOOL FD31_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam, LPARAM lParam)
126 {
127     BOOL ret;
128
129     if (lfs->ofnA)
130     {
131         TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
132                lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
133         ret = lfs->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
134         TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
135                lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
136         return ret;
137     }
138
139     TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
140            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
141     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
142     TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
143            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
144     return ret;
145 }
146
147 /***********************************************************************
148  *                              FD31_GetFileType                [internal]
149  */
150 static LPCWSTR FD31_GetFileType(LPCWSTR cfptr, LPCWSTR fptr, const WORD index)
151 {
152   int n, i;
153   i = 0;
154   if (cfptr)
155     for ( ;(n = lstrlenW(cfptr)) != 0; i++)
156       {
157         cfptr += n + 1;
158         if (i == index)
159           return cfptr;
160         cfptr += lstrlenW(cfptr) + 1;
161       }
162   if (fptr)
163     for ( ;(n = lstrlenW(fptr)) != 0; i++)
164       {
165         fptr += n + 1;
166         if (i == index)
167           return fptr;
168         fptr += lstrlenW(fptr) + 1;
169     }
170   return FILE_star; /* FIXME */
171 }
172
173 /***********************************************************************
174  *                              FD31_ScanDir                 [internal]
175  */
176 static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
177 {
178     WCHAR   buffer[BUFFILE];
179     HWND    hdlg;
180     LRESULT lRet = TRUE;
181     HCURSOR hCursorWait, oldCursor;
182
183     TRACE("Trying to change to %s\n", debugstr_w(newPath));
184     if  ( newPath[0] && !SetCurrentDirectoryW( newPath ))
185         return FALSE;
186
187     /* get the list of spec files */
188     lstrcpynW(buffer, FD31_GetFileType(ofn->lpstrCustomFilter,
189               ofn->lpstrFilter, ofn->nFilterIndex - 1), BUFFILE);
190
191     hCursorWait = LoadCursorA(0, (LPSTR)IDC_WAIT);
192     oldCursor = SetCursor(hCursorWait);
193
194     /* list of files */
195     if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) {
196         WCHAR*  scptr; /* ptr on semi-colon */
197         WCHAR*  filter = buffer;
198
199         TRACE("Using filter %s\n", debugstr_w(filter));
200         SendMessageW(hdlg, LB_RESETCONTENT, 0, 0);
201         while (filter) {
202             scptr = strchrW(filter, ';');
203             if (scptr)  *scptr = 0;
204             while (*filter == ' ') filter++;
205             TRACE("Using file spec %s\n", debugstr_w(filter));
206             SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter);
207             if (scptr) *scptr = ';';
208                 filter = (scptr) ? (scptr + 1) : 0;
209          }
210     }
211
212     /* list of directories */
213     strcpyW(buffer, FILE_star);
214
215     if (GetDlgItem(hWnd, lst2) != 0) {
216         lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY);
217     }
218     SetCursor(oldCursor);
219     return lRet;
220 }
221
222 /***********************************************************************
223  *                              FD31_WMDrawItem              [internal]
224  */
225 static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
226                             int savedlg, const DRAWITEMSTRUCT *lpdis)
227 {
228     WCHAR *str;
229     HICON hIcon;
230     COLORREF oldText = 0, oldBk = 0;
231
232     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1)
233     {
234         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE;
235         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
236                       (LPARAM)str);
237
238         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
239         {
240             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
241             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
242         }
243         if (savedlg)
244             SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) );
245
246         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1,
247                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
248                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
249
250         if (lpdis->itemState & ODS_SELECTED)
251             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
252
253         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
254         {
255             SetBkColor( lpdis->hDC, oldBk );
256             SetTextColor( lpdis->hDC, oldText );
257         }
258         HeapFree(GetProcessHeap(), 0, str);
259         return TRUE;
260     }
261
262     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2)
263     {
264         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
265             return FALSE;
266         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
267                       (LPARAM)str);
268
269         if (lpdis->itemState & ODS_SELECTED)
270         {
271             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
272             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
273         }
274         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
275                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
276                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
277
278         if (lpdis->itemState & ODS_SELECTED)
279             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
280
281         if (lpdis->itemState & ODS_SELECTED)
282         {
283             SetBkColor( lpdis->hDC, oldBk );
284             SetTextColor( lpdis->hDC, oldText );
285         }
286         DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder, 16, 16, 0, 0, DI_NORMAL );
287         HeapFree(GetProcessHeap(), 0, str);
288         return TRUE;
289     }
290     if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2)
291     {
292         char root[] = "a:";
293         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
294             return FALSE;
295         SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID,
296                       (LPARAM)str);
297         root[0] += str[2] - 'a';
298         switch(GetDriveTypeA(root))
299         {
300         case DRIVE_REMOVABLE: hIcon = hFloppy; break;
301         case DRIVE_CDROM:     hIcon = hCDRom; break;
302         case DRIVE_REMOTE:    hIcon = hNet; break;
303         case DRIVE_FIXED:
304         default:           hIcon = hHDisk; break;
305         }
306         if (lpdis->itemState & ODS_SELECTED)
307         {
308             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
309             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
310         }
311         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
312                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
313                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
314
315         if (lpdis->itemState & ODS_SELECTED)
316         {
317             SetBkColor( lpdis->hDC, oldBk );
318             SetTextColor( lpdis->hDC, oldText );
319         }
320         DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon, 16, 16, 0, 0, DI_NORMAL );
321         HeapFree(GetProcessHeap(), 0, str);
322         return TRUE;
323     }
324     return FALSE;
325 }
326
327 /***********************************************************************
328  *                              FD31_UpdateResult            [internal]
329  *      update the displayed file name (with path)
330  */
331 static void FD31_UpdateResult(const FD31_DATA *lfs, const WCHAR *tmpstr)
332 {
333     int lenstr2;
334     LPOPENFILENAMEW ofnW = lfs->ofnW;
335     LPOPENFILENAMEA ofnA = lfs->ofnA;
336     WCHAR tmpstr2[BUFFILE];
337     WCHAR *p;
338
339     TRACE("%s\n", debugstr_w(tmpstr));
340     if(ofnW->Flags & OFN_NOVALIDATE)
341         tmpstr2[0] = '\0';
342     else
343         GetCurrentDirectoryW(BUFFILE, tmpstr2);
344     lenstr2 = strlenW(tmpstr2);
345     if (lenstr2 > 3)
346         tmpstr2[lenstr2++]='\\';
347     lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2);
348     if (!ofnW->lpstrFile)
349         return;
350
351     lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile);
352
353     /* set filename offset */
354     p = PathFindFileNameW(ofnW->lpstrFile);
355     ofnW->nFileOffset = (p - ofnW->lpstrFile);
356
357     /* set extension offset */
358     p = PathFindExtensionW(ofnW->lpstrFile);
359     ofnW->nFileExtension = (*p) ? (p - ofnW->lpstrFile) + 1 : 0;
360
361     TRACE("file %s, file offset %d, ext offset %d\n",
362           debugstr_w(ofnW->lpstrFile), ofnW->nFileOffset, ofnW->nFileExtension);
363
364     /* update the real client structures if any */
365     if (ofnA)
366     {
367         LPSTR lpszTemp;
368         if (ofnW->nMaxFile &&
369             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
370                                   ofnA->lpstrFile, ofnA->nMaxFile, NULL, NULL ))
371             ofnA->lpstrFile[ofnA->nMaxFile-1] = 0;
372
373         /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
374         /* set filename offset */
375         lpszTemp = PathFindFileNameA(ofnA->lpstrFile);
376         ofnA->nFileOffset = (lpszTemp - ofnA->lpstrFile);
377
378         /* set extension offset */
379         lpszTemp = PathFindExtensionA(ofnA->lpstrFile);
380         ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - ofnA->lpstrFile) + 1 : 0;
381     }
382 }
383
384 /***********************************************************************
385  *                              FD31_UpdateFileTitle         [internal]
386  *      update the displayed file name (without path)
387  */
388 static void FD31_UpdateFileTitle(const FD31_DATA *lfs)
389 {
390   LONG lRet;
391   LPOPENFILENAMEW ofnW = lfs->ofnW;
392   LPOPENFILENAMEA ofnA = lfs->ofnA;
393
394   if (ofnW->lpstrFileTitle != NULL)
395   {
396     lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
397     SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet,
398                              (LPARAM)ofnW->lpstrFileTitle );
399     if (ofnA)
400     {
401         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
402                                   ofnA->lpstrFileTitle, ofnA->nMaxFileTitle, NULL, NULL ))
403             ofnA->lpstrFileTitle[ofnA->nMaxFileTitle-1] = 0;
404     }
405   }
406 }
407
408 /***********************************************************************
409  *                              FD31_DirListDblClick         [internal]
410  */
411 static LRESULT FD31_DirListDblClick( const FD31_DATA *lfs )
412 {
413   LONG lRet;
414   HWND hWnd = lfs->hwnd;
415   LPWSTR pstr;
416   WCHAR tmpstr[BUFFILE];
417
418   /* get the raw string (with brackets) */
419   lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
420   if (lRet == LB_ERR) return TRUE;
421   pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
422   SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
423                      (LPARAM)pstr);
424   strcpyW( tmpstr, pstr );
425   HeapFree(GetProcessHeap(), 0, pstr);
426   /* get the selected directory in tmpstr */
427   if (tmpstr[0] == '[')
428     {
429       tmpstr[lstrlenW(tmpstr) - 1] = 0;
430       strcpyW(tmpstr,tmpstr+1);
431     }
432   strcatW(tmpstr, FILE_bslash);
433
434   FD31_ScanDir(lfs->ofnW, hWnd, tmpstr);
435   /* notify the app */
436   if (lfs->hook)
437     {
438       if (FD31_CallWindowProc(lfs, lfs->lbselchstring, lst2,
439               MAKELONG(lRet,CD_LBSELCHANGE)))
440         return TRUE;
441     }
442   return TRUE;
443 }
444
445 /***********************************************************************
446  *                              FD31_FileListSelect         [internal]
447  *    called when a new item is picked in the file list
448  */
449 static LRESULT FD31_FileListSelect( const FD31_DATA *lfs )
450 {
451     LONG lRet;
452     HWND hWnd = lfs->hwnd;
453     LPWSTR pstr;
454
455     lRet =  SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
456     if (lRet == LB_ERR)
457         return TRUE;
458
459     /* set the edit control to the chosen file */
460     if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
461     {
462         SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
463                        (LPARAM)pstr);
464         SetDlgItemTextW( hWnd, edt1, pstr );
465         HeapFree(GetProcessHeap(), 0, pstr);
466     }
467     if (lfs->hook)
468     {
469         FD31_CallWindowProc(lfs, lfs->lbselchstring, lst1,
470                            MAKELONG(lRet,CD_LBSELCHANGE));
471     }
472     /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD,
473            CD_LBSELNOITEMS */
474     return TRUE;
475 }
476
477 /***********************************************************************
478  *                              FD31_TestPath      [internal]
479  *      before accepting the file name, test if it includes wild cards
480  *      tries to scan the directory and returns TRUE if no error.
481  */
482 static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
483 {
484     HWND hWnd = lfs->hwnd;
485     LPWSTR pBeginFileName, pstr2;
486     WCHAR tmpstr2[BUFFILE];
487
488     pBeginFileName = strrchrW(path, '\\');
489     if (pBeginFileName == NULL)
490         pBeginFileName = strrchrW(path, ':');
491
492     if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL)
493     {
494         /* edit control contains wildcards */
495         if (pBeginFileName != NULL)
496         {
497             lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE);
498             *(pBeginFileName + 1) = 0;
499         }
500         else
501         {
502             strcpyW(tmpstr2, path);
503             if(!(lfs->ofnW->Flags & OFN_NOVALIDATE))
504                 *path = 0;
505         }
506
507         TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
508         SetDlgItemTextW( hWnd, edt1, tmpstr2 );
509         FD31_ScanDir(lfs->ofnW, hWnd, path);
510         return (lfs->ofnW->Flags & OFN_NOVALIDATE) != 0;
511     }
512
513     /* no wildcards, we might have a directory or a filename */
514     /* try appending a wildcard and reading the directory */
515
516     pstr2 = path + lstrlenW(path);
517     if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
518         strcatW(path, FILE_bslash);
519
520     /* if ScanDir succeeds, we have changed the directory */
521     if (FD31_ScanDir(lfs->ofnW, hWnd, path))
522         return FALSE; /* and path is not a valid file name */
523
524     /* if not, this must be a filename */
525
526     *pstr2 = 0; /* remove the wildcard added before */
527
528     if (pBeginFileName != NULL)
529     {
530         /* strip off the pathname */
531         *pBeginFileName = 0;
532         SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 );
533
534         lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) );
535         /* Should we MessageBox() if this fails? */
536         if (!FD31_ScanDir(lfs->ofnW, hWnd, path))
537         {
538             return FALSE;
539         }
540         strcpyW(path, tmpstr2);
541     }
542     else
543         SetDlgItemTextW( hWnd, edt1, path );
544     return TRUE;
545 }
546
547 /***********************************************************************
548  *                              FD31_Validate               [internal]
549  *   called on: click Ok button, Enter in edit, DoubleClick in file list
550  */
551 static LRESULT FD31_Validate( const FD31_DATA *lfs, LPCWSTR path, UINT control, INT itemIndex,
552                                  BOOL internalUse )
553 {
554     LONG lRet;
555     HWND hWnd = lfs->hwnd;
556     OPENFILENAMEW ofnsav;
557     LPOPENFILENAMEW ofnW = lfs->ofnW;
558     WCHAR filename[BUFFILE];
559
560     ofnsav = *ofnW; /* for later restoring */
561
562     /* get current file name */
563     if (path)
564         lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR));
565     else
566         GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR));
567
568     TRACE("got filename = %s\n", debugstr_w(filename));
569     /* if we did not click in file list to get there */
570     if (control != lst1)
571     {
572         if (!FD31_TestPath( lfs, filename) )
573            return FALSE;
574     }
575     FD31_UpdateResult(lfs, filename);
576
577     if (internalUse)
578     { /* called internally after a change in a combo */
579         if (lfs->hook)
580         {
581              FD31_CallWindowProc(lfs, lfs->lbselchstring, control,
582                              MAKELONG(itemIndex,CD_LBSELCHANGE));
583         }
584         return TRUE;
585     }
586
587     FD31_UpdateFileTitle(lfs);
588     if (lfs->hook)
589     {
590         lRet = FD31_CallWindowProc(lfs, lfs->fileokstring,
591                   0, lfs->lParam );
592         if (lRet)
593         {
594             *ofnW = ofnsav; /* restore old state */
595             return FALSE;
596         }
597     }
598     if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER))
599     {
600         if (ofnW->lpstrFile)
601         {
602             LPWSTR str = ofnW->lpstrFile;
603             LPWSTR ptr = strrchrW(str, '\\');
604             str[lstrlenW(str) + 1] = '\0';
605             *ptr = 0;
606         }
607     }
608     return TRUE;
609 }
610
611 /***********************************************************************
612  *                              FD31_DiskChange             [internal]
613  *    called when a new item is picked in the disk selection combo
614  */
615 static LRESULT FD31_DiskChange( const FD31_DATA *lfs )
616 {
617     LONG lRet;
618     HWND hWnd = lfs->hwnd;
619     LPWSTR pstr;
620     WCHAR diskname[BUFFILE];
621
622     FD31_StripEditControl(hWnd);
623     lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L);
624     if (lRet == LB_ERR)
625         return 0;
626     pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
627     SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
628                          (LPARAM)pstr);
629     wsprintfW(diskname, FILE_specc, pstr[2]);
630     HeapFree(GetProcessHeap(), 0, pstr);
631
632     return FD31_Validate( lfs, diskname, cmb2, lRet, TRUE );
633 }
634
635 /***********************************************************************
636  *                              FD31_FileTypeChange         [internal]
637  *    called when a new item is picked in the file type combo
638  */
639 static LRESULT FD31_FileTypeChange( const FD31_DATA *lfs )
640 {
641     LONG lRet;
642     LPWSTR pstr;
643
644     lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0);
645     if (lRet == LB_ERR)
646         return TRUE;
647     lfs->ofnW->nFilterIndex = lRet + 1;
648     if (lfs->ofnA)
649         lfs->ofnA->nFilterIndex = lRet + 1;
650     pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0);
651     TRACE("Selected filter : %s\n", debugstr_w(pstr));
652
653     return FD31_Validate( lfs, pstr, cmb1, lRet, TRUE );
654 }
655
656 /***********************************************************************
657  *                              FD31_WMCommand               [internal]
658  */
659 static LRESULT FD31_WMCommand( HWND hWnd, LPARAM lParam, UINT notification,
660                                UINT control, const FD31_DATA *lfs )
661 {
662     switch (control)
663     {
664         case lst1: /* file list */
665         FD31_StripEditControl(hWnd);
666         if (notification == LBN_DBLCLK)
667         {
668             return SendMessageW(hWnd, WM_COMMAND, IDOK, 0);
669         }
670         else if (notification == LBN_SELCHANGE)
671             return FD31_FileListSelect( lfs );
672         break;
673
674         case lst2: /* directory list */
675         FD31_StripEditControl(hWnd);
676         if (notification == LBN_DBLCLK)
677             return FD31_DirListDblClick( lfs );
678         break;
679
680         case cmb1: /* file type drop list */
681         if (notification == CBN_SELCHANGE)
682             return FD31_FileTypeChange( lfs );
683         break;
684
685         case chx1:
686         break;
687
688         case pshHelp:
689         break;
690
691         case cmb2: /* disk dropdown combo */
692         if (notification == CBN_SELCHANGE)
693             return FD31_DiskChange( lfs );
694         break;
695
696         case IDOK:
697         TRACE("OK pressed\n");
698         if (FD31_Validate( lfs, NULL, control, 0, FALSE ))
699             EndDialog(hWnd, TRUE);
700         return TRUE;
701
702         case IDCANCEL:
703         EndDialog(hWnd, FALSE);
704         return TRUE;
705
706         case IDABORT: /* can be sent by the hook procedure */
707         EndDialog(hWnd, TRUE);
708         return TRUE;
709     }
710     return FALSE;
711 }
712
713 /************************************************************************
714  *                              FD31_MapStringPairsToW       [internal]
715  *      map string pairs to Unicode
716  */
717 static LPWSTR FD31_MapStringPairsToW(LPCSTR strA, UINT size)
718 {
719     LPCSTR s;
720     LPWSTR x;
721     unsigned int n, len;
722
723     s = strA;
724     while (*s)
725         s = s+strlen(s)+1;
726     s++;
727     n = s + 1 - strA; /* Don't forget the other \0 */
728     if (n < size) n = size;
729
730     len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 );
731     x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR));
732     MultiByteToWideChar( CP_ACP, 0, strA, n, x, len );
733     return x;
734 }
735
736
737 /************************************************************************
738  *                              FD31_DupToW                  [internal]
739  *      duplicates an Ansi string to unicode, with a buffer size
740  */
741 static LPWSTR FD31_DupToW(LPCSTR str, DWORD size)
742 {
743     LPWSTR strW = NULL;
744     if (str && (size > 0))
745     {
746         strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
747         if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size );
748     }
749     return strW;
750 }
751
752 /************************************************************************
753  *                              FD31_MapOfnStructA          [internal]
754  *      map a 32 bits Ansi structure to a Unicode one
755  */
756 static void FD31_MapOfnStructA(const OPENFILENAMEA *ofnA, LPOPENFILENAMEW ofnW, BOOL open)
757 {
758     UNICODE_STRING usBuffer;
759
760     ofnW->lStructSize = sizeof(OPENFILENAMEW);
761     ofnW->hwndOwner = ofnA->hwndOwner;
762     ofnW->hInstance = ofnA->hInstance;
763     if (ofnA->lpstrFilter)
764         ofnW->lpstrFilter = FD31_MapStringPairsToW(ofnA->lpstrFilter, 0);
765
766     if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter)))
767         ofnW->lpstrCustomFilter = FD31_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter);
768     ofnW->nMaxCustFilter = ofnA->nMaxCustFilter;
769     ofnW->nFilterIndex = ofnA->nFilterIndex;
770     ofnW->nMaxFile = ofnA->nMaxFile;
771     ofnW->lpstrFile = FD31_DupToW(ofnA->lpstrFile, ofnW->nMaxFile);
772     ofnW->nMaxFileTitle = ofnA->nMaxFileTitle;
773     ofnW->lpstrFileTitle = FD31_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle);
774     if (ofnA->lpstrInitialDir)
775     {
776         RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrInitialDir);
777         ofnW->lpstrInitialDir = usBuffer.Buffer;
778     }
779     if (ofnA->lpstrTitle) {
780         RtlCreateUnicodeStringFromAsciiz (&usBuffer, ofnA->lpstrTitle);
781         ofnW->lpstrTitle = usBuffer.Buffer;
782     } else {
783         WCHAR buf[16];
784         LPWSTR title_tmp;
785         int len;
786         LoadStringW(COMDLG32_hInstance, open ? IDS_OPEN_FILE : IDS_SAVE_AS,
787                     buf, sizeof(buf)/sizeof(WCHAR));
788         len = lstrlenW(buf)+1;
789         title_tmp = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
790         memcpy(title_tmp, buf, len * sizeof(WCHAR));
791         ofnW->lpstrTitle = title_tmp;
792     }
793     ofnW->Flags = ofnA->Flags;
794     ofnW->nFileOffset = ofnA->nFileOffset;
795     ofnW->nFileExtension = ofnA->nFileExtension;
796     ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3);
797     if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
798     {
799         if (!IS_INTRESOURCE(ofnA->lpTemplateName))
800         {
801             RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName);
802             ofnW->lpTemplateName = usBuffer.Buffer;
803         }
804         else /* numbered resource */
805             ofnW->lpTemplateName = (LPCWSTR) ofnA->lpTemplateName;
806     }
807 }
808
809
810 /************************************************************************
811  *                              FD31_FreeOfnW          [internal]
812  *      Undo all allocations done by FD31_MapOfnStructA
813  */
814 static void FD31_FreeOfnW(OPENFILENAMEW *ofnW)
815 {
816    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter);
817    HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter);
818    HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile);
819    HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle);
820    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir);
821    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle);
822    if (!IS_INTRESOURCE(ofnW->lpTemplateName))
823        HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName);
824 }
825
826 /************************************************************************
827  *                              FD31_DestroyPrivate            [internal]
828  *      destroys the private object
829  */
830 static void FD31_DestroyPrivate(PFD31_DATA lfs)
831 {
832     HWND hwnd;
833     if (!lfs) return;
834     hwnd = lfs->hwnd;
835     TRACE("destroying private allocation %p\n", lfs);
836
837     /* if ofnW has been allocated, have to free everything in it */
838     if (lfs->ofnA)
839     {
840         FD31_FreeOfnW(lfs->ofnW);
841         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
842     }
843     HeapFree(GetProcessHeap(), 0, lfs);
844     RemovePropA(hwnd, FD31_OFN_PROP);
845 }
846
847 /***********************************************************************
848  *           FD31_GetTemplate                                  [internal]
849  *
850  * Get a template (or FALSE if failure) when 16 bits dialogs are used
851  * by a 32 bits application
852  *
853  */
854 static BOOL FD31_GetTemplate(PFD31_DATA lfs)
855 {
856     LPOPENFILENAMEW ofnW = lfs->ofnW;
857     LPOPENFILENAMEA ofnA = lfs->ofnA;
858     HANDLE hDlgTmpl;
859
860     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
861     {
862         if (!(lfs->template = LockResource( ofnW->hInstance )))
863         {
864             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
865             return FALSE;
866         }
867     }
868     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
869     {
870         HRSRC hResInfo;
871         if (ofnA)
872             hResInfo = FindResourceA( ofnA->hInstance, ofnA->lpTemplateName, (LPSTR)RT_DIALOG );
873         else
874             hResInfo = FindResourceW( ofnW->hInstance, ofnW->lpTemplateName, (LPWSTR)RT_DIALOG );
875         if (!hResInfo)
876         {
877             COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
878             return FALSE;
879         }
880         if (!(hDlgTmpl = LoadResource( ofnW->hInstance, hResInfo )) ||
881             !(lfs->template = LockResource( hDlgTmpl )))
882         {
883             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
884             return FALSE;
885         }
886     }
887     else /* get it from internal Wine resource */
888     {
889         HRSRC hResInfo;
890         if (!(hResInfo = FindResourceA( COMDLG32_hInstance, lfs->open ? "OPEN_FILE" : "SAVE_FILE", (LPSTR)RT_DIALOG )))
891         {
892             COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
893             return FALSE;
894         }
895         if (!(hDlgTmpl = LoadResource( COMDLG32_hInstance, hResInfo )) ||
896             !(lfs->template = LockResource( hDlgTmpl )))
897         {
898             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
899             return FALSE;
900         }
901     }
902     return TRUE;
903 }
904
905 /************************************************************************
906  *                              FD31_AllocPrivate            [internal]
907  *      allocate a private object to hold 32 bits Unicode
908  *      structure that will be used throughout the calls, while
909  *      keeping available the original structures and a few variables
910  *      On entry : type = dialog procedure type (16,32A,32W)
911  *                 dlgType = dialog type (open or save)
912  */
913 static PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, BOOL IsUnicode)
914 {
915     PFD31_DATA lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD31_DATA));
916
917     TRACE("alloc private buf %p\n", lfs);
918     if (!lfs) return NULL;
919     lfs->hook = FALSE;
920     lfs->lParam = lParam;
921     lfs->open = (dlgType == OPEN_DIALOG);
922
923     if (IsUnicode)
924     {
925         lfs->ofnA = NULL;
926         lfs->ofnW = (LPOPENFILENAMEW) lParam;
927         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
928             if (lfs->ofnW->lpfnHook)
929                 lfs->hook = TRUE;
930     }
931     else
932     {
933         lfs->ofnA = (LPOPENFILENAMEA) lParam;
934         if (lfs->ofnA->Flags & OFN_ENABLEHOOK)
935             if (lfs->ofnA->lpfnHook)
936                 lfs->hook = TRUE;
937         lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
938         FD31_MapOfnStructA(lfs->ofnA, lfs->ofnW, lfs->open);
939     }
940
941     if (! FD31_GetTemplate(lfs))
942     {
943         FD31_DestroyPrivate(lfs);
944         return NULL;
945     }
946     lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
947     lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
948
949     return lfs;
950 }
951
952 /***********************************************************************
953  *                              FD31_WMInitDialog            [internal]
954  */
955 static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
956 {
957   int i, n;
958   WCHAR tmpstr[BUFFILE];
959   LPWSTR pstr, old_pstr;
960   LPOPENFILENAMEW ofn;
961   PFD31_DATA lfs = (PFD31_DATA) lParam;
962
963   if (!lfs) return FALSE;
964   SetPropA(hWnd, FD31_OFN_PROP, lfs);
965   lfs->hwnd = hWnd;
966   ofn = lfs->ofnW;
967
968   TRACE("flags=%x initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir));
969
970   SetWindowTextW( hWnd, ofn->lpstrTitle );
971   /* read custom filter information */
972   if (ofn->lpstrCustomFilter)
973     {
974       pstr = ofn->lpstrCustomFilter;
975       n = 0;
976       TRACE("lpstrCustomFilter = %p\n", pstr);
977       while(*pstr)
978         {
979           old_pstr = pstr;
980           i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
981                                    (LPARAM)(ofn->lpstrCustomFilter) + n );
982           n += lstrlenW(pstr) + 1;
983           pstr += lstrlenW(pstr) + 1;
984           TRACE("add str=%s associated to %s\n",
985                 debugstr_w(old_pstr), debugstr_w(pstr));
986           SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
987           n += lstrlenW(pstr) + 1;
988           pstr += lstrlenW(pstr) + 1;
989         }
990     }
991   /* read filter information */
992   if (ofn->lpstrFilter) {
993         pstr = (LPWSTR) ofn->lpstrFilter;
994         n = 0;
995         while(*pstr) {
996           old_pstr = pstr;
997           i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
998                                        (LPARAM)(ofn->lpstrFilter + n) );
999           n += lstrlenW(pstr) + 1;
1000           pstr += lstrlenW(pstr) + 1;
1001           TRACE("add str=%s associated to %s\n",
1002                 debugstr_w(old_pstr), debugstr_w(pstr));
1003           SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
1004           n += lstrlenW(pstr) + 1;
1005           pstr += lstrlenW(pstr) + 1;
1006         }
1007   }
1008   /* set default filter */
1009   if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL)
1010         ofn->nFilterIndex = 1;
1011   SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0);
1012   if (ofn->lpstrFile && ofn->lpstrFile[0])
1013   {
1014     TRACE( "SetText of edt1 to %s\n", debugstr_w(ofn->lpstrFile) );
1015     SetDlgItemTextW( hWnd, edt1, ofn->lpstrFile );
1016   }
1017   else
1018   {
1019     lstrcpynW(tmpstr, FD31_GetFileType(ofn->lpstrCustomFilter,
1020              ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE);
1021     TRACE("nFilterIndex = %d, SetText of edt1 to %s\n",
1022                         ofn->nFilterIndex, debugstr_w(tmpstr));
1023     SetDlgItemTextW( hWnd, edt1, tmpstr );
1024   }
1025   /* get drive list */
1026   *tmpstr = 0;
1027   DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE);
1028   /* read initial directory */
1029   /* FIXME: Note that this is now very version-specific (See MSDN description of
1030    * the OPENFILENAME structure).  For example under 2000/XP any path in the
1031    * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME
1032    */
1033   if (ofn->lpstrInitialDir != NULL)
1034     {
1035       int len;
1036       lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511);
1037       len = lstrlenW(tmpstr);
1038       if (len > 0 && tmpstr[len-1] != '\\'  && tmpstr[len-1] != ':') {
1039         tmpstr[len]='\\';
1040         tmpstr[len+1]='\0';
1041       }
1042     }
1043   else
1044     *tmpstr = 0;
1045   if (!FD31_ScanDir(ofn, hWnd, tmpstr)) {
1046     *tmpstr = 0;
1047     if (!FD31_ScanDir(ofn, hWnd, tmpstr))
1048       WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
1049   }
1050   /* select current drive in combo 2, omit missing drives */
1051   {
1052       char dir[MAX_PATH];
1053       char str[4] = "a:\\";
1054       GetCurrentDirectoryA( sizeof(dir), dir );
1055       for(i = 0, n = -1; i < 26; i++)
1056       {
1057           str[0] = 'a' + i;
1058           if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++;
1059           if (toupper(str[0]) == toupper(dir[0])) break;
1060       }
1061   }
1062   SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0);
1063   if (!(ofn->Flags & OFN_SHOWHELP))
1064     ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
1065   if (ofn->Flags & OFN_HIDEREADONLY)
1066     ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
1067   if (lfs->hook)
1068       return FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
1069   return TRUE;
1070 }
1071
1072 int FD31_GetFldrHeight(void)
1073 {
1074   return fldrHeight;
1075 }
1076
1077 /***********************************************************************
1078  *                              FD31_WMMeasureItem           [internal]
1079  */
1080 static LONG FD31_WMMeasureItem(LPARAM lParam)
1081 {
1082     LPMEASUREITEMSTRUCT lpmeasure;
1083
1084     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
1085     lpmeasure->itemHeight = FD31_GetFldrHeight();
1086     return TRUE;
1087 }
1088
1089
1090 /***********************************************************************
1091  *           FileOpenDlgProc                                    [internal]
1092  *      Used for open and save, in fact.
1093  */
1094 static INT_PTR CALLBACK FD31_FileOpenDlgProc(HWND hWnd, UINT wMsg,
1095                                              WPARAM wParam, LPARAM lParam)
1096 {
1097     PFD31_DATA lfs = (PFD31_DATA)GetPropA( hWnd, FD31_OFN_PROP );
1098
1099     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
1100     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1101     {
1102         INT_PTR lRet;
1103         lRet  = (INT_PTR)FD31_CallWindowProc( lfs, wMsg, wParam, lParam );
1104         if (lRet) return lRet;   /* else continue message processing */
1105     }
1106     switch (wMsg)
1107     {
1108     case WM_INITDIALOG:
1109         return FD31_WMInitDialog( hWnd, wParam, lParam );
1110
1111     case WM_MEASUREITEM:
1112         return FD31_WMMeasureItem( lParam );
1113
1114     case WM_DRAWITEM:
1115         return FD31_WMDrawItem( hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam );
1116
1117     case WM_COMMAND:
1118         return FD31_WMCommand( hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs );
1119 #if 0
1120     case WM_CTLCOLOR:
1121         SetBkColor( (HDC16)wParam, 0x00C0C0C0 );
1122         switch (HIWORD(lParam))
1123         {
1124         case CTLCOLOR_BTN:
1125             SetTextColor( (HDC16)wParam, 0x00000000 );
1126             return hGRAYBrush;
1127         case CTLCOLOR_STATIC:
1128             SetTextColor( (HDC16)wParam, 0x00000000 );
1129             return hGRAYBrush;
1130         }
1131         break;
1132 #endif
1133     }
1134     return FALSE;
1135 }
1136
1137 /***********************************************************************
1138  *           GetFileName31A                                 [internal]
1139  *
1140  * Creates a win31 style dialog box for the user to select a file to open/save.
1141  */
1142 BOOL GetFileName31A( OPENFILENAMEA *lpofn, UINT dlgType )
1143 {
1144     BOOL bRet = FALSE;
1145     PFD31_DATA lfs;
1146
1147     if (!lpofn || !FD31_Init()) return FALSE;
1148
1149     TRACE("ofn flags %08x\n", lpofn->Flags);
1150     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
1151     if (lfs)
1152     {
1153         bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1154                                         FD31_FileOpenDlgProc, (LPARAM)lfs);
1155         FD31_DestroyPrivate(lfs);
1156     }
1157
1158     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
1159     return bRet;
1160 }
1161
1162 /***********************************************************************
1163  *           GetFileName31W                                 [internal]
1164  *
1165  * Creates a win31 style dialog box for the user to select a file to open/save
1166  */
1167 BOOL GetFileName31W( OPENFILENAMEW *lpofn, UINT dlgType )
1168 {
1169     BOOL bRet = FALSE;
1170     PFD31_DATA lfs;
1171
1172     if (!lpofn || !FD31_Init()) return FALSE;
1173
1174     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
1175     if (lfs)
1176     {
1177         bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1178                                         FD31_FileOpenDlgProc, (LPARAM)lfs);
1179         FD31_DestroyPrivate(lfs);
1180     }
1181
1182     TRACE("file %s, file offset %d, ext offset %d\n",
1183           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
1184     return bRet;
1185 }