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