atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[wine] / dlls / comdlg32 / filedlg31.c
1 /*
2  * Win 3.1 Style File Dialogs
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1996 Albrecht Kleine
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33 #include "winreg.h"
34 #include "winternl.h"
35 #include "commdlg.h"
36 #include "shlwapi.h"
37 #include "cderr.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
40
41 #include "cdlg.h"
42
43 #define BUFFILE 512
44 #define BUFFILEALLOC 512 * sizeof(WCHAR)
45
46 static const WCHAR FILE_star[] = {'*','.','*', 0};
47 static const WCHAR FILE_bslash[] = {'\\', 0};
48 static const WCHAR FILE_specc[] = {'%','c',':', 0};
49 static const int fldrHeight = 16;
50 static const int fldrWidth = 20;
51
52 static HICON hFolder = 0;
53 static HICON hFolder2 = 0;
54 static HICON hFloppy = 0;
55 static HICON hHDisk = 0;
56 static HICON hCDRom = 0;
57 static HICON hNet = 0;
58
59 #define FD31_OFN_PROP "FILEDLG_OFN"
60
61 typedef struct tagFD31_DATA
62 {
63     HWND hwnd; /* file dialog window handle */
64     BOOL hook; /* TRUE if the dialog is hooked */
65     UINT lbselchstring; /* registered message id */
66     UINT fileokstring; /* registered message id */
67     LPARAM lParam; /* save original lparam */
68     LPCVOID template; /* template for 32 bits resource */
69     BOOL open; /* TRUE if open dialog, FALSE if save dialog */
70     LPOPENFILENAMEW ofnW; /* pointer either to the original structure or
71                              a W copy for A/16 API */
72     LPOPENFILENAMEA ofnA; /* original structure if 32bits ansi dialog */
73 } FD31_DATA, *PFD31_DATA;
74
75 /***********************************************************************
76  *                              FD31_Init                       [internal]
77  */
78 static BOOL FD31_Init(void)
79 {
80     static BOOL initialized = 0;
81
82     if (!initialized) {
83         hFolder  = LoadImageA( COMDLG32_hInstance, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED );
84         hFolder2 = LoadImageA( COMDLG32_hInstance, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED );
85         hFloppy  = LoadImageA( COMDLG32_hInstance, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED );
86         hHDisk   = LoadImageA( COMDLG32_hInstance, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED );
87         hCDRom   = LoadImageA( COMDLG32_hInstance, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED );
88         hNet     = LoadImageA( COMDLG32_hInstance, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED );
89         if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 ||
90             hHDisk == 0 || hCDRom == 0 || hNet == 0)
91         {
92             ERR("Error loading icons !\n");
93             return FALSE;
94         }
95         initialized = TRUE;
96     }
97     return TRUE;
98 }
99
100 /***********************************************************************
101  *                              FD31_StripEditControl        [internal]
102  * Strip pathnames off the contents of the edit control.
103  */
104 static void FD31_StripEditControl(HWND hwnd)
105 {
106     WCHAR temp[BUFFILE], *cp;
107
108     GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR));
109     cp = strrchrW(temp, '\\');
110     if (cp != NULL) {
111         strcpyW(temp, cp+1);
112     }
113     cp = strrchrW(temp, ':');
114     if (cp != NULL) {
115         strcpyW(temp, cp+1);
116     }
117     /* FIXME: shouldn't we do something with the result here? ;-) */
118 }
119
120 /***********************************************************************
121  *                              FD31_CallWindowProc          [internal]
122  *
123  *      Call the appropriate hook
124  */
125 static BOOL FD31_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam, LPARAM lParam)
126 {
127     BOOL ret;
128
129     if (lfs->ofnA)
130     {
131         TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
132                lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
133         ret = lfs->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
134         TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
135                lfs->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
136         return ret;
137     }
138
139     TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
140            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
141     ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
142     TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
143            lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
144     return ret;
145 }
146
147 /***********************************************************************
148  *                              FD31_GetFileType                [internal]
149  */
150 static LPCWSTR FD31_GetFileType(LPCWSTR cfptr, LPCWSTR fptr, const WORD index)
151 {
152   int n, i;
153   i = 0;
154   if (cfptr)
155     for ( ;(n = lstrlenW(cfptr)) != 0; i++)
156       {
157         cfptr += n + 1;
158         if (i == index)
159           return cfptr;
160         cfptr += lstrlenW(cfptr) + 1;
161       }
162   if (fptr)
163     for ( ;(n = lstrlenW(fptr)) != 0; i++)
164       {
165         fptr += n + 1;
166         if (i == index)
167           return fptr;
168         fptr += lstrlenW(fptr) + 1;
169     }
170   return FILE_star; /* FIXME */
171 }
172
173 /***********************************************************************
174  *                              FD31_ScanDir                 [internal]
175  */
176 static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
177 {
178     WCHAR   buffer[BUFFILE];
179     HWND    hdlg;
180     LRESULT lRet = TRUE;
181     HCURSOR hCursorWait, oldCursor;
182
183     TRACE("Trying to change to %s\n", debugstr_w(newPath));
184     if  ( newPath[0] && !SetCurrentDirectoryW( newPath ))
185         return FALSE;
186
187     /* get the list of spec files */
188     lstrcpynW(buffer, FD31_GetFileType(ofn->lpstrCustomFilter,
189               ofn->lpstrFilter, ofn->nFilterIndex - 1), BUFFILE);
190
191     hCursorWait = LoadCursorA(0, (LPSTR)IDC_WAIT);
192     oldCursor = SetCursor(hCursorWait);
193
194     /* list of files */
195     if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) {
196         WCHAR*  scptr; /* ptr on semi-colon */
197         WCHAR*  filter = buffer;
198
199         TRACE("Using filter %s\n", debugstr_w(filter));
200         SendMessageW(hdlg, LB_RESETCONTENT, 0, 0);
201         while (filter) {
202             scptr = strchrW(filter, ';');
203             if (scptr)  *scptr = 0;
204             while (*filter == ' ') filter++;
205             TRACE("Using file spec %s\n", debugstr_w(filter));
206             SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter);
207             if (scptr) *scptr = ';';
208             filter = (scptr) ? (scptr + 1) : 0;
209          }
210     }
211
212     /* list of directories */
213     strcpyW(buffer, FILE_star);
214
215     if (GetDlgItem(hWnd, lst2) != 0) {
216         lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY);
217     }
218     SetCursor(oldCursor);
219     return lRet;
220 }
221
222 /***********************************************************************
223  *                              FD31_WMDrawItem              [internal]
224  */
225 static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
226                             int savedlg, const DRAWITEMSTRUCT *lpdis)
227 {
228     WCHAR *str;
229     HICON hIcon;
230     COLORREF oldText = 0, oldBk = 0;
231
232     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1)
233     {
234         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE;
235         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
236                       (LPARAM)str);
237
238         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
239         {
240             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
241             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
242         }
243         if (savedlg)
244             SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) );
245
246         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1,
247                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
248                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
249
250         if (lpdis->itemState & ODS_SELECTED)
251             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
252
253         if ((lpdis->itemState & ODS_SELECTED) && !savedlg)
254         {
255             SetBkColor( lpdis->hDC, oldBk );
256             SetTextColor( lpdis->hDC, oldText );
257         }
258         HeapFree(GetProcessHeap(), 0, str);
259         return TRUE;
260     }
261
262     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2)
263     {
264         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
265             return FALSE;
266         SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID,
267                       (LPARAM)str);
268
269         if (lpdis->itemState & ODS_SELECTED)
270         {
271             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
272             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
273         }
274         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
275                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
276                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
277
278         if (lpdis->itemState & ODS_SELECTED)
279             DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) );
280
281         if (lpdis->itemState & ODS_SELECTED)
282         {
283             SetBkColor( lpdis->hDC, oldBk );
284             SetTextColor( lpdis->hDC, oldText );
285         }
286         DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder, 16, 16, 0, 0, DI_NORMAL );
287         HeapFree(GetProcessHeap(), 0, str);
288         return TRUE;
289     }
290     if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2)
291     {
292         char root[] = "a:";
293         if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
294             return FALSE;
295         SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID,
296                       (LPARAM)str);
297         root[0] += str[2] - 'a';
298         switch(GetDriveTypeA(root))
299         {
300         case DRIVE_REMOVABLE: hIcon = hFloppy; break;
301         case DRIVE_CDROM:     hIcon = hCDRom; break;
302         case DRIVE_REMOTE:    hIcon = hNet; break;
303         case DRIVE_FIXED:
304         default:           hIcon = hHDisk; break;
305         }
306         if (lpdis->itemState & ODS_SELECTED)
307         {
308             oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
309             oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
310         }
311         ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
312                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
313                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
314
315         if (lpdis->itemState & ODS_SELECTED)
316         {
317             SetBkColor( lpdis->hDC, oldBk );
318             SetTextColor( lpdis->hDC, oldText );
319         }
320         DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon, 16, 16, 0, 0, DI_NORMAL );
321         HeapFree(GetProcessHeap(), 0, str);
322         return TRUE;
323     }
324     return FALSE;
325 }
326
327 /***********************************************************************
328  *                              FD31_UpdateResult            [internal]
329  *      update the displayed file name (with path)
330  */
331 static void FD31_UpdateResult(const FD31_DATA *lfs, const WCHAR *tmpstr)
332 {
333     int lenstr2;
334     LPOPENFILENAMEW ofnW = lfs->ofnW;
335     LPOPENFILENAMEA ofnA = lfs->ofnA;
336     WCHAR tmpstr2[BUFFILE];
337     WCHAR *p;
338
339     TRACE("%s\n", debugstr_w(tmpstr));
340     if(ofnW->Flags & OFN_NOVALIDATE)
341         tmpstr2[0] = '\0';
342     else
343         GetCurrentDirectoryW(BUFFILE, tmpstr2);
344     lenstr2 = strlenW(tmpstr2);
345     if (lenstr2 > 3)
346         tmpstr2[lenstr2++]='\\';
347     lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2);
348     if (!ofnW->lpstrFile)
349         return;
350
351     lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile);
352
353     /* set filename offset */
354     p = PathFindFileNameW(ofnW->lpstrFile);
355     ofnW->nFileOffset = (p - ofnW->lpstrFile);
356
357     /* set extension offset */
358     p = PathFindExtensionW(ofnW->lpstrFile);
359     ofnW->nFileExtension = (*p) ? (p - ofnW->lpstrFile) + 1 : 0;
360
361     TRACE("file %s, file offset %d, ext offset %d\n",
362           debugstr_w(ofnW->lpstrFile), ofnW->nFileOffset, ofnW->nFileExtension);
363
364     /* update the real client structures if any */
365     if (ofnA)
366     {
367         LPSTR lpszTemp;
368         if (ofnW->nMaxFile &&
369             !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
370                                   ofnA->lpstrFile, ofnA->nMaxFile, NULL, NULL ))
371             ofnA->lpstrFile[ofnA->nMaxFile-1] = 0;
372
373         /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
374         /* set filename offset */
375         lpszTemp = PathFindFileNameA(ofnA->lpstrFile);
376         ofnA->nFileOffset = (lpszTemp - ofnA->lpstrFile);
377
378         /* set extension offset */
379         lpszTemp = PathFindExtensionA(ofnA->lpstrFile);
380         ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - ofnA->lpstrFile) + 1 : 0;
381     }
382 }
383
384 /***********************************************************************
385  *                              FD31_UpdateFileTitle         [internal]
386  *      update the displayed file name (without path)
387  */
388 static void FD31_UpdateFileTitle(const FD31_DATA *lfs)
389 {
390   LONG lRet;
391   LPOPENFILENAMEW ofnW = lfs->ofnW;
392   LPOPENFILENAMEA ofnA = lfs->ofnA;
393
394   if (ofnW->lpstrFileTitle != NULL)
395   {
396     lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
397     SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet,
398                              (LPARAM)ofnW->lpstrFileTitle );
399     if (ofnA)
400     {
401         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
402                                   ofnA->lpstrFileTitle, ofnA->nMaxFileTitle, NULL, NULL ))
403             ofnA->lpstrFileTitle[ofnA->nMaxFileTitle-1] = 0;
404     }
405   }
406 }
407
408 /***********************************************************************
409  *                              FD31_DirListDblClick         [internal]
410  */
411 static LRESULT FD31_DirListDblClick( const FD31_DATA *lfs )
412 {
413   LONG lRet;
414   HWND hWnd = lfs->hwnd;
415   LPWSTR pstr;
416   WCHAR tmpstr[BUFFILE];
417
418   /* get the raw string (with brackets) */
419   lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
420   if (lRet == LB_ERR) return TRUE;
421   pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
422   SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
423                      (LPARAM)pstr);
424   strcpyW( tmpstr, pstr );
425   HeapFree(GetProcessHeap(), 0, pstr);
426   /* get the selected directory in tmpstr */
427   if (tmpstr[0] == '[')
428     {
429       tmpstr[lstrlenW(tmpstr) - 1] = 0;
430       strcpyW(tmpstr,tmpstr+1);
431     }
432   strcatW(tmpstr, FILE_bslash);
433
434   FD31_ScanDir(lfs->ofnW, hWnd, tmpstr);
435   /* notify the app */
436   if (lfs->hook)
437     {
438       if (FD31_CallWindowProc(lfs, lfs->lbselchstring, lst2,
439               MAKELONG(lRet,CD_LBSELCHANGE)))
440         return TRUE;
441     }
442   return TRUE;
443 }
444
445 /***********************************************************************
446  *                              FD31_FileListSelect         [internal]
447  *    called when a new item is picked in the file list
448  */
449 static LRESULT FD31_FileListSelect( const FD31_DATA *lfs )
450 {
451     LONG lRet;
452     HWND hWnd = lfs->hwnd;
453     LPWSTR pstr;
454
455     lRet =  SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
456     if (lRet == LB_ERR)
457         return TRUE;
458
459     /* set the edit control to the chosen file */
460     if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC)))
461     {
462         SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet,
463                        (LPARAM)pstr);
464         SetDlgItemTextW( hWnd, edt1, pstr );
465         HeapFree(GetProcessHeap(), 0, pstr);
466     }
467     if (lfs->hook)
468     {
469         FD31_CallWindowProc(lfs, lfs->lbselchstring, lst1,
470                            MAKELONG(lRet,CD_LBSELCHANGE));
471     }
472     /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD,
473            CD_LBSELNOITEMS */
474     return TRUE;
475 }
476
477 /***********************************************************************
478  *                              FD31_TestPath      [internal]
479  *      before accepting the file name, test if it includes wild cards
480  *      tries to scan the directory and returns TRUE if no error.
481  */
482 static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
483 {
484     HWND hWnd = lfs->hwnd;
485     LPWSTR pBeginFileName, pstr2;
486     WCHAR tmpstr2[BUFFILE];
487
488     pBeginFileName = strrchrW(path, '\\');
489     if (pBeginFileName == NULL)
490         pBeginFileName = strrchrW(path, ':');
491
492     if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL)
493     {
494         /* edit control contains wildcards */
495         if (pBeginFileName != NULL)
496         {
497             lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE);
498             *(pBeginFileName + 1) = 0;
499         }
500         else
501         {
502             strcpyW(tmpstr2, path);
503             if(!(lfs->ofnW->Flags & OFN_NOVALIDATE))
504                 *path = 0;
505         }
506
507         TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
508         SetDlgItemTextW( hWnd, edt1, tmpstr2 );
509         FD31_ScanDir(lfs->ofnW, hWnd, path);
510         return (lfs->ofnW->Flags & OFN_NOVALIDATE) != 0;
511     }
512
513     /* no wildcards, we might have a directory or a filename */
514     /* try appending a wildcard and reading the directory */
515
516     pstr2 = path + lstrlenW(path);
517     if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
518         strcatW(path, FILE_bslash);
519
520     /* if ScanDir succeeds, we have changed the directory */
521     if (FD31_ScanDir(lfs->ofnW, hWnd, path))
522         return FALSE; /* and path is not a valid file name */
523
524     /* if not, this must be a filename */
525
526     *pstr2 = 0; /* remove the wildcard added before */
527
528     if (pBeginFileName != NULL)
529     {
530         /* strip off the pathname */
531         *pBeginFileName = 0;
532         SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 );
533
534         lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) );
535         /* Should we MessageBox() if this fails? */
536         if (!FD31_ScanDir(lfs->ofnW, hWnd, path))
537         {
538             return FALSE;
539         }
540         strcpyW(path, tmpstr2);
541     }
542     else
543         SetDlgItemTextW( hWnd, edt1, path );
544     return TRUE;
545 }
546
547 /***********************************************************************
548  *                              FD31_Validate               [internal]
549  *   called on: click Ok button, Enter in edit, DoubleClick in file list
550  */
551 static LRESULT FD31_Validate( const FD31_DATA *lfs, LPCWSTR path, UINT control, INT itemIndex,
552                                  BOOL internalUse )
553 {
554     LONG lRet;
555     HWND hWnd = lfs->hwnd;
556     OPENFILENAMEW ofnsav;
557     LPOPENFILENAMEW ofnW = lfs->ofnW;
558     WCHAR filename[BUFFILE];
559     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, sizeof(filename)/sizeof(WCHAR));
566     else
567         GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR));
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 = strrchrW(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 = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC);
628     SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet,
629                          (LPARAM)pstr);
630     wsprintfW(diskname, FILE_specc, pstr[2]);
631     HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(),0, 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 = HeapAlloc(GetProcessHeap(), 0, 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,
787                     buf, sizeof(buf)/sizeof(WCHAR));
788         len = lstrlenW(buf)+1;
789         title_tmp = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
790         memcpy(title_tmp, buf, len * sizeof(WCHAR));
791         ofnW->lpstrTitle = title_tmp;
792     }
793     ofnW->Flags = ofnA->Flags;
794     ofnW->nFileOffset = ofnA->nFileOffset;
795     ofnW->nFileExtension = ofnA->nFileExtension;
796     ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3);
797     if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName))
798     {
799         if (!IS_INTRESOURCE(ofnA->lpTemplateName))
800         {
801             RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName);
802             ofnW->lpTemplateName = usBuffer.Buffer;
803         }
804         else /* numbered resource */
805             ofnW->lpTemplateName = (LPCWSTR) ofnA->lpTemplateName;
806     }
807     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    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter);
823    HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter);
824    HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile);
825    HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle);
826    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir);
827    HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle);
828    if (!IS_INTRESOURCE(ofnW->lpTemplateName))
829        HeapFree(GetProcessHeap(), 0, (LPWSTR) 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         HeapFree(GetProcessHeap(), 0, lfs->ofnW);
848     }
849     HeapFree(GetProcessHeap(), 0, 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     PFD31_DATA lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD31_DATA));
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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 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 }