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