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
= CURRENT_SS
;
225 context
.SegCs
= SELECTOROF( hook
);
226 context
.Eip
= OFFSETOF( hook
);
227 context
.Ebp
= CURRENT_SP
+ FIELD_OFFSET( STACK16FRAME
, bp
);
228 context
.Eax
= context
.SegDs
;
230 params
[4] = HWND_16( hwnd
);
233 params
[1] = HIWORD( lp
);
234 params
[0] = LOWORD( lp
);
235 WOWCallback16Ex( 0, WCB16_REGS
, sizeof(params
), params
, (DWORD
*)&context
);
236 return LOWORD( context
.Eax
);
239 static UINT_PTR CALLBACK
call_hook_proc( WNDPROC16 hook
, HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
248 CREATESTRUCTA
*cs32
= (CREATESTRUCTA
*)lp
;
251 CREATESTRUCT32Ato16( cs32
, &cs
);
252 cs
.lpszName
= MapLS( cs32
->lpszName
);
253 cs
.lpszClass
= MapLS( cs32
->lpszClass
);
255 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
257 UnMapLS( cs
.lpszName
);
258 UnMapLS( cs
.lpszClass
);
261 case WM_GETMINMAXINFO
:
263 MINMAXINFO
*mmi32
= (MINMAXINFO
*)lp
;
266 MINMAXINFO32to16( mmi32
, &mmi
);
268 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
270 MINMAXINFO16to32( &mmi
, mmi32
);
275 NCCALCSIZE_PARAMS
*nc32
= (NCCALCSIZE_PARAMS
*)lp
;
276 NCCALCSIZE_PARAMS16 nc
;
279 RECT32to16( &nc32
->rgrc
[0], &nc
.rgrc
[0] );
282 RECT32to16( &nc32
->rgrc
[1], &nc
.rgrc
[1] );
283 RECT32to16( &nc32
->rgrc
[2], &nc
.rgrc
[2] );
284 WINDOWPOS32to16( nc32
->lppos
, &winpos
);
285 nc
.lppos
= MapLS( &winpos
);
288 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
290 RECT16to32( &nc
.rgrc
[0], &nc32
->rgrc
[0] );
293 RECT16to32( &nc
.rgrc
[1], &nc32
->rgrc
[1] );
294 RECT16to32( &nc
.rgrc
[2], &nc32
->rgrc
[2] );
295 WINDOWPOS16to32( &winpos
, nc32
->lppos
);
300 case WM_WINDOWPOSCHANGING
:
301 case WM_WINDOWPOSCHANGED
:
303 WINDOWPOS
*winpos32
= (WINDOWPOS
*)lp
;
306 WINDOWPOS32to16( winpos32
, &winpos
);
307 lp
= MapLS( &winpos
);
308 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
310 WINDOWPOS16to32( &winpos
, winpos32
);
315 COMPAREITEMSTRUCT
*cis32
= (COMPAREITEMSTRUCT
*)lp
;
316 COMPAREITEMSTRUCT16 cis
;
317 cis
.CtlType
= cis32
->CtlType
;
318 cis
.CtlID
= cis32
->CtlID
;
319 cis
.hwndItem
= HWND_16( cis32
->hwndItem
);
320 cis
.itemID1
= cis32
->itemID1
;
321 cis
.itemData1
= cis32
->itemData1
;
322 cis
.itemID2
= cis32
->itemID2
;
323 cis
.itemData2
= cis32
->itemData2
;
325 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
331 DELETEITEMSTRUCT
*dis32
= (DELETEITEMSTRUCT
*)lp
;
332 DELETEITEMSTRUCT16 dis
;
333 dis
.CtlType
= dis32
->CtlType
;
334 dis
.CtlID
= dis32
->CtlID
;
335 dis
.itemID
= dis32
->itemID
;
336 dis
.hwndItem
= (dis
.CtlType
== ODT_MENU
) ? (HWND16
)LOWORD(dis32
->hwndItem
)
337 : HWND_16( dis32
->hwndItem
);
338 dis
.itemData
= dis32
->itemData
;
340 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
346 DRAWITEMSTRUCT
*dis32
= (DRAWITEMSTRUCT
*)lp
;
347 DRAWITEMSTRUCT16 dis
;
348 dis
.CtlType
= dis32
->CtlType
;
349 dis
.CtlID
= dis32
->CtlID
;
350 dis
.itemID
= dis32
->itemID
;
351 dis
.itemAction
= dis32
->itemAction
;
352 dis
.itemState
= dis32
->itemState
;
353 dis
.hwndItem
= HWND_16( dis32
->hwndItem
);
354 dis
.hDC
= HDC_16( dis32
->hDC
);
355 dis
.itemData
= dis32
->itemData
;
356 dis
.rcItem
.left
= dis32
->rcItem
.left
;
357 dis
.rcItem
.top
= dis32
->rcItem
.top
;
358 dis
.rcItem
.right
= dis32
->rcItem
.right
;
359 dis
.rcItem
.bottom
= dis32
->rcItem
.bottom
;
361 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
367 MEASUREITEMSTRUCT
*mis32
= (MEASUREITEMSTRUCT
*)lp
;
368 MEASUREITEMSTRUCT16 mis
;
369 mis
.CtlType
= mis32
->CtlType
;
370 mis
.CtlID
= mis32
->CtlID
;
371 mis
.itemID
= mis32
->itemID
;
372 mis
.itemWidth
= mis32
->itemWidth
;
373 mis
.itemHeight
= mis32
->itemHeight
;
374 mis
.itemData
= mis32
->itemData
;
376 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
378 mis32
->itemWidth
= mis
.itemWidth
;
379 mis32
->itemHeight
= mis
.itemHeight
;
384 COPYDATASTRUCT
*cds32
= (COPYDATASTRUCT
*)lp
;
385 COPYDATASTRUCT16 cds
;
387 cds
.dwData
= cds32
->dwData
;
388 cds
.cbData
= cds32
->cbData
;
389 cds
.lpData
= MapLS( cds32
->lpData
);
391 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
393 UnMapLS( cds
.lpData
);
399 MSG
*msg32
= (MSG
*)lp
;
402 msg16
.hwnd
= HWND_16( msg32
->hwnd
);
403 msg16
.message
= msg32
->message
;
404 msg16
.wParam
= msg32
->wParam
;
405 msg16
.lParam
= msg32
->lParam
;
406 msg16
.time
= msg32
->time
;
407 msg16
.pt
.x
= msg32
->pt
.x
;
408 msg16
.pt
.y
= msg32
->pt
.y
;
409 lp
= MapLS( &msg16
);
410 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
414 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
419 MDINEXTMENU
*next
= (MDINEXTMENU
*)lp
;
420 ret
= call_hook16( hook
, hwnd
, msg
, wp
, (LPARAM
)next
->hmenuIn
);
421 result
= GetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
);
422 next
->hmenuNext
= HMENU_32( LOWORD(result
) );
423 next
->hwndNext
= HWND_32( HIWORD(result
) );
424 SetWindowLongPtrW( hwnd
, DWLP_MSGRESULT
, 0 );
428 case WM_ASKCBFORMATNAME
:
429 wp
= min( wp
, 0xff80 ); /* Must be < 64K */
433 case WM_WININICHANGE
:
434 case WM_DEVMODECHANGE
:
435 lp
= MapLS( (void *)lp
);
436 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
443 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( (HWND16
)lp
, HIWORD(wp
) ));
447 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( HIWORD(wp
), (HWND16
)lp
));
449 case WM_CTLCOLORMSGBOX
:
450 case WM_CTLCOLOREDIT
:
451 case WM_CTLCOLORLISTBOX
:
454 case WM_CTLCOLORSCROLLBAR
:
455 case WM_CTLCOLORSTATIC
:
456 ret
= call_hook16( hook
, hwnd
, WM_CTLCOLOR
, wp
, MAKELPARAM( (HWND16
)lp
, msg
- WM_CTLCOLORMSGBOX
));
459 if(HIWORD(wp
) & MF_POPUP
)
462 if ((HIWORD(wp
) != 0xffff) || lp
)
464 if ((hmenu
= GetSubMenu( (HMENU
)lp
, LOWORD(wp
) )))
466 ret
= call_hook16( hook
, hwnd
, msg
, HMENU_16(hmenu
),
467 MAKELPARAM( HIWORD(wp
), (HMENU16
)lp
) );
474 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( HIWORD(wp
), (HMENU16
)lp
));
476 case WM_PARENTNOTIFY
:
477 if ((LOWORD(wp
) == WM_CREATE
) || (LOWORD(wp
) == WM_DESTROY
))
478 ret
= call_hook16( hook
, hwnd
, msg
, wp
, MAKELPARAM( (HWND16
)lp
, HIWORD(wp
) ));
480 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
483 ret
= call_hook16( hook
, hwnd
, msg
, wp
, HTASK_16( lp
));
486 ret
= call_hook16( hook
, hwnd
, msg
, wp
, lp
);
493 #include "pshpack1.h"
496 BYTE popl_eax
; /* popl %eax */
497 BYTE pushl_hook
; /* pushl $hook_ptr */
498 LPOFNHOOKPROC16 hook_ptr
;
499 BYTE pushl_eax
; /* pushl %eax */
500 BYTE jmp
; /* jmp call_hook */
505 static LPOFNHOOKPROC
alloc_hook( LPOFNHOOKPROC16 hook16
)
507 static struct hook_proc
*hooks
;
508 static unsigned int count
;
509 SIZE_T size
= 0x1000;
512 if (!hooks
&& !(hooks
= VirtualAlloc( NULL
, size
, MEM_COMMIT
, PAGE_EXECUTE_READWRITE
)))
515 for (i
= 0; i
< count
; i
++)
516 if (hooks
[i
].hook_ptr
== hook16
)
517 return (LPOFNHOOKPROC
)&hooks
[i
];
519 if (count
>= size
/ sizeof(*hooks
))
521 FIXME( "all hooks are in use\n" );
525 hooks
[count
].popl_eax
= 0x58;
526 hooks
[count
].pushl_hook
= 0x68;
527 hooks
[count
].hook_ptr
= hook16
;
528 hooks
[count
].pushl_eax
= 0x50;
529 hooks
[count
].jmp
= 0xe9;
530 hooks
[count
].call_hook
= (char *)call_hook_proc
- (char *)(&hooks
[count
].call_hook
+ 1);
531 return (LPOFNHOOKPROC
)&hooks
[count
++];
534 static UINT_PTR CALLBACK
dummy_hook( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
539 /***********************************************************************
540 * FileOpenDlgProc (COMMDLG.6)
542 BOOL16 CALLBACK
FileOpenDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
, LPARAM lParam
)
544 FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16
, wMsg
, wParam
, lParam
);
548 /***********************************************************************
549 * FileSaveDlgProc (COMMDLG.7)
551 BOOL16 CALLBACK
FileSaveDlgProc16(HWND16 hWnd16
, UINT16 wMsg
, WPARAM16 wParam
, LPARAM lParam
)
553 FIXME( "%04x %04x %04x %08lx: stub\n", hWnd16
, wMsg
, wParam
, lParam
);
557 /***********************************************************************
558 * GetOpenFileName (COMMDLG.1)
560 * Creates a dialog box for the user to select a file to open.
563 * TRUE on success: user selected a valid file
564 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
567 * unknown, there are some FIXMEs left.
569 BOOL16 WINAPI
GetOpenFileName16( SEGPTR ofn
) /* [in/out] address of structure with data*/
571 LPOPENFILENAME16 lpofn
= MapSL(ofn
);
572 LPDLGTEMPLATEA
template = NULL
;
576 if (!lpofn
) return FALSE
;
578 ofn32
.lStructSize
= OPENFILENAME_SIZE_VERSION_400A
;
579 ofn32
.hwndOwner
= HWND_32( lpofn
->hwndOwner
);
580 ofn32
.lpstrFilter
= MapSL( lpofn
->lpstrFilter
);
581 ofn32
.lpstrCustomFilter
= MapSL( lpofn
->lpstrCustomFilter
);
582 ofn32
.nMaxCustFilter
= lpofn
->nMaxCustFilter
;
583 ofn32
.nFilterIndex
= lpofn
->nFilterIndex
;
584 ofn32
.lpstrFile
= MapSL( lpofn
->lpstrFile
);
585 ofn32
.nMaxFile
= lpofn
->nMaxFile
;
586 ofn32
.lpstrFileTitle
= MapSL( lpofn
->lpstrFileTitle
);
587 ofn32
.nMaxFileTitle
= lpofn
->nMaxFileTitle
;
588 ofn32
.lpstrInitialDir
= MapSL( lpofn
->lpstrInitialDir
);
589 ofn32
.lpstrTitle
= MapSL( lpofn
->lpstrTitle
);
590 ofn32
.Flags
= (lpofn
->Flags
& ~OFN_ENABLETEMPLATE
) | OFN_ENABLEHOOK
;
591 ofn32
.nFileOffset
= lpofn
->nFileOffset
;
592 ofn32
.nFileExtension
= lpofn
->nFileExtension
;
593 ofn32
.lpstrDefExt
= MapSL( lpofn
->lpstrDefExt
);
594 ofn32
.lCustData
= lpofn
->lCustData
;
595 ofn32
.lpfnHook
= dummy_hook
; /* this is to force old 3.1 dialog style */
597 if (lpofn
->Flags
& OFN_ENABLETEMPLATE
)
599 HRSRC16 res
= FindResource16( lpofn
->hInstance
, MapSL(lpofn
->lpTemplateName
), (LPCSTR
)RT_DIALOG
);
600 HGLOBAL16 handle
= LoadResource16( lpofn
->hInstance
, res
);
601 DWORD size
= SizeofResource16( lpofn
->hInstance
, res
);
602 void *ptr
= LockResource16( handle
);
604 if (ptr
&& (template = convert_dialog( ptr
, size
)))
606 ofn32
.hInstance
= (HINSTANCE
)template;
607 ofn32
.Flags
|= OFN_ENABLETEMPLATEHANDLE
;
609 FreeResource16( handle
);
612 if (lpofn
->Flags
& OFN_ENABLEHOOK
) ofn32
.lpfnHook
= alloc_hook( lpofn
->lpfnHook
);
614 if ((ret
= GetOpenFileNameA( &ofn32
)))
616 lpofn
->nFilterIndex
= ofn32
.nFilterIndex
;
617 lpofn
->nFileOffset
= ofn32
.nFileOffset
;
618 lpofn
->nFileExtension
= ofn32
.nFileExtension
;
620 HeapFree( GetProcessHeap(), 0, template );
624 /***********************************************************************
625 * GetSaveFileName (COMMDLG.2)
627 * Creates a dialog box for the user to select a file to save.
630 * TRUE on success: user enters a valid file
631 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
634 * unknown. There are some FIXMEs left.
636 BOOL16 WINAPI
GetSaveFileName16( SEGPTR ofn
) /* [in/out] address of structure with data*/
638 LPOPENFILENAME16 lpofn
= MapSL(ofn
);
639 LPDLGTEMPLATEA
template = NULL
;
643 if (!lpofn
) return FALSE
;
645 ofn32
.lStructSize
= OPENFILENAME_SIZE_VERSION_400A
;
646 ofn32
.hwndOwner
= HWND_32( lpofn
->hwndOwner
);
647 ofn32
.lpstrFilter
= MapSL( lpofn
->lpstrFilter
);
648 ofn32
.lpstrCustomFilter
= MapSL( lpofn
->lpstrCustomFilter
);
649 ofn32
.nMaxCustFilter
= lpofn
->nMaxCustFilter
;
650 ofn32
.nFilterIndex
= lpofn
->nFilterIndex
;
651 ofn32
.lpstrFile
= MapSL( lpofn
->lpstrFile
);
652 ofn32
.nMaxFile
= lpofn
->nMaxFile
;
653 ofn32
.lpstrFileTitle
= MapSL( lpofn
->lpstrFileTitle
);
654 ofn32
.nMaxFileTitle
= lpofn
->nMaxFileTitle
;
655 ofn32
.lpstrInitialDir
= MapSL( lpofn
->lpstrInitialDir
);
656 ofn32
.lpstrTitle
= MapSL( lpofn
->lpstrTitle
);
657 ofn32
.Flags
= (lpofn
->Flags
& ~OFN_ENABLETEMPLATE
) | OFN_ENABLEHOOK
;
658 ofn32
.nFileOffset
= lpofn
->nFileOffset
;
659 ofn32
.nFileExtension
= lpofn
->nFileExtension
;
660 ofn32
.lpstrDefExt
= MapSL( lpofn
->lpstrDefExt
);
661 ofn32
.lCustData
= lpofn
->lCustData
;
662 ofn32
.lpfnHook
= dummy_hook
; /* this is to force old 3.1 dialog style */
664 if (lpofn
->Flags
& OFN_ENABLETEMPLATE
)
666 HRSRC16 res
= FindResource16( lpofn
->hInstance
, MapSL(lpofn
->lpTemplateName
), (LPCSTR
)RT_DIALOG
);
667 HGLOBAL16 handle
= LoadResource16( lpofn
->hInstance
, res
);
668 DWORD size
= SizeofResource16( lpofn
->hInstance
, res
);
669 void *ptr
= LockResource16( handle
);
671 if (ptr
&& (template = convert_dialog( ptr
, size
)))
673 ofn32
.hInstance
= (HINSTANCE
)template;
674 ofn32
.Flags
|= OFN_ENABLETEMPLATEHANDLE
;
676 FreeResource16( handle
);
679 if (lpofn
->Flags
& OFN_ENABLEHOOK
) ofn32
.lpfnHook
= alloc_hook( lpofn
->lpfnHook
);
681 if ((ret
= GetSaveFileNameA( &ofn32
)))
683 lpofn
->nFilterIndex
= ofn32
.nFilterIndex
;
684 lpofn
->nFileOffset
= ofn32
.nFileOffset
;
685 lpofn
->nFileExtension
= ofn32
.nFileExtension
;
687 HeapFree( GetProcessHeap(), 0, template );
692 /***********************************************************************
693 * GetFileTitle (COMMDLG.27)
695 short WINAPI
GetFileTitle16(LPCSTR lpFile
, LPSTR lpTitle
, UINT16 cbBuf
)
697 return GetFileTitleA(lpFile
, lpTitle
, cbBuf
);