[COMDLG32] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / 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/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 }