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