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