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