2 * COMMDLG - File Dialogs
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Albrecht Kleine
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.
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.
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
26 #include "wine/winbase16.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(commdlg
);
37 static inline WORD
get_word( const char **ptr
)
39 WORD ret
= *(WORD
*)*ptr
;
44 static inline void copy_string( WORD
**out
, const char **in
, DWORD maxlen
)
46 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, *in
, -1, *out
, maxlen
);
47 *in
+= strlen(*in
) + 1;
51 static inline void copy_dword( WORD
**out
, const char **in
)
53 *(DWORD
*)*out
= *(DWORD
*)*in
;
55 *out
+= sizeof(DWORD
) / sizeof(WORD
);
58 static LPDLGTEMPLATEA
convert_dialog( const char *p
, DWORD size
)
61 WORD len
, count
, *out
, *end
;
63 if (!(dlg
= HeapAlloc( GetProcessHeap(), 0, size
* 2 ))) return NULL
;
66 copy_dword( &out
, &p
); /* style */
67 *out
++ = 0; *out
++ = 0; /* exstyle */
68 *out
++ = count
= (BYTE
)*p
++; /* count */
69 *out
++ = get_word( &p
); /* x */
70 *out
++ = get_word( &p
); /* y */
71 *out
++ = get_word( &p
); /* cx */
72 *out
++ = get_word( &p
); /* cy */
74 if ((BYTE
)*p
== 0xff) /* menu */
78 *out
++ = get_word( &p
);
80 else copy_string( &out
, &p
, end
- out
);
82 copy_string( &out
, &p
, end
- out
); /* class */
83 copy_string( &out
, &p
, end
- out
); /* caption */
85 if (dlg
->style
& DS_SETFONT
)
87 *out
++ = get_word( &p
); /* point size */
88 copy_string( &out
, &p
, end
- out
); /* face name */
94 WORD x
= get_word( &p
);
95 WORD y
= get_word( &p
);
96 WORD cx
= get_word( &p
);
97 WORD cy
= get_word( &p
);
98 WORD id
= get_word( &p
);
100 out
= (WORD
*)(((UINT_PTR
)out
+ 3) & ~3);
102 copy_dword( &out
, &p
); /* style */
103 *out
++ = 0; *out
++ = 0; /* exstyle */
110 if (*p
& 0x80) /* class */
115 else copy_string( &out
, &p
, end
- out
);
117 if (*p
& 0x80) /* window */
120 *out
++ = get_word( &p
);
122 else copy_string( &out
, &p
, end
- out
);
124 len
= (BYTE
)*p
++; /* data */
125 *out
++ = (len
+ 1) & ~1;
126 memcpy( out
, p
, len
);
128 out
+= (len
+ 1) / sizeof(WORD
);
131 assert( out
<= end
);
135 static void RECT16to32( const RECT16
*from
, RECT
*to
)
137 to
->left
= from
->left
;
139 to
->right
= from
->right
;
140 to
->bottom
= from
->bottom
;
143 static void RECT32to16( const RECT
*from
, RECT16
*to
)
145 to
->left
= from
->left
;
147 to
->right
= from
->right
;
148 to
->bottom
= from
->bottom
;
151 static void MINMAXINFO32to16( const MINMAXINFO
*from
, MINMAXINFO16
*to
)
153 to
->ptReserved
.x
= from
->ptReserved
.x
;
154 to
->ptReserved
.y
= from
->ptReserved
.y
;
155 to
->ptMaxSize
.x
= from
->ptMaxSize
.x
;
156 to
->ptMaxSize
.y
= from
->ptMaxSize
.y
;
157 to
->ptMaxPosition
.x
= from
->ptMaxPosition
.x
;
158 to
->ptMaxPosition
.y
= from
->ptMaxPosition
.y
;
159 to
->ptMinTrackSize
.x
= from
->ptMinTrackSize
.x
;
160 to
->ptMinTrackSize
.y
= from
->ptMinTrackSize
.y
;
161 to
->ptMaxTrackSize
.x
= from
->ptMaxTrackSize
.x
;
162 to
->ptMaxTrackSize
.y
= from
->ptMaxTrackSize
.y
;
165 static void MINMAXINFO16to32( const MINMAXINFO16
*from
, MINMAXINFO
*to
)
167 to
->ptReserved
.x
= from
->ptReserved
.x
;
168 to
->ptReserved
.y
= from
->ptReserved
.y
;
169 to
->ptMaxSize
.x
= from
->ptMaxSize
.x
;
170 to
->ptMaxSize
.y
= from
->ptMaxSize
.y
;
171 to
->ptMaxPosition
.x
= from
->ptMaxPosition
.x
;
172 to
->ptMaxPosition
.y
= from
->ptMaxPosition
.y
;
173 to
->ptMinTrackSize
.x
= from
->ptMinTrackSize
.x
;
174 to
->ptMinTrackSize
.y
= from
->ptMinTrackSize
.y
;
175 to
->ptMaxTrackSize
.x
= from
->ptMaxTrackSize
.x
;
176 to
->ptMaxTrackSize
.y
= from
->ptMaxTrackSize
.y
;
179 static void WINDOWPOS32to16( const WINDOWPOS
* from
, WINDOWPOS16
* to
)
181 to
->hwnd
= HWND_16(from
->hwnd
);
182 to
->hwndInsertAfter
= HWND_16(from
->hwndInsertAfter
);
187 to
->flags
= from
->flags
;
190 static void WINDOWPOS16to32( const WINDOWPOS16
* from
, WINDOWPOS
* to
)
192 to
->hwnd
= HWND_32(from
->hwnd
);
193 to
->hwndInsertAfter
= (from
->hwndInsertAfter
== (HWND16
)-1) ?
194 HWND_TOPMOST
: HWND_32(from
->hwndInsertAfter
);
199 to
->flags
= from
->flags
;
202 static void CREATESTRUCT32Ato16( const CREATESTRUCTA
* from
, CREATESTRUCT16
* to
)
204 to
->lpCreateParams
= (SEGPTR
)from
->lpCreateParams
;
206 to
->hMenu
= HMENU_16(from
->hMenu
);
207 to
->hwndParent
= HWND_16(from
->hwndParent
);
212 to
->style
= from
->style
;
213 to
->dwExStyle
= from
->dwExStyle
;
216 static LRESULT
call_hook16( WNDPROC16 hook
, HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
221 TRACE( "%p: %p %08x %lx %lx: stub\n", hook
, hwnd
, msg
, wp
, lp
);
223 memset( &context
, 0, sizeof(context
) );
224 context
.SegDs
= context
.SegEs
= SELECTOROF( NtCurrentTeb()->WOW32Reserved
);
225 context
.SegFs
= wine_get_fs();
226 context
.SegGs
= wine_get_gs();
227 context
.SegCs
= SELECTOROF( hook
);
228 context
.Eip
= OFFSETOF( hook
);
229 context
.Ebp
= OFFSETOF( NtCurrentTeb()->WOW32Reserved
) + FIELD_OFFSET( STACK16FRAME
, bp
);
230 context
.Eax
= context
.SegDs
;
232 params
[4] = HWND_16( hwnd
);
235 params
[1] = HIWORD( lp
);
236 params
[0] = LOWORD( lp
);
237 WOWCallback16Ex( 0, WCB16_REGS
, sizeof(params
), params
, (DWORD
*)&context
);
238 return LOWORD( context
.Eax
);
241 static UINT_PTR CALLBACK
call_hook_proc( WNDPROC16 hook
, HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
250 CREATESTRUCTA
*cs32
= (CREATESTRUCTA
*)lp
;
253 CREATESTRUCT32Ato16( cs32
, &cs
);
254 cs
.lpszName
= MapLS( cs32
->lpszName
);
255 cs
.lpszClass
= MapLS( cs32
->lpszClass
);
257 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
259 UnMapLS( cs
.lpszName
);
260 UnMapLS( cs
.lpszClass
);
263 case WM_GETMINMAXINFO
:
265 MINMAXINFO
*mmi32
= (MINMAXINFO
*)lp
;
268 MINMAXINFO32to16( mmi32
, &mmi
);
270 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
272 MINMAXINFO16to32( &mmi
, mmi32
);
277 NCCALCSIZE_PARAMS
*nc32
= (NCCALCSIZE_PARAMS
*)lp
;
278 NCCALCSIZE_PARAMS16 nc
;
281 RECT32to16( &nc32
->rgrc
[0], &nc
.rgrc
[0] );
284 RECT32to16( &nc32
->rgrc
[1], &nc
.rgrc
[1] );
285 RECT32to16( &nc32
->rgrc
[2], &nc
.rgrc
[2] );
286 WINDOWPOS32to16( nc32
->lppos
, &winpos
);
287 nc
.lppos
= MapLS( &winpos
);
290 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
292 RECT16to32( &nc
.rgrc
[0], &nc32
->rgrc
[0] );
295 RECT16to32( &nc
.rgrc
[1], &nc32
->rgrc
[1] );
296 RECT16to32( &nc
.rgrc
[2], &nc32
->rgrc
[2] );
297 WINDOWPOS16to32( &winpos
, nc32
->lppos
);
302 case WM_WINDOWPOSCHANGING
:
303 case WM_WINDOWPOSCHANGED
:
305 WINDOWPOS
*winpos32
= (WINDOWPOS
*)lp
;
308 WINDOWPOS32to16( winpos32
, &winpos
);
309 lp
= MapLS( &winpos
);
310 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
312 WINDOWPOS16to32( &winpos
, winpos32
);
317 COMPAREITEMSTRUCT
*cis32
= (COMPAREITEMSTRUCT
*)lp
;
318 COMPAREITEMSTRUCT16 cis
;
319 cis
.CtlType
= cis32
->CtlType
;
320 cis
.CtlID
= cis32
->CtlID
;
321 cis
.hwndItem
= HWND_16( cis32
->hwndItem
);
322 cis
.itemID1
= cis32
->itemID1
;
323 cis
.itemData1
= cis32
->itemData1
;
324 cis
.itemID2
= cis32
->itemID2
;
325 cis
.itemData2
= cis32
->itemData2
;
327 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
333 DELETEITEMSTRUCT
*dis32
= (DELETEITEMSTRUCT
*)lp
;
334 DELETEITEMSTRUCT16 dis
;
335 dis
.CtlType
= dis32
->CtlType
;
336 dis
.CtlID
= dis32
->CtlID
;
337 dis
.itemID
= dis32
->itemID
;
338 dis
.hwndItem
= (dis
.CtlType
== ODT_MENU
) ? (HWND16
)LOWORD(dis32
->hwndItem
)
339 : HWND_16( dis32
->hwndItem
);
340 dis
.itemData
= dis32
->itemData
;
342 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
348 DRAWITEMSTRUCT
*dis32
= (DRAWITEMSTRUCT
*)lp
;
349 DRAWITEMSTRUCT16 dis
;
350 dis
.CtlType
= dis32
->CtlType
;
351 dis
.CtlID
= dis32
->CtlID
;
352 dis
.itemID
= dis32
->itemID
;
353 dis
.itemAction
= dis32
->itemAction
;
354 dis
.itemState
= dis32
->itemState
;
355 dis
.hwndItem
= HWND_16( dis32
->hwndItem
);
356 dis
.hDC
= HDC_16( dis32
->hDC
);
357 dis
.itemData
= dis32
->itemData
;
358 dis
.rcItem
.left
= dis32
->rcItem
.left
;
359 dis
.rcItem
.top
= dis32
->rcItem
.top
;
360 dis
.rcItem
.right
= dis32
->rcItem
.right
;
361 dis
.rcItem
.bottom
= dis32
->rcItem
.bottom
;
363 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
369 MEASUREITEMSTRUCT
*mis32
= (MEASUREITEMSTRUCT
*)lp
;
370 MEASUREITEMSTRUCT16 mis
;
371 mis
.CtlType
= mis32
->CtlType
;
372 mis
.CtlID
= mis32
->CtlID
;
373 mis
.itemID
= mis32
->itemID
;
374 mis
.itemWidth
= mis32
->itemWidth
;
375 mis
.itemHeight
= mis32
->itemHeight
;
376 mis
.itemData
= mis32
->itemData
;
378 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
380 mis32
->itemWidth
= mis
.itemWidth
;
381 mis32
->itemHeight
= mis
.itemHeight
;
386 COPYDATASTRUCT
*cds32
= (COPYDATASTRUCT
*)lp
;
387 COPYDATASTRUCT16 cds
;
389 cds
.dwData
= cds32
->dwData
;
390 cds
.cbData
= cds32
->cbData
;
391 cds
.lpData
= MapLS( cds32
->lpData
);
393 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
395 UnMapLS( cds
.lpData
);
401 MSG
*msg32
= (MSG
*)lp
;
404 msg16
.hwnd
= HWND_16( msg32
->hwnd
);
405 msg16
.message
= msg32
->message
;
406 msg16
.wParam
= msg32
->wParam
;
407 msg16
.lParam
= msg32
->lParam
;
408 msg16
.time
= msg32
->time
;
409 msg16
.pt
.x
= msg32
->pt
.x
;
410 msg16
.pt
.y
= msg32
->pt
.y
;
411 lp
= MapLS( &msg16
);
412 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
416 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
421 MDINEXTMENU
*next
= (MDINEXTMENU
*)lp
;
422 ret
= call_hook16( hook
, hwnd
, msg
, wp
, (LPARAM
)next
->hmenuIn
);
423 result
= GetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
);
424 next
->hmenuNext
= HMENU_32( LOWORD(result
) );
425 next
->hwndNext
= HWND_32( HIWORD(result
) );
426 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, 0 );
430 case WM_ASKCBFORMATNAME
:
431 wp
= min( wp
, 0xff80 ); /* Must be < 64K */
435 case WM_WININICHANGE
:
436 case WM_DEVMODECHANGE
:
437 lp
= MapLS( (void *)lp
);
438 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
445 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( (HWND16
)lp
, HIWORD(wp
) ));
449 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( HIWORD(wp
), (HWND16
)lp
));
451 case WM_CTLCOLORMSGBOX
:
452 case WM_CTLCOLOREDIT
:
453 case WM_CTLCOLORLISTBOX
:
456 case WM_CTLCOLORSCROLLBAR
:
457 case WM_CTLCOLORSTATIC
:
458 ret
= call_hook16( hook
, hwnd
, WM_CTLCOLOR
, wp
, MAKELPARAM( (HWND16
)lp
, msg
- WM_CTLCOLORMSGBOX
));
461 if(HIWORD(wp
) & MF_POPUP
)
464 if ((HIWORD(wp
) != 0xffff) || lp
)
466 if ((hmenu
= GetSubMenu( (HMENU
)lp
, LOWORD(wp
) )))
468 ret
= call_hook16( hook
, hwnd
, msg
, HMENU_16(hmenu
),
469 MAKELPARAM( HIWORD(wp
), (HMENU16
)lp
) );
476 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( HIWORD(wp
), (HMENU16
)lp
));
478 case WM_PARENTNOTIFY
:
479 if ((LOWORD(wp
) == WM_CREATE
) || (LOWORD(wp
) == WM_DESTROY
))
480 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( (HWND16
)lp
, HIWORD(wp
) ));
482 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
485 ret
= call_hook16( hook
, hwnd
, msg
, wp
, HTASK_16( lp
));
488 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
495 #include "pshpack1.h"
498 BYTE popl_eax
; /* popl %eax */
499 BYTE pushl_hook
; /* pushl $hook_ptr */
500 LPOFNHOOKPROC16 hook_ptr
;
501 BYTE pushl_eax
; /* pushl %eax */
502 BYTE jmp
; /* jmp call_hook */
507 static LPOFNHOOKPROC
alloc_hook( LPOFNHOOKPROC16 hook16
)
509 static struct hook_proc
*hooks
;
510 static unsigned int count
;
511 SIZE_T size
= 0x1000;
514 if (!hooks
&& NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&hooks
, 12, &size
,
515 MEM_COMMIT
, PAGE_EXECUTE_READWRITE
))
518 for (i
= 0; i
< count
; i
++)
519 if (hooks
[i
].hook_ptr
== hook16
)
520 return (LPOFNHOOKPROC
)&hooks
[i
];
522 if (count
>= size
/ sizeof(*hooks
))
524 FIXME( "all hooks are in use\n" );
528 hooks
[count
].popl_eax
= 0x58;
529 hooks
[count
].pushl_hook
= 0x68;
530 hooks
[count
].hook_ptr
= hook16
;
531 hooks
[count
].pushl_eax
= 0x50;
532 hooks
[count
].jmp
= 0xe9;
533 hooks
[count
].call_hook
= (char *)call_hook_proc
- (char *)(&hooks
[count
].call_hook
+ 1);
534 return (LPOFNHOOKPROC
)&hooks
[count
++];
537 static UINT_PTR CALLBACK
dummy_hook( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
542 /***********************************************************************
543 * FileOpenDlgProc (COMMDLG.6)
545 BOOL16 CALLBACK
FileOpenDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
, LPARAM lParam
)
547 FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16
, wMsg
, wParam
, lParam
);
551 /***********************************************************************
552 * FileSaveDlgProc (COMMDLG.7)
554 BOOL16 CALLBACK
FileSaveDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
, LPARAM lParam
)
556 FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16
, wMsg
, wParam
, lParam
);
560 /***********************************************************************
561 * GetOpenFileName (COMMDLG.1)
563 * Creates a dialog box for the user to select a file to open.
566 * TRUE on success: user selected a valid file
567 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
570 * unknown, there are some FIXMEs left.
572 BOOL16 WINAPI
GetOpenFileName16( SEGPTR ofn
) /* [in/out] address of structure with data*/
574 LPOPENFILENAME16 lpofn
= MapSL(ofn
);
575 LPDLGTEMPLATEA
template = NULL
;
579 if (!lpofn
) return FALSE
;
581 ofn32
.lStructSize
= OPENFILENAME_SIZE_VERSION_400A
;
582 ofn32
.hwndOwner
= HWND_32( lpofn
->hwndOwner
);
583 ofn32
.lpstrFilter
= MapSL( lpofn
->lpstrFilter
);
584 ofn32
.lpstrCustomFilter
= MapSL( lpofn
->lpstrCustomFilter
);
585 ofn32
.nMaxCustFilter
= lpofn
->nMaxCustFilter
;
586 ofn32
.nFilterIndex
= lpofn
->nFilterIndex
;
587 ofn32
.lpstrFile
= MapSL( lpofn
->lpstrFile
);
588 ofn32
.nMaxFile
= lpofn
->nMaxFile
;
589 ofn32
.lpstrFileTitle
= MapSL( lpofn
->lpstrFileTitle
);
590 ofn32
.nMaxFileTitle
= lpofn
->nMaxFileTitle
;
591 ofn32
.lpstrInitialDir
= MapSL( lpofn
->lpstrInitialDir
);
592 ofn32
.lpstrTitle
= MapSL( lpofn
->lpstrTitle
);
593 ofn32
.Flags
= (lpofn
->Flags
& ~OFN_ENABLETEMPLATE
) | OFN_ENABLEHOOK
;
594 ofn32
.nFileOffset
= lpofn
->nFileOffset
;
595 ofn32
.nFileExtension
= lpofn
->nFileExtension
;
596 ofn32
.lpstrDefExt
= MapSL( lpofn
->lpstrDefExt
);
597 ofn32
.lCustData
= lpofn
->lCustData
;
598 ofn32
.lpfnHook
= dummy_hook
; /* this is to force old 3.1 dialog style */
600 if (lpofn
->Flags
& OFN_ENABLETEMPLATE
)
602 HRSRC16 res
= FindResource16( lpofn
->hInstance
, MapSL(lpofn
->lpTemplateName
), (LPCSTR
)RT_DIALOG
);
603 HGLOBAL16 handle
= LoadResource16( lpofn
->hInstance
, res
);
604 DWORD size
= SizeofResource16( lpofn
->hInstance
, res
);
605 void *ptr
= LockResource16( handle
);
607 if (ptr
&& (template = convert_dialog( ptr
, size
)))
609 ofn32
.hInstance
= (HINSTANCE
)template;
610 ofn32
.Flags
|= OFN_ENABLETEMPLATEHANDLE
;
612 FreeResource16( handle
);
615 if (lpofn
->Flags
& OFN_ENABLEHOOK
) ofn32
.lpfnHook
= alloc_hook( lpofn
->lpfnHook
);
617 if ((ret
= GetOpenFileNameA( &ofn32
)))
619 lpofn
->nFilterIndex
= ofn32
.nFilterIndex
;
620 lpofn
->nFileOffset
= ofn32
.nFileOffset
;
621 lpofn
->nFileExtension
= ofn32
.nFileExtension
;
623 HeapFree( GetProcessHeap(), 0, template );
627 /***********************************************************************
628 * GetSaveFileName (COMMDLG.2)
630 * Creates a dialog box for the user to select a file to save.
633 * TRUE on success: user enters a valid file
634 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
637 * unknown. There are some FIXMEs left.
639 BOOL16 WINAPI
GetSaveFileName16( SEGPTR ofn
) /* [in/out] address of structure with data*/
641 LPOPENFILENAME16 lpofn
= MapSL(ofn
);
642 LPDLGTEMPLATEA
template = NULL
;
646 if (!lpofn
) return FALSE
;
648 ofn32
.lStructSize
= OPENFILENAME_SIZE_VERSION_400A
;
649 ofn32
.hwndOwner
= HWND_32( lpofn
->hwndOwner
);
650 ofn32
.lpstrFilter
= MapSL( lpofn
->lpstrFilter
);
651 ofn32
.lpstrCustomFilter
= MapSL( lpofn
->lpstrCustomFilter
);
652 ofn32
.nMaxCustFilter
= lpofn
->nMaxCustFilter
;
653 ofn32
.nFilterIndex
= lpofn
->nFilterIndex
;
654 ofn32
.lpstrFile
= MapSL( lpofn
->lpstrFile
);
655 ofn32
.nMaxFile
= lpofn
->nMaxFile
;
656 ofn32
.lpstrFileTitle
= MapSL( lpofn
->lpstrFileTitle
);
657 ofn32
.nMaxFileTitle
= lpofn
->nMaxFileTitle
;
658 ofn32
.lpstrInitialDir
= MapSL( lpofn
->lpstrInitialDir
);
659 ofn32
.lpstrTitle
= MapSL( lpofn
->lpstrTitle
);
660 ofn32
.Flags
= (lpofn
->Flags
& ~OFN_ENABLETEMPLATE
) | OFN_ENABLEHOOK
;
661 ofn32
.nFileOffset
= lpofn
->nFileOffset
;
662 ofn32
.nFileExtension
= lpofn
->nFileExtension
;
663 ofn32
.lpstrDefExt
= MapSL( lpofn
->lpstrDefExt
);
664 ofn32
.lCustData
= lpofn
->lCustData
;
665 ofn32
.lpfnHook
= dummy_hook
; /* this is to force old 3.1 dialog style */
667 if (lpofn
->Flags
& OFN_ENABLETEMPLATE
)
669 HRSRC16 res
= FindResource16( lpofn
->hInstance
, MapSL(lpofn
->lpTemplateName
), (LPCSTR
)RT_DIALOG
);
670 HGLOBAL16 handle
= LoadResource16( lpofn
->hInstance
, res
);
671 DWORD size
= SizeofResource16( lpofn
->hInstance
, res
);
672 void *ptr
= LockResource16( handle
);
674 if (ptr
&& (template = convert_dialog( ptr
, size
)))
676 ofn32
.hInstance
= (HINSTANCE
)template;
677 ofn32
.Flags
|= OFN_ENABLETEMPLATEHANDLE
;
679 FreeResource16( handle
);
682 if (lpofn
->Flags
& OFN_ENABLEHOOK
) ofn32
.lpfnHook
= alloc_hook( lpofn
->lpfnHook
);
684 if ((ret
= GetSaveFileNameA( &ofn32
)))
686 lpofn
->nFilterIndex
= ofn32
.nFilterIndex
;
687 lpofn
->nFileOffset
= ofn32
.nFileOffset
;
688 lpofn
->nFileExtension
= ofn32
.nFileExtension
;
690 HeapFree( GetProcessHeap(), 0, template );
695 /***********************************************************************
696 * GetFileTitle (COMMDLG.27)
698 short WINAPI
GetFileTitle16(LPCSTR lpFile
, LPSTR lpTitle
, UINT16 cbBuf
)
700 return GetFileTitleA(lpFile
, lpTitle
, cbBuf
);