xref: /reactos/dll/win32/comdlg32/filedlg31.c (revision 1734f297)
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/debug.h"
32 #include "wine/heap.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 = FALSE;
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, ARRAY_SIZE(temp));
109     cp = wcsrchr(temp, '\\');
110     if (cp != NULL) {
111 	lstrcpyW(temp, cp+1);
112     }
113     cp = wcsrchr(temp, ':');
114     if (cp != NULL) {
115 	lstrcpyW(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 = wcschr(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     lstrcpyW(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 = heap_alloc(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         heap_free(str);
259 	return TRUE;
260     }
261 
262     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2)
263     {
264         if (!(str = heap_alloc(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         heap_free(str);
288 	return TRUE;
289     }
290     if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2)
291     {
292         char root[] = "a:";
293         if (!(str = heap_alloc(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         heap_free(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 = lstrlenW(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 = heap_alloc(BUFFILEALLOC);
422   SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
423 		     (LPARAM)pstr);
424   lstrcpyW( tmpstr, pstr );
425   heap_free(pstr);
426   /* get the selected directory in tmpstr */
427   if (tmpstr[0] == '[')
428     {
429       tmpstr[lstrlenW(tmpstr) - 1] = 0;
430       lstrcpyW(tmpstr,tmpstr+1);
431     }
432   lstrcatW(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 = heap_alloc(BUFFILEALLOC)))
461     {
462         SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
463                        (LPARAM)pstr);
464         SetDlgItemTextW( hWnd, edt1, pstr );
465         heap_free(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 = wcsrchr(path, '\\');
489     if (pBeginFileName == NULL)
490 	pBeginFileName = wcsrchr(path, ':');
491 
492     if (wcschr(path,'*') != NULL || wcschr(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 	    lstrcpyW(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         lstrcatW(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, ARRAY_SIZE(tmpstr2));
535         /* Should we MessageBox() if this fails? */
536         if (!FD31_ScanDir(lfs->ofnW, hWnd, path))
537         {
538             return FALSE;
539         }
540         lstrcpyW(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     int copied_size = min( ofnW->lStructSize, sizeof(ofnsav) );
560 
561     memcpy( &ofnsav, ofnW, copied_size ); /* for later restoring */
562 
563     /* get current file name */
564     if (path)
565         lstrcpynW(filename, path, ARRAY_SIZE(filename));
566     else
567         GetDlgItemTextW( hWnd, edt1, filename, ARRAY_SIZE(filename));
568 
569     TRACE("got filename = %s\n", debugstr_w(filename));
570     /* if we did not click in file list to get there */
571     if (control != lst1)
572     {
573         if (!FD31_TestPath( lfs, filename) )
574            return FALSE;
575     }
576     FD31_UpdateResult(lfs, filename);
577 
578     if (internalUse)
579     { /* called internally after a change in a combo */
580         if (lfs->hook)
581         {
582              FD31_CallWindowProc(lfs, lfs->lbselchstring, control,
583                              MAKELONG(itemIndex,CD_LBSELCHANGE));
584         }
585         return TRUE;
586     }
587 
588     FD31_UpdateFileTitle(lfs);
589     if (lfs->hook)
590     {
591         lRet = FD31_CallWindowProc(lfs, lfs->fileokstring,
592                   0, lfs->lParam );
593         if (lRet)
594         {
595             memcpy( ofnW, &ofnsav, copied_size ); /* restore old state */
596             return FALSE;
597         }
598     }
599     if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER))
600     {
601         if (ofnW->lpstrFile)
602         {
603             LPWSTR str = ofnW->lpstrFile;
604             LPWSTR ptr = wcsrchr(str, '\\');
605 	    str[lstrlenW(str) + 1] = '\0';
606 	    *ptr = 0;
607         }
608     }
609     return TRUE;
610 }
611 
612 /***********************************************************************
613  *                              FD31_DiskChange             [internal]
614  *    called when a new item is picked in the disk selection combo
615  */
616 static LRESULT FD31_DiskChange( const FD31_DATA *lfs )
617 {
618     LONG lRet;
619     HWND hWnd = lfs->hwnd;
620     LPWSTR pstr;
621     WCHAR diskname[BUFFILE];
622 
623     FD31_StripEditControl(hWnd);
624     lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L);
625     if (lRet == LB_ERR)
626         return 0;
627     pstr = heap_alloc(BUFFILEALLOC);
628     SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
629                          (LPARAM)pstr);
630     wsprintfW(diskname, FILE_specc, pstr[2]);
631     heap_free(pstr);
632 
633     return FD31_Validate( lfs, diskname, cmb2, lRet, TRUE );
634 }
635 
636 /***********************************************************************
637  *                              FD31_FileTypeChange         [internal]
638  *    called when a new item is picked in the file type combo
639  */
640 static LRESULT FD31_FileTypeChange( const FD31_DATA *lfs )
641 {
642     LONG lRet;
643     LPWSTR pstr;
644 
645     lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0);
646     if (lRet == LB_ERR)
647         return TRUE;
648     lfs->ofnW->nFilterIndex = lRet + 1;
649     if (lfs->ofnA)
650         lfs->ofnA->nFilterIndex = lRet + 1;
651     pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0);
652     TRACE("Selected filter : %s\n", debugstr_w(pstr));
653 
654     return FD31_Validate( lfs, pstr, cmb1, lRet, TRUE );
655 }
656 
657 /***********************************************************************
658  *                              FD31_WMCommand               [internal]
659  */
660 static LRESULT FD31_WMCommand( HWND hWnd, LPARAM lParam, UINT notification,
661 			       UINT control, const FD31_DATA *lfs )
662 {
663     switch (control)
664     {
665         case lst1: /* file list */
666         FD31_StripEditControl(hWnd);
667         if (notification == LBN_DBLCLK)
668         {
669             return SendMessageW(hWnd, WM_COMMAND, IDOK, 0);
670         }
671         else if (notification == LBN_SELCHANGE)
672             return FD31_FileListSelect( lfs );
673         break;
674 
675         case lst2: /* directory list */
676         FD31_StripEditControl(hWnd);
677         if (notification == LBN_DBLCLK)
678             return FD31_DirListDblClick( lfs );
679         break;
680 
681         case cmb1: /* file type drop list */
682         if (notification == CBN_SELCHANGE)
683             return FD31_FileTypeChange( lfs );
684         break;
685 
686         case chx1:
687         break;
688 
689         case pshHelp:
690         break;
691 
692         case cmb2: /* disk dropdown combo */
693         if (notification == CBN_SELCHANGE)
694             return FD31_DiskChange( lfs );
695         break;
696 
697         case IDOK:
698         TRACE("OK pressed\n");
699         if (FD31_Validate( lfs, NULL, control, 0, FALSE ))
700             EndDialog(hWnd, TRUE);
701         return TRUE;
702 
703         case IDCANCEL:
704         EndDialog(hWnd, FALSE);
705         return TRUE;
706 
707         case IDABORT: /* can be sent by the hook procedure */
708         EndDialog(hWnd, TRUE);
709         return TRUE;
710     }
711     return FALSE;
712 }
713 
714 /************************************************************************
715  *                              FD31_MapStringPairsToW       [internal]
716  *      map string pairs to Unicode
717  */
718 static LPWSTR FD31_MapStringPairsToW(LPCSTR strA, UINT size)
719 {
720     LPCSTR s;
721     LPWSTR x;
722     unsigned int n, len;
723 
724     s = strA;
725     while (*s)
726         s = s+strlen(s)+1;
727     s++;
728     n = s + 1 - strA; /* Don't forget the other \0 */
729     if (n < size) n = size;
730 
731     len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 );
732     x = heap_alloc(len * sizeof(WCHAR));
733     MultiByteToWideChar( CP_ACP, 0, strA, n, x, len );
734     return x;
735 }
736 
737 
738 /************************************************************************
739  *                              FD31_DupToW                  [internal]
740  *      duplicates an Ansi string to unicode, with a buffer size
741  */
742 static LPWSTR FD31_DupToW(LPCSTR str, DWORD size)
743 {
744     LPWSTR strW = NULL;
745     if (str && (size > 0))
746     {
747         strW = heap_alloc(size * sizeof(WCHAR));
748         if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size );
749     }
750     return strW;
751 }
752 
753 /************************************************************************
754  *                              FD31_MapOfnStructA          [internal]
755  *      map a 32 bits Ansi structure to a Unicode one
756  */
757 static void FD31_MapOfnStructA(const OPENFILENAMEA *ofnA, LPOPENFILENAMEW ofnW, BOOL open)
758 {
759     UNICODE_STRING usBuffer;
760 
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, buf, ARRAY_SIZE(buf));
787         len = lstrlenW(buf)+1;
788         title_tmp = heap_alloc(len * sizeof(WCHAR));
789         memcpy(title_tmp, buf, len * sizeof(WCHAR));
790         ofnW->lpstrTitle = title_tmp;
791     }
792     ofnW->Flags = ofnA->Flags;
793     ofnW->nFileOffset = ofnA->nFileOffset;
794     ofnW->nFileExtension = ofnA->nFileExtension;
795     ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3);
796     if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
797     {
798         if (!IS_INTRESOURCE(ofnA->lpTemplateName))
799         {
800             RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName);
801             ofnW->lpTemplateName = usBuffer.Buffer;
802         }
803         else /* numbered resource */
804             ofnW->lpTemplateName = (LPCWSTR) ofnA->lpTemplateName;
805     }
806     if (ofnW->lStructSize > OPENFILENAME_SIZE_VERSION_400W)
807     {
808         ofnW->pvReserved = ofnA->pvReserved;
809         ofnW->dwReserved = ofnA->dwReserved;
810         ofnW->FlagsEx    = ofnA->FlagsEx;
811     }
812 }
813 
814 
815 /************************************************************************
816  *                              FD31_FreeOfnW          [internal]
817  *      Undo all allocations done by FD31_MapOfnStructA
818  */
819 static void FD31_FreeOfnW(OPENFILENAMEW *ofnW)
820 {
821     heap_free((void *)ofnW->lpstrFilter);
822     heap_free(ofnW->lpstrCustomFilter);
823     heap_free(ofnW->lpstrFile);
824     heap_free(ofnW->lpstrFileTitle);
825     heap_free((void *)ofnW->lpstrInitialDir);
826     heap_free((void *)ofnW->lpstrTitle);
827     if (!IS_INTRESOURCE(ofnW->lpTemplateName))
828         heap_free((void *)ofnW->lpTemplateName);
829 }
830 
831 /************************************************************************
832  *                              FD31_DestroyPrivate            [internal]
833  *      destroys the private object
834  */
835 static void FD31_DestroyPrivate(PFD31_DATA lfs)
836 {
837     HWND hwnd;
838     if (!lfs) return;
839     hwnd = lfs->hwnd;
840     TRACE("destroying private allocation %p\n", lfs);
841 
842     /* if ofnW has been allocated, have to free everything in it */
843     if (lfs->ofnA)
844     {
845         FD31_FreeOfnW(lfs->ofnW);
846         heap_free(lfs->ofnW);
847     }
848     heap_free(lfs);
849     RemovePropA(hwnd, FD31_OFN_PROP);
850 }
851 
852 /***********************************************************************
853  *           FD31_GetTemplate                                  [internal]
854  *
855  * Get a template (or FALSE if failure) when 16 bits dialogs are used
856  * by a 32 bits application
857  *
858  */
859 static BOOL FD31_GetTemplate(PFD31_DATA lfs)
860 {
861     LPOPENFILENAMEW ofnW = lfs->ofnW;
862     LPOPENFILENAMEA ofnA = lfs->ofnA;
863     HANDLE hDlgTmpl;
864 
865     if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
866     {
867         if (!(lfs->template = LockResource( ofnW->hInstance )))
868         {
869             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
870             return FALSE;
871         }
872     }
873     else if (ofnW->Flags & OFN_ENABLETEMPLATE)
874     {
875         HRSRC hResInfo;
876         if (ofnA)
877             hResInfo = FindResourceA( ofnA->hInstance, ofnA->lpTemplateName, (LPSTR)RT_DIALOG );
878         else
879             hResInfo = FindResourceW( ofnW->hInstance, ofnW->lpTemplateName, (LPWSTR)RT_DIALOG );
880         if (!hResInfo)
881         {
882             COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
883             return FALSE;
884         }
885         if (!(hDlgTmpl = LoadResource( ofnW->hInstance, hResInfo )) ||
886             !(lfs->template = LockResource( hDlgTmpl )))
887         {
888             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
889             return FALSE;
890         }
891     }
892     else /* get it from internal Wine resource */
893     {
894         HRSRC hResInfo;
895         if (!(hResInfo = FindResourceA( COMDLG32_hInstance, lfs->open ? "OPEN_FILE" : "SAVE_FILE", (LPSTR)RT_DIALOG )))
896         {
897             COMDLG32_SetCommDlgExtendedError( CDERR_FINDRESFAILURE );
898             return FALSE;
899         }
900         if (!(hDlgTmpl = LoadResource( COMDLG32_hInstance, hResInfo )) ||
901             !(lfs->template = LockResource( hDlgTmpl )))
902         {
903             COMDLG32_SetCommDlgExtendedError( CDERR_LOADRESFAILURE );
904             return FALSE;
905         }
906     }
907     return TRUE;
908 }
909 
910 /************************************************************************
911  *                              FD31_AllocPrivate            [internal]
912  *      allocate a private object to hold 32 bits Unicode
913  *      structure that will be used throughout the calls, while
914  *      keeping available the original structures and a few variables
915  *      On entry : type = dialog procedure type (16,32A,32W)
916  *                 dlgType = dialog type (open or save)
917  */
918 static PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, BOOL IsUnicode)
919 {
920     FD31_DATA *lfs = heap_alloc_zero(sizeof(*lfs));
921 
922     TRACE("alloc private buf %p\n", lfs);
923     if (!lfs) return NULL;
924     lfs->hook = FALSE;
925     lfs->lParam = lParam;
926     lfs->open = (dlgType == OPEN_DIALOG);
927 
928     if (IsUnicode)
929     {
930         lfs->ofnA = NULL;
931         lfs->ofnW = (LPOPENFILENAMEW) lParam;
932         if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
933             if (lfs->ofnW->lpfnHook)
934                 lfs->hook = TRUE;
935     }
936     else
937     {
938         lfs->ofnA = (LPOPENFILENAMEA) lParam;
939         if (lfs->ofnA->Flags & OFN_ENABLEHOOK)
940             if (lfs->ofnA->lpfnHook)
941                 lfs->hook = TRUE;
942         lfs->ofnW = heap_alloc_zero(lfs->ofnA->lStructSize);
943         lfs->ofnW->lStructSize = lfs->ofnA->lStructSize;
944         FD31_MapOfnStructA(lfs->ofnA, lfs->ofnW, lfs->open);
945     }
946 
947     if (! FD31_GetTemplate(lfs))
948     {
949         FD31_DestroyPrivate(lfs);
950         return NULL;
951     }
952     lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
953     lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
954 
955     return lfs;
956 }
957 
958 /***********************************************************************
959  *                              FD31_WMInitDialog            [internal]
960  */
961 static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
962 {
963   int i, n;
964   WCHAR tmpstr[BUFFILE];
965   LPWSTR pstr, old_pstr;
966   LPOPENFILENAMEW ofn;
967   PFD31_DATA lfs = (PFD31_DATA) lParam;
968 
969   if (!lfs) return FALSE;
970   SetPropA(hWnd, FD31_OFN_PROP, lfs);
971   lfs->hwnd = hWnd;
972   ofn = lfs->ofnW;
973 
974   TRACE("flags=%x initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir));
975 
976   SetWindowTextW( hWnd, ofn->lpstrTitle );
977   /* read custom filter information */
978   if (ofn->lpstrCustomFilter)
979     {
980       pstr = ofn->lpstrCustomFilter;
981       n = 0;
982       TRACE("lpstrCustomFilter = %p\n", pstr);
983       while(*pstr)
984 	{
985 	  old_pstr = pstr;
986           i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
987                                    (LPARAM)(ofn->lpstrCustomFilter) + n );
988           n += lstrlenW(pstr) + 1;
989 	  pstr += lstrlenW(pstr) + 1;
990 	  TRACE("add str=%s associated to %s\n",
991                 debugstr_w(old_pstr), debugstr_w(pstr));
992           SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
993           n += lstrlenW(pstr) + 1;
994 	  pstr += lstrlenW(pstr) + 1;
995 	}
996     }
997   /* read filter information */
998   if (ofn->lpstrFilter) {
999 	pstr = (LPWSTR) ofn->lpstrFilter;
1000 	n = 0;
1001 	while(*pstr) {
1002 	  old_pstr = pstr;
1003 	  i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0,
1004 				       (LPARAM)(ofn->lpstrFilter + n) );
1005 	  n += lstrlenW(pstr) + 1;
1006 	  pstr += lstrlenW(pstr) + 1;
1007 	  TRACE("add str=%s associated to %s\n",
1008                 debugstr_w(old_pstr), debugstr_w(pstr));
1009 	  SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr);
1010 	  n += lstrlenW(pstr) + 1;
1011 	  pstr += lstrlenW(pstr) + 1;
1012 	}
1013   }
1014   /* set default filter */
1015   if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL)
1016   	ofn->nFilterIndex = 1;
1017   SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0);
1018   if (ofn->lpstrFile && ofn->lpstrFile[0])
1019   {
1020     TRACE( "SetText of edt1 to %s\n", debugstr_w(ofn->lpstrFile) );
1021     SetDlgItemTextW( hWnd, edt1, ofn->lpstrFile );
1022   }
1023   else
1024   {
1025     lstrcpynW(tmpstr, FD31_GetFileType(ofn->lpstrCustomFilter,
1026 	     ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE);
1027     TRACE("nFilterIndex = %d, SetText of edt1 to %s\n",
1028   			ofn->nFilterIndex, debugstr_w(tmpstr));
1029     SetDlgItemTextW( hWnd, edt1, tmpstr );
1030   }
1031   /* get drive list */
1032   *tmpstr = 0;
1033   DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE);
1034   /* read initial directory */
1035   /* FIXME: Note that this is now very version-specific (See MSDN description of
1036    * the OPENFILENAME structure).  For example under 2000/XP any path in the
1037    * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME
1038    */
1039   if (ofn->lpstrInitialDir != NULL)
1040     {
1041       int len;
1042       lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511);
1043       len = lstrlenW(tmpstr);
1044       if (len > 0 && tmpstr[len-1] != '\\'  && tmpstr[len-1] != ':') {
1045         tmpstr[len]='\\';
1046         tmpstr[len+1]='\0';
1047       }
1048     }
1049   else
1050     *tmpstr = 0;
1051   if (!FD31_ScanDir(ofn, hWnd, tmpstr)) {
1052     *tmpstr = 0;
1053     if (!FD31_ScanDir(ofn, hWnd, tmpstr))
1054       WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
1055   }
1056   /* select current drive in combo 2, omit missing drives */
1057   {
1058       char dir[MAX_PATH];
1059       char str[4] = "a:\\";
1060       GetCurrentDirectoryA( sizeof(dir), dir );
1061       for(i = 0, n = -1; i < 26; i++)
1062       {
1063           str[0] = 'a' + i;
1064           if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++;
1065           if (toupper(str[0]) == toupper(dir[0])) break;
1066       }
1067   }
1068   SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0);
1069   if (!(ofn->Flags & OFN_SHOWHELP))
1070     ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
1071   if (ofn->Flags & OFN_HIDEREADONLY)
1072     ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
1073   if (lfs->hook)
1074       return FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
1075   return TRUE;
1076 }
1077 
1078 static int FD31_GetFldrHeight(void)
1079 {
1080   return fldrHeight;
1081 }
1082 
1083 /***********************************************************************
1084  *                              FD31_WMMeasureItem           [internal]
1085  */
1086 static LONG FD31_WMMeasureItem(LPARAM lParam)
1087 {
1088     LPMEASUREITEMSTRUCT lpmeasure;
1089 
1090     lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
1091     lpmeasure->itemHeight = FD31_GetFldrHeight();
1092     return TRUE;
1093 }
1094 
1095 
1096 /***********************************************************************
1097  *           FileOpenDlgProc                                    [internal]
1098  *      Used for open and save, in fact.
1099  */
1100 static INT_PTR CALLBACK FD31_FileOpenDlgProc(HWND hWnd, UINT wMsg,
1101                                              WPARAM wParam, LPARAM lParam)
1102 {
1103     PFD31_DATA lfs = (PFD31_DATA)GetPropA( hWnd, FD31_OFN_PROP );
1104 
1105     TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
1106     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
1107     {
1108         INT_PTR lRet;
1109         lRet  = (INT_PTR)FD31_CallWindowProc( lfs, wMsg, wParam, lParam );
1110         if (lRet) return lRet;   /* else continue message processing */
1111     }
1112     switch (wMsg)
1113     {
1114     case WM_INITDIALOG:
1115         return FD31_WMInitDialog( hWnd, wParam, lParam );
1116 
1117     case WM_MEASUREITEM:
1118         return FD31_WMMeasureItem( lParam );
1119 
1120     case WM_DRAWITEM:
1121         return FD31_WMDrawItem( hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam );
1122 
1123     case WM_COMMAND:
1124         return FD31_WMCommand( hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs );
1125 #if 0
1126     case WM_CTLCOLOR:
1127         SetBkColor( (HDC16)wParam, 0x00C0C0C0 );
1128         switch (HIWORD(lParam))
1129         {
1130         case CTLCOLOR_BTN:
1131             SetTextColor( (HDC16)wParam, 0x00000000 );
1132             return hGRAYBrush;
1133         case CTLCOLOR_STATIC:
1134             SetTextColor( (HDC16)wParam, 0x00000000 );
1135             return hGRAYBrush;
1136         }
1137         break;
1138 #endif
1139     }
1140     return FALSE;
1141 }
1142 
1143 /***********************************************************************
1144  *           GetFileName31A                                 [internal]
1145  *
1146  * Creates a win31 style dialog box for the user to select a file to open/save.
1147  */
1148 BOOL GetFileName31A( OPENFILENAMEA *lpofn, UINT dlgType )
1149 {
1150     BOOL bRet = FALSE;
1151     PFD31_DATA lfs;
1152 
1153     if (!lpofn || !FD31_Init()) return FALSE;
1154 
1155     TRACE("ofn flags %08x\n", lpofn->Flags);
1156     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
1157     if (lfs)
1158     {
1159         bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1160                                         FD31_FileOpenDlgProc, (LPARAM)lfs);
1161         FD31_DestroyPrivate(lfs);
1162     }
1163 
1164     TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
1165     return bRet;
1166 }
1167 
1168 /***********************************************************************
1169  *           GetFileName31W                                 [internal]
1170  *
1171  * Creates a win31 style dialog box for the user to select a file to open/save
1172  */
1173 BOOL GetFileName31W( OPENFILENAMEW *lpofn, UINT dlgType )
1174 {
1175     BOOL bRet = FALSE;
1176     PFD31_DATA lfs;
1177 
1178     if (!lpofn || !FD31_Init()) return FALSE;
1179 
1180     lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
1181     if (lfs)
1182     {
1183         bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
1184                                         FD31_FileOpenDlgProc, (LPARAM)lfs);
1185         FD31_DestroyPrivate(lfs);
1186     }
1187 
1188     TRACE("file %s, file offset %d, ext offset %d\n",
1189           debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
1190     return bRet;
1191 }
1192