Augment the DDSCAPS2 dumping routine with new caps.
[wine] / dlls / commdlg / finddlg.c
1 /*
2  * COMMDLG - 16 bits Find & Replace Text 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
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "winbase.h"
26 #include "wine/winbase16.h"
27 #include "wine/winuser16.h"
28 #include "commdlg.h"
29 #include "wine/debug.h"
30 #include "cderr.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
33
34 #include "cdlg.h"
35
36 struct FRPRIVATE
37 {
38     HANDLE16 hDlgTmpl16; /* handle for resource 16 */
39     HANDLE16 hResource16; /* handle for allocated resource 16 */
40     HANDLE16 hGlobal16; /* 16 bits mem block (resources) */
41     LPCVOID template; /* template for 32 bits resource */
42     BOOL find; /* TRUE if find dialog, FALSE if replace dialog */
43     FINDREPLACE16 *fr16;
44 };
45
46 #define LFRPRIVATE struct FRPRIVATE *
47
48 BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
49                                  LPARAM lParam);
50 BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam,
51                                     LPARAM lParam);
52
53 /***********************************************************************
54  *           FINDDLG_Get16BitsTemplate                                [internal]
55  *
56  * Get a template (FALSE if failure) when 16 bits dialogs are used
57  * by a 16 bits application
58  * FIXME : no test was done for the user-provided template cases
59  */
60 BOOL FINDDLG_Get16BitsTemplate(LFRPRIVATE lfr)
61 {
62     LPFINDREPLACE16 fr16 = lfr->fr16;
63
64     if (fr16->Flags & FR_ENABLETEMPLATEHANDLE)
65     {
66         lfr->template = GlobalLock16(fr16->hInstance);
67         if (!lfr->template)
68         {
69             COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE);
70             return FALSE;
71         }
72     }
73     else if (fr16->Flags & FR_ENABLETEMPLATE)
74     {
75         HANDLE16 hResInfo;
76         if (!(hResInfo = FindResource16(fr16->hInstance,
77                                         MapSL(fr16->lpTemplateName),
78                                         RT_DIALOGA)))
79         {
80             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
81             return FALSE;
82         }
83         if (!(lfr->hDlgTmpl16 = LoadResource16( fr16->hInstance, hResInfo )))
84         {
85             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
86             return FALSE;
87         }
88         lfr->hResource16 = lfr->hDlgTmpl16;
89         lfr->template = LockResource16(lfr->hResource16);
90         if (!lfr->template)
91         {
92             FreeResource16(lfr->hResource16);
93             COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE);
94             return FALSE;
95         }
96     }
97     else
98     { /* get resource from (32 bits) own Wine resource; convert it to 16 */
99         HRSRC hResInfo;
100         HGLOBAL hDlgTmpl32;
101         LPCVOID template32;
102         DWORD size;
103         HGLOBAL16 hGlobal16;
104
105         if (!(hResInfo = FindResourceA(COMMDLG_hInstance32,
106                lfr->find ?
107                MAKEINTRESOURCEA(FINDDLGORD):MAKEINTRESOURCEA(REPLACEDLGORD),
108                RT_DIALOGA)))
109         {
110             COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
111             return FALSE;
112         }
113         if (!(hDlgTmpl32 = LoadResource(COMMDLG_hInstance32, hResInfo )) ||
114             !(template32 = LockResource( hDlgTmpl32 )))
115         {
116             COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
117             return FALSE;
118         }
119         size = SizeofResource(GetModuleHandleA("COMDLG32"), hResInfo);
120         hGlobal16 = GlobalAlloc16(0, size);
121         if (!hGlobal16)
122         {
123             COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
124             ERR("alloc failure for %ld bytes\n", size);
125             return FALSE;
126         }
127         lfr->template = GlobalLock16(hGlobal16);
128         if (!lfr->template)
129         {
130             COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE);
131             ERR("global lock failure for %x handle\n", hGlobal16);
132             GlobalFree16(hGlobal16);
133             return FALSE;
134         }
135         ConvertDialog32To16((LPVOID)template32, size, (LPVOID)lfr->template);
136         lfr->hDlgTmpl16 = hGlobal16;
137         lfr->hGlobal16 = hGlobal16;
138     }
139     return TRUE;
140 }
141
142
143 /***********************************************************************
144  *           FINDDLG_FreeResources                                [internal]
145  *
146  * Free resources allocated
147  */
148 void FINDDLG_FreeResources(LFRPRIVATE lfr)
149 {
150     /* free resources */
151     if (lfr->fr16->Flags & FR_ENABLETEMPLATEHANDLE)
152         GlobalUnlock16(lfr->fr16->hInstance);
153     if (lfr->hResource16)
154     {
155         GlobalUnlock16(lfr->hResource16);
156         FreeResource16(lfr->hResource16);
157     }
158     if (lfr->hGlobal16)
159     {
160         GlobalUnlock16(lfr->hGlobal16);
161         GlobalFree16(lfr->hGlobal16);
162     }
163 }
164
165 /***********************************************************************
166  *           FindText   (COMMDLG.11)
167  */
168 HWND16 WINAPI FindText16( SEGPTR find )
169 {
170     HANDLE16 hInst;
171     HWND16 ret = 0;
172     FARPROC16 ptr;
173     LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE));
174
175     if (!lfr) return 0;
176     lfr->fr16 = MapSL(find);
177     lfr->find = TRUE;
178     if (FINDDLG_Get16BitsTemplate(lfr))
179     {
180         hInst = GetWindowLongA( HWND_32(lfr->fr16->hwndOwner), GWL_HINSTANCE);
181         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 13);
182         ret = CreateDialogIndirectParam16( hInst, lfr->template,
183                     lfr->fr16->hwndOwner, (DLGPROC16) ptr, find);
184         FINDDLG_FreeResources(lfr);
185     }
186     HeapFree(GetProcessHeap(), 0, lfr);
187     return ret;
188 }
189
190
191 /***********************************************************************
192  *           ReplaceText   (COMMDLG.12)
193  */
194 HWND16 WINAPI ReplaceText16( SEGPTR find )
195 {
196     HANDLE16 hInst;
197     HWND16 ret = 0;
198     FARPROC16 ptr;
199     LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE));
200
201     if (!lfr) return 0;
202     /*
203      * FIXME : We should do error checking on the lpFind structure here
204      * and make CommDlgExtendedError() return the error condition.
205      */
206     lfr->fr16 = MapSL(find);
207     lfr->find = FALSE;
208     if (FINDDLG_Get16BitsTemplate(lfr))
209     {
210         hInst = GetWindowLongA( HWND_32(lfr->fr16->hwndOwner), GWL_HINSTANCE);
211         ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 14);
212         ret = CreateDialogIndirectParam16( hInst, lfr->template,
213                     lfr->fr16->hwndOwner, (DLGPROC16) ptr, find);
214
215         FINDDLG_FreeResources(lfr);
216     }
217     HeapFree(GetProcessHeap(), 0, lfr);
218     return ret;
219 }
220
221
222 /***********************************************************************
223  *                              FINDDLG_WMInitDialog            [internal]
224  */
225 static LRESULT FINDDLG_WMInitDialog(HWND hWnd, LPARAM lParam, LPDWORD lpFlags,
226                                     LPSTR lpstrFindWhat, BOOL fUnicode)
227 {
228     SetWindowLongA(hWnd, DWL_USER, lParam);
229     *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
230     /*
231      * FIXME : If the initial FindWhat string is empty, we should disable the
232      * FindNext (IDOK) button.  Only after typing some text, the button should be
233      * enabled.
234      */
235     if (fUnicode) SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat);
236         else SetDlgItemTextA(hWnd, edt1, lpstrFindWhat);
237     CheckRadioButton(hWnd, rad1, rad2, (*lpFlags & FR_DOWN) ? rad2 : rad1);
238     if (*lpFlags & (FR_HIDEUPDOWN | FR_NOUPDOWN)) {
239         EnableWindow(GetDlgItem(hWnd, rad1), FALSE);
240         EnableWindow(GetDlgItem(hWnd, rad2), FALSE);
241     }
242     if (*lpFlags & FR_HIDEUPDOWN) {
243         ShowWindow(GetDlgItem(hWnd, rad1), SW_HIDE);
244         ShowWindow(GetDlgItem(hWnd, rad2), SW_HIDE);
245         ShowWindow(GetDlgItem(hWnd, grp1), SW_HIDE);
246     }
247     CheckDlgButton(hWnd, chx1, (*lpFlags & FR_WHOLEWORD) ? 1 : 0);
248     if (*lpFlags & (FR_HIDEWHOLEWORD | FR_NOWHOLEWORD))
249         EnableWindow(GetDlgItem(hWnd, chx1), FALSE);
250     if (*lpFlags & FR_HIDEWHOLEWORD)
251         ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
252     CheckDlgButton(hWnd, chx2, (*lpFlags & FR_MATCHCASE) ? 1 : 0);
253     if (*lpFlags & (FR_HIDEMATCHCASE | FR_NOMATCHCASE))
254         EnableWindow(GetDlgItem(hWnd, chx2), FALSE);
255     if (*lpFlags & FR_HIDEMATCHCASE)
256         ShowWindow(GetDlgItem(hWnd, chx2), SW_HIDE);
257     if (!(*lpFlags & FR_SHOWHELP)) {
258         EnableWindow(GetDlgItem(hWnd, pshHelp), FALSE);
259         ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
260     }
261     ShowWindow(hWnd, SW_SHOWNORMAL);
262     return TRUE;
263 }
264
265
266 /***********************************************************************
267  *                              FINDDLG_WMCommand               [internal]
268  */
269 static LRESULT FINDDLG_WMCommand(HWND hWnd, WPARAM wParam,
270                         HWND hwndOwner, LPDWORD lpFlags,
271                         LPSTR lpstrFindWhat, WORD wFindWhatLen,
272                         BOOL fUnicode)
273 {
274     int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA );
275     int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA );
276
277     switch (wParam) {
278         case IDOK:
279             if (fUnicode)
280               GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2);
281               else GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
282             if (IsDlgButtonChecked(hWnd, rad2))
283                 *lpFlags |= FR_DOWN;
284                 else *lpFlags &= ~FR_DOWN;
285             if (IsDlgButtonChecked(hWnd, chx1))
286                 *lpFlags |= FR_WHOLEWORD;
287                 else *lpFlags &= ~FR_WHOLEWORD;
288             if (IsDlgButtonChecked(hWnd, chx2))
289                 *lpFlags |= FR_MATCHCASE;
290                 else *lpFlags &= ~FR_MATCHCASE;
291             *lpFlags &= ~(FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
292             *lpFlags |= FR_FINDNEXT;
293             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
294                           GetWindowLongA(hWnd, DWL_USER) );
295             return TRUE;
296         case IDCANCEL:
297             *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL);
298             *lpFlags |= FR_DIALOGTERM;
299             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
300                           GetWindowLongA(hWnd, DWL_USER) );
301             DestroyWindow(hWnd);
302             return TRUE;
303         case pshHelp:
304             /* FIXME : should lpfr structure be passed as an argument ??? */
305             SendMessageA(hwndOwner, uHelpMessage, 0, 0);
306             return TRUE;
307     }
308     return FALSE;
309 }
310
311
312 /***********************************************************************
313  *           FindTextDlgProc   (COMMDLG.13)
314  */
315 BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
316                                  LPARAM lParam)
317 {
318     HWND hWnd = HWND_32(hWnd16);
319     LPFINDREPLACE16 lpfr;
320     switch (wMsg) {
321         case WM_INITDIALOG:
322             lpfr=MapSL(lParam);
323             return FINDDLG_WMInitDialog(hWnd, lParam, &(lpfr->Flags),
324                 MapSL(lpfr->lpstrFindWhat), FALSE);
325         case WM_COMMAND:
326             lpfr=MapSL(GetWindowLongA(hWnd, DWL_USER));
327             return FINDDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner),
328                 &lpfr->Flags, MapSL(lpfr->lpstrFindWhat),
329                 lpfr->wFindWhatLen, FALSE);
330     }
331     return FALSE;
332 }
333
334
335 /***********************************************************************
336  *                              REPLACEDLG_WMInitDialog         [internal]
337  */
338 static LRESULT REPLACEDLG_WMInitDialog(HWND hWnd, LPARAM lParam,
339                     LPDWORD lpFlags, LPSTR lpstrFindWhat,
340                     LPSTR lpstrReplaceWith, BOOL fUnicode)
341 {
342     SetWindowLongA(hWnd, DWL_USER, lParam);
343     *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
344     /*
345      * FIXME : If the initial FindWhat string is empty, we should disable the FinNext /
346      * Replace / ReplaceAll buttons.  Only after typing some text, the buttons should be
347      * enabled.
348      */
349     if (fUnicode)
350     {
351         SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat);
352         SetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith);
353     } else
354     {
355         SetDlgItemTextA(hWnd, edt1, lpstrFindWhat);
356         SetDlgItemTextA(hWnd, edt2, lpstrReplaceWith);
357     }
358     CheckDlgButton(hWnd, chx1, (*lpFlags & FR_WHOLEWORD) ? 1 : 0);
359     if (*lpFlags & (FR_HIDEWHOLEWORD | FR_NOWHOLEWORD))
360         EnableWindow(GetDlgItem(hWnd, chx1), FALSE);
361     if (*lpFlags & FR_HIDEWHOLEWORD)
362         ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
363     CheckDlgButton(hWnd, chx2, (*lpFlags & FR_MATCHCASE) ? 1 : 0);
364     if (*lpFlags & (FR_HIDEMATCHCASE | FR_NOMATCHCASE))
365         EnableWindow(GetDlgItem(hWnd, chx2), FALSE);
366     if (*lpFlags & FR_HIDEMATCHCASE)
367         ShowWindow(GetDlgItem(hWnd, chx2), SW_HIDE);
368     if (!(*lpFlags & FR_SHOWHELP)) {
369         EnableWindow(GetDlgItem(hWnd, pshHelp), FALSE);
370         ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE);
371     }
372     ShowWindow(hWnd, SW_SHOWNORMAL);
373     return TRUE;
374 }
375
376
377 /***********************************************************************
378  *                              REPLACEDLG_WMCommand            [internal]
379  */
380 static LRESULT REPLACEDLG_WMCommand(HWND hWnd, WPARAM16 wParam,
381                     HWND hwndOwner, LPDWORD lpFlags,
382                     LPSTR lpstrFindWhat, WORD wFindWhatLen,
383                     LPSTR lpstrReplaceWith, WORD wReplaceWithLen,
384                     BOOL fUnicode)
385 {
386     int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA );
387     int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA );
388
389     switch (wParam) {
390         case IDOK:
391             if (fUnicode)
392             {
393                 GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2);
394                 GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2);
395             }  else
396             {
397                 GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
398                 GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
399             }
400             if (IsDlgButtonChecked(hWnd, chx1))
401                 *lpFlags |= FR_WHOLEWORD;
402                 else *lpFlags &= ~FR_WHOLEWORD;
403             if (IsDlgButtonChecked(hWnd, chx2))
404                 *lpFlags |= FR_MATCHCASE;
405                 else *lpFlags &= ~FR_MATCHCASE;
406             *lpFlags &= ~(FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM);
407             *lpFlags |= FR_FINDNEXT;
408             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
409                           GetWindowLongA(hWnd, DWL_USER) );
410             return TRUE;
411         case IDCANCEL:
412             *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL);
413             *lpFlags |= FR_DIALOGTERM;
414             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
415                           GetWindowLongA(hWnd, DWL_USER) );
416             DestroyWindow(hWnd);
417             return TRUE;
418         case psh1:
419             if (fUnicode)
420             {
421                 GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2);
422                 GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2);
423             }  else
424             {
425                 GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
426                 GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
427             }
428             if (IsDlgButtonChecked(hWnd, chx1))
429                 *lpFlags |= FR_WHOLEWORD;
430                 else *lpFlags &= ~FR_WHOLEWORD;
431             if (IsDlgButtonChecked(hWnd, chx2))
432                 *lpFlags |= FR_MATCHCASE;
433                 else *lpFlags &= ~FR_MATCHCASE;
434             *lpFlags &= ~(FR_FINDNEXT | FR_REPLACEALL | FR_DIALOGTERM);
435             *lpFlags |= FR_REPLACE;
436             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
437                           GetWindowLongA(hWnd, DWL_USER) );
438             return TRUE;
439         case psh2:
440             if (fUnicode)
441             {
442                 GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2);
443                 GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2);
444             }  else
445             {
446                 GetDlgItemTextA(hWnd, edt1, lpstrFindWhat, wFindWhatLen);
447                 GetDlgItemTextA(hWnd, edt2, lpstrReplaceWith, wReplaceWithLen);
448             }
449             if (IsDlgButtonChecked(hWnd, chx1))
450                 *lpFlags |= FR_WHOLEWORD;
451                 else *lpFlags &= ~FR_WHOLEWORD;
452             if (IsDlgButtonChecked(hWnd, chx2))
453                 *lpFlags |= FR_MATCHCASE;
454                 else *lpFlags &= ~FR_MATCHCASE;
455             *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_DIALOGTERM);
456             *lpFlags |= FR_REPLACEALL;
457             SendMessageA(hwndOwner, uFindReplaceMessage, 0,
458                           GetWindowLongA(hWnd, DWL_USER) );
459             return TRUE;
460         case pshHelp:
461             /* FIXME : should lpfr structure be passed as an argument ??? */
462             SendMessageA(hwndOwner, uHelpMessage, 0, 0);
463             return TRUE;
464     }
465     return FALSE;
466 }
467
468
469 /***********************************************************************
470  *           ReplaceTextDlgProc   (COMMDLG.14)
471  */
472 BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam,
473                                     LPARAM lParam)
474 {
475     HWND hWnd = HWND_32(hWnd16);
476     LPFINDREPLACE16 lpfr;
477     switch (wMsg) {
478         case WM_INITDIALOG:
479             lpfr=MapSL(lParam);
480             return REPLACEDLG_WMInitDialog(hWnd, lParam, &lpfr->Flags,
481                     MapSL(lpfr->lpstrFindWhat),
482                     MapSL(lpfr->lpstrReplaceWith), FALSE);
483         case WM_COMMAND:
484             lpfr=MapSL(GetWindowLongA(hWnd, DWL_USER));
485             return REPLACEDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner),
486                     &lpfr->Flags, MapSL(lpfr->lpstrFindWhat),
487                     lpfr->wFindWhatLen, MapSL(lpfr->lpstrReplaceWith),
488                     lpfr->wReplaceWithLen, FALSE);
489     }
490     return FALSE;
491 }