Sync to Wine-0_9_16:
[reactos.git] / reactos / dll / win32 / comdlg32 / filedlg16.c
1 /*
2 * COMMDLG - 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 <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wine/winbase16.h"
25 #include "winuser.h"
26 #include "wine/winuser16.h"
27 #include "wine/debug.h"
28 #include "cderr.h"
29 #include "commdlg.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
32
33 #include "cdlg.h"
34 #include "cdlg16.h"
35 #include "filedlg31.h"
36
37 typedef struct tagFD16_PRIVATE
38 {
39 HANDLE16 hDlgTmpl16; /* handle for resource 16 */
40 HANDLE16 hResource16; /* handle for allocated resource 16 */
41 HANDLE16 hGlobal16; /* 16 bits mem block (resources) */
42 OPENFILENAME16 *ofn16; /* original structure if 16 bits dialog */
43 } FD16_PRIVATE, *PFD16_PRIVATE;
44
45 /************************************************************************
46 * FD16_MapOfnStruct16 [internal]
47 * map a 16 bits structure to an Unicode one
48 */
49 static void FD16_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open)
50 {
51 OPENFILENAMEA ofnA;
52 /* first convert to linear pointers */
53 memset(&ofnA, 0, sizeof(OPENFILENAMEA));
54 ofnA.lStructSize = sizeof(OPENFILENAMEA);
55 ofnA.hwndOwner = HWND_32(ofn16->hwndOwner);
56 ofnA.hInstance = HINSTANCE_32(ofn16->hInstance);
57 if (ofn16->lpstrFilter)
58 ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter);
59 if (ofn16->lpstrCustomFilter)
60 ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter);
61 ofnA.nMaxCustFilter = ofn16->nMaxCustFilter;
62 ofnA.nFilterIndex = ofn16->nFilterIndex;
63 ofnA.lpstrFile = MapSL(ofn16->lpstrFile);
64 ofnA.nMaxFile = ofn16->nMaxFile;
65 ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle);
66 ofnA.nMaxFileTitle = ofn16->nMaxFileTitle;
67 ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir);
68 ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle);
69 ofnA.Flags = ofn16->Flags;
70 ofnA.nFileOffset = ofn16->nFileOffset;
71 ofnA.nFileExtension = ofn16->nFileExtension;
72 ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt);
73 if (HIWORD(ofn16->lpTemplateName))
74 ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName);
75 else
76 ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */
77 /* now calls the 32 bits Ansi to Unicode version to complete the job */
78 FD31_MapOfnStructA(&ofnA, ofnW, open);
79 }
80
81 /***********************************************************************
82 * FD16_GetTemplate [internal]
83 *
84 * Get a template (FALSE if failure) when 16 bits dialogs are used
85 * by a 16 bits application
86 *
87 */
88 static BOOL FD16_GetTemplate(PFD31_DATA lfs)
89 {
90 PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
91 LPOPENFILENAME16 ofn16 = priv->ofn16;
92 LPCVOID template;
93 HGLOBAL16 hGlobal16 = 0;
94
95 if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE)
96 priv->hDlgTmpl16 = ofn16->hInstance;
97 else if (ofn16->Flags & OFN_ENABLETEMPLATE)
98 {
99 HANDLE16 hResInfo;
100 if (!(hResInfo = FindResource16(ofn16->hInstance,
101 MapSL(ofn16->lpTemplateName),
102 (LPSTR)RT_DIALOG)))
103 {
104 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
105 return FALSE;
106 }
107 if (!(priv->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo )))
108 {
109 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
110 return FALSE;
111 }
112 priv->hResource16 = priv->hDlgTmpl16;
113 }
114 else
115 { /* get resource from (32 bits) own Wine resource; convert it to 16 */
116 HRSRC hResInfo;
117 HGLOBAL hDlgTmpl32;
118 LPCVOID template32;
119 DWORD size;
120
121 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
122 lfs->open ? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
123 {
124 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
125 return FALSE;
126 }
127 if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) ||
128 !(template32 = LockResource( hDlgTmpl32 )))
129 {
130 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
131 return FALSE;
132 }
133 size = SizeofResource(COMDLG32_hInstance, hResInfo);
134 hGlobal16 = GlobalAlloc16(0, size);
135 if (!hGlobal16)
136 {
137 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
138 ERR("alloc failure for %ld bytes\n", size);
139 return FALSE;
140 }
141 template = GlobalLock16(hGlobal16);
142 if (!template)
143 {
144 COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE);
145 ERR("global lock failure for %x handle\n", hGlobal16);
146 GlobalFree16(hGlobal16);
147 return FALSE;
148 }
149 ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template);
150 priv->hDlgTmpl16 = hGlobal16;
151 priv->hGlobal16 = hGlobal16;
152 }
153 return TRUE;
154 }
155
156 /************************************************************************
157 * FD16_Init [internal]
158 * called from the common 16/32 code to initialize 16 bit data
159 */
160 static BOOL CALLBACK FD16_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
161 {
162 PFD16_PRIVATE priv;
163
164 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD16_PRIVATE));
165 lfs->private1632 = priv;
166 if (NULL == lfs->private1632) return FALSE;
167
168 priv->ofn16 = MapSL(lParam);
169 if (priv->ofn16->Flags & OFN_ENABLEHOOK)
170 if (priv->ofn16->lpfnHook)
171 lfs->hook = TRUE;
172
173 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
174 FD16_MapOfnStruct16(priv->ofn16, lfs->ofnW, lfs->open);
175
176 if (! FD16_GetTemplate(lfs)) return FALSE;
177
178 return TRUE;
179 }
180
181 /***********************************************************************
182 * FD16_CallWindowProc [internal]
183 *
184 * called from the common 16/32 code to call the appropriate hook
185 */
186 static BOOL CALLBACK FD16_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
187 LPARAM lParam)
188 {
189 PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
190
191 if (priv->ofn16)
192 {
193 return (BOOL16) CallWindowProc16(
194 (WNDPROC16)priv->ofn16->lpfnHook, HWND_16(lfs->hwnd),
195 (UINT16)wMsg, (WPARAM16)wParam, lParam);
196 }
197 return FALSE;
198 }
199
200
201 /***********************************************************************
202 * FD31_UpdateResult [internal]
203 * update the real client structures
204 */
205 static void CALLBACK FD16_UpdateResult(PFD31_DATA lfs)
206 {
207 PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
208 LPOPENFILENAMEW ofnW = lfs->ofnW;
209
210 if (priv->ofn16)
211 { /* we have to convert to short (8.3) path */
212 char tmp[1024]; /* MAX_PATHNAME_LEN */
213 LPOPENFILENAME16 ofn16 = priv->ofn16;
214 char *dest = MapSL(ofn16->lpstrFile);
215 char *bs16;
216 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
217 tmp, sizeof(tmp), NULL, NULL ))
218 tmp[sizeof(tmp)-1] = 0;
219 GetShortPathNameA(tmp, dest, ofn16->nMaxFile);
220
221 /* the same procedure as every year... */
222 if((bs16 = strrchr(dest, '\\')) != NULL)
223 ofn16->nFileOffset = bs16 - dest +1;
224 else
225 ofn16->nFileOffset = 0;
226 ofn16->nFileExtension = 0;
227 while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0')
228 ofn16->nFileExtension++;
229 if (dest[ofn16->nFileExtension] == '\0')
230 ofn16->nFileExtension = 0;
231 else
232 ofn16->nFileExtension++;
233 }
234 }
235
236
237 /***********************************************************************
238 * FD16_UpdateFileTitle [internal]
239 * update the real client structures
240 */
241 static void CALLBACK FD16_UpdateFileTitle(PFD31_DATA lfs)
242 {
243 PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
244 LPOPENFILENAMEW ofnW = lfs->ofnW;
245
246 if (priv->ofn16)
247 {
248 char *dest = MapSL(priv->ofn16->lpstrFileTitle);
249 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
250 dest, ofnW->nMaxFileTitle, NULL, NULL ))
251 dest[ofnW->nMaxFileTitle-1] = 0;
252 }
253 }
254
255
256 /***********************************************************************
257 * FD16_SendLbGetCurSel [internal]
258 * retrieve selected listbox item
259 */
260 static LRESULT CALLBACK FD16_SendLbGetCurSel(PFD31_DATA lfs)
261 {
262 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL16, 0, 0);
263 }
264
265
266 /************************************************************************
267 * FD16_Destroy [internal]
268 * called from the common 16/32 code to cleanup 32 bit data
269 */
270 static void CALLBACK FD16_Destroy(PFD31_DATA lfs)
271 {
272 PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
273
274 /* free resources for a 16 bits dialog */
275 if (NULL != priv)
276 {
277 if (priv->hResource16) FreeResource16(priv->hResource16);
278 if (priv->hGlobal16)
279 {
280 GlobalUnlock16(priv->hGlobal16);
281 GlobalFree16(priv->hGlobal16);
282 }
283 FD31_FreeOfnW(lfs->ofnW);
284 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
285 }
286 }
287
288 static void FD16_SetupCallbacks(PFD31_CALLBACKS callbacks)
289 {
290 callbacks->Init = FD16_Init;
291 callbacks->CWP = FD16_CallWindowProc;
292 callbacks->UpdateResult = FD16_UpdateResult;
293 callbacks->UpdateFileTitle = FD16_UpdateFileTitle;
294 callbacks->SendLbGetCurSel = FD16_SendLbGetCurSel;
295 callbacks->Destroy = FD16_Destroy;
296 }
297
298 /***********************************************************************
299 * FD16_MapDrawItemStruct [internal]
300 * map a 16 bits drawitem struct to 32
301 */
302 static void FD16_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis)
303 {
304 lpdis->CtlType = lpdis16->CtlType;
305 lpdis->CtlID = lpdis16->CtlID;
306 lpdis->itemID = lpdis16->itemID;
307 lpdis->itemAction = lpdis16->itemAction;
308 lpdis->itemState = lpdis16->itemState;
309 lpdis->hwndItem = HWND_32(lpdis16->hwndItem);
310 lpdis->hDC = HDC_32(lpdis16->hDC);
311 lpdis->rcItem.right = lpdis16->rcItem.right;
312 lpdis->rcItem.left = lpdis16->rcItem.left;
313 lpdis->rcItem.top = lpdis16->rcItem.top;
314 lpdis->rcItem.bottom = lpdis16->rcItem.bottom;
315 lpdis->itemData = lpdis16->itemData;
316 }
317
318
319 /***********************************************************************
320 * FD16_WMMeasureItem16 [internal]
321 */
322 static LONG FD16_WMMeasureItem(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam)
323 {
324 LPMEASUREITEMSTRUCT16 lpmeasure;
325
326 lpmeasure = MapSL(lParam);
327 lpmeasure->itemHeight = FD31_GetFldrHeight();
328 return TRUE;
329 }
330
331 /* ------------------ Dialog procedures ---------------------- */
332
333 /***********************************************************************
334 * FileOpenDlgProc (COMMDLG.6)
335 */
336 BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
337 {
338 HWND hWnd = HWND_32(hWnd16);
339 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
340 DRAWITEMSTRUCT dis;
341
342 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
343 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
344 {
345 LRESULT lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
346 if (lRet)
347 return lRet; /* else continue message processing */
348 }
349 switch (wMsg)
350 {
351 case WM_INITDIALOG:
352 return FD31_WMInitDialog(hWnd, wParam, lParam);
353
354 case WM_MEASUREITEM:
355 return FD16_WMMeasureItem(hWnd16, wParam, lParam);
356
357 case WM_DRAWITEM:
358 FD16_MapDrawItemStruct(MapSL(lParam), &dis);
359 return FD31_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis);
360
361 case WM_COMMAND:
362 return FD31_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs);
363 #if 0
364 case WM_CTLCOLOR:
365 SetBkColor((HDC16)wParam, 0x00C0C0C0);
366 switch (HIWORD(lParam))
367 {
368 case CTLCOLOR_BTN:
369 SetTextColor((HDC16)wParam, 0x00000000);
370 return hGRAYBrush;
371 case CTLCOLOR_STATIC:
372 SetTextColor((HDC16)wParam, 0x00000000);
373 return hGRAYBrush;
374 }
375 break;
376 #endif
377 }
378 return FALSE;
379 }
380
381 /***********************************************************************
382 * FileSaveDlgProc (COMMDLG.7)
383 */
384 BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
385 {
386 HWND hWnd = HWND_32(hWnd16);
387 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
388 DRAWITEMSTRUCT dis;
389
390 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
391 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
392 {
393 LRESULT lRet;
394 lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
395 if (lRet)
396 return lRet; /* else continue message processing */
397 }
398 switch (wMsg) {
399 case WM_INITDIALOG:
400 return FD31_WMInitDialog(hWnd, wParam, lParam);
401
402 case WM_MEASUREITEM:
403 return FD16_WMMeasureItem(hWnd16, wParam, lParam);
404
405 case WM_DRAWITEM:
406 FD16_MapDrawItemStruct(MapSL(lParam), &dis);
407 return FD31_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis);
408
409 case WM_COMMAND:
410 return FD31_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs);
411 }
412
413 /*
414 case WM_CTLCOLOR:
415 SetBkColor((HDC16)wParam, 0x00C0C0C0);
416 switch (HIWORD(lParam))
417 {
418 case CTLCOLOR_BTN:
419 SetTextColor((HDC16)wParam, 0x00000000);
420 return hGRAYBrush;
421 case CTLCOLOR_STATIC:
422 SetTextColor((HDC16)wParam, 0x00000000);
423 return hGRAYBrush;
424 }
425 return FALSE;
426
427 */
428 return FALSE;
429 }
430
431 /* ------------------ APIs ---------------------- */
432
433 /***********************************************************************
434 * GetOpenFileName (COMMDLG.1)
435 *
436 * Creates a dialog box for the user to select a file to open.
437 *
438 * RETURNS
439 * TRUE on success: user selected a valid file
440 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
441 *
442 * BUGS
443 * unknown, there are some FIXME's left.
444 */
445 BOOL16 WINAPI GetOpenFileName16(
446 SEGPTR ofn /* [in/out] address of structure with data*/
447 )
448 {
449 HINSTANCE16 hInst;
450 BOOL bRet = FALSE;
451 LPOPENFILENAME16 lpofn = MapSL(ofn);
452 PFD31_DATA lfs;
453 FARPROC16 ptr;
454 FD31_CALLBACKS callbacks;
455 PFD16_PRIVATE priv;
456
457 if (!lpofn || !FD31_Init()) return FALSE;
458
459 FD16_SetupCallbacks(&callbacks);
460 lfs = FD31_AllocPrivate((LPARAM) ofn, OPEN_DIALOG, &callbacks, 0);
461 if (lfs)
462 {
463 priv = (PFD16_PRIVATE) lfs->private1632;
464 hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE );
465 ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6);
466 bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner,
467 (DLGPROC16) ptr, (LPARAM) lfs);
468 FD31_DestroyPrivate(lfs);
469 }
470
471 TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
472 return bRet;
473 }
474
475 /***********************************************************************
476 * GetSaveFileName (COMMDLG.2)
477 *
478 * Creates a dialog box for the user to select a file to save.
479 *
480 * RETURNS
481 * TRUE on success: user enters a valid file
482 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
483 *
484 * BUGS
485 * unknown. There are some FIXME's left.
486 */
487 BOOL16 WINAPI GetSaveFileName16(
488 SEGPTR ofn /* [in/out] addess of structure with data*/
489 )
490 {
491 HINSTANCE16 hInst;
492 BOOL bRet = FALSE;
493 LPOPENFILENAME16 lpofn = MapSL(ofn);
494 PFD31_DATA lfs;
495 FARPROC16 ptr;
496 FD31_CALLBACKS callbacks;
497 PFD16_PRIVATE priv;
498
499 if (!lpofn || !FD31_Init()) return FALSE;
500
501 FD16_SetupCallbacks(&callbacks);
502 lfs = FD31_AllocPrivate((LPARAM) ofn, SAVE_DIALOG, &callbacks, 0);
503 if (lfs)
504 {
505 priv = (PFD16_PRIVATE) lfs->private1632;
506 hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE );
507 ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7);
508 bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner,
509 (DLGPROC16) ptr, (LPARAM) lfs);
510 FD31_DestroyPrivate(lfs);
511 }
512
513 TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
514 return bRet;
515 }