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