Added some sanity checks on window dimensions.
[wine] / dlls / commdlg / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 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 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     FD16_MapOfnStruct16(priv->ofn16, &lfs->ofnW, lfs->open);
174
175     if (! FD16_GetTemplate(lfs)) return FALSE;
176
177     return TRUE;
178 }
179
180 /***********************************************************************
181  *                              FD16_CallWindowProc          [internal]
182  *
183  *      called from the common 16/32 code to call the appropriate hook
184  */
185 BOOL CALLBACK FD16_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
186                                  LPARAM lParam)
187 {
188     PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
189
190     if (priv->ofn16)
191     {
192         return (BOOL16) CallWindowProc16(
193           (WNDPROC16)priv->ofn16->lpfnHook, HWND_16(lfs->hwnd),
194           (UINT16)wMsg, (WPARAM16)wParam, lParam);
195     }
196     return FALSE;
197 }
198
199
200 /***********************************************************************
201  *                              FD31_UpdateResult            [internal]
202  *          update the real client structures
203  */
204 static void CALLBACK FD16_UpdateResult(PFD31_DATA lfs)
205 {
206     PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
207     LPOPENFILENAMEW ofnW = &lfs->ofnW;
208
209     if (priv->ofn16)
210     { /* we have to convert to short (8.3) path */
211         char tmp[1024]; /* MAX_PATHNAME_LEN */
212         LPOPENFILENAME16 ofn16 = priv->ofn16;
213         char *dest = MapSL(ofn16->lpstrFile);
214         char *bs16;
215         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
216                                   tmp, sizeof(tmp), NULL, NULL ))
217             tmp[sizeof(tmp)-1] = 0;
218         GetShortPathNameA(tmp, dest, ofn16->nMaxFile);
219
220         /* the same procedure as every year... */
221         if((bs16 = strrchr(dest, '\\')) != NULL)
222             ofn16->nFileOffset = bs16 - dest +1;
223         else
224             ofn16->nFileOffset = 0;
225         ofn16->nFileExtension = 0;
226         while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0')
227             ofn16->nFileExtension++;
228         if (dest[ofn16->nFileExtension] == '\0')
229             ofn16->nFileExtension = 0;
230         else
231             ofn16->nFileExtension++;
232     }
233 }
234
235
236 /***********************************************************************
237  *                              FD16_UpdateFileTitle         [internal]
238  *          update the real client structures
239  */
240 static void CALLBACK FD16_UpdateFileTitle(PFD31_DATA lfs)
241 {
242     PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
243     LPOPENFILENAMEW ofnW = &lfs->ofnW;
244
245     if (priv->ofn16)
246     {
247         char *dest = MapSL(priv->ofn16->lpstrFileTitle);
248         if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
249                                   dest, ofnW->nMaxFileTitle, NULL, NULL ))
250             dest[ofnW->nMaxFileTitle-1] = 0;
251     }
252 }
253
254
255 /***********************************************************************
256  *                              FD16_SendLbGetCurSel         [internal]
257  *          retrieve selected listbox item
258  */
259 static LRESULT CALLBACK FD16_SendLbGetCurSel(PFD31_DATA lfs)
260 {
261     return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL16, 0, 0);
262 }
263
264
265 /************************************************************************
266  *                              FD16_Destroy          [internal]
267  *      called from the common 16/32 code to cleanup 32 bit data
268  */
269 static void CALLBACK FD16_Destroy(PFD31_DATA lfs)
270 {
271     PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632;
272
273     /* free resources for a 16 bits dialog */
274     if (NULL != priv)
275     {
276         if (priv->hResource16) FreeResource16(priv->hResource16);
277         if (priv->hGlobal16)
278         {
279             GlobalUnlock16(priv->hGlobal16);
280             GlobalFree16(priv->hGlobal16);
281         }
282         FD31_FreeOfnW(&lfs->ofnW);
283     }
284 }
285
286 static void FD16_SetupCallbacks(PFD31_CALLBACKS callbacks)
287 {
288     callbacks->Init = FD16_Init;
289     callbacks->CWP = FD16_CallWindowProc;
290     callbacks->UpdateResult = FD16_UpdateResult;
291     callbacks->UpdateFileTitle = FD16_UpdateFileTitle;
292     callbacks->SendLbGetCurSel = FD16_SendLbGetCurSel;
293     callbacks->Destroy = FD16_Destroy;
294 }
295
296 /***********************************************************************
297  *                              FD16_MapDrawItemStruct       [internal]
298  *      map a 16 bits drawitem struct to 32
299  */
300 static void FD16_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis)
301 {
302     lpdis->CtlType = lpdis16->CtlType;
303     lpdis->CtlID = lpdis16->CtlID;
304     lpdis->itemID = lpdis16->itemID;
305     lpdis->itemAction = lpdis16->itemAction;
306     lpdis->itemState = lpdis16->itemState;
307     lpdis->hwndItem = HWND_32(lpdis16->hwndItem);
308     lpdis->hDC = HDC_32(lpdis16->hDC);
309     lpdis->rcItem.right = lpdis16->rcItem.right;
310     lpdis->rcItem.left = lpdis16->rcItem.left;
311     lpdis->rcItem.top = lpdis16->rcItem.top;
312     lpdis->rcItem.bottom = lpdis16->rcItem.bottom;
313     lpdis->itemData = lpdis16->itemData;
314 }
315
316
317 /***********************************************************************
318  *                              FD16_WMMeasureItem16         [internal]
319  */
320 static LONG FD16_WMMeasureItem(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam)
321 {
322     LPMEASUREITEMSTRUCT16 lpmeasure;
323
324     lpmeasure = MapSL(lParam);
325     lpmeasure->itemHeight = FD31_GetFldrHeight();
326     return TRUE;
327 }
328
329 /* ------------------ Dialog procedures ---------------------- */
330
331 /***********************************************************************
332  *           FileOpenDlgProc   (COMMDLG.6)
333  */
334 BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
335 {
336     HWND hWnd = HWND_32(hWnd16);
337     PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
338     DRAWITEMSTRUCT dis;
339
340     TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
341     if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
342         {
343             LRESULT lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
344             if (lRet)
345                 return lRet;         /* else continue message processing */
346         }
347     switch (wMsg)
348     {
349     case WM_INITDIALOG:
350         return FD31_WMInitDialog(hWnd, wParam, lParam);
351
352     case WM_MEASUREITEM:
353         return FD16_WMMeasureItem(hWnd16, wParam, lParam);
354
355     case WM_DRAWITEM:
356         FD16_MapDrawItemStruct(MapSL(lParam), &dis);
357         return FD31_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis);
358
359     case WM_COMMAND:
360         return FD31_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs);
361 #if 0
362     case WM_CTLCOLOR:
363          SetBkColor((HDC16)wParam, 0x00C0C0C0);
364          switch (HIWORD(lParam))
365          {
366          case CTLCOLOR_BTN:
367              SetTextColor((HDC16)wParam, 0x00000000);
368              return hGRAYBrush;
369         case CTLCOLOR_STATIC:
370              SetTextColor((HDC16)wParam, 0x00000000);
371              return hGRAYBrush;
372         }
373       break;
374 #endif
375     }
376     return FALSE;
377 }
378
379 /***********************************************************************
380  *           FileSaveDlgProc   (COMMDLG.7)
381  */
382 BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam)
383 {
384  HWND hWnd = HWND_32(hWnd16);
385  PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
386  DRAWITEMSTRUCT dis;
387
388  TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
389  if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
390   {
391    LRESULT  lRet;
392    lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
393    if (lRet)
394     return lRet;         /* else continue message processing */
395   }
396   switch (wMsg) {
397    case WM_INITDIALOG:
398       return FD31_WMInitDialog(hWnd, wParam, lParam);
399
400    case WM_MEASUREITEM:
401       return FD16_WMMeasureItem(hWnd16, wParam, lParam);
402
403    case WM_DRAWITEM:
404       FD16_MapDrawItemStruct(MapSL(lParam), &dis);
405       return FD31_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis);
406
407    case WM_COMMAND:
408       return FD31_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs);
409   }
410
411   /*
412   case WM_CTLCOLOR:
413    SetBkColor((HDC16)wParam, 0x00C0C0C0);
414    switch (HIWORD(lParam))
415    {
416     case CTLCOLOR_BTN:
417      SetTextColor((HDC16)wParam, 0x00000000);
418      return hGRAYBrush;
419     case CTLCOLOR_STATIC:
420      SetTextColor((HDC16)wParam, 0x00000000);
421      return hGRAYBrush;
422    }
423    return FALSE;
424
425    */
426   return FALSE;
427 }
428
429 /* ------------------ APIs ---------------------- */
430
431 /***********************************************************************
432  *           GetOpenFileName   (COMMDLG.1)
433  *
434  * Creates a dialog box for the user to select a file to open.
435  *
436  * RETURNS
437  *    TRUE on success: user selected a valid file
438  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
439  *
440  * BUGS
441  *    unknown, there are some FIXME's left.
442  */
443 BOOL16 WINAPI GetOpenFileName16(
444                                 SEGPTR ofn /* [in/out] address of structure with data*/
445                                 )
446 {
447     HINSTANCE16 hInst;
448     BOOL bRet = FALSE;
449     LPOPENFILENAME16 lpofn = MapSL(ofn);
450     PFD31_DATA lfs;
451     FARPROC16 ptr;
452     FD31_CALLBACKS callbacks;
453     PFD16_PRIVATE priv;
454
455     if (!lpofn || !FD31_Init()) return FALSE;
456
457     FD16_SetupCallbacks(&callbacks);
458     lfs = FD31_AllocPrivate((LPARAM) ofn, OPEN_DIALOG, &callbacks, 0);
459     if (lfs)
460     {
461         priv = (PFD16_PRIVATE) lfs->private1632;
462         hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE );
463         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6);
464         bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner,
465                                          (DLGPROC16) ptr, (LPARAM) lfs);
466         FD31_DestroyPrivate(lfs);
467     }
468
469     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
470     return bRet;
471 }
472
473 /***********************************************************************
474  *           GetSaveFileName   (COMMDLG.2)
475  *
476  * Creates a dialog box for the user to select a file to save.
477  *
478  * RETURNS
479  *    TRUE on success: user enters a valid file
480  *    FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
481  *
482  * BUGS
483  *    unknown. There are some FIXME's left.
484  */
485 BOOL16 WINAPI GetSaveFileName16(
486                                 SEGPTR ofn /* [in/out] addess of structure with data*/
487                                 )
488 {
489     HINSTANCE16 hInst;
490     BOOL bRet = FALSE;
491     LPOPENFILENAME16 lpofn = MapSL(ofn);
492     PFD31_DATA lfs;
493     FARPROC16 ptr;
494     FD31_CALLBACKS callbacks;
495     PFD16_PRIVATE priv;
496
497     if (!lpofn || !FD31_Init()) return FALSE;
498
499     FD16_SetupCallbacks(&callbacks);
500     lfs = FD31_AllocPrivate((LPARAM) ofn, SAVE_DIALOG, &callbacks, 0);
501     if (lfs)
502     {
503         priv = (PFD16_PRIVATE) lfs->private1632;
504         hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE );
505         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7);
506         bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner,
507                                          (DLGPROC16) ptr, (LPARAM) lfs);
508         FD31_DestroyPrivate(lfs);
509     }
510
511     TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile));
512     return bRet;
513 }